Skip to content

Commit

Permalink
feat: support known after apply
Browse files Browse the repository at this point in the history
  • Loading branch information
takaishi committed Jul 27, 2023
1 parent b719045 commit 6be1ede
Show file tree
Hide file tree
Showing 8 changed files with 473 additions and 2 deletions.
34 changes: 34 additions & 0 deletions internal/format/format_unknown.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package format

import (
"errors"
tfjson "github.com/hashicorp/terraform-json"
)

func FormatUnknownPlan(plan *tfjson.Plan) (*tfjson.Plan, error) {
var err error
if plan == nil {
return nil, errors.New("nil plan supplied")
}

for i := range plan.ResourceChanges {
plan.ResourceChanges[i].Change, err = formatUnknownChange(plan.ResourceChanges[i].Change)
if err != nil {
return nil, err
}
}

return plan, nil
}

func formatUnknownChange(change *tfjson.Change) (*tfjson.Change, error) {
if change.Actions.Update() {
for k, v := range change.AfterUnknown.(map[string]interface{}) {
switch v.(type) {
case bool:
change.After.(map[string]interface{})[k] = "(known after apply)"
}
}
}
return change, nil
}
12 changes: 10 additions & 2 deletions internal/terraform/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ func (r ResourceChangeData) GetUnifiedDiffString() (string, error) {
if err != nil {
return "", fmt.Errorf("failed to create diff: %w", err)
}

return diffText, nil
}

Expand Down Expand Up @@ -145,20 +144,29 @@ func (plan *PlanData) Render(w io.Writer, escapeHTML bool) error {
}

func NewPlanData(input io.Reader) (*PlanData, error) {
var err error
var plan tfjson.Plan
if err := json.NewDecoder(input).Decode(&plan); err != nil {
return nil, fmt.Errorf("cannot parse input: %w", err)
}

sanitizedPlan, err := sanitize.SanitizePlan(&plan)
if err != nil {
return nil, fmt.Errorf("failed to sanitize plan: %w", err)
}

formattedJsonPlan, err := format.FormatJsonPlan(sanitizedPlan)
if err != nil {
return nil, fmt.Errorf("failed to prettify plan: %w", err)
}

formattedUnknownPlan, err := format.FormatUnknownPlan(formattedJsonPlan)
if err != nil {
return nil, fmt.Errorf("failed to prettify plan: %w", err)
}

planData := PlanData{}
for _, c := range formattedJsonPlan.ResourceChanges {
for _, c := range formattedUnknownPlan.ResourceChanges {
if c.Change.Actions.NoOp() || c.Change.Actions.Read() {
continue
}
Expand Down
73 changes: 73 additions & 0 deletions test/format_json_test/format_unknown_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package format_json_test

import (
tfjson "github.com/hashicorp/terraform-json"
"github.com/reproio/terraform-j2md/internal/format"
"reflect"
"testing"
)

func TestFormatUnknownPlan(t *testing.T) {
type args struct {
old *tfjson.Plan
}
tests := []struct {
name string
args args
want *tfjson.Plan
wantErr bool
}{
{
name: "plain string",
args: args{
old: &tfjson.Plan{
ResourceChanges: []*tfjson.ResourceChange{
{
Change: &tfjson.Change{
Actions: tfjson.Actions{tfjson.ActionUpdate},
Before: map[string]interface{}{
"foo": "bar",
},
After: map[string]interface{}{},
AfterUnknown: map[string]interface{}{
"foo": true,
},
},
},
},
},
},
want: &tfjson.Plan{
ResourceChanges: []*tfjson.ResourceChange{
{
Change: &tfjson.Change{
Actions: tfjson.Actions{tfjson.ActionUpdate},
Before: map[string]interface{}{
"foo": "bar",
},
After: map[string]interface{}{
"foo": "(known after apply)",
},
AfterUnknown: map[string]interface{}{
"foo": true,
},
},
},
},
},
wantErr: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := format.FormatUnknownPlan(tt.args.old)
if (err != nil) != tt.wantErr {
t.Errorf("FormatJsonPlan() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("FormatJsonPlan() got = \n%v\n, want \n%v", got.ResourceChanges[0].Change.After, tt.want.ResourceChanges[0].Change.After)
}
})
}
}
1 change: 1 addition & 0 deletions test/plan_test/plan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ func Test_render(t *testing.T) {
{name: "iam_policy", wantErr: false},
{name: "include_code_fence", wantErr: false},
{name: "include_module", wantErr: false},
{name: "known_after_apply", wantErr: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
51 changes: 51 additions & 0 deletions test/testdata/known_after_apply/expected.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
### 1 to add, 1 to change, 1 to destroy, 0 to replace.
- add
- random_id.test2
- change
- env_variable.test
- destroy
- random_id.test
<details><summary>Change details</summary>

````````diff
# env_variable.test will be updated in-place
@@ -1,6 +1,6 @@
{
"id": "07ec30c9d869e0f6392f",
- "name": "07ec30c9d869e0f6392f",
+ "name": "(known after apply)",
"value": "REDACTED_SENSITIVE"
}

````````

````````diff
# random_id.test will be destroyed
@@ -1,11 +1,2 @@
-{
- "b64_std": "B+wwydhp4PY5Lw==",
- "b64_url": "B-wwydhp4PY5Lw",
- "byte_length": 10,
- "dec": "37413512560416367458607",
- "hex": "07ec30c9d869e0f6392f",
- "id": "B-wwydhp4PY5Lw",
- "keepers": null,
- "prefix": null
-}
+null

````````

````````diff
# random_id.test2 will be created
@@ -1,2 +1,6 @@
-null
+{
+ "byte_length": 10,
+ "keepers": null,
+ "prefix": null
+}

````````

</details>
24 changes: 24 additions & 0 deletions test/testdata/known_after_apply/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
terraform {
required_providers {
env = {
source = "tchupp/env"
version = "0.0.2"
}
}
}

provider "env" {
# Configuration options
}

resource "env_variable" "test" {
name = random_id.test2.hex
}

#resource "random_id" "test" {
# byte_length = 10
#}

resource "random_id" "test2" {
byte_length = 10
}
Loading

0 comments on commit 6be1ede

Please sign in to comment.