forked from runatlantis/atlantis
-
Notifications
You must be signed in to change notification settings - Fork 0
/
markdown_renderer.go
154 lines (136 loc) · 4.51 KB
/
markdown_renderer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package events
import (
"bytes"
"fmt"
"strings"
"text/template"
)
// MarkdownRenderer renders responses as markdown.
type MarkdownRenderer struct{}
// CommonData is data that all responses have.
type CommonData struct {
Command string
Verbose bool
Log string
}
// ErrData is data about an error response.
type ErrData struct {
Error string
CommonData
}
// FailureData is data about a failure response.
type FailureData struct {
Failure string
CommonData
}
// ResultData is data about a successful response.
type ResultData struct {
Results map[string]string
CommonData
}
// Render formats the data into a markdown string.
// nolint: interfacer
func (g *MarkdownRenderer) Render(res CommandResponse, cmdName CommandName, log string, verbose bool) string {
if cmdName == Help {
return g.renderTemplate(helpTmpl, nil)
}
commandStr := strings.Title(cmdName.String())
common := CommonData{commandStr, verbose, log}
if res.Error != nil {
return g.renderTemplate(errWithLogTmpl, ErrData{res.Error.Error(), common})
}
if res.Failure != "" {
return g.renderTemplate(failureWithLogTmpl, FailureData{res.Failure, common})
}
return g.renderProjectResults(res.ProjectResults, common)
}
func (g *MarkdownRenderer) renderProjectResults(pathResults []ProjectResult, common CommonData) string {
results := make(map[string]string)
for _, result := range pathResults {
if result.Error != nil {
results[result.Path] = g.renderTemplate(errTmpl, struct {
Command string
Error string
}{
Command: common.Command,
Error: result.Error.Error(),
})
} else if result.Failure != "" {
results[result.Path] = g.renderTemplate(failureTmpl, struct {
Command string
Failure string
}{
Command: common.Command,
Failure: result.Failure,
})
} else if result.PlanSuccess != nil {
results[result.Path] = g.renderTemplate(planSuccessTmpl, *result.PlanSuccess)
} else if result.ApplySuccess != "" {
results[result.Path] = g.renderTemplate(applySuccessTmpl, struct{ Output string }{result.ApplySuccess})
} else {
results[result.Path] = "Found no template. This is a bug!"
}
}
var tmpl *template.Template
if len(results) == 1 {
tmpl = singleProjectTmpl
} else {
tmpl = multiProjectTmpl
}
return g.renderTemplate(tmpl, ResultData{results, common})
}
func (g *MarkdownRenderer) renderTemplate(tmpl *template.Template, data interface{}) string {
buf := &bytes.Buffer{}
if err := tmpl.Execute(buf, data); err != nil {
return fmt.Sprintf("Failed to render template, this is a bug: %v", err)
}
return buf.String()
}
var helpTmpl = template.Must(template.New("").Parse("```cmake\n" +
`atlantis - Terraform collaboration tool that enables you to collaborate on infrastructure
safely and securely.
Usage: atlantis <command> [workspace] [--verbose]
Commands:
plan Runs 'terraform plan' on the files changed in the pull request
apply Runs 'terraform apply' using the plans generated by 'atlantis plan'
help Get help
Examples:
# Generates a plan for staging workspace
atlantis plan staging
# Generates a plan for a standalone terraform project
atlantis plan
# Applies a plan for staging workspace
atlantis apply staging
# Applies a plan for a standalone terraform project
atlantis apply
`))
var singleProjectTmpl = template.Must(template.New("").Parse("{{ range $result := .Results }}{{$result}}{{end}}\n" + logTmpl))
var multiProjectTmpl = template.Must(template.New("").Parse(
"Ran {{.Command}} in {{ len .Results }} directories:\n" +
"{{ range $path, $result := .Results }}" +
" * `{{$path}}`\n" +
"{{end}}\n" +
"{{ range $path, $result := .Results }}" +
"## {{$path}}/\n" +
"{{$result}}\n" +
"---\n{{end}}" +
logTmpl))
var planSuccessTmpl = template.Must(template.New("").Parse(
"```diff\n" +
"{{.TerraformOutput}}\n" +
"```\n\n" +
"* To **discard** this plan click [here]({{.LockURL}})."))
var applySuccessTmpl = template.Must(template.New("").Parse(
"```diff\n" +
"{{.Output}}\n" +
"```"))
var errTmplText = "**{{.Command}} Error**\n" +
"```\n" +
"{{.Error}}\n" +
"```\n"
var errTmpl = template.Must(template.New("").Parse(errTmplText))
var errWithLogTmpl = template.Must(template.New("").Parse(errTmplText + logTmpl))
var failureTmplText = "**{{.Command}} Failed**: {{.Failure}}\n"
var failureTmpl = template.Must(template.New("").Parse(failureTmplText))
var failureWithLogTmpl = template.Must(template.New("").Parse(failureTmplText + logTmpl))
var logTmpl = "{{if .Verbose}}\n<details><summary>Log</summary>\n <p>\n\n```\n{{.Log}}```\n</p></details>{{end}}\n"