Skip to content

Commit

Permalink
Dont add -upgrade of the lock file exists & dedupe extra args (#1651)
Browse files Browse the repository at this point in the history
  • Loading branch information
gezb authored Jun 23, 2021
1 parent 0ed7a43 commit cd9d5b2
Show file tree
Hide file tree
Showing 2 changed files with 230 additions and 2 deletions.
67 changes: 65 additions & 2 deletions server/events/runtime/init_step_runner.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package runtime

import (
"os"
"path/filepath"
"strings"

version "github.com/hashicorp/go-version"
"github.com/runatlantis/atlantis/server/events/models"
)
Expand All @@ -16,14 +20,55 @@ func (i *InitStepRunner) Run(ctx models.ProjectCommandContext, extraArgs []strin
if ctx.TerraformVersion != nil {
tfVersion = ctx.TerraformVersion
}
terraformInitCmd := append([]string{"init", "-input=false", "-no-color", "-upgrade"}, extraArgs...)

terraformInitVerb := []string{"init"}
terraformInitArgs := []string{"-input=false"}

// If we're running < 0.9 we have to use `terraform get` instead of `init`.
if MustConstraint("< 0.9.0").Check(tfVersion) {
ctx.Log.Info("running terraform version %s so will use `get` instead of `init`", tfVersion)
terraformInitCmd = append([]string{"get", "-no-color", "-upgrade"}, extraArgs...)
terraformInitVerb = []string{"get"}
terraformInitArgs = []string{}
}

terraformInitArgs = append(terraformInitArgs, "-no-color")

lockfilePath := filepath.Join(path, ".terraform.lock.hcl")
if MustConstraint("< 0.14.0").Check(tfVersion) || fileDoesNotExists(lockfilePath) {
terraformInitArgs = append(terraformInitArgs, "-upgrade")
}

// work if any of the core args have been overridden
finalArgs := []string{}
usedExtraArgs := []string{}
for _, arg := range terraformInitArgs {
override := ""
prefix := arg
argSplit := strings.Split(arg, "=")
if len(argSplit) == 2 {
prefix = argSplit[0]
}
for _, extraArg := range extraArgs {
if strings.HasPrefix(extraArg, prefix) {
override = extraArg
}
}
if override != "" {
finalArgs = append(finalArgs, override)
usedExtraArgs = append(usedExtraArgs, override)
} else {
finalArgs = append(finalArgs, arg)
}
}
// add any extra args that are not overrides
for _, extraArg := range extraArgs {
if !stringInSlice(usedExtraArgs, extraArg) {
finalArgs = append(finalArgs, extraArg)
}
}

terraformInitCmd := append(terraformInitVerb, finalArgs...)

out, err := i.TerraformExecutor.RunCommandWithVersion(ctx.Log, path, terraformInitCmd, envs, tfVersion, ctx.Workspace)
// Only include the init output if there was an error. Otherwise it's
// unnecessary and lengthens the comment.
Expand All @@ -32,3 +77,21 @@ func (i *InitStepRunner) Run(ctx models.ProjectCommandContext, extraArgs []strin
}
return "", nil
}

func fileDoesNotExists(name string) bool {
if _, err := os.Stat(name); err != nil {
if os.IsNotExist(err) {
return true
}
}
return false
}

func stringInSlice(stringSlice []string, target string) bool {
for _, value := range stringSlice {
if value == target {
return true
}
}
return false
}
165 changes: 165 additions & 0 deletions server/events/runtime/init_step_runner_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package runtime_test

import (
"io/ioutil"
"path/filepath"
"testing"

version "github.com/hashicorp/go-version"
Expand Down Expand Up @@ -95,3 +97,166 @@ func TestRun_ShowInitOutputOnError(t *testing.T) {
ErrEquals(t, "error", err)
Equals(t, "output", output)
}

func TestRun_InitOmitsUpgradeFlagIfLockFilePresent(t *testing.T) {
tmpDir, cleanup := TempDir(t)
defer cleanup()
lockFilePath := filepath.Join(tmpDir, ".terraform.lock.hcl")
err := ioutil.WriteFile(lockFilePath, nil, 0600)
Ok(t, err)

RegisterMockTestingT(t)
terraform := mocks.NewMockClient()

logger := logging.NewNoopLogger(t)

tfVersion, _ := version.NewVersion("0.14.0")
iso := runtime.InitStepRunner{
TerraformExecutor: terraform,
DefaultTFVersion: tfVersion,
}
When(terraform.RunCommandWithVersion(logging_matchers.AnyLoggingSimpleLogging(), AnyString(), AnyStringSlice(), matchers2.AnyMapOfStringToString(), matchers2.AnyPtrToGoVersionVersion(), AnyString())).
ThenReturn("output", nil)

output, err := iso.Run(models.ProjectCommandContext{
Workspace: "workspace",
RepoRelDir: ".",
Log: logger,
}, []string{"extra", "args"}, tmpDir, map[string]string(nil))
Ok(t, err)
// When there is no error, should not return init output to PR.
Equals(t, "", output)

expectedArgs := []string{"init", "-input=false", "-no-color", "extra", "args"}
terraform.VerifyWasCalledOnce().RunCommandWithVersion(logger, tmpDir, expectedArgs, map[string]string(nil), tfVersion, "workspace")
}

func TestRun_InitKeepsUpgradeFlagIfLockFileNotPresent(t *testing.T) {
tmpDir, cleanup := TempDir(t)
defer cleanup()

RegisterMockTestingT(t)
terraform := mocks.NewMockClient()

logger := logging.NewNoopLogger(t)

tfVersion, _ := version.NewVersion("0.14.0")
iso := runtime.InitStepRunner{
TerraformExecutor: terraform,
DefaultTFVersion: tfVersion,
}
When(terraform.RunCommandWithVersion(logging_matchers.AnyLoggingSimpleLogging(), AnyString(), AnyStringSlice(), matchers2.AnyMapOfStringToString(), matchers2.AnyPtrToGoVersionVersion(), AnyString())).
ThenReturn("output", nil)

output, err := iso.Run(models.ProjectCommandContext{
Workspace: "workspace",
RepoRelDir: ".",
Log: logger,
}, []string{"extra", "args"}, tmpDir, map[string]string(nil))
Ok(t, err)
// When there is no error, should not return init output to PR.
Equals(t, "", output)

expectedArgs := []string{"init", "-input=false", "-no-color", "-upgrade", "extra", "args"}
terraform.VerifyWasCalledOnce().RunCommandWithVersion(logger, tmpDir, expectedArgs, map[string]string(nil), tfVersion, "workspace")
}

func TestRun_InitKeepUpgradeFlagIfLockFilePresentAndTFLessThanPoint14(t *testing.T) {
tmpDir, cleanup := TempDir(t)
defer cleanup()
lockFilePath := filepath.Join(tmpDir, ".terraform.lock.hcl")
err := ioutil.WriteFile(lockFilePath, nil, 0600)
Ok(t, err)

RegisterMockTestingT(t)
terraform := mocks.NewMockClient()

logger := logging.NewNoopLogger(t)

tfVersion, _ := version.NewVersion("0.13.0")
iso := runtime.InitStepRunner{
TerraformExecutor: terraform,
DefaultTFVersion: tfVersion,
}
When(terraform.RunCommandWithVersion(logging_matchers.AnyLoggingSimpleLogging(), AnyString(), AnyStringSlice(), matchers2.AnyMapOfStringToString(), matchers2.AnyPtrToGoVersionVersion(), AnyString())).
ThenReturn("output", nil)

output, err := iso.Run(models.ProjectCommandContext{
Workspace: "workspace",
RepoRelDir: ".",
Log: logger,
}, []string{"extra", "args"}, tmpDir, map[string]string(nil))
Ok(t, err)
// When there is no error, should not return init output to PR.
Equals(t, "", output)

expectedArgs := []string{"init", "-input=false", "-no-color", "-upgrade", "extra", "args"}
terraform.VerifyWasCalledOnce().RunCommandWithVersion(logger, tmpDir, expectedArgs, map[string]string(nil), tfVersion, "workspace")
}

func TestRun_InitExtraArgsDeDupe(t *testing.T) {
RegisterMockTestingT(t)
cases := []struct {
description string
extraArgs []string
expectedArgs []string
}{
{
"No extra args",
[]string{},
[]string{"init", "-input=false", "-no-color", "-upgrade"},
},
{
"Override -upgrade",
[]string{"-upgrade=false"},
[]string{"init", "-input=false", "-no-color", "-upgrade=false"},
},
{
"Override -input",
[]string{"-input=true"},
[]string{"init", "-input=true", "-no-color", "-upgrade"},
},
{
"Override -input and -upgrade",
[]string{"-input=true", "-upgrade=false"},
[]string{"init", "-input=true", "-no-color", "-upgrade=false"},
},
{
"Non duplicate extra args",
[]string{"extra", "args"},
[]string{"init", "-input=false", "-no-color", "-upgrade", "extra", "args"},
},
{
"Override upgrade with extra args",
[]string{"extra", "args", "-upgrade=false"},
[]string{"init", "-input=false", "-no-color", "-upgrade=false", "extra", "args"},
},
}

for _, c := range cases {
t.Run(c.description, func(t *testing.T) {
terraform := mocks.NewMockClient()

logger := logging.NewNoopLogger(t)

tfVersion, _ := version.NewVersion("0.10.0")
iso := runtime.InitStepRunner{
TerraformExecutor: terraform,
DefaultTFVersion: tfVersion,
}
When(terraform.RunCommandWithVersion(logging_matchers.AnyLoggingSimpleLogging(), AnyString(), AnyStringSlice(), matchers2.AnyMapOfStringToString(), matchers2.AnyPtrToGoVersionVersion(), AnyString())).
ThenReturn("output", nil)

output, err := iso.Run(models.ProjectCommandContext{
Workspace: "workspace",
RepoRelDir: ".",
Log: logger,
}, c.extraArgs, "/path", map[string]string(nil))
Ok(t, err)
// When there is no error, should not return init output to PR.
Equals(t, "", output)

terraform.VerifyWasCalledOnce().RunCommandWithVersion(logger, "/path", c.expectedArgs, map[string]string(nil), tfVersion, "workspace")
})
}
}

0 comments on commit cd9d5b2

Please sign in to comment.