Skip to content

fix: support colour output in CI via FORCE_COLOR/CLICOLOR_FORCE - #622

Open
NickJosevski wants to merge 4 commits into
mainfrom
nj/fix-506
Open

fix: support colour output in CI via FORCE_COLOR/CLICOLOR_FORCE#622
NickJosevski wants to merge 4 commits into
mainfrom
nj/fix-506

Conversation

@NickJosevski

Copy link
Copy Markdown
Contributor

Fixes #506

Problem

Colour was gated solely on term.IsTerminal(os.Stdout.Fd()), which never resolves to true inside a CI job. CI systems that do render ANSI codes — GitHub Actions, GitLab CI — could therefore never show coloured output.

Change

pkg/output/color.go now follows the conventions from no-color.org and bixense.com/clicolors:

Condition Result
NO_COLOR set to anything non-empty colour off (highest precedence)
CLICOLOR_FORCE or FORCE_COLOR set to anything but 0 colour on, even without a TTY
otherwise existing terminal detection

This is opt-in, so CI output stays plain unless asked for. Auto-enabling on a CI env var would inject escape codes into the logs of systems that don't render them, and would break anyone currently parsing CLI output in a pipeline.

Verification

Unit tests cover the precedence matrix. Manually against a build:

$ octopus --help | cat -v | head -3
Work seamlessly with Octopus Deploy from the command line.
                ####

$ FORCE_COLOR=1 octopus --help | cat -v | head -3
Work seamlessly with Octopus Deploy from the command line.
^[[0;36m                ####

README documents the variables under Getting Started.

🤖 Generated with Claude Code

Colour was gated solely on term.IsTerminal(stdout), which never resolves
to true in a CI job, so CI systems that do render ANSI codes (GitHub
Actions, GitLab CI) could never show coloured output.

Honour the conventional CLICOLOR_FORCE and FORCE_COLOR opt-ins, keeping
NO_COLOR as the highest-precedence override. Terminal detection remains
the default so existing non-CI behaviour is unchanged, and CI output
stays plain unless explicitly opted in.

Fixes #506

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@NickJosevski
NickJosevski marked this pull request as ready for review August 4, 2026 07:48

@YuKitsune YuKitsune left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I ran this locally and noticed the Octopus logo was still appearing in cyan. Taking a look at color.go, many of the functions there ignore the IsColorEnabled flag. Is this intentional?

Setting one of the force variables to 0 fell through to terminal
detection, so `FORCE_COLOR=0 octopus --help` in a terminal still printed
the cyan Octopus logo. Both bixense.com/clicolors and the de facto
FORCE_COLOR convention treat 0 as an instruction to disable colour, so
an explicitly set force variable now overrides terminal detection in
both directions. CLICOLOR=0 is honoured for the same reason.

Terminal detection is now injected into the decision function so the
table can be tested with and without a TTY, and tests assert that every
exported helper in color.go honours IsColorEnabled.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@NickJosevski

NickJosevski commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

I'm still testing this myself...

NickJosevski and others added 2 commits August 5, 2026 16:05
Builds the CLI at main, at the PR as reviewed, and at the PR with the
review fix, then prints `octopus --help` under a matrix of colour
environment variables so the before/after can be seen in a real CI log.

GitHub Actions renders ANSI colour but attaches no TTY, which is exactly
the situation issue #506 describes. A second job re-runs the cases that
only apply to a terminal under a pty allocated with `script`, covering
the FORCE_COLOR=0 case raised in review. Both jobs assert the expected
outcomes rather than only printing them.

Demo only: runs on this branch and manual dispatch, and can be dropped
before merge.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Colour was applied by wrapping a whole string in a single escape and a
single reset. A terminal renders that correctly, but log viewers are
less forgiving: GitHub Actions resets SGR state at every line break, so
the 18-line Octopus logo carried one escape at the top and rendered
entirely plain. Colour reached CI but could not be seen there, which is
most of the point of #506.

Wrap each line separately instead. Terminal output is unchanged, blank
lines are left alone so they do not collect stray escapes, and the logo
now renders in GitHub Actions and GitLab CI logs.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@NickJosevski

Copy link
Copy Markdown
Contributor Author

@YuKitsune i's about colours being displayed on build agents/CI/etc, but then it became very obvious I shouldn't trust claude to verify how it looks.

So yes found more issues, so got it to write Actions to prove it to me:

CleanShot 2026-08-05 at 16 33 05@2x

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.

Support color output for CI jobs

2 participants