diff --git a/modules.go b/modules.go index 26c7407..9337d4d 100644 --- a/modules.go +++ b/modules.go @@ -2114,6 +2114,7 @@ func (e *Executor) moduleIncludeVars(args map[string]any) (*TaskResult, error) { } dir := getStringArg(args, "dir", "") name := getStringArg(args, "name", "") + filesMatching := getStringArg(args, "files_matching", "") hashBehaviour := lower(getStringArg(args, "hash_behaviour", "replace")) depth := getIntArg(args, "depth", 0) @@ -2148,7 +2149,7 @@ func (e *Executor) moduleIncludeVars(args map[string]any) (*TaskResult, error) { if dir != "" { dir = e.resolveLocalPath(dir) - files, err := collectIncludeVarsFiles(dir, depth) + files, err := collectIncludeVarsFiles(dir, depth, filesMatching) if err != nil { return nil, err } @@ -2175,7 +2176,7 @@ func (e *Executor) moduleIncludeVars(args map[string]any) (*TaskResult, error) { return &TaskResult{Changed: true, Msg: msg}, nil } -func collectIncludeVarsFiles(dir string, depth int) ([]string, error) { +func collectIncludeVarsFiles(dir string, depth int, filesMatching string) ([]string, error) { info, err := os.Stat(dir) if err != nil { return nil, coreerr.E("Executor.moduleIncludeVars", "read vars dir", err) @@ -2189,6 +2190,14 @@ func collectIncludeVarsFiles(dir string, depth int) ([]string, error) { depth int } + var matcher *regexp.Regexp + if filesMatching != "" { + matcher, err = regexp.Compile(filesMatching) + if err != nil { + return nil, coreerr.E("Executor.moduleIncludeVars", "compile files_matching", err) + } + } + var files []string stack := []dirEntry{{path: dir, depth: 0}} for len(stack) > 0 { @@ -2213,6 +2222,9 @@ func collectIncludeVarsFiles(dir string, depth int) ([]string, error) { ext := lower(filepath.Ext(entry.Name())) if ext == ".yml" || ext == ".yaml" { + if matcher != nil && !matcher.MatchString(entry.Name()) { + continue + } files = append(files, fullPath) } } diff --git a/modules_adv_test.go b/modules_adv_test.go index 2f2d5ac..bea3b3a 100644 --- a/modules_adv_test.go +++ b/modules_adv_test.go @@ -998,6 +998,28 @@ func TestModulesAdv_ModuleIncludeVars_Good_RespectsDepthLimit(t *testing.T) { assert.NotContains(t, result.Msg, joinPath(dir, "nested", "deep", "03-grandchild.yml")) } +func TestModulesAdv_ModuleIncludeVars_Good_FiltersFilesMatching(t *testing.T) { + dir := t.TempDir() + require.NoError(t, writeTestFile(joinPath(dir, "01-base.yml"), []byte("base_value: base\n"), 0644)) + require.NoError(t, writeTestFile(joinPath(dir, "02-extra.yaml"), []byte("extra_value: extra\n"), 0644)) + require.NoError(t, writeTestFile(joinPath(dir, "notes.txt"), []byte("ignored: true\n"), 0644)) + + e := NewExecutor("/tmp") + + result, err := e.moduleIncludeVars(map[string]any{ + "dir": dir, + "files_matching": `^02-.*\.ya?ml$`, + }) + + require.NoError(t, err) + assert.True(t, result.Changed) + assert.Equal(t, "extra", e.vars["extra_value"]) + _, hasBase := e.vars["base_value"] + assert.False(t, hasBase) + assert.Contains(t, result.Msg, joinPath(dir, "02-extra.yaml")) + assert.NotContains(t, result.Msg, joinPath(dir, "01-base.yml")) +} + // --- sysctl module --- func TestModulesAdv_ModuleSysctl_Good_ReloadsAfterPersisting(t *testing.T) {