fix(output): always report warnings on stderr

Signed-off-by: bircni <bircni@icloud.com>
This commit is contained in:
bircni committed 2026-10-12 20:27:12 +02:00
1 parent badd934d64
commit 102de5a2c2
3 files changed
+10 -8

No files matched your search

+2 -1
View File
@@ -298,7 +298,8 @@ of printing nothing. See `tea help formatting`.
When stdout is not a terminal, lists print tab-separated values without header, When stdout is not a terminal, lists print tab-separated values without header,
color or links, with times in RFC 3339 UTC, and a `--page` hint goes to stderr; color or links, with times in RFC 3339 UTC, and a `--page` hint goes to stderr;
prefer `--json` in scripts. Commands that change resources report each change on prefer `--json` in scripts. Commands that change resources report each change on
stderr only on a terminal. Create commands print the URL of the new resource on stderr only on a terminal; warnings, such as a step that was skipped or failed,
always go to stderr. Create commands print the URL of the new resource on
stdout, so `url=$(tea issue create …)` works; other changes print nothing when stdout, so `url=$(tea issue create …)` works; other changes print nothing when
piped. Bodies are rendered as Markdown only on a terminal (`tea config set piped. Bodies are rendered as Markdown only on a terminal (`tea config set
markdown raw` turns this off). See `tea help formatting` for the terminal layout. markdown raw` turns this off). See `tea help formatting` for the terminal layout.
+6 -5
View File
@@ -133,19 +133,20 @@ func writeView[T any](a *application, cmd *cobra.Command, item T, view func(T) t
// done reports a completed mutation on stderr, such as "✓ Closed issue alice/x#5 (Fix login)", // done reports a completed mutation on stderr, such as "✓ Closed issue alice/x#5 (Fix login)",
// when people read stdout: on a TTY and without --json. // when people read stdout: on a TTY and without --json.
func (a *application) done(cmd *cobra.Command, format string, args ...any) { func (a *application) done(cmd *cobra.Command, format string, args ...any) {
if !a.deps.Streams.OutTTY || a.options.json != "" {
return
}
a.feedback(cmd, "✓", "green", format, args...) a.feedback(cmd, "✓", "green", format, args...)
} }
// warn reports a mutation that had nothing to do, such as "! Issue alice/x#5 (Fix login) is already // warn reports on stderr a mutation that had nothing to do, such as "! Issue alice/x#5 (Fix login)
// closed", under the same conditions as done. // is already closed", or a part of one that failed. Unlike done it is never silenced, so scripts
// and --json callers still learn about partial failures.
func (a *application) warn(cmd *cobra.Command, format string, args ...any) { func (a *application) warn(cmd *cobra.Command, format string, args ...any) {
a.feedback(cmd, "!", "yellow", format, args...) a.feedback(cmd, "!", "yellow", format, args...)
} }
func (a *application) feedback(cmd *cobra.Command, icon, color, format string, args ...any) { func (a *application) feedback(cmd *cobra.Command, icon, color, format string, args ...any) {
if !a.deps.Streams.OutTTY || a.options.json != "" {
return
}
fmt.Fprintln(cmd.ErrOrStderr(), terminal.Colorize(color, icon, a.colorEnabled())+" "+terminal.SafeLine(fmt.Sprintf(format, args...))) fmt.Fprintln(cmd.ErrOrStderr(), terminal.Colorize(color, icon, a.colorEnabled())+" "+terminal.SafeLine(fmt.Sprintf(format, args...)))
} }
+2 -2
View File
@@ -359,8 +359,8 @@ func TestMutationFeedback(t *testing.T) {
tty bool tty bool
}{ }{
{name: "terminal", tty: true, out: "https://example.org/12\n", stderr: "✓ Created issue alice/x#12 (Fix[2J login)\n! Issue alice/x#12 (Fix[2J login) is already closed\n"}, {name: "terminal", tty: true, out: "https://example.org/12\n", stderr: "✓ Created issue alice/x#12 (Fix[2J login)\n! Issue alice/x#12 (Fix[2J login) is already closed\n"},
{name: "piped", out: "https://example.org/12\n"}, {name: "piped", out: "https://example.org/12\n", stderr: "! Issue alice/x#12 (Fix[2J login) is already closed\n"},
{name: "JSON", tty: true, json: "number"}, {name: "JSON", tty: true, json: "number", stderr: "! Issue alice/x#12 (Fix[2J login) is already closed\n"},
} { } {
t.Run(tc.name, func(t *testing.T) { t.Run(tc.name, func(t *testing.T) {
deps, out, diagnostics := testDeps(t) deps, out, diagnostics := testDeps(t)