Skip to content

Commit

Permalink
fix: requested changes: commit status resets, misc fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
GenPage committed Apr 5, 2021
1 parent 000eb52 commit 6eb3d01
Show file tree
Hide file tree
Showing 8 changed files with 212 additions and 94 deletions.
99 changes: 56 additions & 43 deletions server/events/apply_command_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,22 @@ func NewApplyCommandRunner(
db *db.BoltDB,
parallelPoolSize int,
SilenceNoProjects bool,
silenceVCSStatusNoProjects bool,
) *ApplyCommandRunner {
return &ApplyCommandRunner{
vcsClient: vcsClient,
DisableApplyAll: disableApplyAll,
locker: applyCommandLocker,
commitStatusUpdater: commitStatusUpdater,
prjCmdBuilder: prjCommandBuilder,
prjCmdRunner: prjCmdRunner,
autoMerger: autoMerger,
pullUpdater: pullUpdater,
dbUpdater: dbUpdater,
DB: db,
parallelPoolSize: parallelPoolSize,
SilenceNoProjects: SilenceNoProjects,
vcsClient: vcsClient,
DisableApplyAll: disableApplyAll,
locker: applyCommandLocker,
commitStatusUpdater: commitStatusUpdater,
prjCmdBuilder: prjCommandBuilder,
prjCmdRunner: prjCmdRunner,
autoMerger: autoMerger,
pullUpdater: pullUpdater,
dbUpdater: dbUpdater,
DB: db,
parallelPoolSize: parallelPoolSize,
SilenceNoProjects: SilenceNoProjects,
silenceVCSStatusNoProjects: silenceVCSStatusNoProjects,
}
}

Expand All @@ -52,13 +54,46 @@ type ApplyCommandRunner struct {
// SilenceNoProjects is whether Atlantis should respond to PRs if no projects
// are found
SilenceNoProjects bool
// SilenceVCSStatusNoPlans is whether any plan should set commit status if no projects
// are found
silenceVCSStatusNoProjects bool
}

