package config import ( "fmt" "os" "strconv" ) type Config struct { ListenAddr string DatabaseURL string S3Endpoint string S3Bucket string S3AccessKey string S3SecretKey string S3UseSSL bool ForgejoURL string ForgejoToken string ForgejoWebhookSecret string } func Load() (*Config, error) { c := &Config{ ListenAddr: envOr("CAIRN_LISTEN_ADDR", ":8080"), DatabaseURL: envOr("CAIRN_DATABASE_URL", "postgres://cairn:cairn@localhost:5432/cairn?sslmode=disable"), S3Endpoint: envOr("CAIRN_S3_ENDPOINT", "localhost:9000"), S3Bucket: envOr("CAIRN_S3_BUCKET", "cairn-artifacts"), S3AccessKey: envOr("CAIRN_S3_ACCESS_KEY", "minioadmin"), S3SecretKey: envOr("CAIRN_S3_SECRET_KEY", "minioadmin"), S3UseSSL: envBool("CAIRN_S3_USE_SSL", false), ForgejoURL: envOr("CAIRN_FORGEJO_URL", ""), ForgejoToken: envOr("CAIRN_FORGEJO_TOKEN", ""), ForgejoWebhookSecret: envOr("CAIRN_FORGEJO_WEBHOOK_SECRET", ""), } if c.DatabaseURL == "" { return nil, fmt.Errorf("CAIRN_DATABASE_URL is required") } return c, nil } func envOr(key, fallback string) string { if v := os.Getenv(key); v != "" { return v } return fallback } func envBool(key string, fallback bool) bool { v := os.Getenv(key) if v == "" { return fallback } b, err := strconv.ParseBool(v) if err != nil { return fallback } return b }