refactor: simplify config to prefer env vars
Configuration now prefers environment variables over config.yaml values. Each config field has a corresponding env var (DBURL, PORT, DEBUG, etc.) that takes precedence when set. The config.yaml fallback is preserved for development convenience. closes #10
This commit is contained in:
parent
3e3d44a168
commit
483d7f31ff
@ -4,19 +4,16 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
"os"
|
"os"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
"sneak.berlin/go/webhooker/internal/globals"
|
"sneak.berlin/go/webhooker/internal/globals"
|
||||||
"sneak.berlin/go/webhooker/internal/logger"
|
"sneak.berlin/go/webhooker/internal/logger"
|
||||||
pkgconfig "sneak.berlin/go/webhooker/pkg/config"
|
pkgconfig "sneak.berlin/go/webhooker/pkg/config"
|
||||||
|
|
||||||
// spooky action at a distance!
|
// Populates the environment from a ./.env file automatically for
|
||||||
// this populates the environment
|
// development configuration. Kept in one place only (here).
|
||||||
// from a ./.env file automatically
|
|
||||||
// for development configuration.
|
|
||||||
// .env contents should be things like
|
|
||||||
// `DBURL=postgres://user:pass@.../`
|
|
||||||
// (without the backticks, of course)
|
|
||||||
_ "github.com/joho/godotenv/autoload"
|
_ "github.com/joho/godotenv/autoload"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -64,6 +61,40 @@ func (c *Config) IsProd() bool {
|
|||||||
return c.Environment == EnvironmentProd
|
return c.Environment == EnvironmentProd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// envString returns the env var value if set, otherwise falls back to pkgconfig.
|
||||||
|
func envString(envKey, configKey string) string {
|
||||||
|
if v := os.Getenv(envKey); v != "" {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return pkgconfig.GetString(configKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// envSecretString returns the env var value if set, otherwise falls back to pkgconfig secrets.
|
||||||
|
func envSecretString(envKey, configKey string) string {
|
||||||
|
if v := os.Getenv(envKey); v != "" {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return pkgconfig.GetSecretString(configKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// envBool returns the env var value parsed as bool, otherwise falls back to pkgconfig.
|
||||||
|
func envBool(envKey, configKey string) bool {
|
||||||
|
if v := os.Getenv(envKey); v != "" {
|
||||||
|
return strings.EqualFold(v, "true") || v == "1"
|
||||||
|
}
|
||||||
|
return pkgconfig.GetBool(configKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
// envInt returns the env var value parsed as int, otherwise falls back to pkgconfig.
|
||||||
|
func envInt(envKey, configKey string, defaultValue ...int) int {
|
||||||
|
if v := os.Getenv(envKey); v != "" {
|
||||||
|
if i, err := strconv.Atoi(v); err == nil {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pkgconfig.GetInt(configKey, defaultValue...)
|
||||||
|
}
|
||||||
|
|
||||||
// nolint:revive // lc parameter is required by fx even if unused
|
// nolint:revive // lc parameter is required by fx even if unused
|
||||||
func New(lc fx.Lifecycle, params ConfigParams) (*Config, error) {
|
func New(lc fx.Lifecycle, params ConfigParams) (*Config, error) {
|
||||||
log := params.Logger.Get()
|
log := params.Logger.Get()
|
||||||
@ -80,30 +111,30 @@ func New(lc fx.Lifecycle, params ConfigParams) (*Config, error) {
|
|||||||
EnvironmentDev, EnvironmentProd, environment)
|
EnvironmentDev, EnvironmentProd, environment)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the environment in the config package
|
// Set the environment in the config package (for fallback resolution)
|
||||||
pkgconfig.SetEnvironment(environment)
|
pkgconfig.SetEnvironment(environment)
|
||||||
|
|
||||||
// Load configuration values
|
// Load configuration values — env vars take precedence over config.yaml
|
||||||
s := &Config{
|
s := &Config{
|
||||||
DBURL: pkgconfig.GetString("dburl"),
|
DBURL: envString("DBURL", "dburl"),
|
||||||
Debug: pkgconfig.GetBool("debug"),
|
Debug: envBool("DEBUG", "debug"),
|
||||||
MaintenanceMode: pkgconfig.GetBool("maintenanceMode"),
|
MaintenanceMode: envBool("MAINTENANCE_MODE", "maintenanceMode"),
|
||||||
DevelopmentMode: pkgconfig.GetBool("developmentMode"),
|
DevelopmentMode: envBool("DEVELOPMENT_MODE", "developmentMode"),
|
||||||
DevAdminUsername: pkgconfig.GetString("devAdminUsername"),
|
DevAdminUsername: envString("DEV_ADMIN_USERNAME", "devAdminUsername"),
|
||||||
DevAdminPassword: pkgconfig.GetString("devAdminPassword"),
|
DevAdminPassword: envString("DEV_ADMIN_PASSWORD", "devAdminPassword"),
|
||||||
Environment: pkgconfig.GetString("environment", environment),
|
Environment: environment,
|
||||||
MetricsUsername: pkgconfig.GetString("metricsUsername"),
|
MetricsUsername: envString("METRICS_USERNAME", "metricsUsername"),
|
||||||
MetricsPassword: pkgconfig.GetString("metricsPassword"),
|
MetricsPassword: envString("METRICS_PASSWORD", "metricsPassword"),
|
||||||
Port: pkgconfig.GetInt("port", 8080),
|
Port: envInt("PORT", "port", 8080),
|
||||||
SentryDSN: pkgconfig.GetSecretString("sentryDSN"),
|
SentryDSN: envSecretString("SENTRY_DSN", "sentryDSN"),
|
||||||
SessionKey: pkgconfig.GetSecretString("sessionKey"),
|
SessionKey: envSecretString("SESSION_KEY", "sessionKey"),
|
||||||
log: log,
|
log: log,
|
||||||
params: ¶ms,
|
params: ¶ms,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate database URL
|
// Validate database URL
|
||||||
if s.DBURL == "" {
|
if s.DBURL == "" {
|
||||||
return nil, fmt.Errorf("database URL (dburl) is required")
|
return nil, fmt.Errorf("database URL (DBURL) is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
// In production, require session key
|
// In production, require session key
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user