func (a *ApplyCommandRunner) Run(ctx *CommandContext, cmd *CommentCommand) {
var err error
baseRepo := ctx.Pull.BaseRepo
pull := ctx.Pull

locked, err := a.IsLocked()
// CheckApplyLock falls back to DisableApply flag if fetching the lock
// raises an error
// We will log failure as warning
if err != nil {
ctx.Log.Warn("checking global apply lock: %s", err)
}

if locked {
ctx.Log.Info("ignoring apply command since apply disabled globally")
if err := a.vcsClient.CreateComment(baseRepo, pull.Num, applyDisabledComment, models.ApplyCommand.String()); err != nil {
ctx.Log.Err("unable to comment on pull request: %s", err)
}

return
}

if a.DisableApplyAll && !cmd.IsForSpecificProject() {
ctx.Log.Info("ignoring apply command without flags since apply all is disabled")
if err := a.vcsClient.CreateComment(baseRepo, pull.Num, applyAllDisabledComment, models.ApplyCommand.String()); err != nil {
ctx.Log.Err("unable to comment on pull request: %s", err)
}

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 @@ -85,7 +120,7 @@ func (a *ApplyCommandRunner) Run(ctx *CommandContext, cmd *CommentCommand) {
projectCmds, err = a.prjCmdBuilder.BuildApplyCommands(ctx, cmd)

if err != nil {
if statusErr := a.commitStatusUpdater.UpdateCombined(ctx.Pull.BaseRepo, ctx.Pull, models.FailedCommitStatus, cmd.CommandName()); statusErr != nil && !a.SilenceNoProjects {
if statusErr := a.commitStatusUpdater.UpdateCombined(ctx.Pull.BaseRepo, ctx.Pull, models.FailedCommitStatus, cmd.CommandName()); statusErr != nil {
ctx.Log.Warn("unable to update commit status: %s", statusErr)
}
a.pullUpdater.updatePull(ctx, cmd, CommandResult{Error: err})
Expand All @@ -95,40 +130,18 @@ func (a *ApplyCommandRunner) Run(ctx *CommandContext, cmd *CommentCommand) {
// If there are no projects to apply, don't respond to the PR and ignore
if len(projectCmds) == 0 && a.SilenceNoProjects {
ctx.Log.Info("determined there was no project to run apply in.")
return
}

locked, err := a.IsLocked()
// CheckApplyLock falls back to DisableApply flag if fetching the lock
// raises an erro r
// We will log failure as warning
if err != nil {
ctx.Log.Warn("checking global apply lock: %s", err)
}

if locked {
ctx.Log.Info("ignoring apply command since apply disabled globally")
if err := a.vcsClient.CreateComment(baseRepo, pull.Num, applyDisabledComment, models.ApplyCommand.String()); err != nil {
ctx.Log.Err("unable to comment on pull request: %s", err)
if !a.silenceVCSStatusNoProjects {
// If there were no projects modified, we set successful commit statuses
// with 0/0 projects planned/policy_checked/applied successfully because some users require
// the Atlantis status to be passing for all pull requests.
ctx.Log.Debug("setting VCS status to success with no projects found")
if err := a.commitStatusUpdater.UpdateCombinedCount(baseRepo, pull, models.SuccessCommitStatus, models.ApplyCommand, 0, 0); err != nil {
ctx.Log.Warn("unable to update commit status: %s", err)
}
}

return
}

if a.DisableApplyAll && !cmd.IsForSpecificProject() {
ctx.Log.Info("ignoring apply command without flags since apply all is disabled")
if err := a.vcsClient.CreateComment(baseRepo, pull.Num, applyAllDisabledComment, models.ApplyCommand.String()); err != nil {
ctx.Log.Err("unable to comment on pull request: %s", err)
}

return
}

// At this point we are sure Atlantis has work to do, so set commit status to pending
if err = a.commitStatusUpdater.UpdateCombined(baseRepo, pull, models.PendingCommitStatus, cmd.CommandName()); err != nil {
ctx.Log.Warn("unable to update commit status: %s", err)
}

// Only run commands in parallel if enabled
var result CommandResult
if a.isParallelEnabled(projectCmds) {
Expand Down
30 changes: 21 additions & 9 deletions server/events/approve_policies_command_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ func NewApprovePoliciesCommandRunner(
pullUpdater *PullUpdater,
dbUpdater *DBUpdater,
SilenceNoProjects bool,
silenceVCSStatusNoProjects bool,
) *ApprovePoliciesCommandRunner {
return &ApprovePoliciesCommandRunner{
commitStatusUpdater: commitStatusUpdater,
prjCmdBuilder: prjCommandBuilder,
prjCmdRunner: prjCommandRunner,
pullUpdater: pullUpdater,
dbUpdater: dbUpdater,
SilenceNoProjects: SilenceNoProjects,
commitStatusUpdater: commitStatusUpdater,
prjCmdBuilder: prjCommandBuilder,
prjCmdRunner: prjCommandRunner,
pullUpdater: pullUpdater,
dbUpdater: dbUpdater,
SilenceNoProjects: SilenceNoProjects,
silenceVCSStatusNoProjects: silenceVCSStatusNoProjects,
}
}

Expand All @@ -32,20 +34,21 @@ type ApprovePoliciesCommandRunner struct {
prjCmdRunner ProjectApprovePoliciesCommandRunner
// SilenceNoProjects is whether Atlantis should respond to PRs if no projects
// are found
SilenceNoProjects bool
SilenceNoProjects bool
silenceVCSStatusNoProjects bool
}

func (a *ApprovePoliciesCommandRunner) Run(ctx *CommandContext, cmd *CommentCommand) {
baseRepo := ctx.Pull.BaseRepo
pull := ctx.Pull

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

projectCmds, err := a.prjCmdBuilder.BuildApprovePoliciesCommands(ctx, cmd)
if err != nil {
if statusErr := a.commitStatusUpdater.UpdateCombined(ctx.Pull.BaseRepo, ctx.Pull, models.FailedCommitStatus, models.PolicyCheckCommand); statusErr != nil {
if statusErr := a.commitStatusUpdater.UpdateCombined(ctx.Pull.BaseRepo, ctx.Pull, models.FailedCommitStatus, models.ApprovePoliciesCommand); statusErr != nil {
ctx.Log.Warn("unable to update commit status: %s", statusErr)
}
a.pullUpdater.updatePull(ctx, cmd, CommandResult{Error: err})
Expand All @@ -54,6 +57,15 @@ func (a *ApprovePoliciesCommandRunner) Run(ctx *CommandContext, cmd *CommentComm

if len(projectCmds) == 0 && a.SilenceNoProjects {
ctx.Log.Info("determined there was no project to run approve_policies in")
if !a.silenceVCSStatusNoProjects {
// If there were no projects modified, we set successful commit statuses
// with 0/0 projects planned/policy_checked/applied successfully because some users require
// the Atlantis status to be passing for all pull requests.
ctx.Log.Debug("setting VCS status to success with no projects found")
if err := a.commitStatusUpdater.UpdateCombinedCount(ctx.Pull.BaseRepo, ctx.Pull, models.SuccessCommitStatus, models.ApprovePoliciesCommand, 0, 0); err != nil {
ctx.Log.Warn("unable to update commit status: %s", err)
}
}
return
}

Expand Down
65 changes: 60 additions & 5 deletions server/events/command_runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,11 @@ func setup(t *testing.T) *vcsmocks.MockClient {
commitUpdater,
projectCommandRunner,
parallelPoolSize,
false,
)

planCommandRunner = events.NewPlanCommandRunner(
false,
false,
vcsClient,
pendingPlanFinder,
Expand Down Expand Up @@ -146,6 +148,7 @@ func setup(t *testing.T) *vcsmocks.MockClient {
defaultBoltDB,
parallelPoolSize,
SilenceNoProjects,
false,
)

approvePoliciesCommandRunner = events.NewApprovePoliciesCommandRunner(
Expand All @@ -155,6 +158,7 @@ func setup(t *testing.T) *vcsmocks.MockClient {
pullUpdater,
dbUpdater,
SilenceNoProjects,
false,
)

unlockCommandRunner = events.NewUnlockCommandRunner(
Expand Down Expand Up @@ -284,26 +288,77 @@ func TestRunCommentCommand_ForkPRDisabled_SilenceEnabled(t *testing.T) {
vcsClient.VerifyWasCalled(Never()).CreateComment(matchers.AnyModelsRepo(), AnyInt(), AnyString(), AnyString())
}

func TestRunCommentCommand_NoProjects_SilenceEnabled(t *testing.T) {
t.Log("if a command is run on a pull request and SilenceNoProjects is enabled and we are silencing all comments if the modified files don't have a matching project")
func TestRunCommentCommandPlan_NoProjects_SilenceEnabled(t *testing.T) {
t.Log("if a plan command is run on a pull request and SilenceNoProjects is enabled and we are silencing all comments if the modified files don't have a matching project")
vcsClient := setup(t)
planCommandRunner.SilenceNoProjects = true
applyCommandRunner.SilenceNoProjects = true
approvePoliciesCommandRunner.SilenceNoProjects = true
unlockCommandRunner.SilenceNoProjects = true
var pull github.PullRequest
modelPull := models.PullRequest{BaseRepo: fixtures.GithubRepo, State: models.OpenPullState}
When(githubGetter.GetPullRequest(fixtures.GithubRepo, fixtures.Pull.Num)).ThenReturn(&pull, nil)
When(eventParsing.ParseGithubPull(&pull)).ThenReturn(modelPull, modelPull.BaseRepo, fixtures.GithubRepo, nil)

ch.RunCommentCommand(fixtures.GithubRepo, nil, nil, fixtures.User, fixtures.Pull.Num, &events.CommentCommand{Name: models.PlanCommand})
vcsClient.VerifyWasCalled(Never()).CreateComment(matchers.AnyModelsRepo(), AnyInt(), AnyString(), AnyString())
commitUpdater.VerifyWasCalledOnce().UpdateCombinedCount(
matchers.AnyModelsRepo(),
matchers.AnyModelsPullRequest(),
matchers.EqModelsCommitStatus(models.SuccessCommitStatus),
matchers.EqModelsCommandName(models.PlanCommand),
EqInt(0),
EqInt(0),
)
}

func TestRunCommentCommandApply_NoProjects_SilenceEnabled(t *testing.T) {
t.Log("if an apply command is run on a pull request and SilenceNoProjects is enabled and we are silencing all comments if the modified files don't have a matching project")
vcsClient := setup(t)
applyCommandRunner.SilenceNoProjects = true
var pull github.PullRequest
modelPull := models.PullRequest{BaseRepo: fixtures.GithubRepo, State: models.OpenPullState}
When(githubGetter.GetPullRequest(fixtures.GithubRepo, fixtures.Pull.Num)).ThenReturn(&pull, nil)
When(eventParsing.ParseGithubPull(&pull)).ThenReturn(modelPull, modelPull.BaseRepo, fixtures.GithubRepo, nil)

ch.RunCommentCommand(fixtures.GithubRepo, nil, nil, fixtures.User, fixtures.Pull.Num, &events.CommentCommand{Name: models.ApplyCommand})
vcsClient.VerifyWasCalled(Never()).CreateComment(matchers.AnyModelsRepo(), AnyInt(), AnyString(), AnyString())
commitUpdater.VerifyWasCalledOnce().UpdateCombinedCount(
matchers.AnyModelsRepo(),
matchers.AnyModelsPullRequest(),
matchers.EqModelsCommitStatus(models.SuccessCommitStatus),
matchers.EqModelsCommandName(models.ApplyCommand),
EqInt(0),
EqInt(0),
)
}

func TestRunCommentCommandApprovePolicy_NoProjects_SilenceEnabled(t *testing.T) {
t.Log("if an approve_policy command is run on a pull request and SilenceNoProjects is enabled and we are silencing all comments if the modified files don't have a matching project")
vcsClient := setup(t)
approvePoliciesCommandRunner.SilenceNoProjects = true
var pull github.PullRequest
modelPull := models.PullRequest{BaseRepo: fixtures.GithubRepo, State: models.OpenPullState}
When(githubGetter.GetPullRequest(fixtures.GithubRepo, fixtures.Pull.Num)).ThenReturn(&pull, nil)
When(eventParsing.ParseGithubPull(&pull)).ThenReturn(modelPull, modelPull.BaseRepo, fixtures.GithubRepo, nil)

ch.RunCommentCommand(fixtures.GithubRepo, nil, nil, fixtures.User, fixtures.Pull.Num, &events.CommentCommand{Name: models.ApprovePoliciesCommand})
vcsClient.VerifyWasCalled(Never()).CreateComment(matchers.AnyModelsRepo(), AnyInt(), AnyString(), AnyString())
commitUpdater.VerifyWasCalledOnce().UpdateCombinedCount(
matchers.AnyModelsRepo(),
matchers.AnyModelsPullRequest(),
matchers.EqModelsCommitStatus(models.SuccessCommitStatus),
matchers.EqModelsCommandName(models.ApprovePoliciesCommand),
EqInt(0),
EqInt(0),
)
}

func TestRunCommentCommandUnlock_NoProjects_SilenceEnabled(t *testing.T) {
t.Log("if an unlock command is run on a pull request and SilenceNoProjects is enabled and we are silencing all comments if the modified files don't have a matching project")
vcsClient := setup(t)
unlockCommandRunner.SilenceNoProjects = true
var pull github.PullRequest
modelPull := models.PullRequest{BaseRepo: fixtures.GithubRepo, State: models.OpenPullState}
When(githubGetter.GetPullRequest(fixtures.GithubRepo, fixtures.Pull.Num)).ThenReturn(&pull, nil)
When(eventParsing.ParseGithubPull(&pull)).ThenReturn(modelPull, modelPull.BaseRepo, fixtures.GithubRepo, nil)

ch.RunCommentCommand(fixtures.GithubRepo, nil, nil, fixtures.User, fixtures.Pull.Num, &events.CommentCommand{Name: models.UnlockCommand})
vcsClient.VerifyWasCalled(Never()).CreateComment(matchers.AnyModelsRepo(), AnyInt(), AnyString(), AnyString())
Expand Down
Loading

0 comments on commit 6eb3d01

Please sign in to comment.