feat(devops): add config loading
Loads ~/.core/config.yaml with image source preferences. Defaults to auto-detection with host-uk/core-images. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
cead09feb2
commit
7275961769
4 changed files with 138 additions and 0 deletions
86
pkg/devops/config.go
Normal file
86
pkg/devops/config.go
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
package devops
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// Config holds global devops configuration from ~/.core/config.yaml.
|
||||
type Config struct {
|
||||
Version int `yaml:"version"`
|
||||
Images ImagesConfig `yaml:"images"`
|
||||
}
|
||||
|
||||
// ImagesConfig holds image source configuration.
|
||||
type ImagesConfig struct {
|
||||
Source string `yaml:"source"` // auto, github, registry, cdn
|
||||
GitHub GitHubConfig `yaml:"github,omitempty"`
|
||||
Registry RegistryConfig `yaml:"registry,omitempty"`
|
||||
CDN CDNConfig `yaml:"cdn,omitempty"`
|
||||
}
|
||||
|
||||
// GitHubConfig holds GitHub Releases configuration.
|
||||
type GitHubConfig struct {
|
||||
Repo string `yaml:"repo"` // owner/repo format
|
||||
}
|
||||
|
||||
// RegistryConfig holds container registry configuration.
|
||||
type RegistryConfig struct {
|
||||
Image string `yaml:"image"` // e.g., ghcr.io/host-uk/core-devops
|
||||
}
|
||||
|
||||
// CDNConfig holds CDN/S3 configuration.
|
||||
type CDNConfig struct {
|
||||
URL string `yaml:"url"` // base URL for downloads
|
||||
}
|
||||
|
||||
// DefaultConfig returns sensible defaults.
|
||||
func DefaultConfig() *Config {
|
||||
return &Config{
|
||||
Version: 1,
|
||||
Images: ImagesConfig{
|
||||
Source: "auto",
|
||||
GitHub: GitHubConfig{
|
||||
Repo: "host-uk/core-images",
|
||||
},
|
||||
Registry: RegistryConfig{
|
||||
Image: "ghcr.io/host-uk/core-devops",
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// ConfigPath returns the path to the config file.
|
||||
func ConfigPath() (string, error) {
|
||||
home, err := os.UserHomeDir()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return filepath.Join(home, ".core", "config.yaml"), nil
|
||||
}
|
||||
|
||||
// LoadConfig loads configuration from ~/.core/config.yaml.
|
||||
// Returns default config if file doesn't exist.
|
||||
func LoadConfig() (*Config, error) {
|
||||
configPath, err := ConfigPath()
|
||||
if err != nil {
|
||||
return DefaultConfig(), nil
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(configPath)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
return DefaultConfig(), nil
|
||||
}
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cfg := DefaultConfig()
|
||||
if err := yaml.Unmarshal(data, cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
48
pkg/devops/config_test.go
Normal file
48
pkg/devops/config_test.go
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
package devops
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestLoadConfig_Good_Default(t *testing.T) {
|
||||
// Use temp home dir
|
||||
tmpDir := t.TempDir()
|
||||
t.Setenv("HOME", tmpDir)
|
||||
|
||||
cfg, err := LoadConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if cfg.Images.Source != "auto" {
|
||||
t.Errorf("expected source 'auto', got %q", cfg.Images.Source)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadConfig_Good_FromFile(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
t.Setenv("HOME", tmpDir)
|
||||
|
||||
configDir := filepath.Join(tmpDir, ".core")
|
||||
os.MkdirAll(configDir, 0755)
|
||||
|
||||
configContent := `version: 1
|
||||
images:
|
||||
source: github
|
||||
github:
|
||||
repo: myorg/images
|
||||
`
|
||||
os.WriteFile(filepath.Join(configDir, "config.yaml"), []byte(configContent), 0644)
|
||||
|
||||
cfg, err := LoadConfig()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if cfg.Images.Source != "github" {
|
||||
t.Errorf("expected source 'github', got %q", cfg.Images.Source)
|
||||
}
|
||||
if cfg.Images.GitHub.Repo != "myorg/images" {
|
||||
t.Errorf("expected repo 'myorg/images', got %q", cfg.Images.GitHub.Repo)
|
||||
}
|
||||
}
|
||||
|
|
@ -4,4 +4,6 @@ go 1.25
|
|||
|
||||
require github.com/host-uk/core v0.0.0
|
||||
|
||||
require gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
|
||||
replace github.com/host-uk/core => ../..
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue