feat(status): add per-entity sync counts from migration 027
Enhances sync status reporting to include granular per-entity counts that were added in database migration 027. This provides better visibility into what each sync run actually processed. New fields in SyncRunInfo and robot mode JSON: - issues_fetched / issues_ingested: issue sync counts - mrs_fetched / mrs_ingested: merge request sync counts - skipped_stale: entities skipped due to staleness - docs_regenerated / docs_embedded: document pipeline counts - warnings_count: non-fatal issues during sync Robot mode optimization: - Uses skip_serializing_if = "is_zero" to omit zero-value fields - Reduces JSON payload size for typical sync runs - Maintains backwards compatibility (fields are additive) SQL query now reads all 8 new columns from sync_runs table, with defensive unwrap_or(0) for NULL handling. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,10 @@ use crate::core::time::{format_full_datetime, ms_to_iso};
|
|||||||
|
|
||||||
const RECENT_RUNS_LIMIT: usize = 10;
|
const RECENT_RUNS_LIMIT: usize = 10;
|
||||||
|
|
||||||
|
fn is_zero(value: &i64) -> bool {
|
||||||
|
*value == 0
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct SyncRunInfo {
|
pub struct SyncRunInfo {
|
||||||
pub id: i64,
|
pub id: i64,
|
||||||
@@ -24,6 +28,15 @@ pub struct SyncRunInfo {
|
|||||||
pub total_items_processed: i64,
|
pub total_items_processed: i64,
|
||||||
pub total_errors: i64,
|
pub total_errors: i64,
|
||||||
pub stages: Option<Vec<StageTiming>>,
|
pub stages: Option<Vec<StageTiming>>,
|
||||||
|
// Per-entity counts (from migration 027)
|
||||||
|
pub issues_fetched: i64,
|
||||||
|
pub issues_ingested: i64,
|
||||||
|
pub mrs_fetched: i64,
|
||||||
|
pub mrs_ingested: i64,
|
||||||
|
pub skipped_stale: i64,
|
||||||
|
pub docs_regenerated: i64,
|
||||||
|
pub docs_embedded: i64,
|
||||||
|
pub warnings_count: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -68,7 +81,9 @@ pub fn run_sync_status(config: &Config) -> Result<SyncStatusResult> {
|
|||||||
fn get_recent_sync_runs(conn: &Connection, limit: usize) -> Result<Vec<SyncRunInfo>> {
|
fn get_recent_sync_runs(conn: &Connection, limit: usize) -> Result<Vec<SyncRunInfo>> {
|
||||||
let mut stmt = conn.prepare(
|
let mut stmt = conn.prepare(
|
||||||
"SELECT id, started_at, finished_at, status, command, error,
|
"SELECT id, started_at, finished_at, status, command, error,
|
||||||
run_id, total_items_processed, total_errors, metrics_json
|
run_id, total_items_processed, total_errors, metrics_json,
|
||||||
|
issues_fetched, issues_ingested, mrs_fetched, mrs_ingested,
|
||||||
|
skipped_stale, docs_regenerated, docs_embedded, warnings_count
|
||||||
FROM sync_runs
|
FROM sync_runs
|
||||||
ORDER BY started_at DESC
|
ORDER BY started_at DESC
|
||||||
LIMIT ?1",
|
LIMIT ?1",
|
||||||
@@ -91,6 +106,14 @@ fn get_recent_sync_runs(conn: &Connection, limit: usize) -> Result<Vec<SyncRunIn
|
|||||||
total_items_processed: row.get::<_, Option<i64>>(7)?.unwrap_or(0),
|
total_items_processed: row.get::<_, Option<i64>>(7)?.unwrap_or(0),
|
||||||
total_errors: row.get::<_, Option<i64>>(8)?.unwrap_or(0),
|
total_errors: row.get::<_, Option<i64>>(8)?.unwrap_or(0),
|
||||||
stages,
|
stages,
|
||||||
|
issues_fetched: row.get::<_, Option<i64>>(10)?.unwrap_or(0),
|
||||||
|
issues_ingested: row.get::<_, Option<i64>>(11)?.unwrap_or(0),
|
||||||
|
mrs_fetched: row.get::<_, Option<i64>>(12)?.unwrap_or(0),
|
||||||
|
mrs_ingested: row.get::<_, Option<i64>>(13)?.unwrap_or(0),
|
||||||
|
skipped_stale: row.get::<_, Option<i64>>(14)?.unwrap_or(0),
|
||||||
|
docs_regenerated: row.get::<_, Option<i64>>(15)?.unwrap_or(0),
|
||||||
|
docs_embedded: row.get::<_, Option<i64>>(16)?.unwrap_or(0),
|
||||||
|
warnings_count: row.get::<_, Option<i64>>(17)?.unwrap_or(0),
|
||||||
})
|
})
|
||||||
})?
|
})?
|
||||||
.collect();
|
.collect();
|
||||||
@@ -198,6 +221,23 @@ struct SyncRunJsonInfo {
|
|||||||
error: Option<String>,
|
error: Option<String>,
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
stages: Option<Vec<StageTiming>>,
|
stages: Option<Vec<StageTiming>>,
|
||||||
|
// Per-entity counts
|
||||||
|
#[serde(skip_serializing_if = "is_zero")]
|
||||||
|
issues_fetched: i64,
|
||||||
|
#[serde(skip_serializing_if = "is_zero")]
|
||||||
|
issues_ingested: i64,
|
||||||
|
#[serde(skip_serializing_if = "is_zero")]
|
||||||
|
mrs_fetched: i64,
|
||||||
|
#[serde(skip_serializing_if = "is_zero")]
|
||||||
|
mrs_ingested: i64,
|
||||||
|
#[serde(skip_serializing_if = "is_zero")]
|
||||||
|
skipped_stale: i64,
|
||||||
|
#[serde(skip_serializing_if = "is_zero")]
|
||||||
|
docs_regenerated: i64,
|
||||||
|
#[serde(skip_serializing_if = "is_zero")]
|
||||||
|
docs_embedded: i64,
|
||||||
|
#[serde(skip_serializing_if = "is_zero")]
|
||||||
|
warnings_count: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize)]
|
#[derive(Serialize)]
|
||||||
@@ -237,6 +277,14 @@ pub fn print_sync_status_json(result: &SyncStatusResult, elapsed_ms: u64) {
|
|||||||
total_errors: run.total_errors,
|
total_errors: run.total_errors,
|
||||||
error: run.error.clone(),
|
error: run.error.clone(),
|
||||||
stages: run.stages.clone(),
|
stages: run.stages.clone(),
|
||||||
|
issues_fetched: run.issues_fetched,
|
||||||
|
issues_ingested: run.issues_ingested,
|
||||||
|
mrs_fetched: run.mrs_fetched,
|
||||||
|
mrs_ingested: run.mrs_ingested,
|
||||||
|
skipped_stale: run.skipped_stale,
|
||||||
|
docs_regenerated: run.docs_regenerated,
|
||||||
|
docs_embedded: run.docs_embedded,
|
||||||
|
warnings_count: run.warnings_count,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
|
|||||||
Reference in New Issue
Block a user