feat(cli): Add MR support to list/show/count/ingest commands
Extends all data commands to support merge requests alongside issues, with consistent patterns and JSON output for robot mode. List command (gi list mrs): - MR-specific columns: branches, draft status, reviewers - Filters: --state (opened|merged|closed|locked|all), --draft, --no-draft, --reviewer, --target-branch, --source-branch - Discussion count with unresolved indicator (e.g., "5/2!") - JSON output includes full MR metadata Show command (gi show mr <iid>): - MR details with branches, assignees, reviewers, merge status - DiffNote positions showing file:line for code review comments - Full description and discussion bodies (no truncation in JSON) - --json flag for structured output with ISO timestamps Count command (gi count mrs): - MR counting with optional --type filter for discussions/notes - JSON output with breakdown by state Ingest command (gi ingest --type mrs): - Full MR sync with discussion prefetch - Progress output shows MR-specific metrics (diffnotes count) - JSON summary with comprehensive sync statistics All commands respect global --robot mode for auto-JSON output. The pattern "gi list mrs --json | jq '.mrs[] | .iid'" now works for scripted MR processing. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
use console::style;
|
||||
use rusqlite::Connection;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::Config;
|
||||
use crate::core::db::create_connection;
|
||||
@@ -175,6 +176,95 @@ fn format_number(n: i64) -> String {
|
||||
result
|
||||
}
|
||||
|
||||
/// JSON output structures for robot mode.
|
||||
#[derive(Serialize)]
|
||||
struct SyncStatusJsonOutput {
|
||||
ok: bool,
|
||||
data: SyncStatusJsonData,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct SyncStatusJsonData {
|
||||
last_sync: Option<SyncRunJsonInfo>,
|
||||
cursors: Vec<CursorJsonInfo>,
|
||||
summary: SummaryJsonInfo,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct SyncRunJsonInfo {
|
||||
id: i64,
|
||||
status: String,
|
||||
command: String,
|
||||
started_at: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
completed_at: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
duration_ms: Option<i64>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
error: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct CursorJsonInfo {
|
||||
project: String,
|
||||
resource_type: String,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
updated_at_cursor: Option<String>,
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
tie_breaker_id: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct SummaryJsonInfo {
|
||||
issues: i64,
|
||||
discussions: i64,
|
||||
notes: i64,
|
||||
system_notes: i64,
|
||||
}
|
||||
|
||||
/// Print sync status as JSON (robot mode).
|
||||
pub fn print_sync_status_json(result: &SyncStatusResult) {
|
||||
let last_sync = result.last_run.as_ref().map(|run| {
|
||||
let duration_ms = run.finished_at.map(|f| f - run.started_at);
|
||||
SyncRunJsonInfo {
|
||||
id: run.id,
|
||||
status: run.status.clone(),
|
||||
command: run.command.clone(),
|
||||
started_at: ms_to_iso(run.started_at),
|
||||
completed_at: run.finished_at.map(ms_to_iso),
|
||||
duration_ms,
|
||||
error: run.error.clone(),
|
||||
}
|
||||
});
|
||||
|
||||
let cursors = result
|
||||
.cursors
|
||||
.iter()
|
||||
.map(|c| CursorJsonInfo {
|
||||
project: c.project_path.clone(),
|
||||
resource_type: c.resource_type.clone(),
|
||||
updated_at_cursor: c.updated_at_cursor.filter(|&ts| ts > 0).map(ms_to_iso),
|
||||
tie_breaker_id: c.tie_breaker_id,
|
||||
})
|
||||
.collect();
|
||||
|
||||
let output = SyncStatusJsonOutput {
|
||||
ok: true,
|
||||
data: SyncStatusJsonData {
|
||||
last_sync,
|
||||
cursors,
|
||||
summary: SummaryJsonInfo {
|
||||
issues: result.summary.issue_count,
|
||||
discussions: result.summary.discussion_count,
|
||||
notes: result.summary.note_count - result.summary.system_note_count,
|
||||
system_notes: result.summary.system_note_count,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
println!("{}", serde_json::to_string(&output).unwrap());
|
||||
}
|
||||
|
||||
/// Print sync status result.
|
||||
pub fn print_sync_status(result: &SyncStatusResult) {
|
||||
// Last Sync section
|
||||
|
||||
Reference in New Issue
Block a user