Skip to content

fix flash log streaming and add colored output#114

Merged
bennyz merged 5 commits into
centos-automotive-suite:mainfrom
bennyz:fix-flash-logs
Feb 15, 2026
Merged

fix flash log streaming and add colored output#114
bennyz merged 5 commits into
centos-automotive-suite:mainfrom
bennyz:fix-flash-logs

Conversation

@bennyz

@bennyz bennyz commented Feb 15, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Terminal color output with environment-aware detection.
    • Colorized build result and flash instruction messages, including lease/timeout display.
    • Improved flash failure handling with actionable instructions.
    • Better log-streaming UX with periodic keepalive messages during long waits.
  • Chores

    • Vendored/updated libraries to enable cross-platform colored terminal output.

Signed-off-by: Benny Zlotnik <bzlotnik@redhat.com>
fixes centos-automotive-suite#104

Signed-off-by: Benny Zlotnik <bzlotnik@redhat.com>
@bennyz bennyz changed the title fix flash log streaming fix flash log streaming and add colored output Feb 15, 2026
@coderabbitai

coderabbitai Bot commented Feb 15, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@bennyz has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 24 minutes and 0 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📝 Walkthrough

Walkthrough

Adds colorized terminal output and flash-aware UX to the CLI (cmd/caib), vendores a terminal color library and colorable writers, adjusts server log streaming and Jumpstarter mapping, and removes a large set of vendored OpenShift config v1 API type files and generated manifests.

Changes

