neiam
/gitgud
Git Gud
public · Issues · Pulls · Labels · Forks · Compare · Actions success · Badges · Packages
⭐
1
Log in to mark this repository.
Android: warning jobs read as an amber warning, and the run counts them
ebe084c · Gabriel Morell · 2026-10-31 03:54
Message
{commit_body(@commit)}
Files changed
modified
android/app/src/main/java/org/neiam/gitgud/app/ui/RunScreen.kt
+14
−0
@@ -328,6 +328,20 @@ private fun RunHeader(d: RunDetailResponse) {
| 328 | 328 | color = MaterialTheme.colorScheme.onSurfaceVariant, |
| 329 | 329 | modifier = Modifier.padding(top = 2.dp), |
| 330 | 330 | ) |
| 331 | + // A run its warning jobs passed is `success`; the count says | |
| 332 | + // there's still something to look at. | |
| 333 | + warningsLabel(d.jobs)?.let { label -> | |
| 334 | + Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(top = 6.dp)) { | |
| 335 | + Icon( | |
| 336 | + statusIcon("warning"), | |
| 337 | + contentDescription = null, | |
| 338 | + tint = LocalAppTheme.current.warning, | |
| 339 | + modifier = Modifier.size(15.dp), | |
| 340 | + ) | |
| 341 | + Spacer(Modifier.width(4.dp)) | |
| 342 | + Text(label, style = MaterialTheme.typography.labelMedium, color = LocalAppTheme.current.warning) | |
| 343 | + } | |
| 344 | + } | |
| 331 | 345 | } |
| 332 | 346 | } |
| 333 | 347 | } |
modified
android/app/src/main/java/org/neiam/gitgud/app/ui/StatusChip.kt
+20
−1
@@ -16,6 +16,7 @@ import androidx.compose.material.icons.automirrored.filled.HelpOutline
| 16 | 16 | import androidx.compose.material.icons.filled.HourglassEmpty |
| 17 | 17 | import androidx.compose.material.icons.filled.PlayCircle |
| 18 | 18 | import androidx.compose.material.icons.filled.RemoveCircle |
| 19 | +import androidx.compose.material.icons.filled.Warning | |
| 19 | 20 | import androidx.compose.material3.Icon |
| 20 | 21 | import androidx.compose.material3.MaterialTheme |
| 21 | 22 | import androidx.compose.material3.Surface |
@@ -26,6 +27,7 @@ import androidx.compose.ui.Modifier
| 26 | 27 | import androidx.compose.ui.graphics.Color |
| 27 | 28 | import androidx.compose.ui.graphics.vector.ImageVector |
| 28 | 29 | import androidx.compose.ui.unit.dp |
| 30 | +import org.neiam.gitgud.app.data.Job | |
| 29 | 31 | import org.neiam.gitgud.app.ui.theme.LocalAppTheme |
| 30 | 32 | |
| 31 | 33 | /** |
@@ -41,13 +43,16 @@ import org.neiam.gitgud.app.ui.theme.LocalAppTheme
| 41 | 43 | * (`Run.displayStatus` — the server says `queued`) and `superseded`, a |
| 42 | 44 | * job cancelled because a newer one in its concurrency group replaced |
| 43 | 45 | * it (`Job.displayStatus`). Superseded is grey, not red: the newer run |
| 44 | − * decides, as its commit status (`cancelled`) says. | |
| 46 | + * decides, as its commit status (`cancelled`) says. A `warning` job | |
| 47 | + * passed but wants a look — it failed under `continue-on-error`, or | |
| 48 | + * reported `gitgud-conclusion: warning` — so it's amber, not red. | |
| 45 | 49 | */ |
| 46 | 50 | @Composable |
| 47 | 51 | fun statusColor(status: String?): Color { |
| 48 | 52 | val theme = LocalAppTheme.current |
| 49 | 53 | return when (status) { |
| 50 | 54 | "success" -> theme.success |
| 55 | + "warning" -> theme.warning | |
| 51 | 56 | "failure", "cancelled", "timed_out" -> theme.danger |
| 52 | 57 | "queued", "running", "pending", "blocked", "waiting", "awaiting_approval" -> theme.pending |
| 53 | 58 | "skipped", "superseded" -> theme.dim |
@@ -57,6 +62,7 @@ fun statusColor(status: String?): Color {
| 57 | 62 | |
| 58 | 63 | fun statusIcon(status: String?): ImageVector = when (status) { |
| 59 | 64 | "success" -> Icons.Default.CheckCircle |
| 65 | + "warning" -> Icons.Default.Warning | |
| 60 | 66 | "failure", "timed_out" -> Icons.Default.Error |
| 61 | 67 | "cancelled", "superseded" -> Icons.Default.Cancel |
| 62 | 68 | "running" -> Icons.Default.PlayCircle |
@@ -91,6 +97,19 @@ fun triggerLabel(trigger: String?): String? = when (trigger) {
| 91 | 97 | else -> trigger.replace('_', ' ') |
| 92 | 98 | } |
| 93 | 99 | |
| 100 | +/** | |
| 101 | + * "1 warning" / "3 warnings" for a run whose jobs include `warning` | |
| 102 | + * ones, null for a run without. The run itself still reads `success`, | |
| 103 | + * so this is what says there's something to look at, as the run page's | |
| 104 | + * header and `gg ci show` do. | |
| 105 | + */ | |
| 106 | +fun warningsLabel(jobs: List<Job>): String? = | |
| 107 | + when (val n = jobs.count { it.displayStatus == "warning" }) { | |
| 108 | + 0 -> null | |
| 109 | + 1 -> "1 warning" | |
| 110 | + else -> "$n warnings" | |
| 111 | + } | |
| 112 | + | |
| 94 | 113 | /** `conclusion` when the thing has finished, else its raw `status`. */ |
| 95 | 114 | fun effectiveStatus(status: String?, conclusion: String?): String? = |
| 96 | 115 | if (status == "completed" || status == "finished") conclusion ?: status else status |
modified
android/app/src/main/java/org/neiam/gitgud/app/ui/theme/AppTheme.kt
+4
−0
@@ -56,6 +56,8 @@ data class AppTheme(
| 56 | 56 | val danger: Color, |
| 57 | 57 | /** CI queued or running. */ |
| 58 | 58 | val pending: Color, |
| 59 | + /** A job that passed but wants a look: amber, apart from pending's yellow. */ | |
| 60 | + val warning: Color, | |
| 59 | 61 | val isLight: Boolean = false, |
| 60 | 62 | ) { |
| 61 | 63 | fun toColorScheme() = if (isLight) { |
@@ -132,6 +134,7 @@ data class AppTheme(
| 132 | 134 | private val SUCCESS = oklchToColor(0.75f, 0.15f, 145f) |
| 133 | 135 | private val DANGER = oklchToColor(0.68f, 0.19f, 25f) |
| 134 | 136 | private val PENDING = oklchToColor(0.80f, 0.14f, 85f) |
| 137 | +private val WARNING = oklchToColor(0.76f, 0.16f, 60f) | |
| 135 | 138 | |
| 136 | 139 | private fun oklchTheme( |
| 137 | 140 | name: String, key: String, |
@@ -153,6 +156,7 @@ private fun oklchTheme(
| 153 | 156 | success = SUCCESS, |
| 154 | 157 | danger = DANGER, |
| 155 | 158 | pending = PENDING, |
| 159 | + warning = WARNING, | |
| 156 | 160 | isLight = isLight, |
| 157 | 161 | ) |
| 158 | 162 |
modified
android/app/src/test/java/org/neiam/gitgud/app/data/CiModelsTest.kt
+16
−0
@@ -7,6 +7,7 @@ import org.junit.Assert.assertTrue
| 7 | 7 | import org.junit.Test |
| 8 | 8 | import org.neiam.gitgud.app.ui.statusLabel |
| 9 | 9 | import org.neiam.gitgud.app.ui.triggerLabel |
| 10 | +import org.neiam.gitgud.app.ui.warningsLabel | |
| 10 | 11 | import org.neiam.gitgud.app.widget.CiWidgetModel |
| 11 | 12 | import org.neiam.gitgud.app.widget.StatusCategory |
| 12 | 13 |
@@ -51,6 +52,21 @@ class CiModelsTest {
| 51 | 52 | assertEquals(StatusCategory.DIM, CiWidgetModel.category(job.displayStatus)) |
| 52 | 53 | } |
| 53 | 54 | |
| 55 | + @Test | |
| 56 | + fun warningJobsAreCountedAndNotFailures() { | |
| 57 | + val warned = json.decodeFromString<Job>( | |
| 58 | + """{"id": 2, "status": "warning", "conclusion": "failure", | |
| 59 | + "status_reason": "Failed, but continue-on-error allows it"}""", | |
| 60 | + ) | |
| 61 | + val jobs = listOf(Job(id = 1, status = "success"), warned, warned.copy(id = 3)) | |
| 62 | + | |
| 63 | + assertEquals("warning", warned.displayStatus) | |
| 64 | + assertEquals("warning", statusLabel(warned.displayStatus)) | |
| 65 | + assertEquals("2 warnings", warningsLabel(jobs)) | |
| 66 | + assertEquals("1 warning", warningsLabel(jobs.take(2))) | |
| 67 | + assertEquals(null, warningsLabel(jobs.take(1))) | |
| 68 | + } | |
| 69 | + | |
| 54 | 70 | @Test |
| 55 | 71 | fun aRunWaitingForApprovalSaysSo() { |
| 56 | 72 | val run = json.decodeFromString<Run>( |
Parents: 81bfaa9