refactor: adopt portigo infrastructure patterns
Add config package with build-tag-switched dev/prod environments, structured logging via zerolog, Taskfile for dev workflow, golangci-lint config, testutil package, and improved DB setup with proper SQLite pragmas and cleanup. Rename sqlc output package from gen to repository. Switch to allowlist .gitignore, Alpine+UPX+scratch Dockerfile, and CI pipeline with test/lint gates before deploy.
This commit is contained in:
73
config/config.go
Normal file
73
config/config.go
Normal file
@@ -0,0 +1,73 @@
|
||||
// Package config provides build-tag-switched application configuration.
|
||||
// The global Config singleton is initialized at import time via init()
|
||||
// and can be overridden in tests with LoadForTest().
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
"sync"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
type Environment string
|
||||
|
||||
const (
|
||||
Dev Environment = "dev"
|
||||
Prod Environment = "prod"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Environment Environment
|
||||
Host string
|
||||
Port string
|
||||
LogLevel zerolog.Level
|
||||
AppURL string
|
||||
DBPath string
|
||||
}
|
||||
|
||||
var (
|
||||
Global *Config
|
||||
once sync.Once
|
||||
)
|
||||
|
||||
func init() {
|
||||
once.Do(func() {
|
||||
Global = Load()
|
||||
})
|
||||
}
|
||||
|
||||
func getEnv(key, fallback string) string {
|
||||
if val, ok := os.LookupEnv(key); ok {
|
||||
return val
|
||||
}
|
||||
return fallback
|
||||
}
|
||||
|
||||
func loadBase() *Config {
|
||||
godotenv.Load() //nolint:errcheck // .env file is optional
|
||||
|
||||
return &Config{
|
||||
Host: getEnv("HOST", "0.0.0.0"),
|
||||
Port: getEnv("PORT", "7331"),
|
||||
LogLevel: func() zerolog.Level {
|
||||
switch os.Getenv("LOG_LEVEL") {
|
||||
case "TRACE":
|
||||
return zerolog.TraceLevel
|
||||
case "DEBUG":
|
||||
return zerolog.DebugLevel
|
||||
case "INFO":
|
||||
return zerolog.InfoLevel
|
||||
case "WARN":
|
||||
return zerolog.WarnLevel
|
||||
case "ERROR":
|
||||
return zerolog.ErrorLevel
|
||||
default:
|
||||
return zerolog.InfoLevel
|
||||
}
|
||||
}(),
|
||||
AppURL: getEnv("APP_URL", "https://games.adriatica.io"),
|
||||
DBPath: getEnv("DB_PATH", "data/c4.db"),
|
||||
}
|
||||
}
|
||||
9
config/config_dev.go
Normal file
9
config/config_dev.go
Normal file
@@ -0,0 +1,9 @@
|
||||
//go:build dev
|
||||
|
||||
package config
|
||||
|
||||
func Load() *Config {
|
||||
cfg := loadBase()
|
||||
cfg.Environment = Dev
|
||||
return cfg
|
||||
}
|
||||
9
config/config_prod.go
Normal file
9
config/config_prod.go
Normal file
@@ -0,0 +1,9 @@
|
||||
//go:build !dev
|
||||
|
||||
package config
|
||||
|
||||
func Load() *Config {
|
||||
cfg := loadBase()
|
||||
cfg.Environment = Prod
|
||||
return cfg
|
||||
}
|
||||
19
config/config_test_helper.go
Normal file
19
config/config_test_helper.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/rs/zerolog"
|
||||
)
|
||||
|
||||
// LoadForTest sets config.Global to safe defaults without reading
|
||||
// environment variables or .env files. Call this in TestMain or at the
|
||||
// top of tests that import packages which depend on config.Global.
|
||||
func LoadForTest() {
|
||||
Global = &Config{
|
||||
Environment: Dev,
|
||||
Host: "127.0.0.1",
|
||||
Port: "0",
|
||||
LogLevel: zerolog.WarnLevel,
|
||||
AppURL: "http://localhost:0",
|
||||
DBPath: ":memory:",
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user