mirror of
https://github.com/go-gitea/gitea.git
synced 2026-10-08 14:12:37 +02:00
fix(cmd): print only the error on CLI usage errors
cli v3.10 dumps the full command help to stdout on a usage error (unknown flag, missing required flag, etc.). Take over that reporting via OnUsageError so usage errors print only "Incorrect Usage: <err>" to stderr and nothing to stdout, covering the auto-built completion subtree through ConfigureShellCompletionCommand. Also stop RunMainApp from printing the error a second time for non-unknown-flag usage errors. Assisted-by: Claude:Opus-4.8
This commit is contained in:
2 files changed
+27
-6
No files matched your search
@@ -202,8 +202,8 @@ func TestCliCmdError(t *testing.T) {
|
|||||||
r, err = runTestApp(app, "./gitea", "test-cmd", "--no-such")
|
r, err = runTestApp(app, "./gitea", "test-cmd", "--no-such")
|
||||||
assert.Error(t, err)
|
assert.Error(t, err)
|
||||||
assert.Equal(t, 1, r.ExitCode)
|
assert.Equal(t, 1, r.ExitCode)
|
||||||
assert.NotEmpty(t, r.Stdout) // since cli v3.10, the usage help is printed to stdout on a usage error
|
assert.Empty(t, r.Stdout)
|
||||||
assert.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n\n", r.Stderr)
|
assert.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n", r.Stderr)
|
||||||
|
|
||||||
app = newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return nil }})
|
app = newTestApp(cli.Command{Action: func(ctx context.Context, cmd *cli.Command) error { return nil }})
|
||||||
r, err = runTestApp(app, "./gitea", "test-cmd")
|
r, err = runTestApp(app, "./gitea", "test-cmd")
|
||||||
|
|||||||
+25
-4
@@ -5,10 +5,10 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"gitea.dev/modules/log"
|
"gitea.dev/modules/log"
|
||||||
"gitea.dev/modules/setting"
|
"gitea.dev/modules/setting"
|
||||||
@@ -154,16 +154,37 @@ func NewMainApp(appVer AppVersion) *cli.Command {
|
|||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// usageErr marks a usage error already reported by cliOnUsageError, so RunMainApp does not print it again.
|
||||||
|
type usageErr struct{ err error }
|
||||||
|
|
||||||
|
func (e usageErr) Error() string { return e.err.Error() }
|
||||||
|
func (e usageErr) Unwrap() error { return e.err }
|
||||||
|
|
||||||
|
// cliOnUsageError reports usage errors itself instead of letting cli dump the full help to stdout (since cli v3.10).
|
||||||
|
func cliOnUsageError(_ context.Context, cmd *cli.Command, err error, _ bool) error {
|
||||||
|
_, _ = fmt.Fprintf(cmd.Root().ErrWriter, "Incorrect Usage: %s\n", err.Error())
|
||||||
|
return usageErr{err}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setCLIOnUsageError(cmd *cli.Command) {
|
||||||
|
_ = cmd.Walk(func(c *cli.Command) error {
|
||||||
|
c.OnUsageError = cliOnUsageError
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func RunMainApp(app *cli.Command, args ...string) error {
|
func RunMainApp(app *cli.Command, args ...string) error {
|
||||||
ctx, cancel := installSignals()
|
ctx, cancel := installSignals()
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
setCLIOnUsageError(app)
|
||||||
|
// the completion subcommands are built during app.Run, after the Walk above, so cover them via this hook
|
||||||
|
app.ConfigureShellCompletionCommand = setCLIOnUsageError
|
||||||
err := app.Run(ctx, args)
|
err := app.Run(ctx, args)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if strings.HasPrefix(err.Error(), "flag provided but not defined:") {
|
if ue := (usageErr{}); errors.As(err, &ue) {
|
||||||
// the cli package should already have output the error message, so just exit
|
cli.OsExiter(1) // cliOnUsageError already reported it
|
||||||
cli.OsExiter(1)
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
_, _ = fmt.Fprintf(app.ErrWriter, "Command error: %v\n", err)
|
_, _ = fmt.Fprintf(app.ErrWriter, "Command error: %v\n", err)
|
||||||
|
|||||||
Reference in new issue
Block a user