Skip to content

Commit

Permalink
feat: add a pending status for apply when running plan command (#2053)
Browse files Browse the repository at this point in the history
* add a pending status for apply when running plan command

* fix status updater logic, we should only update the status after we check if the PR is mergeable like the doc next to it says

* do not dismiss the PR if the only our "atlantis/apply" status is pending/failing

* fix logic and tests

* linting
  • Loading branch information
AndreZiviani authored Mar 4, 2022
1 parent 534ccb0 commit 1a7cc36
Show file tree
Hide file tree
Showing 6 changed files with 297 additions and 5 deletions.
8 changes: 4 additions & 4 deletions server/events/apply_command_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,6 @@ func (a *ApplyCommandRunner) Run(ctx *CommandContext, cmd *CommentCommand) {
return
}

if err = a.commitStatusUpdater.UpdateCombined(baseRepo, pull, models.PendingCommitStatus, cmd.CommandName()); err != nil {
ctx.Log.Warn("unable to update commit status: %s", err)
}

// Get the mergeable status before we set any build statuses of our own.
// We do this here because when we set a "Pending" status, if users have
// required the Atlantis status checks to pass, then we've now changed
Expand All @@ -111,6 +107,10 @@ func (a *ApplyCommandRunner) Run(ctx *CommandContext, cmd *CommentCommand) {
ctx.Log.Warn("unable to get pull request status: %s. Continuing with mergeable and approved assumed false", err)
}

if err = a.commitStatusUpdater.UpdateCombined(baseRepo, pull, models.PendingCommitStatus, cmd.CommandName()); err != nil {
ctx.Log.Warn("unable to update commit status: %s", err)
}

var projectCmds []models.ProjectCommandContext
projectCmds, err = a.prjCmdBuilder.BuildApplyCommands(ctx, cmd)

Expand Down
13 changes: 12 additions & 1 deletion server/events/plan_command_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,10 @@ func (p *PlanCommandRunner) runAutoplan(ctx *CommandContext) {

// At this point we are sure Atlantis has work to do, so set commit status to pending
if err := p.commitStatusUpdater.UpdateCombined(ctx.Pull.BaseRepo, ctx.Pull, models.PendingCommitStatus, models.PlanCommand); err != nil {
ctx.Log.Warn("unable to update commit status: %s", err)
ctx.Log.Warn("unable to update plan commit status: %s", err)
}
if err := p.commitStatusUpdater.UpdateCombinedCount(ctx.Pull.BaseRepo, ctx.Pull, models.PendingCommitStatus, models.ApplyCommand, 0, len(projectCmds)); err != nil {
ctx.Log.Warn("unable to update apply commit status: %s", err)
}

// Only run commands in parallel if enabled
Expand Down Expand Up @@ -179,6 +182,14 @@ func (p *PlanCommandRunner) run(ctx *CommandContext, cmd *CommentCommand) {

projectCmds, policyCheckCmds := p.partitionProjectCmds(ctx, projectCmds)

// At this point we are sure Atlantis has work to do, so set commit status to pending
if err := p.commitStatusUpdater.UpdateCombined(ctx.Pull.BaseRepo, ctx.Pull, models.PendingCommitStatus, models.PlanCommand); err != nil {
ctx.Log.Warn("unable to update plan commit status: %s", err)
}
if err := p.commitStatusUpdater.UpdateCombinedCount(ctx.Pull.BaseRepo, ctx.Pull, models.PendingCommitStatus, models.ApplyCommand, 0, len(projectCmds)); err != nil {
ctx.Log.Warn("unable to update apply commit status: %s", err)
}

// Only run commands in parallel if enabled
var result CommandResult
if p.isParallelEnabled(projectCmds) {
Expand Down
77 changes: 77 additions & 0 deletions server/events/vcs/fixtures/github-commit-status-empty.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
{
"state": "pending",
"statuses": [

],
"sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e",
"total_count": 0,
"repository": {
"id": 1296269,
"node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5",
"name": "Hello-World",
"full_name": "octocat/Hello-World",
"private": false,
"owner": {
"login": "octocat",
"id": 583231,
"node_id": "MDQ6VXNlcjU4MzIzMQ==",
"avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": false
},
"html_url": "https://github.com/octocat/Hello-World",
"description": "My first repository on GitHub!",
"fork": false,
"url": "https://api.github.com/repos/octocat/Hello-World",
"forks_url": "https://api.github.com/repos/octocat/Hello-World/forks",
"keys_url": "https://api.github.com/repos/octocat/Hello-World/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/octocat/Hello-World/teams",
"hooks_url": "https://api.github.com/repos/octocat/Hello-World/hooks",
"issue_events_url": "https://api.github.com/repos/octocat/Hello-World/issues/events{/number}",
"events_url": "https://api.github.com/repos/octocat/Hello-World/events",
"assignees_url": "https://api.github.com/repos/octocat/Hello-World/assignees{/user}",
"branches_url": "https://api.github.com/repos/octocat/Hello-World/branches{/branch}",
"tags_url": "https://api.github.com/repos/octocat/Hello-World/tags",
"blobs_url": "https://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/octocat/Hello-World/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/octocat/Hello-World/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/octocat/Hello-World/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/octocat/Hello-World/statuses/{sha}",
"languages_url": "https://api.github.com/repos/octocat/Hello-World/languages",
"stargazers_url": "https://api.github.com/repos/octocat/Hello-World/stargazers",
"contributors_url": "https://api.github.com/repos/octocat/Hello-World/contributors",
"subscribers_url": "https://api.github.com/repos/octocat/Hello-World/subscribers",
"subscription_url": "https://api.github.com/repos/octocat/Hello-World/subscription",
"commits_url": "https://api.github.com/repos/octocat/Hello-World/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/octocat/Hello-World/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/octocat/Hello-World/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/octocat/Hello-World/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/octocat/Hello-World/contents/{+path}",
"compare_url": "https://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/octocat/Hello-World/merges",
"archive_url": "https://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/octocat/Hello-World/downloads",
"issues_url": "https://api.github.com/repos/octocat/Hello-World/issues{/number}",
"pulls_url": "https://api.github.com/repos/octocat/Hello-World/pulls{/number}",
"milestones_url": "https://api.github.com/repos/octocat/Hello-World/milestones{/number}",
"notifications_url": "https://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/octocat/Hello-World/labels{/name}",
"releases_url": "https://api.github.com/repos/octocat/Hello-World/releases{/id}",
"deployments_url": "https://api.github.com/repos/octocat/Hello-World/deployments"
},
"commit_url": "https://api.github.com/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e",
"url": "https://api.github.com/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e/status"
}
148 changes: 148 additions & 0 deletions server/events/vcs/fixtures/github-commit-status-full.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
{
"state": "blocked",
"statuses": [
{
"url": "https://api.github.com/repos/octocat/Hello-World/statuses/6dcb09b5b57875f334f61aebed695e2e4193db5e",
"avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4",
"id": 16230299674,
"node_id": "SC_kwDOFRFvL88AAAADx2a4Gg",
"state": "success",
"description": "Plan succeeded.",
"target_url": "https://localhost/jobs/octocat/Hello-World/1/project1",
"context": "atlantis/plan: project1",
"created_at": "2022-02-10T15:26:01Z",
"updated_at": "2022-02-10T15:26:01Z"
},
{
"url": "https://api.github.com/repos/octocat/Hello-World/statuses/6dcb09b5b57875f334f61aebed695e2e4193db5e",
"avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4",
"id": 16230303174,
"node_id": "SC_kwDOFRFvL88AAAADx2bFxg",
"state": "success",
"description": "Plan succeeded.",
"target_url": "https://localhost/jobs/octocat/Hello-World/1/project2",
"context": "atlantis/plan: project2",
"created_at": "2022-02-10T15:26:12Z",
"updated_at": "2022-02-10T15:26:12Z"
},
{
"url": "https://api.github.com/repos/octocat/Hello-World/statuses/6dcb09b5b57875f334f61aebed695e2e4193db5e",
"avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4",
"id": 16230303679,
"node_id": "SC_kwDOFRFvL88AAAADx2bHvw",
"state": "success",
"description": "2/2 projects planned successfully.",
"target_url": "",
"context": "atlantis/plan",
"created_at": "2022-02-10T15:26:13Z",
"updated_at": "2022-02-10T15:26:13Z"
},
{
"url": "https://api.github.com/repos/octocat/Hello-World/statuses/6dcb09b5b57875f334f61aebed695e2e4193db5e",
"avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4",
"id": 16230307923,
"node_id": "SC_kwDOFRFvL88AAAADx2bYUw",
"state": "failure",
"description": "Apply failed.",
"target_url": "https://localhost/jobs/octocat/Hello-World/1/project1",
"context": "atlantis/apply: project1",
"created_at": "2022-02-10T15:26:27Z",
"updated_at": "2022-02-10T15:26:27Z"
},
{
"url": "https://api.github.com/repos/octocat/Hello-World/statuses/6dcb09b5b57875f334f61aebed695e2e4193db5e",
"avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4",
"id": 16230308153,
"node_id": "SC_kwDOFRFvL88AAAADx2bZOQ",
"state": "failure",
"description": "Apply failed.",
"target_url": "https://localhost/jobs/octocat/Hello-World/1/project2",
"context": "atlantis/apply: project2",
"created_at": "2022-02-10T15:26:27Z",
"updated_at": "2022-02-10T15:26:27Z"
},
{
"url": "https://api.github.com/repos/octocat/Hello-World/statuses/6dcb09b5b57875f334f61aebed695e2e4193db5e",
"avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4",
"id": 16230308528,
"node_id": "SC_kwDOFRFvL88AAAADx2basA",
"state": "failure",
"description": "0/2 projects applied successfully.",
"target_url": "",
"context": "atlantis/apply",
"created_at": "2022-02-10T15:26:28Z",
"updated_at": "2022-02-10T15:26:28Z"
}
],
"sha": "6dcb09b5b57875f334f61aebed695e2e4193db5e",
"total_count": 0,
"repository": {
"id": 1296269,
"node_id": "MDEwOlJlcG9zaXRvcnkxMjk2MjY5",
"name": "Hello-World",
"full_name": "octocat/Hello-World",
"private": false,
"owner": {
"login": "octocat",
"id": 583231,
"node_id": "MDQ6VXNlcjU4MzIzMQ==",
"avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4",
"gravatar_id": "",
"url": "https://api.github.com/users/octocat",
"html_url": "https://github.com/octocat",
"followers_url": "https://api.github.com/users/octocat/followers",
"following_url": "https://api.github.com/users/octocat/following{/other_user}",
"gists_url": "https://api.github.com/users/octocat/gists{/gist_id}",
"starred_url": "https://api.github.com/users/octocat/starred{/owner}{/repo}",
"subscriptions_url": "https://api.github.com/users/octocat/subscriptions",
"organizations_url": "https://api.github.com/users/octocat/orgs",
"repos_url": "https://api.github.com/users/octocat/repos",
"events_url": "https://api.github.com/users/octocat/events{/privacy}",
"received_events_url": "https://api.github.com/users/octocat/received_events",
"type": "User",
"site_admin": false
},
"html_url": "https://github.com/octocat/Hello-World",
"description": "My first repository on GitHub!",
"fork": false,
"url": "https://api.github.com/repos/octocat/Hello-World",
"forks_url": "https://api.github.com/repos/octocat/Hello-World/forks",
"keys_url": "https://api.github.com/repos/octocat/Hello-World/keys{/key_id}",
"collaborators_url": "https://api.github.com/repos/octocat/Hello-World/collaborators{/collaborator}",
"teams_url": "https://api.github.com/repos/octocat/Hello-World/teams",
"hooks_url": "https://api.github.com/repos/octocat/Hello-World/hooks",
"issue_events_url": "https://api.github.com/repos/octocat/Hello-World/issues/events{/number}",
"events_url": "https://api.github.com/repos/octocat/Hello-World/events",
"assignees_url": "https://api.github.com/repos/octocat/Hello-World/assignees{/user}",
"branches_url": "https://api.github.com/repos/octocat/Hello-World/branches{/branch}",
"tags_url": "https://api.github.com/repos/octocat/Hello-World/tags",
"blobs_url": "https://api.github.com/repos/octocat/Hello-World/git/blobs{/sha}",
"git_tags_url": "https://api.github.com/repos/octocat/Hello-World/git/tags{/sha}",
"git_refs_url": "https://api.github.com/repos/octocat/Hello-World/git/refs{/sha}",
"trees_url": "https://api.github.com/repos/octocat/Hello-World/git/trees{/sha}",
"statuses_url": "https://api.github.com/repos/octocat/Hello-World/statuses/{sha}",
"languages_url": "https://api.github.com/repos/octocat/Hello-World/languages",
"stargazers_url": "https://api.github.com/repos/octocat/Hello-World/stargazers",
"contributors_url": "https://api.github.com/repos/octocat/Hello-World/contributors",
"subscribers_url": "https://api.github.com/repos/octocat/Hello-World/subscribers",
"subscription_url": "https://api.github.com/repos/octocat/Hello-World/subscription",
"commits_url": "https://api.github.com/repos/octocat/Hello-World/commits{/sha}",
"git_commits_url": "https://api.github.com/repos/octocat/Hello-World/git/commits{/sha}",
"comments_url": "https://api.github.com/repos/octocat/Hello-World/comments{/number}",
"issue_comment_url": "https://api.github.com/repos/octocat/Hello-World/issues/comments{/number}",
"contents_url": "https://api.github.com/repos/octocat/Hello-World/contents/{+path}",
"compare_url": "https://api.github.com/repos/octocat/Hello-World/compare/{base}...{head}",
"merges_url": "https://api.github.com/repos/octocat/Hello-World/merges",
"archive_url": "https://api.github.com/repos/octocat/Hello-World/{archive_format}{/ref}",
"downloads_url": "https://api.github.com/repos/octocat/Hello-World/downloads",
"issues_url": "https://api.github.com/repos/octocat/Hello-World/issues{/number}",
"pulls_url": "https://api.github.com/repos/octocat/Hello-World/pulls{/number}",
"milestones_url": "https://api.github.com/repos/octocat/Hello-World/milestones{/number}",
"notifications_url": "https://api.github.com/repos/octocat/Hello-World/notifications{?since,all,participating}",
"labels_url": "https://api.github.com/repos/octocat/Hello-World/labels{/name}",
"releases_url": "https://api.github.com/repos/octocat/Hello-World/releases{/id}",
"deployments_url": "https://api.github.com/repos/octocat/Hello-World/deployments"
},
"commit_url": "https://api.github.com/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e",
"url": "https://api.github.com/repos/octocat/Hello-World/commits/6dcb09b5b57875f334f61aebed695e2e4193db5e/status"
}
28 changes: 28 additions & 0 deletions server/events/vcs/github_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,8 @@ func (g *GithubClient) PullIsMergeable(repo models.Repo, pull models.PullRequest
return false, errors.Wrap(err, "getting pull request")
}
state := githubPR.GetMergeableState()
status, _ := g.GetCombinedStatus(repo, githubPR.GetHead().GetSHA())

// We map our mergeable check to when the GitHub merge button is clickable.
// This corresponds to the following states:
// clean: No conflicts, all requirements satisfied.
Expand All @@ -299,9 +301,27 @@ func (g *GithubClient) PullIsMergeable(repo models.Repo, pull models.PullRequest
// has_hooks: GitHub Enterprise only, if a repo has custom pre-receive
// hooks. Merging is allowed (green box).
// See: https://github.com/octokit/octokit.net/issues/1763
//
// We should not dismiss the PR if the only our "atlantis/apply" status is pending/failing
if state == "blocked" {
applyStatus := false
for _, s := range status.Statuses {
if strings.Contains(s.GetContext(), "atlantis/apply") {
applyStatus = true
continue
}
if s.GetContext() != "atlantis/apply" && s.GetState() != "success" {
// If any other status is pending/failing mark as non-mergeable
return false, nil
}
}
return applyStatus, nil
}

if state != "clean" && state != "unstable" && state != "has_hooks" {
return false, nil
}

return true, nil
}

Expand Down Expand Up @@ -332,6 +352,14 @@ func (g *GithubClient) GetPullRequest(repo models.Repo, num int) (*github.PullRe
return pull, err
}

func (g *GithubClient) GetCombinedStatus(repo models.Repo, ref string) (*github.CombinedStatus, error) {
opts := github.ListOptions{
PerPage: 300,
}
status, _, err := g.client.Repositories.GetCombinedStatus(g.ctx, repo.Owner, repo.Name, ref, &opts)
return status, err
}

// UpdateStatus updates the status badge on the pull request.
// See https://github.com/blog/1227-commit-status-api.
func (g *GithubClient) UpdateStatus(repo models.Repo, pull models.PullRequest, state models.CommitStatus, src string, description string, url string) error {
Expand Down
Loading

0 comments on commit 1a7cc36

Please sign in to comment.