diff --git a/cmd/generate/codeowners/codeowners.go b/cmd/generate/codeowners/codeowners.go index 3da44f8..149d525 100644 --- a/cmd/generate/codeowners/codeowners.go +++ b/cmd/generate/codeowners/codeowners.go @@ -26,6 +26,9 @@ type Options struct { // The default should be to generate a GitHub style "CODEOWNERS" file. ownersStyleFile bool + // where the output file will go + outputPath string + // the number of days to look back previousDays int @@ -113,6 +116,7 @@ pizza generate codeowners . --config /path/to/.sauced.yaml } opts.ownersStyleFile, _ = cmd.Flags().GetBool("owners-style-file") + opts.outputPath, _ = cmd.Flags().GetString("output-path") opts.previousDays, _ = cmd.Flags().GetInt("range") opts.tty, _ = cmd.Flags().GetBool("tty-disable") @@ -139,6 +143,7 @@ pizza generate codeowners . --config /path/to/.sauced.yaml cmd.PersistentFlags().IntP("range", "r", 90, "The number of days to analyze commit history (default 90)") cmd.PersistentFlags().Bool("owners-style-file", false, "Generate an agnostic OWNERS style file instead of CODEOWNERS.") + cmd.PersistentFlags().StringP("output-path", "o", "./", "Directory to create the output file.") return cmd } @@ -176,21 +181,24 @@ func run(opts *Options, cmd *cobra.Command) error { return fmt.Errorf("error traversing git log: %w", err) } - // Bootstrap codeowners - var outputPath string + // Add optional output path to base path + fullOutputPath := filepath.Join(opts.path, opts.outputPath) + + // Define the file type based on a flag + var finalOutputPath string if opts.ownersStyleFile { - outputPath = filepath.Join(opts.path, "OWNERS") + finalOutputPath = filepath.Join(fullOutputPath, "OWNERS") } else { - outputPath = filepath.Join(opts.path, "CODEOWNERS") + finalOutputPath = filepath.Join(fullOutputPath, "CODEOWNERS") } - opts.logger.V(logging.LogDebug).Style(0, colors.FgBlue).Infof("Processing codeowners file at: %s\n", outputPath) - err = generateOutputFile(codeowners, outputPath, opts, cmd) + opts.logger.V(logging.LogDebug).Style(0, colors.FgBlue).Infof("Processing codeowners file at: %s\n", finalOutputPath) + err = generateOutputFile(codeowners, finalOutputPath, opts, cmd) if err != nil { _ = opts.telemetry.CaptureFailedCodeownersGenerate() return fmt.Errorf("error generating github style codeowners file: %w", err) } - opts.logger.V(logging.LogInfo).Style(0, colors.FgGreen).Infof("Finished generating file: %s\n", outputPath) + opts.logger.V(logging.LogInfo).Style(0, colors.FgGreen).Infof("Finished generating file: %s\n", finalOutputPath) _ = opts.telemetry.CaptureCodeownersGenerate() opts.logger.V(logging.LogInfo).Style(0, colors.FgCyan).Infof("\nCreate an OpenSauced Contributor Insight to get metrics and insights on these codeowners:\n") diff --git a/cmd/generate/codeowners/output.go b/cmd/generate/codeowners/output.go index a4bd1c4..6b51054 100644 --- a/cmd/generate/codeowners/output.go +++ b/cmd/generate/codeowners/output.go @@ -15,6 +15,15 @@ import ( ) func generateOutputFile(fileStats FileStats, outputPath string, opts *Options, cmd *cobra.Command) error { + + // Create specified output directories if necessary + err := os.MkdirAll(filepath.Dir(outputPath), os.ModePerm) + if err != nil { + if !os.IsExist(err) { + return fmt.Errorf("error creating directory at %s filepath: %w", outputPath, err) + } + } + // Open the file for writing file, err := os.Create(outputPath) if err != nil {