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

Commit

Permalink
Add repo-config command line argument (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
aknysh authored Oct 16, 2018
1 parent a22bda2 commit 18355c6
Show file tree
Hide file tree
Showing 12 changed files with 144 additions and 70 deletions.
18 changes: 17 additions & 1 deletion cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,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 @@ -67,6 +68,7 @@ const (
DefaultGitlabHostname = "gitlab.com"
DefaultLogLevel = "info"
DefaultPort = 4141
DefaultRepoConfig = "atlantis.yaml"
)

const redTermStart = "\033[31m"
Expand Down Expand Up @@ -163,6 +165,11 @@ var stringFlags = []stringFlag{
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. " +
"The format is {hostname}/{owner}/{repo}, ex. github.com/runatlantis/atlantis. '*' matches any characters until the next comma and can be used for example to whitelist " +
Expand All @@ -186,7 +193,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 @@ -379,6 +386,9 @@ func (s *ServerCmd) setDefaults(c *server.UserConfig) {
if c.GithubTeamWhitelist == "" {
c.GithubTeamWhitelist = DefaultGHTeamWhitelist
}
if c.RepoConfig == "" {
c.RepoConfig = DefaultRepoConfig
}
}

func (s *ServerCmd) validate(userConfig server.UserConfig) error {
Expand Down Expand Up @@ -424,6 +434,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
39 changes: 32 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 Down Expand Up @@ -592,7 +598,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 +614,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 +626,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 +642,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 +653,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 +669,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 +694,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 +707,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 Down Expand Up @@ -731,7 +741,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 +757,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 +768,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 +784,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 +834,19 @@ 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
14 changes: 12 additions & 2 deletions runatlantis.io/docs/server-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ Atlantis injects 5 Terraform variables that can be used to dynamically name the
Setting the `session_name` allows you to trace API calls made through Atlantis back to a specific
user and repo via CloudWatch:

```bash
```hcl
provider "aws" {
assume_role {
role_arn = "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME"
Expand All @@ -72,7 +72,7 @@ Atlantis runs `terraform` with the following variables:
If you want to use `assume_role` with Atlantis and you're also using the [S3 Backend](https://www.terraform.io/docs/backends/types/s3.html),
make sure to add the `role_arn` option:

```bash
```hcl
terraform {
backend "s3" {
bucket = "mybucket"
Expand All @@ -85,3 +85,13 @@ 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/cloudposse/atlantis/server/events/models"
"github.com/cloudposse/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 repo's 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 repo's 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

0 comments on commit 18355c6

Please sign in to comment.