Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(pkg/commands): provide ExitCodeError to use in place of os.Exit #2187

Merged
merged 2 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions gnovm/cmd/gno/lint.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,8 @@ import (
)

type lintCfg struct {
verbose bool
rootDir string
setExitStatus int
verbose bool
rootDir string
// min_confidence: minimum confidence of a problem to print it (default 0.8)
// auto-fix: apply suggested fixes automatically.
}
Expand All @@ -48,7 +47,6 @@ func (c *lintCfg) RegisterFlags(fs *flag.FlagSet) {

fs.BoolVar(&c.verbose, "v", false, "verbose output when lintning")
fs.StringVar(&c.rootDir, "root-dir", rootdir, "clone location of github.com/gnolang/gno (gno tries to guess it)")
fs.IntVar(&c.setExitStatus, "set-exit-status", 1, "set exit status to 1 if any issues are found")
}

func execLint(cfg *lintCfg, args []string, io commands.IO) error {
Expand Down Expand Up @@ -135,8 +133,8 @@ func execLint(cfg *lintCfg, args []string, io commands.IO) error {
// TODO: Add more checkers
}

if hasError && cfg.setExitStatus != 0 {
os.Exit(cfg.setExitStatus)
if hasError {
return commands.ExitCodeError(1)
}

return nil
Expand Down
19 changes: 12 additions & 7 deletions gnovm/cmd/gno/lint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,25 +8,30 @@ func TestLintApp(t *testing.T) {
args: []string{"lint"},
errShouldBe: "flag: help requested",
}, {
args: []string{"lint", "--set-exit-status=0", "../../tests/integ/run_main/"},
args: []string{"lint", "../../tests/integ/run_main/"},
stderrShouldContain: "./../../tests/integ/run_main: missing 'gno.mod' file (code=1).",
errShouldBe: "exit code: 1",
}, {
args: []string{"lint", "--set-exit-status=0", "../../tests/integ/undefined_variable_test/undefined_variables_test.gno"},
args: []string{"lint", "../../tests/integ/undefined_variable_test/undefined_variables_test.gno"},
stderrShouldContain: "undefined_variables_test.gno:6: name toto not declared (code=2)",
errShouldBe: "exit code: 1",
}, {
args: []string{"lint", "--set-exit-status=0", "../../tests/integ/package_not_declared/main.gno"},
args: []string{"lint", "../../tests/integ/package_not_declared/main.gno"},
stderrShouldContain: "main.gno:4: name fmt not declared (code=2).",
errShouldBe: "exit code: 1",
}, {
args: []string{"lint", "--set-exit-status=0", "../../tests/integ/several-lint-errors/main.gno"},
args: []string{"lint", "../../tests/integ/several-lint-errors/main.gno"},
stderrShouldContain: "../../tests/integ/several-lint-errors/main.gno:5: expected ';', found example (code=2).\n../../tests/integ/several-lint-errors/main.gno:6",
errShouldBe: "exit code: 1",
}, {
args: []string{"lint", "--set-exit-status=0", "../../tests/integ/run_main/"},
args: []string{"lint", "../../tests/integ/run_main/"},
stderrShouldContain: "./../../tests/integ/run_main: missing 'gno.mod' file (code=1).",
errShouldBe: "exit code: 1",
}, {
args: []string{"lint", "--set-exit-status=0", "../../tests/integ/minimalist_gnomod/"},
args: []string{"lint", "../../tests/integ/minimalist_gnomod/"},
// TODO: raise an error because there is a gno.mod, but no .gno files
}, {
args: []string{"lint", "--set-exit-status=0", "../../tests/integ/invalid_module_name/"},
args: []string{"lint", "../../tests/integ/invalid_module_name/"},
// TODO: raise an error because gno.mod is invalid
},

Expand Down
2 changes: 1 addition & 1 deletion gnovm/cmd/gno/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@
}

if hasError {
os.Exit(1)
return nil, commands.ExitCodeError(1)

Check warning on line 166 in gnovm/cmd/gno/run.go

View check run for this annotation

Codecov / codecov/patch

gnovm/cmd/gno/run.go#L166

Added line #L166 was not covered by tests
}
return files, nil
}
Expand Down
2 changes: 1 addition & 1 deletion gnovm/cmd/gno/test.go
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@
})

if hasError {
os.Exit(1)
return commands.ExitCodeError(1)

Check warning on line 335 in gnovm/cmd/gno/test.go

View check run for this annotation

Codecov / codecov/patch

gnovm/cmd/gno/test.go#L335

Added line #L335 was not covered by tests
}
testPkgName := getPkgNameFromFileset(ifiles)

Expand Down
10 changes: 9 additions & 1 deletion tm2/pkg/commands/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,17 @@
// handles the flag.ErrHelp error, ensuring that every command with -h or
// --help won't show an error message:
// 'error parsing commandline arguments: flag: help requested'
//
// Additionally, any error of type [ErrExitCode] will be handled by exiting with
// the given status code.
func (c *Command) Execute(ctx context.Context, args []string) {
if err := c.ParseAndRun(ctx, args); err != nil {
if !errors.Is(err, flag.ErrHelp) {
var ece ExitCodeError
switch {
case errors.Is(err, flag.ErrHelp): // just exit with 1 (help already printed)
case errors.As(err, &ece):
os.Exit(int(ece))
default:

Check warning on line 123 in tm2/pkg/commands/command.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/commands/command.go#L118-L123

Added lines #L118 - L123 were not covered by tests
_, _ = fmt.Fprintf(os.Stderr, "%+v\n", err)
}
os.Exit(1)
Expand Down
16 changes: 16 additions & 0 deletions tm2/pkg/commands/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package commands

import (
"strconv"
)

// ExitCodeError is an error to terminate the program without printing any error,
// but passing in the given exit code to os.Exit.
//
// [Command.ParseAndRun] will return any ExitCodeError encountered, but
// [Command.Execute] will handle it and return an appropriate error message.
type ExitCodeError int

func (e ExitCodeError) Error() string {
return "exit code: " + strconv.Itoa(int(e))

Check warning on line 15 in tm2/pkg/commands/errors.go

View check run for this annotation

Codecov / codecov/patch

tm2/pkg/commands/errors.go#L14-L15

Added lines #L14 - L15 were not covered by tests
}
Loading