diff --git a/cmd/packages.go b/cmd/packages.go index 248f78f7b..8d3d0028f 100644 --- a/cmd/packages.go +++ b/cmd/packages.go @@ -49,7 +49,6 @@ const ( var ( packagesPresenterOpt packages.PresenterOption - packagesArgs = cobra.MaximumNArgs(1) packagesCmd = &cobra.Command{ Use: "packages [SOURCE]", Short: "Generate a package SBOM", @@ -58,18 +57,10 @@ var ( "appName": internal.ApplicationName, "command": "packages", }), - Args: packagesArgs, + Args: validateInputArgs, SilenceUsage: true, SilenceErrors: true, PreRunE: func(cmd *cobra.Command, args []string) error { - if len(args) == 0 { - err := cmd.Help() - if err != nil { - return err - } - return fmt.Errorf("an image/directory argument is required") - } - // set the presenter presenterOption := packages.ParsePresenterOption(appConfig.Output) if presenterOption == packages.UnknownPresenterOption { @@ -194,6 +185,18 @@ func bindPackagesConfigOptions(flags *pflag.FlagSet) error { return nil } +func validateInputArgs(cmd *cobra.Command, args []string) error { + if len(args) == 0 { + // in the case that no arguments are given we want to show the help text and return with a non-0 return code. + if err := cmd.Help(); err != nil { + return fmt.Errorf("unable to display help: %w", err) + } + return fmt.Errorf("an image/directory argument is required") + } + + return cobra.MaximumNArgs(1)(cmd, args) +} + func packagesExec(_ *cobra.Command, args []string) error { // could be an image or a directory, with or without a scheme userInput := args[0] diff --git a/cmd/power_user.go b/cmd/power_user.go index 3b1eacff5..85126f737 100644 --- a/cmd/power_user.go +++ b/cmd/power_user.go @@ -35,19 +35,11 @@ var powerUserCmd = &cobra.Command{ "appName": internal.ApplicationName, "command": "power-user", }), - Args: cobra.MaximumNArgs(1), + Args: validateInputArgs, Hidden: true, SilenceUsage: true, SilenceErrors: true, PreRunE: func(cmd *cobra.Command, args []string) error { - if len(args) == 0 { - err := cmd.Help() - if err != nil { - return err - } - return fmt.Errorf("an image/directory argument is required") - } - if appConfig.Dev.ProfileCPU && appConfig.Dev.ProfileMem { return fmt.Errorf("cannot profile CPU and memory simultaneously") } diff --git a/test/cli/trait_assertions_test.go b/test/cli/trait_assertions_test.go index 465149999..90728aae1 100644 --- a/test/cli/trait_assertions_test.go +++ b/test/cli/trait_assertions_test.go @@ -14,6 +14,7 @@ import ( type traitAssertion func(tb testing.TB, stdout, stderr string, rc int) func assertJsonReport(tb testing.TB, stdout, _ string, _ int) { + tb.Helper() var data interface{} if err := json.Unmarshal([]byte(stdout), &data); err != nil { @@ -22,6 +23,7 @@ func assertJsonReport(tb testing.TB, stdout, _ string, _ int) { } func assertTableReport(tb testing.TB, stdout, _ string, _ int) { + tb.Helper() if !strings.Contains(stdout, "NAME") || !strings.Contains(stdout, "VERSION") || !strings.Contains(stdout, "TYPE") { tb.Errorf("expected to find a table report, but did not") } @@ -29,6 +31,7 @@ func assertTableReport(tb testing.TB, stdout, _ string, _ int) { func assertScope(scope source.Scope) traitAssertion { return func(tb testing.TB, stdout, stderr string, rc int) { + tb.Helper() // we can only verify source with the json report assertJsonReport(tb, stdout, stderr, rc) @@ -44,6 +47,7 @@ func assertLoggingLevel(level string) traitAssertion { // "[0012] DEBUG" logPattern := regexp.MustCompile(`(?m)^\[\d\d\d\d\]\s+` + strings.ToUpper(level)) return func(tb testing.TB, _, stderr string, _ int) { + tb.Helper() if !logPattern.MatchString(stripansi.Strip(stderr)) { tb.Errorf("output did not indicate the %q logging level", level) } @@ -52,6 +56,7 @@ func assertLoggingLevel(level string) traitAssertion { func assertNotInOutput(data string) traitAssertion { return func(tb testing.TB, stdout, stderr string, _ int) { + tb.Helper() if strings.Contains(stripansi.Strip(stderr), data) { tb.Errorf("data=%q was found in stderr, but should not have been there", data) } @@ -63,6 +68,7 @@ func assertNotInOutput(data string) traitAssertion { func assertInOutput(data string) traitAssertion { return func(tb testing.TB, stdout, stderr string, _ int) { + tb.Helper() if !strings.Contains(stripansi.Strip(stderr), data) && !strings.Contains(stripansi.Strip(stdout), data) { tb.Errorf("data=%q was NOT found in any output, but should have been there", data) } @@ -70,12 +76,14 @@ func assertInOutput(data string) traitAssertion { } func assertFailingReturnCode(tb testing.TB, _, _ string, rc int) { + tb.Helper() if rc == 0 { tb.Errorf("expected a failure but got rc=%d", rc) } } func assertSuccessfulReturnCode(tb testing.TB, _, _ string, rc int) { + tb.Helper() if rc != 0 { tb.Errorf("expected no failure but got rc=%d", rc) } diff --git a/test/cli/utils_test.go b/test/cli/utils_test.go index b52302833..550377dd3 100644 --- a/test/cli/utils_test.go +++ b/test/cli/utils_test.go @@ -50,23 +50,20 @@ func runSyftInDocker(t testing.TB, env map[string]string, image string, args ... func runSyft(t testing.TB, env map[string]string, args ...string) (*exec.Cmd, string, string) { cmd := getSyftCommand(t, args...) - if env != nil { - env["SYFT_CHECK_FOR_APP_UPDATE"] = "false" + if env == nil { + env = make(map[string]string) } + + // we should not have tests reaching out for app update checks + env["SYFT_CHECK_FOR_APP_UPDATE"] = "false" + stdout, stderr := runCommand(cmd, env) return cmd, stdout, stderr } func runCommand(cmd *exec.Cmd, env map[string]string) (string, string) { if env != nil { - var envList []string - for key, val := range env { - if key == "" { - continue - } - envList = append(envList, fmt.Sprintf("%s=%s", key, val)) - } - cmd.Env = envList + cmd.Env = append(os.Environ(), envMapToSlice(env)...) } var stdout, stderr bytes.Buffer cmd.Stdout = &stdout @@ -78,6 +75,16 @@ func runCommand(cmd *exec.Cmd, env map[string]string) (string, string) { return stdout.String(), stderr.String() } +func envMapToSlice(env map[string]string) (envList []string) { + for key, val := range env { + if key == "" { + continue + } + envList = append(envList, fmt.Sprintf("%s=%s", key, val)) + } + return +} + func getSyftCommand(t testing.TB, args ...string) *exec.Cmd { return exec.Command(getSyftBinaryLocation(t), args...) }