Skip to content

Commit 225ea0a

Browse files
committed
Gate update check on terminal-attachment, not NO_COLOR
1 parent 5d82aac commit 225ea0a

3 files changed

Lines changed: 20 additions & 16 deletions

File tree

‎cmd/root.go‎

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -246,15 +246,12 @@ func newRootCmd(v string) *cobra.Command {
246246
func Execute() {
247247
root := newRootCmd(version)
248248

249-
// Pre-flight skip: the opt-out env var, CI, stderr TTY-ness, and the build
250-
// version are all known before the command parses its flags, so when any
251-
// of them opts out we never launch the network call at all. (JSONMode and
252-
// Quiet come from flags parsed during Execute, so they can't be evaluated
253-
// here — they're handled by the post-command notice gate below, which may
254-
// still suppress a notice whose cache refresh we deliberately allowed.)
249+
// Skip the network call entirely for opt-outs knowable before flags parse.
250+
// Uses IsTerminal, not IsTTY, so NO_COLOR (a styling pref) still gets checks.
251+
// JSONMode/Quiet are flag-derived and gate only the notice, below.
255252
preSkip := updater.ShouldSkip(updater.Conditions{
256253
CurrentVersion: version,
257-
StderrTTY: ui.IsTTY(root.ErrOrStderr()),
254+
StderrTTY: ui.IsTerminal(root.ErrOrStderr()),
258255
OptOut: env.UpdateNotifierOptOut(),
259256
})
260257

@@ -264,28 +261,24 @@ func Execute() {
264261
defer updCancel()
265262
resultCh := make(chan updater.Result, 1)
266263
if preSkip == updater.SkipNone {
264+
// Run even when we may end up skipping the notice (e.g. JSON mode) so
265+
// the cache still refreshes; the gate below decides on printing.
267266
go func() {
268-
// Conservatively run the network call even when we might end up
269-
// skipping the *notice* (e.g. JSON mode), so the cache refresh
270-
// still happens. The notice gate below makes the final call.
271267
resultCh <- updater.Check(updCtx, version, updater.CacheDir())
272268
}()
273269
}
274270

275271
runErr := root.Execute()
276272

277-
// Decide whether the *notice* should be considered for printing. This
278-
// is the gate the user perceives — silent skips don't even touch the
279-
// channel below, so a hung check doesn't delay exit in those cases. When
280-
// the pre-flight already opted out, no goroutine is running, so we keep
281-
// that reason and never wait on the channel.
273+
// Re-check with the now-parsed flags to gate the notice. If the pre-flight
274+
// already opted out, no goroutine ran, so keep that reason.
282275
skip := preSkip
283276
if skip == updater.SkipNone {
284277
skip = updater.ShouldSkip(updater.Conditions{
285278
CurrentVersion: version,
286279
JSONMode: jsonOutput,
287280
Quiet: quietMode,
288-
StderrTTY: ui.IsTTY(root.ErrOrStderr()),
281+
StderrTTY: ui.IsTerminal(root.ErrOrStderr()),
289282
OptOut: env.UpdateNotifierOptOut(),
290283
})
291284
}

‎internal/ui/spinner.go‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,12 @@ var isTerminal = func(w io.Writer) bool {
4949
return term.IsTerminal(int(f.Fd()))
5050
}
5151

52+
// IsTerminal reports whether w is a terminal, ignoring NO_COLOR. Use it for
53+
// interactivity decisions; IsTTY (which honors NO_COLOR) is for styling.
54+
func IsTerminal(w io.Writer) bool {
55+
return isTerminal(w)
56+
}
57+
5258
// terminalWidth returns the column count of the terminal w is writing to,
5359
// or 0 if w isn't a TTY or the size can't be determined. Re-measured on
5460
// every frame so the progress bar tracks terminal resizes.

‎internal/ui/spinner_test.go‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ func TestIsTTY_NoColor(t *testing.T) {
5959
t.Errorf("NO_COLOR=yes: IsTTY should be false, got true")
6060
}
6161

62+
// IsTerminal ignores NO_COLOR, so it stays true here.
63+
if !IsTerminal(&buf) {
64+
t.Errorf("NO_COLOR set: IsTerminal should stay true")
65+
}
66+
6267
// Sanity-check style helpers respect the propagated decision.
6368
if got := Cyan("x", IsTTY(&buf)); got != "x" {
6469
t.Errorf("Cyan with NO_COLOR set should return %q, got %q", "x", got)

0 commit comments

Comments
 (0)