Rationalized the default configuration file path and updated documentation
All checks were successful
ci/woodpecker/tag/release Pipeline was successful
All checks were successful
ci/woodpecker/tag/release Pipeline was successful
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
`config.yml` defines application-level defaults used by CLI commands.
|
||||
|
||||
By default, Scriptorium looks for `/etc/scriptorium/config.yml`. You can also pass `--config PATH`.
|
||||
By default, Scriptorium looks for `/usr/local/etc/scriptorium/config.yml` and, if not present, then for `/etc/scriptorium/config.yml`. You can also pass `--config PATH`.
|
||||
|
||||
## Complete Example
|
||||
|
||||
|
||||
@@ -450,7 +450,16 @@ func (c *serveConfig) addrIfSet(fs *flag.FlagSet) string {
|
||||
}
|
||||
|
||||
func registerConfigPathFlag(fs *flag.FlagSet, target *string) {
|
||||
fs.StringVar(target, "config", "", fmt.Sprintf("application config path (default %s)", appconfig.DefaultConfigPath))
|
||||
fs.StringVar(
|
||||
target,
|
||||
"config",
|
||||
"",
|
||||
fmt.Sprintf(
|
||||
"application config path (default search: %s, then %s)",
|
||||
appconfig.DefaultConfigPathLocal,
|
||||
appconfig.DefaultConfigPath,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
func resolveAppSettings(fs *flag.FlagSet, configPath string, overrides appconfig.CLIOverrides) (appconfig.AppSettings, error) {
|
||||
|
||||
@@ -14,7 +14,15 @@ import (
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
const DefaultConfigPath = "/etc/scriptorium/config.yml"
|
||||
const (
|
||||
DefaultConfigPath = "/etc/scriptorium/config.yml"
|
||||
DefaultConfigPathLocal = "/usr/local/etc/scriptorium/config.yml"
|
||||
)
|
||||
|
||||
var defaultConfigSearchPaths = []string{
|
||||
DefaultConfigPathLocal,
|
||||
DefaultConfigPath,
|
||||
}
|
||||
|
||||
var (
|
||||
ErrConfigNotFound = errors.New("config file not found")
|
||||
@@ -74,7 +82,24 @@ func LoadConfig(path string, explicit bool) (AppSettings, error) {
|
||||
resolved := BuiltInDefaults()
|
||||
configPath := strings.TrimSpace(path)
|
||||
if configPath == "" {
|
||||
configPath = DefaultConfigPath
|
||||
if explicit {
|
||||
configPath = DefaultConfigPath
|
||||
} else {
|
||||
for _, candidate := range defaultConfigSearchPaths {
|
||||
if _, err := os.Stat(candidate); err == nil {
|
||||
configPath = candidate
|
||||
break
|
||||
} else if !errors.Is(err, os.ErrNotExist) {
|
||||
return AppSettings{}, fmt.Errorf("failed to stat config file %q: %w", candidate, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if configPath == "" {
|
||||
if explicit {
|
||||
return AppSettings{}, fmt.Errorf("%w: %s", ErrConfigNotFound, DefaultConfigPath)
|
||||
}
|
||||
return resolved, nil
|
||||
}
|
||||
configPath = filepath.Clean(configPath)
|
||||
|
||||
|
||||
@@ -132,6 +132,53 @@ func TestLoadConfigEmptyFileResolvesToBuiltInDefaults(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadConfigImplicitSearchPrefersUsrLocalEtcOverEtc(t *testing.T) {
|
||||
tmp := t.TempDir()
|
||||
localPath := filepath.Join(tmp, "usr-local.yml")
|
||||
etcPath := filepath.Join(tmp, "etc.yml")
|
||||
|
||||
if err := os.WriteFile(localPath, []byte("prompt_dir: ./from-usr-local\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(etcPath, []byte("prompt_dir: ./from-etc\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
orig := defaultConfigSearchPaths
|
||||
defaultConfigSearchPaths = []string{localPath, etcPath}
|
||||
t.Cleanup(func() { defaultConfigSearchPaths = orig })
|
||||
|
||||
got, err := LoadConfig("", false)
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, got %v", err)
|
||||
}
|
||||
if got.PromptDir != filepath.Clean("./from-usr-local") {
|
||||
t.Fatalf("expected usr-local config to win, got prompt_dir=%q", got.PromptDir)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadConfigImplicitSearchFallsBackToEtcWhenUsrLocalMissing(t *testing.T) {
|
||||
tmp := t.TempDir()
|
||||
missingLocal := filepath.Join(tmp, "missing-local.yml")
|
||||
etcPath := filepath.Join(tmp, "etc.yml")
|
||||
|
||||
if err := os.WriteFile(etcPath, []byte("prompt_dir: ./from-etc\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
orig := defaultConfigSearchPaths
|
||||
defaultConfigSearchPaths = []string{missingLocal, etcPath}
|
||||
t.Cleanup(func() { defaultConfigSearchPaths = orig })
|
||||
|
||||
got, err := LoadConfig("", false)
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, got %v", err)
|
||||
}
|
||||
if got.PromptDir != filepath.Clean("./from-etc") {
|
||||
t.Fatalf("expected etc fallback config, got prompt_dir=%q", got.PromptDir)
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyCLIOverridesAppliesPrecedence(t *testing.T) {
|
||||
base := AppSettings{
|
||||
PromptDir: "/from/config/prompts",
|
||||
|
||||
Reference in New Issue
Block a user