Skip to content

Commit

Permalink
Set PLANFILE environment variable in run step.
Browse files Browse the repository at this point in the history
Env var is set to where Atlantis expects the planfile to be.
Fixes #168.
  • Loading branch information
lkysow committed Jul 7, 2018
1 parent 88da8c6 commit 78a2bb5
Show file tree
Hide file tree
Showing 7 changed files with 75 additions and 22 deletions.
7 changes: 5 additions & 2 deletions runatlantis.io/docs/atlantis-yaml-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ steps:
| steps | array[[Step](atlantis-yaml-reference.html#step)] | `[]` | no | List of steps for this stage. If the steps key is empty, no steps will be run for this stage. |

### Step
#### Built-In Command
#### Built-In Commands: init, plan, apply
Steps can be a single string for a built-in command.
```yaml
- init
Expand All @@ -162,7 +162,7 @@ A map from string to `extra_args` for a built-in command with extra arguments.
| Key | Type | Default | Required | Description |
| -------------| --- |-------------| -----|---|
| init/plan/apply | map[`extra_args` -> array[string]] | none | no | Use a built-in command and append `extra_args`. Only `init`, `plan` and `apply` are supported as keys and only `extra_args` is supported as a value||
#### Custom Command
#### Custom `run` Command
Or a custom command
```yaml
- run: custom-command
Expand All @@ -177,6 +177,9 @@ Or a custom command
* NOTE: if the step is executed before `init` then Atlantis won't have switched to this workspace yet.
* `ATLANTIS_TERRAFORM_VERSION` - The version of Terraform used for this project, ex. `0.11.0`.
* `DIR` - Absolute path to the current directory.
* `PLANFILE` - Absolute path to the location where Atlantis expects the plan to
either be generated (by plan) or already exist (if running apply). Can be used to
override the built-in `plan`/`apply` commands, ex. `run: terraform plan -out $PLANFILE`.
:::

## Next Steps
Expand Down
11 changes: 3 additions & 8 deletions server/events/runtime/apply_step_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,13 @@ type ApplyStepRunner struct {
}

func (a *ApplyStepRunner) Run(ctx models.ProjectCommandContext, extraArgs []string, path string) (string, error) {
// todo: move this to a common library
planFileName := fmt.Sprintf("%s.tfplan", ctx.Workspace)
if ctx.ProjectConfig != nil && ctx.ProjectConfig.Name != nil {
planFileName = fmt.Sprintf("%s-%s", *ctx.ProjectConfig.Name, planFileName)
}
planFile := filepath.Join(path, planFileName)
stat, err := os.Stat(planFile)
planPath := filepath.Join(path, GetPlanFilename(ctx.Workspace, ctx.ProjectConfig))
stat, err := os.Stat(planPath)
if err != nil || stat.IsDir() {
return "", fmt.Errorf("no plan found at path %q and workspace %q–did you run plan?", ctx.RepoRelDir, ctx.Workspace)
}

tfApplyCmd := append(append(append([]string{"apply", "-no-color"}, extraArgs...), ctx.CommentArgs...), planFile)
tfApplyCmd := append(append(append([]string{"apply", "-no-color"}, extraArgs...), ctx.CommentArgs...), planPath)
var tfVersion *version.Version
if ctx.ProjectConfig != nil && ctx.ProjectConfig.TerraformVersion != nil {
tfVersion = ctx.ProjectConfig.TerraformVersion
Expand Down
7 changes: 1 addition & 6 deletions server/events/runtime/plan_step_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,7 @@ func (p *PlanStepRunner) Run(ctx models.ProjectCommandContext, extraArgs []strin
return "", err
}

// todo: move this to a common library
planFileName := fmt.Sprintf("%s.tfplan", ctx.Workspace)
if ctx.ProjectConfig != nil && ctx.ProjectConfig.Name != nil {
planFileName = fmt.Sprintf("%s-%s", *ctx.ProjectConfig.Name, planFileName)
}
planFile := filepath.Join(path, planFileName)
planFile := filepath.Join(path, GetPlanFilename(ctx.Workspace, ctx.ProjectConfig))
userVar := fmt.Sprintf("%s=%s", atlantisUserTFVar, ctx.User.Username)
tfPlanCmd := append(append([]string{"plan", "-refresh", "-no-color", "-out", planFile, "-var", userVar}, extraArgs...), ctx.CommentArgs...)

Expand Down
2 changes: 2 additions & 0 deletions server/events/runtime/run_step_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"

"github.com/hashicorp/go-version"
Expand Down Expand Up @@ -32,6 +33,7 @@ func (r *RunStepRunner) Run(ctx models.ProjectCommandContext, command []string,
fmt.Sprintf("WORKSPACE=%s", ctx.Workspace),
fmt.Sprintf("ATLANTIS_TERRAFORM_VERSION=%s", tfVersion),
fmt.Sprintf("DIR=%s", path),
fmt.Sprintf("PLANFILE=%s", filepath.Join(path, GetPlanFilename(ctx.Workspace, ctx.ProjectConfig))),
}
finalEnvVars := append(baseEnvVars, customEnvVars...)
cmd.Env = finalEnvVars
Expand Down
9 changes: 6 additions & 3 deletions server/events/runtime/run_step_runner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ func TestRunStepRunner_Run(t *testing.T) {
ExpErr: "exit status 127: running \"lkjlkj\" in",
},
{
Command: "echo workspace=$WORKSPACE version=$ATLANTIS_TERRAFORM_VERSION dir=$DIR",
ExpOut: "workspace=myworkspace version=0.11.0 dir=$DIR\n",
Command: "echo workspace=$WORKSPACE version=$ATLANTIS_TERRAFORM_VERSION dir=$DIR planfile=$PLANFILE",
ExpOut: "workspace=myworkspace version=0.11.0 dir=$DIR planfile=$DIR/myworkspace.tfplan\n",
},
}

Expand Down Expand Up @@ -70,7 +70,10 @@ func TestRunStepRunner_Run(t *testing.T) {
return
}
Ok(t, err)
expOut := strings.Replace(c.ExpOut, "dir=$DIR", "dir="+tmpDir, -1)
// Replace $DIR in the exp with the actual temp dir. We do this
// here because when constructing the cases we don't yet know the
// temp dir.
expOut := strings.Replace(c.ExpOut, "$DIR", tmpDir, -1)
Equals(t, expOut, out)
})
}
Expand Down
17 changes: 14 additions & 3 deletions server/events/runtime/runtime.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
// Package runtime handles constructing an execution graph for each action
// based on configuration and defaults. The handlers can then execute this
// graph.
// Package runtime holds code for actually running commands vs. preparing
// and constructing.
package runtime

