Skip to content
This repository has been archived by the owner on Sep 9, 2022. It is now read-only.

Support --repo-config flag #8

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ output
.terraform/
node_modules/
**/.vuepress/dist
helm/test-values.yaml
helm/test-values.yaml
server/testfixtures/test-repos/*/*.txt.act
19 changes: 18 additions & 1 deletion cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ const (
GitlabWebhookSecretFlag = "gitlab-webhook-secret" // nolint: gosec
LogLevelFlag = "log-level"
PortFlag = "port"
RepoConfigFlag = "repo-config"
RepoWhitelistFlag = "repo-whitelist"
RequireApprovalFlag = "require-approval"
SSLCertFileFlag = "ssl-cert-file"
Expand All @@ -65,6 +66,7 @@ const (
DefaultGitlabHostname = "gitlab.com"
DefaultLogLevel = "info"
DefaultPort = 4141
DefaultRepoConfig = "atlantis.yaml"
)

const redTermStart = "\033[31m"
Expand Down Expand Up @@ -151,6 +153,12 @@ var stringFlags = []stringFlag{
description: "Log level. Either debug, info, warn, or error.",
defaultValue: DefaultLogLevel,
},
{
name: RepoConfigFlag,
description: "Optional path to the Atlantis YAML config file contained in each repo that this server should use. " +
"This allows different Atlantis servers to point at different configs in the same repo.",
defaultValue: DefaultRepoConfig,
},
{
name: RepoWhitelistFlag,
description: "Comma separated list of repositories that Atlantis will operate on. " +
Expand All @@ -175,7 +183,7 @@ var boolFlags = []boolFlag{
},
{
name: AllowRepoConfigFlag,
description: "Allow repositories to use atlantis.yaml files to customize the commands Atlantis runs." +
description: "Allow repositories to use atlantis repo config YAML files to customize the commands Atlantis runs." +
" Should only be enabled in a trusted environment since it enables a pull request to run arbitrary commands" +
" on the Atlantis server.",
defaultValue: false,
Expand Down Expand Up @@ -365,6 +373,9 @@ func (s *ServerCmd) setDefaults(c *server.UserConfig) {
if c.Port == 0 {
c.Port = DefaultPort
}
if c.RepoConfig == "" {
c.RepoConfig = DefaultRepoConfig
}
}

func (s *ServerCmd) validate(userConfig server.UserConfig) error {
Expand Down Expand Up @@ -410,6 +421,12 @@ func (s *ServerCmd) validate(userConfig server.UserConfig) error {
if parsed.Scheme != "http" && parsed.Scheme != "https" {
return fmt.Errorf("--%s must have http:// or https://, got %q", BitbucketBaseURLFlag, userConfig.BitbucketBaseURL)
}

// Cannot accept custom repo config if we know repo configs are disabled
if (userConfig.RepoConfig != DefaultRepoConfig) && (!userConfig.AllowRepoConfig) {
return fmt.Errorf("custom --%s cannot be specified if --%s is false", RepoConfigFlag, AllowRepoConfigFlag)
}

return nil
}

Expand Down
42 changes: 35 additions & 7 deletions cmd/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,7 @@ func TestExecute_Defaults(t *testing.T) {
cmd.GitlabTokenFlag: "gitlab-token",
cmd.BitbucketUserFlag: "bitbucket-user",
cmd.BitbucketTokenFlag: "bitbucket-token",
cmd.RepoConfigFlag: "atlantis.yaml",
cmd.RepoWhitelistFlag: "*",
})
err := c.Execute()
Expand Down Expand Up @@ -441,6 +442,7 @@ func TestExecute_Flags(t *testing.T) {
cmd.GitlabWebhookSecretFlag: "gitlab-secret",
cmd.LogLevelFlag: "debug",
cmd.PortFlag: 8181,
cmd.RepoConfigFlag: "atlantis.yaml",
cmd.RepoWhitelistFlag: "github.com/runatlantis/atlantis",
cmd.RequireApprovalFlag: true,
cmd.SSLCertFileFlag: "cert-file",
Expand All @@ -467,6 +469,7 @@ func TestExecute_Flags(t *testing.T) {
Equals(t, "gitlab-secret", passedConfig.GitlabWebhookSecret)
Equals(t, "debug", passedConfig.LogLevel)
Equals(t, 8181, passedConfig.Port)
Equals(t, "atlantis.yaml", passedConfig.RepoConfig)
Equals(t, "github.com/runatlantis/atlantis", passedConfig.RepoWhitelist)
Equals(t, true, passedConfig.RequireApproval)
Equals(t, "cert-file", passedConfig.SSLCertFile)
Expand Down Expand Up @@ -494,6 +497,7 @@ gitlab-user: "gitlab-user"
gitlab-webhook-secret: "gitlab-secret"
log-level: "debug"
port: 8181
repo-config: "atlantis.yaml"
repo-whitelist: "github.com/runatlantis/atlantis"
require-approval: true
ssl-cert-file: cert-file
Expand Down Expand Up @@ -524,6 +528,7 @@ ssl-key-file: key-file
Equals(t, "gitlab-secret", passedConfig.GitlabWebhookSecret)
Equals(t, "debug", passedConfig.LogLevel)
Equals(t, 8181, passedConfig.Port)
Equals(t, "atlantis.yaml", passedConfig.RepoConfig)
Equals(t, "github.com/runatlantis/atlantis", passedConfig.RepoWhitelist)
Equals(t, true, passedConfig.RequireApproval)
Equals(t, "cert-file", passedConfig.SSLCertFile)
Expand Down Expand Up @@ -551,6 +556,7 @@ gitlab-user: "gitlab-user"
gitlab-webhook-secret: "gitlab-secret"
log-level: "debug"
port: 8181
repo-config: "atlantis.yaml"
repo-whitelist: "github.com/runatlantis/atlantis"
require-approval: true
ssl-cert-file: cert-file
Expand All @@ -562,7 +568,7 @@ ssl-key-file: key-file
for name, value := range map[string]string{
"ATLANTIS_URL": "override-url",
"ALLOW_FORK_PRS": "false",
"ALLOW_REPO_CONFIG": "false",
"ALLOW_REPO_CONFIG": "true",
"BITBUCKET_BASE_URL": "https://override-bitbucket-base-url",
"BITBUCKET_TOKEN": "override-bitbucket-token",
"BITBUCKET_USER": "override-bitbucket-user",
Expand All @@ -578,6 +584,7 @@ ssl-key-file: key-file
"GITLAB_WEBHOOK_SECRET": "override-gitlab-webhook-secret",
"LOG_LEVEL": "info",
"PORT": "8282",
"REPO_CONFIG": "override-atlantis.yaml",
"REPO_WHITELIST": "override,override",
"REQUIRE_APPROVAL": "false",
"SSL_CERT_FILE": "override-cert-file",
Expand All @@ -592,7 +599,7 @@ ssl-key-file: key-file
Ok(t, err)
Equals(t, "override-url", passedConfig.AtlantisURL)
Equals(t, false, passedConfig.AllowForkPRs)
Equals(t, false, passedConfig.AllowRepoConfig)
Equals(t, true, passedConfig.AllowRepoConfig)
Equals(t, "https://override-bitbucket-base-url", passedConfig.BitbucketBaseURL)
Equals(t, "override-bitbucket-token", passedConfig.BitbucketToken)
Equals(t, "override-bitbucket-user", passedConfig.BitbucketUser)
Expand All @@ -608,6 +615,7 @@ ssl-key-file: key-file
Equals(t, "override-gitlab-webhook-secret", passedConfig.GitlabWebhookSecret)
Equals(t, "info", passedConfig.LogLevel)
Equals(t, 8282, passedConfig.Port)
Equals(t, "override-atlantis.yaml", passedConfig.RepoConfig)
Equals(t, "override,override", passedConfig.RepoWhitelist)
Equals(t, false, passedConfig.RequireApproval)
Equals(t, "override-cert-file", passedConfig.SSLCertFile)
Expand All @@ -619,7 +627,7 @@ func TestExecute_FlagConfigOverride(t *testing.T) {
tmpFile := tempFile(t, `---
atlantis-url: "url"
allow-fork-prs: true
allow-repo-config: true
allow-repo-config: false
bitbucket-base-url: "https://bitbucket-base-url"
bitbucket-token: "bitbucket-token"
bitbucket-user: "bitbucket-user"
Expand All @@ -635,6 +643,7 @@ gitlab-user: "gitlab-user"
gitlab-webhook-secret: "gitlab-secret"
log-level: "debug"
port: 8181
repo-config: "atlantis.yaml"
repo-whitelist: "github.com/runatlantis/atlantis"
require-approval: true
ssl-cert-file: cert-file
Expand All @@ -645,7 +654,7 @@ ssl-key-file: key-file
c := setup(map[string]interface{}{
cmd.AtlantisURLFlag: "override-url",
cmd.AllowForkPRsFlag: false,
cmd.AllowRepoConfigFlag: false,
cmd.AllowRepoConfigFlag: true,
cmd.BitbucketBaseURLFlag: "https://override-bitbucket-base-url",
cmd.BitbucketTokenFlag: "override-bitbucket-token",
cmd.BitbucketUserFlag: "override-bitbucket-user",
Expand All @@ -661,6 +670,7 @@ ssl-key-file: key-file
cmd.GitlabWebhookSecretFlag: "override-gitlab-webhook-secret",
cmd.LogLevelFlag: "info",
cmd.PortFlag: 8282,
cmd.RepoConfigFlag: "override-atlantis.yaml",
cmd.RepoWhitelistFlag: "override,override",
cmd.RequireApprovalFlag: false,
cmd.SSLCertFileFlag: "override-cert-file",
Expand All @@ -685,6 +695,7 @@ ssl-key-file: key-file
Equals(t, "override-gitlab-webhook-secret", passedConfig.GitlabWebhookSecret)
Equals(t, "info", passedConfig.LogLevel)
Equals(t, 8282, passedConfig.Port)
Equals(t, "override-atlantis.yaml", passedConfig.RepoConfig)
Equals(t, "override,override", passedConfig.RepoWhitelist)
Equals(t, false, passedConfig.RequireApproval)
Equals(t, "override-cert-file", passedConfig.SSLCertFile)
Expand All @@ -697,7 +708,7 @@ func TestExecute_FlagEnvVarOverride(t *testing.T) {
envVars := map[string]string{
"ATLANTIS_URL": "url",
"ALLOW_FORK_PRS": "true",
"ALLOW_REPO_CONFIG": "true",
"ALLOW_REPO_CONFIG": "false",
"BITBUCKET_BASE_URL": "https://bitbucket-base-url",
"BITBUCKET_TOKEN": "bitbucket-token",
"BITBUCKET_USER": "bitbucket-user",
Expand All @@ -713,6 +724,7 @@ func TestExecute_FlagEnvVarOverride(t *testing.T) {
"GITLAB_WEBHOOK_SECRET": "gitlab-webhook-secret",
"LOG_LEVEL": "debug",
"PORT": "8181",
"REPO_CONFIG": "atlantis.yaml",
"REPO_WHITELIST": "*",
"REQUIRE_APPROVAL": "true",
"SSL_CERT_FILE": "cert-file",
Expand All @@ -731,7 +743,7 @@ func TestExecute_FlagEnvVarOverride(t *testing.T) {
c := setup(map[string]interface{}{
cmd.AtlantisURLFlag: "override-url",
cmd.AllowForkPRsFlag: false,
cmd.AllowRepoConfigFlag: false,
cmd.AllowRepoConfigFlag: true,
cmd.BitbucketBaseURLFlag: "https://override-bitbucket-base-url",
cmd.BitbucketTokenFlag: "override-bitbucket-token",
cmd.BitbucketUserFlag: "override-bitbucket-user",
Expand All @@ -747,6 +759,7 @@ func TestExecute_FlagEnvVarOverride(t *testing.T) {
cmd.GitlabWebhookSecretFlag: "override-gitlab-webhook-secret",
cmd.LogLevelFlag: "info",
cmd.PortFlag: 8282,
cmd.RepoConfigFlag: "override-atlantis.yaml",
cmd.RepoWhitelistFlag: "override,override",
cmd.RequireApprovalFlag: false,
cmd.SSLCertFileFlag: "override-cert-file",
Expand All @@ -757,7 +770,7 @@ func TestExecute_FlagEnvVarOverride(t *testing.T) {

Equals(t, "override-url", passedConfig.AtlantisURL)
Equals(t, false, passedConfig.AllowForkPRs)
Equals(t, false, passedConfig.AllowRepoConfig)
Equals(t, true, passedConfig.AllowRepoConfig)
Equals(t, "https://override-bitbucket-base-url", passedConfig.BitbucketBaseURL)
Equals(t, "override-bitbucket-token", passedConfig.BitbucketToken)
Equals(t, "override-bitbucket-user", passedConfig.BitbucketUser)
Expand All @@ -773,6 +786,7 @@ func TestExecute_FlagEnvVarOverride(t *testing.T) {
Equals(t, "override-gitlab-webhook-secret", passedConfig.GitlabWebhookSecret)
Equals(t, "info", passedConfig.LogLevel)
Equals(t, 8282, passedConfig.Port)
Equals(t, "override-atlantis.yaml", passedConfig.RepoConfig)
Equals(t, "override,override", passedConfig.RepoWhitelist)
Equals(t, false, passedConfig.RequireApproval)
Equals(t, "override-cert-file", passedConfig.SSLCertFile)
Expand Down Expand Up @@ -822,6 +836,20 @@ func TestExecute_BitbucketServerBaseURLPort(t *testing.T) {
Equals(t, "http://mydomain.com:7990", passedConfig.BitbucketBaseURL)
}

func TestExecute_RepoConfigWithoutAllowRepoConfig(t *testing.T) {
t.Log("Should error when repo-config provided and allow-repo-config false.")

c := setup(map[string]interface{}{
cmd.BitbucketUserFlag: "user",
cmd.BitbucketTokenFlag: "token",
cmd.RepoWhitelistFlag: "*",
cmd.AllowRepoConfigFlag: false,
cmd.RepoConfigFlag: "atlantis-stage.yaml",
})
err := c.Execute()
ErrEquals(t, "custom --repo-config cannot be specified if --allow-repo-config is false", err)
}

func setup(flags map[string]interface{}) *cobra.Command {
vipr := viper.New()
for k, v := range flags {
Expand Down
2 changes: 1 addition & 1 deletion helm/atlantis/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ image:
tag: v0.4.5
pullPolicy: IfNotPresent

## enable using atlantis.yaml file
## enable using atlantis repo config YAML files
allowRepoConfig: false

# We only need to check every 60s since Atlantis is not a high-throughput service.
Expand Down
7 changes: 7 additions & 0 deletions runatlantis.io/docs/server-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,3 +85,10 @@ terraform {
}
}
```

## Running Multiple Atlantis Servers Against The Same Repo

A common use case is to have separate production and staging Atlantis servers. You can achieve this by using multiple atlantis.yaml config files in the same repo and setting the `--repo-config` flag on each server. This allows you to launch a staging Atlantis server pointing at a staging atlantis.yaml file (e.g. `--repo-config atlantis-staging.yaml`) and a production Atlantis server pointing at a production atlantis.yaml file in the same repo (e.g. `--repo-config atlantis-production.yaml`).

This way you can use different credentials for staging and production and maintain cleaner separation between environments.

5 changes: 2 additions & 3 deletions server/events/comment_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (
"strings"

"github.com/runatlantis/atlantis/server/events/models"
"github.com/runatlantis/atlantis/server/events/yaml"
"github.com/spf13/pflag"
)

Expand Down Expand Up @@ -162,15 +161,15 @@ func (e *CommentParser) Parse(comment string, vcsHost models.VCSHostType) Commen
flagSet.SetOutput(ioutil.Discard)
flagSet.StringVarP(&workspace, workspaceFlagLong, workspaceFlagShort, "", "Switch to this Terraform workspace before planning.")
flagSet.StringVarP(&dir, dirFlagLong, dirFlagShort, "", "Which directory to run plan in relative to root of repo, ex. 'child/dir'.")
flagSet.StringVarP(&project, projectFlagLong, projectFlagShort, "", fmt.Sprintf("Which project to run plan for. Refers to the name of the project configured in %s. Cannot be used at same time as workspace or dir flags.", yaml.AtlantisYAMLFilename))
flagSet.StringVarP(&project, projectFlagLong, projectFlagShort, "", fmt.Sprintf("Which project to run plan for. Refers to the name of the project configured in the repos atlantis.yaml file. Cannot be used at same time as workspace or dir flags."))
flagSet.BoolVarP(&verbose, verboseFlagLong, verboseFlagShort, false, "Append Atlantis log to comment.")
case ApplyCommand.String():
name = ApplyCommand
flagSet = pflag.NewFlagSet(ApplyCommand.String(), pflag.ContinueOnError)
flagSet.SetOutput(ioutil.Discard)
flagSet.StringVarP(&workspace, workspaceFlagLong, workspaceFlagShort, "", "Apply the plan for this Terraform workspace.")
flagSet.StringVarP(&dir, dirFlagLong, dirFlagShort, "", "Apply the plan for this directory, relative to root of repo, ex. 'child/dir'.")
flagSet.StringVarP(&project, projectFlagLong, projectFlagShort, "", fmt.Sprintf("Apply the plan for this project. Refers to the name of the project configured in %s. Cannot be used at same time as workspace or dir flags.", yaml.AtlantisYAMLFilename))
flagSet.StringVarP(&project, projectFlagLong, projectFlagShort, "", fmt.Sprintf("Apply the plan for this project. Refers to the name of the project configured in the repos atlantis.yaml file. Cannot be used at same time as workspace or dir flags."))
flagSet.BoolVarP(&verbose, verboseFlagLong, verboseFlagShort, false, "Append Atlantis log to comment.")
default:
return CommentParseResult{CommentResponse: fmt.Sprintf("Error: unknown command %q – this is a bug", command)}
Expand Down
8 changes: 4 additions & 4 deletions server/events/comment_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -632,8 +632,8 @@ var PlanUsage = `Usage of plan:
-d, --dir string Which directory to run plan in relative to root of repo,
ex. 'child/dir'.
-p, --project string Which project to run plan for. Refers to the name of the
project configured in atlantis.yaml. Cannot be used at
same time as workspace or dir flags.
project configured in the repos atlantis.yaml file.
Cannot be used at same time as workspace or dir flags.
--verbose Append Atlantis log to comment.
-w, --workspace string Switch to this Terraform workspace before planning.
`
Expand All @@ -642,8 +642,8 @@ var ApplyUsage = `Usage of apply:
-d, --dir string Apply the plan for this directory, relative to root of
repo, ex. 'child/dir'.
-p, --project string Apply the plan for this project. Refers to the name of
the project configured in atlantis.yaml. Cannot be used
at same time as workspace or dir flags.
the project configured in the repos atlantis.yaml file.
Cannot be used at same time as workspace or dir flags.
--verbose Append Atlantis log to comment.
-w, --workspace string Apply the plan for this Terraform workspace.
`
Loading