diff --git a/.changes/v1.14/BUG FIXES-20260123-103307.yaml b/.changes/v1.14/BUG FIXES-20260123-103307.yaml new file mode 100644 index 0000000000..7eac4e1b7d --- /dev/null +++ b/.changes/v1.14/BUG FIXES-20260123-103307.yaml @@ -0,0 +1,5 @@ +kind: BUG FIXES +body: actions in modules without instances failed the plan graph +time: 2026-01-23T10:33:07.244665+01:00 +custom: + Issue: "38089" diff --git a/internal/terraform/context_apply_action_test.go b/internal/terraform/context_apply_action_test.go index c6f363d68d..7e0c7f0774 100644 --- a/internal/terraform/context_apply_action_test.go +++ b/internal/terraform/context_apply_action_test.go @@ -783,6 +783,32 @@ resource "test_object" "a" { }}, }, + "not triggered with no module instances": { + module: map[string]string{ + "main.tf": ` +module "mod" { + count = 0 + source = "./mod" +} + +// an empty plan is not applyable so we have this extra resource here +resource "test_object" "a" {} +`, + "mod/mod.tf": ` +action "action_example" "hello" {} +resource "test_object" "a" { + lifecycle { + action_trigger { + events = [before_create] + actions = [action.action_example.hello] + } + } +} +`, + }, + expectInvokeActionCalled: false, + }, + "provider is within module": { module: map[string]string{ "main.tf": ` diff --git a/internal/terraform/context_plan_actions_test.go b/internal/terraform/context_plan_actions_test.go index feabf66a63..9f86b53429 100644 --- a/internal/terraform/context_plan_actions_test.go +++ b/internal/terraform/context_plan_actions_test.go @@ -1749,6 +1749,82 @@ resource "other_object" "a" { }, }, + "not triggered if module is count=0": { + module: map[string]string{ + "main.tf": ` +module "mod" { + count = 0 + source = "./mod" +} +`, + "mod/mod.tf": ` +action "test_action" "hello" {} +resource "other_object" "a" { + lifecycle { + action_trigger { + events = [before_create] + actions = [action.test_action.hello] + } + } +} +`, + }, + expectPlanActionCalled: false, + }, + + "not triggered if for_each is empty": { + module: map[string]string{ + "main.tf": ` +module "mod" { + for_each = toset([]) + source = "./mod" +} +`, + "mod/mod.tf": ` +action "test_action" "hello" {} +resource "other_object" "a" { + lifecycle { + action_trigger { + events = [before_create] + actions = [action.test_action.hello] + } + } +} +`, + }, + expectPlanActionCalled: false, + }, + + "action declaration in module if module is count=0": { + module: map[string]string{ + "main.tf": ` +module "mod" { + count = 0 + source = "./mod" +} +`, + "mod/mod.tf": ` +action "test_action" "hello" {} +`, + }, + expectPlanActionCalled: false, + }, + + "action declaration in module if for_each is empty": { + module: map[string]string{ + "main.tf": ` +module "mod" { + for_each = toset([]) + source = "./mod" +} +`, + "mod/mod.tf": ` +action "test_action" "hello" {} +`, + }, + expectPlanActionCalled: false, + }, + "provider is within module": { module: map[string]string{ "main.tf": ` diff --git a/internal/terraform/node_action.go b/internal/terraform/node_action.go index 21ec1c39d6..331548c88c 100644 --- a/internal/terraform/node_action.go +++ b/internal/terraform/node_action.go @@ -55,7 +55,6 @@ func (n *nodeExpandActionDeclaration) DynamicExpand(ctx EvalContext) (*Graph, tf resolvedProvider: n.ResolvedProvider, }) } - addRootNodeToGraph(&g) } for _, module := range moduleInstances { @@ -94,9 +93,8 @@ func (n *nodeExpandActionDeclaration) DynamicExpand(ctx EvalContext) (*Graph, tf g.Add(&node) } - - addRootNodeToGraph(&g) } + addRootNodeToGraph(&g) return &g, diags }