use anyhow::{Context, Result, bail};
use serde_json::Value;
use super::ReviewState;
pub(super) fn parse_body_field(output: &str, field: &str) -> Result<String> {
let value: serde_json::Value =
serde_json::from_str(output).context("failed to parse provider JSON")?;
Ok(value
.get(field)
.and_then(serde_json::Value::as_str)
.unwrap_or_default()
.to_owned())
}
pub(super) fn optional_bool(value: &Value, key: &str) -> bool {
value.get(key).and_then(Value::as_bool).unwrap_or(false)
}
pub(super) fn optional_string(value: &Value, key: &str) -> String {
value
.get(key)
.and_then(Value::as_str)
.unwrap_or_default()
.to_owned()
}
pub(super) fn first_json_item(output: &str) -> Result<Option<Value>> {
let value: Value = serde_json::from_str(output).context("failed to parse provider JSON")?;
match value {
Value::Array(items) => Ok(items.into_iter().next()),
Value::Object(_) => Ok(Some(value)),
_ => bail!("provider JSON must be an object or array"),
}
}
pub(super) fn required_string(value: &Value, keys: &[&str]) -> Result<String> {
for key in keys {
if let Some(field) = value.get(*key) {
if let Some(value) = field.as_str() {
return Ok(value.to_owned());
}
if let Some(value) = field.as_i64() {
return Ok(value.to_string());
}
if let Some(value) = field.as_u64() {
return Ok(value.to_string());
}
}
}
bail!(
"provider JSON missing required field: {}",
keys.join(" or ")
)
}
pub(super) fn parse_state(state: &str) -> ReviewState {
match state.to_ascii_lowercase().as_str() {
"open" | "opened" => ReviewState::Open,
"merged" => ReviewState::Merged,
"closed" => ReviewState::Closed,
_ => ReviewState::Unknown(state.to_owned()),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_body_field_reads_field_and_defaults_empty() {
assert_eq!(
parse_body_field(r#"{"body":"hello"}"#, "body").expect("parse body"),
"hello"
);
assert_eq!(
parse_body_field(r#"{"description":null}"#, "description").expect("parse body"),
""
);
assert_eq!(parse_body_field(r#"{}"#, "body").expect("parse body"), "");
}
}