mirror of
https://github.com/go-gitea/gitea.git
synced 2026-07-19 04:45:18 +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:
@@ -202,8 +202,8 @@ func TestCliCmdError(t *testing.T) {
|
||||
r, err = runTestApp(app, "./gitea", "test-cmd", "--no-such")
|
||||
assert.Error(t, err)
|
||||
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.Equal(t, "Incorrect Usage: flag provided but not defined: -no-such\n\n", r.Stderr)
|
||||
assert.Empty(t, r.Stdout)
|
||||
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 }})
|
||||
r, err = runTestApp(app, "./gitea", "test-cmd")
|
||||
|
||||
29
cmd/main.go
29
cmd/main.go
@@ -5,10 +5,10 @@ package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"gitea.dev/modules/log"
|
||||
"gitea.dev/modules/setting"
|
||||
@@ -154,16 +154,37 @@ func NewMainApp(appVer AppVersion) *cli.Command {
|
||||
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 {
|
||||
ctx, cancel := installSignals()
|
||||
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)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
if strings.HasPrefix(err.Error(), "flag provided but not defined:") {
|
||||
// the cli package should already have output the error message, so just exit
|
||||
cli.OsExiter(1)
|
||||
if ue := (usageErr{}); errors.As(err, &ue) {
|
||||
cli.OsExiter(1) // cliOnUsageError already reported it
|
||||
return err
|
||||
}
|
||||
_, _ = fmt.Fprintf(app.ErrWriter, "Command error: %v\n", err)
|
||||
|
||||
Reference in New Issue
Block a user