From 206e2e6d6ae2b6ff72866a5e3b959d7025187cd8 Mon Sep 17 00:00:00 2001 From: Alisdair McDiarmid Date: Thu, 26 Mar 2020 13:58:20 -0400 Subject: [PATCH] command/fmt: Include source snippets in errors Previously, diagnostic errors would display the filename and line number, along with "(source code not available)". This is because the fmt command directly loads and parses the configuration, instead of using the config loader. This commit registers the manually parsed source as a synthetic configuration file, so that the diagnostic formatter can look up the source for the range with the error and display it. --- command/fmt.go | 4 ++++ command/fmt_test.go | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) diff --git a/command/fmt.go b/command/fmt.go index a8ce41304..13cd6f113 100644 --- a/command/fmt.go +++ b/command/fmt.go @@ -167,6 +167,10 @@ func (c *FmtCommand) processFile(path string, r io.Reader, w io.Writer, isStdout return diags } + // Register this path as a synthetic configuration source, so that any + // diagnostic errors can include the source code snippet + c.registerSynthConfigSource(path, src) + // File must be parseable as HCL native syntax before we'll try to format // it. If not, the formatter is likely to make drastic changes that would // be hard for the user to undo. diff --git a/command/fmt_test.go b/command/fmt_test.go index f35737953..274784b10 100644 --- a/command/fmt_test.go +++ b/command/fmt_test.go @@ -66,6 +66,41 @@ a = 1 + } } +func TestFmt_snippetInError(t *testing.T) { + tempDir := testTempDir(t) + + backendSrc := `terraform {backend "s3" {}}` + + err := ioutil.WriteFile(filepath.Join(tempDir, "backend.tf"), []byte(backendSrc), 0644) + if err != nil { + t.Fatal(err) + } + + ui := new(cli.MockUi) + c := &FmtCommand{ + Meta: Meta{ + testingOverrides: metaOverridesForProvider(testProvider()), + Ui: ui, + }, + } + + args := []string{tempDir} + if code := c.Run(args); code != 2 { + t.Fatalf("wrong exit code. errors: \n%s", ui.ErrorWriter.String()) + } + + substrings := []string{ + "Argument definition required", + "line 1, in terraform", + `1: terraform {backend "s3" {}}`, + } + for _, substring := range substrings { + if actual := ui.ErrorWriter.String(); !strings.Contains(actual, substring) { + t.Errorf("expected:\n%s\n\nto include: %q", actual, substring) + } + } +} + func TestFmt_tooManyArgs(t *testing.T) { ui := new(cli.MockUi) c := &FmtCommand{