import (
"fmt"

"github.com/hashicorp/go-version"
"github.com/runatlantis/atlantis/server/events/yaml/valid"
"github.com/runatlantis/atlantis/server/logging"
)

Expand All @@ -20,3 +22,12 @@ func MustConstraint(constraint string) version.Constraints {
}
return c
}

// GetPlanFilename returns the filename (not the path) of the generated tf plan
// given a workspace and maybe a project's config.
func GetPlanFilename(workspace string, maybeCfg *valid.Project) string {
if maybeCfg == nil || maybeCfg.Name == nil {
return fmt.Sprintf("%s.tfplan", workspace)
}
return fmt.Sprintf("%s-%s.tfplan", *maybeCfg.Name, workspace)
}
44 changes: 44 additions & 0 deletions server/events/runtime/runtime_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package runtime_test

import (
"fmt"
"testing"

"github.com/runatlantis/atlantis/server/events/runtime"
"github.com/runatlantis/atlantis/server/events/yaml/valid"
. "github.com/runatlantis/atlantis/testing"
)

func TestGetPlanFilename(t *testing.T) {
cases := []struct {
workspace string
maybeCfg *valid.Project
exp string
}{
{
"workspace",
nil,
"workspace.tfplan",
},
{
"workspace",
&valid.Project{},
"workspace.tfplan",
},
{
"workspace",
&valid.Project{
Name: String("project"),
},
"project-workspace.tfplan",
},
}

for i, c := range cases {
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
Equals(t, c.exp, runtime.GetPlanFilename(c.workspace, c.maybeCfg))
})
}
}

func String(v string) *string { return &v }

0 comments on commit 78a2bb5

Please sign in to comment.