Skip to content

Commit

Permalink
fix: use PRJ_ROOT to find config
Browse files Browse the repository at this point in the history
Improves the tests for config file resolution.

Signed-off-by: Brian McGee <[email protected]>
  • Loading branch information
brianmcgee committed Nov 7, 2024
1 parent 10a4616 commit ec6eba4
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 32 deletions.
22 changes: 18 additions & 4 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,13 +107,27 @@ func runE(v *viper.Viper, statz *stats.Stats, cmd *cobra.Command, args []string)
configFile = os.Getenv("TREEFMT_CONFIG")
}

// find the config file if one was not specified
filenames := []string{"treefmt.toml", ".treefmt.toml"}

// look in PRJ_ROOT if set
if prjRoot := os.Getenv("PRJ_ROOT"); configFile == "" && prjRoot != "" {
configFile, _ = config.Find(prjRoot, filenames...)
}

// search up from the working directory
if configFile == "" {
if configFile, _, err = config.FindUp(workingDir, "treefmt.toml", ".treefmt.toml"); err != nil {
return fmt.Errorf("failed to find treefmt config file: %w", err)
}
configFile, _, err = config.FindUp(workingDir, filenames...)
}

// error out if we couldn't find the config file
if err != nil {
cmd.SilenceUsage = true

return fmt.Errorf("failed to find treefmt config file: %w", err)
}

log.Infof("using config file: %s", configFile)

// read in the config
v.SetConfigFile(configFile)

Expand Down
126 changes: 104 additions & 22 deletions cmd/root_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -413,30 +413,93 @@ func TestIncludesAndExcludes(t *testing.T) {
)
}

func TestPrjRootEnvVariable(t *testing.T) {
tempDir := test.TempExamples(t)
configPath := filepath.Join(tempDir, "treefmt.toml")
func TestConfigFile(t *testing.T) {
as := require.New(t)

t.Setenv("PRJ_ROOT", tempDir)
for _, name := range []string{"treefmt.toml", ".treefmt.toml"} {
t.Run(name, func(t *testing.T) {
tempDir := test.TempExamples(t)

treefmt(t,
withConfig(configPath, &config.Config{
FormatterConfigs: map[string]*config.Formatter{
"echo": {
Command: "echo",
Includes: []string{"*"},
},
},
}),
withArgs("--config-file", configPath),
withNoError(t),
withStats(t, map[stats.Type]int{
stats.Traversed: 32,
stats.Matched: 32,
stats.Formatted: 32,
stats.Changed: 0,
}),
)
// use a config file in a different temp directory
configPath := filepath.Join(t.TempDir(), name)

// if we don't specify a tree root, we default to the directory containing the config file
treefmt(t,
withConfig(configPath, &config.Config{
FormatterConfigs: map[string]*config.Formatter{
"echo": {
Command: "echo",
Includes: []string{"*"},
},
},
}),
withArgs("--config-file", configPath),
withNoError(t),
withStats(t, map[stats.Type]int{
stats.Traversed: 1,
stats.Matched: 1,
stats.Formatted: 1,
stats.Changed: 0,
}),
)

treefmt(t,
withArgs("--config-file", configPath, "--tree-root", tempDir),
withNoError(t),
withStats(t, map[stats.Type]int{
stats.Traversed: 32,
stats.Matched: 32,
stats.Formatted: 32,
stats.Changed: 0,
}),
)

// use env variable
treefmt(t,
withEnv(map[string]string{
// TREEFMT_CONFIG takes precedence
"TREEFMT_CONFIG": configPath,
"PRJ_ROOT": tempDir,
}),
withNoError(t),
withStats(t, map[stats.Type]int{
stats.Traversed: 1,
stats.Matched: 1,
stats.Formatted: 0,
stats.Changed: 0,
}),
)

// should fallback to PRJ_ROOT
treefmt(t,
withArgs("--tree-root", tempDir),
withEnv(map[string]string{
"PRJ_ROOT": filepath.Dir(configPath),
}),
withNoError(t),
withStats(t, map[stats.Type]int{
stats.Traversed: 32,
stats.Matched: 32,
stats.Formatted: 0,
stats.Changed: 0,
}),
)

// should not search upwards if using PRJ_ROOT
configSubDir := filepath.Join(filepath.Dir(configPath), "sub")
as.NoError(os.MkdirAll(configSubDir, 0o600))

treefmt(t,
withArgs("--tree-root", tempDir),
withEnv(map[string]string{
"PRJ_ROOT": configSubDir,
}),
withError(func(err error) {
as.ErrorContains(err, "failed to find treefmt config file")
}),
)
})
}
}

func TestCache(t *testing.T) {
Expand Down Expand Up @@ -1715,6 +1778,7 @@ func TestRunInSubdir(t *testing.T) {

type options struct {
args []string
env map[string]string

config struct {
path string
Expand All @@ -1740,6 +1804,12 @@ func withArgs(args ...string) option {
}
}

func withEnv(env map[string]string) option {
return func(o *options) {
o.env = env
}
}

func withConfig(path string, cfg *config.Config) option {
return func(o *options) {
o.config.path = path
Expand Down Expand Up @@ -1804,6 +1874,18 @@ func treefmt(
option(opts)
}

// set env
for k, v := range opts.env {
t.Setenv(k, v)
}

defer func() {
// unset env variables after executing
for k := range opts.env {
t.Setenv(k, "")
}
}()

// default args if nil
// we must pass an empty array otherwise cobra with use os.Args[1:]
args := opts.args
Expand Down
19 changes: 14 additions & 5 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,13 +238,22 @@ func FromViper(v *viper.Viper) (*Config, error) {
return cfg, nil
}

func Find(searchDir string, fileNames ...string) (path string, err error) {
for _, f := range fileNames {
path := filepath.Join(searchDir, f)
if fileExists(path) {
return path, nil
}
}

return "", fmt.Errorf("could not find %s in %s", fileNames, searchDir)
}

func FindUp(searchDir string, fileNames ...string) (path string, dir string, err error) {
for _, dir := range eachDir(searchDir) {
for _, f := range fileNames {
path := filepath.Join(dir, f)
if fileExists(path) {
return path, dir, nil
}
path, err := Find(dir, fileNames...)
if err == nil {
return path, dir, nil
}
}

Expand Down
6 changes: 5 additions & 1 deletion nix/packages/docs.nix
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
{ pkgs, perSystem, ... }:
{
pkgs,
perSystem,
...
}:
pkgs.stdenvNoCC.mkDerivation {
name = "docs";

Expand Down

0 comments on commit ec6eba4

Please sign in to comment.