diff --git a/docs/public/api-reference/fabro-api.yaml b/docs/public/api-reference/fabro-api.yaml index bd41cc8ae..740950999 100644 --- a/docs/public/api-reference/fabro-api.yaml +++ b/docs/public/api-reference/fabro-api.yaml @@ -8034,6 +8034,7 @@ components: SystemRepairRunsResponse: description: Runs that need manual repair or deletion because they cannot be loaded. type: object + required: [runs, total_count] properties: runs: type: array @@ -8047,6 +8048,7 @@ components: SystemRepairRunIssue: description: One cataloged run that cannot be loaded from durable storage. type: object + required: [run_id, created_at, error] properties: run_id: type: string diff --git a/lib/crates/fabro-cli/src/commands/runs/rm.rs b/lib/crates/fabro-cli/src/commands/runs/rm.rs index c959a4b4f..f6fe97c52 100644 --- a/lib/crates/fabro-cli/src/commands/runs/rm.rs +++ b/lib/crates/fabro-cli/src/commands/runs/rm.rs @@ -21,49 +21,26 @@ async fn remove_from(args: &RunsRemoveArgs, ctx: &CommandContext) -> Result<()> let mut errors = Vec::new(); for identifier in &args.runs { - if args.force { - if let Ok(run_id) = identifier.parse::() { - let run_id_string = run_id.to_string(); - if let Err(err) = delete_server_run(client, &run_id, true).await { - let error = err.to_string(); - if !json { - fabro_util::printerr!(printer, "error: {identifier}: {error}"); - } - errors.push(serde_json::json!({ - "identifier": identifier, - "error": error, - })); - had_errors = true; - continue; - } - removed.push(run_id_string.clone()); - if !json { - fabro_util::printerr!(printer, "{}", short_run_id(&run_id_string)); - } - continue; - } - } - - let run = match client.resolve_run(identifier).await { - Ok(run) => run, + let run_id = match resolve_target(client, identifier, args.force).await { + Ok(run_id) => run_id, Err(err) => { + let error = err.to_string(); if !json { - fabro_util::printerr!(printer, "error: {identifier}: {err}"); + fabro_util::printerr!(printer, "error: {identifier}: {error}"); } errors.push(serde_json::json!({ "identifier": identifier, - "error": err.to_string(), + "error": error, })); had_errors = true; continue; } }; - let run_id = run.run_id.to_string(); - if let Err(err) = delete_server_run(client, &run.run_id, args.force).await { + if let Err(err) = delete_server_run(client, &run_id, args.force).await { let error = err.to_string(); if !json { - if error.starts_with("cannot remove active run ") { + if !args.force && error.starts_with("cannot remove active run ") { fabro_util::printerr!(printer, "{error}"); } else { fabro_util::printerr!(printer, "error: {identifier}: {error}"); @@ -76,9 +53,11 @@ async fn remove_from(args: &RunsRemoveArgs, ctx: &CommandContext) -> Result<()> had_errors = true; continue; } - removed.push(run_id.clone()); + + let run_id_string = run_id.to_string(); + removed.push(run_id_string.clone()); if !json { - fabro_util::printerr!(printer, "{}", short_run_id(&run_id)); + fabro_util::printerr!(printer, "{}", short_run_id(&run_id_string)); } } @@ -95,6 +74,19 @@ async fn remove_from(args: &RunsRemoveArgs, ctx: &CommandContext) -> Result<()> Ok(()) } +async fn resolve_target( + client: &server_client::Client, + identifier: &str, + force: bool, +) -> Result { + if force { + if let Ok(run_id) = identifier.parse::() { + return Ok(run_id); + } + } + Ok(client.resolve_run(identifier).await?.run_id) +} + async fn delete_server_run( client: &server_client::Client, run_id: &fabro_types::RunId, diff --git a/lib/crates/fabro-cli/src/commands/system/repair.rs b/lib/crates/fabro-cli/src/commands/system/repair.rs index 80edca4f4..c0a4a5b35 100644 --- a/lib/crates/fabro-cli/src/commands/system/repair.rs +++ b/lib/crates/fabro-cli/src/commands/system/repair.rs @@ -1,5 +1,4 @@ use anyhow::Result; -use chrono::{DateTime, Utc}; use fabro_api::types; use fabro_util::printer::Printer; @@ -33,33 +32,26 @@ fn repair_runs_from( return Ok(()); } - let runs = response.runs.as_slice(); - if runs.is_empty() { + if response.runs.is_empty() { fabro_util::printout!(printer, "No run repair issues found."); return Ok(()); } fabro_util::printout!(printer, "Unreadable runs:"); - for run in runs { + for run in &response.runs { fabro_util::printout!( printer, " {} {} {}", - run.run_id.as_deref().unwrap_or("-"), - format_created_at(run.created_at.as_ref()), - run.error.as_deref().unwrap_or("-"), + run.run_id, + run.created_at.to_rfc3339(), + run.error, ); } fabro_util::printout!(printer, ""); fabro_util::printout!(printer, "Delete with:"); - for run in runs { - if let Some(run_id) = run.run_id.as_deref() { - fabro_util::printout!(printer, " fabro rm --force {run_id}"); - } + for run in &response.runs { + fabro_util::printout!(printer, " fabro rm --force {}", run.run_id); } Ok(()) } - -fn format_created_at(created_at: Option<&DateTime>) -> String { - created_at.map_or_else(|| "-".to_string(), DateTime::to_rfc3339) -} diff --git a/lib/crates/fabro-server/src/server/handler/system.rs b/lib/crates/fabro-server/src/server/handler/system.rs index 07455b70e..63dd0f28d 100644 --- a/lib/crates/fabro-server/src/server/handler/system.rs +++ b/lib/crates/fabro-server/src/server/handler/system.rs @@ -130,22 +130,19 @@ async fn get_system_repair_runs( .into_response(); } }; - let total_count = issues.len(); + let total_count = to_i64(issues.len()); let runs = issues .into_iter() .map(|issue| SystemRepairRunIssue { - run_id: Some(issue.run_id.to_string()), - created_at: Some(issue.created_at), - error: Some(issue.error), + run_id: issue.run_id.to_string(), + created_at: issue.created_at, + error: issue.error, }) .collect(); ( StatusCode::OK, - Json(SystemRepairRunsResponse { - runs, - total_count: Some(to_i64(total_count)), - }), + Json(SystemRepairRunsResponse { runs, total_count }), ) .into_response() } diff --git a/lib/crates/fabro-server/src/server/tests.rs b/lib/crates/fabro-server/src/server/tests.rs index 0cedf8c0a..0ce363b61 100644 --- a/lib/crates/fabro-server/src/server/tests.rs +++ b/lib/crates/fabro-server/src/server/tests.rs @@ -2071,7 +2071,14 @@ async fn system_repair_runs_lists_catalog_entries_without_projection() { .parse::>() .unwrap(); assert_eq!(created_at, run_id.created_at()); - assert_eq!(body["runs"][0]["error"], "run has no events"); + assert!( + body["runs"][0]["error"] + .as_str() + .unwrap() + .contains("no events"), + "got: {}", + body["runs"][0]["error"] + ); } #[tokio::test] diff --git a/lib/packages/fabro-api-client/src/.openapi-generator/FILES b/lib/packages/fabro-api-client/src/.openapi-generator/FILES index 31c539fbb..0f91dd09c 100644 --- a/lib/packages/fabro-api-client/src/.openapi-generator/FILES +++ b/lib/packages/fabro-api-client/src/.openapi-generator/FILES @@ -230,9 +230,9 @@ models/run-git-settings.ts models/run-goal-file.ts models/run-goal-inline.ts models/run-goal.ts -models/run-interviews-settings.ts models/run-integrations-github-settings.ts models/run-integrations-settings.ts +models/run-interviews-settings.ts models/run-list-item.ts models/run-manifest.ts models/run-mode.ts diff --git a/lib/packages/fabro-api-client/src/models/index.ts b/lib/packages/fabro-api-client/src/models/index.ts index b50c5e824..34479400e 100644 --- a/lib/packages/fabro-api-client/src/models/index.ts +++ b/lib/packages/fabro-api-client/src/models/index.ts @@ -209,9 +209,9 @@ export * from './run-git-settings'; export * from './run-goal'; export * from './run-goal-file'; export * from './run-goal-inline'; -export * from './run-interviews-settings'; export * from './run-integrations-github-settings'; export * from './run-integrations-settings'; +export * from './run-interviews-settings'; export * from './run-list-item'; export * from './run-manifest'; export * from './run-mode'; diff --git a/lib/packages/fabro-api-client/src/models/run-integrations-github-settings.ts b/lib/packages/fabro-api-client/src/models/run-integrations-github-settings.ts index 8502a9339..64d0c6c53 100644 --- a/lib/packages/fabro-api-client/src/models/run-integrations-github-settings.ts +++ b/lib/packages/fabro-api-client/src/models/run-integrations-github-settings.ts @@ -18,4 +18,3 @@ export interface RunIntegrationsGithubSettings { 'permissions': { [key: string]: string; }; } - diff --git a/lib/packages/fabro-api-client/src/models/run-integrations-settings.ts b/lib/packages/fabro-api-client/src/models/run-integrations-settings.ts index 4b6dcd6ae..6102093da 100644 --- a/lib/packages/fabro-api-client/src/models/run-integrations-settings.ts +++ b/lib/packages/fabro-api-client/src/models/run-integrations-settings.ts @@ -21,4 +21,3 @@ export interface RunIntegrationsSettings { 'github': RunIntegrationsGithubSettings; } - diff --git a/lib/packages/fabro-api-client/src/models/run-stage.ts b/lib/packages/fabro-api-client/src/models/run-stage.ts index 060a6166e..b14c97e54 100644 --- a/lib/packages/fabro-api-client/src/models/run-stage.ts +++ b/lib/packages/fabro-api-client/src/models/run-stage.ts @@ -47,3 +47,6 @@ export interface RunStage { */ 'started_at'?: string | null; } + + + diff --git a/lib/packages/fabro-api-client/src/models/system-repair-run-issue.ts b/lib/packages/fabro-api-client/src/models/system-repair-run-issue.ts index cd5fd76ad..992a0b57a 100644 --- a/lib/packages/fabro-api-client/src/models/system-repair-run-issue.ts +++ b/lib/packages/fabro-api-client/src/models/system-repair-run-issue.ts @@ -21,14 +21,14 @@ export interface SystemRepairRunIssue { /** * Run identifier. */ - 'run_id'?: string; + 'run_id': string; /** * Timestamp encoded in the run identifier. */ - 'created_at'?: string; + 'created_at': string; /** * Error produced while loading the run projection. */ - 'error'?: string; + 'error': string; } diff --git a/lib/packages/fabro-api-client/src/models/system-repair-runs-response.ts b/lib/packages/fabro-api-client/src/models/system-repair-runs-response.ts index 7fbe34534..173c849f1 100644 --- a/lib/packages/fabro-api-client/src/models/system-repair-runs-response.ts +++ b/lib/packages/fabro-api-client/src/models/system-repair-runs-response.ts @@ -21,10 +21,10 @@ import type { SystemRepairRunIssue } from './system-repair-run-issue'; * Runs that need manual repair or deletion because they cannot be loaded. */ export interface SystemRepairRunsResponse { - 'runs'?: Array; + 'runs': Array; /** * Count of run repair issues. */ - 'total_count'?: number; + 'total_count': number; }