mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-07-28 22:28:25 +00:00
Add custom templating support (#2647)
* added custom templates support * made default templates DRY * Change init to anonymous function. * Initialize anonymous function inside var * - Add flag/cfg param for custom template dir - Add test for custom template * Add documentation. * Address PR comments. Co-authored-by: Ricard Bejarano <ribejara@thousandeyes.com>
This commit is contained in:
198
cmd/server.go
198
cmd/server.go
@@ -37,63 +37,64 @@ import (
|
||||
// 3. Add your flag's description etc. to the stringFlags, intFlags, or boolFlags slices.
|
||||
const (
|
||||
// Flag names.
|
||||
ADWebhookPasswordFlag = "azuredevops-webhook-password" // nolint: gosec
|
||||
ADWebhookUserFlag = "azuredevops-webhook-user"
|
||||
ADTokenFlag = "azuredevops-token" // nolint: gosec
|
||||
ADUserFlag = "azuredevops-user"
|
||||
ADHostnameFlag = "azuredevops-hostname"
|
||||
AllowForkPRsFlag = "allow-fork-prs"
|
||||
AllowRepoConfigFlag = "allow-repo-config"
|
||||
AtlantisURLFlag = "atlantis-url"
|
||||
AutomergeFlag = "automerge"
|
||||
AutoplanFileListFlag = "autoplan-file-list"
|
||||
BitbucketBaseURLFlag = "bitbucket-base-url"
|
||||
BitbucketTokenFlag = "bitbucket-token"
|
||||
BitbucketUserFlag = "bitbucket-user"
|
||||
BitbucketWebhookSecretFlag = "bitbucket-webhook-secret"
|
||||
ConfigFlag = "config"
|
||||
CheckoutStrategyFlag = "checkout-strategy"
|
||||
DataDirFlag = "data-dir"
|
||||
DefaultTFVersionFlag = "default-tf-version"
|
||||
DisableApplyAllFlag = "disable-apply-all"
|
||||
DisableApplyFlag = "disable-apply"
|
||||
DisableAutoplanFlag = "disable-autoplan"
|
||||
DisableMarkdownFoldingFlag = "disable-markdown-folding"
|
||||
DisableRepoLockingFlag = "disable-repo-locking"
|
||||
EnablePolicyChecksFlag = "enable-policy-checks"
|
||||
EnableRegExpCmdFlag = "enable-regexp-cmd"
|
||||
EnableDiffMarkdownFormat = "enable-diff-markdown-format"
|
||||
GHHostnameFlag = "gh-hostname"
|
||||
GHTeamAllowlistFlag = "gh-team-allowlist"
|
||||
GHTokenFlag = "gh-token"
|
||||
GHUserFlag = "gh-user"
|
||||
GHAppIDFlag = "gh-app-id"
|
||||
GHAppKeyFlag = "gh-app-key"
|
||||
GHAppKeyFileFlag = "gh-app-key-file"
|
||||
GHAppSlugFlag = "gh-app-slug"
|
||||
GHOrganizationFlag = "gh-org"
|
||||
GHWebhookSecretFlag = "gh-webhook-secret" // nolint: gosec
|
||||
GHAllowMergeableBypassApply = "gh-allow-mergeable-bypass-apply" // nolint: gosec
|
||||
GitlabHostnameFlag = "gitlab-hostname"
|
||||
GitlabTokenFlag = "gitlab-token"
|
||||
GitlabUserFlag = "gitlab-user"
|
||||
GitlabWebhookSecretFlag = "gitlab-webhook-secret" // nolint: gosec
|
||||
APISecretFlag = "api-secret"
|
||||
HidePrevPlanComments = "hide-prev-plan-comments"
|
||||
LockingDBType = "locking-db-type"
|
||||
LogLevelFlag = "log-level"
|
||||
ParallelPoolSize = "parallel-pool-size"
|
||||
StatsNamespace = "stats-namespace"
|
||||
AllowDraftPRs = "allow-draft-prs"
|
||||
PortFlag = "port"
|
||||
RedisDB = "redis-db"
|
||||
RedisHost = "redis-host"
|
||||
RedisPassword = "redis-password"
|
||||
RedisPort = "redis-port"
|
||||
RedisTLSEnabled = "redis-tls-enabled"
|
||||
RedisInsecureSkipVerify = "redis-insecure-skip-verify"
|
||||
RepoConfigFlag = "repo-config"
|
||||
RepoConfigJSONFlag = "repo-config-json"
|
||||
ADWebhookPasswordFlag = "azuredevops-webhook-password" // nolint: gosec
|
||||
ADWebhookUserFlag = "azuredevops-webhook-user"
|
||||
ADTokenFlag = "azuredevops-token" // nolint: gosec
|
||||
ADUserFlag = "azuredevops-user"
|
||||
ADHostnameFlag = "azuredevops-hostname"
|
||||
AllowForkPRsFlag = "allow-fork-prs"
|
||||
AllowRepoConfigFlag = "allow-repo-config"
|
||||
AtlantisURLFlag = "atlantis-url"
|
||||
AutomergeFlag = "automerge"
|
||||
AutoplanFileListFlag = "autoplan-file-list"
|
||||
BitbucketBaseURLFlag = "bitbucket-base-url"
|
||||
BitbucketTokenFlag = "bitbucket-token"
|
||||
BitbucketUserFlag = "bitbucket-user"
|
||||
BitbucketWebhookSecretFlag = "bitbucket-webhook-secret"
|
||||
ConfigFlag = "config"
|
||||
CheckoutStrategyFlag = "checkout-strategy"
|
||||
DataDirFlag = "data-dir"
|
||||
DefaultTFVersionFlag = "default-tf-version"
|
||||
DisableApplyAllFlag = "disable-apply-all"
|
||||
DisableApplyFlag = "disable-apply"
|
||||
DisableAutoplanFlag = "disable-autoplan"
|
||||
DisableMarkdownFoldingFlag = "disable-markdown-folding"
|
||||
DisableRepoLockingFlag = "disable-repo-locking"
|
||||
EnablePolicyChecksFlag = "enable-policy-checks"
|
||||
EnableRegExpCmdFlag = "enable-regexp-cmd"
|
||||
EnableDiffMarkdownFormat = "enable-diff-markdown-format"
|
||||
GHHostnameFlag = "gh-hostname"
|
||||
GHTeamAllowlistFlag = "gh-team-allowlist"
|
||||
GHTokenFlag = "gh-token"
|
||||
GHUserFlag = "gh-user"
|
||||
GHAppIDFlag = "gh-app-id"
|
||||
GHAppKeyFlag = "gh-app-key"
|
||||
GHAppKeyFileFlag = "gh-app-key-file"
|
||||
GHAppSlugFlag = "gh-app-slug"
|
||||
GHOrganizationFlag = "gh-org"
|
||||
GHWebhookSecretFlag = "gh-webhook-secret" // nolint: gosec
|
||||
GHAllowMergeableBypassApply = "gh-allow-mergeable-bypass-apply" // nolint: gosec
|
||||
GitlabHostnameFlag = "gitlab-hostname"
|
||||
GitlabTokenFlag = "gitlab-token"
|
||||
GitlabUserFlag = "gitlab-user"
|
||||
GitlabWebhookSecretFlag = "gitlab-webhook-secret" // nolint: gosec
|
||||
APISecretFlag = "api-secret"
|
||||
HidePrevPlanComments = "hide-prev-plan-comments"
|
||||
LockingDBType = "locking-db-type"
|
||||
LogLevelFlag = "log-level"
|
||||
MarkdownTemplateOverridesDirFlag = "markdown-template-overrides-dir"
|
||||
ParallelPoolSize = "parallel-pool-size"
|
||||
StatsNamespace = "stats-namespace"
|
||||
AllowDraftPRs = "allow-draft-prs"
|
||||
PortFlag = "port"
|
||||
RedisDB = "redis-db"
|
||||
RedisHost = "redis-host"
|
||||
RedisPassword = "redis-password"
|
||||
RedisPort = "redis-port"
|
||||
RedisTLSEnabled = "redis-tls-enabled"
|
||||
RedisInsecureSkipVerify = "redis-insecure-skip-verify"
|
||||
RepoConfigFlag = "repo-config"
|
||||
RepoConfigJSONFlag = "repo-config-json"
|
||||
// RepoWhitelistFlag is deprecated for RepoAllowlistFlag.
|
||||
RepoWhitelistFlag = "repo-whitelist"
|
||||
RepoAllowlistFlag = "repo-allowlist"
|
||||
@@ -122,30 +123,31 @@ const (
|
||||
WebsocketCheckOrigin = "websocket-check-origin"
|
||||
|
||||
// NOTE: Must manually set these as defaults in the setDefaults function.
|
||||
DefaultADBasicUser = ""
|
||||
DefaultADBasicPassword = ""
|
||||
DefaultADHostname = "dev.azure.com"
|
||||
DefaultAutoplanFileList = "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl"
|
||||
DefaultCheckoutStrategy = "branch"
|
||||
DefaultBitbucketBaseURL = bitbucketcloud.BaseURL
|
||||
DefaultDataDir = "~/.atlantis"
|
||||
DefaultGHHostname = "github.com"
|
||||
DefaultGitlabHostname = "gitlab.com"
|
||||
DefaultLockingDBType = "boltdb"
|
||||
DefaultLogLevel = "info"
|
||||
DefaultParallelPoolSize = 15
|
||||
DefaultStatsNamespace = "atlantis"
|
||||
DefaultPort = 4141
|
||||
DefaultRedisDB = 0
|
||||
DefaultRedisPort = 6379
|
||||
DefaultRedisTLSEnabled = false
|
||||
DefaultRedisInsecureSkipVerify = false
|
||||
DefaultTFDownloadURL = "https://releases.hashicorp.com"
|
||||
DefaultTFEHostname = "app.terraform.io"
|
||||
DefaultVCSStatusName = "atlantis"
|
||||
DefaultWebBasicAuth = false
|
||||
DefaultWebUsername = "atlantis"
|
||||
DefaultWebPassword = "atlantis"
|
||||
DefaultADBasicUser = ""
|
||||
DefaultADBasicPassword = ""
|
||||
DefaultADHostname = "dev.azure.com"
|
||||
DefaultAutoplanFileList = "**/*.tf,**/*.tfvars,**/*.tfvars.json,**/terragrunt.hcl,**/.terraform.lock.hcl"
|
||||
DefaultCheckoutStrategy = "branch"
|
||||
DefaultBitbucketBaseURL = bitbucketcloud.BaseURL
|
||||
DefaultDataDir = "~/.atlantis"
|
||||
DefaultMarkdownTemplateOverridesDir = "~/.markdown_templates"
|
||||
DefaultGHHostname = "github.com"
|
||||
DefaultGitlabHostname = "gitlab.com"
|
||||
DefaultLockingDBType = "boltdb"
|
||||
DefaultLogLevel = "info"
|
||||
DefaultParallelPoolSize = 15
|
||||
DefaultStatsNamespace = "atlantis"
|
||||
DefaultPort = 4141
|
||||
DefaultRedisDB = 0
|
||||
DefaultRedisPort = 6379
|
||||
DefaultRedisTLSEnabled = false
|
||||
DefaultRedisInsecureSkipVerify = false
|
||||
DefaultTFDownloadURL = "https://releases.hashicorp.com"
|
||||
DefaultTFEHostname = "app.terraform.io"
|
||||
DefaultVCSStatusName = "atlantis"
|
||||
DefaultWebBasicAuth = false
|
||||
DefaultWebUsername = "atlantis"
|
||||
DefaultWebPassword = "atlantis"
|
||||
)
|
||||
|
||||
var stringFlags = map[string]stringFlag{
|
||||
@@ -285,6 +287,10 @@ var stringFlags = map[string]stringFlag{
|
||||
description: "Log level. Either debug, info, warn, or error.",
|
||||
defaultValue: DefaultLogLevel,
|
||||
},
|
||||
MarkdownTemplateOverridesDirFlag: {
|
||||
description: "Directory for custom overrides to the markdown templates used for comments.",
|
||||
defaultValue: DefaultMarkdownTemplateOverridesDir,
|
||||
},
|
||||
StatsNamespace: {
|
||||
description: "Namespace for aggregating stats.",
|
||||
defaultValue: DefaultStatsNamespace,
|
||||
@@ -671,6 +677,9 @@ func (s *ServerCmd) run() error {
|
||||
if err := s.setDataDir(&userConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.setMarkdownTemplateOverridesDir(&userConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
s.setVarFileAllowlist(&userConfig)
|
||||
if err := s.deprecationWarnings(&userConfig); err != nil {
|
||||
return err
|
||||
@@ -722,6 +731,9 @@ func (s *ServerCmd) setDefaults(c *server.UserConfig) {
|
||||
if c.LogLevel == "" {
|
||||
c.LogLevel = DefaultLogLevel
|
||||
}
|
||||
if c.MarkdownTemplateOverridesDir == "" {
|
||||
c.MarkdownTemplateOverridesDir = DefaultMarkdownTemplateOverridesDir
|
||||
}
|
||||
if c.ParallelPoolSize == 0 {
|
||||
c.ParallelPoolSize = DefaultParallelPoolSize
|
||||
}
|
||||
@@ -887,6 +899,30 @@ func (s *ServerCmd) setDataDir(userConfig *server.UserConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// setMarkdownTemplateOverridesDir checks if ~ was used in markdown-template-overrides-dir and converts it to the actual
|
||||
// home directory. If we don't do this, we'll create a directory called "~"
|
||||
// instead of actually using home. It also converts relative paths to absolute.
|
||||
func (s *ServerCmd) setMarkdownTemplateOverridesDir(userConfig *server.UserConfig) error {
|
||||
finalPath := userConfig.MarkdownTemplateOverridesDir
|
||||
|
||||
// Convert ~ to the actual home dir.
|
||||
if strings.HasPrefix(finalPath, "~/") {
|
||||
var err error
|
||||
finalPath, err = homedir.Expand(finalPath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "determining home directory")
|
||||
}
|
||||
}
|
||||
|
||||
// Convert relative paths to absolute.
|
||||
finalPath, err := filepath.Abs(finalPath)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "making markdown-template-overrides-dir absolute")
|
||||
}
|
||||
userConfig.MarkdownTemplateOverridesDir = finalPath
|
||||
return nil
|
||||
}
|
||||
|
||||
// setVarFileAllowlist checks if var-file-allowlist is unassigned and makes it default to data-dir for better backward
|
||||
// compatibility.
|
||||
func (s *ServerCmd) setVarFileAllowlist(userConfig *server.UserConfig) {
|
||||
|
||||
@@ -51,66 +51,67 @@ func (s *ServerStarterMock) Start() error {
|
||||
// Adding a new flag? Add it to this slice for testing in alphabetical
|
||||
// order.
|
||||
var testFlags = map[string]interface{}{
|
||||
ADTokenFlag: "ad-token",
|
||||
ADUserFlag: "ad-user",
|
||||
ADWebhookPasswordFlag: "ad-wh-pass",
|
||||
ADWebhookUserFlag: "ad-wh-user",
|
||||
AtlantisURLFlag: "url",
|
||||
AllowForkPRsFlag: true,
|
||||
AllowRepoConfigFlag: true,
|
||||
AutomergeFlag: true,
|
||||
AutoplanFileListFlag: "**/*.tf,**/*.yml",
|
||||
BitbucketBaseURLFlag: "https://bitbucket-base-url.com",
|
||||
BitbucketTokenFlag: "bitbucket-token",
|
||||
BitbucketUserFlag: "bitbucket-user",
|
||||
BitbucketWebhookSecretFlag: "bitbucket-secret",
|
||||
CheckoutStrategyFlag: "merge",
|
||||
DataDirFlag: "/path",
|
||||
DefaultTFVersionFlag: "v0.11.0",
|
||||
DisableApplyAllFlag: true,
|
||||
DisableApplyFlag: true,
|
||||
DisableMarkdownFoldingFlag: true,
|
||||
DisableRepoLockingFlag: true,
|
||||
GHHostnameFlag: "ghhostname",
|
||||
GHTokenFlag: "token",
|
||||
GHUserFlag: "user",
|
||||
GHAppIDFlag: int64(0),
|
||||
GHAppKeyFlag: "",
|
||||
GHAppKeyFileFlag: "",
|
||||
GHAppSlugFlag: "atlantis",
|
||||
GHOrganizationFlag: "",
|
||||
GHWebhookSecretFlag: "secret",
|
||||
GitlabHostnameFlag: "gitlab-hostname",
|
||||
GitlabTokenFlag: "gitlab-token",
|
||||
GitlabUserFlag: "gitlab-user",
|
||||
GitlabWebhookSecretFlag: "gitlab-secret",
|
||||
LockingDBType: "boltdb",
|
||||
LogLevelFlag: "debug",
|
||||
StatsNamespace: "atlantis",
|
||||
AllowDraftPRs: true,
|
||||
PortFlag: 8181,
|
||||
ParallelPoolSize: 100,
|
||||
RepoAllowlistFlag: "github.com/runatlantis/atlantis",
|
||||
RequireApprovalFlag: true,
|
||||
RequireMergeableFlag: true,
|
||||
SilenceNoProjectsFlag: false,
|
||||
SilenceForkPRErrorsFlag: true,
|
||||
SilenceAllowlistErrorsFlag: true,
|
||||
SilenceVCSStatusNoPlans: true,
|
||||
SkipCloneNoChanges: true,
|
||||
SlackTokenFlag: "slack-token",
|
||||
SSLCertFileFlag: "cert-file",
|
||||
SSLKeyFileFlag: "key-file",
|
||||
TFDownloadURLFlag: "https://my-hostname.com",
|
||||
TFEHostnameFlag: "my-hostname",
|
||||
TFELocalExecutionModeFlag: true,
|
||||
TFETokenFlag: "my-token",
|
||||
VCSStatusName: "my-status",
|
||||
WriteGitCredsFlag: true,
|
||||
DisableAutoplanFlag: true,
|
||||
EnablePolicyChecksFlag: false,
|
||||
EnableRegExpCmdFlag: false,
|
||||
EnableDiffMarkdownFormat: false,
|
||||
ADTokenFlag: "ad-token",
|
||||
ADUserFlag: "ad-user",
|
||||
ADWebhookPasswordFlag: "ad-wh-pass",
|
||||
ADWebhookUserFlag: "ad-wh-user",
|
||||
AtlantisURLFlag: "url",
|
||||
AllowForkPRsFlag: true,
|
||||
AllowRepoConfigFlag: true,
|
||||
AutomergeFlag: true,
|
||||
AutoplanFileListFlag: "**/*.tf,**/*.yml",
|
||||
BitbucketBaseURLFlag: "https://bitbucket-base-url.com",
|
||||
BitbucketTokenFlag: "bitbucket-token",
|
||||
BitbucketUserFlag: "bitbucket-user",
|
||||
BitbucketWebhookSecretFlag: "bitbucket-secret",
|
||||
CheckoutStrategyFlag: "merge",
|
||||
DataDirFlag: "/path",
|
||||
DefaultTFVersionFlag: "v0.11.0",
|
||||
DisableApplyAllFlag: true,
|
||||
DisableApplyFlag: true,
|
||||
DisableMarkdownFoldingFlag: true,
|
||||
DisableRepoLockingFlag: true,
|
||||
GHHostnameFlag: "ghhostname",
|
||||
GHTokenFlag: "token",
|
||||
GHUserFlag: "user",
|
||||
GHAppIDFlag: int64(0),
|
||||
GHAppKeyFlag: "",
|
||||
GHAppKeyFileFlag: "",
|
||||
GHAppSlugFlag: "atlantis",
|
||||
GHOrganizationFlag: "",
|
||||
GHWebhookSecretFlag: "secret",
|
||||
GitlabHostnameFlag: "gitlab-hostname",
|
||||
GitlabTokenFlag: "gitlab-token",
|
||||
GitlabUserFlag: "gitlab-user",
|
||||
GitlabWebhookSecretFlag: "gitlab-secret",
|
||||
LockingDBType: "boltdb",
|
||||
LogLevelFlag: "debug",
|
||||
MarkdownTemplateOverridesDirFlag: "/path2",
|
||||
StatsNamespace: "atlantis",
|
||||
AllowDraftPRs: true,
|
||||
PortFlag: 8181,
|
||||
ParallelPoolSize: 100,
|
||||
RepoAllowlistFlag: "github.com/runatlantis/atlantis",
|
||||
RequireApprovalFlag: true,
|
||||
RequireMergeableFlag: true,
|
||||
SilenceNoProjectsFlag: false,
|
||||
SilenceForkPRErrorsFlag: true,
|
||||
SilenceAllowlistErrorsFlag: true,
|
||||
SilenceVCSStatusNoPlans: true,
|
||||
SkipCloneNoChanges: true,
|
||||
SlackTokenFlag: "slack-token",
|
||||
SSLCertFileFlag: "cert-file",
|
||||
SSLKeyFileFlag: "key-file",
|
||||
TFDownloadURLFlag: "https://my-hostname.com",
|
||||
TFEHostnameFlag: "my-hostname",
|
||||
TFELocalExecutionModeFlag: true,
|
||||
TFETokenFlag: "my-token",
|
||||
VCSStatusName: "my-status",
|
||||
WriteGitCredsFlag: true,
|
||||
DisableAutoplanFlag: true,
|
||||
EnablePolicyChecksFlag: false,
|
||||
EnableRegExpCmdFlag: false,
|
||||
EnableDiffMarkdownFormat: false,
|
||||
}
|
||||
|
||||
func TestExecute_Defaults(t *testing.T) {
|
||||
@@ -128,17 +129,20 @@ func TestExecute_Defaults(t *testing.T) {
|
||||
hostname, err := os.Hostname()
|
||||
Ok(t, err)
|
||||
|
||||
// Get our home dir since that's what data-dir defaulted to.
|
||||
// Get our home dir since that's what data-dir and markdown-template-overrides-dir defaulted to.
|
||||
dataDir, err := homedir.Expand("~/.atlantis")
|
||||
Ok(t, err)
|
||||
markdownTemplateOverridesDir, err := homedir.Expand("~/.markdown_templates")
|
||||
Ok(t, err)
|
||||
|
||||
strExceptions := map[string]string{
|
||||
GHUserFlag: "user",
|
||||
GHTokenFlag: "token",
|
||||
DataDirFlag: dataDir,
|
||||
AtlantisURLFlag: "http://" + hostname + ":4141",
|
||||
RepoAllowlistFlag: "*",
|
||||
VarFileAllowlistFlag: dataDir,
|
||||
GHUserFlag: "user",
|
||||
GHTokenFlag: "token",
|
||||
DataDirFlag: dataDir,
|
||||
MarkdownTemplateOverridesDirFlag: markdownTemplateOverridesDir,
|
||||
AtlantisURLFlag: "http://" + hostname + ":4141",
|
||||
RepoAllowlistFlag: "*",
|
||||
VarFileAllowlistFlag: dataDir,
|
||||
}
|
||||
strIgnore := map[string]bool{
|
||||
"config": true,
|
||||
|
||||
@@ -456,6 +456,21 @@ Values are chosen in this order:
|
||||
```
|
||||
Log level. Defaults to `info`.
|
||||
|
||||
### `--markdown-template-overrides-dir`
|
||||
```bash
|
||||
atlantis server --markdown-template-overrides-dir="path/to/templates/"
|
||||
```
|
||||
Directory where Atlantis will read in overrides for markdown templates used to render comments on pull requests.
|
||||
Markdown template overrides may be specified either in individual files, or all together in a single file. All template
|
||||
override files _must_ have the `.tmpl` extension, otherwise they will not be parsed.
|
||||
|
||||
Markdown templates which may have overrides can be found [here](https://github.com/runatlantis/atlantis/tree/master/server/events/templates)
|
||||
|
||||
Please be mindful that settings like `--enable-diff-markdown-format` depend on logic defined in the templates. It is
|
||||
possible to diverge from expected behavior, if care is not taken when overriding default templates.
|
||||
|
||||
Defaults to the atlantis home directory `/home/atlantis/.markdown_templates/` in `/$HOME/.markdown_templates`.
|
||||
|
||||
### `--parallel-pool-size`
|
||||
```bash
|
||||
atlantis server --parallel-pool-size=100
|
||||
|
||||
@@ -1036,7 +1036,7 @@ func setupE2E(t *testing.T, repoDir string) (events_controllers.VCSEventsControl
|
||||
pullUpdater := &events.PullUpdater{
|
||||
HidePrevPlanComments: false,
|
||||
VCSClient: e2eVCSClient,
|
||||
MarkdownRenderer: &events.MarkdownRenderer{},
|
||||
MarkdownRenderer: events.GetMarkdownRenderer(false, false, false, false, false, false, ""),
|
||||
}
|
||||
|
||||
autoMerger := &events.AutoMerger{
|
||||
|
||||
@@ -99,7 +99,7 @@ func setup(t *testing.T) *vcsmocks.MockClient {
|
||||
pullUpdater = &events.PullUpdater{
|
||||
HidePrevPlanComments: false,
|
||||
VCSClient: vcsClient,
|
||||
MarkdownRenderer: &events.MarkdownRenderer{},
|
||||
MarkdownRenderer: events.GetMarkdownRenderer(false, false, false, false, false, false, ""),
|
||||
}
|
||||
|
||||
autoMerger = &events.AutoMerger{
|
||||
|
||||
@@ -15,6 +15,7 @@ package events
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"embed"
|
||||
"fmt"
|
||||
"strings"
|
||||
"text/template"
|
||||
@@ -33,6 +34,9 @@ var (
|
||||
// maxUnwrappedLines is the maximum number of lines the Terraform output
|
||||
// can be before we wrap it in an expandable template.
|
||||
maxUnwrappedLines = 12
|
||||
|
||||
//go:embed templates/*
|
||||
templatesFS embed.FS
|
||||
)
|
||||
|
||||
// MarkdownRenderer renders responses as markdown.
|
||||
@@ -46,6 +50,7 @@ type MarkdownRenderer struct {
|
||||
DisableMarkdownFolding bool
|
||||
DisableRepoLocking bool
|
||||
EnableDiffMarkdownFormat bool
|
||||
MarkdownTemplates *template.Template
|
||||
}
|
||||
|
||||
// commonData is data that all responses have.
|
||||
@@ -98,6 +103,33 @@ type projectResultTmplData struct {
|
||||
Rendered string
|
||||
}
|
||||
|
||||
// Initialize templates
|
||||
func GetMarkdownRenderer(
|
||||
GitlabSupportsCommonMark bool,
|
||||
DisableApplyAll bool,
|
||||
DisableApply bool,
|
||||
DisableMarkdownFolding bool,
|
||||
DisableRepoLocking bool,
|
||||
EnableDiffMarkdownFormat bool,
|
||||
MarkdownTemplateOverridesDir string,
|
||||
) *MarkdownRenderer {
|
||||
var templates *template.Template
|
||||
templates, _ = template.New("").Funcs(sprig.TxtFuncMap()).ParseFS(templatesFS, "templates/*.tmpl")
|
||||
if overrides, err := templates.ParseGlob(fmt.Sprintf("%s/*.tmpl", MarkdownTemplateOverridesDir)); err == nil {
|
||||
// doesn't override if templates directory doesn't exist
|
||||
templates = overrides
|
||||
}
|
||||
return &MarkdownRenderer{
|
||||
GitlabSupportsCommonMark: GitlabSupportsCommonMark,
|
||||
DisableApplyAll: DisableApplyAll,
|
||||
DisableMarkdownFolding: DisableMarkdownFolding,
|
||||
DisableApply: DisableApply,
|
||||
DisableRepoLocking: DisableRepoLocking,
|
||||
EnableDiffMarkdownFormat: EnableDiffMarkdownFormat,
|
||||
MarkdownTemplates: templates,
|
||||
}
|
||||
}
|
||||
|
||||
// Render formats the data into a markdown string.
|
||||
// nolint: interfacer
|
||||
func (m *MarkdownRenderer) Render(res command.Result, cmdName command.Name, log string, verbose bool, vcsHost models.VCSHostType) string {
|
||||
@@ -112,11 +144,14 @@ func (m *MarkdownRenderer) Render(res command.Result, cmdName command.Name, log
|
||||
DisableRepoLocking: m.DisableRepoLocking,
|
||||
EnableDiffMarkdownFormat: m.EnableDiffMarkdownFormat,
|
||||
}
|
||||
|
||||
templates := m.MarkdownTemplates
|
||||
|
||||
if res.Error != nil {
|
||||
return m.renderTemplate(unwrappedErrWithLogTmpl, errData{res.Error.Error(), common})
|
||||
return m.renderTemplate(templates.Lookup("unwrappedErrWithLog"), errData{res.Error.Error(), common})
|
||||
}
|
||||
if res.Failure != "" {
|
||||
return m.renderTemplate(failureWithLogTmpl, failureData{res.Failure, common})
|
||||
return m.renderTemplate(templates.Lookup("failureWithLog"), failureData{res.Failure, common})
|
||||
}
|
||||
return m.renderProjectResults(res.ProjectResults, common, vcsHost)
|
||||
}
|
||||
@@ -127,6 +162,8 @@ func (m *MarkdownRenderer) renderProjectResults(results []command.ProjectResult,
|
||||
numPolicyCheckSuccesses := 0
|
||||
numVersionSuccesses := 0
|
||||
|
||||
templates := m.MarkdownTemplates
|
||||
|
||||
for _, result := range results {
|
||||
resultData := projectResultTmplData{
|
||||
Workspace: result.Workspace,
|
||||
@@ -134,9 +171,9 @@ func (m *MarkdownRenderer) renderProjectResults(results []command.ProjectResult,
|
||||
ProjectName: result.ProjectName,
|
||||
}
|
||||
if result.Error != nil {
|
||||
tmpl := unwrappedErrTmpl
|
||||
tmpl := templates.Lookup("unwrappedErr")
|
||||
if m.shouldUseWrappedTmpl(vcsHost, result.Error.Error()) {
|
||||
tmpl = wrappedErrTmpl
|
||||
tmpl = templates.Lookup("wrappedErr")
|
||||
}
|
||||
resultData.Rendered = m.renderTemplate(tmpl, struct {
|
||||
Command string
|
||||
@@ -146,7 +183,7 @@ func (m *MarkdownRenderer) renderProjectResults(results []command.ProjectResult,
|
||||
Error: result.Error.Error(),
|
||||
})
|
||||
} else if result.Failure != "" {
|
||||
resultData.Rendered = m.renderTemplate(failureTmpl, struct {
|
||||
resultData.Rendered = m.renderTemplate(templates.Lookup("failure"), struct {
|
||||
Command string
|
||||
Failure string
|
||||
}{
|
||||
@@ -155,29 +192,29 @@ func (m *MarkdownRenderer) renderProjectResults(results []command.ProjectResult,
|
||||
})
|
||||
} else if result.PlanSuccess != nil {
|
||||
if m.shouldUseWrappedTmpl(vcsHost, result.PlanSuccess.TerraformOutput) {
|
||||
resultData.Rendered = m.renderTemplate(planSuccessWrappedTmpl, planSuccessData{PlanSuccess: *result.PlanSuccess, PlanSummary: result.PlanSuccess.Summary(), PlanWasDeleted: common.PlansDeleted, DisableApply: common.DisableApply, DisableRepoLocking: common.DisableRepoLocking, EnableDiffMarkdownFormat: common.EnableDiffMarkdownFormat})
|
||||
resultData.Rendered = m.renderTemplate(templates.Lookup("planSuccessWrapped"), planSuccessData{PlanSuccess: *result.PlanSuccess, PlanSummary: result.PlanSuccess.Summary(), PlanWasDeleted: common.PlansDeleted, DisableApply: common.DisableApply, DisableRepoLocking: common.DisableRepoLocking, EnableDiffMarkdownFormat: common.EnableDiffMarkdownFormat})
|
||||
} else {
|
||||
resultData.Rendered = m.renderTemplate(planSuccessUnwrappedTmpl, planSuccessData{PlanSuccess: *result.PlanSuccess, PlanWasDeleted: common.PlansDeleted, DisableApply: common.DisableApply, DisableRepoLocking: common.DisableRepoLocking, EnableDiffMarkdownFormat: common.EnableDiffMarkdownFormat})
|
||||
resultData.Rendered = m.renderTemplate(templates.Lookup("planSuccessUnwrapped"), planSuccessData{PlanSuccess: *result.PlanSuccess, PlanWasDeleted: common.PlansDeleted, DisableApply: common.DisableApply, DisableRepoLocking: common.DisableRepoLocking, EnableDiffMarkdownFormat: common.EnableDiffMarkdownFormat})
|
||||
}
|
||||
numPlanSuccesses++
|
||||
} else if result.PolicyCheckSuccess != nil {
|
||||
if m.shouldUseWrappedTmpl(vcsHost, result.PolicyCheckSuccess.PolicyCheckOutput) {
|
||||
resultData.Rendered = m.renderTemplate(policyCheckSuccessWrappedTmpl, policyCheckSuccessData{PolicyCheckSuccess: *result.PolicyCheckSuccess})
|
||||
resultData.Rendered = m.renderTemplate(templates.Lookup("policyCheckSuccessWrapped"), policyCheckSuccessData{PolicyCheckSuccess: *result.PolicyCheckSuccess})
|
||||
} else {
|
||||
resultData.Rendered = m.renderTemplate(policyCheckSuccessUnwrappedTmpl, policyCheckSuccessData{PolicyCheckSuccess: *result.PolicyCheckSuccess})
|
||||
resultData.Rendered = m.renderTemplate(templates.Lookup("policyCheckSuccessUnwrapped"), policyCheckSuccessData{PolicyCheckSuccess: *result.PolicyCheckSuccess})
|
||||
}
|
||||
numPolicyCheckSuccesses++
|
||||
} else if result.ApplySuccess != "" {
|
||||
if m.shouldUseWrappedTmpl(vcsHost, result.ApplySuccess) {
|
||||
resultData.Rendered = m.renderTemplate(applyWrappedSuccessTmpl, struct{ Output string }{result.ApplySuccess})
|
||||
resultData.Rendered = m.renderTemplate(templates.Lookup("applyWrappedSuccess"), struct{ Output string }{result.ApplySuccess})
|
||||
} else {
|
||||
resultData.Rendered = m.renderTemplate(applyUnwrappedSuccessTmpl, struct{ Output string }{result.ApplySuccess})
|
||||
resultData.Rendered = m.renderTemplate(templates.Lookup("applyUnwrappedSuccess"), struct{ Output string }{result.ApplySuccess})
|
||||
}
|
||||
} else if result.VersionSuccess != "" {
|
||||
if m.shouldUseWrappedTmpl(vcsHost, result.VersionSuccess) {
|
||||
resultData.Rendered = m.renderTemplate(versionWrappedSuccessTmpl, struct{ Output string }{result.VersionSuccess})
|
||||
resultData.Rendered = m.renderTemplate(templates.Lookup("versionWrappedSuccess"), struct{ Output string }{result.VersionSuccess})
|
||||
} else {
|
||||
resultData.Rendered = m.renderTemplate(versionUnwrappedSuccessTmpl, struct{ Output string }{result.VersionSuccess})
|
||||
resultData.Rendered = m.renderTemplate(templates.Lookup("versionUnwrappedSuccess"), struct{ Output string }{result.VersionSuccess})
|
||||
}
|
||||
numVersionSuccesses++
|
||||
} else {
|
||||
@@ -189,28 +226,28 @@ func (m *MarkdownRenderer) renderProjectResults(results []command.ProjectResult,
|
||||
var tmpl *template.Template
|
||||
switch {
|
||||
case len(resultsTmplData) == 1 && common.Command == planCommandTitle && numPlanSuccesses > 0:
|
||||
tmpl = singleProjectPlanSuccessTmpl
|
||||
tmpl = templates.Lookup("singleProjectPlanSuccess")
|
||||
case len(resultsTmplData) == 1 && common.Command == planCommandTitle && numPlanSuccesses == 0:
|
||||
tmpl = singleProjectPlanUnsuccessfulTmpl
|
||||
tmpl = templates.Lookup("singleProjectPlanUnsuccessful")
|
||||
case len(resultsTmplData) == 1 && common.Command == policyCheckCommandTitle && numPolicyCheckSuccesses > 0:
|
||||
tmpl = singleProjectPlanSuccessTmpl
|
||||
tmpl = templates.Lookup("singleProjectPlanSuccess")
|
||||
case len(resultsTmplData) == 1 && common.Command == policyCheckCommandTitle && numPolicyCheckSuccesses == 0:
|
||||
tmpl = singleProjectPlanUnsuccessfulTmpl
|
||||
tmpl = templates.Lookup("singleProjectPlanUnsuccessful")
|
||||
case len(resultsTmplData) == 1 && common.Command == versionCommandTitle && numVersionSuccesses > 0:
|
||||
tmpl = singleProjectVersionSuccessTmpl
|
||||
tmpl = templates.Lookup("singleProjectVersionSuccess")
|
||||
case len(resultsTmplData) == 1 && common.Command == versionCommandTitle && numVersionSuccesses == 0:
|
||||
tmpl = singleProjectVersionUnsuccessfulTmpl
|
||||
tmpl = templates.Lookup("singleProjectVersionUnsuccessful")
|
||||
case len(resultsTmplData) == 1 && common.Command == applyCommandTitle:
|
||||
tmpl = singleProjectApplyTmpl
|
||||
tmpl = templates.Lookup("singleProjectApply")
|
||||
case common.Command == planCommandTitle,
|
||||
common.Command == policyCheckCommandTitle:
|
||||
tmpl = multiProjectPlanTmpl
|
||||
tmpl = templates.Lookup("multiProjectPlan")
|
||||
case common.Command == approvePoliciesCommandTitle:
|
||||
tmpl = approveAllProjectsTmpl
|
||||
tmpl = templates.Lookup("approveAllProjects")
|
||||
case common.Command == applyCommandTitle:
|
||||
tmpl = multiProjectApplyTmpl
|
||||
tmpl = templates.Lookup("multiProjectApply")
|
||||
case common.Command == versionCommandTitle:
|
||||
tmpl = multiProjectVersionTmpl
|
||||
tmpl = templates.Lookup("multiProjectVersion")
|
||||
default:
|
||||
return "no template matched–this is a bug"
|
||||
}
|
||||
@@ -245,146 +282,3 @@ func (m *MarkdownRenderer) renderTemplate(tmpl *template.Template, data interfac
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
// todo: refactor to remove duplication #refactor
|
||||
var singleProjectApplyTmpl = template.Must(template.New("").Parse(
|
||||
"{{$result := index .Results 0}}Ran {{.Command}} for {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`\n\n{{$result.Rendered}}\n" + logTmpl))
|
||||
var singleProjectPlanSuccessTmpl = template.Must(template.New("").Parse(
|
||||
"{{$result := index .Results 0}}Ran {{.Command}} for {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`\n\n{{$result.Rendered}}\n" +
|
||||
"\n" +
|
||||
"{{ if ne .DisableApplyAll true }}---\n" +
|
||||
"* :fast_forward: To **apply** all unapplied plans from this pull request, comment:\n" +
|
||||
" * `atlantis apply`\n" +
|
||||
"* :put_litter_in_its_place: To delete all plans and locks for the PR, comment:\n" +
|
||||
" * `atlantis unlock`{{ end }}" + logTmpl))
|
||||
var singleProjectPlanUnsuccessfulTmpl = template.Must(template.New("").Parse(
|
||||
"{{$result := index .Results 0}}Ran {{.Command}} for dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`\n\n" +
|
||||
"{{$result.Rendered}}\n" + logTmpl))
|
||||
var singleProjectVersionSuccessTmpl = template.Must(template.New("").Parse(
|
||||
"{{$result := index .Results 0}}Ran {{.Command}} for {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`\n\n{{$result.Rendered}}\n" + logTmpl))
|
||||
var singleProjectVersionUnsuccessfulTmpl = template.Must(template.New("").Parse(
|
||||
"{{$result := index .Results 0}}Ran {{.Command}} for dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`\n\n{{$result.Rendered}}\n" + logTmpl))
|
||||
var approveAllProjectsTmpl = template.Must(template.New("").Funcs(sprig.TxtFuncMap()).Parse(
|
||||
"Approved Policies for {{ len .Results }} projects:\n\n" +
|
||||
"{{ range $result := .Results }}" +
|
||||
"1. {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`\n" +
|
||||
"{{end}}\n" + logTmpl))
|
||||
var multiProjectPlanTmpl = template.Must(template.New("").Funcs(sprig.TxtFuncMap()).Parse(
|
||||
"Ran {{.Command}} for {{ len .Results }} projects:\n\n" +
|
||||
"{{ range $result := .Results }}" +
|
||||
"1. {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`\n" +
|
||||
"{{end}}\n" +
|
||||
"{{ $disableApplyAll := .DisableApplyAll }}{{ range $i, $result := .Results }}" +
|
||||
"### {{add $i 1}}. {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`\n" +
|
||||
"{{$result.Rendered}}\n\n" +
|
||||
"{{ if ne $disableApplyAll true }}---\n{{end}}{{end}}{{ if ne .DisableApplyAll true }}{{ if and (gt (len .Results) 0) (not .PlansDeleted) }}* :fast_forward: To **apply** all unapplied plans from this pull request, comment:\n" +
|
||||
" * `atlantis apply`\n" +
|
||||
"* :put_litter_in_its_place: To delete all plans and locks for the PR, comment:\n" +
|
||||
" * `atlantis unlock`" +
|
||||
"{{end}}{{end}}" +
|
||||
logTmpl))
|
||||
var multiProjectApplyTmpl = template.Must(template.New("").Funcs(sprig.TxtFuncMap()).Parse(
|
||||
"Ran {{.Command}} for {{ len .Results }} projects:\n\n" +
|
||||
"{{ range $result := .Results }}" +
|
||||
"1. {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`\n" +
|
||||
"{{end}}\n" +
|
||||
"{{ range $i, $result := .Results }}" +
|
||||
"### {{add $i 1}}. {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`\n" +
|
||||
"{{$result.Rendered}}\n\n" +
|
||||
"---\n{{end}}" +
|
||||
logTmpl))
|
||||
var multiProjectVersionTmpl = template.Must(template.New("").Funcs(sprig.TxtFuncMap()).Parse(
|
||||
"Ran {{.Command}} for {{ len .Results }} projects:\n\n" +
|
||||
"{{ range $result := .Results }}" +
|
||||
"1. {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`\n" +
|
||||
"{{end}}\n" +
|
||||
"{{ range $i, $result := .Results }}" +
|
||||
"### {{add $i 1}}. {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`\n" +
|
||||
"{{$result.Rendered}}\n\n" +
|
||||
"---\n{{end}}" +
|
||||
logTmpl))
|
||||
var planSuccessUnwrappedTmpl = template.Must(template.New("").Parse(
|
||||
"```diff\n" +
|
||||
"{{ if .EnableDiffMarkdownFormat }}{{.DiffMarkdownFormattedTerraformOutput}}{{else}}{{.TerraformOutput}}{{end}}\n" +
|
||||
"```\n\n" + planNextSteps +
|
||||
"{{ if .HasDiverged }}\n\n:warning: The branch we're merging into is ahead, it is recommended to pull new commits first.{{end}}"))
|
||||
|
||||
var planSuccessWrappedTmpl = template.Must(template.New("").Parse(
|
||||
"<details><summary>Show Output</summary>\n\n" +
|
||||
"```diff\n" +
|
||||
"{{ if .EnableDiffMarkdownFormat }}{{.DiffMarkdownFormattedTerraformOutput}}{{else}}{{.TerraformOutput}}{{end}}\n" +
|
||||
"```\n\n" +
|
||||
planNextSteps + "\n" +
|
||||
"</details>" + "\n" +
|
||||
"{{.PlanSummary}}" +
|
||||
"{{ if .HasDiverged }}\n\n:warning: The branch we're merging into is ahead, it is recommended to pull new commits first.{{end}}"))
|
||||
|
||||
var policyCheckSuccessUnwrappedTmpl = template.Must(template.New("").Parse(
|
||||
"```diff\n" +
|
||||
"{{.PolicyCheckOutput}}\n" +
|
||||
"```\n\n" + policyCheckNextSteps +
|
||||
"{{ if .HasDiverged }}\n\n:warning: The branch we're merging into is ahead, it is recommended to pull new commits first.{{end}}"))
|
||||
|
||||
var policyCheckSuccessWrappedTmpl = template.Must(template.New("").Parse(
|
||||
"<details><summary>Show Output</summary>\n\n" +
|
||||
"```diff\n" +
|
||||
"{{.PolicyCheckOutput}}\n" +
|
||||
"```\n\n" +
|
||||
policyCheckNextSteps + "\n" +
|
||||
"</details>" +
|
||||
"{{ if .HasDiverged }}\n\n:warning: The branch we're merging into is ahead, it is recommended to pull new commits first.{{end}}"))
|
||||
|
||||
// policyCheckNextSteps are instructions appended after successful plans as to what
|
||||
// to do next.
|
||||
var policyCheckNextSteps = "* :arrow_forward: To **apply** this plan, comment:\n" +
|
||||
" * `{{.ApplyCmd}}`\n" +
|
||||
"* :put_litter_in_its_place: To **delete** this plan click [here]({{.LockURL}})\n" +
|
||||
"* :repeat: To re-run policies **plan** this project again by commenting:\n" +
|
||||
" * `{{.RePlanCmd}}`"
|
||||
|
||||
// planNextSteps are instructions appended after successful plans as to what
|
||||
// to do next.
|
||||
var planNextSteps = "{{ if .PlanWasDeleted }}This plan was not saved because one or more projects failed and automerge requires all plans pass.{{ else }}" +
|
||||
"{{ if not .DisableApply }}* :arrow_forward: To **apply** this plan, comment:\n" +
|
||||
" * `{{.ApplyCmd}}`\n{{end}}" +
|
||||
"{{ if not .DisableRepoLocking }}* :put_litter_in_its_place: To **delete** this plan click [here]({{.LockURL}})\n{{end}}" +
|
||||
"* :repeat: To **plan** this project again, comment:\n" +
|
||||
" * `{{.RePlanCmd}}`{{end}}"
|
||||
var applyUnwrappedSuccessTmpl = template.Must(template.New("").Parse(
|
||||
"```diff\n" +
|
||||
"{{.Output}}\n" +
|
||||
"```"))
|
||||
var applyWrappedSuccessTmpl = template.Must(template.New("").Parse(
|
||||
"<details><summary>Show Output</summary>\n\n" +
|
||||
"```diff\n" +
|
||||
"{{.Output}}\n" +
|
||||
"```\n" +
|
||||
"</details>"))
|
||||
var versionUnwrappedSuccessTmpl = template.Must(template.New("").Parse("```\n{{.Output}}```"))
|
||||
var versionWrappedSuccessTmpl = template.Must(template.New("").Parse(
|
||||
"<details><summary>Show Output</summary>\n\n" +
|
||||
"```\n" +
|
||||
"{{.Output}}" +
|
||||
"```\n" +
|
||||
"</details>"))
|
||||
var unwrappedErrTmplText = "**{{.Command}} Error**\n" +
|
||||
"```\n" +
|
||||
"{{.Error}}\n" +
|
||||
"```" +
|
||||
"{{ if eq .Command \"Policy Check\" }}" +
|
||||
"\n* :heavy_check_mark: To **approve** failing policies an authorized approver can comment:\n" +
|
||||
" * `atlantis approve_policies`\n" +
|
||||
"* :repeat: Or, address the policy failure by modifying the codebase and re-planning.\n" +
|
||||
"{{ end }}"
|
||||
var wrappedErrTmplText = "**{{.Command}} Error**\n" +
|
||||
"<details><summary>Show Output</summary>\n\n" +
|
||||
"```\n" +
|
||||
"{{.Error}}\n" +
|
||||
"```\n</details>"
|
||||
var unwrappedErrTmpl = template.Must(template.New("").Parse(unwrappedErrTmplText))
|
||||
var unwrappedErrWithLogTmpl = template.Must(template.New("").Parse(unwrappedErrTmplText + logTmpl))
|
||||
var wrappedErrTmpl = template.Must(template.New("").Parse(wrappedErrTmplText))
|
||||
var failureTmplText = "**{{.Command}} Failed**: {{.Failure}}"
|
||||
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"
|
||||
|
||||
@@ -16,6 +16,7 @@ package events_test
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -56,7 +57,7 @@ func TestRenderErr(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
r := events.MarkdownRenderer{}
|
||||
r := events.GetMarkdownRenderer(false, false, false, false, false, false, "")
|
||||
for _, c := range cases {
|
||||
res := command.Result{
|
||||
Error: c.Error,
|
||||
@@ -101,7 +102,7 @@ func TestRenderFailure(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
r := events.MarkdownRenderer{}
|
||||
r := events.GetMarkdownRenderer(false, false, false, false, false, false, "")
|
||||
for _, c := range cases {
|
||||
res := command.Result{
|
||||
Failure: c.Failure,
|
||||
@@ -120,7 +121,7 @@ func TestRenderFailure(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRenderErrAndFailure(t *testing.T) {
|
||||
r := events.MarkdownRenderer{}
|
||||
r := events.GetMarkdownRenderer(false, false, false, false, false, false, "")
|
||||
res := command.Result{
|
||||
Error: errors.New("error"),
|
||||
Failure: "failure",
|
||||
@@ -750,7 +751,7 @@ $$$
|
||||
},
|
||||
}
|
||||
|
||||
r := events.MarkdownRenderer{}
|
||||
r := events.GetMarkdownRenderer(false, false, false, false, false, false, "")
|
||||
for _, c := range cases {
|
||||
t.Run(c.Description, func(t *testing.T) {
|
||||
res := command.Result{
|
||||
@@ -901,9 +902,15 @@ $$$
|
||||
`,
|
||||
},
|
||||
}
|
||||
r := events.MarkdownRenderer{
|
||||
DisableApplyAll: true,
|
||||
}
|
||||
r := events.GetMarkdownRenderer(
|
||||
false, // GitlabSupportsCommonMark
|
||||
true, // DisableApplyAll
|
||||
false, // DisableApply
|
||||
false, // DisableMarkdownFolding
|
||||
false, // DisableRepoLocking
|
||||
false, // EnableDiffMarkdownFormat
|
||||
"", // MarkdownTemplateOverridesDir
|
||||
)
|
||||
for _, c := range cases {
|
||||
t.Run(c.Description, func(t *testing.T) {
|
||||
res := command.Result{
|
||||
@@ -1046,10 +1053,16 @@ $$$
|
||||
`,
|
||||
},
|
||||
}
|
||||
r := events.MarkdownRenderer{
|
||||
DisableApplyAll: true,
|
||||
DisableApply: true,
|
||||
}
|
||||
|
||||
r := events.GetMarkdownRenderer(
|
||||
false, // GitlabSupportsCommonMark
|
||||
true, // DisableApplyAll
|
||||
true, // DisableApply
|
||||
false, // DisableMarkdownFolding
|
||||
false, // DisableRepoLocking
|
||||
false, // EnableDiffMarkdownFormat
|
||||
"", // MarkdownTemplateOverridesDir
|
||||
)
|
||||
for _, c := range cases {
|
||||
t.Run(c.Description, func(t *testing.T) {
|
||||
res := command.Result{
|
||||
@@ -1070,11 +1083,55 @@ $$$
|
||||
}
|
||||
}
|
||||
|
||||
// Run policy check with a custom template to validate custom template rendering.
|
||||
func TestRenderCustomPolicyCheckTemplate_DisableApplyAll(t *testing.T) {
|
||||
tmpDir, cleanup := TempDir(t)
|
||||
filePath := fmt.Sprintf("%s/templates.tmpl", tmpDir)
|
||||
_, err := os.Create(filePath)
|
||||
Ok(t, err)
|
||||
err = os.WriteFile(filePath, []byte("{{ define \"policyCheckSuccessUnwrapped\" -}}somecustometext{{- end}}\n"), 0600)
|
||||
Ok(t, err)
|
||||
defer cleanup()
|
||||
r := events.GetMarkdownRenderer(
|
||||
false, // GitlabSupportsCommonMark
|
||||
true, // DisableApplyAll
|
||||
true, // DisableApply
|
||||
false, // DisableMarkdownFolding
|
||||
false, // DisableRepoLocking
|
||||
false, // EnableDiffMarkdownFormat
|
||||
tmpDir, // MarkdownTemplateOverridesDir
|
||||
)
|
||||
|
||||
rendered := r.Render(command.Result{
|
||||
ProjectResults: []command.ProjectResult{
|
||||
{
|
||||
Workspace: "workspace",
|
||||
RepoRelDir: "path",
|
||||
PolicyCheckSuccess: &models.PolicyCheckSuccess{
|
||||
PolicyCheckOutput: "4 tests, 4 passed, 0 warnings, 0 failures, 0 exceptions",
|
||||
LockURL: "lock-url",
|
||||
ApplyCmd: "atlantis apply -d path -w workspace",
|
||||
RePlanCmd: "atlantis plan -d path -w workspace",
|
||||
},
|
||||
},
|
||||
},
|
||||
}, command.PolicyCheck, "log", false, models.Github)
|
||||
fmt.Println(rendered)
|
||||
Equals(t, rendered, "Ran Policy Check for dir: `path` workspace: `workspace`\n\nsomecustometext\n\n\n")
|
||||
|
||||
}
|
||||
|
||||
// Test that if folding is disabled that it's not used.
|
||||
func TestRenderProjectResults_DisableFolding(t *testing.T) {
|
||||
mr := events.MarkdownRenderer{
|
||||
DisableMarkdownFolding: true,
|
||||
}
|
||||
mr := events.GetMarkdownRenderer(
|
||||
false, // GitlabSupportsCommonMark
|
||||
false, // DisableApplyAll
|
||||
false, // DisableApply
|
||||
true, // DisableMarkdownFolding
|
||||
false, // DisableRepoLocking
|
||||
false, // EnableDiffMarkdownFormat
|
||||
"", // MarkdownTemplateOverridesDir
|
||||
)
|
||||
|
||||
rendered := mr.Render(command.Result{
|
||||
ProjectResults: []command.ProjectResult{
|
||||
@@ -1156,9 +1213,15 @@ func TestRenderProjectResults_WrappedErr(t *testing.T) {
|
||||
for _, c := range cases {
|
||||
t.Run(fmt.Sprintf("%s_%v", c.VCSHost.String(), c.ShouldWrap),
|
||||
func(t *testing.T) {
|
||||
mr := events.MarkdownRenderer{
|
||||
GitlabSupportsCommonMark: c.GitlabCommonMarkSupport,
|
||||
}
|
||||
mr := events.GetMarkdownRenderer(
|
||||
c.GitlabCommonMarkSupport, // GitlabSupportsCommonMark
|
||||
false, // DisableApplyAll
|
||||
false, // DisableApply
|
||||
false, // DisableMarkdownFolding
|
||||
false, // DisableRepoLocking
|
||||
false, // EnableDiffMarkdownFormat
|
||||
"", // MarkdownTemplateOverridesDir
|
||||
)
|
||||
|
||||
rendered := mr.Render(command.Result{
|
||||
ProjectResults: []command.ProjectResult{
|
||||
@@ -1268,9 +1331,15 @@ func TestRenderProjectResults_WrapSingleProject(t *testing.T) {
|
||||
for _, cmd := range []command.Name{command.Plan, command.Apply} {
|
||||
t.Run(fmt.Sprintf("%s_%s_%v", c.VCSHost.String(), cmd.String(), c.ShouldWrap),
|
||||
func(t *testing.T) {
|
||||
mr := events.MarkdownRenderer{
|
||||
GitlabSupportsCommonMark: c.GitlabCommonMarkSupport,
|
||||
}
|
||||
mr := events.GetMarkdownRenderer(
|
||||
c.GitlabCommonMarkSupport, // GitlabSupportsCommonMark
|
||||
false, // DisableApplyAll
|
||||
false, // DisableApply
|
||||
false, // DisableMarkdownFolding
|
||||
false, // DisableRepoLocking
|
||||
false, // EnableDiffMarkdownFormat
|
||||
"", // MarkdownTemplateOverridesDir
|
||||
)
|
||||
var pr command.ProjectResult
|
||||
switch cmd {
|
||||
case command.Plan:
|
||||
@@ -1373,7 +1442,15 @@ $$$
|
||||
}
|
||||
|
||||
func TestRenderProjectResults_MultiProjectApplyWrapped(t *testing.T) {
|
||||
mr := events.MarkdownRenderer{}
|
||||
mr := events.GetMarkdownRenderer(
|
||||
false, // GitlabSupportsCommonMark
|
||||
false, // DisableApplyAll
|
||||
false, // DisableApply
|
||||
false, // DisableMarkdownFolding
|
||||
false, // DisableRepoLocking
|
||||
false, // EnableDiffMarkdownFormat
|
||||
"", // MarkdownTemplateOverridesDir
|
||||
)
|
||||
tfOut := strings.Repeat("line\n", 13)
|
||||
rendered := mr.Render(command.Result{
|
||||
ProjectResults: []command.ProjectResult{
|
||||
@@ -1419,7 +1496,15 @@ $$$
|
||||
}
|
||||
|
||||
func TestRenderProjectResults_MultiProjectPlanWrapped(t *testing.T) {
|
||||
mr := events.MarkdownRenderer{}
|
||||
mr := events.GetMarkdownRenderer(
|
||||
false, // GitlabSupportsCommonMark
|
||||
false, // DisableApplyAll
|
||||
false, // DisableApply
|
||||
false, // DisableMarkdownFolding
|
||||
false, // DisableRepoLocking
|
||||
false, // EnableDiffMarkdownFormat
|
||||
"", // MarkdownTemplateOverridesDir
|
||||
)
|
||||
tfOut := strings.Repeat("line\n", 13) + "Plan: 1 to add, 0 to change, 0 to destroy."
|
||||
rendered := mr.Render(command.Result{
|
||||
ProjectResults: []command.ProjectResult{
|
||||
@@ -1592,7 +1677,15 @@ This plan was not saved because one or more projects failed and automerge requir
|
||||
|
||||
for name, c := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
mr := events.MarkdownRenderer{}
|
||||
mr := events.GetMarkdownRenderer(
|
||||
false, // GitlabSupportsCommonMark
|
||||
false, // DisableApplyAll
|
||||
false, // DisableApply
|
||||
false, // DisableMarkdownFolding
|
||||
false, // DisableRepoLocking
|
||||
false, // EnableDiffMarkdownFormat
|
||||
"", // MarkdownTemplateOverridesDir
|
||||
)
|
||||
rendered := mr.Render(c.cr, command.Plan, "log", false, models.Github)
|
||||
expWithBackticks := strings.Replace(c.exp, "$", "`", -1)
|
||||
Equals(t, expWithBackticks, rendered)
|
||||
@@ -2052,7 +2145,15 @@ $$$
|
||||
},
|
||||
}
|
||||
|
||||
r := events.MarkdownRenderer{}
|
||||
r := events.GetMarkdownRenderer(
|
||||
false, // GitlabSupportsCommonMark
|
||||
false, // DisableApplyAll
|
||||
false, // DisableApply
|
||||
false, // DisableMarkdownFolding
|
||||
false, // DisableRepoLocking
|
||||
false, // EnableDiffMarkdownFormat
|
||||
"", // MarkdownTemplateOverridesDir
|
||||
)
|
||||
r.DisableRepoLocking = true
|
||||
for _, c := range cases {
|
||||
t.Run(c.Description, func(t *testing.T) {
|
||||
@@ -2481,11 +2582,16 @@ Plan: 1 to add, 2 to change, 1 to destroy.
|
||||
`,
|
||||
},
|
||||
}
|
||||
r := events.MarkdownRenderer{
|
||||
DisableApplyAll: true,
|
||||
DisableApply: true,
|
||||
EnableDiffMarkdownFormat: true,
|
||||
}
|
||||
r := events.GetMarkdownRenderer(
|
||||
false, // GitlabSupportsCommonMark
|
||||
true, // DisableApplyAll
|
||||
true, // DisableApply
|
||||
false, // DisableMarkdownFolding
|
||||
false, // DisableRepoLocking
|
||||
true, // EnableDiffMarkdownFormat
|
||||
"", // MarkdownTemplateOverridesDir
|
||||
)
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.Description, func(t *testing.T) {
|
||||
res := command.Result{
|
||||
|
||||
5
server/events/templates/apply_unwrapped_success.tmpl
Normal file
5
server/events/templates/apply_unwrapped_success.tmpl
Normal file
@@ -0,0 +1,5 @@
|
||||
{{ define "applyUnwrappedSuccess" -}}
|
||||
```diff
|
||||
{{.Output}}
|
||||
```
|
||||
{{- end }}
|
||||
6
server/events/templates/apply_wrapped_success.tmpl
Normal file
6
server/events/templates/apply_wrapped_success.tmpl
Normal file
@@ -0,0 +1,6 @@
|
||||
{{ define "applyWrappedSuccess" -}}
|
||||
<details><summary>Show Output</summary>
|
||||
|
||||
{{ template "applyUnwrappedSuccess" . }}
|
||||
</details>
|
||||
{{- end }}
|
||||
7
server/events/templates/approve_all_projects.tmpl
Normal file
7
server/events/templates/approve_all_projects.tmpl
Normal file
@@ -0,0 +1,7 @@
|
||||
{{ define "approveAllProjects" -}}
|
||||
Approved Policies for {{ len .Results }} projects:
|
||||
|
||||
{{ range $result := .Results }}1. {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`
|
||||
{{end}}
|
||||
{{ template "log" . }}
|
||||
{{ end }}
|
||||
5
server/events/templates/diverged.tmpl
Normal file
5
server/events/templates/diverged.tmpl
Normal file
@@ -0,0 +1,5 @@
|
||||
{{ define "diverged" -}}
|
||||
{{ if .HasDiverged }}
|
||||
|
||||
:warning: The branch we're merging into is ahead, it is recommended to pull new commits first.{{end}}
|
||||
{{- end }}
|
||||
3
server/events/templates/failure.tmpl
Normal file
3
server/events/templates/failure.tmpl
Normal file
@@ -0,0 +1,3 @@
|
||||
{{ define "failure" -}}
|
||||
**{{.Command}} Failed**: {{.Failure}}
|
||||
{{- end }}
|
||||
3
server/events/templates/failure_with_log.tmpl
Normal file
3
server/events/templates/failure_with_log.tmpl
Normal file
@@ -0,0 +1,3 @@
|
||||
{{ define "failureWithLog" -}}
|
||||
{{ template "failure" . }}{{ template "log" . }}
|
||||
{{ end }}
|
||||
9
server/events/templates/log.tmpl
Normal file
9
server/events/templates/log.tmpl
Normal file
@@ -0,0 +1,9 @@
|
||||
{{ define "log" -}}
|
||||
{{if .Verbose}}
|
||||
<details><summary>Log</summary>
|
||||
<p>
|
||||
|
||||
```
|
||||
{{.Log}}```
|
||||
</p></details>{{end}}
|
||||
{{- end }}
|
||||
8
server/events/templates/multi_project_apply.tmpl
Normal file
8
server/events/templates/multi_project_apply.tmpl
Normal file
@@ -0,0 +1,8 @@
|
||||
{{ define "multiProjectApply" -}}
|
||||
{{ template "multiProjectHeader" . }}
|
||||
{{ range $i, $result := .Results }}### {{add $i 1}}. {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`
|
||||
{{$result.Rendered}}
|
||||
|
||||
---
|
||||
{{end}}{{ template "log" . }}
|
||||
{{ end }}
|
||||
6
server/events/templates/multi_project_header.tmpl
Normal file
6
server/events/templates/multi_project_header.tmpl
Normal file
@@ -0,0 +1,6 @@
|
||||
{{ define "multiProjectHeader" -}}
|
||||
Ran {{.Command}} for {{ len .Results }} projects:
|
||||
|
||||
{{ range $result := .Results }}1. {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`
|
||||
{{end}}
|
||||
{{- end }}
|
||||
11
server/events/templates/multi_project_plan.tmpl
Normal file
11
server/events/templates/multi_project_plan.tmpl
Normal file
@@ -0,0 +1,11 @@
|
||||
{{ define "multiProjectPlan" -}}
|
||||
{{ template "multiProjectHeader" . }}
|
||||
{{ $disableApplyAll := .DisableApplyAll }}{{ range $i, $result := .Results }}### {{add $i 1}}. {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`
|
||||
{{$result.Rendered}}
|
||||
|
||||
{{ if ne $disableApplyAll true }}---
|
||||
{{end}}{{end}}{{ if ne .DisableApplyAll true }}{{ if and (gt (len .Results) 0) (not .PlansDeleted) }}* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
|
||||
* `atlantis apply`
|
||||
* :put_litter_in_its_place: To delete all plans and locks for the PR, comment:
|
||||
* `atlantis unlock`{{end}}{{end}}{{ template "log" . }}
|
||||
{{ end }}
|
||||
3
server/events/templates/multi_project_version.tmpl
Normal file
3
server/events/templates/multi_project_version.tmpl
Normal file
@@ -0,0 +1,3 @@
|
||||
{{ define "multiProjectVersion" -}}
|
||||
{{ template "multiProjectApply" . }}
|
||||
{{- end }}
|
||||
11
server/events/templates/plan_success_unwrapped.tmpl
Normal file
11
server/events/templates/plan_success_unwrapped.tmpl
Normal file
@@ -0,0 +1,11 @@
|
||||
{{ define "planSuccessUnwrapped" -}}
|
||||
```diff
|
||||
{{ if .EnableDiffMarkdownFormat }}{{.DiffMarkdownFormattedTerraformOutput}}{{else}}{{.TerraformOutput}}{{end}}
|
||||
```
|
||||
|
||||
{{ if .PlanWasDeleted }}This plan was not saved because one or more projects failed and automerge requires all plans pass.{{ else }}{{ if not .DisableApply }}* :arrow_forward: To **apply** this plan, comment:
|
||||
* `{{.ApplyCmd}}`
|
||||
{{end}}{{ if not .DisableRepoLocking }}* :put_litter_in_its_place: To **delete** this plan click [here]({{.LockURL}})
|
||||
{{end}}* :repeat: To **plan** this project again, comment:
|
||||
* `{{.RePlanCmd}}`{{end}}{{ template "diverged" . }}
|
||||
{{- end }}
|
||||
15
server/events/templates/plan_success_wrapped.tmpl
Normal file
15
server/events/templates/plan_success_wrapped.tmpl
Normal file
@@ -0,0 +1,15 @@
|
||||
{{ define "planSuccessWrapped" -}}
|
||||
<details><summary>Show Output</summary>
|
||||
|
||||
```diff
|
||||
{{ if .EnableDiffMarkdownFormat }}{{.DiffMarkdownFormattedTerraformOutput}}{{else}}{{.TerraformOutput}}{{end}}
|
||||
```
|
||||
|
||||
{{ if .PlanWasDeleted }}This plan was not saved because one or more projects failed and automerge requires all plans pass.{{ else }}{{ if not .DisableApply }}* :arrow_forward: To **apply** this plan, comment:
|
||||
* `{{.ApplyCmd}}`
|
||||
{{end}}{{ if not .DisableRepoLocking }}* :put_litter_in_its_place: To **delete** this plan click [here]({{.LockURL}})
|
||||
{{end}}* :repeat: To **plan** this project again, comment:
|
||||
* `{{.RePlanCmd}}`{{end}}
|
||||
</details>
|
||||
{{.PlanSummary}}{{ template "diverged" . }}
|
||||
{{- end }}
|
||||
11
server/events/templates/policy_check_success_unwrapped.tmpl
Normal file
11
server/events/templates/policy_check_success_unwrapped.tmpl
Normal file
@@ -0,0 +1,11 @@
|
||||
{{ define "policyCheckSuccessUnwrapped" -}}
|
||||
```diff
|
||||
{{.PolicyCheckOutput}}
|
||||
```
|
||||
|
||||
* :arrow_forward: To **apply** this plan, comment:
|
||||
* `{{.ApplyCmd}}`
|
||||
* :put_litter_in_its_place: To **delete** this plan click [here]({{.LockURL}})
|
||||
* :repeat: To re-run policies **plan** this project again by commenting:
|
||||
* `{{.RePlanCmd}}`{{ template "diverged" . }}
|
||||
{{- end }}
|
||||
14
server/events/templates/policy_check_success_wrapped.tmpl
Normal file
14
server/events/templates/policy_check_success_wrapped.tmpl
Normal file
@@ -0,0 +1,14 @@
|
||||
{{ define "policyCheckSuccessWrapped" -}}
|
||||
<details><summary>Show Output</summary>
|
||||
|
||||
```diff
|
||||
{{.PolicyCheckOutput}}
|
||||
```
|
||||
|
||||
* :arrow_forward: To **apply** this plan, comment:
|
||||
* `{{.ApplyCmd}}`
|
||||
* :put_litter_in_its_place: To **delete** this plan click [here]({{.LockURL}})
|
||||
* :repeat: To re-run policies **plan** this project again by commenting:
|
||||
* `{{.RePlanCmd}}`
|
||||
</details>{{ template "diverged" . }}
|
||||
{{- end }}
|
||||
6
server/events/templates/single_project_apply.tmpl
Normal file
6
server/events/templates/single_project_apply.tmpl
Normal file
@@ -0,0 +1,6 @@
|
||||
{{ define "singleProjectApply" -}}
|
||||
{{$result := index .Results 0}}Ran {{.Command}} for {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`
|
||||
|
||||
{{$result.Rendered}}
|
||||
{{ template "log" . }}
|
||||
{{ end }}
|
||||
11
server/events/templates/single_project_plan_success.tmpl
Normal file
11
server/events/templates/single_project_plan_success.tmpl
Normal file
@@ -0,0 +1,11 @@
|
||||
{{ define "singleProjectPlanSuccess" -}}
|
||||
{{$result := index .Results 0}}Ran {{.Command}} for {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`
|
||||
|
||||
{{$result.Rendered}}
|
||||
|
||||
{{ if ne .DisableApplyAll true }}---
|
||||
* :fast_forward: To **apply** all unapplied plans from this pull request, comment:
|
||||
* `atlantis apply`
|
||||
* :put_litter_in_its_place: To delete all plans and locks for the PR, comment:
|
||||
* `atlantis unlock`{{ end }}{{ template "log" . }}
|
||||
{{ end }}
|
||||
@@ -0,0 +1,6 @@
|
||||
{{ define "singleProjectPlanUnsuccessful" -}}
|
||||
{{$result := index .Results 0}}Ran {{.Command}} for dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`
|
||||
|
||||
{{$result.Rendered}}
|
||||
{{ template "log" . }}
|
||||
{{ end }}
|
||||
@@ -0,0 +1,6 @@
|
||||
{{ define "singleProjectVersionSuccess" -}}
|
||||
{{$result := index .Results 0}}Ran {{.Command}} for {{ if $result.ProjectName }}project: `{{$result.ProjectName}}` {{ end }}dir: `{{$result.RepoRelDir}}` workspace: `{{$result.Workspace}}`
|
||||
|
||||
{{$result.Rendered}}
|
||||
{{ template "log" . }}
|
||||
{{ end }}
|
||||
@@ -0,0 +1,3 @@
|
||||
{{ define "singleProjectVersionUnsuccessful" -}}
|
||||
{{ template "singleProjectPlanUnsuccessful" . }}
|
||||
{{- end }}
|
||||
10
server/events/templates/unwrapped_err.tmpl
Normal file
10
server/events/templates/unwrapped_err.tmpl
Normal file
@@ -0,0 +1,10 @@
|
||||
{{ define "unwrappedErr" -}}
|
||||
**{{.Command}} Error**
|
||||
```
|
||||
{{.Error}}
|
||||
```{{ if eq .Command "Policy Check" }}
|
||||
* :heavy_check_mark: To **approve** failing policies an authorized approver can comment:
|
||||
* `atlantis approve_policies`
|
||||
* :repeat: Or, address the policy failure by modifying the codebase and re-planning.
|
||||
{{ end }}
|
||||
{{- end }}
|
||||
3
server/events/templates/unwrapped_err_with_log.tmpl
Normal file
3
server/events/templates/unwrapped_err_with_log.tmpl
Normal file
@@ -0,0 +1,3 @@
|
||||
{{ define "unwrappedErrWithLog" -}}
|
||||
{{ template "unwrappedErr" . }}{{ template "log" . }}
|
||||
{{ end }}
|
||||
5
server/events/templates/version_unwrapped_success.tmpl
Normal file
5
server/events/templates/version_unwrapped_success.tmpl
Normal file
@@ -0,0 +1,5 @@
|
||||
{{ define "versionUnwrappedSuccess" -}}
|
||||
```
|
||||
{{.Output}}
|
||||
```
|
||||
{{ end }}
|
||||
6
server/events/templates/version_wrapped_success.tmpl
Normal file
6
server/events/templates/version_wrapped_success.tmpl
Normal file
@@ -0,0 +1,6 @@
|
||||
{{ define "versionWrappedSuccess" -}}
|
||||
<details><summary>Show Output</summary>
|
||||
|
||||
{{ template "versionUnwrappedSuccess" . }}
|
||||
</details>
|
||||
{{- end }}
|
||||
9
server/events/templates/wrapped_err.tmpl
Normal file
9
server/events/templates/wrapped_err.tmpl
Normal file
@@ -0,0 +1,9 @@
|
||||
{{ define "wrappedErr" -}}
|
||||
**{{.Command}} Error**
|
||||
<details><summary>Show Output</summary>
|
||||
|
||||
```
|
||||
{{.Error}}
|
||||
```
|
||||
</details>
|
||||
{{- end }}
|
||||
@@ -389,14 +389,15 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) {
|
||||
if err != nil && flag.Lookup("test.v") == nil {
|
||||
return nil, errors.Wrap(err, "initializing terraform")
|
||||
}
|
||||
markdownRenderer := &events.MarkdownRenderer{
|
||||
GitlabSupportsCommonMark: gitlabClient.SupportsCommonMark(),
|
||||
DisableApplyAll: userConfig.DisableApplyAll,
|
||||
DisableMarkdownFolding: userConfig.DisableMarkdownFolding,
|
||||
DisableApply: userConfig.DisableApply,
|
||||
DisableRepoLocking: userConfig.DisableRepoLocking,
|
||||
EnableDiffMarkdownFormat: userConfig.EnableDiffMarkdownFormat,
|
||||
}
|
||||
markdownRenderer := events.GetMarkdownRenderer(
|
||||
gitlabClient.SupportsCommonMark(),
|
||||
userConfig.DisableApplyAll,
|
||||
userConfig.DisableMarkdownFolding,
|
||||
userConfig.DisableApply,
|
||||
userConfig.DisableRepoLocking,
|
||||
userConfig.EnableDiffMarkdownFormat,
|
||||
userConfig.MarkdownTemplateOverridesDir,
|
||||
)
|
||||
|
||||
var lockingClient locking.Locker
|
||||
var applyLockingClient locking.ApplyLocker
|
||||
|
||||
@@ -51,6 +51,7 @@ type UserConfig struct {
|
||||
HidePrevPlanComments bool `mapstructure:"hide-prev-plan-comments"`
|
||||
LockingDBType string `mapstructure:"locking-db-type"`
|
||||
LogLevel string `mapstructure:"log-level"`
|
||||
MarkdownTemplateOverridesDir string `mapstructure:"markdown-template-overrides-dir"`
|
||||
ParallelPoolSize int `mapstructure:"parallel-pool-size"`
|
||||
StatsNamespace string `mapstructure:"stats-namespace"`
|
||||
PlanDrafts bool `mapstructure:"allow-draft-prs"`
|
||||
|
||||
Reference in New Issue
Block a user