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 github.com/host-uk/core v0.0.0
|
||||||
|
|
||||||
|
require gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
|
||||||
replace github.com/host-uk/core => ../..
|
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/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/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
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 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue