package config import ( "fmt" "os" "path/filepath" "github.com/spf13/viper" ) // Config represents the application configuration type Config struct { // Git settings DefaultRemote string `mapstructure:"default_remote"` DefaultBranch string `mapstructure:"default_branch"` // GitHub settings GitHubToken string `mapstructure:"github_token"` GitHubURL string `mapstructure:"github_url"` // Behavior settings AutoCleanup bool `mapstructure:"auto_cleanup"` ConfirmDestructive bool `mapstructure:"confirm_destructive"` DryRun bool `mapstructure:"dry_run"` Verbose bool `mapstructure:"verbose"` // Branch settings BranchPrefix string `mapstructure:"branch_prefix"` FeaturePrefix string `mapstructure:"feature_prefix"` HotfixPrefix string `mapstructure:"hotfix_prefix"` } var ( // GlobalConfig holds the application configuration GlobalConfig *Config // configFile is the path to the configuration file configFile string // v is the viper instance v *viper.Viper ) // initViper initializes the viper instance func initViper() { if v == nil { v = viper.New() } } // Init initializes the configuration func Init() error { initViper() // Set default values v.SetDefault("default_remote", "origin") v.SetDefault("default_branch", "main") v.SetDefault("github_url", "https://api.github.com") v.SetDefault("auto_cleanup", false) v.SetDefault("confirm_destructive", true) v.SetDefault("dry_run", false) v.SetDefault("verbose", false) v.SetDefault("branch_prefix", "") v.SetDefault("feature_prefix", "feature/") v.SetDefault("hotfix_prefix", "hotfix/") // Set configuration file paths home, err := os.UserHomeDir() if err != nil { return fmt.Errorf("could not get user home directory: %w", err) } configDir := filepath.Join(home, ".gitauto") configFile = filepath.Join(configDir, "config.yaml") // Ensure config directory exists if err := os.MkdirAll(configDir, 0755); err != nil { return fmt.Errorf("could not create config directory: %w", err) } // Set configuration file v.SetConfigName("config") v.SetConfigType("yaml") v.AddConfigPath(configDir) v.AddConfigPath(".") // Read environment variables v.SetEnvPrefix("GITAUTO") v.AutomaticEnv() // Read configuration file if err := v.ReadInConfig(); err != nil { // It's okay if config file doesn't exist if _, ok := err.(viper.ConfigFileNotFoundError); !ok { return fmt.Errorf("could not read config file: %w", err) } } // Unmarshal configuration GlobalConfig = &Config{} if err := v.Unmarshal(GlobalConfig); err != nil { return fmt.Errorf("could not unmarshal config: %w", err) } return nil } // Save saves the current configuration to file func Save() error { initViper() if err := v.WriteConfigAs(configFile); err != nil { return fmt.Errorf("could not save config file: %w", err) } return nil } // GetConfigFile returns the path to the configuration file func GetConfigFile() string { return configFile } // SetConfigFile sets the path to the configuration file (for testing) func SetConfigFile(path string) { configFile = path } // Set sets a configuration value func Set(key string, value interface{}) { initViper() v.Set(key, value) // Update the global config v.Unmarshal(GlobalConfig) } // Get gets a configuration value func Get(key string) interface{} { initViper() return v.Get(key) } // SetViper sets the viper instance (for testing) func SetViper(viperInstance *viper.Viper) { v = viperInstance } // ResetViper resets the viper instance (for testing) func ResetViper() { v = nil }