From 360708901667b61cf7f9008415a2d20be0c3312b Mon Sep 17 00:00:00 2001 From: Daniel Banck Date: Wed, 23 Jul 2025 16:52:19 +0200 Subject: [PATCH] Support tfquery files in `terraform fmt` (#37347) --- internal/command/fmt.go | 19 ++-- internal/command/fmt_test.go | 104 ++++++++++++++---- .../testdata/tfquery-fmt/main_in.tfquery.hcl | 14 +++ .../testdata/tfquery-fmt/main_out.tfquery.hcl | 14 +++ 4 files changed, 123 insertions(+), 28 deletions(-) create mode 100644 internal/command/testdata/tfquery-fmt/main_in.tfquery.hcl create mode 100644 internal/command/testdata/tfquery-fmt/main_out.tfquery.hcl diff --git a/internal/command/fmt.go b/internal/command/fmt.go index b7990f61c4..bc1118c2db 100644 --- a/internal/command/fmt.go +++ b/internal/command/fmt.go @@ -7,7 +7,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "log" "os" "os/exec" @@ -53,6 +52,10 @@ func (c *FmtCommand) Run(args []string) int { c.input = os.Stdin } + if c.Meta.AllowExperimentalFeatures { + fmtSupportedExts = append(fmtSupportedExts, ".tfquery.hcl") + } + args = c.Meta.process(args) cmdFlags := c.Meta.defaultFlagSet("fmt") cmdFlags.BoolVar(&c.list, "list", true, "list") @@ -174,7 +177,7 @@ func (c *FmtCommand) processFile(path string, r io.Reader, w io.Writer, isStdout log.Printf("[TRACE] terraform fmt: Formatting %s", path) - src, err := ioutil.ReadAll(r) + src, err := io.ReadAll(r) if err != nil { diags = diags.Append(fmt.Errorf("Failed to read %s", path)) return diags @@ -201,7 +204,7 @@ func (c *FmtCommand) processFile(path string, r io.Reader, w io.Writer, isStdout fmt.Fprintln(w, path) } if c.write { - err := ioutil.WriteFile(path, result, 0644) + err := os.WriteFile(path, result, 0644) if err != nil { diags = diags.Append(fmt.Errorf("Failed to write %s", path)) return diags @@ -232,7 +235,7 @@ func (c *FmtCommand) processDir(path string, stdout io.Writer) tfdiags.Diagnosti log.Printf("[TRACE] terraform fmt: looking for files in %s", path) - entries, err := ioutil.ReadDir(path) + entries, err := os.ReadDir(path) if err != nil { switch { case os.IsNotExist(err): @@ -551,8 +554,8 @@ func (c *FmtCommand) Help() string { Usage: terraform [global options] fmt [options] [target...] Rewrites all Terraform configuration files to a canonical format. All - configuration files (.tf), variables files (.tfvars), and testing files - (.tftest.hcl) are updated. JSON files (.tf.json, .tfvars.json, or + configuration files (.tf), variables files (.tfvars), and testing files + (.tftest.hcl) are updated. JSON files (.tf.json, .tfvars.json, or .tftest.json) are not modified. By default, fmt scans the current directory for configuration files. If you @@ -590,14 +593,14 @@ func (c *FmtCommand) Synopsis() string { } func bytesDiff(b1, b2 []byte, path string) (data []byte, err error) { - f1, err := ioutil.TempFile("", "") + f1, err := os.CreateTemp("", "") if err != nil { return } defer os.Remove(f1.Name()) defer f1.Close() - f2, err := ioutil.TempFile("", "") + f2, err := os.CreateTemp("", "") if err != nil { return } diff --git a/internal/command/fmt_test.go b/internal/command/fmt_test.go index 2f46ec0e8a..7953bb7c1f 100644 --- a/internal/command/fmt_test.go +++ b/internal/command/fmt_test.go @@ -6,7 +6,6 @@ package command import ( "bytes" "fmt" - "io/ioutil" "os" "path/filepath" "strings" @@ -20,7 +19,7 @@ func TestFmt_MockDataFiles(t *testing.T) { const inSuffix = "_in.tfmock.hcl" const outSuffix = "_out.tfmock.hcl" const gotSuffix = "_got.tfmock.hcl" - entries, err := ioutil.ReadDir("testdata/tfmock-fmt") + entries, err := os.ReadDir("testdata/tfmock-fmt") if err != nil { t.Fatal(err) } @@ -43,15 +42,15 @@ func TestFmt_MockDataFiles(t *testing.T) { inFile := filepath.Join("testdata", "tfmock-fmt", testName+inSuffix) wantFile := filepath.Join("testdata", "tfmock-fmt", testName+outSuffix) gotFile := filepath.Join(tmpDir, testName+gotSuffix) - input, err := ioutil.ReadFile(inFile) + input, err := os.ReadFile(inFile) if err != nil { t.Fatal(err) } - want, err := ioutil.ReadFile(wantFile) + want, err := os.ReadFile(wantFile) if err != nil { t.Fatal(err) } - err = ioutil.WriteFile(gotFile, input, 0700) + err = os.WriteFile(gotFile, input, 0700) if err != nil { t.Fatal(err) } @@ -68,7 +67,7 @@ func TestFmt_MockDataFiles(t *testing.T) { t.Fatalf("fmt command was unsuccessful:\n%s", ui.ErrorWriter.String()) } - got, err := ioutil.ReadFile(gotFile) + got, err := os.ReadFile(gotFile) if err != nil { t.Fatal(err) } @@ -84,7 +83,7 @@ func TestFmt_TestFiles(t *testing.T) { const inSuffix = "_in.tftest.hcl" const outSuffix = "_out.tftest.hcl" const gotSuffix = "_got.tftest.hcl" - entries, err := ioutil.ReadDir("testdata/tftest-fmt") + entries, err := os.ReadDir("testdata/tftest-fmt") if err != nil { t.Fatal(err) } @@ -107,15 +106,15 @@ func TestFmt_TestFiles(t *testing.T) { inFile := filepath.Join("testdata", "tftest-fmt", testName+inSuffix) wantFile := filepath.Join("testdata", "tftest-fmt", testName+outSuffix) gotFile := filepath.Join(tmpDir, testName+gotSuffix) - input, err := ioutil.ReadFile(inFile) + input, err := os.ReadFile(inFile) if err != nil { t.Fatal(err) } - want, err := ioutil.ReadFile(wantFile) + want, err := os.ReadFile(wantFile) if err != nil { t.Fatal(err) } - err = ioutil.WriteFile(gotFile, input, 0700) + err = os.WriteFile(gotFile, input, 0700) if err != nil { t.Fatal(err) } @@ -132,7 +131,72 @@ func TestFmt_TestFiles(t *testing.T) { t.Fatalf("fmt command was unsuccessful:\n%s", ui.ErrorWriter.String()) } - got, err := ioutil.ReadFile(gotFile) + got, err := os.ReadFile(gotFile) + if err != nil { + t.Fatal(err) + } + + if diff := cmp.Diff(string(want), string(got)); diff != "" { + t.Errorf("wrong result\n%s", diff) + } + }) + } +} + +func TestFmt_QueryFiles(t *testing.T) { + const inSuffix = "_in.tfquery.hcl" + const outSuffix = "_out.tfquery.hcl" + const gotSuffix = "_got.tfquery.hcl" + entries, err := os.ReadDir("testdata/tfquery-fmt") + if err != nil { + t.Fatal(err) + } + + tmpDir, err := filepath.EvalSymlinks(t.TempDir()) + if err != nil { + t.Fatal(err) + } + + for _, info := range entries { + if info.IsDir() { + continue + } + filename := info.Name() + if !strings.HasSuffix(filename, inSuffix) { + continue + } + testName := filename[:len(filename)-len(inSuffix)] + t.Run(testName, func(t *testing.T) { + inFile := filepath.Join("testdata", "tfquery-fmt", testName+inSuffix) + wantFile := filepath.Join("testdata", "tfquery-fmt", testName+outSuffix) + gotFile := filepath.Join(tmpDir, testName+gotSuffix) + input, err := os.ReadFile(inFile) + if err != nil { + t.Fatal(err) + } + want, err := os.ReadFile(wantFile) + if err != nil { + t.Fatal(err) + } + err = os.WriteFile(gotFile, input, 0700) + if err != nil { + t.Fatal(err) + } + + ui := cli.NewMockUi() + c := &FmtCommand{ + Meta: Meta{ + testingOverrides: metaOverridesForProvider(testProvider()), + Ui: ui, + AllowExperimentalFeatures: true, + }, + } + args := []string{gotFile} + if code := c.Run(args); code != 0 { + t.Fatalf("fmt command was unsuccessful:\n%s", ui.ErrorWriter.String()) + } + + got, err := os.ReadFile(gotFile) if err != nil { t.Fatal(err) } @@ -148,7 +212,7 @@ func TestFmt(t *testing.T) { const inSuffix = "_in.tf" const outSuffix = "_out.tf" const gotSuffix = "_got.tf" - entries, err := ioutil.ReadDir("testdata/fmt") + entries, err := os.ReadDir("testdata/fmt") if err != nil { t.Fatal(err) } @@ -171,15 +235,15 @@ func TestFmt(t *testing.T) { inFile := filepath.Join("testdata", "fmt", testName+inSuffix) wantFile := filepath.Join("testdata", "fmt", testName+outSuffix) gotFile := filepath.Join(tmpDir, testName+gotSuffix) - input, err := ioutil.ReadFile(inFile) + input, err := os.ReadFile(inFile) if err != nil { t.Fatal(err) } - want, err := ioutil.ReadFile(wantFile) + want, err := os.ReadFile(wantFile) if err != nil { t.Fatal(err) } - err = ioutil.WriteFile(gotFile, input, 0700) + err = os.WriteFile(gotFile, input, 0700) if err != nil { t.Fatal(err) } @@ -196,7 +260,7 @@ func TestFmt(t *testing.T) { t.Fatalf("fmt command was unsuccessful:\n%s", ui.ErrorWriter.String()) } - got, err := ioutil.ReadFile(gotFile) + got, err := os.ReadFile(gotFile) if err != nil { t.Fatal(err) } @@ -238,7 +302,7 @@ func TestFmt_syntaxError(t *testing.T) { a = 1 + ` - err := ioutil.WriteFile(filepath.Join(tempDir, "invalid.tf"), []byte(invalidSrc), 0644) + err := os.WriteFile(filepath.Join(tempDir, "invalid.tf"), []byte(invalidSrc), 0644) if err != nil { t.Fatal(err) } @@ -267,7 +331,7 @@ func TestFmt_snippetInError(t *testing.T) { backendSrc := `terraform {backend "s3" {}}` - err := ioutil.WriteFile(filepath.Join(tempDir, "backend.tf"), []byte(backendSrc), 0644) + err := os.WriteFile(filepath.Join(tempDir, "backend.tf"), []byte(backendSrc), 0644) if err != nil { t.Fatal(err) } @@ -302,7 +366,7 @@ func TestFmt_manyArgs(t *testing.T) { // Add a second file secondSrc := `locals { x = 1 }` - err := ioutil.WriteFile(filepath.Join(tempDir, "second.tf"), []byte(secondSrc), 0644) + err := os.WriteFile(filepath.Join(tempDir, "second.tf"), []byte(secondSrc), 0644) if err != nil { t.Fatal(err) } @@ -539,7 +603,7 @@ var fmtFixture = struct { func fmtFixtureWriteDir(t *testing.T) string { dir := testTempDir(t) - err := ioutil.WriteFile(filepath.Join(dir, fmtFixture.filename), fmtFixture.input, 0644) + err := os.WriteFile(filepath.Join(dir, fmtFixture.filename), fmtFixture.input, 0644) if err != nil { t.Fatal(err) } diff --git a/internal/command/testdata/tfquery-fmt/main_in.tfquery.hcl b/internal/command/testdata/tfquery-fmt/main_in.tfquery.hcl new file mode 100644 index 0000000000..d888c72551 --- /dev/null +++ b/internal/command/testdata/tfquery-fmt/main_in.tfquery.hcl @@ -0,0 +1,14 @@ + +variable "value" { + type = string +default = "value" +} + +list foo_list "some_list_block" { + provider=foo + + config { + condition = var.value + filter = 42 + } +} diff --git a/internal/command/testdata/tfquery-fmt/main_out.tfquery.hcl b/internal/command/testdata/tfquery-fmt/main_out.tfquery.hcl new file mode 100644 index 0000000000..530ac9b521 --- /dev/null +++ b/internal/command/testdata/tfquery-fmt/main_out.tfquery.hcl @@ -0,0 +1,14 @@ + +variable "value" { + type = string + default = "value" +} + +list "foo_list" "some_list_block" { + provider = foo + + config { + condition = var.value + filter = 42 + } +}