Skip to content

Commit

Permalink
feat(tf,plan): extract action part from terraform plan output.
Browse files Browse the repository at this point in the history
**Why**
Sometimes we found the part about `Refreshing Terraform state in-memory prior to plan`
has too many lines that we do not need to care about in the code review. So make this
change can help us to focus on the action part that terraform plan is.
  • Loading branch information
Han Zhou committed May 11, 2020
1 parent 7a2ba7c commit 94ab83c
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 12 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ Placeholder | Usage
---|---
`{{ .Title }}` | Like `## Plan result`
`{{ .Message }}` | A string that can be set from CLI with `--message` option
`{{ .Action }}` | Using in terraform plan, and matched leading message by parsing like `Terraform will perform the following actions:`
`{{ .Result }}` | Matched result by parsing like `Plan: 1 to add` or `No changes`
`{{ .Body }}` | The entire of Terraform execution result
`{{ .Link }}` | The link of the build page on CI
Expand Down
20 changes: 16 additions & 4 deletions terraform/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ type Parser interface {
type ParseResult struct {
Result string
HasDestroy bool
Action string
ExitCode int
Error error
}
Expand All @@ -32,6 +33,7 @@ type FmtParser struct {
// PlanParser is a parser for terraform plan
type PlanParser struct {
Pass *regexp.Regexp
Action *regexp.Regexp
Fail *regexp.Regexp
HasDestroy *regexp.Regexp
}
Expand All @@ -57,8 +59,9 @@ func NewFmtParser() *FmtParser {
// NewPlanParser is PlanParser initialized with its Regexp
func NewPlanParser() *PlanParser {
return &PlanParser{
Pass: regexp.MustCompile(`(?m)^(Plan: \d|No changes.)`),
Fail: regexp.MustCompile(`(?m)^(Error: )`),
Pass: regexp.MustCompile(`(?m)^(Plan: \d|No changes.)`),
Action: regexp.MustCompile(`(?m)^(An execution plan has been generated)`),
Fail: regexp.MustCompile(`(?m)^(Error: )`),
// "0 to destroy" should be treated as "no destroy"
HasDestroy: regexp.MustCompile(`(?m)([1-9][0-9]* to destroy.)`),
}
Expand Down Expand Up @@ -107,16 +110,24 @@ func (p *PlanParser) Parse(body string) ParseResult {
}
}
lines := strings.Split(body, "\n")
var i int
var result, line string
var i, actionStartIdx int
var result, action, line string
for i, line = range lines {
if p.Action.MatchString(line) {
// action starts with the line: An execution plan...
actionStartIdx = i
}
if p.Pass.MatchString(line) || p.Fail.MatchString(line) {
break
}
}
switch {
case p.Pass.MatchString(line):
result = lines[i]
if actionStartIdx != 0 {
// action ends with the line above summary
action = strings.Join(trimLastNewline(lines[actionStartIdx:i]), "\n")
}
case p.Fail.MatchString(line):
result = strings.Join(trimLastNewline(lines[i:]), "\n")
}
Expand All @@ -126,6 +137,7 @@ func (p *PlanParser) Parse(body string) ParseResult {
return ParseResult{
Result: result,
HasDestroy: hasDestroy,
Action: action,
ExitCode: exitCode,
Error: nil,
}
Expand Down
20 changes: 17 additions & 3 deletions terraform/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ versions.tf
--- old/versions.tf
+++ new/versions.tf
@@ -1,4 +1,4 @@
terraform {
- required_version = ">= 0.12"
+ required_version = ">= 0.12"
Expand Down Expand Up @@ -309,8 +309,22 @@ func TestPlanParserParse(t *testing.T) {
result: ParseResult{
Result: "Plan: 1 to add, 0 to change, 0 to destroy.",
HasDestroy: false,
ExitCode: 0,
Error: nil,
Action: `An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
+ create
Terraform will perform the following actions:
+ google_compute_global_address.my_another_project
id: <computed>
address: <computed>
ip_version: "IPV4"
name: "my-another-project"
project: "my-project"
self_link: <computed>
`,
ExitCode: 0,
Error: nil,
},
},
{
Expand Down
12 changes: 7 additions & 5 deletions terraform/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,12 @@ type Template interface {

// CommonTemplate represents template entities
type CommonTemplate struct {
Title string
Message string
Result string
Body string
Link string
Title string
Message string
Action string
Result string
Body string
Link string
UseRawOutput bool
}

Expand Down Expand Up @@ -278,6 +279,7 @@ func (t *DestroyWarningTemplate) Execute() (string, error) {
data := map[string]interface{}{
"Title": t.Title,
"Message": t.Message,
"Action": t.Action,
"Result": t.Result,
"Body": t.Body,
"Link": t.Link,
Expand Down
11 changes: 11 additions & 0 deletions terraform/template_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,17 @@ message
},
resp: `a-b-c-d`,
},
{
template: `{{ .Title }}-{{ .Message }}-{{ .Action }}-{{ .Result }}-{{ .Body }}`,
value: CommonTemplate{
Title: "a",
Message: "b",
Action: "action",
Result: "c",
Body: "d",
},
resp: `a-b-action-c-d`,
},
}
for _, testCase := range testCases {
template := NewPlanTemplate(testCase.template)
Expand Down

0 comments on commit 94ab83c

Please sign in to comment.