Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce new mergeable requirement #385

Merged
merged 1 commit into from
Dec 12, 2018
Merged
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
6 changes: 6 additions & 0 deletions cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ const (
PortFlag = "port"
RepoWhitelistFlag = "repo-whitelist"
RequireApprovalFlag = "require-approval"
RequireMergeableFlag = "require-mergeable"
SilenceWhitelistErrorsFlag = "silence-whitelist-errors"
SSLCertFileFlag = "ssl-cert-file"
SSLKeyFileFlag = "ssl-key-file"
Expand Down Expand Up @@ -186,6 +187,11 @@ var boolFlags = []boolFlag{
description: "Require pull requests to be \"Approved\" before allowing the apply command to be run.",
defaultValue: false,
},
{
brndnmtthws marked this conversation as resolved.
Show resolved Hide resolved
name: RequireMergeableFlag,
description: "Require pull requests to be mergeable before allowing the apply command to be run.",
defaultValue: false,
},
{
name: SilenceWhitelistErrorsFlag,
description: "Silences the posting of whitelist error comments.",
Expand Down
13 changes: 13 additions & 0 deletions cmd/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ func TestExecute_Defaults(t *testing.T) {
Equals(t, "info", passedConfig.LogLevel)
Equals(t, 4141, passedConfig.Port)
Equals(t, false, passedConfig.RequireApproval)
Equals(t, false, passedConfig.RequireMergeable)
Equals(t, "", passedConfig.SSLCertFile)
Equals(t, "", passedConfig.SSLKeyFile)
}
Expand Down Expand Up @@ -443,6 +444,7 @@ func TestExecute_Flags(t *testing.T) {
cmd.PortFlag: 8181,
cmd.RepoWhitelistFlag: "github.com/runatlantis/atlantis",
cmd.RequireApprovalFlag: true,
cmd.RequireMergeableFlag: true,
cmd.SSLCertFileFlag: "cert-file",
cmd.SSLKeyFileFlag: "key-file",
})
Expand All @@ -469,6 +471,7 @@ func TestExecute_Flags(t *testing.T) {
Equals(t, 8181, passedConfig.Port)
Equals(t, "github.com/runatlantis/atlantis", passedConfig.RepoWhitelist)
Equals(t, true, passedConfig.RequireApproval)
Equals(t, true, passedConfig.RequireMergeable)
Equals(t, "cert-file", passedConfig.SSLCertFile)
Equals(t, "key-file", passedConfig.SSLKeyFile)
}
Expand Down Expand Up @@ -496,6 +499,7 @@ log-level: "debug"
port: 8181
repo-whitelist: "github.com/runatlantis/atlantis"
require-approval: true
require-mergeable: true
ssl-cert-file: cert-file
ssl-key-file: key-file
`)
Expand Down Expand Up @@ -526,6 +530,7 @@ ssl-key-file: key-file
Equals(t, 8181, passedConfig.Port)
Equals(t, "github.com/runatlantis/atlantis", passedConfig.RepoWhitelist)
Equals(t, true, passedConfig.RequireApproval)
Equals(t, true, passedConfig.RequireMergeable)
Equals(t, "cert-file", passedConfig.SSLCertFile)
Equals(t, "key-file", passedConfig.SSLKeyFile)
}
Expand Down Expand Up @@ -580,6 +585,7 @@ ssl-key-file: key-file
"PORT": "8282",
"REPO_WHITELIST": "override,override",
"REQUIRE_APPROVAL": "false",
"REQUIRE_MERGEABLE": "false",
"SSL_CERT_FILE": "override-cert-file",
"SSL_KEY_FILE": "override-key-file",
} {
Expand Down Expand Up @@ -610,6 +616,7 @@ ssl-key-file: key-file
Equals(t, 8282, passedConfig.Port)
Equals(t, "override,override", passedConfig.RepoWhitelist)
Equals(t, false, passedConfig.RequireApproval)
Equals(t, false, passedConfig.RequireMergeable)
Equals(t, "override-cert-file", passedConfig.SSLCertFile)
Equals(t, "override-key-file", passedConfig.SSLKeyFile)
}
Expand Down Expand Up @@ -637,6 +644,7 @@ log-level: "debug"
port: 8181
repo-whitelist: "github.com/runatlantis/atlantis"
require-approval: true
require-mergeable: true
ssl-cert-file: cert-file
ssl-key-file: key-file
`)
Expand All @@ -663,6 +671,7 @@ ssl-key-file: key-file
cmd.PortFlag: 8282,
cmd.RepoWhitelistFlag: "override,override",
cmd.RequireApprovalFlag: false,
cmd.RequireMergeableFlag: false,
cmd.SSLCertFileFlag: "override-cert-file",
cmd.SSLKeyFileFlag: "override-key-file",
})
Expand All @@ -687,6 +696,7 @@ ssl-key-file: key-file
Equals(t, 8282, passedConfig.Port)
Equals(t, "override,override", passedConfig.RepoWhitelist)
Equals(t, false, passedConfig.RequireApproval)
Equals(t, false, passedConfig.RequireMergeable)
Equals(t, "override-cert-file", passedConfig.SSLCertFile)
Equals(t, "override-key-file", passedConfig.SSLKeyFile)
}
Expand Down Expand Up @@ -715,6 +725,7 @@ func TestExecute_FlagEnvVarOverride(t *testing.T) {
"PORT": "8181",
"REPO_WHITELIST": "*",
"REQUIRE_APPROVAL": "true",
"REQUIRE_MERGEABLE": "true",
"SSL_CERT_FILE": "cert-file",
"SSL_KEY_FILE": "key-file",
}
Expand Down Expand Up @@ -749,6 +760,7 @@ func TestExecute_FlagEnvVarOverride(t *testing.T) {
cmd.PortFlag: 8282,
cmd.RepoWhitelistFlag: "override,override",
cmd.RequireApprovalFlag: false,
cmd.RequireMergeableFlag: false,
cmd.SSLCertFileFlag: "override-cert-file",
cmd.SSLKeyFileFlag: "override-key-file",
})
Expand All @@ -775,6 +787,7 @@ func TestExecute_FlagEnvVarOverride(t *testing.T) {
Equals(t, 8282, passedConfig.Port)
Equals(t, "override,override", passedConfig.RepoWhitelist)
Equals(t, false, passedConfig.RequireApproval)
Equals(t, false, passedConfig.RequireMergeable)
Equals(t, "override-cert-file", passedConfig.SSLCertFile)
Equals(t, "override-key-file", passedConfig.SSLKeyFile)
}
Expand Down
1 change: 0 additions & 1 deletion e2e/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,6 @@ func main() {
func createAtlantisWebhook(g *GithubClient, ownerName string, repoName string, hookURL string) (int, error) {
// create atlantis hook
atlantisHook := &github.Hook{
Name: github.String("web"),
Events: []string{"issue_comment", "pull_request", "push"},
Config: map[string]interface{}{
"url": hookURL,
Expand Down
16 changes: 16 additions & 0 deletions runatlantis.io/docs/apply-requirements.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
If you'd like to require pull/merge requests to be approved prior to a user running `atlantis apply` simply run Atlantis with the `--require-approval` flag.
By default, no approval is required. If you want to configure this on a per-repo/project basis, for example to only require approvals for your production
configuration you must use an `atlantis.yaml` file:

```yaml
version: 2
projects:
Expand All @@ -23,6 +24,21 @@ Atlantis does not count that as an approval and requires at least one user that
is not the author of the pull request to approve it.
:::

## Mergeable

You may also set the `mergeable` requirement for pull/merge requests. A PR/MR must be marked as `mergeable` before a user is able to run `atlantis apply`. This is helpful in prevent certain edge cases, such as applying stale code in an outdated PR which has passed all other checks. You can enable this feature by passing the `--require-mergeable` flag to Atlantis, or by using an `atlantis.yaml` file like this:

```yaml
version: 2
projects:
- dir: .
apply_requirements: [mergeable, approved]
```

::: tip Note
The meaning of "mergeable" may be slightly different depending on your Git provider. In the case of GitHub and GitLab, it means that a PR/MR has no conflicts and satisfies all required approvals and checks. On BitBucket, it means that merging is possible and there are no conflicts.
:::

## Next Steps
* For more information on GitHub pull request reviews and approvals see: [https://help.github.com/articles/about-pull-request-reviews/](https://help.github.com/articles/about-pull-request-reviews/)
* For more information on GitLab merge request reviews and approvals (only supported on GitLab Enterprise) see: [https://docs.gitlab.com/ee/user/project/merge_requests/merge_request_approvals.html](https://docs.gitlab.com/ee/user/project/merge_requests/merge_request_approvals.html).
Expand Down
70 changes: 35 additions & 35 deletions runatlantis.io/docs/atlantis-yaml-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ projects:
autoplan:
when_modified: ["*.tf", "../modules/**.tf"]
enabled: true
apply_requirements: [approved]
apply_requirements: [mergeable, approved]
workflow: myworkflow
workflows:
myworkflow:
Expand Down Expand Up @@ -70,11 +70,11 @@ version:
projects:
workflows:
```
| Key | Type | Default | Required | Description |
| -------------| --- |-------------| -----|---|
| version | int | none | yes | This key is required and must be set to `2`|
| projects | array[[Project](atlantis-yaml-reference.html#project)] | [] | no | Lists the projects in this repo |
| workflows | map[string -> [Workflow](atlantis-yaml-reference.html#workflow)] | {} | no | Custom workflows |
| Key | Type | Default | Required | Description |
| --------- | ---------------------------------------------------------------- | ------- | -------- | ------------------------------------------- |
| version | int | none | yes | This key is required and must be set to `2` |
| projects | array[[Project](atlantis-yaml-reference.html#project)] | [] | no | Lists the projects in this repo |
| workflows | map[string -> [Workflow](atlantis-yaml-reference.html#workflow)] | {} | no | Custom workflows |

### Project
```yaml
Expand All @@ -87,15 +87,15 @@ apply_requirements: ["approved"]
workflow: myworkflow
```

| Key | Type | Default | Required | Description |
| -------------| --- |-------------| -----|---|
| name | string | none | maybe | Required if there is more than one project with the same `dir` and `workspace`. This project name can be used with the `-p` flag.|
| dir | string | none | yes | The directory of this project relative to the repo root. Use `.` for the root. For example if the project was under `./project1` then use `project1`|
| workspace | string| default | no | The [Terraform workspace](https://www.terraform.io/docs/state/workspaces.html) for this project. Atlantis will switch to this workplace when planning/applying and will create it if it doesn't exist.|
| autoplan | [Autoplan](atlantis-yaml-reference.html#autoplan) | none | no | A custom autoplan configuration. If not specified, will use the default algorithm. See [Autoplanning](autoplanning.html).|
| terraform_version | string | none | no | A specific Terraform version to use when running commands for this project. Requires there to be a binary in the Atlantis `PATH` with the name `terraform{VERSION}`, ex. `terraform0.11.0`|
| apply_requirements | array[string] | [] | no | Requirements that must be satisfied before `atlantis apply` can be run. Currently the only supported requirement is `approved`. See [Apply Requirements](apply-requirements.html#approved) for more details.|
| workflow | string | none | no | A custom workflow. If not specified, Atlantis will use its default workflow.|
| Key | Type | Default | Required | Description |
| ------------------ | ------------------------------------------------- | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| name | string | none | maybe | Required if there is more than one project with the same `dir` and `workspace`. This project name can be used with the `-p` flag. |
| dir | string | none | yes | The directory of this project relative to the repo root. Use `.` for the root. For example if the project was under `./project1` then use `project1` |
| workspace | string | default | no | The [Terraform workspace](https://www.terraform.io/docs/state/workspaces.html) for this project. Atlantis will switch to this workplace when planning/applying and will create it if it doesn't exist. |
| autoplan | [Autoplan](atlantis-yaml-reference.html#autoplan) | none | no | A custom autoplan configuration. If not specified, will use the default algorithm. See [Autoplanning](autoplanning.html). |
| terraform_version | string | none | no | A specific Terraform version to use when running commands for this project. Requires there to be a binary in the Atlantis `PATH` with the name `terraform{VERSION}`, ex. `terraform0.11.0` |
| apply_requirements | array[string] | [] | no | Requirements that must be satisfied before `atlantis apply` can be run. Currently the only supported requirements are `approved` and `mergeable`. See [Apply Requirements](apply-requirements.html) for more details. |
| workflow | string | none | no | A custom workflow. If not specified, Atlantis will use its default workflow. |

::: tip
A project represents a Terraform state. Typically, there is one state per directory and workspace however it's possible to
Expand All @@ -108,21 +108,21 @@ Atlantis supports this but requires the `name` key to be specified. See [atlanti
enabled: true
when_modified: ["*.tf"]
```
| Key | Type | Default | Required | Description |
| -------------| --- |-------------| -----|---|
| enabled | boolean | true | no | Whether autoplanning is enabled for this project. |
| when_modified | array[string] | no | no | Uses [.dockerignore](https://docs.docker.com/engine/reference/builder/#dockerignore-file) syntax. If any modified file in the pull request matches, this project will be planned. If not specified, Atlantis will use its own algorithm. See [Autoplanning](autoplanning.html). Paths are relative to the project's dir.|
| Key | Type | Default | Required | Description |
| ------------- | ------------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| enabled | boolean | true | no | Whether autoplanning is enabled for this project. |
| when_modified | array[string] | no | no | Uses [.dockerignore](https://docs.docker.com/engine/reference/builder/#dockerignore-file) syntax. If any modified file in the pull request matches, this project will be planned. If not specified, Atlantis will use its own algorithm. See [Autoplanning](autoplanning.html). Paths are relative to the project's dir. |

### Workflow
```yaml
plan:
apply:
```

| Key | Type | Default | Required | Description |
| -------------| --- |-------------| -----|---|
| plan | [Stage](atlantis-yaml-reference.html#stage) | `steps: [init, plan]` | no | How to plan for this project. |
| apply | [Stage](atlantis-yaml-reference.html#stage) | `steps: [apply]` | no | How to apply for this project. |
| Key | Type | Default | Required | Description |
| ----- | ------------------------------------------- | --------------------- | -------- | ------------------------------ |
| plan | [Stage](atlantis-yaml-reference.html#stage) | `steps: [init, plan]` | no | How to plan for this project. |
| apply | [Stage](atlantis-yaml-reference.html#stage) | `steps: [apply]` | no | How to apply for this project. |

### Stage
```yaml
Expand All @@ -133,9 +133,9 @@ steps:
extra_args: [-lock=false]
```

| Key | Type | Default | Required | Description |
| -------------| --- |-------------| -----|---|
| steps | array[[Step](atlantis-yaml-reference.html#step)] | `[]` | no | List of steps for this stage. If the steps key is empty, no steps will be run for this stage. |
| Key | Type | Default | Required | Description |
| ----- | ------------------------------------------------ | ------- | -------- | --------------------------------------------------------------------------------------------- |
| steps | array[[Step](atlantis-yaml-reference.html#step)] | `[]` | no | List of steps for this stage. If the steps key is empty, no steps will be run for this stage. |

### Step
#### Built-In Commands: init, plan, apply
Expand All @@ -145,9 +145,9 @@ Steps can be a single string for a built-in command.
- plan
- apply
```
| Key | Type | Default | Required | Description |
| -------------| --- |-------------| -----|---|
| init/plan/apply | string | none | no | Use a built-in command without additional configuration. Only `init`, `plan` and `apply` are supported||
| Key | Type | Default | Required | Description |
| --------------- | ------ | ------- | -------- | ------------------------------------------------------------------------------------------------------ |
| init/plan/apply | string | none | no | Use a built-in command without additional configuration. Only `init`, `plan` and `apply` are supported |

#### Built-In Command With Extra Args
A map from string to `extra_args` for a built-in command with extra arguments.
Expand All @@ -159,17 +159,17 @@ A map from string to `extra_args` for a built-in command with extra arguments.
- apply:
extra_args: [arg1, arg2]
```
| Key | Type | Default | Required | Description |
| -------------| --- |-------------| -----|---|
| init/plan/apply | map[`extra_args` -> array[string]] | none | no | Use a built-in command and append `extra_args`. Only `init`, `plan` and `apply` are supported as keys and only `extra_args` is supported as a value||
| Key | Type | Default | Required | Description |
| --------------- | ---------------------------------- | ------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| init/plan/apply | map[`extra_args` -> array[string]] | none | no | Use a built-in command and append `extra_args`. Only `init`, `plan` and `apply` are supported as keys and only `extra_args` is supported as a value |
#### Custom `run` Command
Or a custom command
```yaml
- run: custom-command
```
| Key | Type | Default | Required | Description |
| -------------| --- |-------------| -----|---|
| run | string| none | no | Run a custom command|
| Key | Type | Default | Required | Description |
| --- | ------ | ------- | -------- | -------------------- |
| run | string | none | no | Run a custom command |

::: tip
`run` steps are executed with the following environment variables:
Expand Down
Loading