refactor(robot): add constructors to RobotMeta, support optional gitlab_base_url
RobotMeta previously required direct struct literal construction with only elapsed_ms. This made it impossible to add optional fields without updating every call site to include them. Introduce two constructors: - RobotMeta::new(elapsed_ms) — standard meta with timing only - RobotMeta::with_base_url(elapsed_ms, base_url) — meta enriched with the GitLab instance URL, enabling consumers to construct entity links without needing config access The gitlab_base_url field uses #[serde(skip_serializing_if = "Option::is_none")] so existing JSON envelopes are byte-identical — no breaking change for any robot mode consumer. All 22 call sites across handlers, count, cron, drift, embed, generate_docs, ingest, list (mrs/notes), related, show, stats, sync_status, and who are updated from struct literals to RobotMeta::new(). Three tests verify the new constructors and trailing-slash normalization. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -254,7 +254,7 @@ pub fn print_event_count_json(counts: &EventCounts, elapsed_ms: u64) {
|
||||
},
|
||||
total: counts.total(),
|
||||
},
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::new(elapsed_ms),
|
||||
};
|
||||
|
||||
match serde_json::to_string(&output) {
|
||||
@@ -325,7 +325,7 @@ pub fn print_count_json(result: &CountResult, elapsed_ms: u64) {
|
||||
system_excluded: result.system_count,
|
||||
breakdown,
|
||||
},
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::new(elapsed_ms),
|
||||
};
|
||||
|
||||
match serde_json::to_string(&output) {
|
||||
|
||||
@@ -80,7 +80,7 @@ pub fn print_cron_install_json(result: &CronInstallResult, elapsed_ms: u64) {
|
||||
log_path: result.log_path.display().to_string(),
|
||||
replaced: result.replaced,
|
||||
},
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::new(elapsed_ms),
|
||||
};
|
||||
if let Ok(json) = serde_json::to_string(&output) {
|
||||
println!("{json}");
|
||||
@@ -128,7 +128,7 @@ pub fn print_cron_uninstall_json(result: &CronUninstallResult, elapsed_ms: u64)
|
||||
action: "uninstall",
|
||||
was_installed: result.was_installed,
|
||||
},
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::new(elapsed_ms),
|
||||
};
|
||||
if let Ok(json) = serde_json::to_string(&output) {
|
||||
println!("{json}");
|
||||
@@ -284,7 +284,7 @@ pub fn print_cron_status_json(info: &CronStatusInfo, elapsed_ms: u64) {
|
||||
last_sync_at: info.last_sync.as_ref().map(|s| s.started_at_iso.clone()),
|
||||
last_sync_status: info.last_sync.as_ref().map(|s| s.status.clone()),
|
||||
},
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::new(elapsed_ms),
|
||||
};
|
||||
if let Ok(json) = serde_json::to_string(&output) {
|
||||
println!("{json}");
|
||||
|
||||
@@ -468,7 +468,7 @@ pub fn print_drift_human(response: &DriftResponse) {
|
||||
}
|
||||
|
||||
pub fn print_drift_json(response: &DriftResponse, elapsed_ms: u64) {
|
||||
let meta = RobotMeta { elapsed_ms };
|
||||
let meta = RobotMeta::new(elapsed_ms);
|
||||
let output = serde_json::json!({
|
||||
"ok": true,
|
||||
"data": response,
|
||||
|
||||
@@ -135,7 +135,7 @@ pub fn print_embed_json(result: &EmbedCommandResult, elapsed_ms: u64) {
|
||||
let output = EmbedJsonOutput {
|
||||
ok: true,
|
||||
data: result,
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::new(elapsed_ms),
|
||||
};
|
||||
match serde_json::to_string(&output) {
|
||||
Ok(json) => println!("{json}"),
|
||||
|
||||
@@ -257,7 +257,7 @@ pub fn print_generate_docs_json(result: &GenerateDocsResult, elapsed_ms: u64) {
|
||||
unchanged: result.unchanged,
|
||||
errored: result.errored,
|
||||
},
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::new(elapsed_ms),
|
||||
};
|
||||
match serde_json::to_string(&output) {
|
||||
Ok(json) => println!("{json}"),
|
||||
|
||||
@@ -191,7 +191,7 @@ pub fn print_ingest_summary_json(result: &IngestResult, elapsed_ms: u64) {
|
||||
status_enrichment,
|
||||
status_enrichment_errors: result.status_enrichment_errors,
|
||||
},
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::new(elapsed_ms),
|
||||
};
|
||||
|
||||
match serde_json::to_string(&output) {
|
||||
|
||||
@@ -370,7 +370,7 @@ pub fn print_list_mrs(result: &MrListResult) {
|
||||
|
||||
pub fn print_list_mrs_json(result: &MrListResult, elapsed_ms: u64, fields: Option<&[String]>) {
|
||||
let json_result = MrListResultJson::from(result);
|
||||
let meta = RobotMeta { elapsed_ms };
|
||||
let meta = RobotMeta::new(elapsed_ms);
|
||||
let output = serde_json::json!({
|
||||
"ok": true,
|
||||
"data": json_result,
|
||||
|
||||
@@ -193,7 +193,7 @@ pub fn print_list_notes(result: &NoteListResult) {
|
||||
|
||||
pub fn print_list_notes_json(result: &NoteListResult, elapsed_ms: u64, fields: Option<&[String]>) {
|
||||
let json_result = NoteListResultJson::from(result);
|
||||
let meta = RobotMeta { elapsed_ms };
|
||||
let meta = RobotMeta::new(elapsed_ms);
|
||||
let output = serde_json::json!({
|
||||
"ok": true,
|
||||
"data": json_result,
|
||||
|
||||
@@ -558,7 +558,7 @@ pub fn print_related_human(response: &RelatedResponse) {
|
||||
}
|
||||
|
||||
pub fn print_related_json(response: &RelatedResponse, elapsed_ms: u64) {
|
||||
let meta = RobotMeta { elapsed_ms };
|
||||
let meta = RobotMeta::new(elapsed_ms);
|
||||
let output = serde_json::json!({
|
||||
"ok": true,
|
||||
"data": response,
|
||||
|
||||
@@ -557,7 +557,7 @@ impl From<&MrNoteDetail> for MrNoteDetailJson {
|
||||
|
||||
pub fn print_show_issue_json(issue: &IssueDetail, elapsed_ms: u64) {
|
||||
let json_result = IssueDetailJson::from(issue);
|
||||
let meta = RobotMeta { elapsed_ms };
|
||||
let meta = RobotMeta::new(elapsed_ms);
|
||||
let output = serde_json::json!({
|
||||
"ok": true,
|
||||
"data": json_result,
|
||||
@@ -571,7 +571,7 @@ pub fn print_show_issue_json(issue: &IssueDetail, elapsed_ms: u64) {
|
||||
|
||||
pub fn print_show_mr_json(mr: &MrDetail, elapsed_ms: u64) {
|
||||
let json_result = MrDetailJson::from(mr);
|
||||
let meta = RobotMeta { elapsed_ms };
|
||||
let meta = RobotMeta::new(elapsed_ms);
|
||||
let output = serde_json::json!({
|
||||
"ok": true,
|
||||
"data": json_result,
|
||||
|
||||
@@ -583,7 +583,7 @@ pub fn print_stats_json(result: &StatsResult, elapsed_ms: u64) {
|
||||
}),
|
||||
}),
|
||||
},
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::new(elapsed_ms),
|
||||
};
|
||||
match serde_json::to_string(&output) {
|
||||
Ok(json) => println!("{json}"),
|
||||
|
||||
@@ -313,7 +313,7 @@ pub fn print_sync_status_json(result: &SyncStatusResult, elapsed_ms: u64) {
|
||||
system_notes: result.summary.system_note_count,
|
||||
},
|
||||
},
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::new(elapsed_ms),
|
||||
};
|
||||
|
||||
match serde_json::to_string(&output) {
|
||||
|
||||
@@ -376,7 +376,7 @@ pub fn print_who_json(run: &WhoRun, args: &WhoArgs, elapsed_ms: u64) {
|
||||
resolved_input,
|
||||
result: data,
|
||||
},
|
||||
meta: RobotMeta { elapsed_ms },
|
||||
meta: RobotMeta::new(elapsed_ms),
|
||||
};
|
||||
|
||||
let mut value = serde_json::to_value(&output).unwrap_or_else(|e| {
|
||||
|
||||
Reference in New Issue
Block a user