Cohort / File(s) Summary
CLI: color & flash UX
cmd/caib/main.go
Add supportsColorOutput(), label/value color helpers, displayFlashInstructions(), handleFlashError(), parseLeaseDuration(); integrate color-aware messages into build result and flash/error flows; tweak waitForBuildCompletion output formatting.
Server: logs & Jumpstarter mapping
internal/buildapi/server.go
Lazy log header emission, keepalive "[Waiting for remaining pipeline tasks...]" keepalive messages when pods complete but build not finished, and include Jumpstarter mapping for failed terminal builds.
Color libraries vendored
vendor/github.com/fatih/color/*, vendor/github.com/mattn/go-colorable/*
Add fatih/color and go-colorable vendor files (color formatting, Windows VT support, colorable writers, noncolorable stripping, docs, licenses, tests script).
Dependency edits
go.mod, vendor/modules.txt
Add github.com/fatih/color, github.com/mattn/go-colorable, golang.org/x/term; adjust indirect visibility and module entries.
Removed OpenShift v1 APIs
vendor/github.com/openshift/api/config/v1/*
Remove many v1 config API files and generated manifest: types and registration/docs for APIServer, Authentication, Build, ClusterImagePolicy, ClusterOperator, ClusterVersion, Console, DNS, FeatureGate, Image, ImageContentPolicy, ImageDigestMirrorSet, ImagePolicy, ImageTagMirrorSet, Ingress, KMS encryption, Network, Node, OAuth, OperatorHub, Project, Proxy, Scheduling, TestReporting, TLSSecurityProfile, zz_generated.featuregated-crd-manifests.yaml, and related files.

Sequence Diagram

sequenceDiagram
    participant User
    participant CLI as cmd/caib<br/>(main.go)
    participant Server as buildapi<br/>(internal/buildapi)
    participant Term as Terminal

    User->>CLI: start build (with/without flash)
    CLI->>Server: request build start / status
    Server->>Server: run pipeline, stream logs
    Server->>Term: stream logs (plain or colored)
    Note over CLI,Term: CLI checks supportsColorOutput()
    Server->>CLI: build completes/fails + Jumpstarter info
    alt build success
        CLI->>Term: displayBuildResults() (colored labels/values)
        CLI->>Term: displayFlashInstructions() (if flash)
    else build failure
        CLI->>Term: handleFlashError() (colored error + recovery options)
    end
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • basic jumpstarter integration #42 — Adds Jumpstarter flash integration and earlier flash flows that this PR augments with colorized messaging and flash error handling.
  • adjust imagebuild api #40 — Modifies internal/buildapi/server.go; related to the server-side Jumpstarter mapping and build retrieval changes present here.
  • fix golangci lint #32 — Previously adjusted log streaming and getBuild logic in server.go; overlaps with the keepalive and header emission changes.

Poem

🐰✨
I hopped through logs with colors bright,
Green for go and red for plight,
Flash commands glow in carrot hue,
Leasing stars to guide you through,
A cheerful hop — build done, delight!

🚥 Pre-merge checks | ✅ 3 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Merge Conflict Detection ⚠️ Warning ❌ Merge conflicts detected (6 files):

⚔️ cmd/caib/main.go (content)
⚔️ go.mod (content)
⚔️ go.sum (content)
⚔️ internal/buildapi/client_tokens.go (content)
⚔️ internal/buildapi/server.go (content)
⚔️ vendor/modules.txt (content)

These conflicts must be resolved before merging into main.
Resolve conflicts locally and push changes to this branch.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title clearly and specifically describes the main changes: fixing flash log streaming issues and adding colored output support to the CLI.
Docstring Coverage ✅ Passed Docstring coverage is 82.43% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cmd/caib/main.go (1)

2564-2574: ⚠️ Potential issue | 🟠 Major

Flash log client has a hard 10-minute timeout, unlike the build log client.

The build log path (Line 1586–1591) explicitly avoids setting Timeout on the HTTP client because log streams can run for the entire build duration, relying on the context timeout instead. The flash log client here sets Timeout: 10 * time.Minute, but the flash lease duration defaults to 3 hours and is user-configurable. If a flash operation streams logs for longer than 10 minutes, this http.Client timeout will kill the connection, potentially losing log output.

Apply the same pattern as the build path — omit the hard Timeout and let timeoutCtx govern cancellation:

Proposed fix
 	logClient := &http.Client{
-		Timeout:   10 * time.Minute,
 		Transport: flashLogTransport,
 	}
🧹 Nitpick comments (3)
internal/buildapi/server.go (1)

820-838: Keepalive message is well-designed for the flash log streaming fix.

The unconditional 2-second sleep prevents tight-looping, and the [Waiting for remaining pipeline tasks...] keepalive when allPodsComplete && hadStream serves dual purpose: preventing proxy idle-timeouts and keeping the client's line-based scanner alive while waiting for the flash pod to appear.

One minor consideration: this keepalive message will be emitted every 2 seconds and will appear in the client's log output. If the wait is long (e.g., flash pod scheduling takes minutes), the client will see many repeated lines. Consider whether this is acceptable UX or if a longer interval / deduplication would be preferable.

cmd/caib/main.go (2)

123-144: supportsColorOutput may enable color even when TERM=dumb.

When TERM=dumb (common in CI, Emacs shells, etc.), color.NoColor is true, so !color.NoColor is false. However, the || fallback to isSupportedShell means color is still enabled if SHELL contains bash/zsh/fish — overriding the explicit TERM=dumb signal. This can produce garbled output in those environments.

Consider adding an early-out for TERM=dumb:

Proposed fix
 func supportsColorOutput() bool {
 	if os.Getenv("NO_COLOR") != "" {
 		return false
 	}
 
+	if os.Getenv("TERM") == "dumb" {
+		return false
+	}
+
 	if !term.IsTerminal(int(os.Stdout.Fd())) {
 		return false
 	}

2488-2499: parseLeaseDuration silently falls back on parse errors.

fmt.Sscanf errors are discarded, so malformed input like "abc:def:ghi" would silently result in 0s duration (not the 1-hour default, which only applies when the part count ≠ 3). This is acceptable since the format is validated elsewhere (the CLI flag default is well-formed), but consider logging a warning for unexpected formats if this function may be called with arbitrary input in the future.

Signed-off-by: Benny Zlotnik <bzlotnik@redhat.com>
Signed-off-by: Benny Zlotnik <bzlotnik@redhat.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
cmd/caib/main.go (1)

2492-2502: ⚠️ Potential issue | 🟡 Minor

parseLeaseDuration silently swallows parse errors.

fmt.Sscanf errors are discarded, so malformed input like "abc:def:ghi" returns 0s instead of the 1-hour default (which is only triggered when the colon-split doesn't produce 3 parts). Consider validating the Sscanf results or returning an error for clearly invalid values.

Suggested fix
 func parseLeaseDuration(duration string) time.Duration {
 	parts := strings.Split(duration, ":")
 	if len(parts) != 3 {
 		return time.Hour // Default 1 hour
 	}
-	var hours, mins, secs int
-	_, _ = fmt.Sscanf(parts[0], "%d", &hours)
-	_, _ = fmt.Sscanf(parts[1], "%d", &mins)
-	_, _ = fmt.Sscanf(parts[2], "%d", &secs)
+	hours, err1 := strconv.Atoi(parts[0])
+	mins, err2 := strconv.Atoi(parts[1])
+	secs, err3 := strconv.Atoi(parts[2])
+	if err1 != nil || err2 != nil || err3 != nil {
+		return time.Hour // Default 1 hour for invalid input
+	}
 	return time.Duration(hours)*time.Hour + time.Duration(mins)*time.Minute + time.Duration(secs)*time.Second
 }
🤖 Fix all issues with AI agents
In `@cmd/caib/main.go`:
- Around line 1670-1697: The code currently sets isFlashFailure = true whenever
flashAfterBuild is true, which misclassifies build-time failures as flash
failures; update the failure-classification logic in the block that inspects
st.Phase/lastPhase/flashAfterBuild so that isFlashFailure is only true when the
build actually reached a flash-related phase or the status message explicitly
indicates a flash error (e.g., when lastPhase == "Flashing" or
strings.Contains(strings.ToLower(st.Message), errPrefixFlash) is true), and
remove the unconditional flashAfterBuild branch (or make it conditional on
lastPhase indicating flashing) before calling handleFlashError(err, st) vs
handleError(err). Use the existing symbols st.Phase, st.Message, lastPhase,
flashAfterBuild, errPrefixFlash, handleFlashError and handleError to locate and
change the logic.
🧹 Nitpick comments (1)
cmd/caib/main.go (1)

123-147: supportsColorOutput() can disagree with fatih/color's internal NoColor check.

The custom detection on lines 128–146 uses term.IsTerminal while fatih/color uses its own isatty.IsTerminal. When these disagree, supportsColorOutput() may return true but color.New(...).SprintFunc() still produces plain text (because color.NoColor is true). The opposite is also possible due to the extra isSupportedShell / hasColorTerm fallbacks overriding color.NoColor.

In practice the output is always correct (fatih/color governs actual escape codes), but the branching is misleading. Consider aligning with the library by using color.NoColor directly, or explicitly setting color.NoColor = false when you want to override it.

Suggested simplification
 func supportsColorOutput() bool {
 	if os.Getenv("NO_COLOR") != "" {
 		return false
 	}
-
 	if !term.IsTerminal(int(os.Stdout.Fd())) {
 		return false
 	}
-
 	termType := os.Getenv("TERM")
 	if termType == "dumb" {
 		return false
 	}
-
-	shell := os.Getenv("SHELL")
-
-	isSupportedShell := strings.Contains(shell, "bash") ||
-		strings.Contains(shell, "fish") ||
-		strings.Contains(shell, "zsh")
-
-	hasColorTerm := termType != "" &&
-		!strings.Contains(termType, "mono")
-
-	return !color.NoColor || isSupportedShell || hasColorTerm
+	return !color.NoColor
 }

Comment thread cmd/caib/main.go
Signed-off-by: Benny Zlotnik <bzlotnik@redhat.com>
@bennyz bennyz requested a review from bkhizgiy February 15, 2026 10:33
@bennyz bennyz merged commit fefe424 into centos-automotive-suite:main Feb 15, 2026
4 checks passed
@bennyz bennyz deleted the fix-flash-logs branch February 15, 2026 13:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants