-
Notifications
You must be signed in to change notification settings - Fork 132
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Introduce a new job for running early validation (#1346)
* Implement unreferenced variable validation (#1357) Add the ability to use the collected origin and target references in early validation by providing a hook for validation funcs. This also adds a validator for unreferenced variables. Validation funcs will be provided by terraform-ls for now, but may be moved into hcl-lang in the future. * Introduce ValidationDiagnostics field to module * Publish early validation diagnostics * Include validation diagnotics in changes check * Introduce early validation job * Check ValidationDiagnosticsState when running validation * Run early validation job after collection jobs * Bump hcl-lang to `b6a3f8` * Update internal/terraform/module/module_ops.go Co-authored-by: Radek Simko <radek.simko@gmail.com> --------- Co-authored-by: James Pogran <jpogran@outlook.com> Co-authored-by: Radek Simko <radek.simko@gmail.com>
- Loading branch information
1 parent
5ee9606
commit e619a8e
Showing
11 changed files
with
312 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
// Copyright (c) HashiCorp, Inc. | ||
// SPDX-License-Identifier: MPL-2.0 | ||
|
||
package validations | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/hashicorp/hcl-lang/decoder" | ||
"github.com/hashicorp/hcl-lang/lang" | ||
"github.com/hashicorp/hcl-lang/reference" | ||
"github.com/hashicorp/hcl/v2" | ||
) | ||
|
||
func UnreferencedOrigins(ctx context.Context) lang.DiagnosticsMap { | ||
diagsMap := make(lang.DiagnosticsMap) | ||
|
||
pathCtx, err := decoder.PathCtx(ctx) | ||
if err != nil { | ||
return diagsMap | ||
} | ||
|
||
for _, origin := range pathCtx.ReferenceOrigins { | ||
matchableOrigin, ok := origin.(reference.MatchableOrigin) | ||
if !ok { | ||
// we don't report on other origins to avoid complexity for now | ||
// other origins would need to be matched against other | ||
// modules/directories and we cannot be sure the targets are | ||
// available within the workspace or were parsed/decoded/collected | ||
// at the time this event occurs | ||
continue | ||
} | ||
|
||
// we only initially validate variables | ||
// resources and data sources can have unknown schema | ||
// and will be researched at a later point | ||
firstStep := matchableOrigin.Address()[0] | ||
if firstStep.String() != "var" { | ||
continue | ||
} | ||
|
||
_, ok = pathCtx.ReferenceTargets.Match(matchableOrigin) | ||
if !ok { | ||
// target not found | ||
fileName := origin.OriginRange().Filename | ||
d := &hcl.Diagnostic{ | ||
Severity: hcl.DiagError, | ||
Summary: fmt.Sprintf("No declaration found for %q", matchableOrigin.Address()), | ||
Subject: origin.OriginRange().Ptr(), | ||
} | ||
diagsMap[fileName] = diagsMap[fileName].Append(d) | ||
|
||
continue | ||
} | ||
|
||
} | ||
|
||
return diagsMap | ||
} |
120 changes: 120 additions & 0 deletions
120
internal/decoder/validations/unreferenced_origin_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
// Copyright (c) HashiCorp, Inc. | ||
// SPDX-License-Identifier: MPL-2.0 | ||
|
||
package validations | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
"testing" | ||
|
||
"github.com/google/go-cmp/cmp" | ||
"github.com/hashicorp/hcl-lang/decoder" | ||
"github.com/hashicorp/hcl-lang/lang" | ||
"github.com/hashicorp/hcl-lang/reference" | ||
"github.com/hashicorp/hcl/v2" | ||
) | ||
|
||
func TestUnreferencedOrigins(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
origins reference.Origins | ||
want lang.DiagnosticsMap | ||
}{ | ||
{ | ||
name: "undeclared variable", | ||
origins: reference.Origins{ | ||
reference.LocalOrigin{ | ||
Range: hcl.Range{ | ||
Filename: "test.tf", | ||
Start: hcl.Pos{}, | ||
End: hcl.Pos{}, | ||
}, | ||
Addr: lang.Address{ | ||
lang.RootStep{Name: "var"}, | ||
lang.AttrStep{Name: "foo"}, | ||
}, | ||
}, | ||
}, | ||
want: lang.DiagnosticsMap{ | ||
"test.tf": hcl.Diagnostics{ | ||
&hcl.Diagnostic{ | ||
Severity: hcl.DiagError, | ||
Summary: "No declaration found for \"var.foo\"", | ||
Subject: &hcl.Range{ | ||
Filename: "test.tf", | ||
Start: hcl.Pos{}, | ||
End: hcl.Pos{}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
{ | ||
name: "many undeclared variables", | ||
origins: reference.Origins{ | ||
reference.LocalOrigin{ | ||
Range: hcl.Range{ | ||
Filename: "test.tf", | ||
Start: hcl.Pos{Line: 1, Column: 1, Byte: 0}, | ||
End: hcl.Pos{Line: 1, Column: 10, Byte: 10}, | ||
}, | ||
Addr: lang.Address{ | ||
lang.RootStep{Name: "var"}, | ||
lang.AttrStep{Name: "foo"}, | ||
}, | ||
}, | ||
reference.LocalOrigin{ | ||
Range: hcl.Range{ | ||
Filename: "test.tf", | ||
Start: hcl.Pos{Line: 2, Column: 1, Byte: 0}, | ||
End: hcl.Pos{Line: 2, Column: 10, Byte: 10}, | ||
}, | ||
Addr: lang.Address{ | ||
lang.RootStep{Name: "var"}, | ||
lang.AttrStep{Name: "wakka"}, | ||
}, | ||
}, | ||
}, | ||
want: lang.DiagnosticsMap{ | ||
"test.tf": hcl.Diagnostics{ | ||
&hcl.Diagnostic{ | ||
Severity: hcl.DiagError, | ||
Summary: "No declaration found for \"var.foo\"", | ||
Subject: &hcl.Range{ | ||
Filename: "test.tf", | ||
Start: hcl.Pos{Line: 1, Column: 1, Byte: 0}, | ||
End: hcl.Pos{Line: 1, Column: 10, Byte: 10}, | ||
}, | ||
}, | ||
&hcl.Diagnostic{ | ||
Severity: hcl.DiagError, | ||
Summary: "No declaration found for \"var.wakka\"", | ||
Subject: &hcl.Range{ | ||
Filename: "test.tf", | ||
Start: hcl.Pos{Line: 2, Column: 1, Byte: 0}, | ||
End: hcl.Pos{Line: 2, Column: 10, Byte: 10}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
} | ||
|
||
for i, tt := range tests { | ||
t.Run(fmt.Sprintf("%2d-%s", i, tt.name), func(t *testing.T) { | ||
ctx := context.Background() | ||
|
||
pathCtx := &decoder.PathContext{ | ||
ReferenceOrigins: tt.origins, | ||
} | ||
|
||
ctx = decoder.WithPathContext(ctx, pathCtx) | ||
|
||
diags := UnreferencedOrigins(ctx) | ||
if diff := cmp.Diff(tt.want["test.tf"], diags["test.tf"]); diff != "" { | ||
t.Fatalf("unexpected diagnostics: %s", diff) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.