neiam
/gitgud
Git Gud
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
1
Log in to mark this repository.
gg: warning jobs read as an amber warning, and the run counts them
52481e7 · Gabriel Morell · 2026-10-27 18:57
Message
{commit_body(@commit)}
Files changed
modified
cli/src/commands/ci.rs
+33
−0
@@ -116,6 +116,11 @@ fn print_run(ctx: &Ctx, repo: &RepoRef, res: &Res<RunDetailResponse>, steps: boo
| 116 | 116 | if let Some(took) = duration(run.started_at.as_deref(), run.completed_at.as_deref()) { |
| 117 | 117 | println!("took {took}"); |
| 118 | 118 | } |
| 119 | + // A run its warning jobs passed is `success`; the count says there's | |
| 120 | + // still something to look at, as the run page's header does. | |
| 121 | + if let Some(line) = warnings_line(&res.jobs) { | |
| 122 | + println!("{}", paint(&line, Tone::Warn)); | |
| 123 | + } | |
| 119 | 124 | if run.awaiting_approval { |
| 120 | 125 | println!("\n{}", paint(&approval_notice(run), Tone::Busy)); |
| 121 | 126 | } |
@@ -358,6 +363,19 @@ fn pick_job<'a>(jobs: &'a [Job], wanted: Option<&str>) -> Result<&'a Job> {
| 358 | 363 | } |
| 359 | 364 | } |
| 360 | 365 | |
| 366 | +/// "⚠ 2 warnings" for a run with warning jobs, nothing for one without. | |
| 367 | +fn warnings_line(jobs: &[Job]) -> Option<String> { | |
| 368 | + match jobs | |
| 369 | + .iter() | |
| 370 | + .filter(|j| j.display_status() == "warning") | |
| 371 | + .count() | |
| 372 | + { | |
| 373 | + 0 => None, | |
| 374 | + 1 => Some("⚠ 1 warning".into()), | |
| 375 | + n => Some(format!("⚠ {n} warnings")), | |
| 376 | + } | |
| 377 | +} | |
| 378 | + | |
| 361 | 379 | fn job_names(jobs: &[Job]) -> String { |
| 362 | 380 | jobs.iter() |
| 363 | 381 | .map(|j| j.job_id.clone().unwrap_or_else(|| j.label())) |
@@ -660,6 +678,21 @@ mod tests {
| 660 | 678 | assert!(pick_job(&jobs, None).is_err()); |
| 661 | 679 | } |
| 662 | 680 | |
| 681 | + #[test] | |
| 682 | + fn warning_jobs_are_counted_and_not_failures() { | |
| 683 | + let jobs = vec![ | |
| 684 | + job(1, "build", "success", None), | |
| 685 | + job(2, "audit", "warning", Some("warning")), | |
| 686 | + job(3, "image", "warning", Some("warning")), | |
| 687 | + ]; | |
| 688 | + assert_eq!(warnings_line(&jobs).as_deref(), Some("⚠ 2 warnings")); | |
| 689 | + assert_eq!(warnings_line(&jobs[..2]).as_deref(), Some("⚠ 1 warning")); | |
| 690 | + assert_eq!(warnings_line(&jobs[..1]), None); | |
| 691 | + assert_eq!(status_badge(jobs[1].display_status()), "⚠ warning"); | |
| 692 | + // No failed job to pick: a warning isn't one. | |
| 693 | + assert!(pick_job(&jobs, None).is_err()); | |
| 694 | + } | |
| 695 | + | |
| 663 | 696 | #[test] |
| 664 | 697 | fn superseded_jobs_read_as_superseded_not_cancelled() { |
| 665 | 698 | let mut j = job(1, "build", "cancelled", None); |
modified
cli/src/output.rs
+19
−3
@@ -17,6 +17,7 @@ pub enum Tone {
| 17 | 17 | Good, |
| 18 | 18 | Bad, |
| 19 | 19 | Busy, |
| 20 | + Warn, | |
| 20 | 21 | Muted, |
| 21 | 22 | Accent, |
| 22 | 23 | Plain, |
@@ -28,6 +29,7 @@ impl Tone {
| 28 | 29 | Tone::Good => "\x1b[32m", |
| 29 | 30 | Tone::Bad => "\x1b[31m", |
| 30 | 31 | Tone::Busy => "\x1b[33m", |
| 32 | + Tone::Warn => "\x1b[1;33m", | |
| 31 | 33 | Tone::Muted => "\x1b[90m", |
| 32 | 34 | Tone::Accent => "\x1b[36m", |
| 33 | 35 | Tone::Plain => "", |
@@ -76,10 +78,13 @@ pub fn effective_status<'a>(status: &'a str, conclusion: Option<&'a str>) -> &'a
| 76 | 78 | /// ([`Run::display_status`] — the server says `queued`) and `superseded`, |
| 77 | 79 | /// a job cancelled because a newer one in its concurrency group replaced |
| 78 | 80 | /// it ([`Job::display_status`]). Superseded is dim, not red: the newer |
| 79 | −/// run decides, as its commit status (`cancelled`) says. | |
| 81 | +/// run decides, as its commit status (`cancelled`) says. A `warning` job | |
| 82 | +/// passed but wants a look — it failed under `continue-on-error`, or | |
| 83 | +/// reported `gitgud-conclusion: warning` — so it's amber, not red. | |
| 80 | 84 | pub fn status_tone(status: &str) -> Tone { |
| 81 | 85 | match status { |
| 82 | 86 | "success" => Tone::Good, |
| 87 | + "warning" => Tone::Warn, | |
| 83 | 88 | "failure" | "cancelled" | "timed_out" => Tone::Bad, |
| 84 | 89 | "queued" | "running" | "pending" | "blocked" | "waiting" | "awaiting_approval" => { |
| 85 | 90 | Tone::Busy |
@@ -93,6 +98,7 @@ pub fn status_tone(status: &str) -> Tone {
| 93 | 98 | pub fn status_mark(status: &str) -> &'static str { |
| 94 | 99 | match status { |
| 95 | 100 | "success" => "✔", |
| 101 | + "warning" => "⚠", | |
| 96 | 102 | "failure" | "timed_out" => "✘", |
| 97 | 103 | "cancelled" | "superseded" => "⊘", |
| 98 | 104 | "running" => "▶", |
@@ -119,7 +125,7 @@ pub fn status_label(status: &str) -> String {
| 119 | 125 | pub fn finished(status: &str) -> bool { |
| 120 | 126 | matches!( |
| 121 | 127 | status, |
| 122 | − "success" | "failure" | "cancelled" | "skipped" | "timed_out" | "superseded" | |
| 128 | + "success" | "failure" | "cancelled" | "skipped" | "timed_out" | "superseded" | "warning" | |
| 123 | 129 | ) |
| 124 | 130 | } |
| 125 | 131 |
@@ -396,6 +402,9 @@ mod tests {
| 396 | 402 | assert_eq!(status_tone("awaiting_approval"), Tone::Busy); |
| 397 | 403 | assert_eq!(status_tone("superseded"), Tone::Muted); |
| 398 | 404 | assert_eq!(status_tone("skipped"), Tone::Muted); |
| 405 | + assert_eq!(status_tone("warning"), Tone::Warn); | |
| 406 | + assert_eq!(status_mark("warning"), "⚠"); | |
| 407 | + assert_eq!(status_label("warning"), "warning"); | |
| 399 | 408 | assert_ne!(status_mark("awaiting_approval"), status_mark("queued")); |
| 400 | 409 | assert_eq!(status_label("awaiting_approval"), "needs approval"); |
| 401 | 410 | assert_eq!(status_label("timed_out"), "timed out"); |
@@ -404,7 +413,14 @@ mod tests {
| 404 | 413 | |
| 405 | 414 | #[test] |
| 406 | 415 | fn only_known_endings_are_finished() { |
| 407 | − for done in ["success", "failure", "cancelled", "skipped", "superseded"] { | |
| 416 | + for done in [ | |
| 417 | + "success", | |
| 418 | + "failure", | |
| 419 | + "cancelled", | |
| 420 | + "skipped", | |
| 421 | + "superseded", | |
| 422 | + "warning", | |
| 423 | + ] { | |
| 408 | 424 | assert!(finished(done), "{done}"); |
| 409 | 425 | } |
| 410 | 426 | for busy in [ |
modified
cli/src/tui/mod.rs
+1
−1
@@ -547,7 +547,7 @@ fn tone_color(status: &str) -> Color {
| 547 | 547 | match status_tone(status) { |
| 548 | 548 | Tone::Good => Color::Green, |
| 549 | 549 | Tone::Bad => Color::Red, |
| 550 | − Tone::Busy => Color::Yellow, | |
| 550 | + Tone::Busy | Tone::Warn => Color::Yellow, | |
| 551 | 551 | Tone::Accent => Color::Cyan, |
| 552 | 552 | Tone::Muted | Tone::Plain => Color::DarkGray, |
| 553 | 553 | } |
Parents: d8a7c7f