package config import ( "fmt" "os" "strconv" "github.com/joho/godotenv" ) type Config struct { // Azure AzureOrg string AzurePAT string // Forgejo ForgejoURL string ForgejoToken string ForgejoOwner string // Migration MirrorInterval string Concurrent int DryRun bool } var globalConfig *Config func Load(path string) error { if err := godotenv.Load(path); err != nil { // Try to load from environment if file doesn't exist if !os.IsNotExist(err) { return fmt.Errorf("error loading env file: %w", err) } } concurrent := 3 if c := os.Getenv("CONCURRENT_MIGRATIONS"); c != "" { if v, err := strconv.Atoi(c); err == nil { concurrent = v } } globalConfig = &Config{ AzureOrg: getEnvOrError("AZURE_ORG"), AzurePAT: getEnvOrError("AZURE_PAT"), ForgejoURL: getEnvOrError("FORGEJO_URL"), ForgejoToken: getEnvOrError("FORGEJO_TOKEN"), ForgejoOwner: getEnvOrError("FORGEJO_OWNER"), MirrorInterval: getEnv("MIRROR_INTERVAL", "8h"), Concurrent: concurrent, } return validate(globalConfig) } func Get() *Config { return globalConfig } func getEnv(key, defaultValue string) string { if value := os.Getenv(key); value != "" { return value } return defaultValue } func getEnvOrError(key string) string { value := os.Getenv(key) if value == "" { panic(fmt.Sprintf("Required environment variable %s is not set", key)) } return value } func validate(c *Config) error { if c.AzureOrg == "" || c.AzurePAT == "" { return fmt.Errorf("Azure organization and PAT must be configured") } if c.ForgejoURL == "" || c.ForgejoToken == "" { return fmt.Errorf("Forgejo URL and token must be configured") } return nil }