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 Oct 8, 2019
1 parent f3008ac commit 70df13e
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 10 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,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
24 changes: 18 additions & 6 deletions terraform/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ type Parser interface {
// ParseResult represents the result of parsed terraform execution
type ParseResult struct {
Result string
Action string
ExitCode int
Error error
}
Expand All @@ -30,8 +31,9 @@ type FmtParser struct {

// PlanParser is a parser for terraform plan
type PlanParser struct {
Pass *regexp.Regexp
Fail *regexp.Regexp
Pass *regexp.Regexp
Action *regexp.Regexp
Fail *regexp.Regexp
}

// ApplyParser is a parser for terraform apply
Expand All @@ -55,8 +57,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: )`),
}
}

Expand Down Expand Up @@ -103,21 +106,30 @@ 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")
}
return ParseResult{
Result: result,
Action: action,
ExitCode: exitCode,
Error: nil,
}
Expand Down
16 changes: 15 additions & 1 deletion terraform/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,21 @@ func TestPlanParserParse(t *testing.T) {
name: "plan ok pattern",
body: planSuccessResult,
result: ParseResult{
Result: "Plan: 1 to add, 0 to change, 0 to destroy.",
Result: "Plan: 1 to add, 0 to change, 0 to destroy.",
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
8 changes: 5 additions & 3 deletions terraform/template.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ type FmtTemplate struct {
// PlanTemplate is a default template for terraform plan
type PlanTemplate struct {
Template string
Action string

CommonTemplate
}
Expand Down Expand Up @@ -182,7 +183,7 @@ func (t *DefaultTemplate) Execute() (resp string, err error) {
return resp, err
}

// Execute binds the execution result of terraform fmt into tepmlate
// Execute binds the execution result of terraform fmt into template
func (t *FmtTemplate) Execute() (resp string, err error) {
tpl, err := template.New("fmt").Parse(t.Template)
if err != nil {
Expand All @@ -202,7 +203,7 @@ func (t *FmtTemplate) Execute() (resp string, err error) {
return resp, err
}

// Execute binds the execution result of terraform plan into tepmlate
// Execute binds the execution result of terraform plan into template
func (t *PlanTemplate) Execute() (resp string, err error) {
tpl, err := template.New("plan").Parse(t.Template)
if err != nil {
Expand All @@ -212,6 +213,7 @@ func (t *PlanTemplate) Execute() (resp string, err error) {
if err := tpl.Execute(&b, map[string]interface{}{
"Title": t.Title,
"Message": t.Message,
"Action": t.Action,
"Result": t.Result,
"Body": t.Body,
"Link": t.Link,
Expand All @@ -222,7 +224,7 @@ func (t *PlanTemplate) Execute() (resp string, err error) {
return resp, err
}

// Execute binds the execution result of terraform apply into tepmlate
// Execute binds the execution result of terraform apply into template
func (t *ApplyTemplate) Execute() (resp string, err error) {
tpl, err := template.New("apply").Parse(t.Template)
if err != nil {
Expand Down

0 comments on commit 70df13e

Please sign in to comment.