Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 35 additions & 2 deletions internal/terraform/context_plan_actions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4088,8 +4088,41 @@ resource "test_object" "a" {
if !diags.HasErrors() {
t.Fatal("expected errors, got success!")
}
if diags.Err().Error() != "Configuration for triggered action does not exist: The configuration for the given action action.test_action.hello does not exist. All triggered actions must have an associated configuration." {
t.Fatal("wrong error!")
expectedErr := "action_trigger actions references non-existent action: The lifecycle action_trigger actions list contains a reference to the action \"action.test_action.hello\" that does not exist in the configuration of this module."
if diags.Err().Error() != expectedErr {
t.Fatalf("wrong error!, got %q, expected %q", diags.Err().Error(), expectedErr)
}
}

func TestContextPlan_validateActionInTriggerExistsWithSimilarAction(t *testing.T) {
// this validation occurs during TransformConfig
module := `
action "test_action" "hello_word" {}

resource "test_object" "a" {
lifecycle {
action_trigger {
events = [after_create]
actions = [action.test_action.hello_world]
}
}
}
`
m := testModuleInline(t, map[string]string{"main.tf": module})
p := simpleMockProvider()
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
})

_, diags := ctx.Plan(m, nil, DefaultPlanOpts)
if !diags.HasErrors() {
t.Fatal("expected errors, got success!")
}
expectedErr := "action_trigger actions references non-existent action: The lifecycle action_trigger actions list contains a reference to the action \"action.test_action.hello_world\" that does not exist in the configuration of this module. Did you mean \"action.test_action.hello_word\"?"
if diags.Err().Error() != expectedErr {
t.Fatalf("wrong error!, got %q, expected %q", diags.Err().Error(), expectedErr)
}
}

Expand Down
17 changes: 13 additions & 4 deletions internal/terraform/transform_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ package terraform
import (
"fmt"
"log"
"maps"
"slices"

"github.com/hashicorp/hcl/v2"

"github.com/hashicorp/terraform/internal/addrs"
"github.com/hashicorp/terraform/internal/configs"
"github.com/hashicorp/terraform/internal/dag"
"github.com/hashicorp/terraform/internal/didyoumean"
"github.com/hashicorp/terraform/internal/lang/langrefs"
"github.com/hashicorp/terraform/internal/tfdiags"
)
Expand Down Expand Up @@ -164,7 +167,7 @@ func (t *ConfigTransformer) transformSingle(g *Graph, config *configs.Config) er
// Verify that any actions referenced in the resource's ActionTriggers exist in this module
var diags tfdiags.Diagnostics
if r.Managed != nil && r.Managed.ActionTriggers != nil {
for i, at := range r.Managed.ActionTriggers {
for _, at := range r.Managed.ActionTriggers {
for _, action := range at.Actions {

refs, parseRefDiags := langrefs.ReferencesInExpr(addrs.ParseRef, action.Expr)
Expand All @@ -190,11 +193,17 @@ func (t *ConfigTransformer) transformSingle(g *Graph, config *configs.Config) er

_, ok := allConfigActions[configAction.String()]
if !ok {
suggestion := didyoumean.NameSuggestion(configAction.String(), slices.Collect(maps.Keys(allConfigActions)))
if suggestion != "" {
suggestion = fmt.Sprintf(" Did you mean %q?", suggestion)
}

diags = diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Configuration for triggered action does not exist",
Detail: fmt.Sprintf("The configuration for the given action %s does not exist. All triggered actions must have an associated configuration.", configAction.String()),
Subject: &r.Managed.ActionTriggers[i].DeclRange,
Summary: "action_trigger actions references non-existent action",
Detail: fmt.Sprintf("The lifecycle action_trigger actions list contains a reference to the action %q that does not exist in the configuration of this module.%s", configAction.String(), suggestion),
Subject: action.Expr.Range().Ptr(),
Context: r.DeclRange.Ptr(),
})
}
}
Expand Down
Loading