Skip to content

Commit 2fd2922

Browse files
authored
Merge pull request #172 from hashicorp/mutahhir/add-action-invocation
Add support for action invocation within Plan JSON
2 parents 41f8aaf + b539674 commit 2fd2922

File tree

3 files changed

+78
-10
lines changed

3 files changed

+78
-10
lines changed

plan.go

Lines changed: 34 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ type Plan struct {
9292
// Timestamp contains the static timestamp that Terraform considers to be
9393
// the time this plan executed, in UTC.
9494
Timestamp string `json:"timestamp,omitempty"`
95+
96+
ActionInvocations []*ActionInvocation `json:"action_invocations,omitempty"`
9597
}
9698

9799
// ResourceAttribute describes a full path to a resource attribute
@@ -140,15 +142,6 @@ func (p *Plan) Validate() error {
140142
return nil
141143
}
142144

143-
func isStringInSlice(slice []string, s string) bool {
144-
for _, el := range slice {
145-
if el == s {
146-
return true
147-
}
148-
}
149-
return false
150-
}
151-
152145
func (p *Plan) UnmarshalJSON(b []byte) error {
153146
type rawPlan Plan
154147
var plan rawPlan
@@ -305,3 +298,35 @@ type DeferredResourceChange struct {
305298
// Change contains any information we have about the deferred change.
306299
ResourceChange *ResourceChange `json:"resource_change,omitempty"`
307300
}
301+
302+
type ActionInvocation struct {
303+
// Address is the absolute action address
304+
Address string `json:"address,omitempty"`
305+
// Type is the type of the action
306+
Type string `json:"type,omitempty"`
307+
// Name is the name of the action
308+
Name string `json:"name,omitempty"`
309+
310+
// ConfigValues is the JSON representation of the values in the config block of the action
311+
ConfigValues interface{} `json:"config_values,omitempty"`
312+
ConfigSensitive interface{} `json:"config_sensitive,omitempty"`
313+
ConfigUnknown interface{} `json:"config_unknown,omitempty"`
314+
315+
// ProviderName allows the property "type" to be interpreted unambiguously
316+
// in the unusual situation where a provider offers a type whose
317+
// name does not start with its own name, such as the "googlebeta" provider
318+
// offering "google_compute_instance".
319+
ProviderName string `json:"provider_name,omitempty"`
320+
321+
LifecycleActionTrigger *LifecycleActionTrigger `json:"lifecycle_action_trigger,omitempty"`
322+
InvokeActionTrigger *InvokeActionTrigger `json:"invoke_action_trigger,omitempty"`
323+
}
324+
325+
type LifecycleActionTrigger struct {
326+
TriggeringResourceAddress string `json:"triggering_resource_address,omitempty"`
327+
ActionTriggerEvent string `json:"action_trigger_event,omitempty"`
328+
ActionTriggerBlockIndex int `json:"action_trigger_block_index"`
329+
ActionsListIndex int `json:"actions_list_index"`
330+
}
331+
332+
type InvokeActionTrigger struct{}

plan_test.go

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,49 @@ func TestPlan_movedBlock(t *testing.T) {
136136
}
137137
}
138138

139+
func TestPlan_actionInvocations(t *testing.T) {
140+
f, err := os.Open("testdata/actions/plan.json")
141+
if err != nil {
142+
t.Fatal(err)
143+
}
144+
defer f.Close()
145+
146+
var plan *Plan
147+
if err := json.NewDecoder(f).Decode(&plan); err != nil {
148+
t.Fatal(err)
149+
}
150+
151+
if err := plan.Validate(); err != nil {
152+
t.Fatal(err)
153+
}
154+
155+
if len(plan.ActionInvocations) != 1 {
156+
t.Fatalf("expected exactly 1 action invocation, got %d", len(plan.ActionInvocations))
157+
}
158+
159+
expectedAction := []*ActionInvocation{
160+
{
161+
Address: "action.bufo_print.success",
162+
Type: "bufo_print",
163+
Name: "success",
164+
ConfigValues: map[string]interface{}{
165+
"color": nil,
166+
"name": "bufo-the-builder",
167+
"ratio": nil,
168+
},
169+
ConfigSensitive: map[string]interface{}{},
170+
ConfigUnknown: map[string]interface{}{},
171+
ProviderName: "registry.terraform.io/austinvalle/bufo",
172+
LifecycleActionTrigger: nil,
173+
InvokeActionTrigger: &InvokeActionTrigger{},
174+
},
175+
}
176+
177+
if diff := cmp.Diff(expectedAction, plan.ActionInvocations); diff != "" {
178+
t.Fatalf("unexpected action invocation: %s", diff)
179+
}
180+
}
181+
139182
func TestPlan_UnmarshalJSON(t *testing.T) {
140183
t.Parallel()
141184

@@ -168,7 +211,6 @@ func TestPlan_UnmarshalJSON(t *testing.T) {
168211
plan.UseJSONNumber(testCase.useJSONNumber)
169212

170213
err = plan.UnmarshalJSON(b)
171-
172214
if err != nil {
173215
t.Fatal(err)
174216
}

testdata/actions/plan.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"format_version":"1.2","planned_values":{"root_module":{}},"complete":true,"configuration":{"provider_config":{"bufo":{"name":"bufo","full_name":"registry.terraform.io/austinvalle/bufo"}},"root_module":{}},"timestamp":"2025-09-12T09:56:02Z","action_invocations":[{"address":"action.bufo_print.success","type":"bufo_print","name":"success","config_values":{"color":null,"name":"bufo-the-builder","ratio":null},"config_sensitive":{},"config_unknown":{},"provider_name":"registry.terraform.io/austinvalle/bufo","invoke_action_trigger":{}}]}

0 commit comments

Comments
 (0)