From 9e073d47771053dc176c3656dc3ff074633b1b8a Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Fri, 8 Dec 2023 12:31:29 +0000 Subject: [PATCH 1/8] Adding ShowOption for JSON handling (#426) --- tfexec/internal/e2etest/cmp.go | 2 +- tfexec/internal/e2etest/show_test.go | 449 +++++++++++++++++++++++++++ tfexec/options.go | 13 + tfexec/show.go | 20 ++ 4 files changed, 483 insertions(+), 1 deletion(-) diff --git a/tfexec/internal/e2etest/cmp.go b/tfexec/internal/e2etest/cmp.go index 15022e5a..4af13351 100644 --- a/tfexec/internal/e2etest/cmp.go +++ b/tfexec/internal/e2etest/cmp.go @@ -21,7 +21,7 @@ func diffState(expected *tfjson.State, actual *tfjson.State) string { // diffPlan returns a human-readable report of the differences between two // plan values. It returns an empty string if the two values are equal. func diffPlan(expected *tfjson.Plan, actual *tfjson.Plan) string { - return cmp.Diff(expected, actual, cmpopts.IgnoreFields(tfjson.Plan{}, "TerraformVersion")) + return cmp.Diff(expected, actual, cmpopts.IgnoreFields(tfjson.Plan{}, "TerraformVersion", "useJSONNumber")) } // diffSchema returns a human-readable report of the differences between two diff --git a/tfexec/internal/e2etest/show_test.go b/tfexec/internal/e2etest/show_test.go index 98bbd8ac..9501ca71 100644 --- a/tfexec/internal/e2etest/show_test.go +++ b/tfexec/internal/e2etest/show_test.go @@ -9,6 +9,7 @@ import ( "errors" "io/ioutil" "os" + "path/filepath" "runtime" "strings" "testing" @@ -764,6 +765,454 @@ func TestShowBigInt(t *testing.T) { }) } +func TestShowFloat64(t *testing.T) { + runTest(t, "bigint", func(t *testing.T, tfv *version.Version, tf *tfexec.Terraform) { + if tfv.LessThan(showMinVersion) { + t.Skip("terraform show was added in Terraform 0.12, so test is not valid") + } + + providerName := "registry.terraform.io/hashicorp/random" + if tfv.LessThan(providerAddressMinVersion) { + providerName = "random" + } + + formatVersion := "0.1" + var sensitiveValues json.RawMessage + + if tfv.Core().GreaterThanOrEqual(v1_0_1) { + formatVersion = "0.2" + sensitiveValues = json.RawMessage([]byte("{}")) + } + if tfv.Core().GreaterThanOrEqual(v1_1) { + formatVersion = "1.0" + } + + expected := &tfjson.State{ + FormatVersion: formatVersion, + // TerraformVersion is ignored to facilitate latest version testing + Values: &tfjson.StateValues{ + RootModule: &tfjson.StateModule{ + Resources: []*tfjson.StateResource{{ + Address: "random_integer.bigint", + AttributeValues: map[string]interface{}{ + "id": "7227701560655103598", + "max": float64(7227701560655103598), + "min": float64(7227701560655103597), + "result": float64(7227701560655103598), + "seed": "12345", + "keepers": nil, + }, + SensitiveValues: sensitiveValues, + Mode: tfjson.ManagedResourceMode, + Type: "random_integer", + Name: "bigint", + ProviderName: providerName, + }}, + }, + }, + } + + err := tf.Init(context.Background()) + if err != nil { + t.Fatalf("error running Init in test directory: %s", err) + } + + err = tf.Apply(context.Background()) + if err != nil { + t.Fatalf("error running Apply in test directory: %s", err) + } + + actual, err := tf.Show(context.Background(), tfexec.JSON(tfexec.JSONConfig{UseJSONNumber: false})) + if err != nil { + t.Fatal(err) + } + + if diff := diffState(expected, actual); diff != "" { + t.Fatalf("mismatch (-want +got):\n%s", diff) + } + }) +} + +func TestShowStateFileBigInt(t *testing.T) { + runTest(t, "bigint", func(t *testing.T, tfv *version.Version, tf *tfexec.Terraform) { + if tfv.LessThan(showMinVersion) { + t.Skip("terraform show was added in Terraform 0.12, so test is not valid") + } + + providerName := "registry.terraform.io/hashicorp/random" + if tfv.LessThan(providerAddressMinVersion) { + providerName = "random" + } + + formatVersion := "0.1" + var sensitiveValues json.RawMessage + + if tfv.Core().GreaterThanOrEqual(v1_0_1) { + formatVersion = "0.2" + sensitiveValues = json.RawMessage([]byte("{}")) + } + if tfv.Core().GreaterThanOrEqual(v1_1) { + formatVersion = "1.0" + } + + expected := &tfjson.State{ + FormatVersion: formatVersion, + // TerraformVersion is ignored to facilitate latest version testing + Values: &tfjson.StateValues{ + RootModule: &tfjson.StateModule{ + Resources: []*tfjson.StateResource{{ + Address: "random_integer.bigint", + AttributeValues: map[string]interface{}{ + "id": "7227701560655103598", + "max": json.Number("7227701560655103598"), + "min": json.Number("7227701560655103597"), + "result": json.Number("7227701560655103598"), + "seed": "12345", + "keepers": nil, + }, + SensitiveValues: sensitiveValues, + Mode: tfjson.ManagedResourceMode, + Type: "random_integer", + Name: "bigint", + ProviderName: providerName, + }}, + }, + }, + } + + err := tf.Init(context.Background()) + if err != nil { + t.Fatalf("error running Init in test directory: %s", err) + } + + err = tf.Apply(context.Background()) + if err != nil { + t.Fatalf("error running Apply in test directory: %s", err) + } + + actual, err := tf.ShowStateFile(context.Background(), filepath.Join(tf.WorkingDir(), "terraform.tfstate")) + if err != nil { + t.Fatal(err) + } + + if diff := diffState(expected, actual); diff != "" { + t.Fatalf("mismatch (-want +got):\n%s", diff) + } + }) +} + +func TestShowStateFileFloat64(t *testing.T) { + runTest(t, "bigint", func(t *testing.T, tfv *version.Version, tf *tfexec.Terraform) { + if tfv.LessThan(showMinVersion) { + t.Skip("terraform show was added in Terraform 0.12, so test is not valid") + } + + providerName := "registry.terraform.io/hashicorp/random" + if tfv.LessThan(providerAddressMinVersion) { + providerName = "random" + } + + formatVersion := "0.1" + var sensitiveValues json.RawMessage + + if tfv.Core().GreaterThanOrEqual(v1_0_1) { + formatVersion = "0.2" + sensitiveValues = json.RawMessage([]byte("{}")) + } + if tfv.Core().GreaterThanOrEqual(v1_1) { + formatVersion = "1.0" + } + + expected := &tfjson.State{ + FormatVersion: formatVersion, + // TerraformVersion is ignored to facilitate latest version testing + Values: &tfjson.StateValues{ + RootModule: &tfjson.StateModule{ + Resources: []*tfjson.StateResource{{ + Address: "random_integer.bigint", + AttributeValues: map[string]interface{}{ + "id": "7227701560655103598", + "max": float64(7227701560655103598), + "min": float64(7227701560655103598), + "result": float64(7227701560655103598), + "seed": "12345", + "keepers": nil, + }, + SensitiveValues: sensitiveValues, + Mode: tfjson.ManagedResourceMode, + Type: "random_integer", + Name: "bigint", + ProviderName: providerName, + }}, + }, + }, + } + + err := tf.Init(context.Background()) + if err != nil { + t.Fatalf("error running Init in test directory: %s", err) + } + + err = tf.Apply(context.Background()) + if err != nil { + t.Fatalf("error running Apply in test directory: %s", err) + } + + actual, err := tf.ShowStateFile(context.Background(), filepath.Join(tf.WorkingDir(), "terraform.tfstate"), tfexec.JSON(tfexec.JSONConfig{UseJSONNumber: false})) + if err != nil { + t.Fatal(err) + } + + if diff := diffState(expected, actual); diff != "" { + t.Fatalf("mismatch (-want +got):\n%s", diff) + } + }) +} + +func TestShowPlanFileBigInt(t *testing.T) { + runTest(t, "bigint", func(t *testing.T, tfv *version.Version, tf *tfexec.Terraform) { + if tfv.LessThan(showMinVersion) { + t.Skip("terraform show was added in Terraform 0.12, so test is not valid") + } + + providerName := "registry.terraform.io/hashicorp/random" + if tfv.LessThan(providerAddressMinVersion) { + providerName = "random" + } + + formatVersion := "0.1" + var sensitiveValues json.RawMessage + + if tfv.Core().GreaterThanOrEqual(v1_0_1) { + formatVersion = "0.2" + sensitiveValues = json.RawMessage([]byte("{}")) + } + if tfv.Core().GreaterThanOrEqual(v1_1) { + formatVersion = "1.0" + } + + expected := &tfjson.Plan{ + FormatVersion: formatVersion, + // TerraformVersion is ignored to facilitate latest version testing + PlannedValues: &tfjson.StateValues{ + RootModule: &tfjson.StateModule{ + Resources: []*tfjson.StateResource{{ + Address: "random_integer.bigint", + AttributeValues: map[string]interface{}{ + "keepers": nil, + "max": json.Number("7227701560655103598"), + "min": json.Number("7227701560655103597"), + "seed": "12345", + }, + SensitiveValues: sensitiveValues, + Mode: tfjson.ManagedResourceMode, + Type: "random_integer", + Name: "bigint", + ProviderName: providerName, + }}, + }, + }, + ResourceChanges: []*tfjson.ResourceChange{{ + Address: "random_integer.bigint", + Mode: tfjson.ManagedResourceMode, + Type: "random_integer", + Name: "bigint", + ProviderName: providerName, + Change: &tfjson.Change{ + Actions: tfjson.Actions{tfjson.ActionCreate}, + After: map[string]interface{}{ + "keepers": nil, + "max": json.Number("7227701560655103598"), + "min": json.Number("7227701560655103597"), + "seed": "12345", + }, + AfterUnknown: map[string]interface{}{ + "id": true, + "result": true, + }, + BeforeSensitive: false, + AfterSensitive: map[string]any{}, + }, + }}, + Config: &tfjson.Config{ + ProviderConfigs: map[string]*tfjson.ProviderConfig{ + "random": { + Name: "random", + VersionConstraint: "3.1.3", + }, + }, + RootModule: &tfjson.ConfigModule{ + Resources: []*tfjson.ConfigResource{{ + Address: "random_integer.bigint", + Mode: tfjson.ManagedResourceMode, + Type: "random_integer", + Name: "bigint", + ProviderConfigKey: "random", + Expressions: map[string]*tfjson.Expression{ + "max": { + ExpressionData: &tfjson.ExpressionData{ + ConstantValue: float64(7227701560655104000), + }, + }, + "min": { + ExpressionData: &tfjson.ExpressionData{ + ConstantValue: float64(7227701560655104000), + }, + }, + "seed": { + ExpressionData: &tfjson.ExpressionData{ + ConstantValue: float64(12345), + }, + }, + }, + }}, + }, + }, + } + + err := tf.Init(context.Background()) + if err != nil { + t.Fatalf("error running Init in test directory: %s", err) + } + + _, err = tf.Plan(context.Background(), tfexec.Out(filepath.Join(tf.WorkingDir(), "tfplan"))) + if err != nil { + t.Fatalf("error running Plan in test directory: %s", err) + } + + actual, err := tf.ShowPlanFile(context.Background(), filepath.Join(tf.WorkingDir(), "tfplan"), tfexec.JSON(tfexec.JSONConfig{UseJSONNumber: true})) + if err != nil { + t.Fatal(err) + } + + if diff := diffPlan(expected, actual); diff != "" { + t.Fatalf("mismatch (-want +got):\n%s", diff) + } + }) +} + +func TestShowPlanFileFloat64(t *testing.T) { + runTest(t, "bigint", func(t *testing.T, tfv *version.Version, tf *tfexec.Terraform) { + if tfv.LessThan(showMinVersion) { + t.Skip("terraform show was added in Terraform 0.12, so test is not valid") + } + + providerName := "registry.terraform.io/hashicorp/random" + if tfv.LessThan(providerAddressMinVersion) { + providerName = "random" + } + + formatVersion := "0.1" + var sensitiveValues json.RawMessage + + if tfv.Core().GreaterThanOrEqual(v1_0_1) { + formatVersion = "0.2" + sensitiveValues = json.RawMessage([]byte("{}")) + } + if tfv.Core().GreaterThanOrEqual(v1_1) { + formatVersion = "1.0" + } + + expected := &tfjson.Plan{ + FormatVersion: formatVersion, + // TerraformVersion is ignored to facilitate latest version testing + PlannedValues: &tfjson.StateValues{ + RootModule: &tfjson.StateModule{ + Resources: []*tfjson.StateResource{{ + Address: "random_integer.bigint", + AttributeValues: map[string]interface{}{ + "keepers": nil, + "max": float64(7227701560655103598), + "min": float64(7227701560655103597), + "seed": "12345", + }, + SensitiveValues: sensitiveValues, + Mode: tfjson.ManagedResourceMode, + Type: "random_integer", + Name: "bigint", + ProviderName: providerName, + }}, + }, + }, + ResourceChanges: []*tfjson.ResourceChange{{ + Address: "random_integer.bigint", + Mode: tfjson.ManagedResourceMode, + Type: "random_integer", + Name: "bigint", + ProviderName: providerName, + Change: &tfjson.Change{ + Actions: tfjson.Actions{tfjson.ActionCreate}, + After: map[string]interface{}{ + "keepers": nil, + "max": float64(7227701560655103598), + "min": float64(7227701560655103597), + "seed": "12345", + }, + AfterUnknown: map[string]interface{}{ + "id": true, + "result": true, + }, + BeforeSensitive: false, + AfterSensitive: map[string]any{}, + }, + }}, + Config: &tfjson.Config{ + ProviderConfigs: map[string]*tfjson.ProviderConfig{ + "random": { + Name: "random", + VersionConstraint: "3.1.3", + }, + }, + RootModule: &tfjson.ConfigModule{ + Resources: []*tfjson.ConfigResource{{ + Address: "random_integer.bigint", + Mode: tfjson.ManagedResourceMode, + Type: "random_integer", + Name: "bigint", + ProviderConfigKey: "random", + Expressions: map[string]*tfjson.Expression{ + "max": { + ExpressionData: &tfjson.ExpressionData{ + ConstantValue: float64(7227701560655104000), + }, + }, + "min": { + ExpressionData: &tfjson.ExpressionData{ + ConstantValue: float64(7227701560655104000), + }, + }, + "seed": { + ExpressionData: &tfjson.ExpressionData{ + ConstantValue: float64(12345), + }, + }, + }, + }}, + }, + }, + } + + err := tf.Init(context.Background()) + if err != nil { + t.Fatalf("error running Init in test directory: %s", err) + } + + _, err = tf.Plan(context.Background(), tfexec.Out(filepath.Join(tf.WorkingDir(), "tfplan"))) + if err != nil { + t.Fatalf("error running Plan in test directory: %s", err) + } + + actual, err := tf.ShowPlanFile(context.Background(), filepath.Join(tf.WorkingDir(), "tfplan")) + if err != nil { + t.Fatal(err) + } + + if diff := diffPlan(expected, actual); diff != "" { + t.Fatalf("mismatch (-want +got):\n%s", diff) + } + }) +} + // Since our plan strings are not large, prefer simple cross-platform // normalization handling over pulling in a dependency. func normalizePlanOutput(str string) string { diff --git a/tfexec/options.go b/tfexec/options.go index 5f04680b..b604f00a 100644 --- a/tfexec/options.go +++ b/tfexec/options.go @@ -243,6 +243,19 @@ func GraphPlan(file string) *GraphPlanOption { return &GraphPlanOption{file} } +// JSONConfig holds information which determines how JSON is decoded. +type JSONConfig struct { + UseJSONNumber bool +} + +type JSONOption struct { + config JSONConfig +} + +func JSON(config JSONConfig) *JSONOption { + return &JSONOption{config} +} + type PlatformOption struct { platform string } diff --git a/tfexec/show.go b/tfexec/show.go index 8bf0779f..9c944844 100644 --- a/tfexec/show.go +++ b/tfexec/show.go @@ -14,6 +14,7 @@ import ( type showConfig struct { reattachInfo ReattachInfo + jsonConfig *JSONConfig } var defaultShowOptions = showConfig{} @@ -22,6 +23,10 @@ type ShowOption interface { configureShow(*showConfig) } +func (opt *JSONOption) configureShow(conf *showConfig) { + conf.jsonConfig = &opt.config +} + func (opt *ReattachOption) configureShow(conf *showConfig) { conf.reattachInfo = opt.info } @@ -53,6 +58,11 @@ func (tf *Terraform) Show(ctx context.Context, opts ...ShowOption) (*tfjson.Stat var ret tfjson.State ret.UseJSONNumber(true) + + if c.jsonConfig != nil { + ret.UseJSONNumber(c.jsonConfig.UseJSONNumber) + } + err = tf.runTerraformCmdJSON(ctx, showCmd, &ret) if err != nil { return nil, err @@ -96,6 +106,11 @@ func (tf *Terraform) ShowStateFile(ctx context.Context, statePath string, opts . var ret tfjson.State ret.UseJSONNumber(true) + + if c.jsonConfig != nil { + ret.UseJSONNumber(c.jsonConfig.UseJSONNumber) + } + err = tf.runTerraformCmdJSON(ctx, showCmd, &ret) if err != nil { return nil, err @@ -138,6 +153,11 @@ func (tf *Terraform) ShowPlanFile(ctx context.Context, planPath string, opts ... showCmd := tf.showCmd(ctx, true, mergeEnv, planPath) var ret tfjson.Plan + + if c.jsonConfig != nil { + ret.UseJSONNumber(c.jsonConfig.UseJSONNumber) + } + err = tf.runTerraformCmdJSON(ctx, showCmd, &ret) if err != nil { return nil, err From d1eee8e3f11e1892926a935f7b6349199fc85140 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Fri, 8 Dec 2023 12:32:08 +0000 Subject: [PATCH 2/8] Temporarily pointing at terraform-json PR for dependent changes (#426) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 09c998c5..39266248 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/google/go-cmp v0.6.0 github.com/hashicorp/go-version v1.6.0 github.com/hashicorp/hc-install v0.6.2 - github.com/hashicorp/terraform-json v0.18.0 + github.com/hashicorp/terraform-json v0.18.1-0.20231207151239-da9b6fa7714c github.com/zclconf/go-cty v1.14.1 github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b ) diff --git a/go.sum b/go.sum index 276244a4..b2b77e36 100644 --- a/go.sum +++ b/go.sum @@ -41,8 +41,8 @@ github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mO github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/hc-install v0.6.2 h1:V1k+Vraqz4olgZ9UzKiAcbman9i9scg9GgSt/U3mw/M= github.com/hashicorp/hc-install v0.6.2/go.mod h1:2JBpd+NCFKiHiu/yYCGaPyPHhZLxXTpz8oreHa/a3Ps= -github.com/hashicorp/terraform-json v0.18.0 h1:pCjgJEqqDESv4y0Tzdqfxr/edOIGkjs8keY42xfNBwU= -github.com/hashicorp/terraform-json v0.18.0/go.mod h1:qdeBs11ovMzo5puhrRibdD6d2Dq6TyE/28JiU4tIQxk= +github.com/hashicorp/terraform-json v0.18.1-0.20231207151239-da9b6fa7714c h1:BjxlDdtxdtm5AdJjYEQGdkJ05534/zFNSwFsCG20KcE= +github.com/hashicorp/terraform-json v0.18.1-0.20231207151239-da9b6fa7714c/go.mod h1:qdeBs11ovMzo5puhrRibdD6d2Dq6TyE/28JiU4tIQxk= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= From 309258fafae9376e07ad831fa10524588f349a52 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Fri, 8 Dec 2023 18:30:00 +0000 Subject: [PATCH 3/8] Ignoring fields that differ between TF versions (#426) --- tfexec/internal/e2etest/cmp.go | 6 +++-- tfexec/internal/e2etest/show_test.go | 39 ++++++++++++++-------------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/tfexec/internal/e2etest/cmp.go b/tfexec/internal/e2etest/cmp.go index 4af13351..d1d84e6a 100644 --- a/tfexec/internal/e2etest/cmp.go +++ b/tfexec/internal/e2etest/cmp.go @@ -20,8 +20,10 @@ func diffState(expected *tfjson.State, actual *tfjson.State) string { // diffPlan returns a human-readable report of the differences between two // plan values. It returns an empty string if the two values are equal. -func diffPlan(expected *tfjson.Plan, actual *tfjson.Plan) string { - return cmp.Diff(expected, actual, cmpopts.IgnoreFields(tfjson.Plan{}, "TerraformVersion", "useJSONNumber")) +func diffPlan(expected *tfjson.Plan, actual *tfjson.Plan, opts ...cmp.Option) string { + opts = append(opts, cmpopts.IgnoreFields(tfjson.Plan{}, "TerraformVersion", "useJSONNumber")) + + return cmp.Diff(expected, actual, opts...) } // diffSchema returns a human-readable report of the differences between two diff --git a/tfexec/internal/e2etest/show_test.go b/tfexec/internal/e2etest/show_test.go index 9501ca71..8b94d147 100644 --- a/tfexec/internal/e2etest/show_test.go +++ b/tfexec/internal/e2etest/show_test.go @@ -15,6 +15,7 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" "github.com/hashicorp/go-version" tfjson "github.com/hashicorp/terraform-json" @@ -980,19 +981,15 @@ func TestShowPlanFileBigInt(t *testing.T) { providerName = "random" } - formatVersion := "0.1" var sensitiveValues json.RawMessage if tfv.Core().GreaterThanOrEqual(v1_0_1) { - formatVersion = "0.2" sensitiveValues = json.RawMessage([]byte("{}")) } if tfv.Core().GreaterThanOrEqual(v1_1) { - formatVersion = "1.0" } expected := &tfjson.Plan{ - FormatVersion: formatVersion, // TerraformVersion is ignored to facilitate latest version testing PlannedValues: &tfjson.StateValues{ RootModule: &tfjson.StateModule{ @@ -1030,17 +1027,9 @@ func TestShowPlanFileBigInt(t *testing.T) { "id": true, "result": true, }, - BeforeSensitive: false, - AfterSensitive: map[string]any{}, }, }}, Config: &tfjson.Config{ - ProviderConfigs: map[string]*tfjson.ProviderConfig{ - "random": { - Name: "random", - VersionConstraint: "3.1.3", - }, - }, RootModule: &tfjson.ConfigModule{ Resources: []*tfjson.ConfigResource{{ Address: "random_integer.bigint", @@ -1085,7 +1074,15 @@ func TestShowPlanFileBigInt(t *testing.T) { t.Fatal(err) } - if diff := diffPlan(expected, actual); diff != "" { + opts := []cmp.Option{ + cmpopts.IgnoreFields(tfjson.Change{}, "BeforeSensitive"), + cmpopts.IgnoreFields(tfjson.Change{}, "AfterSensitive"), + cmpopts.IgnoreFields(tfjson.Config{}, "ProviderConfigs"), + cmpopts.IgnoreFields(tfjson.Plan{}, "FormatVersion"), + cmpopts.IgnoreFields(tfjson.Plan{}, "Timestamp"), + } + + if diff := diffPlan(expected, actual, opts...); diff != "" { t.Fatalf("mismatch (-want +got):\n%s", diff) } }) @@ -1102,19 +1099,15 @@ func TestShowPlanFileFloat64(t *testing.T) { providerName = "random" } - formatVersion := "0.1" var sensitiveValues json.RawMessage if tfv.Core().GreaterThanOrEqual(v1_0_1) { - formatVersion = "0.2" sensitiveValues = json.RawMessage([]byte("{}")) } if tfv.Core().GreaterThanOrEqual(v1_1) { - formatVersion = "1.0" } expected := &tfjson.Plan{ - FormatVersion: formatVersion, // TerraformVersion is ignored to facilitate latest version testing PlannedValues: &tfjson.StateValues{ RootModule: &tfjson.StateModule{ @@ -1152,8 +1145,6 @@ func TestShowPlanFileFloat64(t *testing.T) { "id": true, "result": true, }, - BeforeSensitive: false, - AfterSensitive: map[string]any{}, }, }}, Config: &tfjson.Config{ @@ -1207,7 +1198,15 @@ func TestShowPlanFileFloat64(t *testing.T) { t.Fatal(err) } - if diff := diffPlan(expected, actual); diff != "" { + opts := []cmp.Option{ + cmpopts.IgnoreFields(tfjson.Change{}, "BeforeSensitive"), + cmpopts.IgnoreFields(tfjson.Change{}, "AfterSensitive"), + cmpopts.IgnoreFields(tfjson.Config{}, "ProviderConfigs"), + cmpopts.IgnoreFields(tfjson.Plan{}, "FormatVersion"), + cmpopts.IgnoreFields(tfjson.Plan{}, "Timestamp"), + } + + if diff := diffPlan(expected, actual, opts...); diff != "" { t.Fatalf("mismatch (-want +got):\n%s", diff) } }) From d64e88de1a54cda0804393c6ca280693b47c1aba Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 14 Dec 2023 14:03:13 +0000 Subject: [PATCH 4/8] Rename structs and func (#426) --- tfexec/internal/e2etest/show_test.go | 6 +++--- tfexec/options.go | 12 ++++++------ tfexec/show.go | 6 +++--- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/tfexec/internal/e2etest/show_test.go b/tfexec/internal/e2etest/show_test.go index 8b94d147..5773cc51 100644 --- a/tfexec/internal/e2etest/show_test.go +++ b/tfexec/internal/e2etest/show_test.go @@ -823,7 +823,7 @@ func TestShowFloat64(t *testing.T) { t.Fatalf("error running Apply in test directory: %s", err) } - actual, err := tf.Show(context.Background(), tfexec.JSON(tfexec.JSONConfig{UseJSONNumber: false})) + actual, err := tf.Show(context.Background(), tfexec.JSONNumber(tfexec.UseJSONNumber{UseJSONNumber: false})) if err != nil { t.Fatal(err) } @@ -959,7 +959,7 @@ func TestShowStateFileFloat64(t *testing.T) { t.Fatalf("error running Apply in test directory: %s", err) } - actual, err := tf.ShowStateFile(context.Background(), filepath.Join(tf.WorkingDir(), "terraform.tfstate"), tfexec.JSON(tfexec.JSONConfig{UseJSONNumber: false})) + actual, err := tf.ShowStateFile(context.Background(), filepath.Join(tf.WorkingDir(), "terraform.tfstate"), tfexec.JSONNumber(tfexec.UseJSONNumber{UseJSONNumber: false})) if err != nil { t.Fatal(err) } @@ -1069,7 +1069,7 @@ func TestShowPlanFileBigInt(t *testing.T) { t.Fatalf("error running Plan in test directory: %s", err) } - actual, err := tf.ShowPlanFile(context.Background(), filepath.Join(tf.WorkingDir(), "tfplan"), tfexec.JSON(tfexec.JSONConfig{UseJSONNumber: true})) + actual, err := tf.ShowPlanFile(context.Background(), filepath.Join(tf.WorkingDir(), "tfplan"), tfexec.JSONNumber(tfexec.UseJSONNumber{UseJSONNumber: true})) if err != nil { t.Fatal(err) } diff --git a/tfexec/options.go b/tfexec/options.go index b604f00a..058e37b5 100644 --- a/tfexec/options.go +++ b/tfexec/options.go @@ -243,17 +243,17 @@ func GraphPlan(file string) *GraphPlanOption { return &GraphPlanOption{file} } -// JSONConfig holds information which determines how JSON is decoded. -type JSONConfig struct { +// UseJSONNumber determines how numerical values are handled when JSON is decoded. +type UseJSONNumber struct { UseJSONNumber bool } -type JSONOption struct { - config JSONConfig +type UseJSONNumberOption struct { + useJSONNumber UseJSONNumber } -func JSON(config JSONConfig) *JSONOption { - return &JSONOption{config} +func JSONNumber(config UseJSONNumber) *UseJSONNumberOption { + return &UseJSONNumberOption{config} } type PlatformOption struct { diff --git a/tfexec/show.go b/tfexec/show.go index 9c944844..1680c580 100644 --- a/tfexec/show.go +++ b/tfexec/show.go @@ -14,7 +14,7 @@ import ( type showConfig struct { reattachInfo ReattachInfo - jsonConfig *JSONConfig + jsonConfig *UseJSONNumber } var defaultShowOptions = showConfig{} @@ -23,8 +23,8 @@ type ShowOption interface { configureShow(*showConfig) } -func (opt *JSONOption) configureShow(conf *showConfig) { - conf.jsonConfig = &opt.config +func (opt *UseJSONNumberOption) configureShow(conf *showConfig) { + conf.jsonConfig = &opt.useJSONNumber } func (opt *ReattachOption) configureShow(conf *showConfig) { From ddc87e4ed943bf258d837823cffddea1c3f7c14f Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Thu, 14 Dec 2023 14:37:14 +0000 Subject: [PATCH 5/8] Removing redundant struct (#426) --- tfexec/internal/e2etest/show_test.go | 6 +++--- tfexec/options.go | 12 ++++-------- tfexec/show.go | 22 +++++++++++----------- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/tfexec/internal/e2etest/show_test.go b/tfexec/internal/e2etest/show_test.go index 5773cc51..c81d9793 100644 --- a/tfexec/internal/e2etest/show_test.go +++ b/tfexec/internal/e2etest/show_test.go @@ -823,7 +823,7 @@ func TestShowFloat64(t *testing.T) { t.Fatalf("error running Apply in test directory: %s", err) } - actual, err := tf.Show(context.Background(), tfexec.JSONNumber(tfexec.UseJSONNumber{UseJSONNumber: false})) + actual, err := tf.Show(context.Background(), tfexec.JSONNumber(false)) if err != nil { t.Fatal(err) } @@ -959,7 +959,7 @@ func TestShowStateFileFloat64(t *testing.T) { t.Fatalf("error running Apply in test directory: %s", err) } - actual, err := tf.ShowStateFile(context.Background(), filepath.Join(tf.WorkingDir(), "terraform.tfstate"), tfexec.JSONNumber(tfexec.UseJSONNumber{UseJSONNumber: false})) + actual, err := tf.ShowStateFile(context.Background(), filepath.Join(tf.WorkingDir(), "terraform.tfstate"), tfexec.JSONNumber(false)) if err != nil { t.Fatal(err) } @@ -1069,7 +1069,7 @@ func TestShowPlanFileBigInt(t *testing.T) { t.Fatalf("error running Plan in test directory: %s", err) } - actual, err := tf.ShowPlanFile(context.Background(), filepath.Join(tf.WorkingDir(), "tfplan"), tfexec.JSONNumber(tfexec.UseJSONNumber{UseJSONNumber: true})) + actual, err := tf.ShowPlanFile(context.Background(), filepath.Join(tf.WorkingDir(), "tfplan"), tfexec.JSONNumber(true)) if err != nil { t.Fatal(err) } diff --git a/tfexec/options.go b/tfexec/options.go index 058e37b5..66a276bd 100644 --- a/tfexec/options.go +++ b/tfexec/options.go @@ -243,17 +243,13 @@ func GraphPlan(file string) *GraphPlanOption { return &GraphPlanOption{file} } -// UseJSONNumber determines how numerical values are handled when JSON is decoded. type UseJSONNumber struct { - UseJSONNumber bool + useJSONNumber bool } -type UseJSONNumberOption struct { - useJSONNumber UseJSONNumber -} - -func JSONNumber(config UseJSONNumber) *UseJSONNumberOption { - return &UseJSONNumberOption{config} +// JSONNumber determines how numerical values are handled during JSON decoding. +func JSONNumber(useJSONNumber bool) *UseJSONNumber { + return &UseJSONNumber{useJSONNumber} } type PlatformOption struct { diff --git a/tfexec/show.go b/tfexec/show.go index 1680c580..f7548e5e 100644 --- a/tfexec/show.go +++ b/tfexec/show.go @@ -14,7 +14,7 @@ import ( type showConfig struct { reattachInfo ReattachInfo - jsonConfig *UseJSONNumber + jsonNumber *UseJSONNumber } var defaultShowOptions = showConfig{} @@ -23,14 +23,14 @@ type ShowOption interface { configureShow(*showConfig) } -func (opt *UseJSONNumberOption) configureShow(conf *showConfig) { - conf.jsonConfig = &opt.useJSONNumber -} - func (opt *ReattachOption) configureShow(conf *showConfig) { conf.reattachInfo = opt.info } +func (opt *UseJSONNumber) configureShow(conf *showConfig) { + conf.jsonNumber = opt +} + // Show reads the default state path and outputs the state. // To read a state or plan file, ShowState or ShowPlan must be used instead. func (tf *Terraform) Show(ctx context.Context, opts ...ShowOption) (*tfjson.State, error) { @@ -59,8 +59,8 @@ func (tf *Terraform) Show(ctx context.Context, opts ...ShowOption) (*tfjson.Stat var ret tfjson.State ret.UseJSONNumber(true) - if c.jsonConfig != nil { - ret.UseJSONNumber(c.jsonConfig.UseJSONNumber) + if c.jsonNumber != nil { + ret.UseJSONNumber(c.jsonNumber.useJSONNumber) } err = tf.runTerraformCmdJSON(ctx, showCmd, &ret) @@ -107,8 +107,8 @@ func (tf *Terraform) ShowStateFile(ctx context.Context, statePath string, opts . var ret tfjson.State ret.UseJSONNumber(true) - if c.jsonConfig != nil { - ret.UseJSONNumber(c.jsonConfig.UseJSONNumber) + if c.jsonNumber != nil { + ret.UseJSONNumber(c.jsonNumber.useJSONNumber) } err = tf.runTerraformCmdJSON(ctx, showCmd, &ret) @@ -154,8 +154,8 @@ func (tf *Terraform) ShowPlanFile(ctx context.Context, planPath string, opts ... var ret tfjson.Plan - if c.jsonConfig != nil { - ret.UseJSONNumber(c.jsonConfig.UseJSONNumber) + if c.jsonNumber != nil { + ret.UseJSONNumber(c.jsonNumber.useJSONNumber) } err = tf.runTerraformCmdJSON(ctx, showCmd, &ret) From ad07ae8d270b7e2e437b3bdf2bb28a0cae70ab1c Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Mon, 18 Dec 2023 16:44:16 +0000 Subject: [PATCH 6/8] Update tfexec/options.go Co-authored-by: kmoe <5575356+kmoe@users.noreply.github.com> --- tfexec/options.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tfexec/options.go b/tfexec/options.go index 66a276bd..7c2f6fda 100644 --- a/tfexec/options.go +++ b/tfexec/options.go @@ -243,7 +243,7 @@ func GraphPlan(file string) *GraphPlanOption { return &GraphPlanOption{file} } -type UseJSONNumber struct { +type UseJSONNumberOption struct { useJSONNumber bool } From 85ec0154bcc24803edb3093edac26b7a88a6b74e Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Mon, 18 Dec 2023 16:46:15 +0000 Subject: [PATCH 7/8] Updating to use renamed struct (#426) --- tfexec/options.go | 4 ++-- tfexec/show.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tfexec/options.go b/tfexec/options.go index 7c2f6fda..d783027a 100644 --- a/tfexec/options.go +++ b/tfexec/options.go @@ -248,8 +248,8 @@ type UseJSONNumberOption struct { } // JSONNumber determines how numerical values are handled during JSON decoding. -func JSONNumber(useJSONNumber bool) *UseJSONNumber { - return &UseJSONNumber{useJSONNumber} +func JSONNumber(useJSONNumber bool) *UseJSONNumberOption { + return &UseJSONNumberOption{useJSONNumber} } type PlatformOption struct { diff --git a/tfexec/show.go b/tfexec/show.go index f7548e5e..5854af1d 100644 --- a/tfexec/show.go +++ b/tfexec/show.go @@ -14,7 +14,7 @@ import ( type showConfig struct { reattachInfo ReattachInfo - jsonNumber *UseJSONNumber + jsonNumber *UseJSONNumberOption } var defaultShowOptions = showConfig{} @@ -27,7 +27,7 @@ func (opt *ReattachOption) configureShow(conf *showConfig) { conf.reattachInfo = opt.info } -func (opt *UseJSONNumber) configureShow(conf *showConfig) { +func (opt *UseJSONNumberOption) configureShow(conf *showConfig) { conf.jsonNumber = opt } From 513872d324e62abe037a3070519eecedc01d54b3 Mon Sep 17 00:00:00 2001 From: Benjamin Bennett Date: Wed, 20 Dec 2023 10:56:30 +0000 Subject: [PATCH 8/8] Bumping terraform-json to v0.19.0 (#426) --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 39266248..c12826ac 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/google/go-cmp v0.6.0 github.com/hashicorp/go-version v1.6.0 github.com/hashicorp/hc-install v0.6.2 - github.com/hashicorp/terraform-json v0.18.1-0.20231207151239-da9b6fa7714c + github.com/hashicorp/terraform-json v0.19.0 github.com/zclconf/go-cty v1.14.1 github.com/zclconf/go-cty-debug v0.0.0-20191215020915-b22d67c1ba0b ) diff --git a/go.sum b/go.sum index b2b77e36..642966c4 100644 --- a/go.sum +++ b/go.sum @@ -41,8 +41,8 @@ github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mO github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/hc-install v0.6.2 h1:V1k+Vraqz4olgZ9UzKiAcbman9i9scg9GgSt/U3mw/M= github.com/hashicorp/hc-install v0.6.2/go.mod h1:2JBpd+NCFKiHiu/yYCGaPyPHhZLxXTpz8oreHa/a3Ps= -github.com/hashicorp/terraform-json v0.18.1-0.20231207151239-da9b6fa7714c h1:BjxlDdtxdtm5AdJjYEQGdkJ05534/zFNSwFsCG20KcE= -github.com/hashicorp/terraform-json v0.18.1-0.20231207151239-da9b6fa7714c/go.mod h1:qdeBs11ovMzo5puhrRibdD6d2Dq6TyE/28JiU4tIQxk= +github.com/hashicorp/terraform-json v0.19.0 h1:e9DBKC5sxDfiJT7Zoi+yRIwqLVtFur/fwK/FuE6AWsA= +github.com/hashicorp/terraform-json v0.19.0/go.mod h1:qdeBs11ovMzo5puhrRibdD6d2Dq6TyE/28JiU4tIQxk= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=