From 2e56c81dbc37a82884604a714a33665ce7c93817 Mon Sep 17 00:00:00 2001 From: rdzehtsiar <105226800+rdzehtsiar@users.noreply.github.com> Date: Fri, 19 Jun 2026 01:43:36 +0200 Subject: [PATCH] Add scan context to human output --- src/pipeline/scan_summary.rs | 35 +++++++++++++++++++++++++++++++++-- tests/scanner_cli.rs | 23 +++++++++++++++++++++-- 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/src/pipeline/scan_summary.rs b/src/pipeline/scan_summary.rs index f8b01a1..74948f0 100644 --- a/src/pipeline/scan_summary.rs +++ b/src/pipeline/scan_summary.rs @@ -246,6 +246,8 @@ pub fn render_scan_summary(summary: &ScanSummary, run: &ScanRunSummary) -> Strin lines.push(String::new()); lines.extend(render_risk(&run.risk)); lines.push(String::new()); + lines.extend(render_scan(&run.scan)); + lines.push(String::new()); lines.extend(render_hotspots(&summary.hotspots)); lines.push(String::new()); lines.extend(render_limitations(&summary.limitations)); @@ -542,6 +544,25 @@ fn render_risk(risk: &RiskSummary) -> Vec { ] } +fn render_scan(scan: &ScanRunInfo) -> Vec { + let commits = scan + .commits_total + .map(|total| format!("{}/{total}", scan.commits_processed)) + .unwrap_or_else(|| format!("{}/unknown", scan.commits_processed)); + + vec![ + "Scan".to_owned(), + format!(" Type: {}", scan.scan_type), + format!( + " Files: {}/{} analyzed", + scan.files_analyzed, scan.files_detected + ), + format!(" Git history: {}", scan.git_history), + format!(" Commits: {commits}"), + format!(" Duration: {} ms", scan.duration_ms), + ] +} + fn render_hotspots(hotspots: &[GoHotspot]) -> Vec { let mut lines = vec!["Top Hotspots".to_owned()]; if hotspots.is_empty() { @@ -679,7 +700,12 @@ mod tests { assert!(rendered.contains(" Primary driver: Churn")); assert!(!rendered.contains(" Primary driver: churn (Churn)")); assert!(rendered.contains(" Files by band: extreme 0 high 1 medium 1 low 0")); - assert!(!rendered.contains("\nScan\n")); + assert!(rendered.contains("\nScan\n")); + assert!(rendered.contains(" Type: full")); + assert!(rendered.contains(" Files: 3/3 analyzed")); + assert!(rendered.contains(" Git history: bounded")); + assert!(rendered.contains(" Commits: 2/2")); + assert!(rendered.contains(" Duration: 42 ms")); assert!(!rendered.contains("duration_ms")); assert!(!rendered.contains("files_detected")); assert!(rendered.contains("Top Hotspots\n\n 1 internal/service/a.go")); @@ -710,7 +736,12 @@ mod tests { assert!(rendered.contains(" Score: unavailable")); assert!(rendered.contains(" Band: unavailable")); assert!(rendered.contains(" Primary driver: none")); - assert!(!rendered.contains("\nScan\n")); + assert!(rendered.contains("\nScan\n")); + assert!(rendered.contains(" Type: full")); + assert!(rendered.contains(" Files: 0/0 analyzed")); + assert!(rendered.contains(" Git history: absent")); + assert!(rendered.contains(" Commits: 0/unknown")); + assert!(rendered.contains(" Duration: 0 ms")); assert!(rendered.contains("Top Hotspots\n none")); assert!(rendered.contains("Limitations\n none")); } diff --git a/tests/scanner_cli.rs b/tests/scanner_cli.rs index 5f30e3d..61002ed 100644 --- a/tests/scanner_cli.rs +++ b/tests/scanner_cli.rs @@ -82,7 +82,12 @@ fn scan_prints_file_and_git_progress_summary() { assert!(stdout.contains(" Scoring confidence: high")); assert!(stdout.contains("Risk")); assert!(stdout.contains(" Files by band:")); - assert!(!stdout.contains("\nScan\n")); + assert!(stdout.contains("\nScan\n")); + assert!(stdout.contains(" Type: full")); + assert!(stdout.contains(" Files: 2/2 analyzed")); + assert!(stdout.contains(" Git history: absent")); + assert!(stdout.contains(" Commits: 0/")); + assert!(stdout.contains(" Duration: ")); assert!(!stdout.contains("files_detected")); assert!(!stdout.contains("files_analyzed")); assert!(!stdout.contains("git_history")); @@ -335,6 +340,9 @@ fn scan_summary_reports_no_go_coverage_and_limitation() { assert!(stdout.contains(" Score: unavailable")); assert!(stdout.contains(" Band: unavailable")); assert!(stdout.contains(" Primary driver: none")); + assert!(stdout.contains(" Files: 1/1 analyzed")); + assert!(stdout.contains(" Git history: absent")); + assert!(stdout.contains(" Commits: 0/")); assert!(!stdout.contains("files_detected")); assert!(!stdout.contains("files_analyzed")); assert!(stdout.contains("Top Hotspots\n none")); @@ -692,7 +700,8 @@ fn scan_reports_actionable_non_git_diagnostic() { assert!(output.status.success()); let stdout = String::from_utf8(output.stdout).expect("stdout should be UTF-8"); - assert!(!stdout.contains("\nScan\n")); + assert!(stdout.contains("\nScan\n")); + assert!(stdout.contains(" Git history: absent")); assert!(stdout.contains("Git analysis skipped: current directory is not a Git worktree")); assert!(!stdout.contains("diagnostic not_git")); assert!(!stdout.contains("index_action cleared_not_git")); @@ -816,6 +825,12 @@ fn scan_reports_git_progress_for_git_repository() { assert!(final_lines.is_empty()); assert!(stdout.contains("Hotpath scan complete")); assert!(stdout.contains("Assessment")); + assert!(stdout.contains("\nScan\n")); + assert!(stdout.contains(" Type: full")); + assert!(stdout.contains(" Files: 1/1 analyzed")); + assert!(stdout.contains(" Git history: bounded")); + assert!(stdout.contains(" Commits:")); + assert!(stdout.contains(" Duration: ")); let connection = Connection::open(fixture.path().join(".hotpath").join("index.sqlite")).expect("db opens"); @@ -1305,6 +1320,10 @@ func Stop(enabled bool) int { assert!(stdout.contains("Top Hotspots")); assert!(stdout.contains("cmd/app/main.go")); assert!(stdout.contains("internal/service/a.go")); + assert!(stdout.contains("\nScan\n")); + assert!(stdout.contains(" Type: full")); + assert!(stdout.contains(" Git history: absent")); + assert!(stdout.contains(" Commits: 0/")); assert!(!stdout.contains("files_detected")); assert!(!stdout.contains("files_analyzed")); assert!(!stdout.contains("git_history"));