Skip to content

Commit

Permalink
Delete previous plans on autoplan or atlantis plan
Browse files Browse the repository at this point in the history
When using non-default workspaces, plans are stored
in pr-and-workspace-specific directories.
If a PR is subsequently updated it might happen that
some of the plans are no longer relevant with regards
to the latest changes.
This change ensures that plans are always deleted
when a generic plan is triggered either by autoplan
or by a "atlantis plan" command.
NB Plans are not cleaned up when specific projects are
planned explicitly with "atlantis plan -p/-d/-w".
  • Loading branch information
giuli007 committed Jun 14, 2021
1 parent 31ebd50 commit a8a94f9
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 2 deletions.
68 changes: 66 additions & 2 deletions server/events/command_runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -431,9 +431,72 @@ func TestRunUnlockCommandFail_VCSComment(t *testing.T) {
vcsClient.VerifyWasCalledOnce().CreateComment(fixtures.GithubRepo, fixtures.Pull.Num, "Failed to delete PR locks", "unlock")
}

func TestRunAutoplanCommand_DeletePlans(t *testing.T) {
setup(t)
tmp, cleanup := TempDir(t)
defer cleanup()
boltDB, err := db.New(tmp)
Ok(t, err)
dbUpdater.DB = boltDB
applyCommandRunner.DB = boltDB
autoMerger.GlobalAutomerge = true
defer func() { autoMerger.GlobalAutomerge = false }()

When(projectCommandBuilder.BuildAutoplanCommands(matchers.AnyPtrToEventsCommandContext())).
ThenReturn([]models.ProjectCommandContext{
{
CommandName: models.PlanCommand,
},
{
CommandName: models.PlanCommand,
},
}, nil)
When(projectCommandRunner.Plan(matchers.AnyModelsProjectCommandContext())).ThenReturn(models.ProjectResult{PlanSuccess: &models.PlanSuccess{}}, nil)
When(workingDir.GetPullDir(matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest())).ThenReturn(tmp, nil)
fixtures.Pull.BaseRepo = fixtures.GithubRepo
ch.RunAutoplanCommand(fixtures.GithubRepo, fixtures.GithubRepo, fixtures.Pull, fixtures.User)
pendingPlanFinder.VerifyWasCalledOnce().DeletePlans(tmp)
}

func TestRunGenericPlanCommand_DeletePlans(t *testing.T) {
setup(t)
tmp, cleanup := TempDir(t)
defer cleanup()
boltDB, err := db.New(tmp)
Ok(t, err)
dbUpdater.DB = boltDB
applyCommandRunner.DB = boltDB
autoMerger.GlobalAutomerge = true
defer func() { autoMerger.GlobalAutomerge = false }()

When(projectCommandRunner.Plan(matchers.AnyModelsProjectCommandContext())).ThenReturn(models.ProjectResult{PlanSuccess: &models.PlanSuccess{}})
When(workingDir.GetPullDir(matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest())).ThenReturn(tmp, nil)
fixtures.Pull.BaseRepo = fixtures.GithubRepo
ch.RunCommentCommand(fixtures.GithubRepo, nil, nil, fixtures.User, fixtures.Pull.Num, &events.CommentCommand{Name: models.PlanCommand})
pendingPlanFinder.VerifyWasCalledOnce().DeletePlans(tmp)
}

func TestRunSpecificPlanCommandDoesnt_DeletePlans(t *testing.T) {
setup(t)
tmp, cleanup := TempDir(t)
defer cleanup()
boltDB, err := db.New(tmp)
Ok(t, err)
dbUpdater.DB = boltDB
applyCommandRunner.DB = boltDB
autoMerger.GlobalAutomerge = true
defer func() { autoMerger.GlobalAutomerge = false }()

When(projectCommandRunner.Plan(matchers.AnyModelsProjectCommandContext())).ThenReturn(models.ProjectResult{PlanSuccess: &models.PlanSuccess{}})
When(workingDir.GetPullDir(matchers.AnyModelsRepo(), matchers.AnyModelsPullRequest())).ThenReturn(tmp, nil)
fixtures.Pull.BaseRepo = fixtures.GithubRepo
ch.RunCommentCommand(fixtures.GithubRepo, nil, nil, fixtures.User, fixtures.Pull.Num, &events.CommentCommand{Name: models.PlanCommand, ProjectName: "default"})
pendingPlanFinder.VerifyWasCalled(Never()).DeletePlans(tmp)
}

// Test that if one plan fails and we are using automerge, that
// we delete the plans.
func TestRunAutoplanCommand_DeletePlans(t *testing.T) {
func TestRunAutoplanCommandWithError_DeletePlans(t *testing.T) {
setup(t)
tmp, cleanup := TempDir(t)
defer cleanup()
Expand Down Expand Up @@ -476,7 +539,8 @@ func TestRunAutoplanCommand_DeletePlans(t *testing.T) {
ThenReturn(tmp, nil)
fixtures.Pull.BaseRepo = fixtures.GithubRepo
ch.RunAutoplanCommand(fixtures.GithubRepo, fixtures.GithubRepo, fixtures.Pull, fixtures.User)
pendingPlanFinder.VerifyWasCalledOnce().DeletePlans(tmp)
// gets called twice: the first time before the plan starts, the second time after the plan errors
pendingPlanFinder.VerifyWasCalled(Times(2)).DeletePlans(tmp)
}

func TestFailedApprovalCreatesFailedStatusUpdate(t *testing.T) {
Expand Down
11 changes: 11 additions & 0 deletions server/events/plan_command_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ func (p *PlanCommandRunner) runAutoplan(ctx *CommandContext) {
ctx.Log.Warn("unable to update commit status: %s", err)
}

// discard previous plans that might not be relevant anymore
ctx.Log.Debug("deleting previous plans")
p.deletePlans(ctx)

// Only run commands in parallel if enabled
var result CommandResult
if p.isParallelEnabled(projectCmds) {
Expand Down Expand Up @@ -179,6 +183,13 @@ func (p *PlanCommandRunner) run(ctx *CommandContext, cmd *CommentCommand) {

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

// if the plan is generic, new plans will be generated based on changes
// discard previous plans that might not be relevant anymore
if !cmd.IsForSpecificProject() {
ctx.Log.Debug("deleting previous plans")
p.deletePlans(ctx)
}

// Only run commands in parallel if enabled
var result CommandResult
if p.isParallelEnabled(projectCmds) {
Expand Down

0 comments on commit a8a94f9

Please sign in to comment.