diff --git a/internal/command/format/diagnostic.go b/internal/command/format/diagnostic.go index 73a11d76d3..a32839ee72 100644 --- a/internal/command/format/diagnostic.go +++ b/internal/command/format/diagnostic.go @@ -253,6 +253,16 @@ func (f *snippetFormatter) write() { } fmt.Fprintf(buf, " on %s line %d%s:\n", diag.Range.Filename, diag.Range.Start.Line, contextStr) f.writeSnippet(snippet, code) + + if diag.DeprecationOriginRange != nil && diag.DeprecationOriginSnippet != nil { + var depContextStr string + if diag.DeprecationOriginSnippet.Context != nil { + depContextStr = fmt.Sprintf(", in %s", *snippet.Context) + } + buf.WriteByte('\n') + fmt.Fprintf(buf, " (origin of deprecation on %s line %d%s):\n", diag.DeprecationOriginRange.Filename, diag.DeprecationOriginRange.Start.Line, depContextStr) + f.writeSnippet(diag.DeprecationOriginSnippet, diag.DeprecationOriginSnippet.Code) + } } buf.WriteByte('\n') diff --git a/internal/command/format/diagnostic_test.go b/internal/command/format/diagnostic_test.go index 40130e0045..b2f15ab531 100644 --- a/internal/command/format/diagnostic_test.go +++ b/internal/command/format/diagnostic_test.go @@ -405,12 +405,44 @@ func TestDiagnostic(t *testing.T) { [red]│[reset] [red]│[reset] Example crash [red]╵[reset] +`, + }, + "warning from deprecation": { + &hcl.Diagnostic{ + Severity: hcl.DiagWarning, + Summary: "Deprecation detected", + Detail: "Countermeasures must be taken.", + Subject: &hcl.Range{ + Filename: "test.tf", + Start: hcl.Pos{Line: 1, Column: 6, Byte: 5}, + End: hcl.Pos{Line: 1, Column: 12, Byte: 11}, + }, + Extra: &tfdiags.DeprecationOriginDiagnosticExtra{ + Origin: &tfdiags.SourceRange{ + Filename: "deprecated.tf", + Start: tfdiags.SourcePos{Line: 1, Column: 11, Byte: 10}, + End: tfdiags.SourcePos{Line: 1, Column: 22, Byte: 21}, + }, + }, + }, + `[yellow]╷[reset] +[yellow]│[reset] [bold][yellow]Warning: [reset][bold]Deprecation detected[reset] +[yellow]│[reset] +[yellow]│[reset] on test.tf line 1: +[yellow]│[reset] 1: test [underline]source[reset] code +[yellow]│[reset] +[yellow]│[reset] (origin of deprecation on deprecated.tf line 1): +[yellow]│[reset] 1: source of [underline]deprecation[reset] +[yellow]│[reset] +[yellow]│[reset] Countermeasures must be taken. +[yellow]╵[reset] `, }, } sources := map[string][]byte{ - "test.tf": []byte(`test source code`), + "test.tf": []byte(`test source code`), + "deprecated.tf": []byte(`source of deprecation`), } // This empty Colorize just passes through all of the formatting codes @@ -424,8 +456,9 @@ func TestDiagnostic(t *testing.T) { diag := diags[0] got := strings.TrimSpace(Diagnostic(diag, sources, colorize, 40)) want := strings.TrimSpace(test.Want) - if got != want { - t.Errorf("wrong result\ngot:\n%s\n\nwant:\n%s\n\n", got, want) + + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("wrong result\ngot:\n%s\n\nwant:\n%s\n\ndiff:\n%s\n\n", got, want, diff) } }) } @@ -713,12 +746,44 @@ Error: Bad bad bad 1: test source code Whatever shall we do? +`, + }, + + "warning from deprecation": { + &hcl.Diagnostic{ + Severity: hcl.DiagWarning, + Summary: "Deprecation detected", + Detail: "Countermeasures must be taken.", + Subject: &hcl.Range{ + Filename: "test.tf", + Start: hcl.Pos{Line: 1, Column: 6, Byte: 5}, + End: hcl.Pos{Line: 1, Column: 12, Byte: 11}, + }, + Extra: &tfdiags.DeprecationOriginDiagnosticExtra{ + Origin: &tfdiags.SourceRange{ + Filename: "deprecated.tf", + Start: tfdiags.SourcePos{Line: 1, Column: 11, Byte: 10}, + End: tfdiags.SourcePos{Line: 1, Column: 22, Byte: 21}, + }, + }, + }, + ` +Warning: Deprecation detected + + on test.tf line 1: + 1: test source code + + (origin of deprecation on deprecated.tf line 1): + 1: source of deprecation + +Countermeasures must be taken. `, }, } sources := map[string][]byte{ - "test.tf": []byte(`test source code`), + "test.tf": []byte(`test source code`), + "deprecated.tf": []byte(`source of deprecation`), } for name, test := range tests { @@ -728,8 +793,8 @@ Whatever shall we do? diag := diags[0] got := strings.TrimSpace(DiagnosticPlain(diag, sources, 40)) want := strings.TrimSpace(test.Want) - if got != want { - t.Errorf("wrong result\ngot:\n%s\n\nwant:\n%s\n\n", got, want) + if diff := cmp.Diff(got, want); diff != "" { + t.Errorf("wrong result\ngot:\n%s\n\nwant:\n%s\n\n,diff:\n%s\n\n", got, want, diff) } }) } diff --git a/internal/command/views/json/diagnostic_test.go b/internal/command/views/json/diagnostic_test.go index f4a32ca89e..a375a33f4a 100644 --- a/internal/command/views/json/diagnostic_test.go +++ b/internal/command/views/json/diagnostic_test.go @@ -48,6 +48,7 @@ func TestNewDiagnostic(t *testing.T) { var.k, ] `), + "deprecation.tf": []byte(`resource "test_resource" "deprecated" {}`), } testCases := map[string]struct { diag interface{} // allow various kinds of diags @@ -867,6 +868,65 @@ func TestNewDiagnostic(t *testing.T) { }, }, }, + + "warning with deprecation origin": { + &hcl.Diagnostic{ + Severity: hcl.DiagWarning, + Summary: "Deprecated value caught in action", + Detail: "Oh no - don't do it!", + Subject: &hcl.Range{ + Filename: "test.tf", + Start: hcl.Pos{Line: 1, Column: 10, Byte: 9}, + End: hcl.Pos{Line: 1, Column: 25, Byte: 24}, + }, + Extra: &tfdiags.DeprecationOriginDiagnosticExtra{ + Origin: &tfdiags.SourceRange{ + Filename: "deprecation.tf", + Start: tfdiags.SourcePos{Line: 1, Column: 10, Byte: 9}, + End: tfdiags.SourcePos{Line: 1, Column: 25, Byte: 24}, + }, + }, + }, + &Diagnostic{ + Severity: "warning", + Summary: "Deprecated value caught in action", + Detail: "Oh no - don't do it!", + Range: &DiagnosticRange{ + Filename: "test.tf", + Start: Pos{ + Line: 1, + Column: 10, + Byte: 9, + }, + End: Pos{ + Line: 1, + Column: 25, + Byte: 24, + }, + }, + Snippet: &DiagnosticSnippet{ + Context: strPtr(`resource "test_resource" "test"`), + Code: `resource "test_resource" "test" {`, + StartLine: 1, + HighlightStartOffset: 9, + HighlightEndOffset: 24, + Values: []DiagnosticExpressionValue{}, + }, + DeprecationOriginRange: &DiagnosticRange{ + Filename: "deprecation.tf", + Start: Pos{Line: 1, Column: 10, Byte: 9}, + End: Pos{Line: 1, Column: 25, Byte: 24}, + }, + DeprecationOriginSnippet: &DiagnosticSnippet{ + Context: strPtr(`resource "test_resource" "deprecated"`), + Code: `resource "test_resource" "deprecated" {}`, + StartLine: 1, + HighlightStartOffset: 9, + HighlightEndOffset: 24, + Values: []DiagnosticExpressionValue{}, + }, + }, + }, } for name, tc := range testCases { diff --git a/internal/command/views/json/testdata/diagnostic/warning-with-deprecation-origin.json b/internal/command/views/json/testdata/diagnostic/warning-with-deprecation-origin.json new file mode 100644 index 0000000000..5223cbbf67 --- /dev/null +++ b/internal/command/views/json/testdata/diagnostic/warning-with-deprecation-origin.json @@ -0,0 +1,47 @@ +{ + "severity": "warning", + "summary": "Deprecated value caught in action", + "detail": "Oh no - don't do it!", + "range": { + "filename": "test.tf", + "start": { + "line": 1, + "column": 10, + "byte": 9 + }, + "end": { + "line": 1, + "column": 25, + "byte": 24 + } + }, + "snippet": { + "context": "resource \"test_resource\" \"test\"", + "code": "resource \"test_resource\" \"test\" {", + "start_line": 1, + "highlight_start_offset": 9, + "highlight_end_offset": 24, + "values": [] + }, + "deprecation_origin_range": { + "filename": "deprecation.tf", + "start": { + "line": 1, + "column": 10, + "byte": 9 + }, + "end": { + "line": 1, + "column": 25, + "byte": 24 + } + }, + "deprecation_origin_snippet": { + "context": "resource \"test_resource\" \"deprecated\"", + "code": "resource \"test_resource\" \"deprecated\" {}", + "start_line": 1, + "highlight_start_offset": 9, + "highlight_end_offset": 24, + "values": [] + } +}