Skip to content

Commit

Permalink
Run terraform plan -destroy when destroy flag is enabled (#168)
Browse files Browse the repository at this point in the history
* destroy plan

* destroy plan

* nit

* nit2

* remove unneeded decorator

* nit
  • Loading branch information
samrabelachew authored Jan 27, 2022
1 parent b0377ca commit 3a95031
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 7 deletions.
21 changes: 21 additions & 0 deletions server/lyft/decorators/destroy_plan_step_runner_wrapper.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package decorators

import (
"github.com/runatlantis/atlantis/server/events"
"github.com/runatlantis/atlantis/server/events/models"
)

const Deprecated = "deprecated"
const Destroy = "-destroy"

type DestroyPlanStepRunnerWrapper struct {
events.StepRunner
}

func (d *DestroyPlanStepRunnerWrapper) Run(ctx models.ProjectCommandContext, extraArgs []string, path string, envs map[string]string) (string, error) {
// DestroyPlan tag is true when the Terraform client should construct a destroy plan given a repo config.
if ctx.Tags[Deprecated] == Destroy {
extraArgs = append(extraArgs, Destroy)
}
return d.StepRunner.Run(ctx, extraArgs, path, envs)
}
128 changes: 128 additions & 0 deletions server/lyft/decorators/destroy_plan_step_runner_wrapper_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
package decorators_test

import (
"fmt"
"github.com/hashicorp/go-version"
"github.com/runatlantis/atlantis/server/core/runtime"
"github.com/runatlantis/atlantis/server/core/terraform/mocks"
"os"
"path/filepath"
"testing"

"github.com/runatlantis/atlantis/server/events/models"
"github.com/runatlantis/atlantis/server/logging"
"github.com/runatlantis/atlantis/server/lyft/decorators"

. "github.com/petergtz/pegomock"
. "github.com/runatlantis/atlantis/testing"
)

func TestRun_DestroyPlan(t *testing.T) {
RegisterMockTestingT(t)

// Create the env/workspace.tfvars file.
tmpDir, cleanup := TempDir(t)
defer cleanup()
err := os.MkdirAll(filepath.Join(tmpDir, "env"), 0700)
Ok(t, err)

cases := []struct {
description string
expPlanArgs []string
tags map[string]string
}{
{
description: "uses destroy plan",
expPlanArgs: []string{
"plan",
"-input=false",
"-refresh",
"-out",
fmt.Sprintf("%q", filepath.Join(tmpDir, "workspace.tfplan")),
"-var",
"atlantis_user=\"username\"",
"-var",
"atlantis_repo=\"owner/repo\"",
"-var",
"atlantis_repo_name=\"repo\"",
"-var",
"atlantis_repo_owner=\"owner\"",
"-var",
"atlantis_pull_num=2",
"extra",
"args",
"-destroy",
"comment",
"args",
},
tags: map[string]string{
decorators.Deprecated: decorators.Destroy,
},
},
{
description: "no destroy plan",
expPlanArgs: []string{
"plan",
"-input=false",
"-refresh",
"-out",
fmt.Sprintf("%q", filepath.Join(tmpDir, "workspace.tfplan")),
"-var",
"atlantis_user=\"username\"",
"-var",
"atlantis_repo=\"owner/repo\"",
"-var",
"atlantis_repo_name=\"repo\"",
"-var",
"atlantis_repo_owner=\"owner\"",
"-var",
"atlantis_pull_num=2",
"extra",
"args",
"comment",
"args",
},
tags: map[string]string{},
},
}

for _, c := range cases {
t.Run(c.description, func(t *testing.T) {
// Using version >= 0.10 here so we don't expect any env commands.
terraform := mocks.NewMockClient()
tfVersion, _ := version.NewVersion("0.10.0")
logger := logging.NewNoopLogger(t)
planStepRunner := runtime.PlanStepRunner{
TerraformExecutor: terraform,
DefaultTFVersion: tfVersion,
}
stepRunner := decorators.DestroyPlanStepRunnerWrapper{
StepRunner: &planStepRunner,
}
ctx := models.ProjectCommandContext{
Log: logger,
Workspace: "workspace",
RepoRelDir: ".",
User: models.User{Username: "username"},
EscapedCommentArgs: []string{"comment", "args"},
Pull: models.PullRequest{
Num: 2,
},
BaseRepo: models.Repo{
FullName: "owner/repo",
Owner: "owner",
Name: "repo",
},
Tags: c.tags,
}
When(terraform.RunCommandWithVersion(ctx, tmpDir, c.expPlanArgs, map[string]string(nil), tfVersion, "workspace")).ThenReturn("output", nil)

output, err := stepRunner.Run(ctx, []string{"extra", "args"}, tmpDir, map[string]string(nil))
Ok(t, err)

// Verify that we next called for the actual
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, tmpDir, c.expPlanArgs, map[string]string(nil), tfVersion, "workspace")
Equals(t, "output", output)
})
}
}
19 changes: 12 additions & 7 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,9 @@ import (
"github.com/runatlantis/atlantis/server/events"
"github.com/runatlantis/atlantis/server/events/models"
"github.com/runatlantis/atlantis/server/events/vcs"
lyft_vcs "github.com/runatlantis/atlantis/server/events/vcs/lyft"
"github.com/runatlantis/atlantis/server/events/vcs/bitbucketcloud"
"github.com/runatlantis/atlantis/server/events/vcs/bitbucketserver"
lyft_vcs "github.com/runatlantis/atlantis/server/events/vcs/lyft"
"github.com/runatlantis/atlantis/server/events/webhooks"
"github.com/runatlantis/atlantis/server/events/yaml"
"github.com/runatlantis/atlantis/server/logging"
Expand Down Expand Up @@ -539,19 +539,24 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) {
WorkingDir: workingDir,
}

planStepRunner := &runtime.PlanStepRunner{
TerraformExecutor: terraformClient,
DefaultTFVersion: defaultTfVersion,
CommitStatusUpdater: commitStatusUpdater,
AsyncTFExec: terraformClient,
}
destroyPlanStepRunnerWrapper := &lyftDecorators.DestroyPlanStepRunnerWrapper{
StepRunner: planStepRunner,
}

projectCommandRunner := &events.DefaultProjectCommandRunner{
Locker: projectLocker,
LockURLGenerator: router,
InitStepRunner: &runtime.InitStepRunner{
TerraformExecutor: terraformClient,
DefaultTFVersion: defaultTfVersion,
},
PlanStepRunner: &runtime.PlanStepRunner{
TerraformExecutor: terraformClient,
DefaultTFVersion: defaultTfVersion,
CommitStatusUpdater: commitStatusUpdater,
AsyncTFExec: terraformClient,
},
PlanStepRunner: destroyPlanStepRunnerWrapper,
ShowStepRunner: showStepRunner,
PolicyCheckStepRunner: policyCheckRunner,
ApplyStepRunner: &runtime.ApplyStepRunner{
Expand Down

0 comments on commit 3a95031

Please sign in to comment.