mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
fix: Support PMG_* env vars regardless of config file state
AutomaticEnv only resolves env vars for keys Viper already knows about via AllKeys(). When a key is absent from the config file (commented out, new key added after last setup, or no config file at all), Viper had no knowledge of it and silently skipped the env var. Fix by registering all Config struct fields as Viper defaults via reflection (using mapstructure tags) before reading the config file. This ensures PMG_* env vars work in all cases. Precedence: cobra flags > env vars > config file > defaults. SetDefault is used (not Set) so env vars and config file can still override the Go defaults freely. Tests added covering all precedence levels including the key-absent- from-config-file case that was the original bug report.
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@@ -124,6 +125,89 @@ func TestProxyInstallOnlyConfig(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// TestConfigPrecedence verifies the expected override order:
|
||||
// flags > env var > config file > default
|
||||
func TestConfigPrecedence(t *testing.T) {
|
||||
t.Run("env var overrides config file", func(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
t.Setenv("PMG_CONFIG_DIR", tmpDir)
|
||||
t.Setenv("PMG_PROXY_INSTALL_ONLY", "true")
|
||||
|
||||
configPath := filepath.Join(tmpDir, "config.yml")
|
||||
err := os.WriteFile(configPath, []byte("proxy_install_only: false\n"), 0o644)
|
||||
require.NoError(t, err)
|
||||
|
||||
initConfig()
|
||||
assert.Equal(t, true, Get().Config.ProxyInstallOnly, "env var should override config file")
|
||||
})
|
||||
|
||||
t.Run("config file overrides default", func(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
t.Setenv("PMG_CONFIG_DIR", tmpDir)
|
||||
t.Setenv("PMG_PROXY_INSTALL_ONLY", "")
|
||||
|
||||
configPath := filepath.Join(tmpDir, "config.yml")
|
||||
err := os.WriteFile(configPath, []byte("proxy_install_only: true\n"), 0o644)
|
||||
require.NoError(t, err)
|
||||
|
||||
initConfig()
|
||||
assert.Equal(t, true, Get().Config.ProxyInstallOnly, "config file should override default")
|
||||
})
|
||||
|
||||
t.Run("env var works when key is absent from config file", func(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
t.Setenv("PMG_CONFIG_DIR", tmpDir)
|
||||
t.Setenv("PMG_PROXY_INSTALL_ONLY", "true")
|
||||
|
||||
// Config file exists but proxy_install_only is not in it (e.g. commented out
|
||||
// or user hasn't re-run "pmg setup install" after an upgrade)
|
||||
configPath := filepath.Join(tmpDir, "config.yml")
|
||||
err := os.WriteFile(configPath, []byte("transitive: false\n"), 0o644)
|
||||
require.NoError(t, err)
|
||||
|
||||
initConfig()
|
||||
assert.Equal(t, true, Get().Config.ProxyInstallOnly, "env var should work even when key is absent from config file")
|
||||
})
|
||||
|
||||
t.Run("env var works without a config file", func(t *testing.T) {
|
||||
t.Setenv("PMG_CONFIG_DIR", "/tmp/pmg-test/random-does-not-exist")
|
||||
t.Setenv("PMG_PROXY_INSTALL_ONLY", "true")
|
||||
|
||||
initConfig()
|
||||
assert.Equal(t, true, Get().Config.ProxyInstallOnly, "env var should work even without a config file")
|
||||
})
|
||||
|
||||
t.Run("default is used when neither env var nor config file sets the key", func(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
t.Setenv("PMG_CONFIG_DIR", tmpDir)
|
||||
t.Setenv("PMG_PROXY_INSTALL_ONLY", "")
|
||||
|
||||
configPath := filepath.Join(tmpDir, "config.yml")
|
||||
err := os.WriteFile(configPath, []byte("transitive: false\n"), 0o644)
|
||||
require.NoError(t, err)
|
||||
|
||||
initConfig()
|
||||
assert.Equal(t, false, Get().Config.ProxyInstallOnly, "should use default when key absent from config and env")
|
||||
})
|
||||
|
||||
t.Run("cobra flag overrides env var", func(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
t.Setenv("PMG_CONFIG_DIR", tmpDir)
|
||||
t.Setenv("PMG_PARANOID", "true")
|
||||
|
||||
initConfig()
|
||||
assert.Equal(t, true, Get().Config.Paranoid, "env var should set paranoid=true")
|
||||
|
||||
// Simulate cobra flag parsing — BoolVar writes directly to the struct
|
||||
// field after Viper, giving flags the highest effective precedence.
|
||||
cmd := &cobra.Command{}
|
||||
ApplyCobraFlags(cmd)
|
||||
require.NoError(t, cmd.ParseFlags([]string{"--paranoid=false"}))
|
||||
|
||||
assert.Equal(t, false, Get().Config.Paranoid, "cobra flag should override env var")
|
||||
})
|
||||
}
|
||||
|
||||
func TestWriteTemplateConfigMergesExistingConfig(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
t.Setenv("PMG_CONFIG_DIR", tmpDir)
|
||||
|
||||
Reference in New Issue
Block a user