diff --git a/tfexec/internal/e2etest/refresh_test.go b/tfexec/internal/e2etest/refresh_test.go new file mode 100644 index 00000000..40dbb9d7 --- /dev/null +++ b/tfexec/internal/e2etest/refresh_test.go @@ -0,0 +1,29 @@ +package e2etest + +import ( + "context" + "testing" + + "github.com/hashicorp/go-version" + + "github.com/hashicorp/terraform-exec/tfexec" +) + +func TestRefresh(t *testing.T) { + runTest(t, "basic", func(t *testing.T, tfv *version.Version, tf *tfexec.Terraform) { + 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: %s", err) + } + + err = tf.Refresh(context.Background()) + if err != nil { + t.Fatalf("error running Refresh: %s", err) + } + }) +} diff --git a/tfexec/refresh.go b/tfexec/refresh.go new file mode 100644 index 00000000..ae19dab3 --- /dev/null +++ b/tfexec/refresh.go @@ -0,0 +1,117 @@ +package tfexec + +import ( + "context" + "os/exec" + "strconv" +) + +type refreshConfig struct { + backup string + dir string + lock bool + lockTimeout string + state string + stateOut string + targets []string + vars []string + varFile string +} + +var defaultRefreshOptions = refreshConfig{ + lock: true, + lockTimeout: "0s", +} + +type RefreshCmdOption interface { + configureRefresh(*refreshConfig) +} + +func (opt *BackupOption) configureRefresh(conf *refreshConfig) { + conf.backup = opt.path +} + +func (opt *DirOption) configureRefresh(conf *refreshConfig) { + conf.dir = opt.path +} + +func (opt *LockOption) configureRefresh(conf *refreshConfig) { + conf.lock = opt.lock +} + +func (opt *LockTimeoutOption) configureRefresh(conf *refreshConfig) { + conf.lockTimeout = opt.timeout +} + +func (opt *StateOption) configureRefresh(conf *refreshConfig) { + conf.state = opt.path +} + +func (opt *StateOutOption) configureRefresh(conf *refreshConfig) { + conf.stateOut = opt.path +} + +func (opt *TargetOption) configureRefresh(conf *refreshConfig) { + conf.targets = append(conf.targets, opt.target) +} + +func (opt *VarOption) configureRefresh(conf *refreshConfig) { + conf.vars = append(conf.vars, opt.assignment) +} + +func (opt *VarFileOption) configureRefresh(conf *refreshConfig) { + conf.varFile = opt.path +} + +func (tf *Terraform) Refresh(ctx context.Context, opts ...RefreshCmdOption) error { + return tf.runTerraformCmd(tf.refreshCmd(ctx, opts...)) +} + +func (tf *Terraform) refreshCmd(ctx context.Context, opts ...RefreshCmdOption) *exec.Cmd { + c := defaultRefreshOptions + + for _, o := range opts { + o.configureRefresh(&c) + } + + args := []string{"refresh", "-no-color", "-input=false"} + + // string opts: only pass if set + if c.backup != "" { + args = append(args, "-backup="+c.backup) + } + if c.lockTimeout != "" { + args = append(args, "-lock-timeout="+c.lockTimeout) + } + if c.state != "" { + args = append(args, "-state="+c.state) + } + if c.stateOut != "" { + args = append(args, "-state-out="+c.stateOut) + } + if c.varFile != "" { + args = append(args, "-var-file="+c.varFile) + } + + // boolean and numerical opts: always pass + args = append(args, "-lock="+strconv.FormatBool(c.lock)) + + // string slice opts: split into separate args + if c.targets != nil { + for _, ta := range c.targets { + args = append(args, "-target="+ta) + } + } + if c.vars != nil { + for _, v := range c.vars { + args = append(args, "-var", v) + } + } + + // optional positional argument + if c.dir != "" { + args = append(args, c.dir) + } + + return tf.buildTerraformCmd(ctx, args...) +} diff --git a/tfexec/refresh_test.go b/tfexec/refresh_test.go new file mode 100644 index 00000000..9d47ceac --- /dev/null +++ b/tfexec/refresh_test.go @@ -0,0 +1,55 @@ +package tfexec + +import ( + "context" + "os" + "testing" + + "github.com/hashicorp/terraform-exec/tfexec/internal/testutil" +) + +func TestRefreshCmd(t *testing.T) { + td := testTempDir(t) + defer os.RemoveAll(td) + + tf, err := NewTerraform(td, tfVersion(t, testutil.Latest013)) + if err != nil { + t.Fatal(err) + } + + // empty env, to avoid environ mismatch in testing + tf.SetEnv(map[string]string{}) + + t.Run("defaults", func(t *testing.T) { + refreshCmd := tf.refreshCmd(context.Background()) + + assertCmd(t, []string{ + "refresh", + "-no-color", + "-input=false", + "-lock-timeout=0s", + "-lock=true", + }, nil, refreshCmd) + }) + + t.Run("override all defaults", func(t *testing.T) { + refreshCmd := tf.refreshCmd(context.Background(), Backup("testbackup"), LockTimeout("200s"), State("teststate"), StateOut("teststateout"), VarFile("testvarfile"), Lock(false), Target("target1"), Target("target2"), Var("var1=foo"), Var("var2=bar"), Dir("refreshdir")) + + assertCmd(t, []string{ + "refresh", + "-no-color", + "-input=false", + "-backup=testbackup", + "-lock-timeout=200s", + "-state=teststate", + "-state-out=teststateout", + "-var-file=testvarfile", + "-lock=false", + "-target=target1", + "-target=target2", + "-var", "var1=foo", + "-var", "var2=bar", + "refreshdir", + }, nil, refreshCmd) + }) +}