use crate::api::{ApiError, JiraClient};
use crate::config::Config;
use crate::output::OutputConfig;
pub async fn run(client: &JiraClient, config: &Config, out: &OutputConfig) -> Result<(), ApiError> {
let safety = if config.read_only {
"read-only mode enabled"
} else {
"write operations enabled"
};
let configuration = format!("{} ยท REST API v{}", config.host, config.api_version);
let me = match client.get_myself().await {
Ok(me) => me,
Err(error) => {
let error = contextualize_auth_error(error, config);
render_failure(out, &configuration, safety, "authentication", &error);
return Err(error);
}
};
let projects = match client.list_projects().await {
Ok(projects) => projects,
Err(error) => {
render_project_failure(out, &configuration, &me.display_name, safety, &error);
return Err(error);
}
};
let project_detail = match projects.len() {
0 => "accessible; no projects visible".to_string(),
1 => "1 project accessible".to_string(),
count => format!("{count} projects accessible"),
};
let checks = serde_json::json!([
{"name": "configuration", "ok": true, "detail": configuration},
{"name": "authentication", "ok": true, "detail": me.display_name},
{"name": "projects", "ok": true, "detail": project_detail},
{"name": "write_safety", "ok": true, "detail": safety}
]);
if out.json {
out.print_data(
&serde_json::to_string_pretty(&serde_json::json!({
"ok": true,
"instance": client.browse_base_url(),
"user": {
"accountId": me.account_id,
"displayName": me.display_name,
"email": me.email_address,
},
"projectCount": projects.len(),
"checks": checks,
}))
.expect("failed to serialize doctor result"),
);
} else {
println!("Jira connection\n");
for check in checks.as_array().expect("checks are an array") {
println!(
" โ {:<16} {}",
check["name"].as_str().unwrap_or("check"),
check["detail"].as_str().unwrap_or_default()
);
}
println!("\nReady.");
}
Ok(())
}
fn contextualize_auth_error(error: ApiError, config: &Config) -> ApiError {
match error {
ApiError::NotFound(_) => ApiError::NotFound(format!(
"Jira REST API at {} was not found. Confirm the site is active and REST API v{} matches this deployment",
config.host, config.api_version
)),
other => other,
}
}
fn render_failure(
out: &OutputConfig,
configuration: &str,
safety: &str,
failed_check: &str,
error: &ApiError,
) {
let checks = serde_json::json!([
{"name": "configuration", "ok": true, "detail": configuration},
{"name": failed_check, "ok": false, "detail": error.to_string()},
{"name": "projects", "ok": false, "detail": "not run"},
{"name": "write_safety", "ok": true, "detail": safety}
]);
render_failed_checks(out, checks);
}
fn render_project_failure(
out: &OutputConfig,
configuration: &str,
user: &str,
safety: &str,
error: &ApiError,
) {
let checks = serde_json::json!([
{"name": "configuration", "ok": true, "detail": configuration},
{"name": "authentication", "ok": true, "detail": user},
{"name": "projects", "ok": false, "detail": error.to_string()},
{"name": "write_safety", "ok": true, "detail": safety}
]);
render_failed_checks(out, checks);
}
fn render_failed_checks(out: &OutputConfig, checks: serde_json::Value) {
if out.json {
out.print_data(
&serde_json::to_string_pretty(&serde_json::json!({
"ok": false,
"checks": checks,
}))
.expect("failed to serialize doctor result"),
);
} else {
println!("Jira connection\n");
for check in checks.as_array().expect("checks are an array") {
let marker = if check["ok"].as_bool().unwrap_or(false) {
"โ"
} else {
"โ"
};
println!(
" {marker} {:<16} {}",
check["name"].as_str().unwrap_or("check"),
check["detail"].as_str().unwrap_or_default()
);
}
}
}