From a80daf5494ba10a2f9c7c91357452155e99480b3 Mon Sep 17 00:00:00 2001 From: Virgil Date: Fri, 3 Apr 2026 16:10:15 +0000 Subject: [PATCH] fix(ansible): scope playbook_dir for nested imports --- parser.go | 19 ++++++++++++++++++- parser_test.go | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/parser.go b/parser.go index 150843d..610b9f8 100644 --- a/parser.go +++ b/parser.go @@ -86,10 +86,27 @@ func (p *Parser) parsePlaybook(path string, seen map[string]bool) ([]Play, error if importPath != "" && !pathIsAbs(importPath) { importPath = joinPath(pathDir(path), importPath) } - imported, err := p.parsePlaybook(importPath, seen) + savedPlaybookDir, hadPlaybookDir := p.vars["playbook_dir"] + p.vars["playbook_dir"] = pathDir(importPath) + imported, err := func() ([]Play, error) { + defer func() { + if hadPlaybookDir { + p.vars["playbook_dir"] = savedPlaybookDir + } else { + delete(p.vars, "playbook_dir") + } + }() + return p.parsePlaybook(importPath, seen) + }() if err != nil { return nil, coreerr.E("Parser.ParsePlaybook", sprintf("expand import_playbook %d", i), err) } + for i := range imported { + if imported[i].Vars == nil { + imported[i].Vars = make(map[string]any) + } + imported[i].Vars["playbook_dir"] = savedPlaybookDir + } expanded = append(expanded, imported...) continue } diff --git a/parser_test.go b/parser_test.go index c064f20..261dbab 100644 --- a/parser_test.go +++ b/parser_test.go @@ -185,6 +185,43 @@ func TestParser_ParsePlaybook_Good_FQCNImportPlaybook(t *testing.T) { assert.Equal(t, "all", plays[0].Hosts) } +func TestParser_ParsePlaybook_Good_NestedImportPlaybookDirScope(t *testing.T) { + dir := t.TempDir() + mainPath := joinPath(dir, "site.yml") + outerDir := joinPath(dir, "plays") + outerPath := joinPath(outerDir, "outer.yml") + innerDir := joinPath(outerDir, "nested") + innerPath := joinPath(innerDir, "inner.yml") + + yamlMain := `--- +- import_playbook: plays/outer.yml +` + yamlOuter := `--- +- import_playbook: "{{ playbook_dir }}/nested/inner.yml" +` + yamlInner := `--- +- name: Inner play + hosts: all + tasks: + - name: Say inner + debug: + msg: "inner" +` + require.NoError(t, os.MkdirAll(innerDir, 0755)) + require.NoError(t, writeTestFile(mainPath, []byte(yamlMain), 0644)) + require.NoError(t, writeTestFile(outerPath, []byte(yamlOuter), 0644)) + require.NoError(t, writeTestFile(innerPath, []byte(yamlInner), 0644)) + + p := NewParser(dir) + plays, err := p.ParsePlaybook("site.yml") + + require.NoError(t, err) + require.Len(t, plays, 1) + assert.Equal(t, "Inner play", plays[0].Name) + require.NotNil(t, plays[0].Vars) + assert.Equal(t, dir, plays[0].Vars["playbook_dir"]) +} + func TestParser_ParsePlaybook_Good_WithVars(t *testing.T) { dir := t.TempDir() path := joinPath(dir, "playbook.yml")