Skip to content

Commit

Permalink
feat: set apply status to successful by default when result is 'No Ch…
Browse files Browse the repository at this point in the history
…anges'
  • Loading branch information
chroju committed Aug 2, 2023
1 parent d68b72d commit d50acbc
Show file tree
Hide file tree
Showing 11 changed files with 392 additions and 158 deletions.
21 changes: 8 additions & 13 deletions cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,14 @@ const (
RepoConfigFlag = "repo-config"
RepoConfigJSONFlag = "repo-config-json"
// RepoWhitelistFlag is deprecated for RepoAllowlistFlag.
RepoWhitelistFlag = "repo-whitelist"
RepoAllowlistFlag = "repo-allowlist"
RequireApprovalFlag = "require-approval"
RequireMergeableFlag = "require-mergeable"
SetAtlantisApplyCheckSuccessfulIfNoChanges = "set-atlantis-apply-check-successful-if-no-changes"
SilenceNoProjectsFlag = "silence-no-projects"
SilenceForkPRErrorsFlag = "silence-fork-pr-errors"
SilenceVCSStatusNoPlans = "silence-vcs-status-no-plans"
SilenceAllowlistErrorsFlag = "silence-allowlist-errors"
RepoWhitelistFlag = "repo-whitelist"
RepoAllowlistFlag = "repo-allowlist"
RequireApprovalFlag = "require-approval"
RequireMergeableFlag = "require-mergeable"
SilenceNoProjectsFlag = "silence-no-projects"
SilenceForkPRErrorsFlag = "silence-fork-pr-errors"
SilenceVCSStatusNoPlans = "silence-vcs-status-no-plans"
SilenceAllowlistErrorsFlag = "silence-allowlist-errors"
// SilenceWhitelistErrorsFlag is deprecated for SilenceAllowlistErrorsFlag.
SilenceWhitelistErrorsFlag = "silence-whitelist-errors"
SkipCloneNoChanges = "skip-clone-no-changes"
Expand Down Expand Up @@ -501,10 +500,6 @@ var boolFlags = map[string]boolFlag{
defaultValue: false,
hidden: true,
},
SetAtlantisApplyCheckSuccessfulIfNoChanges: {
description: "Set the `atlantis/apply` pull request status check to \"passing\" if \"No Changes\" are detected.",
defaultValue: false,
},
SilenceNoProjectsFlag: {
description: "Silences Atlants from responding to PRs when it finds no projects.",
defaultValue: false,
Expand Down
312 changes: 312 additions & 0 deletions log

Large diffs are not rendered by default.

10 changes: 0 additions & 10 deletions runatlantis.io/docs/server-configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -830,16 +830,6 @@ This is useful when you have many projects and want to keep the pull request cle
* Allowlist all repositories
* `--repo-allowlist='*'`

### `--set-atlantis-apply-check-successful-if-no-changes`
```bash
atlantis server --set-atlantis-apply-check-successful-if-no-changes
# or
ATLANTIS_SET_ATLANTIS_APPLY_CHECK_SUCCESSFUL_IF_NO_CHANGES=true
```
`--set-atlantis-apply-check-successful-if-no-changes` will set the `atlantis/apply` status check to "passing" on a VCS pull request if the `atlantis plan` command results in "No Changes".
This is useful, for example, when enabling auto-merge for pull requests that do not involve resource changes, such as automatic dependency updates.
Defaults to `false`.

### `--silence-fork-pr-errors`
```bash
atlantis server --silence-fork-pr-errors
Expand Down
2 changes: 0 additions & 2 deletions server/controllers/events/events_controller_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1425,7 +1425,6 @@ func setupE2E(t *testing.T, repoDir string, opt setupOption) (events_controllers
lockingClient,
discardApprovalOnPlan,
e2ePullReqStatusFetcher,
false,
)

applyCommandRunner := events.NewApplyCommandRunner(
Expand All @@ -1443,7 +1442,6 @@ func setupE2E(t *testing.T, repoDir string, opt setupOption) (events_controllers
silenceNoProjects,
false,
e2ePullReqStatusFetcher,
false,
)

approvePoliciesCommandRunner := events.NewApprovePoliciesCommandRunner(
Expand Down
10 changes: 2 additions & 8 deletions server/events/apply_command_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ func NewApplyCommandRunner(
SilenceNoProjects bool,
silenceVCSStatusNoProjects bool,
pullReqStatusFetcher vcs.PullReqStatusFetcher,
SetAtlantisApplyCheckSuccessfulIfNoChanges bool,
) *ApplyCommandRunner {
return &ApplyCommandRunner{
vcsClient: vcsClient,
Expand All @@ -39,7 +38,6 @@ func NewApplyCommandRunner(
SilenceNoProjects: SilenceNoProjects,
silenceVCSStatusNoProjects: silenceVCSStatusNoProjects,
pullReqStatusFetcher: pullReqStatusFetcher,
SetAtlantisApplyCheckSuccessfulIfNoChanges: SetAtlantisApplyCheckSuccessfulIfNoChanges,
}
}

Expand All @@ -61,8 +59,7 @@ type ApplyCommandRunner struct {
SilenceNoProjects bool
// SilenceVCSStatusNoPlans is whether any plan should set commit status if no projects
// are found
silenceVCSStatusNoProjects bool
SetAtlantisApplyCheckSuccessfulIfNoChanges bool
silenceVCSStatusNoProjects bool
}

func (a *ApplyCommandRunner) Run(ctx *command.Context, cmd *CommentCommand) {
Expand Down Expand Up @@ -202,10 +199,7 @@ func (a *ApplyCommandRunner) updateCommitStatus(ctx *command.Context, pullStatus
var numErrored int
status := models.SuccessCommitStatus

numSuccess = pullStatus.StatusCount(models.AppliedPlanStatus)
if a.SetAtlantisApplyCheckSuccessfulIfNoChanges {
numSuccess += pullStatus.StatusCount(models.PlannedNoChangesPlanStatus)
}
numSuccess = pullStatus.StatusCount(models.AppliedPlanStatus) + pullStatus.StatusCount(models.PlannedNoChangesPlanStatus)
numErrored = pullStatus.StatusCount(models.ErroredApplyStatus)

if numErrored > 0 {
Expand Down
38 changes: 7 additions & 31 deletions server/events/command_runner_internal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,14 @@ import (

func TestApplyUpdateCommitStatus(t *testing.T) {
cases := map[string]struct {
cmd command.Name
SetAtlantisApplyCheckSuccessfulIfNoChanges bool
pullStatus models.PullStatus
expStatus models.CommitStatus
expNumSuccess int
expNumTotal int
cmd command.Name
pullStatus models.PullStatus
expStatus models.CommitStatus
expNumSuccess int
expNumTotal int
}{
"apply, one pending": {
cmd: command.Apply,
SetAtlantisApplyCheckSuccessfulIfNoChanges: false,
pullStatus: models.PullStatus{
Projects: []models.ProjectStatus{
{
Expand All @@ -36,7 +34,6 @@ func TestApplyUpdateCommitStatus(t *testing.T) {
},
"apply, all successful": {
cmd: command.Apply,
SetAtlantisApplyCheckSuccessfulIfNoChanges: false,
pullStatus: models.PullStatus{
Projects: []models.ProjectStatus{
{
Expand All @@ -53,7 +50,6 @@ func TestApplyUpdateCommitStatus(t *testing.T) {
},
"apply, one errored, one pending": {
cmd: command.Apply,
SetAtlantisApplyCheckSuccessfulIfNoChanges: false,
pullStatus: models.PullStatus{
Projects: []models.ProjectStatus{
{
Expand All @@ -73,24 +69,6 @@ func TestApplyUpdateCommitStatus(t *testing.T) {
},
"apply, one planned no changes": {
cmd: command.Apply,
SetAtlantisApplyCheckSuccessfulIfNoChanges: false,
pullStatus: models.PullStatus{
Projects: []models.ProjectStatus{
{
Status: models.AppliedPlanStatus,
},
{
Status: models.PlannedNoChangesPlanStatus,
},
},
},
expStatus: models.PendingCommitStatus,
expNumSuccess: 1,
expNumTotal: 2,
},
"apply, one planned no changes, skip apply when no changes": {
cmd: command.Apply,
SetAtlantisApplyCheckSuccessfulIfNoChanges: true,
pullStatus: models.PullStatus{
Projects: []models.ProjectStatus{
{
Expand All @@ -111,8 +89,7 @@ func TestApplyUpdateCommitStatus(t *testing.T) {
t.Run(name, func(t *testing.T) {
csu := &MockCSU{}
cr := &ApplyCommandRunner{
commitStatusUpdater: csu,
SetAtlantisApplyCheckSuccessfulIfNoChanges: c.SetAtlantisApplyCheckSuccessfulIfNoChanges,
commitStatusUpdater: csu,
}
cr.updateCommitStatus(&command.Context{}, c.pullStatus)
Equals(t, models.Repo{}, csu.CalledRepo)
Expand Down Expand Up @@ -271,8 +248,7 @@ func TestPlanUpdateApplyCommitStatus(t *testing.T) {
t.Run(name, func(t *testing.T) {
csu := &MockCSU{}
cr := &PlanCommandRunner{
commitStatusUpdater: csu,
SetAtlantisApplyCheckSuccessfulIfNoChanges: true,
commitStatusUpdater: csu,
}
cr.updateCommitStatus(&command.Context{}, c.pullStatus, command.Apply)
Equals(t, models.Repo{}, csu.CalledRepo)
Expand Down
20 changes: 8 additions & 12 deletions server/events/command_runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,13 @@ var preWorkflowHooksCommandRunner events.PreWorkflowHooksCommandRunner
var postWorkflowHooksCommandRunner events.PostWorkflowHooksCommandRunner

type TestConfig struct {
parallelPoolSize int
SilenceNoProjects bool
silenceVCSStatusNoPlans bool
silenceVCSStatusNoProjects bool
StatusName string
discardApprovalOnPlan bool
SetAtlantisApplyCheckSuccessfulIfNoChanges bool
backend locking.Backend
parallelPoolSize int
SilenceNoProjects bool
silenceVCSStatusNoPlans bool
silenceVCSStatusNoProjects bool
StatusName string
discardApprovalOnPlan bool
backend locking.Backend
}

func setup(t *testing.T, options ...func(testConfig *TestConfig)) *vcsmocks.MockClient {
Expand All @@ -93,8 +92,7 @@ func setup(t *testing.T, options ...func(testConfig *TestConfig)) *vcsmocks.Mock
SilenceNoProjects: false,
StatusName: "atlantis-test",
discardApprovalOnPlan: false,
SetAtlantisApplyCheckSuccessfulIfNoChanges: false,
backend: defaultBoltDB,
backend: defaultBoltDB,
}

for _, op := range options {
Expand Down Expand Up @@ -163,7 +161,6 @@ func setup(t *testing.T, options ...func(testConfig *TestConfig)) *vcsmocks.Mock
lockingLocker,
testConfig.discardApprovalOnPlan,
pullReqStatusFetcher,
testConfig.SetAtlantisApplyCheckSuccessfulIfNoChanges,
)

applyCommandRunner = events.NewApplyCommandRunner(
Expand All @@ -181,7 +178,6 @@ func setup(t *testing.T, options ...func(testConfig *TestConfig)) *vcsmocks.Mock
testConfig.SilenceNoProjects,
testConfig.silenceVCSStatusNoProjects,
pullReqStatusFetcher,
testConfig.SetAtlantisApplyCheckSuccessfulIfNoChanges,
)

approvePoliciesCommandRunner = events.NewApprovePoliciesCommandRunner(
Expand Down
15 changes: 4 additions & 11 deletions server/events/plan_command_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ func NewPlanCommandRunner(
lockingLocker locking.Locker,
discardApprovalOnPlan bool,
pullReqStatusFetcher vcs.PullReqStatusFetcher,
SetAtlantisApplyCheckSuccessfulIfNoChanges bool,
) *PlanCommandRunner {
return &PlanCommandRunner{
silenceVCSStatusNoPlans: silenceVCSStatusNoPlans,
Expand All @@ -47,7 +46,6 @@ func NewPlanCommandRunner(
lockingLocker: lockingLocker,
DiscardApprovalOnPlan: discardApprovalOnPlan,
pullReqStatusFetcher: pullReqStatusFetcher,
SetAtlantisApplyCheckSuccessfulIfNoChanges: SetAtlantisApplyCheckSuccessfulIfNoChanges,
}
}

Expand Down Expand Up @@ -76,9 +74,8 @@ type PlanCommandRunner struct {
lockingLocker locking.Locker
// DiscardApprovalOnPlan controls if all already existing approvals should be removed/dismissed before executing
// a plan.
DiscardApprovalOnPlan bool
pullReqStatusFetcher vcs.PullReqStatusFetcher
SetAtlantisApplyCheckSuccessfulIfNoChanges bool
DiscardApprovalOnPlan bool
pullReqStatusFetcher vcs.PullReqStatusFetcher
}

func (p *PlanCommandRunner) runAutoplan(ctx *command.Context) {
Expand Down Expand Up @@ -152,9 +149,7 @@ func (p *PlanCommandRunner) runAutoplan(ctx *command.Context) {
}

p.updateCommitStatus(ctx, pullStatus, command.Plan)
if p.SetAtlantisApplyCheckSuccessfulIfNoChanges {
p.updateCommitStatus(ctx, pullStatus, command.Apply)
}
p.updateCommitStatus(ctx, pullStatus, command.Apply)

// Check if there are any planned projects and if there are any errors or if plans are being deleted
if len(policyCheckCmds) > 0 &&
Expand Down Expand Up @@ -279,9 +274,7 @@ func (p *PlanCommandRunner) run(ctx *command.Context, cmd *CommentCommand) {
}

p.updateCommitStatus(ctx, pullStatus, command.Plan)
if p.SetAtlantisApplyCheckSuccessfulIfNoChanges {
p.updateCommitStatus(ctx, pullStatus, command.Apply)
}
p.updateCommitStatus(ctx, pullStatus, command.Apply)

// Runs policy checks step after all plans are successful.
// This step does not approve any policies that require approval.
Expand Down
Loading

0 comments on commit d50acbc

Please sign in to comment.