feat: add refresh-only flag for plan and apply methods (#402)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b83a3cf..443e17f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,10 @@
- Fix bug in which the `TF_WORKSPACE` env var was set to an empty string, instead of being unset as intended. [GH-388]
+ENHANCEMENTS:
+
+- tfexec: Add `-refresh-only` to `(Terraform).Apply()` and `(Terraform).Plan()` methods ([#402](https://github.com/hashicorp/terraform-exec/pull/402))
+
# 0.18.1 (March 01, 2023)
BUG FIXES:
diff --git a/tfexec/apply.go b/tfexec/apply.go
index a13ff85..2c5a6d0 100644
--- a/tfexec/apply.go
+++ b/tfexec/apply.go
@@ -22,6 +22,7 @@
parallelism int
reattachInfo ReattachInfo
refresh bool
+ refreshOnly bool
replaceAddrs []string
state string
stateOut string
@@ -80,6 +81,10 @@
conf.refresh = opt.refresh
}
+func (opt *RefreshOnlyOption) configureApply(conf *applyConfig) {
+ conf.refreshOnly = opt.refreshOnly
+}
+
func (opt *ReplaceOption) configureApply(conf *applyConfig) {
conf.replaceAddrs = append(conf.replaceAddrs, opt.address)
}
@@ -187,6 +192,17 @@
args = append(args, "-parallelism="+fmt.Sprint(c.parallelism))
args = append(args, "-refresh="+strconv.FormatBool(c.refresh))
+ if c.refreshOnly {
+ err := tf.compatible(ctx, tf0_15_4, nil)
+ if err != nil {
+ return nil, fmt.Errorf("refresh-only option was introduced in Terraform 0.15.4: %w", err)
+ }
+ if !c.refresh {
+ return nil, fmt.Errorf("you cannot use refresh=false in refresh-only planning mode")
+ }
+ args = append(args, "-refresh-only")
+ }
+
// string slice opts: split into separate args
if c.replaceAddrs != nil {
err := tf.compatible(ctx, tf0_15_2, nil)
diff --git a/tfexec/apply_test.go b/tfexec/apply_test.go
index c226a1f..8e2ddee 100644
--- a/tfexec/apply_test.go
+++ b/tfexec/apply_test.go
@@ -69,6 +69,26 @@
"testfile",
}, nil, applyCmd)
})
+
+ t.Run("refresh-only operation", func(t *testing.T) {
+ applyCmd, err := tf.applyCmd(context.Background(),
+ RefreshOnly(true),
+ )
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ assertCmd(t, []string{
+ "apply",
+ "-no-color",
+ "-auto-approve",
+ "-input=false",
+ "-lock=true",
+ "-parallelism=10",
+ "-refresh=true",
+ "-refresh-only",
+ }, nil, applyCmd)
+ })
}
func TestApplyJSONCmd(t *testing.T) {
diff --git a/tfexec/options.go b/tfexec/options.go
index 5cccde3..5f04680 100644
--- a/tfexec/options.go
+++ b/tfexec/options.go
@@ -327,6 +327,14 @@
return &RefreshOption{refresh}
}
+type RefreshOnlyOption struct {
+ refreshOnly bool
+}
+
+func RefreshOnly(refreshOnly bool) *RefreshOnlyOption {
+ return &RefreshOnlyOption{refreshOnly}
+}
+
type ReplaceOption struct {
address string
}
diff --git a/tfexec/plan.go b/tfexec/plan.go
index a4aacfb..946ce8d 100644
--- a/tfexec/plan.go
+++ b/tfexec/plan.go
@@ -20,6 +20,7 @@
parallelism int
reattachInfo ReattachInfo
refresh bool
+ refreshOnly bool
replaceAddrs []string
state string
targets []string
@@ -68,6 +69,10 @@
conf.refresh = opt.refresh
}
+func (opt *RefreshOnlyOption) configurePlan(conf *planConfig) {
+ conf.refreshOnly = opt.refreshOnly
+}
+
func (opt *ReplaceOption) configurePlan(conf *planConfig) {
conf.replaceAddrs = append(conf.replaceAddrs, opt.address)
}
@@ -202,6 +207,17 @@
args = append(args, "-parallelism="+fmt.Sprint(c.parallelism))
args = append(args, "-refresh="+strconv.FormatBool(c.refresh))
+ if c.refreshOnly {
+ err := tf.compatible(ctx, tf0_15_4, nil)
+ if err != nil {
+ return nil, fmt.Errorf("refresh-only option was introduced in Terraform 0.15.4: %w", err)
+ }
+ if !c.refresh {
+ return nil, fmt.Errorf("you cannot use refresh=false in refresh-only planning mode")
+ }
+ args = append(args, "-refresh-only")
+ }
+
// unary flags: pass if true
if c.replaceAddrs != nil {
err := tf.compatible(ctx, tf0_15_2, nil)
diff --git a/tfexec/plan_test.go b/tfexec/plan_test.go
index 8abfb8e..b0c404e 100644
--- a/tfexec/plan_test.go
+++ b/tfexec/plan_test.go
@@ -82,6 +82,25 @@
"earth",
}, nil, planCmd)
})
+
+ t.Run("run a refresh-only plan", func(t *testing.T) {
+ planCmd, err := tf.planCmd(context.Background(), RefreshOnly(true))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ assertCmd(t, []string{
+ "plan",
+ "-no-color",
+ "-input=false",
+ "-detailed-exitcode",
+ "-lock-timeout=0s",
+ "-lock=true",
+ "-parallelism=10",
+ "-refresh=true",
+ "-refresh-only",
+ }, nil, planCmd)
+ })
}
func TestPlanJSONCmd(t *testing.T) {
diff --git a/tfexec/version.go b/tfexec/version.go
index 6233212..4ba4f6e 100644
--- a/tfexec/version.go
+++ b/tfexec/version.go
@@ -29,6 +29,7 @@
tf0_15_0 = version.Must(version.NewVersion("0.15.0"))
tf0_15_2 = version.Must(version.NewVersion("0.15.2"))
tf0_15_3 = version.Must(version.NewVersion("0.15.3"))
+ tf0_15_4 = version.Must(version.NewVersion("0.15.4"))
tf1_1_0 = version.Must(version.NewVersion("1.1.0"))
tf1_4_0 = version.Must(version.NewVersion("1.4.0"))
tf1_6_0 = version.Must(version.NewVersion("1.6.0"))