@@ -15,8 +15,7 @@ import (
15
15
16
16
const (
17
17
defaultWorkspace = "default"
18
- // refreshSeparator is what separates the refresh stage from the calculated
19
- // plan during a terraform plan.
18
+ refreshKeyword = "Refreshing state..."
20
19
refreshSeparator = "------------------------------------------------------------------------\n "
21
20
)
22
21
@@ -55,7 +54,7 @@ func (p *PlanStepRunner) Run(ctx models.ProjectCommandContext, extraArgs []strin
55
54
if err != nil {
56
55
return output , err
57
56
}
58
- return p .fmtPlanOutput (output ), nil
57
+ return p .fmtPlanOutput (output , tfVersion ), nil
59
58
}
60
59
61
60
// isRemoteOpsErr returns true if there was an error caused due to this
@@ -89,11 +88,7 @@ func (p *PlanStepRunner) remotePlan(ctx models.ProjectCommandContext, extraArgs
89
88
// plan. To ensure that what gets applied is the plan we printed to the PR,
90
89
// during the apply phase, we diff the output we stored in the fake
91
90
// planfile with the pending apply output.
92
- planOutput := output
93
- sepIdx := strings .Index (planOutput , refreshSeparator )
94
- if sepIdx > - 1 {
95
- planOutput = planOutput [sepIdx + len (refreshSeparator ):]
96
- }
91
+ planOutput := StripRefreshingFromPlanOutput (output , tfVersion )
97
92
98
93
// We also prepend our own remote ops header to the file so during apply we
99
94
// know this is a remote apply.
@@ -102,7 +97,7 @@ func (p *PlanStepRunner) remotePlan(ctx models.ProjectCommandContext, extraArgs
102
97
return output , errors .Wrap (err , "unable to create planfile for remote ops" )
103
98
}
104
99
105
- return p .fmtPlanOutput (output ), nil
100
+ return p .fmtPlanOutput (output , tfVersion ), nil
106
101
}
107
102
108
103
// switchWorkspace changes the terraform workspace if necessary and will create
@@ -228,14 +223,8 @@ func (p *PlanStepRunner) flatten(slices [][]string) []string {
228
223
// "- aws_security_group_rule.allow_all"
229
224
// We do it for +, ~ and -.
230
225
// It also removes the "Refreshing..." preamble.
231
- func (p * PlanStepRunner ) fmtPlanOutput (output string ) string {
232
- // Plan output contains a lot of "Refreshing..." lines followed by a
233
- // separator. We want to remove everything before that separator.
234
- sepIdx := strings .Index (output , refreshSeparator )
235
- if sepIdx > - 1 {
236
- output = output [sepIdx + len (refreshSeparator ):]
237
- }
238
-
226
+ func (p * PlanStepRunner ) fmtPlanOutput (output string , tfVersion * version.Version ) string {
227
+ output = StripRefreshingFromPlanOutput (output , tfVersion )
239
228
output = plusDiffRegex .ReplaceAllString (output , "+" )
240
229
output = tildeDiffRegex .ReplaceAllString (output , "~" )
241
230
return minusDiffRegex .ReplaceAllString (output , "-" )
@@ -299,6 +288,32 @@ func (p *PlanStepRunner) runRemotePlan(
299
288
return output , err
300
289
}
301
290
291
+ func StripRefreshingFromPlanOutput (output string , tfVersion * version.Version ) string {
292
+ if tfVersion .GreaterThanOrEqual (version .Must (version .NewVersion ("0.14.0" ))) {
293
+ // Plan output contains a lot of "Refreshing..." lines, remove it
294
+ lines := strings .Split (output , "\n " )
295
+ finalIndex := 0
296
+ for i , line := range lines {
297
+ if strings .Contains (line , refreshKeyword ) {
298
+ finalIndex = i
299
+ }
300
+ }
301
+
302
+ if finalIndex != 0 {
303
+ output = strings .Join (lines [finalIndex + 1 :], "\n " )
304
+ }
305
+ return output
306
+ } else {
307
+ // Plan output contains a lot of "Refreshing..." lines followed by a
308
+ // separator. We want to remove everything before that separator.
309
+ sepIdx := strings .Index (output , refreshSeparator )
310
+ if sepIdx > - 1 {
311
+ output = output [sepIdx + len (refreshSeparator ):]
312
+ }
313
+ return output
314
+ }
315
+ }
316
+
302
317
// remoteOpsErr01114 is the error terraform plan will return if this project is
303
318
// using TFE remote operations in TF 0.11.14.
304
319
var remoteOpsErr01114 = `Error: Saving a generated plan is currently not supported!
0 commit comments