Skip to content

Commit

Permalink
Merge pull request #427 from runatlantis/checkout-strategy
Browse files Browse the repository at this point in the history
Add new --checkout-strategy flag
  • Loading branch information
lkysow authored Jan 17, 2019
2 parents 3b7542b + 16a4946 commit a9d5fea
Show file tree
Hide file tree
Showing 18 changed files with 454 additions and 57 deletions.
2 changes: 0 additions & 2 deletions .gometalinter.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
"megacheck",
"safesql",
"structcheck",
"test",
"testify",
"unconvert",
"unparam",
"varcheck",
Expand Down
19 changes: 19 additions & 0 deletions cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ const (
BitbucketUserFlag = "bitbucket-user"
BitbucketWebhookSecretFlag = "bitbucket-webhook-secret"
ConfigFlag = "config"
CheckoutStrategyFlag = "checkout-strategy"
DataDirFlag = "data-dir"
GHHostnameFlag = "gh-hostname"
GHTokenFlag = "gh-token"
Expand All @@ -64,6 +65,7 @@ const (
TFETokenFlag = "tfe-token"

// Flag defaults.
DefaultCheckoutStrategy = "branch"
DefaultBitbucketBaseURL = bitbucketcloud.BaseURL
DefaultDataDir = "~/.atlantis"
DefaultGHHostname = "github.com"
Expand Down Expand Up @@ -103,6 +105,16 @@ var stringFlags = []stringFlag{
name: ConfigFlag,
description: "Path to config file. All flags can be set in a YAML config file instead.",
},
{
name: CheckoutStrategyFlag,
description: "How to check out pull requests. Accepts either 'branch' (default) or 'merge'." +
" If set to branch, Atlantis will check out the source branch of the pull request." +
" If set to merge, Atlantis will check out the destination branch of the pull request (ex. master)" +
" and then locally perform a git merge of the source branch." +
" This effectively means Atlantis operates on the repo as it will look" +
" after the pull request is merged.",
defaultValue: "branch",
},
{
name: DataDirFlag,
description: "Path to directory to store Atlantis data.",
Expand Down Expand Up @@ -372,6 +384,9 @@ func (s *ServerCmd) run() error {
}

func (s *ServerCmd) setDefaults(c *server.UserConfig) {
if c.CheckoutStrategy == "" {
c.CheckoutStrategy = DefaultCheckoutStrategy
}
if c.DataDir == "" {
c.DataDir = DefaultDataDir
}
Expand All @@ -397,6 +412,10 @@ func (s *ServerCmd) validate(userConfig server.UserConfig) error {
if logLevel != "debug" && logLevel != "info" && logLevel != "warn" && logLevel != "error" {
return errors.New("invalid log level: not one of debug, info, warn, error")
}
checkoutStrat := userConfig.CheckoutStrategy
if checkoutStrat != "branch" && checkoutStrat != "merge" {
return errors.New("invalid checkout strategy: not one of branch or merge")
}

if (userConfig.SSLKeyFile == "") != (userConfig.SSLCertFile == "") {
return fmt.Errorf("--%s and --%s are both required for ssl", SSLKeyFileFlag, SSLCertFileFlag)
Expand Down
22 changes: 22 additions & 0 deletions cmd/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,14 @@ func TestExecute_ValidateLogLevel(t *testing.T) {
Equals(t, "invalid log level: not one of debug, info, warn, error", err.Error())
}

func TestExecute_ValidateCheckoutStrategy(t *testing.T) {
c := setupWithDefaults(map[string]interface{}{
cmd.CheckoutStrategyFlag: "invalid",
})
err := c.Execute()
ErrEquals(t, "invalid checkout strategy: not one of branch or merge", err)
}

func TestExecute_ValidateSSLConfig(t *testing.T) {
expErr := "--ssl-key-file and --ssl-cert-file are both required for ssl"
cases := []struct {
Expand Down Expand Up @@ -331,6 +339,7 @@ func TestExecute_Defaults(t *testing.T) {
Ok(t, err)
Equals(t, dataDir, passedConfig.DataDir)

Equals(t, "branch", passedConfig.CheckoutStrategy)
Equals(t, "github.com", passedConfig.GithubHostname)
Equals(t, "token", passedConfig.GithubToken)
Equals(t, "user", passedConfig.GithubUser)
Expand Down Expand Up @@ -432,6 +441,7 @@ func TestExecute_Flags(t *testing.T) {
cmd.BitbucketTokenFlag: "bitbucket-token",
cmd.BitbucketUserFlag: "bitbucket-user",
cmd.BitbucketWebhookSecretFlag: "bitbucket-secret",
cmd.CheckoutStrategyFlag: "merge",
cmd.DataDirFlag: "/path",
cmd.GHHostnameFlag: "ghhostname",
cmd.GHTokenFlag: "token",
Expand Down Expand Up @@ -460,6 +470,7 @@ func TestExecute_Flags(t *testing.T) {
Equals(t, "bitbucket-token", passedConfig.BitbucketToken)
Equals(t, "bitbucket-user", passedConfig.BitbucketUser)
Equals(t, "bitbucket-secret", passedConfig.BitbucketWebhookSecret)
Equals(t, "merge", passedConfig.CheckoutStrategy)
Equals(t, "/path", passedConfig.DataDir)
Equals(t, "ghhostname", passedConfig.GithubHostname)
Equals(t, "token", passedConfig.GithubToken)
Expand Down Expand Up @@ -489,6 +500,7 @@ bitbucket-base-url: "https://mydomain.com"
bitbucket-token: "bitbucket-token"
bitbucket-user: "bitbucket-user"
bitbucket-webhook-secret: "bitbucket-secret"
checkout-strategy: "merge"
data-dir: "/path"
gh-hostname: "ghhostname"
gh-token: "token"
Expand Down Expand Up @@ -521,6 +533,7 @@ tfe-token: my-token
Equals(t, "bitbucket-token", passedConfig.BitbucketToken)
Equals(t, "bitbucket-user", passedConfig.BitbucketUser)
Equals(t, "bitbucket-secret", passedConfig.BitbucketWebhookSecret)
Equals(t, "merge", passedConfig.CheckoutStrategy)
Equals(t, "/path", passedConfig.DataDir)
Equals(t, "ghhostname", passedConfig.GithubHostname)
Equals(t, "token", passedConfig.GithubToken)
Expand Down Expand Up @@ -550,6 +563,7 @@ bitbucket-base-url: "https://mydomain.com"
bitbucket-token: "bitbucket-token"
bitbucket-user: "bitbucket-user"
bitbucket-webhook-secret: "bitbucket-secret"
checkout-strategy: "merge"
data-dir: "/path"
gh-hostname: "ghhostname"
gh-token: "token"
Expand Down Expand Up @@ -578,6 +592,7 @@ ssl-key-file: my-token
"BITBUCKET_TOKEN": "override-bitbucket-token",
"BITBUCKET_USER": "override-bitbucket-user",
"BITBUCKET_WEBHOOK_SECRET": "override-bitbucket-secret",
"CHECKOUT_STRATEGY": "branch",
"DATA_DIR": "/override-path",
"GH_HOSTNAME": "override-gh-hostname",
"GH_TOKEN": "override-gh-token",
Expand Down Expand Up @@ -610,6 +625,7 @@ ssl-key-file: my-token
Equals(t, "override-bitbucket-token", passedConfig.BitbucketToken)
Equals(t, "override-bitbucket-user", passedConfig.BitbucketUser)
Equals(t, "override-bitbucket-secret", passedConfig.BitbucketWebhookSecret)
Equals(t, "branch", passedConfig.CheckoutStrategy)
Equals(t, "/override-path", passedConfig.DataDir)
Equals(t, "override-gh-hostname", passedConfig.GithubHostname)
Equals(t, "override-gh-token", passedConfig.GithubToken)
Expand Down Expand Up @@ -639,6 +655,7 @@ bitbucket-base-url: "https://bitbucket-base-url"
bitbucket-token: "bitbucket-token"
bitbucket-user: "bitbucket-user"
bitbucket-webhook-secret: "bitbucket-secret"
checkout-strategy: "merge"
data-dir: "/path"
gh-hostname: "ghhostname"
gh-token: "token"
Expand Down Expand Up @@ -667,6 +684,7 @@ tfe-token: my-token
cmd.BitbucketTokenFlag: "override-bitbucket-token",
cmd.BitbucketUserFlag: "override-bitbucket-user",
cmd.BitbucketWebhookSecretFlag: "override-bitbucket-secret",
cmd.CheckoutStrategyFlag: "branch",
cmd.DataDirFlag: "/override-path",
cmd.GHHostnameFlag: "override-gh-hostname",
cmd.GHTokenFlag: "override-gh-token",
Expand All @@ -693,6 +711,7 @@ tfe-token: my-token
Equals(t, "override-bitbucket-token", passedConfig.BitbucketToken)
Equals(t, "override-bitbucket-user", passedConfig.BitbucketUser)
Equals(t, "override-bitbucket-secret", passedConfig.BitbucketWebhookSecret)
Equals(t, "branch", passedConfig.CheckoutStrategy)
Equals(t, "/override-path", passedConfig.DataDir)
Equals(t, "override-gh-hostname", passedConfig.GithubHostname)
Equals(t, "override-gh-token", passedConfig.GithubToken)
Expand Down Expand Up @@ -723,6 +742,7 @@ func TestExecute_FlagEnvVarOverride(t *testing.T) {
"BITBUCKET_TOKEN": "bitbucket-token",
"BITBUCKET_USER": "bitbucket-user",
"BITBUCKET_WEBHOOK_SECRET": "bitbucket-secret",
"CHECKOUT_STRATEGY": "merge",
"DATA_DIR": "/path",
"GH_HOSTNAME": "gh-hostname",
"GH_TOKEN": "gh-token",
Expand Down Expand Up @@ -759,6 +779,7 @@ func TestExecute_FlagEnvVarOverride(t *testing.T) {
cmd.BitbucketTokenFlag: "override-bitbucket-token",
cmd.BitbucketUserFlag: "override-bitbucket-user",
cmd.BitbucketWebhookSecretFlag: "override-bitbucket-secret",
cmd.CheckoutStrategyFlag: "branch",
cmd.DataDirFlag: "/override-path",
cmd.GHHostnameFlag: "override-gh-hostname",
cmd.GHTokenFlag: "override-gh-token",
Expand Down Expand Up @@ -787,6 +808,7 @@ func TestExecute_FlagEnvVarOverride(t *testing.T) {
Equals(t, "override-bitbucket-token", passedConfig.BitbucketToken)
Equals(t, "override-bitbucket-user", passedConfig.BitbucketUser)
Equals(t, "override-bitbucket-secret", passedConfig.BitbucketWebhookSecret)
Equals(t, "branch", passedConfig.CheckoutStrategy)
Equals(t, "/override-path", passedConfig.DataDir)
Equals(t, "override-gh-hostname", passedConfig.GithubHostname)
Equals(t, "override-gh-token", passedConfig.GithubToken)
Expand Down
3 changes: 2 additions & 1 deletion runatlantis.io/docs/atlantis-yaml-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,8 @@ override the built-in `plan`/`apply` commands, ex. `run: terraform plan -out $PL
* `BASE_REPO_OWNER` - Owner of the repository that the pull request will be merged into, ex. `runatlantis`.
* `HEAD_REPO_NAME` - Name of the repository that is getting merged into the base repository, ex. `atlantis`.
* `HEAD_REPO_OWNER` - Owner of the repository that is getting merged into the base repository, ex. `acme-corp`.
* `HEAD_BRANCH_NAME` - Name of the head branch of the pull request
* `HEAD_BRANCH_NAME` - Name of the head branch of the pull request (the branch that is getting merged into the base)
* `BASE_BRANCH_NAME` - Name of the base branch of the pull request (the branch that the pull request is getting merged into)
* `PULL_NUM` - Pull request number or ID, ex. `2`.
* `PULL_AUTHOR` - Username of the pull request author, ex. `acme-user`.
:::
Expand Down
25 changes: 18 additions & 7 deletions server/events/event_parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,8 @@ func (e *EventParser) parseCommonBitbucketCloudEventData(event bitbucketcloud.Co
Num: *event.PullRequest.ID,
HeadCommit: *event.PullRequest.Source.Commit.Hash,
URL: *event.PullRequest.Links.HTML.HREF,
Branch: *event.PullRequest.Source.Branch.Name,
HeadBranch: *event.PullRequest.Source.Branch.Name,
BaseBranch: *event.PullRequest.Destination.Branch.Name,
Author: *event.Actor.Username,
State: prState,
BaseRepo: baseRepo,
Expand Down Expand Up @@ -417,11 +418,17 @@ func (e *EventParser) ParseGithubPull(pull *github.PullRequest) (pullModel model
err = errors.New("html_url is null")
return
}
branch := pull.Head.GetRef()
if branch == "" {
headBranch := pull.Head.GetRef()
if headBranch == "" {
err = errors.New("head.ref is null")
return
}
baseBranch := pull.Base.GetRef()
if baseBranch == "" {
err = errors.New("base.ref is null")
return
}

authorUsername := pull.User.GetLogin()
if authorUsername == "" {
err = errors.New("user.login is null")
Expand Down Expand Up @@ -449,12 +456,13 @@ func (e *EventParser) ParseGithubPull(pull *github.PullRequest) (pullModel model

pullModel = models.PullRequest{
Author: authorUsername,
Branch: branch,
HeadBranch: headBranch,
HeadCommit: commit,
URL: url,
Num: num,
State: pullState,
BaseRepo: baseRepo,
BaseBranch: baseBranch,
}
return
}
Expand Down Expand Up @@ -491,7 +499,8 @@ func (e *EventParser) ParseGitlabMergeRequestEvent(event gitlab.MergeEvent) (pul
Author: event.User.Username,
Num: event.ObjectAttributes.IID,
HeadCommit: event.ObjectAttributes.LastCommit.ID,
Branch: event.ObjectAttributes.SourceBranch,
HeadBranch: event.ObjectAttributes.SourceBranch,
BaseBranch: event.ObjectAttributes.TargetBranch,
State: modelState,
BaseRepo: baseRepo,
}
Expand Down Expand Up @@ -553,7 +562,8 @@ func (e *EventParser) ParseGitlabMergeRequest(mr *gitlab.MergeRequest, baseRepo
Author: mr.Author.Username,
Num: mr.IID,
HeadCommit: mr.SHA,
Branch: mr.SourceBranch,
HeadBranch: mr.SourceBranch,
BaseBranch: mr.TargetBranch,
State: pullState,
BaseRepo: baseRepo,
}
Expand Down Expand Up @@ -633,7 +643,8 @@ func (e *EventParser) parseCommonBitbucketServerEventData(event bitbucketserver.
Num: *event.PullRequest.ID,
HeadCommit: *event.PullRequest.FromRef.LatestCommit,
URL: fmt.Sprintf("%s/projects/%s/repos/%s/pull-requests/%d", e.BitbucketServerURL, *event.PullRequest.ToRef.Repository.Project.Key, *event.PullRequest.ToRef.Repository.Slug, *event.PullRequest.ID),
Branch: *event.PullRequest.FromRef.DisplayID,
HeadBranch: *event.PullRequest.FromRef.DisplayID,
BaseBranch: *event.PullRequest.ToRef.DisplayID,
Author: *event.Actor.Username,
State: prState,
BaseRepo: baseRepo,
Expand Down
35 changes: 25 additions & 10 deletions server/events/event_parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ func TestParseGithubPullEvent(t *testing.T) {
Equals(t, models.PullRequest{
URL: Pull.GetHTMLURL(),
Author: Pull.User.GetLogin(),
Branch: Pull.Head.GetRef(),
HeadBranch: Pull.Head.GetRef(),
BaseBranch: Pull.Base.GetRef(),
HeadCommit: Pull.Head.GetSHA(),
Num: Pull.GetNumber(),
State: models.OpenPullState,
Expand Down Expand Up @@ -230,6 +231,11 @@ func TestParseGithubPull(t *testing.T) {
_, _, _, err = parser.ParseGithubPull(&testPull)
ErrEquals(t, "head.ref is null", err)

testPull = deepcopy.Copy(Pull).(github.PullRequest)
testPull.Base.Ref = nil
_, _, _, err = parser.ParseGithubPull(&testPull)
ErrEquals(t, "base.ref is null", err)

testPull = deepcopy.Copy(Pull).(github.PullRequest)
testPull.User.Login = nil
_, _, _, err = parser.ParseGithubPull(&testPull)
Expand All @@ -256,7 +262,8 @@ func TestParseGithubPull(t *testing.T) {
Equals(t, models.PullRequest{
URL: Pull.GetHTMLURL(),
Author: Pull.User.GetLogin(),
Branch: Pull.Head.GetRef(),
HeadBranch: Pull.Head.GetRef(),
BaseBranch: Pull.Base.GetRef(),
HeadCommit: Pull.Head.GetSHA(),
Num: Pull.GetNumber(),
State: models.OpenPullState,
Expand Down Expand Up @@ -294,7 +301,8 @@ func TestParseGitlabMergeEvent(t *testing.T) {
Author: "lkysow",
Num: 12,
HeadCommit: "d2eae324ca26242abca45d7b49d582cddb2a4f15",
Branch: "patch-1",
HeadBranch: "patch-1",
BaseBranch: "master",
State: models.OpenPullState,
BaseRepo: expBaseRepo,
}, pull)
Expand Down Expand Up @@ -350,7 +358,8 @@ func TestParseGitlabMergeEvent_Subgroup(t *testing.T) {
Author: "lkysow",
Num: 2,
HeadCommit: "901d9770ef1a6862e2a73ec1bacc73590abb9aff",
Branch: "patch",
HeadBranch: "patch",
BaseBranch: "master",
State: models.OpenPullState,
BaseRepo: expBaseRepo,
}, pull)
Expand Down Expand Up @@ -445,7 +454,8 @@ func TestParseGitlabMergeRequest(t *testing.T) {
Author: "lkysow",
Num: 8,
HeadCommit: "0b4ac85ea3063ad5f2974d10cd68dd1f937aaac2",
Branch: "abc",
HeadBranch: "abc",
BaseBranch: "master",
State: models.OpenPullState,
BaseRepo: repo,
}, pull)
Expand Down Expand Up @@ -483,7 +493,8 @@ func TestParseGitlabMergeRequest_Subgroup(t *testing.T) {
Author: "lkysow",
Num: 2,
HeadCommit: "901d9770ef1a6862e2a73ec1bacc73590abb9aff",
Branch: "patch",
HeadBranch: "patch",
BaseBranch: "master",
State: models.OpenPullState,
BaseRepo: repo,
}, pull)
Expand Down Expand Up @@ -707,7 +718,8 @@ func TestParseBitbucketCloudCommentEvent_ValidEvent(t *testing.T) {
Num: 2,
HeadCommit: "e0624da46d3a",
URL: "https://bitbucket.org/lkysow/atlantis-example/pull-requests/2",
Branch: "lkysow/maintf-edited-online-with-bitbucket-1532029690581",
HeadBranch: "lkysow/maintf-edited-online-with-bitbucket-1532029690581",
BaseBranch: "master",
Author: "lkysow",
State: models.ClosedPullState,
BaseRepo: expBaseRepo,
Expand Down Expand Up @@ -792,7 +804,8 @@ func TestParseBitbucketCloudPullEvent_ValidEvent(t *testing.T) {
Num: 2,
HeadCommit: "e0624da46d3a",
URL: "https://bitbucket.org/lkysow/atlantis-example/pull-requests/2",
Branch: "lkysow/maintf-edited-online-with-bitbucket-1532029690581",
HeadBranch: "lkysow/maintf-edited-online-with-bitbucket-1532029690581",
BaseBranch: "master",
Author: "lkysow",
State: models.ClosedPullState,
BaseRepo: expBaseRepo,
Expand Down Expand Up @@ -892,7 +905,8 @@ func TestParseBitbucketServerCommentEvent_ValidEvent(t *testing.T) {
Num: 1,
HeadCommit: "bfb1af1ba9c2a2fa84cd61af67e6e1b60a22e060",
URL: "http://mycorp.com:7490/projects/AT/repos/atlantis-example/pull-requests/1",
Branch: "branch",
HeadBranch: "branch",
BaseBranch: "master",
Author: "lkysow",
State: models.OpenPullState,
BaseRepo: expBaseRepo,
Expand Down Expand Up @@ -973,7 +987,8 @@ func TestParseBitbucketServerPullEvent_ValidEvent(t *testing.T) {
Num: 2,
HeadCommit: "86a574157f5a2dadaf595b9f06c70fdfdd039912",
URL: "http://mycorp.com:7490/projects/AT/repos/atlantis-example/pull-requests/2",
Branch: "branch",
HeadBranch: "branch",
BaseBranch: "master",
Author: "lkysow",
State: models.ClosedPullState,
BaseRepo: expBaseRepo,
Expand Down
2 changes: 1 addition & 1 deletion server/events/models/fixtures/fixtures.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import "github.com/runatlantis/atlantis/server/events/models"
var Pull = models.PullRequest{
Num: 1,
HeadCommit: "16ca62f65c18ff456c6ef4cacc8d4826e264bb17",
Branch: "branch",
HeadBranch: "branch",
Author: "lkysow",
URL: "url",
}
Expand Down
Loading

0 comments on commit a9d5fea

Please sign in to comment.