From 8aa029c80c6ef8ae4e376bb27eaf0663613116f6 Mon Sep 17 00:00:00 2001 From: magodo Date: Thu, 12 Aug 2021 15:48:02 +0800 Subject: [PATCH 1/4] add supports for cmd: terraform add --- tfexec/add.go | 88 +++++++++++++++++++++++++++++ tfexec/add_test.go | 56 ++++++++++++++++++ tfexec/internal/testutil/tfcache.go | 13 +++-- tfexec/options.go | 18 ++++++ tfexec/version.go | 1 + 5 files changed, 170 insertions(+), 6 deletions(-) create mode 100644 tfexec/add.go create mode 100644 tfexec/add_test.go diff --git a/tfexec/add.go b/tfexec/add.go new file mode 100644 index 00000000..d8aeeadf --- /dev/null +++ b/tfexec/add.go @@ -0,0 +1,88 @@ +package tfexec + +import ( + "context" + "fmt" + "os/exec" + "strconv" +) + +type addConfig struct { + fromState bool + out string + includeOptional bool + provider string + reattachInfo ReattachInfo +} + +var defaultAddOptions = addConfig{} + +type AddOption interface { + configureAdd(*addConfig) +} + +func (opt *FromStateOption) configureAdd(conf *addConfig) { + conf.fromState = opt.fromState +} + +func (opt *OutOption) configureAdd(conf *addConfig) { + conf.out = opt.path +} + +func (opt *IncludeOptionalOption) configureAdd(conf *addConfig) { + conf.includeOptional = opt.includeOptional +} + +func (opt *ProviderOption) configureAdd(conf *addConfig) { + conf.provider = opt.provider +} + +func (opt *ReattachOption) configureAdd(conf *addConfig) { + conf.reattachInfo = opt.info +} + +// Add represents the terraform add subcommand. +func (tf *Terraform) Add(ctx context.Context, address string, opts ...AddOption) error { + cmd, err := tf.addCmd(ctx, address, opts...) + if err != nil { + return err + } + return tf.runTerraformCmd(ctx, cmd) +} + +func (tf *Terraform) addCmd(ctx context.Context, address string, opts ...AddOption) (*exec.Cmd, error) { + err := tf.compatible(ctx, tf1_1_0, nil) + if err != nil { + return nil, fmt.Errorf("terraform add was added in 1.1.0: %w", err) + } + + c := defaultAddOptions + + for _, o := range opts { + o.configureAdd(&c) + } + + args := []string{"add"} + + args = append(args, "-from-state="+strconv.FormatBool(c.fromState)) + if c.out != "" { + args = append(args, "-out="+c.out) + } + args = append(args, "-optional="+strconv.FormatBool(c.includeOptional)) + if c.provider != "" { + args = append(args, "-provider="+c.provider) + } + + args = append(args, address) + + mergeEnv := map[string]string{} + if c.reattachInfo != nil { + reattachStr, err := c.reattachInfo.marshalString() + if err != nil { + return nil, err + } + mergeEnv[reattachEnvVar] = reattachStr + } + + return tf.buildTerraformCmd(ctx, mergeEnv, args...), nil +} diff --git a/tfexec/add_test.go b/tfexec/add_test.go new file mode 100644 index 00000000..55f10e28 --- /dev/null +++ b/tfexec/add_test.go @@ -0,0 +1,56 @@ +package tfexec + +import ( + "context" + "testing" + + "github.com/hashicorp/terraform-exec/tfexec/internal/testutil" +) + +func TestAddCmd(t *testing.T) { + td := testTempDir(t) + + tf, err := NewTerraform(td, tfVersion(t, testutil.Latest_v1_1_alpha)) + if err != nil { + t.Fatal(err) + } + + // empty env, to avoid environ mismatch in testing + tf.SetEnv(map[string]string{}) + + t.Run("default", func(t *testing.T) { + addCmd, err := tf.addCmd(context.Background(), "my-addr") + if err != nil { + t.Fatal(err) + } + + assertCmd(t, []string{ + "add", + "-from-state=false", + "-optional=false", + "my-addr", + }, nil, addCmd) + }) + + t.Run("override-default", func(t *testing.T) { + addCmd, err := tf.addCmd(context.Background(), + "my-addr", + FromState(true), + Out("out"), + IncludeOptional(true), + Provider("my-provider"), + ) + if err != nil { + t.Fatal(err) + } + + assertCmd(t, []string{ + "add", + "-from-state=true", + "-out=out", + "-optional=true", + "-provider=my-provider", + "my-addr", + }, nil, addCmd) + }) +} diff --git a/tfexec/internal/testutil/tfcache.go b/tfexec/internal/testutil/tfcache.go index 4f3bcd3a..114f0560 100644 --- a/tfexec/internal/testutil/tfcache.go +++ b/tfexec/internal/testutil/tfcache.go @@ -9,12 +9,13 @@ import ( ) const ( - Latest011 = "0.11.15" - Latest012 = "0.12.31" - Latest013 = "0.13.7" - Latest014 = "0.14.11" - Latest015 = "0.15.5" - Latest_v1 = "1.0.0" + Latest011 = "0.11.15" + Latest012 = "0.12.31" + Latest013 = "0.13.7" + Latest014 = "0.14.11" + Latest015 = "0.15.5" + Latest_v1 = "1.0.0" + Latest_v1_1_alpha = "1.1.0-alpha20210811" ) const appendUserAgent = "tfexec-testutil" diff --git a/tfexec/options.go b/tfexec/options.go index 74fd96a0..4d573efd 100644 --- a/tfexec/options.go +++ b/tfexec/options.go @@ -365,3 +365,21 @@ type VerifyPluginsOption struct { func VerifyPlugins(verifyPlugins bool) *VerifyPluginsOption { return &VerifyPluginsOption{verifyPlugins} } + +// FromStateOption represents the -from-state option of the "terraform add" command. +type FromStateOption struct { + fromState bool +} + +func FromState(fromState bool) *FromStateOption { + return &FromStateOption{fromState} +} + +// IncludeOptionalOption represents the -optional option of the "terraform add" command. +type IncludeOptionalOption struct { + includeOptional bool +} + +func IncludeOptional(includeOptional bool) *IncludeOptionalOption { + return &IncludeOptionalOption{includeOptional} +} diff --git a/tfexec/version.go b/tfexec/version.go index 2e842a87..0bdcbcef 100644 --- a/tfexec/version.go +++ b/tfexec/version.go @@ -19,6 +19,7 @@ var ( tf0_13_0 = version.Must(version.NewVersion("0.13.0")) tf0_14_0 = version.Must(version.NewVersion("0.14.0")) tf0_15_0 = version.Must(version.NewVersion("0.15.0")) + tf1_1_0 = version.Must(version.NewVersion("1.1.0")) ) // Version returns structured output from the terraform version command including both the Terraform CLI version From cc3d774d8443c279e36334d30599bcffb08413b2 Mon Sep 17 00:00:00 2001 From: magodo Date: Thu, 12 Aug 2021 17:12:31 +0800 Subject: [PATCH 2/4] refine per review comments --- tfexec/add.go | 21 +++++++++++++++++---- tfexec/internal/testutil/tfcache.go | 14 +++++++------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/tfexec/add.go b/tfexec/add.go index d8aeeadf..04377410 100644 --- a/tfexec/add.go +++ b/tfexec/add.go @@ -1,6 +1,7 @@ package tfexec import ( + "bytes" "context" "fmt" "os/exec" @@ -41,13 +42,25 @@ func (opt *ReattachOption) configureAdd(conf *addConfig) { conf.reattachInfo = opt.info } -// Add represents the terraform add subcommand. -func (tf *Terraform) Add(ctx context.Context, address string, opts ...AddOption) error { +// Add represents the `terraform add` subcommand (added in 1.1.0). +// +// Note that this function signature and behaviour is subject +// to breaking changes including removal of that function +// until final 1.1.0 Terraform version (with this command) is released. +func (tf *Terraform) Add(ctx context.Context, address string, opts ...AddOption) (string, error) { cmd, err := tf.addCmd(ctx, address, opts...) if err != nil { - return err + return "", err } - return tf.runTerraformCmd(ctx, cmd) + + var outBuf bytes.Buffer + cmd.Stdout = mergeWriters(cmd.Stdout, &outBuf) + + if err := tf.runTerraformCmd(ctx, cmd); err != nil { + return "", err + } + + return outBuf.String(), nil } func (tf *Terraform) addCmd(ctx context.Context, address string, opts ...AddOption) (*exec.Cmd, error) { diff --git a/tfexec/internal/testutil/tfcache.go b/tfexec/internal/testutil/tfcache.go index 114f0560..4fac9317 100644 --- a/tfexec/internal/testutil/tfcache.go +++ b/tfexec/internal/testutil/tfcache.go @@ -9,13 +9,13 @@ import ( ) const ( - Latest011 = "0.11.15" - Latest012 = "0.12.31" - Latest013 = "0.13.7" - Latest014 = "0.14.11" - Latest015 = "0.15.5" - Latest_v1 = "1.0.0" - Latest_v1_1_alpha = "1.1.0-alpha20210811" + Latest011 = "0.11.15" + Latest012 = "0.12.31" + Latest013 = "0.13.7" + Latest014 = "0.14.11" + Latest015 = "0.15.5" + Latest_v1 = "1.0.0" + Latest_v1_1 = "1.1.0-alpha20210811" ) const appendUserAgent = "tfexec-testutil" From 75826ea8e2fbd1c2ccb8e5e4968aba5ef8687555 Mon Sep 17 00:00:00 2001 From: magodo Date: Thu, 12 Aug 2021 17:14:59 +0800 Subject: [PATCH 3/4] tiny fix --- tfexec/add_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tfexec/add_test.go b/tfexec/add_test.go index 55f10e28..1af63cc7 100644 --- a/tfexec/add_test.go +++ b/tfexec/add_test.go @@ -10,7 +10,7 @@ import ( func TestAddCmd(t *testing.T) { td := testTempDir(t) - tf, err := NewTerraform(td, tfVersion(t, testutil.Latest_v1_1_alpha)) + tf, err := NewTerraform(td, tfVersion(t, testutil.Latest_v1_1)) if err != nil { t.Fatal(err) } From 0baea57f20f7b45a5ec19937c708e12d0cf4e689 Mon Sep 17 00:00:00 2001 From: magodo Date: Thu, 12 Aug 2021 18:36:51 +0800 Subject: [PATCH 4/4] use strings.Builder as writer as we returns string --- tfexec/add.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tfexec/add.go b/tfexec/add.go index 04377410..0e60034e 100644 --- a/tfexec/add.go +++ b/tfexec/add.go @@ -1,11 +1,11 @@ package tfexec import ( - "bytes" "context" "fmt" "os/exec" "strconv" + "strings" ) type addConfig struct { @@ -53,7 +53,7 @@ func (tf *Terraform) Add(ctx context.Context, address string, opts ...AddOption) return "", err } - var outBuf bytes.Buffer + var outBuf strings.Builder cmd.Stdout = mergeWriters(cmd.Stdout, &outBuf) if err := tf.runTerraformCmd(ctx, cmd); err != nil {