Skip to content

Commit

Permalink
Add mergeable requirement.
Browse files Browse the repository at this point in the history
Introduce new `mergeable` requirement, in similar vein to the `approved`
requirement. Ran `make go-generate` to update mocks accordingly.

This addresses issue #43.
  • Loading branch information
Brenden Matthews committed Dec 11, 2018
1 parent 27eb577 commit e001353
Show file tree
Hide file tree
Showing 25 changed files with 640 additions and 87 deletions.
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,
},
{
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

0 comments on commit e001353

Please sign in to comment.