diff --git a/cmd/generate/codeowners/codeowners.go b/cmd/generate/codeowners/codeowners.go index 2f4bbdc..f2ad82b 100644 --- a/cmd/generate/codeowners/codeowners.go +++ b/cmd/generate/codeowners/codeowners.go @@ -36,7 +36,8 @@ type Options struct { // telemetry for capturing CLI events via PostHog telemetry *utils.PosthogCliClient - config *config.Spec + config *config.Spec + configLoadedPath string } const codeownersLongDesc string = `Generates a CODEOWNERS file for a given git repository. The generated file specifies up to 3 owners for EVERY file in the git tree based on the number of lines touched in that specific file over the specified range of time. @@ -102,7 +103,11 @@ pizza generate codeowners . --config /path/to/.sauced.yaml opts.telemetry = utils.NewPosthogCliClient(!disableTelem) configPath, _ := cmd.Flags().GetString("config") - opts.config, err = config.LoadConfig(configPath) + if configPath == "" { + configPath = filepath.Join(opts.path, ".sauced.yaml") + } + + opts.config, opts.configLoadedPath, err = config.LoadConfig(configPath) if err != nil { return err } @@ -148,6 +153,7 @@ func run(opts *Options, cmd *cobra.Command) error { return fmt.Errorf("could not build logger: %w", err) } opts.logger.V(logging.LogDebug).Style(0, colors.FgBlue).Infof("Built logger with log level: %d\n", opts.loglevel) + opts.logger.V(logging.LogDebug).Style(0, colors.FgBlue).Infof("Loaded config from: %s\n", opts.configLoadedPath) repo, err := git.PlainOpen(opts.path) if err != nil { diff --git a/cmd/root/root.go b/cmd/root/root.go index 7b35e4a..bbf81ae 100644 --- a/cmd/root/root.go +++ b/cmd/root/root.go @@ -36,7 +36,7 @@ func NewRootCommand() (*cobra.Command, error) { cmd.PersistentFlags().StringP(constants.FlagNameEndpoint, "e", constants.EndpointProd, "The API endpoint to send requests to") cmd.PersistentFlags().Bool(constants.FlagNameBeta, false, fmt.Sprintf("Shorthand for using the beta OpenSauced API endpoint (\"%s\"). Supersedes the '--%s' flag", constants.EndpointBeta, constants.FlagNameEndpoint)) cmd.PersistentFlags().Bool(constants.FlagNameTelemetry, false, "Disable sending telemetry data to OpenSauced") - cmd.PersistentFlags().StringP("config", "c", "~/.sauced.yaml", "The codeowners config") + cmd.PersistentFlags().StringP("config", "c", "", "The codeowners config") cmd.PersistentFlags().StringP("log-level", "l", "info", "The logging level. Options: error, warn, info, debug") cmd.PersistentFlags().Bool("tty-disable", false, "Disable log stylization. Suitable for CI/CD and automation") diff --git a/pkg/config/config.go b/pkg/config/config.go index ed722c5..98ec6f6 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -9,55 +9,57 @@ import ( "gopkg.in/yaml.v3" ) -// LoadConfig loads a configuration file at a given path. It attempts to load -// the default location of a ".sauced.yaml" in the current working directory if an -// empty path is provided. If none is found, it tries to load -// "~/.sauced.yaml" from the fallback path, which is the user's home directory. -func LoadConfig(path string) (*Spec, error) { - println("Config path loading from -c flag", path) +// LoadConfig loads a configuration file at a given path. +// If the provided path does not exist or doesn't contain a ".sauced.yaml" file, +// "~/.sauced.yaml" from the fallback path, which is the user's home directory, is used. +// +// This function returns the config Spec, the location the spec was loaded from, and an error +func LoadConfig(path string) (*Spec, string, error) { + givenPathSpec, givenLoadedPath, givenPathErr := loadSpecAtPath(path) + if givenPathErr == nil { + return givenPathSpec, givenLoadedPath, nil + } + + homePathSpec, homeLoadedPath, homePathErr := loadSpecAtHome() + if homePathErr == nil { + return homePathSpec, homeLoadedPath, nil + } + return nil, "", fmt.Errorf("could not load config at given path: %w - could not load config at home: %w", givenPathErr, homePathErr) +} + +func loadSpecAtPath(path string) (*Spec, string, error) { config := &Spec{} absPath, err := filepath.Abs(path) if err != nil { - return nil, fmt.Errorf("error resolving absolute path: %w", err) + return nil, "", fmt.Errorf("error resolving absolute path: %s - %w", path, err) } data, err := os.ReadFile(absPath) if err != nil { - // If the file does not exist, check if the fallback path exists - if os.IsNotExist(err) { - // load the default file path under the user's home dir - usr, err := user.Current() - - if err != nil { - return nil, fmt.Errorf("could not get user home directory: %w", err) - } - - homeDirPathConfig, err := filepath.Abs(filepath.Join(usr.HomeDir, ".sauced.yaml")) - - if err != nil { - return nil, fmt.Errorf("error home directory absolute path: %w", err) - } - - _, err = os.Stat(homeDirPathConfig) - if err != nil { - return nil, fmt.Errorf("error reading config file from %s", homeDirPathConfig) - } - - data, err = os.ReadFile(homeDirPathConfig) - if err != nil { - return nil, fmt.Errorf("error reading config file from %s or %s", absPath, homeDirPathConfig) - } - } else { - return nil, fmt.Errorf("error reading config file: %w", err) - } + return nil, "", fmt.Errorf("error reading config file from given absolute path: %s - %w", absPath, err) } err = yaml.Unmarshal(data, config) if err != nil { - return nil, fmt.Errorf("error unmarshaling config: %w", err) + return nil, "", fmt.Errorf("error unmarshaling config at: %s - %w", absPath, err) + } + + return config, absPath, nil +} + +func loadSpecAtHome() (*Spec, string, error) { + usr, err := user.Current() + if err != nil { + return nil, "", fmt.Errorf("could not get user home directory: %w", err) + } + + path := filepath.Join(usr.HomeDir, ".sauced.yaml") + conf, loadedPath, err := loadSpecAtPath(path) + if err != nil { + return nil, "", fmt.Errorf("could not load spec at home: %s - %w", path, err) } - return config, nil + return conf, loadedPath, nil } diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index c0da2e6..8611f5e 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -30,7 +30,7 @@ attribution: require.NoError(t, os.WriteFile(configFilePath, []byte(fileContents), 0600)) - config, err := LoadConfig(configFilePath) + config, _, err := LoadConfig(configFilePath) require.NoError(t, err) assert.NotNil(t, config) @@ -47,7 +47,7 @@ attribution: tmpDir := t.TempDir() nonExistentPath := filepath.Join(tmpDir, ".sauced.yaml") - config, err := LoadConfig(nonExistentPath) + config, _, err := LoadConfig(nonExistentPath) require.Error(t, err) assert.Nil(t, config) }) @@ -78,7 +78,7 @@ attribution: _, err := os.ReadFile(fallbackPath) require.NoError(t, err) - config, err := LoadConfig(fallbackPath) + config, _, err := LoadConfig(fallbackPath) require.NoError(t, err) assert.NotNil(t, config)