Skip to content

Commit 6663066

Browse files
authored
chore: add warnings if modules are missing
2 parents be15107 + 3bfc554 commit 6663066

File tree

7 files changed

+109
-0
lines changed

7 files changed

+109
-0
lines changed

CONTRIBUTING.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ To run preview:
66
2. `pnpm install`
77
3. `cd ..`
88
4. `go run ./cmd/preview/main.go web --pnpm=site`
9+
5. visit http://localhost:5173/?testcontrols=true

preview_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@ import (
55
"encoding/json"
66
"os"
77
"path/filepath"
8+
"regexp"
9+
"slices"
810
"testing"
911

12+
"github.com/hashicorp/hcl/v2"
1013
"github.com/stretchr/testify/assert"
1114
"github.com/stretchr/testify/require"
1215

@@ -38,6 +41,7 @@ func Test_Extract(t *testing.T) {
3841
expTags map[string]string
3942
unknownTags []string
4043
params map[string]assertParam
44+
warnings []*regexp.Regexp
4145
}{
4246
{
4347
name: "bad param values",
@@ -402,6 +406,19 @@ func Test_Extract(t *testing.T) {
402406
"beta": ap().unknown(),
403407
},
404408
},
409+
{
410+
name: "missing_module",
411+
dir: "missingmodule",
412+
expTags: map[string]string{},
413+
input: preview.Input{
414+
ParameterValues: map[string]string{},
415+
},
416+
unknownTags: []string{},
417+
params: map[string]assertParam{},
418+
warnings: []*regexp.Regexp{
419+
regexp.MustCompile("Module not loaded"),
420+
},
421+
},
405422
{
406423
skip: "skip until https://github.com/aquasecurity/trivy/pull/8479 is resolved",
407424
name: "submodcount",
@@ -440,6 +457,16 @@ func Test_Extract(t *testing.T) {
440457
}
441458
require.False(t, diags.HasErrors())
442459

460+
if len(tc.warnings) > 0 {
461+
for _, w := range tc.warnings {
462+
idx := slices.IndexFunc(diags, func(diagnostic *hcl.Diagnostic) bool {
463+
return w.MatchString(diagnostic.Error())
464+
465+
})
466+
require.Greater(t, idx, -1, "expected warning %q to be present in diags", w.String())
467+
}
468+
}
469+
443470
// Assert tags
444471
validTags := output.WorkspaceTags.Tags()
445472

testdata/missingmodule/main.tf

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module "does-not-exist" {
2+
source = "registry.coder.com/modules/does-not-exist/coder"
3+
}
4+
5+
module "does-not-exist-2" {
6+
count = 0
7+
source = "registry.coder.com/modules/does-not-exist/coder"
8+
}
9+
10+
module "one" {
11+
source = "./one"
12+
}

testdata/missingmodule/one/one.tf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module "onea" {
2+
source = "./onea"
3+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
terraform {
2+
required_providers {
3+
coder = {
4+
source = "coder/coder"
5+
version = "2.4.0-pre0"
6+
}
7+
}
8+
}
9+
10+
data "null_data_source" "values" {
11+
inputs = {
12+
foo = "bar"
13+
}
14+
}

testdata/missingmodule/skipe2e

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Not a real module

warnings.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,57 @@ import (
1111
func warnings(modules terraform.Modules) hcl.Diagnostics {
1212
var diags hcl.Diagnostics
1313
diags = diags.Extend(unexpandedCountBlocks(modules))
14+
diags = diags.Extend(unresolvedModules(modules))
15+
16+
return diags
17+
}
18+
19+
// unresolvedModules does a best effort to try and detect if some modules
20+
// failed to resolve. This is usually because `terraform init` is not run.
21+
func unresolvedModules(modules terraform.Modules) hcl.Diagnostics {
22+
var diags hcl.Diagnostics
23+
modulesUsed := make(map[string]bool)
24+
modulesByID := make(map[string]*terraform.Block)
25+
26+
// There is no easy way to know if a `module` failed to resolve. The failure is
27+
// only logged in the trivy package. No errors are returned to the caller. So
28+
// instead this code will infer a failed resolution by checking if any blocks
29+
// exist that reference each `module` block. This will work as long as the module
30+
// has some content. If a module is completely empty, then it will be detected as
31+
// "not loaded".
32+
blocks := modules.GetBlocks()
33+
for _, block := range blocks {
34+
if block.InModule() && block.ModuleBlock() != nil {
35+
modulesUsed[block.ModuleBlock().ID()] = true
36+
}
37+
38+
if block.Type() == "module" {
39+
modulesByID[block.ID()] = block
40+
_, ok := modulesUsed[block.ID()]
41+
if !ok {
42+
modulesUsed[block.ID()] = false
43+
}
44+
}
45+
}
46+
47+
for id, v := range modulesUsed {
48+
if !v {
49+
block, ok := modulesByID[id]
50+
if ok {
51+
label := block.Type()
52+
for _, l := range block.Labels() {
53+
label += " " + fmt.Sprintf("%q", l)
54+
}
55+
56+
diags = diags.Append(&hcl.Diagnostic{
57+
Severity: hcl.DiagWarning,
58+
Summary: "Module not loaded. Did you run `terraform init`?",
59+
Detail: fmt.Sprintf("Module '%s' in file %q cannot be resolved. This module will be ignored.", label, block.HCLBlock().DefRange),
60+
Subject: &(block.HCLBlock().DefRange),
61+
})
62+
}
63+
}
64+
}
1465

1566
return diags
1667
}

0 commit comments

Comments
 (0)