diff --git a/cmd/root.go b/cmd/root.go index 4dccf166d644..f7f805ae255a 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -16,6 +16,7 @@ package cmd import ( + "bufio" "context" "fmt" "os" @@ -90,6 +91,21 @@ func rootCmd(o *options.Options) error { ctx := context.Background() logger := sclog.NewLogger(sclog.ParseLevel(o.LogLevel)) + + var outFile *os.File + + if o.ResultsFile != "" { + outFile, err = os.Create(o.ResultsFile) + if err != nil { + panic(err) + } + defer outFile.Close() + os.Stdout = outFile + os.Stderr = outFile + + fmt.Fprintf(os.Stderr, "Repo Queried: %s\n\n", o.Repo) + } + repoURI, repoClient, ossFuzzRepoClient, ciiClient, vulnsClient, err := checker.GetClients( ctx, o.Repo, o.Local, logger) // MODIFIED if err != nil { @@ -170,5 +186,10 @@ func rootCmd(o *options.Options) error { return sce.WithMessage(sce.ErrorCheckRuntime, fmt.Sprintf("%s: %v", result.Name, result.Error)) } } + + if outFile != nil { + writer := bufio.NewWriter(outFile) + defer writer.Flush() + } return nil } diff --git a/options/flags.go b/options/flags.go index 1652c9fd18ae..8b92983fbf84 100644 --- a/options/flags.go +++ b/options/flags.go @@ -64,6 +64,9 @@ const ( FlagFormat = "format" FlagCommitDepth = "commit-depth" + + // FlagResultsFile is the flag name for storing stdout and stderr output + FlagResultsFile = "resultsfile" ) // Command is an interface for handling options for command-line utilities. @@ -162,6 +165,13 @@ func (o *Options) AddFlags(cmd *cobra.Command) { fmt.Sprintf("Checks to run. Possible values are: %s", strings.Join(checkNames, ",")), ) + cmd.Flags().StringVar( + &o.ResultsFile, + FlagResultsFile, + o.ResultsFile, + "Output results and errors to file", + ) + // TODO(options): Extract logic allowedFormats := []string{ FormatDefault, diff --git a/options/flags_test.go b/options/flags_test.go index ff4a38b3e4df..9bc09bfd4431 100644 --- a/options/flags_test.go +++ b/options/flags_test.go @@ -43,6 +43,7 @@ func TestOptions_AddFlags(t *testing.T) { ChecksToRun: []string{"check1", "check2"}, PolicyFile: "policy-file", Format: "json", + ResultsFile: "resultsFile.log", }, }, } @@ -89,6 +90,11 @@ func TestOptions_AddFlags(t *testing.T) { t.Errorf("expected FlagRubyGems to be %q, but got %q", tt.opts.RubyGems, cmd.Flag(FlagRubyGems).Value.String()) } + // check ResultsFile + if cmd.Flag(FlagResultsFile).Value.String() != tt.opts.ResultsFile { + t.Errorf("expected ResultsFile to be %q, but got %q", tt.opts.ResultsFile, cmd.Flag(FlagResultsFile).Value.String()) + } + var e1 []string for _, f := range strings.Split(cmd.Flag(FlagChecks).Value.String(), ",") { f = strings.TrimPrefix(f, "[") diff --git a/options/options.go b/options/options.go index 5be1fda1febe..f4d528b44f85 100644 --- a/options/options.go +++ b/options/options.go @@ -29,17 +29,16 @@ import ( // Options define common options for configuring scorecard. type Options struct { - Repo string - Local string - Commit string - LogLevel string - Format string - NPM string - PyPI string - RubyGems string - Nuget string - PolicyFile string - // TODO(action): Add logic for writing results to file + Repo string + Local string + Commit string + LogLevel string + Format string + NPM string + PyPI string + RubyGems string + Nuget string + PolicyFile string ResultsFile string ChecksToRun []string Metadata []string