diff --git a/command/build_test.go b/command/build_test.go index de476fdb0..9dc8d3b0a 100644 --- a/command/build_test.go +++ b/command/build_test.go @@ -106,6 +106,21 @@ func TestBuild(t *testing.T) { }, fileCheck: fileCheck{expected: []string{"chocolate.txt"}}, }, + { + name: "var-args: json - auto varfile sets a peanut env var", + args: []string{ + testFixture("var-arg", "var-arg-test-autovar-json"), + }, + fileCheck: fileCheck{expected: []string{"peanut.txt"}}, + }, + + { + name: "var-args: hcl - auto varfile and json -auto varfile sets the value in json auto varfile", + args: []string{ + testFixture("var-arg", "var-arg-tests"), + }, + fileCheck: fileCheck{expected: []string{"peanut.txt"}}, + }, { name: "var-args: hcl - hcl varfile sets a apple env var", @@ -124,6 +139,24 @@ func TestBuild(t *testing.T) { }, fileCheck: fileCheck{expected: []string{"apple.txt"}}, }, + { + name: "var-args: banana json var file then hcl var file sets apple env var", + args: []string{ + "-var-file=" + filepath.Join(testFixture("var-arg"), "banana.json"), + "-var-file=" + filepath.Join(testFixture("var-arg"), "apple.hcl"), + testFixture("var-arg"), + }, + fileCheck: fileCheck{expected: []string{"apple.txt"}}, + }, + { + name: "var-args: apple hcl var file then banana json var file sets banana env var", + args: []string{ + "-var-file=" + filepath.Join(testFixture("var-arg"), "apple.hcl"), + "-var-file=" + filepath.Join(testFixture("var-arg"), "banana.json"), + testFixture("var-arg"), + }, + fileCheck: fileCheck{expected: []string{"banana.txt"}}, + }, { name: "var-args: hcl - arg sets a tomato env var", diff --git a/command/test-fixtures/var-arg/banana.json b/command/test-fixtures/var-arg/banana.json new file mode 100644 index 000000000..f87f0c3ba --- /dev/null +++ b/command/test-fixtures/var-arg/banana.json @@ -0,0 +1,3 @@ +{ + "fruit": "banana" +} \ No newline at end of file diff --git a/command/test-fixtures/var-arg/var-arg-test-autovar-json/fruit_builder.pkr.hcl b/command/test-fixtures/var-arg/var-arg-test-autovar-json/fruit_builder.pkr.hcl new file mode 100644 index 000000000..a5e8560cd --- /dev/null +++ b/command/test-fixtures/var-arg/var-arg-test-autovar-json/fruit_builder.pkr.hcl @@ -0,0 +1,22 @@ + +variable "fruit" { + type = string +} + +locals { + fruit = var.fruit +} + +source "null" "builder" { + communicator = "none" +} + +build { + sources = [ + "source.null.builder", + ] + + provisioner "shell-local" { + inline = ["echo ${local.fruit} > ${local.fruit}.txt"] + } +} diff --git a/command/test-fixtures/var-arg/var-arg-test-autovar-json/peanut.auto.pkrvars.json b/command/test-fixtures/var-arg/var-arg-test-autovar-json/peanut.auto.pkrvars.json new file mode 100644 index 000000000..c9fc15731 --- /dev/null +++ b/command/test-fixtures/var-arg/var-arg-test-autovar-json/peanut.auto.pkrvars.json @@ -0,0 +1,3 @@ +{ + "fruit": "peanut" +} \ No newline at end of file diff --git a/command/test-fixtures/var-arg/var-arg-tests/fruit_builder.pkr.hcl b/command/test-fixtures/var-arg/var-arg-tests/fruit_builder.pkr.hcl new file mode 100644 index 000000000..a5e8560cd --- /dev/null +++ b/command/test-fixtures/var-arg/var-arg-tests/fruit_builder.pkr.hcl @@ -0,0 +1,22 @@ + +variable "fruit" { + type = string +} + +locals { + fruit = var.fruit +} + +source "null" "builder" { + communicator = "none" +} + +build { + sources = [ + "source.null.builder", + ] + + provisioner "shell-local" { + inline = ["echo ${local.fruit} > ${local.fruit}.txt"] + } +} diff --git a/command/test-fixtures/var-arg/var-arg-tests/icecream.auto.pkrvrs.hcl b/command/test-fixtures/var-arg/var-arg-tests/icecream.auto.pkrvrs.hcl new file mode 100644 index 000000000..98c49ac04 --- /dev/null +++ b/command/test-fixtures/var-arg/var-arg-tests/icecream.auto.pkrvrs.hcl @@ -0,0 +1 @@ +fruit = "icecream" \ No newline at end of file diff --git a/command/test-fixtures/var-arg/var-arg-tests/peanut.auto.pkrvars.json b/command/test-fixtures/var-arg/var-arg-tests/peanut.auto.pkrvars.json new file mode 100644 index 000000000..c9fc15731 --- /dev/null +++ b/command/test-fixtures/var-arg/var-arg-tests/peanut.auto.pkrvars.json @@ -0,0 +1,3 @@ +{ + "fruit": "peanut" +} \ No newline at end of file diff --git a/hcl2template/parser.go b/hcl2template/parser.go index 1f44e0ce7..5e2670bb5 100644 --- a/hcl2template/parser.go +++ b/hcl2template/parser.go @@ -210,39 +210,44 @@ func (p *Parser) Parse(filename string, varFiles []string, argVars map[string]st { hclVarFiles, jsonVarFiles, moreDiags := GetHCL2Files(filename, hcl2AutoVarFileExt, hcl2AutoVarJsonFileExt) diags = append(diags, moreDiags...) - for _, file := range varFiles { + + // Combine all variable files into a single list, preserving the intended precedence and order. + // The order is: auto-loaded HCL files, auto-loaded JSON files, followed by user-specified varFiles. + // This ensures that user-specified files can override values from auto-loaded files, + // and that their relative order is preserved exactly as specified by the user. + variableFileNames := append(append(hclVarFiles, jsonVarFiles...), varFiles...) + + var variableFiles []*hcl.File + + for _, file := range variableFileNames { + var ( + f *hcl.File + moreDiags hcl.Diagnostics + ) switch filepath.Ext(file) { case ".hcl": - hclVarFiles = append(hclVarFiles, file) + f, moreDiags = p.ParseHCLFile(file) case ".json": - jsonVarFiles = append(jsonVarFiles, file) + f, moreDiags = p.ParseJSONFile(file) default: - diags = append(moreDiags, &hcl.Diagnostic{ - Severity: hcl.DiagError, - Summary: "Could not guess format of " + file, - Detail: "A var file must be suffixed with `.hcl` or `.json`.", - }) + moreDiags = hcl.Diagnostics{ + &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Could not guess format of " + file, + Detail: "A var file must be suffixed with `.hcl` or `.json`.", + }, + } } - } - var varFiles []*hcl.File - for _, filename := range hclVarFiles { - f, moreDiags := p.ParseHCLFile(filename) - diags = append(diags, moreDiags...) - if moreDiags.HasErrors() { - continue - } - varFiles = append(varFiles, f) - } - for _, filename := range jsonVarFiles { - f, moreDiags := p.ParseJSONFile(filename) + diags = append(diags, moreDiags...) if moreDiags.HasErrors() { continue } - varFiles = append(varFiles, f) + variableFiles = append(variableFiles, f) + } - diags = append(diags, cfg.collectInputVariableValues(os.Environ(), varFiles, argVars)...) + diags = append(diags, cfg.collectInputVariableValues(os.Environ(), variableFiles, argVars)...) } return cfg, diags