mirror of
https://git.vectorsigma.ru/public/atlantis.git
synced 2026-07-28 19:38:24 +00:00
feat: Support project-level Terraform distribution selection (#5167)
Signed-off-by: Andrew Borg <andrew.b.borg@gmail.com> Co-authored-by: PePe Amengual <2208324+jamengual@users.noreply.github.com> Co-authored-by: Simon Heather <32168619+X-Guardian@users.noreply.github.com>
This commit is contained in:
@@ -72,6 +72,7 @@ const (
|
||||
CheckoutStrategyFlag = "checkout-strategy"
|
||||
ConfigFlag = "config"
|
||||
DataDirFlag = "data-dir"
|
||||
DefaultTFDistributionFlag = "default-tf-distribution"
|
||||
DefaultTFVersionFlag = "default-tf-version"
|
||||
DisableApplyAllFlag = "disable-apply-all"
|
||||
DisableAutoplanFlag = "disable-autoplan"
|
||||
@@ -141,7 +142,7 @@ const (
|
||||
SSLCertFileFlag = "ssl-cert-file"
|
||||
SSLKeyFileFlag = "ssl-key-file"
|
||||
RestrictFileList = "restrict-file-list"
|
||||
TFDistributionFlag = "tf-distribution"
|
||||
TFDistributionFlag = "tf-distribution" // deprecated for DefaultTFDistributionFlag
|
||||
TFDownloadFlag = "tf-download"
|
||||
TFDownloadURLFlag = "tf-download-url"
|
||||
UseTFPluginCache = "use-tf-plugin-cache"
|
||||
@@ -421,8 +422,8 @@ var stringFlags = map[string]stringFlag{
|
||||
description: fmt.Sprintf("File containing x509 private key matching --%s.", SSLCertFileFlag),
|
||||
},
|
||||
TFDistributionFlag: {
|
||||
description: fmt.Sprintf("Which TF distribution to use. Can be set to %s or %s.", TFDistributionTerraform, TFDistributionOpenTofu),
|
||||
defaultValue: DefaultTFDistribution,
|
||||
description: "[Deprecated for --default-tf-distribution].",
|
||||
hidden: true,
|
||||
},
|
||||
TFDownloadURLFlag: {
|
||||
description: "Base URL to download Terraform versions from.",
|
||||
@@ -437,6 +438,10 @@ var stringFlags = map[string]stringFlag{
|
||||
" Only set if using TFC/E as a remote backend." +
|
||||
" Should be specified via the ATLANTIS_TFE_TOKEN environment variable for security.",
|
||||
},
|
||||
DefaultTFDistributionFlag: {
|
||||
description: fmt.Sprintf("Which TF distribution to use. Can be set to %s or %s.", TFDistributionTerraform, TFDistributionOpenTofu),
|
||||
defaultValue: DefaultTFDistribution,
|
||||
},
|
||||
DefaultTFVersionFlag: {
|
||||
description: "Terraform version to default to (ex. v0.12.0). Will download if not yet on disk." +
|
||||
" If not set, Atlantis uses the terraform binary in its PATH.",
|
||||
@@ -840,12 +845,13 @@ func (s *ServerCmd) run() error {
|
||||
|
||||
// Config looks good. Start the server.
|
||||
server, err := s.ServerCreator.NewServer(userConfig, server.Config{
|
||||
AllowForkPRsFlag: AllowForkPRsFlag,
|
||||
AtlantisURLFlag: AtlantisURLFlag,
|
||||
AtlantisVersion: s.AtlantisVersion,
|
||||
DefaultTFVersionFlag: DefaultTFVersionFlag,
|
||||
RepoConfigJSONFlag: RepoConfigJSONFlag,
|
||||
SilenceForkPRErrorsFlag: SilenceForkPRErrorsFlag,
|
||||
AllowForkPRsFlag: AllowForkPRsFlag,
|
||||
AtlantisURLFlag: AtlantisURLFlag,
|
||||
AtlantisVersion: s.AtlantisVersion,
|
||||
DefaultTFDistributionFlag: DefaultTFDistributionFlag,
|
||||
DefaultTFVersionFlag: DefaultTFVersionFlag,
|
||||
RepoConfigJSONFlag: RepoConfigJSONFlag,
|
||||
SilenceForkPRErrorsFlag: SilenceForkPRErrorsFlag,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
@@ -921,8 +927,11 @@ func (s *ServerCmd) setDefaults(c *server.UserConfig, v *viper.Viper) {
|
||||
if c.RedisPort == 0 {
|
||||
c.RedisPort = DefaultRedisPort
|
||||
}
|
||||
if c.TFDistribution == "" {
|
||||
c.TFDistribution = DefaultTFDistribution
|
||||
if c.TFDistribution != "" && c.DefaultTFDistribution == "" {
|
||||
c.DefaultTFDistribution = c.TFDistribution
|
||||
}
|
||||
if c.DefaultTFDistribution == "" {
|
||||
c.DefaultTFDistribution = DefaultTFDistribution
|
||||
}
|
||||
if c.TFDownloadURL == "" {
|
||||
c.TFDownloadURL = DefaultTFDownloadURL
|
||||
@@ -953,7 +962,7 @@ func (s *ServerCmd) validate(userConfig server.UserConfig) error {
|
||||
return fmt.Errorf("invalid log level: must be one of %v", ValidLogLevels)
|
||||
}
|
||||
|
||||
if userConfig.TFDistribution != TFDistributionTerraform && userConfig.TFDistribution != TFDistributionOpenTofu {
|
||||
if userConfig.DefaultTFDistribution != TFDistributionTerraform && userConfig.DefaultTFDistribution != TFDistributionOpenTofu {
|
||||
return fmt.Errorf("invalid tf distribution: expected one of %s or %s",
|
||||
TFDistributionTerraform, TFDistributionOpenTofu)
|
||||
}
|
||||
@@ -1172,6 +1181,10 @@ func (s *ServerCmd) deprecationWarnings(userConfig *server.UserConfig) error {
|
||||
// }
|
||||
//
|
||||
|
||||
if userConfig.TFDistribution != "" {
|
||||
deprecatedFlags = append(deprecatedFlags, TFDistributionFlag)
|
||||
}
|
||||
|
||||
if len(deprecatedFlags) > 0 {
|
||||
warning := "WARNING: "
|
||||
if len(deprecatedFlags) == 1 {
|
||||
|
||||
@@ -73,6 +73,7 @@ var testFlags = map[string]interface{}{
|
||||
CheckoutStrategyFlag: CheckoutStrategyMerge,
|
||||
CheckoutDepthFlag: 0,
|
||||
DataDirFlag: "/path",
|
||||
DefaultTFDistributionFlag: "terraform",
|
||||
DefaultTFVersionFlag: "v0.11.0",
|
||||
DisableApplyAllFlag: true,
|
||||
DisableMarkdownFoldingFlag: true,
|
||||
@@ -977,6 +978,46 @@ func TestExecute_AutoplanFileList(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecute_ValidateDefaultTFDistribution(t *testing.T) {
|
||||
cases := []struct {
|
||||
description string
|
||||
flags map[string]interface{}
|
||||
expectErr string
|
||||
}{
|
||||
{
|
||||
"terraform",
|
||||
map[string]interface{}{
|
||||
DefaultTFDistributionFlag: "terraform",
|
||||
},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"opentofu",
|
||||
map[string]interface{}{
|
||||
DefaultTFDistributionFlag: "opentofu",
|
||||
},
|
||||
"",
|
||||
},
|
||||
{
|
||||
"errs on invalid distribution",
|
||||
map[string]interface{}{
|
||||
DefaultTFDistributionFlag: "invalid_distribution",
|
||||
},
|
||||
"invalid tf distribution: expected one of terraform or opentofu",
|
||||
},
|
||||
}
|
||||
for _, testCase := range cases {
|
||||
t.Log("Should validate default tf distribution when " + testCase.description)
|
||||
c := setupWithDefaults(testCase.flags, t)
|
||||
err := c.Execute()
|
||||
if testCase.expectErr != "" {
|
||||
ErrEquals(t, testCase.expectErr, err)
|
||||
} else {
|
||||
Ok(t, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func setup(flags map[string]interface{}, t *testing.T) *cobra.Command {
|
||||
vipr := viper.New()
|
||||
for k, v := range flags {
|
||||
|
||||
@@ -66,6 +66,7 @@ projects:
|
||||
branch: /main/
|
||||
dir: .
|
||||
workspace: default
|
||||
terraform_distribution: terraform
|
||||
terraform_version: v0.11.0
|
||||
delete_source_branch_on_merge: true
|
||||
repo_locking: true # deprecated: use repo_locks instead
|
||||
@@ -262,6 +263,20 @@ See [Custom Workflow Use Cases: Terragrunt](custom-workflows.md#terragrunt)
|
||||
|
||||
See [Custom Workflow Use Cases: Running custom commands](custom-workflows.md#running-custom-commands)
|
||||
|
||||
### Terraform Distributions
|
||||
|
||||
If you'd like to use a different distribution of Terraform than what is set
|
||||
by the `--default-tf-version` flag, then set the `terraform_distribution` key:
|
||||
|
||||
```yaml
|
||||
version: 3
|
||||
projects:
|
||||
- dir: project1
|
||||
terraform_distribution: opentofu
|
||||
```
|
||||
|
||||
Atlantis will automatically download and use this distribution. Valid values are `terraform` and `opentofu`.
|
||||
|
||||
### Terraform Versions
|
||||
|
||||
If you'd like to use a different version of Terraform than what is in Atlantis'
|
||||
|
||||
@@ -386,6 +386,16 @@ and set `--autoplan-modules` to `false`.
|
||||
Note that the atlantis user is restricted to `~/.atlantis`.
|
||||
If you set the `--data-dir` flag to a path outside of Atlantis its home directory, ensure that you grant the atlantis user the correct permissions.
|
||||
|
||||
### `--default-tf-distribution`
|
||||
|
||||
```bash
|
||||
atlantis server --default-tf-distribution="terraform"
|
||||
# or
|
||||
ATLANTIS_DEFAULT_TF_DISTRIBUTION="terraform"
|
||||
```
|
||||
|
||||
Which TF distribution to use. Can be set to `terraform` or `opentofu`.
|
||||
|
||||
### `--default-tf-version`
|
||||
|
||||
```bash
|
||||
@@ -1259,13 +1269,8 @@ This is useful when you have many projects and want to keep the pull request cle
|
||||
|
||||
### `--tf-distribution`
|
||||
|
||||
```bash
|
||||
atlantis server --tf-distribution="terraform"
|
||||
# or
|
||||
ATLANTIS_TF_DISTRIBUTION="terraform"
|
||||
```
|
||||
|
||||
Which TF distribution to use. Can be set to `terraform` or `opentofu`.
|
||||
<Badge text="Deprecated" type="warn"/>
|
||||
Deprecated for `--default-tf-distribution`.
|
||||
|
||||
### `--tf-download`
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ import (
|
||||
mock_policy "github.com/runatlantis/atlantis/server/core/runtime/policy/mocks"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform"
|
||||
terraform_mocks "github.com/runatlantis/atlantis/server/core/terraform/mocks"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform/tfclient"
|
||||
"github.com/runatlantis/atlantis/server/events"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/events/mocks"
|
||||
@@ -1319,7 +1320,7 @@ func setupE2E(t *testing.T, repoDir string, opt setupOption) (events_controllers
|
||||
mockDownloader := terraform_mocks.NewMockDownloader()
|
||||
distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
|
||||
terraformClient, err := terraform.NewClient(logger, distribution, binDir, cacheDir, "", "", "", "default-tf-version", "https://releases.hashicorp.com", true, false, projectCmdOutputHandler)
|
||||
terraformClient, err := tfclient.NewClient(logger, distribution, binDir, cacheDir, "", "", "", "default-tf-version", "https://releases.hashicorp.com", true, false, projectCmdOutputHandler)
|
||||
Ok(t, err)
|
||||
boltdb, err := db.New(dataDir)
|
||||
Ok(t, err)
|
||||
@@ -1346,6 +1347,7 @@ func setupE2E(t *testing.T, repoDir string, opt setupOption) (events_controllers
|
||||
}
|
||||
}
|
||||
|
||||
defaultTFDistribution := terraformClient.DefaultDistribution()
|
||||
defaultTFVersion := terraformClient.DefaultVersion()
|
||||
locker := events.NewDefaultWorkingDirLocker()
|
||||
parser := &config.ParserValidator{}
|
||||
@@ -1429,7 +1431,7 @@ func setupE2E(t *testing.T, repoDir string, opt setupOption) (events_controllers
|
||||
terraformClient,
|
||||
)
|
||||
|
||||
showStepRunner, err := runtime.NewShowStepRunner(terraformClient, defaultTFVersion)
|
||||
showStepRunner, err := runtime.NewShowStepRunner(terraformClient, defaultTFDistribution, defaultTFVersion)
|
||||
|
||||
Ok(t, err)
|
||||
|
||||
@@ -1440,6 +1442,7 @@ func setupE2E(t *testing.T, repoDir string, opt setupOption) (events_controllers
|
||||
conftextExec.VersionCache = &LocalConftestCache{}
|
||||
|
||||
policyCheckRunner, err := runtime.NewPolicyCheckStepRunner(
|
||||
defaultTFDistribution,
|
||||
defaultTFVersion,
|
||||
conftextExec,
|
||||
)
|
||||
@@ -1451,11 +1454,13 @@ func setupE2E(t *testing.T, repoDir string, opt setupOption) (events_controllers
|
||||
Locker: projectLocker,
|
||||
LockURLGenerator: &mockLockURLGenerator{},
|
||||
InitStepRunner: &runtime.InitStepRunner{
|
||||
TerraformExecutor: terraformClient,
|
||||
DefaultTFVersion: defaultTFVersion,
|
||||
TerraformExecutor: terraformClient,
|
||||
DefaultTFDistribution: defaultTFDistribution,
|
||||
DefaultTFVersion: defaultTFVersion,
|
||||
},
|
||||
PlanStepRunner: runtime.NewPlanStepRunner(
|
||||
terraformClient,
|
||||
defaultTFDistribution,
|
||||
defaultTFVersion,
|
||||
statusUpdater,
|
||||
asyncTfExec,
|
||||
@@ -1465,10 +1470,11 @@ func setupE2E(t *testing.T, repoDir string, opt setupOption) (events_controllers
|
||||
ApplyStepRunner: &runtime.ApplyStepRunner{
|
||||
TerraformExecutor: terraformClient,
|
||||
},
|
||||
ImportStepRunner: runtime.NewImportStepRunner(terraformClient, defaultTFVersion),
|
||||
StateRmStepRunner: runtime.NewStateRmStepRunner(terraformClient, defaultTFVersion),
|
||||
ImportStepRunner: runtime.NewImportStepRunner(terraformClient, defaultTFDistribution, defaultTFVersion),
|
||||
StateRmStepRunner: runtime.NewStateRmStepRunner(terraformClient, defaultTFDistribution, defaultTFVersion),
|
||||
RunStepRunner: &runtime.RunStepRunner{
|
||||
TerraformExecutor: terraformClient,
|
||||
DefaultTFDistribution: defaultTFDistribution,
|
||||
DefaultTFVersion: defaultTFVersion,
|
||||
ProjectCmdOutputHandler: projectCmdOutputHandler,
|
||||
},
|
||||
|
||||
@@ -610,6 +610,31 @@ workflows:
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "project field with terraform_distribution set to opentofu",
|
||||
input: `
|
||||
version: 3
|
||||
projects:
|
||||
- dir: .
|
||||
workspace: myworkspace
|
||||
terraform_distribution: opentofu
|
||||
`,
|
||||
exp: valid.RepoCfg{
|
||||
Version: 3,
|
||||
Projects: []valid.Project{
|
||||
{
|
||||
Dir: ".",
|
||||
Workspace: "myworkspace",
|
||||
TerraformDistribution: String("opentofu"),
|
||||
Autoplan: valid.Autoplan{
|
||||
WhenModified: raw.DefaultAutoPlanWhenModified,
|
||||
Enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
Workflows: make(map[string]valid.Workflow),
|
||||
},
|
||||
},
|
||||
{
|
||||
description: "project dir with ..",
|
||||
input: `
|
||||
|
||||
@@ -26,6 +26,7 @@ type Project struct {
|
||||
Dir *string `yaml:"dir,omitempty"`
|
||||
Workspace *string `yaml:"workspace,omitempty"`
|
||||
Workflow *string `yaml:"workflow,omitempty"`
|
||||
TerraformDistribution *string `yaml:"terraform_distribution,omitempty"`
|
||||
TerraformVersion *string `yaml:"terraform_version,omitempty"`
|
||||
Autoplan *Autoplan `yaml:"autoplan,omitempty"`
|
||||
PlanRequirements []string `yaml:"plan_requirements,omitempty"`
|
||||
@@ -86,6 +87,7 @@ func (p Project) Validate() error {
|
||||
validation.Field(&p.PlanRequirements, validation.By(validPlanReq)),
|
||||
validation.Field(&p.ApplyRequirements, validation.By(validApplyReq)),
|
||||
validation.Field(&p.ImportRequirements, validation.By(validImportReq)),
|
||||
validation.Field(&p.TerraformDistribution, validation.By(validDistribution)),
|
||||
validation.Field(&p.TerraformVersion, validation.By(VersionValidator)),
|
||||
validation.Field(&p.DependsOn, validation.By(DependsOn)),
|
||||
validation.Field(&p.Name, validation.By(validName)),
|
||||
@@ -118,6 +120,9 @@ func (p Project) ToValid() valid.Project {
|
||||
if p.TerraformVersion != nil {
|
||||
v.TerraformVersion, _ = version.NewVersion(*p.TerraformVersion)
|
||||
}
|
||||
if p.TerraformDistribution != nil {
|
||||
v.TerraformDistribution = p.TerraformDistribution
|
||||
}
|
||||
if p.Autoplan == nil {
|
||||
v.Autoplan = DefaultAutoPlan()
|
||||
} else {
|
||||
@@ -202,3 +207,11 @@ func validImportReq(value interface{}) error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validDistribution(value interface{}) error {
|
||||
distribution := value.(*string)
|
||||
if distribution != nil && *distribution != "terraform" && *distribution != "opentofu" {
|
||||
return fmt.Errorf("'%s' is not a valid terraform_distribution, only '%s' and '%s' are supported", *distribution, "terraform", "opentofu")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -105,6 +105,7 @@ type MergedProjectCfg struct {
|
||||
AutoplanEnabled bool
|
||||
AutoMergeDisabled bool
|
||||
AutoMergeMethod string
|
||||
TerraformDistribution *string
|
||||
TerraformVersion *version.Version
|
||||
RepoCfgVersion int
|
||||
PolicySets PolicySets
|
||||
@@ -412,6 +413,7 @@ func (g GlobalCfg) MergeProjectCfg(log logging.SimpleLogging, repoID string, pro
|
||||
DependsOn: proj.DependsOn,
|
||||
Name: proj.GetName(),
|
||||
AutoplanEnabled: proj.Autoplan.Enabled,
|
||||
TerraformDistribution: proj.TerraformDistribution,
|
||||
TerraformVersion: proj.TerraformVersion,
|
||||
RepoCfgVersion: rCfg.Version,
|
||||
PolicySets: g.PolicySets,
|
||||
@@ -438,6 +440,7 @@ func (g GlobalCfg) DefaultProjCfg(log logging.SimpleLogging, repoID string, repo
|
||||
Workspace: workspace,
|
||||
Name: "",
|
||||
AutoplanEnabled: DefaultAutoPlanEnabled,
|
||||
TerraformDistribution: nil,
|
||||
TerraformVersion: nil,
|
||||
PolicySets: g.PolicySets,
|
||||
DeleteSourceBranchOnMerge: deleteSourceBranchOnMerge,
|
||||
|
||||
@@ -147,6 +147,7 @@ type Project struct {
|
||||
Workspace string
|
||||
Name *string
|
||||
WorkflowName *string
|
||||
TerraformDistribution *string
|
||||
TerraformVersion *version.Version
|
||||
Autoplan Autoplan
|
||||
PlanRequirements []string
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
version "github.com/hashicorp/go-version"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/events/models"
|
||||
"github.com/runatlantis/atlantis/server/utils"
|
||||
@@ -17,10 +18,11 @@ import (
|
||||
|
||||
// ApplyStepRunner runs `terraform apply`.
|
||||
type ApplyStepRunner struct {
|
||||
TerraformExecutor TerraformExec
|
||||
DefaultTFVersion *version.Version
|
||||
CommitStatusUpdater StatusUpdater
|
||||
AsyncTFExec AsyncTFExec
|
||||
TerraformExecutor TerraformExec
|
||||
DefaultTFDistribution terraform.Distribution
|
||||
DefaultTFVersion *version.Version
|
||||
CommitStatusUpdater StatusUpdater
|
||||
AsyncTFExec AsyncTFExec
|
||||
}
|
||||
|
||||
func (a *ApplyStepRunner) Run(ctx command.ProjectContext, extraArgs []string, path string, envs map[string]string) (string, error) {
|
||||
@@ -39,11 +41,19 @@ func (a *ApplyStepRunner) Run(ctx command.ProjectContext, extraArgs []string, pa
|
||||
|
||||
ctx.Log.Info("starting apply")
|
||||
var out string
|
||||
tfDistribution := a.DefaultTFDistribution
|
||||
if ctx.TerraformDistribution != nil {
|
||||
tfDistribution = terraform.NewDistribution(*ctx.TerraformDistribution)
|
||||
}
|
||||
tfVersion := a.DefaultTFVersion
|
||||
if ctx.TerraformVersion != nil {
|
||||
tfVersion = ctx.TerraformVersion
|
||||
}
|
||||
|
||||
// TODO: Leverage PlanTypeStepRunnerDelegate here
|
||||
if IsRemotePlan(contents) {
|
||||
args := append(append([]string{"apply", "-input=false", "-no-color"}, extraArgs...), ctx.EscapedCommentArgs...)
|
||||
out, err = a.runRemoteApply(ctx, args, path, planPath, ctx.TerraformVersion, envs)
|
||||
out, err = a.runRemoteApply(ctx, args, path, planPath, tfDistribution, tfVersion, envs)
|
||||
if err == nil {
|
||||
out = a.cleanRemoteApplyOutput(out)
|
||||
}
|
||||
@@ -51,7 +61,7 @@ func (a *ApplyStepRunner) Run(ctx command.ProjectContext, extraArgs []string, pa
|
||||
// NOTE: we need to quote the plan path because Bitbucket Server can
|
||||
// have spaces in its repo owner names which is part of the path.
|
||||
args := append(append(append([]string{"apply", "-input=false"}, extraArgs...), ctx.EscapedCommentArgs...), fmt.Sprintf("%q", planPath))
|
||||
out, err = a.TerraformExecutor.RunCommandWithVersion(ctx, path, args, envs, ctx.TerraformVersion, ctx.Workspace)
|
||||
out, err = a.TerraformExecutor.RunCommandWithVersion(ctx, path, args, envs, tfDistribution, tfVersion, ctx.Workspace)
|
||||
}
|
||||
|
||||
// If the apply was successful, delete the plan.
|
||||
@@ -115,6 +125,7 @@ func (a *ApplyStepRunner) runRemoteApply(
|
||||
applyArgs []string,
|
||||
path string,
|
||||
absPlanPath string,
|
||||
tfDistribution terraform.Distribution,
|
||||
tfVersion *version.Version,
|
||||
envs map[string]string) (string, error) {
|
||||
// The planfile contents are needed to ensure that the plan didn't change
|
||||
@@ -133,7 +144,7 @@ func (a *ApplyStepRunner) runRemoteApply(
|
||||
|
||||
// Start the async command execution.
|
||||
ctx.Log.Debug("starting async tf remote operation")
|
||||
inCh, outCh := a.AsyncTFExec.RunCommandAsync(ctx, filepath.Clean(path), applyArgs, envs, tfVersion, ctx.Workspace)
|
||||
inCh, outCh := a.AsyncTFExec.RunCommandAsync(ctx, filepath.Clean(path), applyArgs, envs, tfDistribution, tfVersion, ctx.Workspace)
|
||||
var lines []string
|
||||
nextLineIsRunURL := false
|
||||
var runURL string
|
||||
|
||||
@@ -14,7 +14,9 @@ import (
|
||||
"github.com/runatlantis/atlantis/server/core/runtime"
|
||||
runtimemocks "github.com/runatlantis/atlantis/server/core/runtime/mocks"
|
||||
runtimemodels "github.com/runatlantis/atlantis/server/core/runtime/models"
|
||||
tf "github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform/mocks"
|
||||
tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/events/models"
|
||||
"github.com/runatlantis/atlantis/server/logging"
|
||||
@@ -59,17 +61,20 @@ func TestRun_Success(t *testing.T) {
|
||||
Ok(t, err)
|
||||
|
||||
RegisterMockTestingT(t)
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
o := runtime.ApplyStepRunner{
|
||||
TerraformExecutor: terraform,
|
||||
TerraformExecutor: terraform,
|
||||
DefaultTFDistribution: tfDistribution,
|
||||
}
|
||||
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[*version.Version](), Any[string]())).
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())).
|
||||
ThenReturn("output", nil)
|
||||
output, err := o.Run(ctx, []string{"extra", "args"}, tmpDir, map[string]string(nil))
|
||||
Ok(t, err)
|
||||
Equals(t, "output", output)
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, tmpDir, []string{"apply", "-input=false", "extra", "args", "comment", "args", fmt.Sprintf("%q", planPath)}, map[string]string(nil), nil, "workspace")
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, tmpDir, []string{"apply", "-input=false", "extra", "args", "comment", "args", fmt.Sprintf("%q", planPath)}, map[string]string(nil), tfDistribution, nil, "workspace")
|
||||
_, err = os.Stat(planPath)
|
||||
Assert(t, os.IsNotExist(err), "planfile should be deleted")
|
||||
}
|
||||
@@ -91,22 +96,24 @@ func TestRun_AppliesCorrectProjectPlan(t *testing.T) {
|
||||
Ok(t, err)
|
||||
|
||||
RegisterMockTestingT(t)
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
o := runtime.ApplyStepRunner{
|
||||
TerraformExecutor: terraform,
|
||||
TerraformExecutor: terraform,
|
||||
DefaultTFDistribution: tfDistribution,
|
||||
}
|
||||
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[*version.Version](), Any[string]())).
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())).
|
||||
ThenReturn("output", nil)
|
||||
output, err := o.Run(ctx, []string{"extra", "args"}, tmpDir, map[string]string(nil))
|
||||
Ok(t, err)
|
||||
Equals(t, "output", output)
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, tmpDir, []string{"apply", "-input=false", "extra", "args", "comment", "args", fmt.Sprintf("%q", planPath)}, map[string]string(nil), nil, "default")
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, tmpDir, []string{"apply", "-input=false", "extra", "args", "comment", "args", fmt.Sprintf("%q", planPath)}, map[string]string(nil), tfDistribution, nil, "default")
|
||||
_, err = os.Stat(planPath)
|
||||
Assert(t, os.IsNotExist(err), "planfile should be deleted")
|
||||
}
|
||||
|
||||
func TestRun_UsesConfiguredTFVersion(t *testing.T) {
|
||||
func TestApplyStepRunner_TestRun_UsesConfiguredTFVersion(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
planPath := filepath.Join(tmpDir, "workspace.tfplan")
|
||||
err := os.WriteFile(planPath, nil, 0600)
|
||||
@@ -123,17 +130,55 @@ func TestRun_UsesConfiguredTFVersion(t *testing.T) {
|
||||
}
|
||||
|
||||
RegisterMockTestingT(t)
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
o := runtime.ApplyStepRunner{
|
||||
TerraformExecutor: terraform,
|
||||
TerraformExecutor: terraform,
|
||||
DefaultTFDistribution: tfDistribution,
|
||||
}
|
||||
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[*version.Version](), Any[string]())).
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())).
|
||||
ThenReturn("output", nil)
|
||||
output, err := o.Run(ctx, []string{"extra", "args"}, tmpDir, map[string]string(nil))
|
||||
Ok(t, err)
|
||||
Equals(t, "output", output)
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, tmpDir, []string{"apply", "-input=false", "extra", "args", "comment", "args", fmt.Sprintf("%q", planPath)}, map[string]string(nil), tfVersion, "workspace")
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, tmpDir, []string{"apply", "-input=false", "extra", "args", "comment", "args", fmt.Sprintf("%q", planPath)}, map[string]string(nil), tfDistribution, tfVersion, "workspace")
|
||||
_, err = os.Stat(planPath)
|
||||
Assert(t, os.IsNotExist(err), "planfile should be deleted")
|
||||
}
|
||||
|
||||
func TestApplyStepRunner_TestRun_UsesConfiguredDistribution(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
planPath := filepath.Join(tmpDir, "workspace.tfplan")
|
||||
err := os.WriteFile(planPath, nil, 0600)
|
||||
Ok(t, err)
|
||||
|
||||
logger := logging.NewNoopLogger(t)
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
tfVersion, _ := version.NewVersion("0.11.0")
|
||||
projTFDistribution := "opentofu"
|
||||
ctx := command.ProjectContext{
|
||||
Workspace: "workspace",
|
||||
RepoRelDir: ".",
|
||||
EscapedCommentArgs: []string{"comment", "args"},
|
||||
TerraformDistribution: &projTFDistribution,
|
||||
Log: logger,
|
||||
}
|
||||
|
||||
RegisterMockTestingT(t)
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
o := runtime.ApplyStepRunner{
|
||||
TerraformExecutor: terraform,
|
||||
DefaultTFDistribution: tfDistribution,
|
||||
DefaultTFVersion: tfVersion,
|
||||
}
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), NotEq[tf.Distribution](tfDistribution), Any[*version.Version](), Any[string]())).
|
||||
ThenReturn("output", nil)
|
||||
output, err := o.Run(ctx, []string{"extra", "args"}, tmpDir, map[string]string(nil))
|
||||
Ok(t, err)
|
||||
Equals(t, "output", output)
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(ctx), Eq(tmpDir), Eq([]string{"apply", "-input=false", "extra", "args", "comment", "args", fmt.Sprintf("%q", planPath)}), Eq(map[string]string(nil)), NotEq[tf.Distribution](tfDistribution), Eq(tfVersion), Eq("workspace"))
|
||||
_, err = os.Stat(planPath)
|
||||
Assert(t, os.IsNotExist(err), "planfile should be deleted")
|
||||
}
|
||||
@@ -197,7 +242,7 @@ func TestRun_UsingTarget(t *testing.T) {
|
||||
planPath := filepath.Join(tmpDir, "workspace.tfplan")
|
||||
err := os.WriteFile(planPath, nil, 0600)
|
||||
Ok(t, err)
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
step := runtime.ApplyStepRunner{
|
||||
TerraformExecutor: terraform,
|
||||
}
|
||||
@@ -361,7 +406,7 @@ type remoteApplyMock struct {
|
||||
}
|
||||
|
||||
// RunCommandAsync fakes out running terraform async.
|
||||
func (r *remoteApplyMock) RunCommandAsync(_ command.ProjectContext, _ string, args []string, _ map[string]string, _ *version.Version, _ string) (chan<- string, <-chan runtimemodels.Line) {
|
||||
func (r *remoteApplyMock) RunCommandAsync(_ command.ProjectContext, _ string, args []string, _ map[string]string, _ tf.Distribution, _ *version.Version, _ string) (chan<- string, <-chan runtimemodels.Line) {
|
||||
r.CalledArgs = args
|
||||
|
||||
in := make(chan string)
|
||||
|
||||
@@ -5,7 +5,9 @@ import (
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/runatlantis/atlantis/server/core/runtime"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform/mocks"
|
||||
tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/events/models"
|
||||
jobmocks "github.com/runatlantis/atlantis/server/jobs/mocks"
|
||||
@@ -38,12 +40,15 @@ func TestEnvStepRunner_Run(t *testing.T) {
|
||||
},
|
||||
}
|
||||
RegisterMockTestingT(t)
|
||||
tfClient := mocks.NewMockClient()
|
||||
tfClient := tfclientmocks.NewMockClient()
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
tfVersion, err := version.NewVersion("0.12.0")
|
||||
Ok(t, err)
|
||||
projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler()
|
||||
runStepRunner := runtime.RunStepRunner{
|
||||
TerraformExecutor: tfClient,
|
||||
DefaultTFDistribution: tfDistribution,
|
||||
DefaultTFVersion: tfVersion,
|
||||
ProjectCmdOutputHandler: projectCmdOutputHandler,
|
||||
}
|
||||
|
||||
@@ -5,25 +5,32 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
version "github.com/hashicorp/go-version"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/utils"
|
||||
)
|
||||
|
||||
type importStepRunner struct {
|
||||
terraformExecutor TerraformExec
|
||||
defaultTFVersion *version.Version
|
||||
terraformExecutor TerraformExec
|
||||
defaultTFDistribution terraform.Distribution
|
||||
defaultTFVersion *version.Version
|
||||
}
|
||||
|
||||
func NewImportStepRunner(terraformExecutor TerraformExec, defaultTfVersion *version.Version) Runner {
|
||||
func NewImportStepRunner(terraformExecutor TerraformExec, defaultTfDistribution terraform.Distribution, defaultTfVersion *version.Version) Runner {
|
||||
runner := &importStepRunner{
|
||||
terraformExecutor: terraformExecutor,
|
||||
defaultTFVersion: defaultTfVersion,
|
||||
terraformExecutor: terraformExecutor,
|
||||
defaultTFDistribution: defaultTfDistribution,
|
||||
defaultTFVersion: defaultTfVersion,
|
||||
}
|
||||
return NewWorkspaceStepRunnerDelegate(terraformExecutor, defaultTfVersion, runner)
|
||||
return NewWorkspaceStepRunnerDelegate(terraformExecutor, defaultTfDistribution, defaultTfVersion, runner)
|
||||
}
|
||||
|
||||
func (p *importStepRunner) Run(ctx command.ProjectContext, extraArgs []string, path string, envs map[string]string) (string, error) {
|
||||
tfDistribution := p.defaultTFDistribution
|
||||
tfVersion := p.defaultTFVersion
|
||||
if ctx.TerraformDistribution != nil {
|
||||
tfDistribution = terraform.NewDistribution(*ctx.TerraformDistribution)
|
||||
}
|
||||
if ctx.TerraformVersion != nil {
|
||||
tfVersion = ctx.TerraformVersion
|
||||
}
|
||||
@@ -31,7 +38,7 @@ func (p *importStepRunner) Run(ctx command.ProjectContext, extraArgs []string, p
|
||||
importCmd := []string{"import"}
|
||||
importCmd = append(importCmd, extraArgs...)
|
||||
importCmd = append(importCmd, ctx.EscapedCommentArgs...)
|
||||
out, err := p.terraformExecutor.RunCommandWithVersion(ctx, filepath.Clean(path), importCmd, envs, tfVersion, ctx.Workspace)
|
||||
out, err := p.terraformExecutor.RunCommandWithVersion(ctx, filepath.Clean(path), importCmd, envs, tfDistribution, tfVersion, ctx.Workspace)
|
||||
|
||||
// If the import was successful and a plan file exists, delete the plan.
|
||||
planPath := filepath.Join(path, GetPlanFilename(ctx.Workspace, ctx.ProjectName))
|
||||
|
||||
@@ -8,7 +8,9 @@ import (
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
. "github.com/petergtz/pegomock/v4"
|
||||
tf "github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform/mocks"
|
||||
tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/logging"
|
||||
. "github.com/runatlantis/atlantis/testing"
|
||||
@@ -29,17 +31,19 @@ func TestImportStepRunner_Run_Success(t *testing.T) {
|
||||
}
|
||||
|
||||
RegisterMockTestingT(t)
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
tfVersion, _ := version.NewVersion("0.15.0")
|
||||
s := NewImportStepRunner(terraform, tfVersion)
|
||||
s := NewImportStepRunner(terraform, tfDistribution, tfVersion)
|
||||
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[*version.Version](), Any[string]())).
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())).
|
||||
ThenReturn("output", nil)
|
||||
output, err := s.Run(context, []string{}, tmpDir, map[string]string(nil))
|
||||
Ok(t, err)
|
||||
Equals(t, "output", output)
|
||||
commands := []string{"import", "-var", "foo=bar", "addr", "id"}
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, commands, map[string]string(nil), tfVersion, workspace)
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, commands, map[string]string(nil), tfDistribution, tfVersion, workspace)
|
||||
_, err = os.Stat(planPath)
|
||||
Assert(t, os.IsNotExist(err), "planfile should be deleted")
|
||||
}
|
||||
@@ -59,23 +63,66 @@ func TestImportStepRunner_Run_Workspace(t *testing.T) {
|
||||
}
|
||||
|
||||
RegisterMockTestingT(t)
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
tfVersion, _ := version.NewVersion("0.15.0")
|
||||
s := NewImportStepRunner(terraform, tfVersion)
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
s := NewImportStepRunner(terraform, tfDistribution, tfVersion)
|
||||
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[*version.Version](), Any[string]())).
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())).
|
||||
ThenReturn("output", nil)
|
||||
output, err := s.Run(context, []string{}, tmpDir, map[string]string(nil))
|
||||
Ok(t, err)
|
||||
Equals(t, "output", output)
|
||||
|
||||
// switch workspace
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, []string{"workspace", "show"}, map[string]string(nil), tfVersion, workspace)
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, []string{"workspace", "select", workspace}, map[string]string(nil), tfVersion, workspace)
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, []string{"workspace", "show"}, map[string]string(nil), tfDistribution, tfVersion, workspace)
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, []string{"workspace", "select", workspace}, map[string]string(nil), tfDistribution, tfVersion, workspace)
|
||||
|
||||
// exec import
|
||||
commands := []string{"import", "-var", "foo=bar", "addr", "id"}
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, commands, map[string]string(nil), tfVersion, workspace)
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, commands, map[string]string(nil), tfDistribution, tfVersion, workspace)
|
||||
|
||||
_, err = os.Stat(planPath)
|
||||
Assert(t, os.IsNotExist(err), "planfile should be deleted")
|
||||
}
|
||||
|
||||
func TestImportStepRunner_Run_UsesConfiguredDistribution(t *testing.T) {
|
||||
logger := logging.NewNoopLogger(t)
|
||||
workspace := "something"
|
||||
tmpDir := t.TempDir()
|
||||
planPath := filepath.Join(tmpDir, fmt.Sprintf("%s.tfplan", workspace))
|
||||
err := os.WriteFile(planPath, nil, 0600)
|
||||
Ok(t, err)
|
||||
|
||||
projTFDistribution := "opentofu"
|
||||
context := command.ProjectContext{
|
||||
Log: logger,
|
||||
EscapedCommentArgs: []string{"-var", "foo=bar", "addr", "id"},
|
||||
Workspace: workspace,
|
||||
TerraformDistribution: &projTFDistribution,
|
||||
}
|
||||
|
||||
RegisterMockTestingT(t)
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
tfVersion, _ := version.NewVersion("0.15.0")
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
s := NewImportStepRunner(terraform, tfDistribution, tfVersion)
|
||||
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())).
|
||||
ThenReturn("output", nil)
|
||||
output, err := s.Run(context, []string{}, tmpDir, map[string]string(nil))
|
||||
Ok(t, err)
|
||||
Equals(t, "output", output)
|
||||
|
||||
// switch workspace
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(context), Eq(tmpDir), Eq([]string{"workspace", "show"}), Eq(map[string]string(nil)), NotEq(tfDistribution), Eq(tfVersion), Eq(workspace))
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(context), Eq(tmpDir), Eq([]string{"workspace", "select", workspace}), Eq(map[string]string(nil)), NotEq(tfDistribution), Eq(tfVersion), Eq(workspace))
|
||||
|
||||
// exec import
|
||||
commands := []string{"import", "-var", "foo=bar", "addr", "id"}
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(context), Eq(tmpDir), Eq(commands), Eq(map[string]string(nil)), NotEq(tfDistribution), Eq(tfVersion), Eq(workspace))
|
||||
|
||||
_, err = os.Stat(planPath)
|
||||
Assert(t, os.IsNotExist(err), "planfile should be deleted")
|
||||
|
||||
@@ -5,14 +5,16 @@ import (
|
||||
|
||||
version "github.com/hashicorp/go-version"
|
||||
"github.com/runatlantis/atlantis/server/core/runtime/common"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/utils"
|
||||
)
|
||||
|
||||
// InitStep runs `terraform init`.
|
||||
type InitStepRunner struct {
|
||||
TerraformExecutor TerraformExec
|
||||
DefaultTFVersion *version.Version
|
||||
TerraformExecutor TerraformExec
|
||||
DefaultTFDistribution terraform.Distribution
|
||||
DefaultTFVersion *version.Version
|
||||
}
|
||||
|
||||
func (i *InitStepRunner) Run(ctx command.ProjectContext, extraArgs []string, path string, envs map[string]string) (string, error) {
|
||||
@@ -33,6 +35,11 @@ func (i *InitStepRunner) Run(ctx command.ProjectContext, extraArgs []string, pat
|
||||
}
|
||||
}
|
||||
|
||||
tfDistribution := i.DefaultTFDistribution
|
||||
if ctx.TerraformDistribution != nil {
|
||||
tfDistribution = terraform.NewDistribution(*ctx.TerraformDistribution)
|
||||
}
|
||||
|
||||
tfVersion := i.DefaultTFVersion
|
||||
if ctx.TerraformVersion != nil {
|
||||
tfVersion = ctx.TerraformVersion
|
||||
@@ -56,7 +63,7 @@ func (i *InitStepRunner) Run(ctx command.ProjectContext, extraArgs []string, pat
|
||||
|
||||
terraformInitCmd := append(terraformInitVerb, finalArgs...)
|
||||
|
||||
out, err := i.TerraformExecutor.RunCommandWithVersion(ctx, path, terraformInitCmd, envs, tfVersion, ctx.Workspace)
|
||||
out, err := i.TerraformExecutor.RunCommandWithVersion(ctx, path, terraformInitCmd, envs, tfDistribution, tfVersion, ctx.Workspace)
|
||||
// Only include the init output if there was an error. Otherwise it's
|
||||
// unnecessary and lengthens the comment.
|
||||
if err != nil {
|
||||
|
||||
@@ -12,7 +12,9 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/runatlantis/atlantis/server/core/runtime"
|
||||
tf "github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform/mocks"
|
||||
tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/logging"
|
||||
. "github.com/runatlantis/atlantis/testing"
|
||||
@@ -20,6 +22,8 @@ import (
|
||||
|
||||
func TestRun_UsesGetOrInitForRightVersion(t *testing.T) {
|
||||
RegisterMockTestingT(t)
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
cases := []struct {
|
||||
version string
|
||||
expCmd string
|
||||
@@ -44,7 +48,7 @@ func TestRun_UsesGetOrInitForRightVersion(t *testing.T) {
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.version, func(t *testing.T) {
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
|
||||
logger := logging.NewNoopLogger(t)
|
||||
ctx := command.ProjectContext{
|
||||
@@ -55,10 +59,11 @@ func TestRun_UsesGetOrInitForRightVersion(t *testing.T) {
|
||||
|
||||
tfVersion, _ := version.NewVersion(c.version)
|
||||
iso := runtime.InitStepRunner{
|
||||
TerraformExecutor: terraform,
|
||||
DefaultTFVersion: tfVersion,
|
||||
TerraformExecutor: terraform,
|
||||
DefaultTFDistribution: tfDistribution,
|
||||
DefaultTFVersion: tfVersion,
|
||||
}
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[*version.Version](), Any[string]())).
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())).
|
||||
ThenReturn("output", nil)
|
||||
|
||||
output, err := iso.Run(ctx, []string{"extra", "args"}, "/path", map[string]string(nil))
|
||||
@@ -71,7 +76,74 @@ func TestRun_UsesGetOrInitForRightVersion(t *testing.T) {
|
||||
if c.expCmd == "get" {
|
||||
expArgs = []string{c.expCmd, "-upgrade", "extra", "args"}
|
||||
}
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, "/path", expArgs, map[string]string(nil), tfVersion, "workspace")
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, "/path", expArgs, map[string]string(nil), tfDistribution, tfVersion, "workspace")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitStepRunner_TestRun_UsesConfiguredDistribution(t *testing.T) {
|
||||
RegisterMockTestingT(t)
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
cases := []struct {
|
||||
version string
|
||||
distribution string
|
||||
expCmd string
|
||||
}{
|
||||
{
|
||||
"0.8.9",
|
||||
"opentofu",
|
||||
"get",
|
||||
},
|
||||
{
|
||||
"0.8.9",
|
||||
"terraform",
|
||||
"get",
|
||||
},
|
||||
{
|
||||
"0.9.0",
|
||||
"opentofu",
|
||||
"init",
|
||||
},
|
||||
{
|
||||
"0.9.1",
|
||||
"terraform",
|
||||
"init",
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.version, func(t *testing.T) {
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
|
||||
logger := logging.NewNoopLogger(t)
|
||||
ctx := command.ProjectContext{
|
||||
Workspace: "workspace",
|
||||
RepoRelDir: ".",
|
||||
Log: logger,
|
||||
TerraformDistribution: &c.distribution,
|
||||
}
|
||||
|
||||
tfVersion, _ := version.NewVersion(c.version)
|
||||
iso := runtime.InitStepRunner{
|
||||
TerraformExecutor: terraform,
|
||||
DefaultTFDistribution: tfDistribution,
|
||||
DefaultTFVersion: tfVersion,
|
||||
}
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())).
|
||||
ThenReturn("output", nil)
|
||||
|
||||
output, err := iso.Run(ctx, []string{"extra", "args"}, "/path", map[string]string(nil))
|
||||
Ok(t, err)
|
||||
// When there is no error, should not return init output to PR.
|
||||
Equals(t, "", output)
|
||||
|
||||
// If using init then we specify -input=false but not for get.
|
||||
expArgs := []string{c.expCmd, "-input=false", "-upgrade", "extra", "args"}
|
||||
if c.expCmd == "get" {
|
||||
expArgs = []string{c.expCmd, "-upgrade", "extra", "args"}
|
||||
}
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(ctx), Eq("/path"), Eq(expArgs), Eq(map[string]string(nil)), NotEq(tfDistribution), Eq(tfVersion), Eq("workspace"))
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -79,15 +151,17 @@ func TestRun_UsesGetOrInitForRightVersion(t *testing.T) {
|
||||
func TestRun_ShowInitOutputOnError(t *testing.T) {
|
||||
// If there was an error during init then we want the output to be returned.
|
||||
RegisterMockTestingT(t)
|
||||
tfClient := mocks.NewMockClient()
|
||||
tfClient := tfclientmocks.NewMockClient()
|
||||
logger := logging.NewNoopLogger(t)
|
||||
When(tfClient.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[*version.Version](), Any[string]())).
|
||||
When(tfClient.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())).
|
||||
ThenReturn("output", errors.New("error"))
|
||||
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
tfVersion, _ := version.NewVersion("0.11.0")
|
||||
iso := runtime.InitStepRunner{
|
||||
TerraformExecutor: tfClient,
|
||||
DefaultTFVersion: tfVersion,
|
||||
TerraformExecutor: tfClient,
|
||||
DefaultTFDistribution: tfDistribution,
|
||||
DefaultTFVersion: tfVersion,
|
||||
}
|
||||
|
||||
output, err := iso.Run(command.ProjectContext{
|
||||
@@ -118,14 +192,16 @@ func TestRun_InitOmitsUpgradeFlagIfLockFileTracked(t *testing.T) {
|
||||
}
|
||||
|
||||
RegisterMockTestingT(t)
|
||||
terraform := mocks.NewMockClient()
|
||||
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
tfVersion, _ := version.NewVersion("0.14.0")
|
||||
iso := runtime.InitStepRunner{
|
||||
TerraformExecutor: terraform,
|
||||
DefaultTFVersion: tfVersion,
|
||||
TerraformExecutor: terraform,
|
||||
DefaultTFDistribution: tfDistribution,
|
||||
DefaultTFVersion: tfVersion,
|
||||
}
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[*version.Version](), Any[string]())).
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())).
|
||||
ThenReturn("output", nil)
|
||||
|
||||
output, err := iso.Run(ctx, []string{"extra", "args"}, repoDir, map[string]string(nil))
|
||||
@@ -134,27 +210,29 @@ func TestRun_InitOmitsUpgradeFlagIfLockFileTracked(t *testing.T) {
|
||||
Equals(t, "", output)
|
||||
|
||||
expectedArgs := []string{"init", "-input=false", "extra", "args"}
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, repoDir, expectedArgs, map[string]string(nil), tfVersion, "workspace")
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, repoDir, expectedArgs, map[string]string(nil), tfDistribution, tfVersion, "workspace")
|
||||
}
|
||||
|
||||
func TestRun_InitKeepsUpgradeFlagIfLockFileNotPresent(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
RegisterMockTestingT(t)
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
logger := logging.NewNoopLogger(t)
|
||||
ctx := command.ProjectContext{
|
||||
Workspace: "workspace",
|
||||
RepoRelDir: ".",
|
||||
Log: logger,
|
||||
}
|
||||
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
tfVersion, _ := version.NewVersion("0.14.0")
|
||||
iso := runtime.InitStepRunner{
|
||||
TerraformExecutor: terraform,
|
||||
DefaultTFVersion: tfVersion,
|
||||
TerraformExecutor: terraform,
|
||||
DefaultTFDistribution: tfDistribution,
|
||||
DefaultTFVersion: tfVersion,
|
||||
}
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[*version.Version](), Any[string]())).
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())).
|
||||
ThenReturn("output", nil)
|
||||
|
||||
output, err := iso.Run(ctx, []string{"extra", "args"}, tmpDir, map[string]string(nil))
|
||||
@@ -163,7 +241,7 @@ func TestRun_InitKeepsUpgradeFlagIfLockFileNotPresent(t *testing.T) {
|
||||
Equals(t, "", output)
|
||||
|
||||
expectedArgs := []string{"init", "-input=false", "-upgrade", "extra", "args"}
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, tmpDir, expectedArgs, map[string]string(nil), tfVersion, "workspace")
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, tmpDir, expectedArgs, map[string]string(nil), tfDistribution, tfVersion, "workspace")
|
||||
}
|
||||
|
||||
func TestRun_InitKeepUpgradeFlagIfLockFilePresentAndTFLessThanPoint14(t *testing.T) {
|
||||
@@ -173,7 +251,7 @@ func TestRun_InitKeepUpgradeFlagIfLockFilePresentAndTFLessThanPoint14(t *testing
|
||||
Ok(t, err)
|
||||
|
||||
RegisterMockTestingT(t)
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
|
||||
logger := logging.NewNoopLogger(t)
|
||||
ctx := command.ProjectContext{
|
||||
@@ -181,13 +259,15 @@ func TestRun_InitKeepUpgradeFlagIfLockFilePresentAndTFLessThanPoint14(t *testing
|
||||
RepoRelDir: ".",
|
||||
Log: logger,
|
||||
}
|
||||
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
tfVersion, _ := version.NewVersion("0.13.0")
|
||||
iso := runtime.InitStepRunner{
|
||||
TerraformExecutor: terraform,
|
||||
DefaultTFVersion: tfVersion,
|
||||
TerraformExecutor: terraform,
|
||||
DefaultTFDistribution: tfDistribution,
|
||||
DefaultTFVersion: tfVersion,
|
||||
}
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[*version.Version](), Any[string]())).
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())).
|
||||
ThenReturn("output", nil)
|
||||
|
||||
output, err := iso.Run(ctx, []string{"extra", "args"}, tmpDir, map[string]string(nil))
|
||||
@@ -196,7 +276,7 @@ func TestRun_InitKeepUpgradeFlagIfLockFilePresentAndTFLessThanPoint14(t *testing
|
||||
Equals(t, "", output)
|
||||
|
||||
expectedArgs := []string{"init", "-input=false", "-upgrade", "extra", "args"}
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, tmpDir, expectedArgs, map[string]string(nil), tfVersion, "workspace")
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, tmpDir, expectedArgs, map[string]string(nil), tfDistribution, tfVersion, "workspace")
|
||||
}
|
||||
|
||||
func TestRun_InitExtraArgsDeDupe(t *testing.T) {
|
||||
@@ -240,7 +320,7 @@ func TestRun_InitExtraArgsDeDupe(t *testing.T) {
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.description, func(t *testing.T) {
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
|
||||
logger := logging.NewNoopLogger(t)
|
||||
ctx := command.ProjectContext{
|
||||
@@ -248,13 +328,15 @@ func TestRun_InitExtraArgsDeDupe(t *testing.T) {
|
||||
RepoRelDir: ".",
|
||||
Log: logger,
|
||||
}
|
||||
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
tfVersion, _ := version.NewVersion("0.10.0")
|
||||
iso := runtime.InitStepRunner{
|
||||
TerraformExecutor: terraform,
|
||||
DefaultTFVersion: tfVersion,
|
||||
TerraformExecutor: terraform,
|
||||
DefaultTFDistribution: tfDistribution,
|
||||
DefaultTFVersion: tfVersion,
|
||||
}
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[*version.Version](), Any[string]())).
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())).
|
||||
ThenReturn("output", nil)
|
||||
|
||||
output, err := iso.Run(ctx, c.extraArgs, "/path", map[string]string(nil))
|
||||
@@ -262,7 +344,7 @@ func TestRun_InitExtraArgsDeDupe(t *testing.T) {
|
||||
// When there is no error, should not return init output to PR.
|
||||
Equals(t, "", output)
|
||||
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, "/path", c.expectedArgs, map[string]string(nil), tfVersion, "workspace")
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, "/path", c.expectedArgs, map[string]string(nil), tfDistribution, tfVersion, "workspace")
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -276,17 +358,19 @@ func TestRun_InitDeletesLockFileIfPresentAndNotTracked(t *testing.T) {
|
||||
Ok(t, err)
|
||||
|
||||
RegisterMockTestingT(t)
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
|
||||
logger := logging.NewNoopLogger(t)
|
||||
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
tfVersion, _ := version.NewVersion("0.14.0")
|
||||
|
||||
iso := runtime.InitStepRunner{
|
||||
TerraformExecutor: terraform,
|
||||
DefaultTFVersion: tfVersion,
|
||||
TerraformExecutor: terraform,
|
||||
DefaultTFDistribution: tfDistribution,
|
||||
DefaultTFVersion: tfVersion,
|
||||
}
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[*version.Version](), Any[string]())).
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())).
|
||||
ThenReturn("output", nil)
|
||||
|
||||
ctx := command.ProjectContext{
|
||||
@@ -300,7 +384,7 @@ func TestRun_InitDeletesLockFileIfPresentAndNotTracked(t *testing.T) {
|
||||
Equals(t, "", output)
|
||||
|
||||
expectedArgs := []string{"init", "-input=false", "-upgrade", "extra", "args"}
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, repoDir, expectedArgs, map[string]string(nil), tfVersion, "workspace")
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, repoDir, expectedArgs, map[string]string(nil), tfDistribution, tfVersion, "workspace")
|
||||
}
|
||||
|
||||
func runCmd(t *testing.T, dir string, name string, args ...string) string {
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
go_version "github.com/hashicorp/go-version"
|
||||
pegomock "github.com/petergtz/pegomock/v4"
|
||||
models "github.com/runatlantis/atlantis/server/core/runtime/models"
|
||||
terraform "github.com/runatlantis/atlantis/server/core/terraform"
|
||||
command "github.com/runatlantis/atlantis/server/events/command"
|
||||
"reflect"
|
||||
"time"
|
||||
@@ -27,11 +28,11 @@ func NewMockAsyncTFExec(options ...pegomock.Option) *MockAsyncTFExec {
|
||||
func (mock *MockAsyncTFExec) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh }
|
||||
func (mock *MockAsyncTFExec) FailHandler() pegomock.FailHandler { return mock.fail }
|
||||
|
||||
func (mock *MockAsyncTFExec) RunCommandAsync(ctx command.ProjectContext, path string, args []string, envs map[string]string, v *go_version.Version, workspace string) (chan<- string, <-chan models.Line) {
|
||||
func (mock *MockAsyncTFExec) RunCommandAsync(ctx command.ProjectContext, path string, args []string, envs map[string]string, d terraform.Distribution, v *go_version.Version, workspace string) (chan<- string, <-chan models.Line) {
|
||||
if mock == nil {
|
||||
panic("mock must not be nil. Use myMock := NewMockAsyncTFExec().")
|
||||
}
|
||||
_params := []pegomock.Param{ctx, path, args, envs, v, workspace}
|
||||
_params := []pegomock.Param{ctx, path, args, envs, d, v, workspace}
|
||||
_result := pegomock.GetGenericMockFrom(mock).Invoke("RunCommandAsync", _params, []reflect.Type{reflect.TypeOf((*chan<- string)(nil)).Elem(), reflect.TypeOf((*<-chan models.Line)(nil)).Elem()})
|
||||
var _ret0 chan<- string
|
||||
var _ret1 <-chan models.Line
|
||||
@@ -91,8 +92,8 @@ type VerifierMockAsyncTFExec struct {
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
func (verifier *VerifierMockAsyncTFExec) RunCommandAsync(ctx command.ProjectContext, path string, args []string, envs map[string]string, v *go_version.Version, workspace string) *MockAsyncTFExec_RunCommandAsync_OngoingVerification {
|
||||
_params := []pegomock.Param{ctx, path, args, envs, v, workspace}
|
||||
func (verifier *VerifierMockAsyncTFExec) RunCommandAsync(ctx command.ProjectContext, path string, args []string, envs map[string]string, d terraform.Distribution, v *go_version.Version, workspace string) *MockAsyncTFExec_RunCommandAsync_OngoingVerification {
|
||||
_params := []pegomock.Param{ctx, path, args, envs, d, v, workspace}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "RunCommandAsync", _params, verifier.timeout)
|
||||
return &MockAsyncTFExec_RunCommandAsync_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
@@ -102,12 +103,12 @@ type MockAsyncTFExec_RunCommandAsync_OngoingVerification struct {
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *MockAsyncTFExec_RunCommandAsync_OngoingVerification) GetCapturedArguments() (command.ProjectContext, string, []string, map[string]string, *go_version.Version, string) {
|
||||
ctx, path, args, envs, v, workspace := c.GetAllCapturedArguments()
|
||||
return ctx[len(ctx)-1], path[len(path)-1], args[len(args)-1], envs[len(envs)-1], v[len(v)-1], workspace[len(workspace)-1]
|
||||
func (c *MockAsyncTFExec_RunCommandAsync_OngoingVerification) GetCapturedArguments() (command.ProjectContext, string, []string, map[string]string, terraform.Distribution, *go_version.Version, string) {
|
||||
ctx, path, args, envs, d, v, workspace := c.GetAllCapturedArguments()
|
||||
return ctx[len(ctx)-1], path[len(path)-1], args[len(args)-1], envs[len(envs)-1], d[len(d)-1], v[len(v)-1], workspace[len(workspace)-1]
|
||||
}
|
||||
|
||||
func (c *MockAsyncTFExec_RunCommandAsync_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext, _param1 []string, _param2 [][]string, _param3 []map[string]string, _param4 []*go_version.Version, _param5 []string) {
|
||||
func (c *MockAsyncTFExec_RunCommandAsync_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext, _param1 []string, _param2 [][]string, _param3 []map[string]string, _param4 []terraform.Distribution, _param5 []*go_version.Version, _param6 []string) {
|
||||
_params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(_params) > 0 {
|
||||
if len(_params) > 0 {
|
||||
@@ -135,15 +136,21 @@ func (c *MockAsyncTFExec_RunCommandAsync_OngoingVerification) GetAllCapturedArgu
|
||||
}
|
||||
}
|
||||
if len(_params) > 4 {
|
||||
_param4 = make([]*go_version.Version, len(c.methodInvocations))
|
||||
_param4 = make([]terraform.Distribution, len(c.methodInvocations))
|
||||
for u, param := range _params[4] {
|
||||
_param4[u] = param.(*go_version.Version)
|
||||
_param4[u] = param.(terraform.Distribution)
|
||||
}
|
||||
}
|
||||
if len(_params) > 5 {
|
||||
_param5 = make([]string, len(c.methodInvocations))
|
||||
_param5 = make([]*go_version.Version, len(c.methodInvocations))
|
||||
for u, param := range _params[5] {
|
||||
_param5[u] = param.(string)
|
||||
_param5[u] = param.(*go_version.Version)
|
||||
}
|
||||
}
|
||||
if len(_params) > 6 {
|
||||
_param6 = make([]string, len(c.methodInvocations))
|
||||
for u, param := range _params[6] {
|
||||
_param6[u] = param.(string)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@ import (
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/runatlantis/atlantis/server/core/config/valid"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform/ansi"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/events/terraform/ansi"
|
||||
"github.com/runatlantis/atlantis/server/jobs"
|
||||
)
|
||||
|
||||
|
||||
@@ -7,7 +7,9 @@ import (
|
||||
. "github.com/petergtz/pegomock/v4"
|
||||
"github.com/runatlantis/atlantis/server/core/config/valid"
|
||||
"github.com/runatlantis/atlantis/server/core/runtime"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform/mocks"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform"
|
||||
terraformmocks "github.com/runatlantis/atlantis/server/core/terraform/mocks"
|
||||
tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/events/models"
|
||||
jobmocks "github.com/runatlantis/atlantis/server/jobs/mocks"
|
||||
@@ -45,12 +47,15 @@ func TestMultiEnvStepRunner_Run(t *testing.T) {
|
||||
},
|
||||
}
|
||||
RegisterMockTestingT(t)
|
||||
tfClient := mocks.NewMockClient()
|
||||
tfClient := tfclientmocks.NewMockClient()
|
||||
mockDownloader := terraformmocks.NewMockDownloader()
|
||||
tfDistribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
tfVersion, err := version.NewVersion("0.12.0")
|
||||
Ok(t, err)
|
||||
projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler()
|
||||
runStepRunner := runtime.RunStepRunner{
|
||||
TerraformExecutor: tfClient,
|
||||
DefaultTFDistribution: tfDistribution,
|
||||
DefaultTFVersion: tfVersion,
|
||||
ProjectCmdOutputHandler: projectCmdOutputHandler,
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
version "github.com/hashicorp/go-version"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/events/models"
|
||||
)
|
||||
@@ -26,34 +27,40 @@ var (
|
||||
)
|
||||
|
||||
type planStepRunner struct {
|
||||
TerraformExecutor TerraformExec
|
||||
DefaultTFVersion *version.Version
|
||||
CommitStatusUpdater StatusUpdater
|
||||
AsyncTFExec AsyncTFExec
|
||||
TerraformExecutor TerraformExec
|
||||
DefaultTFDistribution terraform.Distribution
|
||||
DefaultTFVersion *version.Version
|
||||
CommitStatusUpdater StatusUpdater
|
||||
AsyncTFExec AsyncTFExec
|
||||
}
|
||||
|
||||
func NewPlanStepRunner(terraformExecutor TerraformExec, defaultTfVersion *version.Version, commitStatusUpdater StatusUpdater, asyncTFExec AsyncTFExec) Runner {
|
||||
func NewPlanStepRunner(terraformExecutor TerraformExec, defaultTfDistribution terraform.Distribution, defaultTfVersion *version.Version, commitStatusUpdater StatusUpdater, asyncTFExec AsyncTFExec) Runner {
|
||||
runner := &planStepRunner{
|
||||
TerraformExecutor: terraformExecutor,
|
||||
DefaultTFVersion: defaultTfVersion,
|
||||
CommitStatusUpdater: commitStatusUpdater,
|
||||
AsyncTFExec: asyncTFExec,
|
||||
TerraformExecutor: terraformExecutor,
|
||||
DefaultTFDistribution: defaultTfDistribution,
|
||||
DefaultTFVersion: defaultTfVersion,
|
||||
CommitStatusUpdater: commitStatusUpdater,
|
||||
AsyncTFExec: asyncTFExec,
|
||||
}
|
||||
return NewWorkspaceStepRunnerDelegate(terraformExecutor, defaultTfVersion, runner)
|
||||
return NewWorkspaceStepRunnerDelegate(terraformExecutor, defaultTfDistribution, defaultTfVersion, runner)
|
||||
}
|
||||
|
||||
func (p *planStepRunner) Run(ctx command.ProjectContext, extraArgs []string, path string, envs map[string]string) (string, error) {
|
||||
tfDistribution := p.DefaultTFDistribution
|
||||
tfVersion := p.DefaultTFVersion
|
||||
if ctx.TerraformDistribution != nil {
|
||||
tfDistribution = terraform.NewDistribution(*ctx.TerraformDistribution)
|
||||
}
|
||||
if ctx.TerraformVersion != nil {
|
||||
tfVersion = ctx.TerraformVersion
|
||||
}
|
||||
|
||||
planFile := filepath.Join(path, GetPlanFilename(ctx.Workspace, ctx.ProjectName))
|
||||
planCmd := p.buildPlanCmd(ctx, extraArgs, path, tfVersion, planFile)
|
||||
output, err := p.TerraformExecutor.RunCommandWithVersion(ctx, filepath.Clean(path), planCmd, envs, tfVersion, ctx.Workspace)
|
||||
output, err := p.TerraformExecutor.RunCommandWithVersion(ctx, filepath.Clean(path), planCmd, envs, tfDistribution, tfVersion, ctx.Workspace)
|
||||
if p.isRemoteOpsErr(output, err) {
|
||||
ctx.Log.Debug("detected that this project is using TFE remote ops")
|
||||
return p.remotePlan(ctx, extraArgs, path, tfVersion, planFile, envs)
|
||||
return p.remotePlan(ctx, extraArgs, path, tfDistribution, tfVersion, planFile, envs)
|
||||
}
|
||||
if err != nil {
|
||||
return output, err
|
||||
@@ -72,14 +79,14 @@ func (p *planStepRunner) isRemoteOpsErr(output string, err error) bool {
|
||||
|
||||
// remotePlan runs a terraform plan command compatible with TFE remote
|
||||
// operations.
|
||||
func (p *planStepRunner) remotePlan(ctx command.ProjectContext, extraArgs []string, path string, tfVersion *version.Version, planFile string, envs map[string]string) (string, error) {
|
||||
func (p *planStepRunner) remotePlan(ctx command.ProjectContext, extraArgs []string, path string, tfDistribution terraform.Distribution, tfVersion *version.Version, planFile string, envs map[string]string) (string, error) {
|
||||
argList := [][]string{
|
||||
{"plan", "-input=false", "-refresh", "-no-color"},
|
||||
extraArgs,
|
||||
ctx.EscapedCommentArgs,
|
||||
}
|
||||
args := p.flatten(argList)
|
||||
output, err := p.runRemotePlan(ctx, args, path, tfVersion, envs)
|
||||
output, err := p.runRemotePlan(ctx, args, path, tfDistribution, tfVersion, envs)
|
||||
if err != nil {
|
||||
return output, err
|
||||
}
|
||||
@@ -193,6 +200,7 @@ func (p *planStepRunner) runRemotePlan(
|
||||
ctx command.ProjectContext,
|
||||
cmdArgs []string,
|
||||
path string,
|
||||
tfDistribution terraform.Distribution,
|
||||
tfVersion *version.Version,
|
||||
envs map[string]string) (string, error) {
|
||||
|
||||
@@ -205,7 +213,7 @@ func (p *planStepRunner) runRemotePlan(
|
||||
|
||||
// Start the async command execution.
|
||||
ctx.Log.Debug("starting async tf remote operation")
|
||||
_, outCh := p.AsyncTFExec.RunCommandAsync(ctx, filepath.Clean(path), cmdArgs, envs, tfVersion, ctx.Workspace)
|
||||
_, outCh := p.AsyncTFExec.RunCommandAsync(ctx, filepath.Clean(path), cmdArgs, envs, tfDistribution, tfVersion, ctx.Workspace)
|
||||
var lines []string
|
||||
nextLineIsRunURL := false
|
||||
var runURL string
|
||||
|
||||
@@ -13,7 +13,9 @@ import (
|
||||
"github.com/runatlantis/atlantis/server/core/runtime"
|
||||
runtimemocks "github.com/runatlantis/atlantis/server/core/runtime/mocks"
|
||||
runtimemodels "github.com/runatlantis/atlantis/server/core/runtime/models"
|
||||
tf "github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform/mocks"
|
||||
tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/events/models"
|
||||
"github.com/runatlantis/atlantis/server/logging"
|
||||
@@ -24,7 +26,7 @@ import (
|
||||
func TestRun_AddsEnvVarFile(t *testing.T) {
|
||||
// Test that if env/workspace.tfvars file exists we use -var-file option.
|
||||
RegisterMockTestingT(t)
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
commitStatusUpdater := runtimemocks.NewMockStatusUpdater()
|
||||
asyncTfExec := runtimemocks.NewMockAsyncTFExec()
|
||||
|
||||
@@ -36,10 +38,12 @@ func TestRun_AddsEnvVarFile(t *testing.T) {
|
||||
err = os.WriteFile(envVarsFile, nil, 0600)
|
||||
Ok(t, err)
|
||||
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
// Using version >= 0.10 here so we don't expect any env commands.
|
||||
tfVersion, _ := version.NewVersion("0.10.0")
|
||||
logger := logging.NewNoopLogger(t)
|
||||
s := runtime.NewPlanStepRunner(terraform, tfVersion, commitStatusUpdater, asyncTfExec)
|
||||
s := runtime.NewPlanStepRunner(terraform, tfDistribution, tfVersion, commitStatusUpdater, asyncTfExec)
|
||||
|
||||
expPlanArgs := []string{"plan",
|
||||
"-input=false",
|
||||
@@ -78,14 +82,14 @@ func TestRun_AddsEnvVarFile(t *testing.T) {
|
||||
Name: "repo",
|
||||
},
|
||||
}
|
||||
When(terraform.RunCommandWithVersion(ctx, tmpDir, expPlanArgs, map[string]string(nil), tfVersion, "workspace")).ThenReturn("output", nil)
|
||||
When(terraform.RunCommandWithVersion(ctx, tmpDir, expPlanArgs, map[string]string(nil), tfDistribution, tfVersion, "workspace")).ThenReturn("output", nil)
|
||||
|
||||
output, err := s.Run(ctx, []string{"extra", "args"}, tmpDir, map[string]string(nil))
|
||||
Ok(t, err)
|
||||
|
||||
// Verify that env select was never called since we're in version >= 0.10
|
||||
terraform.VerifyWasCalled(Never()).RunCommandWithVersion(ctx, tmpDir, []string{"env", "select", "workspace"}, map[string]string(nil), tfVersion, "workspace")
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, tmpDir, expPlanArgs, map[string]string(nil), tfVersion, "workspace")
|
||||
terraform.VerifyWasCalled(Never()).RunCommandWithVersion(ctx, tmpDir, []string{"env", "select", "workspace"}, map[string]string(nil), tfDistribution, tfVersion, "workspace")
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, tmpDir, expPlanArgs, map[string]string(nil), tfDistribution, tfVersion, "workspace")
|
||||
Equals(t, "output", output)
|
||||
}
|
||||
|
||||
@@ -93,12 +97,14 @@ func TestRun_UsesDiffPathForProject(t *testing.T) {
|
||||
// Test that if running for a project, uses a different path for the plan
|
||||
// file.
|
||||
RegisterMockTestingT(t)
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
commitStatusUpdater := runtimemocks.NewMockStatusUpdater()
|
||||
asyncTfExec := runtimemocks.NewMockAsyncTFExec()
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
tfVersion, _ := version.NewVersion("0.10.0")
|
||||
logger := logging.NewNoopLogger(t)
|
||||
s := runtime.NewPlanStepRunner(terraform, tfVersion, commitStatusUpdater, asyncTfExec)
|
||||
s := runtime.NewPlanStepRunner(terraform, tfDistribution, tfVersion, commitStatusUpdater, asyncTfExec)
|
||||
ctx := command.ProjectContext{
|
||||
Log: logger,
|
||||
Workspace: "default",
|
||||
@@ -115,7 +121,7 @@ func TestRun_UsesDiffPathForProject(t *testing.T) {
|
||||
Name: "repo",
|
||||
},
|
||||
}
|
||||
When(terraform.RunCommandWithVersion(ctx, "/path", []string{"workspace", "show"}, map[string]string(nil), tfVersion, "workspace")).ThenReturn("workspace\n", nil)
|
||||
When(terraform.RunCommandWithVersion(ctx, "/path", []string{"workspace", "show"}, map[string]string(nil), tfDistribution, tfVersion, "workspace")).ThenReturn("workspace\n", nil)
|
||||
|
||||
expPlanArgs := []string{"plan",
|
||||
"-input=false",
|
||||
@@ -137,7 +143,7 @@ func TestRun_UsesDiffPathForProject(t *testing.T) {
|
||||
"comment",
|
||||
"args",
|
||||
}
|
||||
When(terraform.RunCommandWithVersion(ctx, "/path", expPlanArgs, map[string]string(nil), tfVersion, "default")).ThenReturn("output", nil)
|
||||
When(terraform.RunCommandWithVersion(ctx, "/path", expPlanArgs, map[string]string(nil), tfDistribution, tfVersion, "default")).ThenReturn("output", nil)
|
||||
|
||||
output, err := s.Run(ctx, []string{"extra", "args"}, "/path", map[string]string(nil))
|
||||
Ok(t, err)
|
||||
@@ -173,16 +179,19 @@ Terraform will perform the following actions:
|
||||
- aws_security_group_rule.allow_all
|
||||
`
|
||||
RegisterMockTestingT(t)
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
commitStatusUpdater := runtimemocks.NewMockStatusUpdater()
|
||||
asyncTfExec := runtimemocks.NewMockAsyncTFExec()
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
tfVersion, _ := version.NewVersion("0.10.0")
|
||||
s := runtime.NewPlanStepRunner(terraform, tfVersion, commitStatusUpdater, asyncTfExec)
|
||||
s := runtime.NewPlanStepRunner(terraform, tfDistribution, tfVersion, commitStatusUpdater, asyncTfExec)
|
||||
When(terraform.RunCommandWithVersion(
|
||||
Any[command.ProjectContext](),
|
||||
Any[string](),
|
||||
Any[[]string](),
|
||||
Any[map[string]string](),
|
||||
Any[tf.Distribution](),
|
||||
Any[*version.Version](),
|
||||
Any[string]())).
|
||||
Then(func(params []Param) ReturnValues {
|
||||
@@ -223,11 +232,13 @@ Terraform will perform the following actions:
|
||||
// Test that even if there's an error, we get the returned output.
|
||||
func TestRun_OutputOnErr(t *testing.T) {
|
||||
RegisterMockTestingT(t)
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
commitStatusUpdater := runtimemocks.NewMockStatusUpdater()
|
||||
asyncTfExec := runtimemocks.NewMockAsyncTFExec()
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
tfVersion, _ := version.NewVersion("0.10.0")
|
||||
s := runtime.NewPlanStepRunner(terraform, tfVersion, commitStatusUpdater, asyncTfExec)
|
||||
s := runtime.NewPlanStepRunner(terraform, tfDistribution, tfVersion, commitStatusUpdater, asyncTfExec)
|
||||
expOutput := "expected output"
|
||||
expErrMsg := "error!"
|
||||
When(terraform.RunCommandWithVersion(
|
||||
@@ -235,6 +246,7 @@ func TestRun_OutputOnErr(t *testing.T) {
|
||||
Any[string](),
|
||||
Any[[]string](),
|
||||
Any[map[string]string](),
|
||||
Any[tf.Distribution](),
|
||||
Any[*version.Version](),
|
||||
Any[string]())).
|
||||
Then(func(params []Param) ReturnValues {
|
||||
@@ -287,7 +299,7 @@ func TestRun_NoOptionalVarsIn012(t *testing.T) {
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
commitStatusUpdater := runtimemocks.NewMockStatusUpdater()
|
||||
asyncTfExec := runtimemocks.NewMockAsyncTFExec()
|
||||
When(terraform.RunCommandWithVersion(
|
||||
@@ -295,11 +307,14 @@ func TestRun_NoOptionalVarsIn012(t *testing.T) {
|
||||
Any[string](),
|
||||
Any[[]string](),
|
||||
Any[map[string]string](),
|
||||
Any[tf.Distribution](),
|
||||
Any[*version.Version](),
|
||||
Any[string]())).ThenReturn("output", nil)
|
||||
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
tfVersion, _ := version.NewVersion(c.tfVersion)
|
||||
s := runtime.NewPlanStepRunner(terraform, tfVersion, commitStatusUpdater, asyncTfExec)
|
||||
s := runtime.NewPlanStepRunner(terraform, tfDistribution, tfVersion, commitStatusUpdater, asyncTfExec)
|
||||
ctx := command.ProjectContext{
|
||||
Workspace: "default",
|
||||
RepoRelDir: ".",
|
||||
@@ -319,7 +334,7 @@ func TestRun_NoOptionalVarsIn012(t *testing.T) {
|
||||
Ok(t, err)
|
||||
Equals(t, "output", output)
|
||||
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, "/path", expPlanArgs, map[string]string(nil), tfVersion, "default")
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, "/path", expPlanArgs, map[string]string(nil), tfDistribution, tfVersion, "default")
|
||||
})
|
||||
}
|
||||
|
||||
@@ -385,11 +400,13 @@ locally at this time.
|
||||
},
|
||||
}
|
||||
RegisterMockTestingT(t)
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
commitStatusUpdater := runtimemocks.NewMockStatusUpdater()
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
tfVersion, _ := version.NewVersion(c.tfVersion)
|
||||
asyncTf := &remotePlanMock{}
|
||||
s := runtime.NewPlanStepRunner(terraform, tfVersion, commitStatusUpdater, asyncTf)
|
||||
s := runtime.NewPlanStepRunner(terraform, tfDistribution, tfVersion, commitStatusUpdater, asyncTf)
|
||||
absProjectPath := t.TempDir()
|
||||
|
||||
// First, terraform workspace gets run.
|
||||
@@ -398,6 +415,7 @@ locally at this time.
|
||||
absProjectPath,
|
||||
[]string{"workspace", "show"},
|
||||
map[string]string(nil),
|
||||
tfDistribution,
|
||||
tfVersion,
|
||||
"default")).ThenReturn("default\n", nil)
|
||||
|
||||
@@ -438,7 +456,7 @@ locally at this time.
|
||||
planErr := errors.New("exit status 1: err")
|
||||
planOutput := "\n" + c.remoteOpsErr
|
||||
asyncTf.LinesToSend = remotePlanOutput
|
||||
When(terraform.RunCommandWithVersion(ctx, absProjectPath, expPlanArgs, map[string]string(nil), tfVersion, "default")).
|
||||
When(terraform.RunCommandWithVersion(ctx, absProjectPath, expPlanArgs, map[string]string(nil), tfDistribution, tfVersion, "default")).
|
||||
ThenReturn(planOutput, planErr)
|
||||
|
||||
output, err := s.Run(ctx, []string{"extra", "args"}, absProjectPath, map[string]string(nil))
|
||||
@@ -536,6 +554,82 @@ Plan: 0 to add, 0 to change, 1 to destroy.`, output)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPlanStepRunner_TestRun_UsesConfiguredDistribution(t *testing.T) {
|
||||
RegisterMockTestingT(t)
|
||||
|
||||
expPlanArgs := []string{
|
||||
"plan",
|
||||
"-input=false",
|
||||
"-refresh",
|
||||
"-out",
|
||||
fmt.Sprintf("%q", "/path/default.tfplan"),
|
||||
"extra",
|
||||
"args",
|
||||
"comment",
|
||||
"args",
|
||||
}
|
||||
|
||||
cases := []struct {
|
||||
name string
|
||||
tfVersion string
|
||||
tfDistribution string
|
||||
}{
|
||||
{
|
||||
"stable version",
|
||||
"0.12.0",
|
||||
"terraform",
|
||||
},
|
||||
{
|
||||
"with prerelease",
|
||||
"0.14.0-rc1",
|
||||
"opentofu",
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.name, func(t *testing.T) {
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
commitStatusUpdater := runtimemocks.NewMockStatusUpdater()
|
||||
asyncTfExec := runtimemocks.NewMockAsyncTFExec()
|
||||
When(terraform.RunCommandWithVersion(
|
||||
Any[command.ProjectContext](),
|
||||
Any[string](),
|
||||
Any[[]string](),
|
||||
Any[map[string]string](),
|
||||
Any[tf.Distribution](),
|
||||
Any[*version.Version](),
|
||||
Any[string]())).ThenReturn("output", nil)
|
||||
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
tfVersion, _ := version.NewVersion(c.tfVersion)
|
||||
s := runtime.NewPlanStepRunner(terraform, tfDistribution, tfVersion, commitStatusUpdater, asyncTfExec)
|
||||
ctx := command.ProjectContext{
|
||||
Workspace: "default",
|
||||
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",
|
||||
},
|
||||
TerraformDistribution: &c.tfDistribution,
|
||||
}
|
||||
|
||||
output, err := s.Run(ctx, []string{"extra", "args"}, "/path", map[string]string(nil))
|
||||
Ok(t, err)
|
||||
Equals(t, "output", output)
|
||||
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(ctx), Eq("/path"), Eq(expPlanArgs), Eq(map[string]string(nil)), NotEq(tfDistribution), Eq(tfVersion), Eq("default"))
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
type remotePlanMock struct {
|
||||
// LinesToSend will be sent on the channel.
|
||||
LinesToSend string
|
||||
@@ -543,7 +637,7 @@ type remotePlanMock struct {
|
||||
CalledArgs []string
|
||||
}
|
||||
|
||||
func (r *remotePlanMock) RunCommandAsync(_ command.ProjectContext, _ string, args []string, _ map[string]string, _ *version.Version, _ string) (chan<- string, <-chan runtimemodels.Line) {
|
||||
func (r *remotePlanMock) RunCommandAsync(_ command.ProjectContext, _ string, args []string, _ map[string]string, _ tf.Distribution, _ *version.Version, _ string) (chan<- string, <-chan runtimemodels.Line) {
|
||||
r.CalledArgs = args
|
||||
in := make(chan string)
|
||||
out := make(chan runtimemodels.Line)
|
||||
|
||||
@@ -153,3 +153,148 @@ func TestRunDelegate(t *testing.T) {
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
var openTofuPlanFileContents = `
|
||||
An execution plan has been generated and is shown below.
|
||||
Resource actions are indicated with the following symbols:
|
||||
- destroy
|
||||
|
||||
OpenTofu will perform the following actions:
|
||||
|
||||
- null_resource.hi[1]
|
||||
|
||||
|
||||
Plan: 0 to add, 0 to change, 1 to destroy.`
|
||||
|
||||
func TestRunDelegate_UsesConfiguredDistribution(t *testing.T) {
|
||||
|
||||
RegisterMockTestingT(t)
|
||||
|
||||
mockDefaultRunner := mocks.NewMockRunner()
|
||||
mockRemoteRunner := mocks.NewMockRunner()
|
||||
|
||||
subject := &planTypeStepRunnerDelegate{
|
||||
defaultRunner: mockDefaultRunner,
|
||||
remotePlanRunner: mockRemoteRunner,
|
||||
}
|
||||
|
||||
tfDistribution := "opentofu"
|
||||
tfVersion, _ := version.NewVersion("1.7.0")
|
||||
|
||||
t.Run("Remote Runner Success", func(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
planPath := filepath.Join(tmpDir, "workspace.tfplan")
|
||||
err := os.WriteFile(planPath, []byte("Atlantis: this plan was created by remote ops\n"+openTofuPlanFileContents), 0600)
|
||||
Ok(t, err)
|
||||
|
||||
ctx := command.ProjectContext{
|
||||
Workspace: "workspace",
|
||||
RepoRelDir: ".",
|
||||
EscapedCommentArgs: []string{"comment", "args"},
|
||||
TerraformDistribution: &tfDistribution,
|
||||
TerraformVersion: tfVersion,
|
||||
}
|
||||
extraArgs := []string{"extra", "args"}
|
||||
envs := map[string]string{}
|
||||
|
||||
expectedOut := "some random output"
|
||||
|
||||
When(mockRemoteRunner.Run(ctx, extraArgs, tmpDir, envs)).ThenReturn(expectedOut, nil)
|
||||
|
||||
output, err := subject.Run(ctx, extraArgs, tmpDir, envs)
|
||||
|
||||
mockDefaultRunner.VerifyWasCalled(Never())
|
||||
|
||||
Equals(t, expectedOut, output)
|
||||
Ok(t, err)
|
||||
|
||||
})
|
||||
|
||||
t.Run("Remote Runner Failure", func(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
planPath := filepath.Join(tmpDir, "workspace.tfplan")
|
||||
err := os.WriteFile(planPath, []byte("Atlantis: this plan was created by remote ops\n"+openTofuPlanFileContents), 0600)
|
||||
Ok(t, err)
|
||||
|
||||
ctx := command.ProjectContext{
|
||||
Workspace: "workspace",
|
||||
RepoRelDir: ".",
|
||||
EscapedCommentArgs: []string{"comment", "args"},
|
||||
TerraformDistribution: &tfDistribution,
|
||||
TerraformVersion: tfVersion,
|
||||
}
|
||||
extraArgs := []string{"extra", "args"}
|
||||
envs := map[string]string{}
|
||||
|
||||
expectedOut := "some random output"
|
||||
|
||||
When(mockRemoteRunner.Run(ctx, extraArgs, tmpDir, envs)).ThenReturn(expectedOut, errors.New("err"))
|
||||
|
||||
output, err := subject.Run(ctx, extraArgs, tmpDir, envs)
|
||||
|
||||
mockDefaultRunner.VerifyWasCalled(Never())
|
||||
|
||||
Equals(t, expectedOut, output)
|
||||
Assert(t, err != nil, "err should not be nil")
|
||||
|
||||
})
|
||||
|
||||
t.Run("Local Runner Success", func(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
planPath := filepath.Join(tmpDir, "workspace.tfplan")
|
||||
err := os.WriteFile(planPath, []byte(openTofuPlanFileContents), 0600)
|
||||
Ok(t, err)
|
||||
|
||||
ctx := command.ProjectContext{
|
||||
Workspace: "workspace",
|
||||
RepoRelDir: ".",
|
||||
EscapedCommentArgs: []string{"comment", "args"},
|
||||
TerraformDistribution: &tfDistribution,
|
||||
TerraformVersion: tfVersion,
|
||||
}
|
||||
extraArgs := []string{"extra", "args"}
|
||||
envs := map[string]string{}
|
||||
|
||||
expectedOut := "some random output"
|
||||
|
||||
When(mockDefaultRunner.Run(ctx, extraArgs, tmpDir, envs)).ThenReturn(expectedOut, nil)
|
||||
|
||||
output, err := subject.Run(ctx, extraArgs, tmpDir, envs)
|
||||
|
||||
mockRemoteRunner.VerifyWasCalled(Never())
|
||||
|
||||
Equals(t, expectedOut, output)
|
||||
Ok(t, err)
|
||||
|
||||
})
|
||||
|
||||
t.Run("Local Runner Failure", func(t *testing.T) {
|
||||
tmpDir := t.TempDir()
|
||||
planPath := filepath.Join(tmpDir, "workspace.tfplan")
|
||||
err := os.WriteFile(planPath, []byte(openTofuPlanFileContents), 0600)
|
||||
Ok(t, err)
|
||||
|
||||
ctx := command.ProjectContext{
|
||||
Workspace: "workspace",
|
||||
RepoRelDir: ".",
|
||||
EscapedCommentArgs: []string{"comment", "args"},
|
||||
TerraformDistribution: &tfDistribution,
|
||||
TerraformVersion: tfVersion,
|
||||
}
|
||||
extraArgs := []string{"extra", "args"}
|
||||
envs := map[string]string{}
|
||||
|
||||
expectedOut := "some random output"
|
||||
|
||||
When(mockDefaultRunner.Run(ctx, extraArgs, tmpDir, envs)).ThenReturn(expectedOut, errors.New("err"))
|
||||
|
||||
output, err := subject.Run(ctx, extraArgs, tmpDir, envs)
|
||||
|
||||
mockRemoteRunner.VerifyWasCalled(Never())
|
||||
|
||||
Equals(t, expectedOut, output)
|
||||
Assert(t, err != nil, "err should not be nil")
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package runtime
|
||||
import (
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
)
|
||||
|
||||
@@ -13,7 +14,7 @@ type policyCheckStepRunner struct {
|
||||
}
|
||||
|
||||
// NewPolicyCheckStepRunner creates a new step runner from an executor workflow
|
||||
func NewPolicyCheckStepRunner(defaultTfVersion *version.Version, executorWorkflow VersionedExecutorWorkflow) (Runner, error) {
|
||||
func NewPolicyCheckStepRunner(defaultTfDistribution terraform.Distribution, defaultTfVersion *version.Version, executorWorkflow VersionedExecutorWorkflow) (Runner, error) {
|
||||
policyCheckStepRunner := &policyCheckStepRunner{
|
||||
versionEnsurer: executorWorkflow,
|
||||
executor: executorWorkflow,
|
||||
|
||||
@@ -8,7 +8,8 @@ import (
|
||||
"github.com/hashicorp/go-version"
|
||||
. "github.com/petergtz/pegomock/v4"
|
||||
"github.com/runatlantis/atlantis/server/core/runtime"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform/mocks"
|
||||
tf "github.com/runatlantis/atlantis/server/core/terraform"
|
||||
tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks"
|
||||
"github.com/runatlantis/atlantis/server/events/models"
|
||||
jobmocks "github.com/runatlantis/atlantis/server/jobs/mocks"
|
||||
"github.com/runatlantis/atlantis/server/logging"
|
||||
@@ -142,8 +143,8 @@ func TestPostWorkflowHookRunner_Run(t *testing.T) {
|
||||
Ok(t, err)
|
||||
|
||||
RegisterMockTestingT(t)
|
||||
terraform := mocks.NewMockClient()
|
||||
When(terraform.EnsureVersion(Any[logging.SimpleLogging](), Any[*version.Version]())).
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
When(terraform.EnsureVersion(Any[logging.SimpleLogging](), Any[tf.Distribution](), Any[*version.Version]())).
|
||||
ThenReturn(nil)
|
||||
|
||||
logger := logging.NewNoopLogger(t)
|
||||
|
||||
@@ -9,7 +9,8 @@ import (
|
||||
"github.com/hashicorp/go-version"
|
||||
. "github.com/petergtz/pegomock/v4"
|
||||
"github.com/runatlantis/atlantis/server/core/runtime"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform/mocks"
|
||||
tf "github.com/runatlantis/atlantis/server/core/terraform"
|
||||
tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks"
|
||||
"github.com/runatlantis/atlantis/server/events/models"
|
||||
jobmocks "github.com/runatlantis/atlantis/server/jobs/mocks"
|
||||
"github.com/runatlantis/atlantis/server/logging"
|
||||
@@ -162,8 +163,8 @@ func TestPreWorkflowHookRunner_Run(t *testing.T) {
|
||||
Ok(t, err)
|
||||
|
||||
RegisterMockTestingT(t)
|
||||
terraform := mocks.NewMockClient()
|
||||
When(terraform.EnsureVersion(Any[logging.SimpleLogging](), Any[*version.Version]())).
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
When(terraform.EnsureVersion(Any[logging.SimpleLogging](), Any[tf.Distribution](), Any[*version.Version]())).
|
||||
ThenReturn(nil)
|
||||
|
||||
logger := logging.NewNoopLogger(t)
|
||||
|
||||
@@ -9,14 +9,16 @@ import (
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/runatlantis/atlantis/server/core/config/valid"
|
||||
"github.com/runatlantis/atlantis/server/core/runtime/models"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/jobs"
|
||||
)
|
||||
|
||||
// RunStepRunner runs custom commands.
|
||||
type RunStepRunner struct {
|
||||
TerraformExecutor TerraformExec
|
||||
DefaultTFVersion *version.Version
|
||||
TerraformExecutor TerraformExec
|
||||
DefaultTFDistribution terraform.Distribution
|
||||
DefaultTFVersion *version.Version
|
||||
// TerraformBinDir is the directory where Atlantis downloads Terraform binaries.
|
||||
TerraformBinDir string
|
||||
ProjectCmdOutputHandler jobs.ProjectCommandOutputHandler
|
||||
@@ -31,12 +33,16 @@ func (r *RunStepRunner) Run(
|
||||
streamOutput bool,
|
||||
postProcessOutput valid.PostProcessRunOutputOption,
|
||||
) (string, error) {
|
||||
tfDistribution := r.DefaultTFDistribution
|
||||
tfVersion := r.DefaultTFVersion
|
||||
if ctx.TerraformDistribution != nil {
|
||||
tfDistribution = terraform.NewDistribution(*ctx.TerraformDistribution)
|
||||
}
|
||||
if ctx.TerraformVersion != nil {
|
||||
tfVersion = ctx.TerraformVersion
|
||||
}
|
||||
|
||||
err := r.TerraformExecutor.EnsureVersion(ctx.Log, tfVersion)
|
||||
err := r.TerraformExecutor.EnsureVersion(ctx.Log, tfDistribution, tfVersion)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("%s: Downloading terraform Version %s", err, tfVersion.String())
|
||||
ctx.Log.Debug("error: %s", err)
|
||||
@@ -45,27 +51,28 @@ func (r *RunStepRunner) Run(
|
||||
|
||||
baseEnvVars := os.Environ()
|
||||
customEnvVars := map[string]string{
|
||||
"ATLANTIS_TERRAFORM_VERSION": tfVersion.String(),
|
||||
"BASE_BRANCH_NAME": ctx.Pull.BaseBranch,
|
||||
"BASE_REPO_NAME": ctx.BaseRepo.Name,
|
||||
"BASE_REPO_OWNER": ctx.BaseRepo.Owner,
|
||||
"COMMENT_ARGS": strings.Join(ctx.EscapedCommentArgs, ","),
|
||||
"DIR": path,
|
||||
"HEAD_BRANCH_NAME": ctx.Pull.HeadBranch,
|
||||
"HEAD_COMMIT": ctx.Pull.HeadCommit,
|
||||
"HEAD_REPO_NAME": ctx.HeadRepo.Name,
|
||||
"HEAD_REPO_OWNER": ctx.HeadRepo.Owner,
|
||||
"PATH": fmt.Sprintf("%s:%s", os.Getenv("PATH"), r.TerraformBinDir),
|
||||
"PLANFILE": filepath.Join(path, GetPlanFilename(ctx.Workspace, ctx.ProjectName)),
|
||||
"SHOWFILE": filepath.Join(path, ctx.GetShowResultFileName()),
|
||||
"POLICYCHECKFILE": filepath.Join(path, ctx.GetPolicyCheckResultFileName()),
|
||||
"PROJECT_NAME": ctx.ProjectName,
|
||||
"PULL_AUTHOR": ctx.Pull.Author,
|
||||
"PULL_NUM": fmt.Sprintf("%d", ctx.Pull.Num),
|
||||
"PULL_URL": ctx.Pull.URL,
|
||||
"REPO_REL_DIR": ctx.RepoRelDir,
|
||||
"USER_NAME": ctx.User.Username,
|
||||
"WORKSPACE": ctx.Workspace,
|
||||
"ATLANTIS_TERRAFORM_DISTRIBUTION": tfDistribution.BinName(),
|
||||
"ATLANTIS_TERRAFORM_VERSION": tfVersion.String(),
|
||||
"BASE_BRANCH_NAME": ctx.Pull.BaseBranch,
|
||||
"BASE_REPO_NAME": ctx.BaseRepo.Name,
|
||||
"BASE_REPO_OWNER": ctx.BaseRepo.Owner,
|
||||
"COMMENT_ARGS": strings.Join(ctx.EscapedCommentArgs, ","),
|
||||
"DIR": path,
|
||||
"HEAD_BRANCH_NAME": ctx.Pull.HeadBranch,
|
||||
"HEAD_COMMIT": ctx.Pull.HeadCommit,
|
||||
"HEAD_REPO_NAME": ctx.HeadRepo.Name,
|
||||
"HEAD_REPO_OWNER": ctx.HeadRepo.Owner,
|
||||
"PATH": fmt.Sprintf("%s:%s", os.Getenv("PATH"), r.TerraformBinDir),
|
||||
"PLANFILE": filepath.Join(path, GetPlanFilename(ctx.Workspace, ctx.ProjectName)),
|
||||
"SHOWFILE": filepath.Join(path, ctx.GetShowResultFileName()),
|
||||
"POLICYCHECKFILE": filepath.Join(path, ctx.GetPolicyCheckResultFileName()),
|
||||
"PROJECT_NAME": ctx.ProjectName,
|
||||
"PULL_AUTHOR": ctx.Pull.Author,
|
||||
"PULL_NUM": fmt.Sprintf("%d", ctx.Pull.Num),
|
||||
"PULL_URL": ctx.Pull.URL,
|
||||
"REPO_REL_DIR": ctx.RepoRelDir,
|
||||
"USER_NAME": ctx.User.Username,
|
||||
"WORKSPACE": ctx.Workspace,
|
||||
}
|
||||
|
||||
finalEnvVars := baseEnvVars
|
||||
|
||||
@@ -10,7 +10,9 @@ import (
|
||||
. "github.com/petergtz/pegomock/v4"
|
||||
"github.com/runatlantis/atlantis/server/core/config/valid"
|
||||
"github.com/runatlantis/atlantis/server/core/runtime"
|
||||
tf "github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform/mocks"
|
||||
tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/events/models"
|
||||
jobmocks "github.com/runatlantis/atlantis/server/jobs/mocks"
|
||||
@@ -20,11 +22,12 @@ import (
|
||||
|
||||
func TestRunStepRunner_Run(t *testing.T) {
|
||||
cases := []struct {
|
||||
Command string
|
||||
ProjectName string
|
||||
ExpOut string
|
||||
ExpErr string
|
||||
Version string
|
||||
Command string
|
||||
ProjectName string
|
||||
ExpOut string
|
||||
ExpErr string
|
||||
Version string
|
||||
Distribution string
|
||||
}{
|
||||
{
|
||||
Command: "",
|
||||
@@ -69,6 +72,18 @@ func TestRunStepRunner_Run(t *testing.T) {
|
||||
ProjectName: "my/project/name",
|
||||
ExpOut: "workspace=myworkspace version=0.11.0 dir=$DIR planfile=$DIR/my::project::name-myworkspace.tfplan showfile=$DIR/my::project::name-myworkspace.json project=my/project/name\n",
|
||||
},
|
||||
{
|
||||
Command: "echo distribution=$ATLANTIS_TERRAFORM_DISTRIBUTION",
|
||||
ProjectName: "my/project/name",
|
||||
ExpOut: "distribution=terraform\n",
|
||||
Distribution: "terraform",
|
||||
},
|
||||
{
|
||||
Command: "echo distribution=$ATLANTIS_TERRAFORM_DISTRIBUTION",
|
||||
ProjectName: "my/project/name",
|
||||
ExpOut: "distribution=tofu\n",
|
||||
Distribution: "opentofu",
|
||||
},
|
||||
{
|
||||
Command: "echo base_repo_name=$BASE_REPO_NAME base_repo_owner=$BASE_REPO_OWNER head_repo_name=$HEAD_REPO_NAME head_repo_owner=$HEAD_REPO_OWNER head_branch_name=$HEAD_BRANCH_NAME head_commit=$HEAD_COMMIT base_branch_name=$BASE_BRANCH_NAME pull_num=$PULL_NUM pull_url=$PULL_URL pull_author=$PULL_AUTHOR repo_rel_dir=$REPO_REL_DIR",
|
||||
ExpOut: "base_repo_name=basename base_repo_owner=baseowner head_repo_name=headname head_repo_owner=headowner head_branch_name=add-feat head_commit=12345abcdef base_branch_name=main pull_num=2 pull_url=https://github.com/runatlantis/atlantis/pull/2 pull_author=acme repo_rel_dir=mydir\n",
|
||||
@@ -100,11 +115,17 @@ func TestRunStepRunner_Run(t *testing.T) {
|
||||
|
||||
Ok(t, err)
|
||||
|
||||
projTFDistribution := "terraform"
|
||||
if c.Distribution != "" {
|
||||
projTFDistribution = c.Distribution
|
||||
}
|
||||
|
||||
defaultVersion, _ := version.NewVersion("0.8")
|
||||
|
||||
RegisterMockTestingT(t)
|
||||
terraform := mocks.NewMockClient()
|
||||
When(terraform.EnsureVersion(Any[logging.SimpleLogging](), Any[*version.Version]())).
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
defaultDistribution := tf.NewDistributionTerraformWithDownloader(mocks.NewMockDownloader())
|
||||
When(terraform.EnsureVersion(Any[logging.SimpleLogging](), Any[tf.Distribution](), Any[*version.Version]())).
|
||||
ThenReturn(nil)
|
||||
|
||||
logger := logging.NewNoopLogger(t)
|
||||
@@ -113,6 +134,7 @@ func TestRunStepRunner_Run(t *testing.T) {
|
||||
|
||||
r := runtime.RunStepRunner{
|
||||
TerraformExecutor: terraform,
|
||||
DefaultTFDistribution: defaultDistribution,
|
||||
DefaultTFVersion: defaultVersion,
|
||||
TerraformBinDir: "/bin/dir",
|
||||
ProjectCmdOutputHandler: projectCmdOutputHandler,
|
||||
@@ -138,12 +160,13 @@ func TestRunStepRunner_Run(t *testing.T) {
|
||||
User: models.User{
|
||||
Username: "acme-user",
|
||||
},
|
||||
Log: logger,
|
||||
Workspace: "myworkspace",
|
||||
RepoRelDir: "mydir",
|
||||
TerraformVersion: projVersion,
|
||||
ProjectName: c.ProjectName,
|
||||
EscapedCommentArgs: []string{"-target=resource1", "-target=resource2"},
|
||||
Log: logger,
|
||||
Workspace: "myworkspace",
|
||||
RepoRelDir: "mydir",
|
||||
TerraformDistribution: &projTFDistribution,
|
||||
TerraformVersion: projVersion,
|
||||
ProjectName: c.ProjectName,
|
||||
EscapedCommentArgs: []string{"-target=resource1", "-target=resource2"},
|
||||
}
|
||||
out, err := r.Run(ctx, nil, c.Command, tmpDir, map[string]string{"test": "var"}, true, valid.PostProcessRunOutputShow)
|
||||
if c.ExpErr != "" {
|
||||
@@ -157,8 +180,8 @@ func TestRunStepRunner_Run(t *testing.T) {
|
||||
expOut := strings.Replace(c.ExpOut, "$DIR", tmpDir, -1)
|
||||
Equals(t, expOut, out)
|
||||
|
||||
terraform.VerifyWasCalledOnce().EnsureVersion(logger, projVersion)
|
||||
terraform.VerifyWasCalled(Never()).EnsureVersion(logger, defaultVersion)
|
||||
terraform.VerifyWasCalledOnce().EnsureVersion(Eq(logger), NotEq(defaultDistribution), Eq(projVersion))
|
||||
terraform.VerifyWasCalled(Never()).EnsureVersion(Eq(logger), Eq(defaultDistribution), Eq(defaultVersion))
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
version "github.com/hashicorp/go-version"
|
||||
"github.com/pkg/errors"
|
||||
runtimemodels "github.com/runatlantis/atlantis/server/core/runtime/models"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/events/models"
|
||||
"github.com/runatlantis/atlantis/server/logging"
|
||||
@@ -26,8 +27,8 @@ const (
|
||||
// TerraformExec brings the interface from TerraformClient into this package
|
||||
// without causing circular imports.
|
||||
type TerraformExec interface {
|
||||
RunCommandWithVersion(ctx command.ProjectContext, path string, args []string, envs map[string]string, v *version.Version, workspace string) (string, error)
|
||||
EnsureVersion(log logging.SimpleLogging, v *version.Version) error
|
||||
RunCommandWithVersion(ctx command.ProjectContext, path string, args []string, envs map[string]string, d terraform.Distribution, v *version.Version, workspace string) (string, error)
|
||||
EnsureVersion(log logging.SimpleLogging, d terraform.Distribution, v *version.Version) error
|
||||
}
|
||||
|
||||
// AsyncTFExec brings the interface from TerraformClient into this package
|
||||
@@ -43,7 +44,7 @@ type AsyncTFExec interface {
|
||||
// Callers can use the input channel to pass stdin input to the command.
|
||||
// If any error is passed on the out channel, there will be no
|
||||
// further output (so callers are free to exit).
|
||||
RunCommandAsync(ctx command.ProjectContext, path string, args []string, envs map[string]string, v *version.Version, workspace string) (chan<- string, <-chan runtimemodels.Line)
|
||||
RunCommandAsync(ctx command.ProjectContext, path string, args []string, envs map[string]string, d terraform.Distribution, v *version.Version, workspace string) (chan<- string, <-chan runtimemodels.Line)
|
||||
}
|
||||
|
||||
// StatusUpdater brings the interface from CommitStatusUpdater into this package
|
||||
|
||||
@@ -6,15 +6,17 @@ import (
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
)
|
||||
|
||||
const minimumShowTfVersion string = "0.12.0"
|
||||
|
||||
func NewShowStepRunner(executor TerraformExec, defaultTFVersion *version.Version) (Runner, error) {
|
||||
func NewShowStepRunner(executor TerraformExec, defaultTfDistribution terraform.Distribution, defaultTFVersion *version.Version) (Runner, error) {
|
||||
showStepRunner := &showStepRunner{
|
||||
terraformExecutor: executor,
|
||||
defaultTFVersion: defaultTFVersion,
|
||||
terraformExecutor: executor,
|
||||
defaultTfDistribution: defaultTfDistribution,
|
||||
defaultTFVersion: defaultTFVersion,
|
||||
}
|
||||
remotePlanRunner := NullRunner{}
|
||||
runner := NewPlanTypeStepRunnerDelegate(showStepRunner, remotePlanRunner)
|
||||
@@ -23,12 +25,17 @@ func NewShowStepRunner(executor TerraformExec, defaultTFVersion *version.Version
|
||||
|
||||
// showStepRunner runs terraform show on an existing plan file and outputs it to a json file
|
||||
type showStepRunner struct {
|
||||
terraformExecutor TerraformExec
|
||||
defaultTFVersion *version.Version
|
||||
terraformExecutor TerraformExec
|
||||
defaultTfDistribution terraform.Distribution
|
||||
defaultTFVersion *version.Version
|
||||
}
|
||||
|
||||
func (p *showStepRunner) Run(ctx command.ProjectContext, _ []string, path string, envs map[string]string) (string, error) {
|
||||
tfDistribution := p.defaultTfDistribution
|
||||
tfVersion := p.defaultTFVersion
|
||||
if ctx.TerraformDistribution != nil {
|
||||
tfDistribution = terraform.NewDistribution(*ctx.TerraformDistribution)
|
||||
}
|
||||
if ctx.TerraformVersion != nil {
|
||||
tfVersion = ctx.TerraformVersion
|
||||
}
|
||||
@@ -41,6 +48,7 @@ func (p *showStepRunner) Run(ctx command.ProjectContext, _ []string, path string
|
||||
path,
|
||||
[]string{"show", "-json", filepath.Clean(planFile)},
|
||||
envs,
|
||||
tfDistribution,
|
||||
tfVersion,
|
||||
ctx.Workspace,
|
||||
)
|
||||
|
||||
@@ -9,7 +9,9 @@ import (
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
. "github.com/petergtz/pegomock/v4"
|
||||
tf "github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform/mocks"
|
||||
tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/logging"
|
||||
. "github.com/runatlantis/atlantis/testing"
|
||||
@@ -20,6 +22,8 @@ func TestShowStepRunnner(t *testing.T) {
|
||||
path := t.TempDir()
|
||||
resultPath := filepath.Join(path, "test-default.json")
|
||||
envs := map[string]string{"key": "val"}
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
tfVersion, _ := version.NewVersion("0.12")
|
||||
context := command.ProjectContext{
|
||||
Workspace: "default",
|
||||
@@ -29,17 +33,18 @@ func TestShowStepRunnner(t *testing.T) {
|
||||
|
||||
RegisterMockTestingT(t)
|
||||
|
||||
mockExecutor := mocks.NewMockClient()
|
||||
mockExecutor := tfclientmocks.NewMockClient()
|
||||
|
||||
subject := showStepRunner{
|
||||
terraformExecutor: mockExecutor,
|
||||
defaultTFVersion: tfVersion,
|
||||
terraformExecutor: mockExecutor,
|
||||
defaultTfDistribution: tfDistribution,
|
||||
defaultTFVersion: tfVersion,
|
||||
}
|
||||
|
||||
t.Run("success", func(t *testing.T) {
|
||||
|
||||
When(mockExecutor.RunCommandWithVersion(
|
||||
context, path, []string{"show", "-json", filepath.Join(path, "test-default.tfplan")}, envs, tfVersion, context.Workspace,
|
||||
context, path, []string{"show", "-json", filepath.Join(path, "test-default.tfplan")}, envs, tfDistribution, tfVersion, context.Workspace,
|
||||
)).ThenReturn("success", nil)
|
||||
|
||||
r, err := subject.Run(context, []string{}, path, envs)
|
||||
@@ -57,6 +62,8 @@ func TestShowStepRunnner(t *testing.T) {
|
||||
t.Run("success w/ version override", func(t *testing.T) {
|
||||
|
||||
v, _ := version.NewVersion("0.13.0")
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
d := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
|
||||
contextWithVersionOverride := command.ProjectContext{
|
||||
Workspace: "default",
|
||||
@@ -66,7 +73,7 @@ func TestShowStepRunnner(t *testing.T) {
|
||||
}
|
||||
|
||||
When(mockExecutor.RunCommandWithVersion(
|
||||
contextWithVersionOverride, path, []string{"show", "-json", filepath.Join(path, "test-default.tfplan")}, envs, v, context.Workspace,
|
||||
contextWithVersionOverride, path, []string{"show", "-json", filepath.Join(path, "test-default.tfplan")}, envs, d, v, context.Workspace,
|
||||
)).ThenReturn("success", nil)
|
||||
|
||||
r, err := subject.Run(contextWithVersionOverride, []string{}, path, envs)
|
||||
@@ -81,9 +88,39 @@ func TestShowStepRunnner(t *testing.T) {
|
||||
|
||||
})
|
||||
|
||||
t.Run("success w/ distribution override", func(t *testing.T) {
|
||||
|
||||
v, _ := version.NewVersion("0.13.0")
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
d := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
projTFDistribution := "opentofu"
|
||||
|
||||
contextWithDistributionOverride := command.ProjectContext{
|
||||
Workspace: "default",
|
||||
ProjectName: "test",
|
||||
Log: logger,
|
||||
TerraformDistribution: &projTFDistribution,
|
||||
}
|
||||
|
||||
When(mockExecutor.RunCommandWithVersion(
|
||||
Eq(contextWithDistributionOverride), Eq(path), Eq([]string{"show", "-json", filepath.Join(path, "test-default.tfplan")}), Eq(envs), NotEq(d), NotEq(v), Eq(context.Workspace),
|
||||
)).ThenReturn("success", nil)
|
||||
|
||||
r, err := subject.Run(contextWithDistributionOverride, []string{}, path, envs)
|
||||
|
||||
Ok(t, err)
|
||||
|
||||
actual, _ := os.ReadFile(resultPath)
|
||||
|
||||
actualStr := string(actual)
|
||||
Assert(t, actualStr == "success", "got expected result")
|
||||
Assert(t, r == "success", "returned expected result")
|
||||
|
||||
})
|
||||
|
||||
t.Run("failure running command", func(t *testing.T) {
|
||||
When(mockExecutor.RunCommandWithVersion(
|
||||
context, path, []string{"show", "-json", filepath.Join(path, "test-default.tfplan")}, envs, tfVersion, context.Workspace,
|
||||
context, path, []string{"show", "-json", filepath.Join(path, "test-default.tfplan")}, envs, tfDistribution, tfVersion, context.Workspace,
|
||||
)).ThenReturn("success", errors.New("error"))
|
||||
|
||||
_, err := subject.Run(context, []string{}, path, envs)
|
||||
|
||||
@@ -5,25 +5,32 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
version "github.com/hashicorp/go-version"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/utils"
|
||||
)
|
||||
|
||||
type stateRmStepRunner struct {
|
||||
terraformExecutor TerraformExec
|
||||
defaultTFVersion *version.Version
|
||||
terraformExecutor TerraformExec
|
||||
defaultTFDistribution terraform.Distribution
|
||||
defaultTFVersion *version.Version
|
||||
}
|
||||
|
||||
func NewStateRmStepRunner(terraformExecutor TerraformExec, defaultTfVersion *version.Version) Runner {
|
||||
func NewStateRmStepRunner(terraformExecutor TerraformExec, defaultTfDistribution terraform.Distribution, defaultTfVersion *version.Version) Runner {
|
||||
runner := &stateRmStepRunner{
|
||||
terraformExecutor: terraformExecutor,
|
||||
defaultTFVersion: defaultTfVersion,
|
||||
terraformExecutor: terraformExecutor,
|
||||
defaultTFDistribution: defaultTfDistribution,
|
||||
defaultTFVersion: defaultTfVersion,
|
||||
}
|
||||
return NewWorkspaceStepRunnerDelegate(terraformExecutor, defaultTfVersion, runner)
|
||||
return NewWorkspaceStepRunnerDelegate(terraformExecutor, defaultTfDistribution, defaultTfVersion, runner)
|
||||
}
|
||||
|
||||
func (p *stateRmStepRunner) Run(ctx command.ProjectContext, extraArgs []string, path string, envs map[string]string) (string, error) {
|
||||
tfDistribution := p.defaultTFDistribution
|
||||
tfVersion := p.defaultTFVersion
|
||||
if ctx.TerraformDistribution != nil {
|
||||
tfDistribution = terraform.NewDistribution(*ctx.TerraformDistribution)
|
||||
}
|
||||
if ctx.TerraformVersion != nil {
|
||||
tfVersion = ctx.TerraformVersion
|
||||
}
|
||||
@@ -31,7 +38,7 @@ func (p *stateRmStepRunner) Run(ctx command.ProjectContext, extraArgs []string,
|
||||
stateRmCmd := []string{"state", "rm"}
|
||||
stateRmCmd = append(stateRmCmd, extraArgs...)
|
||||
stateRmCmd = append(stateRmCmd, ctx.EscapedCommentArgs...)
|
||||
out, err := p.terraformExecutor.RunCommandWithVersion(ctx, filepath.Clean(path), stateRmCmd, envs, tfVersion, ctx.Workspace)
|
||||
out, err := p.terraformExecutor.RunCommandWithVersion(ctx, filepath.Clean(path), stateRmCmd, envs, tfDistribution, tfVersion, ctx.Workspace)
|
||||
|
||||
// If the state rm was successful and a plan file exists, delete the plan.
|
||||
planPath := filepath.Join(path, GetPlanFilename(ctx.Workspace, ctx.ProjectName))
|
||||
|
||||
@@ -8,7 +8,9 @@ import (
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
. "github.com/petergtz/pegomock/v4"
|
||||
tf "github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform/mocks"
|
||||
tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/logging"
|
||||
. "github.com/runatlantis/atlantis/testing"
|
||||
@@ -29,17 +31,19 @@ func TestStateRmStepRunner_Run_Success(t *testing.T) {
|
||||
}
|
||||
|
||||
RegisterMockTestingT(t)
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
tfVersion, _ := version.NewVersion("0.15.0")
|
||||
s := NewStateRmStepRunner(terraform, tfVersion)
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
s := NewStateRmStepRunner(terraform, tfDistribution, tfVersion)
|
||||
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[*version.Version](), Any[string]())).
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())).
|
||||
ThenReturn("output", nil)
|
||||
output, err := s.Run(context, []string{}, tmpDir, map[string]string(nil))
|
||||
Ok(t, err)
|
||||
Equals(t, "output", output)
|
||||
commands := []string{"state", "rm", "-lock=false", "addr1", "addr2", "addr3"}
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, commands, map[string]string(nil), tfVersion, "default")
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, commands, map[string]string(nil), tfDistribution, tfVersion, "default")
|
||||
_, err = os.Stat(planPath)
|
||||
Assert(t, os.IsNotExist(err), "planfile should be deleted")
|
||||
}
|
||||
@@ -59,23 +63,67 @@ func TestStateRmStepRunner_Run_Workspace(t *testing.T) {
|
||||
}
|
||||
|
||||
RegisterMockTestingT(t)
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
tfVersion, _ := version.NewVersion("0.15.0")
|
||||
s := NewStateRmStepRunner(terraform, tfVersion)
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
s := NewStateRmStepRunner(terraform, tfDistribution, tfVersion)
|
||||
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[*version.Version](), Any[string]())).
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())).
|
||||
ThenReturn("output", nil)
|
||||
output, err := s.Run(context, []string{}, tmpDir, map[string]string(nil))
|
||||
Ok(t, err)
|
||||
Equals(t, "output", output)
|
||||
|
||||
// switch workspace
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, []string{"workspace", "show"}, map[string]string(nil), tfVersion, workspace)
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, []string{"workspace", "select", workspace}, map[string]string(nil), tfVersion, workspace)
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, []string{"workspace", "show"}, map[string]string(nil), tfDistribution, tfVersion, workspace)
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, []string{"workspace", "select", workspace}, map[string]string(nil), tfDistribution, tfVersion, workspace)
|
||||
|
||||
// exec state rm
|
||||
commands := []string{"state", "rm", "-lock=false", "addr1", "addr2", "addr3"}
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, commands, map[string]string(nil), tfVersion, workspace)
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, commands, map[string]string(nil), tfDistribution, tfVersion, workspace)
|
||||
|
||||
_, err = os.Stat(planPath)
|
||||
Assert(t, os.IsNotExist(err), "planfile should be deleted")
|
||||
}
|
||||
|
||||
func TestStateRmStepRunner_Run_UsesConfiguredDistribution(t *testing.T) {
|
||||
logger := logging.NewNoopLogger(t)
|
||||
workspace := "something"
|
||||
tmpDir := t.TempDir()
|
||||
planPath := filepath.Join(tmpDir, fmt.Sprintf("%s.tfplan", workspace))
|
||||
err := os.WriteFile(planPath, nil, 0600)
|
||||
Ok(t, err)
|
||||
|
||||
projTFDistribution := "opentofu"
|
||||
|
||||
context := command.ProjectContext{
|
||||
Log: logger,
|
||||
EscapedCommentArgs: []string{"-lock=false", "addr1", "addr2", "addr3"},
|
||||
Workspace: workspace,
|
||||
TerraformDistribution: &projTFDistribution,
|
||||
}
|
||||
|
||||
RegisterMockTestingT(t)
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
tfVersion, _ := version.NewVersion("0.15.0")
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
s := NewStateRmStepRunner(terraform, tfDistribution, tfVersion)
|
||||
|
||||
When(terraform.RunCommandWithVersion(Any[command.ProjectContext](), Any[string](), Any[[]string](), Any[map[string]string](), Any[tf.Distribution](), Any[*version.Version](), Any[string]())).
|
||||
ThenReturn("output", nil)
|
||||
output, err := s.Run(context, []string{}, tmpDir, map[string]string(nil))
|
||||
Ok(t, err)
|
||||
Equals(t, "output", output)
|
||||
|
||||
// switch workspace
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(context), Eq(tmpDir), Eq([]string{"workspace", "show"}), Eq(map[string]string(nil)), NotEq(tfDistribution), Eq(tfVersion), Eq(workspace))
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(context), Eq(tmpDir), Eq([]string{"workspace", "select", workspace}), Eq(map[string]string(nil)), NotEq(tfDistribution), Eq(tfVersion), Eq(workspace))
|
||||
|
||||
// exec state rm
|
||||
commands := []string{"state", "rm", "-lock=false", "addr1", "addr2", "addr3"}
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(context), Eq(tmpDir), Eq(commands), Eq(map[string]string(nil)), NotEq(tfDistribution), Eq(tfVersion), Eq(workspace))
|
||||
|
||||
_, err = os.Stat(planPath)
|
||||
Assert(t, os.IsNotExist(err), "planfile should be deleted")
|
||||
|
||||
@@ -4,22 +4,28 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
)
|
||||
|
||||
// VersionStepRunner runs a version command given a ctx
|
||||
type VersionStepRunner struct {
|
||||
TerraformExecutor TerraformExec
|
||||
DefaultTFVersion *version.Version
|
||||
TerraformExecutor TerraformExec
|
||||
DefaultTFDistribution terraform.Distribution
|
||||
DefaultTFVersion *version.Version
|
||||
}
|
||||
|
||||
// Run ensures a given version for the executable, builds the args from the project context and then runs executable returning the result
|
||||
func (v *VersionStepRunner) Run(ctx command.ProjectContext, _ []string, path string, envs map[string]string) (string, error) {
|
||||
tfDistribution := v.DefaultTFDistribution
|
||||
tfVersion := v.DefaultTFVersion
|
||||
if ctx.TerraformDistribution != nil {
|
||||
tfDistribution = terraform.NewDistribution(*ctx.TerraformDistribution)
|
||||
}
|
||||
if ctx.TerraformVersion != nil {
|
||||
tfVersion = ctx.TerraformVersion
|
||||
}
|
||||
|
||||
versionCmd := []string{"version"}
|
||||
return v.TerraformExecutor.RunCommandWithVersion(ctx, filepath.Clean(path), versionCmd, envs, tfVersion, ctx.Workspace)
|
||||
return v.TerraformExecutor.RunCommandWithVersion(ctx, filepath.Clean(path), versionCmd, envs, tfDistribution, tfVersion, ctx.Workspace)
|
||||
}
|
||||
|
||||
@@ -5,7 +5,9 @@ import (
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
. "github.com/petergtz/pegomock/v4"
|
||||
tf "github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform/mocks"
|
||||
tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/events/models"
|
||||
"github.com/runatlantis/atlantis/server/logging"
|
||||
@@ -33,18 +35,62 @@ func TestRunVersionStep(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
tfVersion, _ := version.NewVersion("0.15.0")
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
s := &VersionStepRunner{
|
||||
TerraformExecutor: terraform,
|
||||
DefaultTFVersion: tfVersion,
|
||||
TerraformExecutor: terraform,
|
||||
DefaultTFDistribution: tfDistribution,
|
||||
DefaultTFVersion: tfVersion,
|
||||
}
|
||||
|
||||
t.Run("ensure runs", func(t *testing.T) {
|
||||
_, err := s.Run(context, []string{}, tmpDir, map[string]string(nil))
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, []string{"version"}, map[string]string(nil), tfVersion, "default")
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(context, tmpDir, []string{"version"}, map[string]string(nil), tfDistribution, tfVersion, "default")
|
||||
Ok(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func TestVersionStepRunner_Run_UsesConfiguredDistribution(t *testing.T) {
|
||||
RegisterMockTestingT(t)
|
||||
logger := logging.NewNoopLogger(t)
|
||||
workspace := "default"
|
||||
projTFDistribution := "opentofu"
|
||||
context := command.ProjectContext{
|
||||
Log: logger,
|
||||
EscapedCommentArgs: []string{"comment", "args"},
|
||||
Workspace: workspace,
|
||||
RepoRelDir: ".",
|
||||
User: models.User{Username: "username"},
|
||||
Pull: models.PullRequest{
|
||||
Num: 2,
|
||||
},
|
||||
BaseRepo: models.Repo{
|
||||
FullName: "owner/repo",
|
||||
Owner: "owner",
|
||||
Name: "repo",
|
||||
},
|
||||
TerraformDistribution: &projTFDistribution,
|
||||
}
|
||||
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
tfVersion, _ := version.NewVersion("0.15.0")
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
s := &VersionStepRunner{
|
||||
TerraformExecutor: terraform,
|
||||
DefaultTFDistribution: tfDistribution,
|
||||
DefaultTFVersion: tfVersion,
|
||||
}
|
||||
|
||||
t.Run("ensure runs", func(t *testing.T) {
|
||||
_, err := s.Run(context, []string{}, tmpDir, map[string]string(nil))
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(context), Eq(tmpDir), Eq([]string{"version"}), Eq(map[string]string(nil)), NotEq(tfDistribution), Eq(tfVersion), Eq("default"))
|
||||
Ok(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,33 +5,40 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
)
|
||||
|
||||
// workspaceStepRunnerDelegate ensures that a given step runner run on switched workspace
|
||||
type workspaceStepRunnerDelegate struct {
|
||||
terraformExecutor TerraformExec
|
||||
defaultTfVersion *version.Version
|
||||
delegate Runner
|
||||
terraformExecutor TerraformExec
|
||||
defaultTfDistribution terraform.Distribution
|
||||
defaultTfVersion *version.Version
|
||||
delegate Runner
|
||||
}
|
||||
|
||||
func NewWorkspaceStepRunnerDelegate(terraformExecutor TerraformExec, defaultTfVersion *version.Version, delegate Runner) Runner {
|
||||
func NewWorkspaceStepRunnerDelegate(terraformExecutor TerraformExec, defaultTfDistribution terraform.Distribution, defaultTfVersion *version.Version, delegate Runner) Runner {
|
||||
return &workspaceStepRunnerDelegate{
|
||||
terraformExecutor: terraformExecutor,
|
||||
defaultTfVersion: defaultTfVersion,
|
||||
delegate: delegate,
|
||||
terraformExecutor: terraformExecutor,
|
||||
defaultTfDistribution: defaultTfDistribution,
|
||||
defaultTfVersion: defaultTfVersion,
|
||||
delegate: delegate,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *workspaceStepRunnerDelegate) Run(ctx command.ProjectContext, extraArgs []string, path string, envs map[string]string) (string, error) {
|
||||
tfDistribution := r.defaultTfDistribution
|
||||
tfVersion := r.defaultTfVersion
|
||||
if ctx.TerraformDistribution != nil {
|
||||
tfDistribution = terraform.NewDistribution(*ctx.TerraformDistribution)
|
||||
}
|
||||
if ctx.TerraformVersion != nil {
|
||||
tfVersion = ctx.TerraformVersion
|
||||
}
|
||||
|
||||
// We only need to switch workspaces in version 0.9.*. In older versions,
|
||||
// there is no such thing as a workspace so we don't need to do anything.
|
||||
if err := r.switchWorkspace(ctx, path, tfVersion, envs); err != nil {
|
||||
if err := r.switchWorkspace(ctx, path, tfDistribution, tfVersion, envs); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -40,7 +47,7 @@ func (r *workspaceStepRunnerDelegate) Run(ctx command.ProjectContext, extraArgs
|
||||
|
||||
// switchWorkspace changes the terraform workspace if necessary and will create
|
||||
// it if it doesn't exist. It handles differences between versions.
|
||||
func (r *workspaceStepRunnerDelegate) switchWorkspace(ctx command.ProjectContext, path string, tfVersion *version.Version, envs map[string]string) error {
|
||||
func (r *workspaceStepRunnerDelegate) switchWorkspace(ctx command.ProjectContext, path string, tfDistribution terraform.Distribution, tfVersion *version.Version, envs map[string]string) error {
|
||||
// In versions less than 0.9 there is no support for workspaces.
|
||||
noWorkspaceSupport := MustConstraint("<0.9").Check(tfVersion)
|
||||
// If the user tried to set a specific workspace in the comment but their
|
||||
@@ -63,7 +70,7 @@ func (r *workspaceStepRunnerDelegate) switchWorkspace(ctx command.ProjectContext
|
||||
// already in the right workspace then no need to switch. This will save us
|
||||
// about ten seconds. This command is only available in > 0.10.
|
||||
if !runningZeroPointNine {
|
||||
workspaceShowOutput, err := r.terraformExecutor.RunCommandWithVersion(ctx, path, []string{workspaceCmd, "show"}, envs, tfVersion, ctx.Workspace)
|
||||
workspaceShowOutput, err := r.terraformExecutor.RunCommandWithVersion(ctx, path, []string{workspaceCmd, "show"}, envs, tfDistribution, tfVersion, ctx.Workspace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -78,11 +85,11 @@ func (r *workspaceStepRunnerDelegate) switchWorkspace(ctx command.ProjectContext
|
||||
// To do this we can either select and catch the error or use list and then
|
||||
// look for the workspace. Both commands take the same amount of time so
|
||||
// that's why we're running select here.
|
||||
_, err := r.terraformExecutor.RunCommandWithVersion(ctx, path, []string{workspaceCmd, "select", ctx.Workspace}, envs, tfVersion, ctx.Workspace)
|
||||
_, err := r.terraformExecutor.RunCommandWithVersion(ctx, path, []string{workspaceCmd, "select", ctx.Workspace}, envs, tfDistribution, tfVersion, ctx.Workspace)
|
||||
if err != nil {
|
||||
// If terraform workspace select fails we run terraform workspace
|
||||
// new to create a new workspace automatically.
|
||||
out, err := r.terraformExecutor.RunCommandWithVersion(ctx, path, []string{workspaceCmd, "new", ctx.Workspace}, envs, tfVersion, ctx.Workspace)
|
||||
out, err := r.terraformExecutor.RunCommandWithVersion(ctx, path, []string{workspaceCmd, "new", ctx.Workspace}, envs, tfDistribution, tfVersion, ctx.Workspace)
|
||||
if err != nil {
|
||||
return fmt.Errorf("%s: %s", err, out)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,9 @@ import (
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
. "github.com/petergtz/pegomock/v4"
|
||||
tf "github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform/mocks"
|
||||
tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/events/models"
|
||||
"github.com/runatlantis/atlantis/server/logging"
|
||||
@@ -16,7 +18,9 @@ import (
|
||||
func TestRun_NoWorkspaceIn08(t *testing.T) {
|
||||
// We don't want any workspace commands to be run in 0.8.
|
||||
RegisterMockTestingT(t)
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
tfVersion, _ := version.NewVersion("0.8")
|
||||
workspace := "default"
|
||||
logger := logging.NewNoopLogger(t)
|
||||
@@ -24,7 +28,7 @@ func TestRun_NoWorkspaceIn08(t *testing.T) {
|
||||
Log: logger,
|
||||
Workspace: workspace,
|
||||
}
|
||||
s := NewWorkspaceStepRunnerDelegate(terraform, tfVersion, &NullRunner{})
|
||||
s := NewWorkspaceStepRunnerDelegate(terraform, tfDistribution, tfVersion, &NullRunner{})
|
||||
|
||||
_, err := s.Run(ctx, []string{"extra", "args"}, "/path", map[string]string(nil))
|
||||
Ok(t, err)
|
||||
@@ -36,6 +40,7 @@ func TestRun_NoWorkspaceIn08(t *testing.T) {
|
||||
"select",
|
||||
"workspace"},
|
||||
map[string]string(nil),
|
||||
tfDistribution,
|
||||
tfVersion,
|
||||
workspace)
|
||||
terraform.VerifyWasCalled(Never()).RunCommandWithVersion(ctx,
|
||||
@@ -44,6 +49,7 @@ func TestRun_NoWorkspaceIn08(t *testing.T) {
|
||||
"select",
|
||||
"workspace"},
|
||||
map[string]string(nil),
|
||||
tfDistribution,
|
||||
tfVersion,
|
||||
workspace)
|
||||
}
|
||||
@@ -52,11 +58,13 @@ func TestRun_ErrWorkspaceIn08(t *testing.T) {
|
||||
// If they attempt to use a workspace other than default in 0.8
|
||||
// we should error.
|
||||
RegisterMockTestingT(t)
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
tfVersion, _ := version.NewVersion("0.8")
|
||||
logger := logging.NewNoopLogger(t)
|
||||
workspace := "notdefault"
|
||||
s := NewWorkspaceStepRunnerDelegate(terraform, tfVersion, &NullRunner{})
|
||||
s := NewWorkspaceStepRunnerDelegate(terraform, tfDistribution, tfVersion, &NullRunner{})
|
||||
|
||||
_, err := s.Run(command.ProjectContext{
|
||||
Log: logger,
|
||||
@@ -67,6 +75,8 @@ func TestRun_ErrWorkspaceIn08(t *testing.T) {
|
||||
|
||||
func TestRun_SwitchesWorkspace(t *testing.T) {
|
||||
RegisterMockTestingT(t)
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
|
||||
cases := []struct {
|
||||
tfVersion string
|
||||
@@ -92,14 +102,14 @@ func TestRun_SwitchesWorkspace(t *testing.T) {
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.tfVersion, func(t *testing.T) {
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
tfVersion, _ := version.NewVersion(c.tfVersion)
|
||||
logger := logging.NewNoopLogger(t)
|
||||
ctx := command.ProjectContext{
|
||||
Log: logger,
|
||||
Workspace: "workspace",
|
||||
}
|
||||
s := NewWorkspaceStepRunnerDelegate(terraform, tfVersion, &NullRunner{})
|
||||
s := NewWorkspaceStepRunnerDelegate(terraform, tfDistribution, tfVersion, &NullRunner{})
|
||||
|
||||
_, err := s.Run(ctx, []string{"extra", "args"}, "/path", map[string]string(nil))
|
||||
Ok(t, err)
|
||||
@@ -111,12 +121,74 @@ func TestRun_SwitchesWorkspace(t *testing.T) {
|
||||
"select",
|
||||
"workspace"},
|
||||
map[string]string(nil),
|
||||
tfDistribution,
|
||||
tfVersion,
|
||||
"workspace")
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRun_SwitchesWorkspaceDistribution(t *testing.T) {
|
||||
RegisterMockTestingT(t)
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
|
||||
cases := []struct {
|
||||
tfVersion string
|
||||
tfDistribution string
|
||||
expWorkspaceCmd string
|
||||
}{
|
||||
{
|
||||
"0.9.0",
|
||||
"opentofu",
|
||||
"env",
|
||||
},
|
||||
{
|
||||
"0.9.11",
|
||||
"terraform",
|
||||
"env",
|
||||
},
|
||||
{
|
||||
"0.10.0",
|
||||
"terraform",
|
||||
"workspace",
|
||||
},
|
||||
{
|
||||
"0.11.0",
|
||||
"opentofu",
|
||||
"workspace",
|
||||
},
|
||||
}
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.tfVersion, func(t *testing.T) {
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
tfVersion, _ := version.NewVersion(c.tfVersion)
|
||||
logger := logging.NewNoopLogger(t)
|
||||
ctx := command.ProjectContext{
|
||||
Log: logger,
|
||||
Workspace: "workspace",
|
||||
TerraformDistribution: &c.tfDistribution,
|
||||
}
|
||||
s := NewWorkspaceStepRunnerDelegate(terraform, tfDistribution, tfVersion, &NullRunner{})
|
||||
|
||||
_, err := s.Run(ctx, []string{"extra", "args"}, "/path", map[string]string(nil))
|
||||
Ok(t, err)
|
||||
|
||||
// Verify that env select was called as well as plan.
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(Eq(ctx),
|
||||
Eq("/path"),
|
||||
Eq([]string{c.expWorkspaceCmd,
|
||||
"select",
|
||||
"workspace"}),
|
||||
Eq(map[string]string(nil)),
|
||||
NotEq(tfDistribution),
|
||||
Eq(tfVersion),
|
||||
Eq("workspace"))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRun_CreatesWorkspace(t *testing.T) {
|
||||
// Test that if `workspace select` fails, we call `workspace new`.
|
||||
RegisterMockTestingT(t)
|
||||
@@ -145,7 +217,9 @@ func TestRun_CreatesWorkspace(t *testing.T) {
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.tfVersion, func(t *testing.T) {
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
tfVersion, _ := version.NewVersion(c.tfVersion)
|
||||
logger := logging.NewNoopLogger(t)
|
||||
ctx := command.ProjectContext{
|
||||
@@ -163,20 +237,20 @@ func TestRun_CreatesWorkspace(t *testing.T) {
|
||||
Name: "repo",
|
||||
},
|
||||
}
|
||||
s := NewWorkspaceStepRunnerDelegate(terraform, tfVersion, &NullRunner{})
|
||||
s := NewWorkspaceStepRunnerDelegate(terraform, tfDistribution, tfVersion, &NullRunner{})
|
||||
|
||||
// Ensure that we actually try to switch workspaces by making the
|
||||
// output of `workspace show` to be a different name.
|
||||
When(terraform.RunCommandWithVersion(ctx, "/path", []string{"workspace", "show"}, map[string]string(nil), tfVersion, "workspace")).ThenReturn("diffworkspace\n", nil)
|
||||
When(terraform.RunCommandWithVersion(ctx, "/path", []string{"workspace", "show"}, map[string]string(nil), tfDistribution, tfVersion, "workspace")).ThenReturn("diffworkspace\n", nil)
|
||||
|
||||
expWorkspaceArgs := []string{c.expWorkspaceCommand, "select", "workspace"}
|
||||
When(terraform.RunCommandWithVersion(ctx, "/path", expWorkspaceArgs, map[string]string(nil), tfVersion, "workspace")).ThenReturn("", errors.New("workspace does not exist"))
|
||||
When(terraform.RunCommandWithVersion(ctx, "/path", expWorkspaceArgs, map[string]string(nil), tfDistribution, tfVersion, "workspace")).ThenReturn("", errors.New("workspace does not exist"))
|
||||
|
||||
_, err := s.Run(ctx, []string{"extra", "args"}, "/path", map[string]string(nil))
|
||||
Ok(t, err)
|
||||
|
||||
// Verify that env select was called as well as plan.
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, "/path", expWorkspaceArgs, map[string]string(nil), tfVersion, "workspace")
|
||||
terraform.VerifyWasCalledOnce().RunCommandWithVersion(ctx, "/path", expWorkspaceArgs, map[string]string(nil), tfDistribution, tfVersion, "workspace")
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -185,7 +259,9 @@ func TestRun_NoWorkspaceSwitchIfNotNecessary(t *testing.T) {
|
||||
// Tests that if workspace show says we're on the right workspace we don't
|
||||
// switch.
|
||||
RegisterMockTestingT(t)
|
||||
terraform := mocks.NewMockClient()
|
||||
terraform := tfclientmocks.NewMockClient()
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
tfDistribution := tf.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
tfVersion, _ := version.NewVersion("0.10.0")
|
||||
logger := logging.NewNoopLogger(t)
|
||||
ctx := command.ProjectContext{
|
||||
@@ -203,12 +279,12 @@ func TestRun_NoWorkspaceSwitchIfNotNecessary(t *testing.T) {
|
||||
Name: "repo",
|
||||
},
|
||||
}
|
||||
s := NewWorkspaceStepRunnerDelegate(terraform, tfVersion, &NullRunner{})
|
||||
When(terraform.RunCommandWithVersion(ctx, "/path", []string{"workspace", "show"}, map[string]string(nil), tfVersion, "workspace")).ThenReturn("workspace\n", nil)
|
||||
s := NewWorkspaceStepRunnerDelegate(terraform, tfDistribution, tfVersion, &NullRunner{})
|
||||
When(terraform.RunCommandWithVersion(ctx, "/path", []string{"workspace", "show"}, map[string]string(nil), tfDistribution, tfVersion, "workspace")).ThenReturn("workspace\n", nil)
|
||||
|
||||
_, err := s.Run(ctx, []string{"extra", "args"}, "/path", map[string]string(nil))
|
||||
Ok(t, err)
|
||||
|
||||
// Verify that workspace select was never called.
|
||||
terraform.VerifyWasCalled(Never()).RunCommandWithVersion(ctx, "/path", []string{"workspace", "select", "workspace"}, map[string]string(nil), tfVersion, "workspace")
|
||||
terraform.VerifyWasCalled(Never()).RunCommandWithVersion(ctx, "/path", []string{"workspace", "select", "workspace"}, map[string]string(nil), tfDistribution, tfVersion, "workspace")
|
||||
}
|
||||
|
||||
@@ -18,6 +18,14 @@ type Distribution interface {
|
||||
ResolveConstraint(context.Context, string) (*version.Version, error)
|
||||
}
|
||||
|
||||
func NewDistribution(distribution string) Distribution {
|
||||
tfDistribution := NewDistributionTerraform()
|
||||
if distribution == "opentofu" {
|
||||
tfDistribution = NewDistributionOpenTofu()
|
||||
}
|
||||
return tfDistribution
|
||||
}
|
||||
|
||||
type DistributionOpenTofu struct {
|
||||
downloader Downloader
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
// Code generated by pegomock. DO NOT EDIT.
|
||||
// Source: github.com/runatlantis/atlantis/server/core/terraform (interfaces: Client)
|
||||
// Source: github.com/runatlantis/atlantis/server/core/terraform/tfclient (interfaces: Client)
|
||||
|
||||
package mocks
|
||||
|
||||
import (
|
||||
go_version "github.com/hashicorp/go-version"
|
||||
pegomock "github.com/petergtz/pegomock/v4"
|
||||
terraform "github.com/runatlantis/atlantis/server/core/terraform"
|
||||
command "github.com/runatlantis/atlantis/server/events/command"
|
||||
logging "github.com/runatlantis/atlantis/server/logging"
|
||||
"reflect"
|
||||
@@ -42,11 +43,11 @@ func (mock *MockClient) DetectVersion(log logging.SimpleLogging, projectDirector
|
||||
return _ret0
|
||||
}
|
||||
|
||||
func (mock *MockClient) EnsureVersion(log logging.SimpleLogging, v *go_version.Version) error {
|
||||
func (mock *MockClient) EnsureVersion(log logging.SimpleLogging, d terraform.Distribution, v *go_version.Version) error {
|
||||
if mock == nil {
|
||||
panic("mock must not be nil. Use myMock := NewMockClient().")
|
||||
}
|
||||
_params := []pegomock.Param{log, v}
|
||||
_params := []pegomock.Param{log, d, v}
|
||||
_result := pegomock.GetGenericMockFrom(mock).Invoke("EnsureVersion", _params, []reflect.Type{reflect.TypeOf((*error)(nil)).Elem()})
|
||||
var _ret0 error
|
||||
if len(_result) != 0 {
|
||||
@@ -57,11 +58,11 @@ func (mock *MockClient) EnsureVersion(log logging.SimpleLogging, v *go_version.V
|
||||
return _ret0
|
||||
}
|
||||
|
||||
func (mock *MockClient) RunCommandWithVersion(ctx command.ProjectContext, path string, args []string, envs map[string]string, v *go_version.Version, workspace string) (string, error) {
|
||||
func (mock *MockClient) RunCommandWithVersion(ctx command.ProjectContext, path string, args []string, envs map[string]string, d terraform.Distribution, v *go_version.Version, workspace string) (string, error) {
|
||||
if mock == nil {
|
||||
panic("mock must not be nil. Use myMock := NewMockClient().")
|
||||
}
|
||||
_params := []pegomock.Param{ctx, path, args, envs, v, workspace}
|
||||
_params := []pegomock.Param{ctx, path, args, envs, d, v, workspace}
|
||||
_result := pegomock.GetGenericMockFrom(mock).Invoke("RunCommandWithVersion", _params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
|
||||
var _ret0 string
|
||||
var _ret1 error
|
||||
@@ -148,8 +149,8 @@ func (c *MockClient_DetectVersion_OngoingVerification) GetAllCapturedArguments()
|
||||
return
|
||||
}
|
||||
|
||||
func (verifier *VerifierMockClient) EnsureVersion(log logging.SimpleLogging, v *go_version.Version) *MockClient_EnsureVersion_OngoingVerification {
|
||||
_params := []pegomock.Param{log, v}
|
||||
func (verifier *VerifierMockClient) EnsureVersion(log logging.SimpleLogging, d terraform.Distribution, v *go_version.Version) *MockClient_EnsureVersion_OngoingVerification {
|
||||
_params := []pegomock.Param{log, d, v}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "EnsureVersion", _params, verifier.timeout)
|
||||
return &MockClient_EnsureVersion_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
@@ -159,12 +160,12 @@ type MockClient_EnsureVersion_OngoingVerification struct {
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *MockClient_EnsureVersion_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, *go_version.Version) {
|
||||
log, v := c.GetAllCapturedArguments()
|
||||
return log[len(log)-1], v[len(v)-1]
|
||||
func (c *MockClient_EnsureVersion_OngoingVerification) GetCapturedArguments() (logging.SimpleLogging, terraform.Distribution, *go_version.Version) {
|
||||
log, d, v := c.GetAllCapturedArguments()
|
||||
return log[len(log)-1], d[len(d)-1], v[len(v)-1]
|
||||
}
|
||||
|
||||
func (c *MockClient_EnsureVersion_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []*go_version.Version) {
|
||||
func (c *MockClient_EnsureVersion_OngoingVerification) GetAllCapturedArguments() (_param0 []logging.SimpleLogging, _param1 []terraform.Distribution, _param2 []*go_version.Version) {
|
||||
_params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(_params) > 0 {
|
||||
if len(_params) > 0 {
|
||||
@@ -174,17 +175,23 @@ func (c *MockClient_EnsureVersion_OngoingVerification) GetAllCapturedArguments()
|
||||
}
|
||||
}
|
||||
if len(_params) > 1 {
|
||||
_param1 = make([]*go_version.Version, len(c.methodInvocations))
|
||||
_param1 = make([]terraform.Distribution, len(c.methodInvocations))
|
||||
for u, param := range _params[1] {
|
||||
_param1[u] = param.(*go_version.Version)
|
||||
_param1[u] = param.(terraform.Distribution)
|
||||
}
|
||||
}
|
||||
if len(_params) > 2 {
|
||||
_param2 = make([]*go_version.Version, len(c.methodInvocations))
|
||||
for u, param := range _params[2] {
|
||||
_param2[u] = param.(*go_version.Version)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (verifier *VerifierMockClient) RunCommandWithVersion(ctx command.ProjectContext, path string, args []string, envs map[string]string, v *go_version.Version, workspace string) *MockClient_RunCommandWithVersion_OngoingVerification {
|
||||
_params := []pegomock.Param{ctx, path, args, envs, v, workspace}
|
||||
func (verifier *VerifierMockClient) RunCommandWithVersion(ctx command.ProjectContext, path string, args []string, envs map[string]string, d terraform.Distribution, v *go_version.Version, workspace string) *MockClient_RunCommandWithVersion_OngoingVerification {
|
||||
_params := []pegomock.Param{ctx, path, args, envs, d, v, workspace}
|
||||
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "RunCommandWithVersion", _params, verifier.timeout)
|
||||
return &MockClient_RunCommandWithVersion_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
|
||||
}
|
||||
@@ -194,12 +201,12 @@ type MockClient_RunCommandWithVersion_OngoingVerification struct {
|
||||
methodInvocations []pegomock.MethodInvocation
|
||||
}
|
||||
|
||||
func (c *MockClient_RunCommandWithVersion_OngoingVerification) GetCapturedArguments() (command.ProjectContext, string, []string, map[string]string, *go_version.Version, string) {
|
||||
ctx, path, args, envs, v, workspace := c.GetAllCapturedArguments()
|
||||
return ctx[len(ctx)-1], path[len(path)-1], args[len(args)-1], envs[len(envs)-1], v[len(v)-1], workspace[len(workspace)-1]
|
||||
func (c *MockClient_RunCommandWithVersion_OngoingVerification) GetCapturedArguments() (command.ProjectContext, string, []string, map[string]string, terraform.Distribution, *go_version.Version, string) {
|
||||
ctx, path, args, envs, d, v, workspace := c.GetAllCapturedArguments()
|
||||
return ctx[len(ctx)-1], path[len(path)-1], args[len(args)-1], envs[len(envs)-1], d[len(d)-1], v[len(v)-1], workspace[len(workspace)-1]
|
||||
}
|
||||
|
||||
func (c *MockClient_RunCommandWithVersion_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext, _param1 []string, _param2 [][]string, _param3 []map[string]string, _param4 []*go_version.Version, _param5 []string) {
|
||||
func (c *MockClient_RunCommandWithVersion_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext, _param1 []string, _param2 [][]string, _param3 []map[string]string, _param4 []terraform.Distribution, _param5 []*go_version.Version, _param6 []string) {
|
||||
_params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
|
||||
if len(_params) > 0 {
|
||||
if len(_params) > 0 {
|
||||
@@ -227,15 +234,21 @@ func (c *MockClient_RunCommandWithVersion_OngoingVerification) GetAllCapturedArg
|
||||
}
|
||||
}
|
||||
if len(_params) > 4 {
|
||||
_param4 = make([]*go_version.Version, len(c.methodInvocations))
|
||||
_param4 = make([]terraform.Distribution, len(c.methodInvocations))
|
||||
for u, param := range _params[4] {
|
||||
_param4[u] = param.(*go_version.Version)
|
||||
_param4[u] = param.(terraform.Distribution)
|
||||
}
|
||||
}
|
||||
if len(_params) > 5 {
|
||||
_param5 = make([]string, len(c.methodInvocations))
|
||||
_param5 = make([]*go_version.Version, len(c.methodInvocations))
|
||||
for u, param := range _params[5] {
|
||||
_param5[u] = param.(string)
|
||||
_param5[u] = param.(*go_version.Version)
|
||||
}
|
||||
}
|
||||
if len(_params) > 6 {
|
||||
_param6 = make([]string, len(c.methodInvocations))
|
||||
for u, param := range _params[6] {
|
||||
_param6[u] = param.(string)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,8 +13,8 @@
|
||||
// limitations under the License.
|
||||
// Modified hereafter by contributors to runatlantis/atlantis.
|
||||
//
|
||||
// Package terraform handles the actual running of terraform commands.
|
||||
package terraform
|
||||
// Package tfclient handles the actual running of terraform commands.
|
||||
package tfclient
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -33,8 +33,9 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/runatlantis/atlantis/server/core/runtime/models"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform/ansi"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/events/terraform/ansi"
|
||||
"github.com/runatlantis/atlantis/server/jobs"
|
||||
"github.com/runatlantis/atlantis/server/logging"
|
||||
)
|
||||
@@ -47,10 +48,10 @@ type Client interface {
|
||||
// RunCommandWithVersion executes terraform with args in path. If v is nil,
|
||||
// it will use the default Terraform version. workspace is the Terraform
|
||||
// workspace which should be set as an environment variable.
|
||||
RunCommandWithVersion(ctx command.ProjectContext, path string, args []string, envs map[string]string, v *version.Version, workspace string) (string, error)
|
||||
RunCommandWithVersion(ctx command.ProjectContext, path string, args []string, envs map[string]string, d terraform.Distribution, v *version.Version, workspace string) (string, error)
|
||||
|
||||
// EnsureVersion makes sure that terraform version `v` is available to use
|
||||
EnsureVersion(log logging.SimpleLogging, v *version.Version) error
|
||||
EnsureVersion(log logging.SimpleLogging, d terraform.Distribution, v *version.Version) error
|
||||
|
||||
// DetectVersion Extracts required_version from Terraform configuration in the specified project directory. Returns nil if unable to determine the version.
|
||||
DetectVersion(log logging.SimpleLogging, projectDirectory string) *version.Version
|
||||
@@ -58,7 +59,7 @@ type Client interface {
|
||||
|
||||
type DefaultClient struct {
|
||||
// Distribution handles logic specific to the TF distribution being used by Atlantis
|
||||
distribution Distribution
|
||||
distribution terraform.Distribution
|
||||
|
||||
// defaultVersion is the default version of terraform to use if another
|
||||
// version isn't specified.
|
||||
@@ -102,7 +103,7 @@ var versionRegex = regexp.MustCompile("(?:Terraform|OpenTofu) v(.*?)(\\s.*)?\n")
|
||||
// NewClientWithDefaultVersion creates a new terraform client and pre-fetches the default version
|
||||
func NewClientWithDefaultVersion(
|
||||
log logging.SimpleLogging,
|
||||
distribution Distribution,
|
||||
distribution terraform.Distribution,
|
||||
binDir string,
|
||||
cacheDir string,
|
||||
tfeToken string,
|
||||
@@ -189,7 +190,7 @@ func NewClientWithDefaultVersion(
|
||||
|
||||
func NewTestClient(
|
||||
log logging.SimpleLogging,
|
||||
distribution Distribution,
|
||||
distribution terraform.Distribution,
|
||||
binDir string,
|
||||
cacheDir string,
|
||||
tfeToken string,
|
||||
@@ -227,7 +228,7 @@ func NewTestClient(
|
||||
// Will asynchronously download the required version if it doesn't exist already.
|
||||
func NewClient(
|
||||
log logging.SimpleLogging,
|
||||
distribution Distribution,
|
||||
distribution terraform.Distribution,
|
||||
binDir string,
|
||||
cacheDir string,
|
||||
tfeToken string,
|
||||
@@ -256,6 +257,10 @@ func NewClient(
|
||||
)
|
||||
}
|
||||
|
||||
func (c *DefaultClient) DefaultDistribution() terraform.Distribution {
|
||||
return c.distribution
|
||||
}
|
||||
|
||||
// Version returns the default version of Terraform we use if no other version
|
||||
// is defined.
|
||||
func (c *DefaultClient) DefaultVersion() *version.Version {
|
||||
@@ -326,14 +331,14 @@ func (c *DefaultClient) DetectVersion(log logging.SimpleLogging, projectDirector
|
||||
}
|
||||
|
||||
// See Client.EnsureVersion.
|
||||
func (c *DefaultClient) EnsureVersion(log logging.SimpleLogging, v *version.Version) error {
|
||||
func (c *DefaultClient) EnsureVersion(log logging.SimpleLogging, d terraform.Distribution, v *version.Version) error {
|
||||
if v == nil {
|
||||
v = c.defaultVersion
|
||||
}
|
||||
|
||||
var err error
|
||||
c.versionsLock.Lock()
|
||||
_, err = ensureVersion(log, c.distribution, c.versions, v, c.binDir, c.downloadBaseURL, c.downloadAllowed)
|
||||
_, err = ensureVersion(log, d, c.versions, v, c.binDir, c.downloadBaseURL, c.downloadAllowed)
|
||||
c.versionsLock.Unlock()
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -343,9 +348,9 @@ func (c *DefaultClient) EnsureVersion(log logging.SimpleLogging, v *version.Vers
|
||||
}
|
||||
|
||||
// See Client.RunCommandWithVersion.
|
||||
func (c *DefaultClient) RunCommandWithVersion(ctx command.ProjectContext, path string, args []string, customEnvVars map[string]string, v *version.Version, workspace string) (string, error) {
|
||||
func (c *DefaultClient) RunCommandWithVersion(ctx command.ProjectContext, path string, args []string, customEnvVars map[string]string, d terraform.Distribution, v *version.Version, workspace string) (string, error) {
|
||||
if isAsyncEligibleCommand(args[0]) {
|
||||
_, outCh := c.RunCommandAsync(ctx, path, args, customEnvVars, v, workspace)
|
||||
_, outCh := c.RunCommandAsync(ctx, path, args, customEnvVars, d, v, workspace)
|
||||
|
||||
var lines []string
|
||||
var err error
|
||||
@@ -362,7 +367,7 @@ func (c *DefaultClient) RunCommandWithVersion(ctx command.ProjectContext, path s
|
||||
output = ansi.Strip(output)
|
||||
return fmt.Sprintf("%s\n", output), err
|
||||
}
|
||||
tfCmd, cmd, err := c.prepExecCmd(ctx.Log, v, workspace, path, args)
|
||||
tfCmd, cmd, err := c.prepExecCmd(ctx.Log, d, v, workspace, path, args)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@@ -388,8 +393,8 @@ func (c *DefaultClient) RunCommandWithVersion(ctx command.ProjectContext, path s
|
||||
// prepExecCmd builds a ready to execute command based on the version of terraform
|
||||
// v, and args. It returns a printable representation of the command that will
|
||||
// be run and the actual command.
|
||||
func (c *DefaultClient) prepExecCmd(log logging.SimpleLogging, v *version.Version, workspace string, path string, args []string) (string, *exec.Cmd, error) {
|
||||
tfCmd, envVars, err := c.prepCmd(log, v, workspace, path, args)
|
||||
func (c *DefaultClient) prepExecCmd(log logging.SimpleLogging, d terraform.Distribution, v *version.Version, workspace string, path string, args []string) (string, *exec.Cmd, error) {
|
||||
tfCmd, envVars, err := c.prepCmd(log, d, v, workspace, path, args)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
}
|
||||
@@ -401,7 +406,8 @@ func (c *DefaultClient) prepExecCmd(log logging.SimpleLogging, v *version.Versio
|
||||
|
||||
// prepCmd prepares a shell command (to be interpreted with `sh -c <cmd>`) and set of environment
|
||||
// variables for running terraform.
|
||||
func (c *DefaultClient) prepCmd(log logging.SimpleLogging, v *version.Version, workspace string, path string, args []string) (string, []string, error) {
|
||||
func (c *DefaultClient) prepCmd(log logging.SimpleLogging, d terraform.Distribution, v *version.Version, workspace string, path string, args []string) (string, []string, error) {
|
||||
|
||||
if v == nil {
|
||||
v = c.defaultVersion
|
||||
}
|
||||
@@ -413,7 +419,7 @@ func (c *DefaultClient) prepCmd(log logging.SimpleLogging, v *version.Version, w
|
||||
} else {
|
||||
var err error
|
||||
c.versionsLock.Lock()
|
||||
binPath, err = ensureVersion(log, c.distribution, c.versions, v, c.binDir, c.downloadBaseURL, c.downloadAllowed)
|
||||
binPath, err = ensureVersion(log, d, c.versions, v, c.binDir, c.downloadBaseURL, c.downloadAllowed)
|
||||
c.versionsLock.Unlock()
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
@@ -446,8 +452,8 @@ func (c *DefaultClient) prepCmd(log logging.SimpleLogging, v *version.Version, w
|
||||
// Callers can use the input channel to pass stdin input to the command.
|
||||
// If any error is passed on the out channel, there will be no
|
||||
// further output (so callers are free to exit).
|
||||
func (c *DefaultClient) RunCommandAsync(ctx command.ProjectContext, path string, args []string, customEnvVars map[string]string, v *version.Version, workspace string) (chan<- string, <-chan models.Line) {
|
||||
cmd, envVars, err := c.prepCmd(ctx.Log, v, workspace, path, args)
|
||||
func (c *DefaultClient) RunCommandAsync(ctx command.ProjectContext, path string, args []string, customEnvVars map[string]string, d terraform.Distribution, v *version.Version, workspace string) (chan<- string, <-chan models.Line) {
|
||||
cmd, envVars, err := c.prepCmd(ctx.Log, d, v, workspace, path, args)
|
||||
if err != nil {
|
||||
// The signature of `RunCommandAsync` doesn't provide for returning an immediate error, only one
|
||||
// once reading the output. Since we won't be spawning a process, simulate that by sending the
|
||||
@@ -486,7 +492,7 @@ func MustConstraint(v string) version.Constraints {
|
||||
// It will download this version if we don't have it.
|
||||
func ensureVersion(
|
||||
log logging.SimpleLogging,
|
||||
dist Distribution,
|
||||
dist terraform.Distribution,
|
||||
versions map[string]string,
|
||||
v *version.Version,
|
||||
binDir string,
|
||||
@@ -1,4 +1,4 @@
|
||||
package terraform
|
||||
package tfclient
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
@@ -10,6 +10,8 @@ import (
|
||||
version "github.com/hashicorp/go-version"
|
||||
. "github.com/petergtz/pegomock/v4"
|
||||
runtimemodels "github.com/runatlantis/atlantis/server/core/runtime/models"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform"
|
||||
terraform_mocks "github.com/runatlantis/atlantis/server/core/terraform/mocks"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/events/models"
|
||||
jobmocks "github.com/runatlantis/atlantis/server/jobs/mocks"
|
||||
@@ -120,7 +122,9 @@ func TestDefaultClient_RunCommandWithVersion_EnvVars(t *testing.T) {
|
||||
"DIR=$DIR",
|
||||
}
|
||||
customEnvVars := map[string]string{}
|
||||
out, err := client.RunCommandWithVersion(ctx, tmp, args, customEnvVars, nil, "workspace")
|
||||
mockDownloader := terraform_mocks.NewMockDownloader()
|
||||
distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
out, err := client.RunCommandWithVersion(ctx, tmp, args, customEnvVars, distribution, nil, "workspace")
|
||||
Ok(t, err)
|
||||
exp := fmt.Sprintf("TF_IN_AUTOMATION=true TF_PLUGIN_CACHE_DIR=%s WORKSPACE=workspace ATLANTIS_TERRAFORM_VERSION=0.11.11 DIR=%s\n", tmp, tmp)
|
||||
Equals(t, exp, out)
|
||||
@@ -163,7 +167,9 @@ func TestDefaultClient_RunCommandWithVersion_Error(t *testing.T) {
|
||||
"exit",
|
||||
"1",
|
||||
}
|
||||
out, err := client.RunCommandWithVersion(ctx, tmp, args, map[string]string{}, nil, "workspace")
|
||||
mockDownloader := terraform_mocks.NewMockDownloader()
|
||||
distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
out, err := client.RunCommandWithVersion(ctx, tmp, args, map[string]string{}, distribution, nil, "workspace")
|
||||
ErrEquals(t, fmt.Sprintf(`running 'echo dying && exit 1' in '%s': exit status 1`, tmp), err)
|
||||
// Test that we still get our output.
|
||||
Equals(t, "dying\n", out)
|
||||
@@ -209,7 +215,9 @@ func TestDefaultClient_RunCommandAsync_Success(t *testing.T) {
|
||||
"ATLANTIS_TERRAFORM_VERSION=$ATLANTIS_TERRAFORM_VERSION",
|
||||
"DIR=$DIR",
|
||||
}
|
||||
_, outCh := client.RunCommandAsync(ctx, tmp, args, map[string]string{}, nil, "workspace")
|
||||
mockDownloader := terraform_mocks.NewMockDownloader()
|
||||
distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
_, outCh := client.RunCommandAsync(ctx, tmp, args, map[string]string{}, distribution, nil, "workspace")
|
||||
|
||||
out, err := waitCh(outCh)
|
||||
Ok(t, err)
|
||||
@@ -261,7 +269,9 @@ func TestDefaultClient_RunCommandAsync_BigOutput(t *testing.T) {
|
||||
_, err = f.WriteString(s)
|
||||
Ok(t, err)
|
||||
}
|
||||
_, outCh := client.RunCommandAsync(ctx, tmp, []string{filename}, map[string]string{}, nil, "workspace")
|
||||
mockDownloader := terraform_mocks.NewMockDownloader()
|
||||
distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
_, outCh := client.RunCommandAsync(ctx, tmp, []string{filename}, map[string]string{}, distribution, nil, "workspace")
|
||||
|
||||
out, err := waitCh(outCh)
|
||||
Ok(t, err)
|
||||
@@ -301,7 +311,9 @@ func TestDefaultClient_RunCommandAsync_StderrOutput(t *testing.T) {
|
||||
overrideTF: "echo",
|
||||
projectCmdOutputHandler: projectCmdOutputHandler,
|
||||
}
|
||||
_, outCh := client.RunCommandAsync(ctx, tmp, []string{"stderr", ">&2"}, map[string]string{}, nil, "workspace")
|
||||
mockDownloader := terraform_mocks.NewMockDownloader()
|
||||
distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
_, outCh := client.RunCommandAsync(ctx, tmp, []string{"stderr", ">&2"}, map[string]string{}, distribution, nil, "workspace")
|
||||
|
||||
out, err := waitCh(outCh)
|
||||
Ok(t, err)
|
||||
@@ -341,7 +353,9 @@ func TestDefaultClient_RunCommandAsync_ExitOne(t *testing.T) {
|
||||
overrideTF: "echo",
|
||||
projectCmdOutputHandler: projectCmdOutputHandler,
|
||||
}
|
||||
_, outCh := client.RunCommandAsync(ctx, tmp, []string{"dying", "&&", "exit", "1"}, map[string]string{}, nil, "workspace")
|
||||
mockDownloader := terraform_mocks.NewMockDownloader()
|
||||
distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
_, outCh := client.RunCommandAsync(ctx, tmp, []string{"dying", "&&", "exit", "1"}, map[string]string{}, distribution, nil, "workspace")
|
||||
|
||||
out, err := waitCh(outCh)
|
||||
ErrEquals(t, fmt.Sprintf(`running 'sh -c' 'echo dying && exit 1' in '%s': exit status 1`, tmp), err)
|
||||
@@ -383,7 +397,9 @@ func TestDefaultClient_RunCommandAsync_Input(t *testing.T) {
|
||||
projectCmdOutputHandler: projectCmdOutputHandler,
|
||||
}
|
||||
|
||||
inCh, outCh := client.RunCommandAsync(ctx, tmp, []string{"a", "&&", "echo", "$a"}, map[string]string{}, nil, "workspace")
|
||||
mockDownloader := terraform_mocks.NewMockDownloader()
|
||||
distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
inCh, outCh := client.RunCommandAsync(ctx, tmp, []string{"a", "&&", "echo", "$a"}, map[string]string{}, distribution, nil, "workspace")
|
||||
inCh <- "echo me\n"
|
||||
|
||||
out, err := waitCh(outCh)
|
||||
@@ -11,7 +11,7 @@
|
||||
// limitations under the License.
|
||||
// Modified hereafter by contributors to runatlantis/atlantis.
|
||||
|
||||
package terraform_test
|
||||
package tfclient_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"github.com/runatlantis/atlantis/cmd"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform/mocks"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform/tfclient"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
jobmocks "github.com/runatlantis/atlantis/server/jobs/mocks"
|
||||
"github.com/runatlantis/atlantis/server/logging"
|
||||
@@ -42,12 +43,12 @@ func TestMustConstraint_PanicsOnBadConstraint(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
|
||||
terraform.MustConstraint("invalid constraint")
|
||||
tfclient.MustConstraint("invalid constraint")
|
||||
}
|
||||
|
||||
func TestMustConstraint(t *testing.T) {
|
||||
t.Log("MustConstraint should return the constrain")
|
||||
c := terraform.MustConstraint(">0.1")
|
||||
c := tfclient.MustConstraint(">0.1")
|
||||
expectedConstraint, err := version.NewConstraint(">0.1")
|
||||
Ok(t, err)
|
||||
Equals(t, expectedConstraint.String(), c.String())
|
||||
@@ -80,13 +81,13 @@ is 0.11.13. You can update by downloading from developer.hashicorp.com/terraform
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
|
||||
c, err := terraform.NewClient(logger, distribution, binDir, cacheDir, "", "", "", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler)
|
||||
c, err := tfclient.NewClient(logger, distribution, binDir, cacheDir, "", "", "", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler)
|
||||
Ok(t, err)
|
||||
|
||||
Ok(t, err)
|
||||
Equals(t, "0.11.10", c.DefaultVersion().String())
|
||||
|
||||
output, err := c.RunCommandWithVersion(ctx, tmp, []string{"terraform", "init"}, map[string]string{"test": "123"}, nil, "")
|
||||
output, err := c.RunCommandWithVersion(ctx, tmp, []string{"terraform", "init"}, map[string]string{"test": "123"}, distribution, nil, "")
|
||||
Ok(t, err)
|
||||
Equals(t, fakeBinOut+"\n", output)
|
||||
}
|
||||
@@ -117,13 +118,13 @@ is 0.11.13. You can update by downloading from developer.hashicorp.com/terraform
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
|
||||
c, err := terraform.NewClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler)
|
||||
c, err := tfclient.NewClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler)
|
||||
Ok(t, err)
|
||||
|
||||
Ok(t, err)
|
||||
Equals(t, "0.11.10", c.DefaultVersion().String())
|
||||
|
||||
output, err := c.RunCommandWithVersion(ctx, tmp, []string{"terraform", "init"}, map[string]string{}, nil, "")
|
||||
output, err := c.RunCommandWithVersion(ctx, tmp, []string{"terraform", "init"}, map[string]string{}, distribution, nil, "")
|
||||
Ok(t, err)
|
||||
Equals(t, fakeBinOut+"\n", output)
|
||||
}
|
||||
@@ -141,7 +142,7 @@ func TestNewClient_NoTF(t *testing.T) {
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
|
||||
_, err := terraform.NewClient(logger, distribution, binDir, cacheDir, "", "", "", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler)
|
||||
_, err := tfclient.NewClient(logger, distribution, binDir, cacheDir, "", "", "", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler)
|
||||
ErrEquals(t, "terraform not found in $PATH. Set --default-tf-version or download terraform from https://developer.hashicorp.com/terraform/downloads", err)
|
||||
}
|
||||
|
||||
@@ -167,13 +168,13 @@ func TestNewClient_DefaultTFFlagInPath(t *testing.T) {
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
|
||||
c, err := terraform.NewClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, false, true, projectCmdOutputHandler)
|
||||
c, err := tfclient.NewClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, false, true, projectCmdOutputHandler)
|
||||
Ok(t, err)
|
||||
|
||||
Ok(t, err)
|
||||
Equals(t, "0.11.10", c.DefaultVersion().String())
|
||||
|
||||
output, err := c.RunCommandWithVersion(ctx, tmp, []string{"terraform", "init"}, map[string]string{}, nil, "")
|
||||
output, err := c.RunCommandWithVersion(ctx, tmp, []string{"terraform", "init"}, map[string]string{}, distribution, nil, "")
|
||||
Ok(t, err)
|
||||
Equals(t, fakeBinOut+"\n", output)
|
||||
}
|
||||
@@ -198,13 +199,13 @@ func TestNewClient_DefaultTFFlagInBinDir(t *testing.T) {
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
|
||||
c, err := terraform.NewClient(logging.NewNoopLogger(t), distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler)
|
||||
c, err := tfclient.NewClient(logging.NewNoopLogger(t), distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler)
|
||||
Ok(t, err)
|
||||
|
||||
Ok(t, err)
|
||||
Equals(t, "0.11.10", c.DefaultVersion().String())
|
||||
|
||||
output, err := c.RunCommandWithVersion(ctx, tmp, []string{"terraform", "init"}, map[string]string{}, nil, "")
|
||||
output, err := c.RunCommandWithVersion(ctx, tmp, []string{"terraform", "init"}, map[string]string{}, distribution, nil, "")
|
||||
Ok(t, err)
|
||||
Equals(t, fakeBinOut+"\n", output)
|
||||
}
|
||||
@@ -232,7 +233,7 @@ func TestNewClient_DefaultTFFlagDownload(t *testing.T) {
|
||||
return []ReturnValue{binPath, err}
|
||||
})
|
||||
distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
c, err := terraform.NewClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler)
|
||||
c, err := tfclient.NewClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler)
|
||||
Ok(t, err)
|
||||
|
||||
Ok(t, err)
|
||||
@@ -243,7 +244,7 @@ func TestNewClient_DefaultTFFlagDownload(t *testing.T) {
|
||||
// Reset PATH so that it has sh.
|
||||
Ok(t, os.Setenv("PATH", orig))
|
||||
|
||||
output, err := c.RunCommandWithVersion(ctx, tmp, []string{"terraform", "init"}, map[string]string{}, nil, "")
|
||||
output, err := c.RunCommandWithVersion(ctx, tmp, []string{"terraform", "init"}, map[string]string{}, distribution, nil, "")
|
||||
Ok(t, err)
|
||||
Equals(t, "\nTerraform v0.11.10\n\n", output)
|
||||
}
|
||||
@@ -255,7 +256,7 @@ func TestNewClient_BadVersion(t *testing.T) {
|
||||
projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler()
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
_, err := terraform.NewClient(logger, distribution, binDir, cacheDir, "", "", "malformed", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler)
|
||||
_, err := tfclient.NewClient(logger, distribution, binDir, cacheDir, "", "", "malformed", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler)
|
||||
ErrEquals(t, "Malformed version: malformed", err)
|
||||
}
|
||||
|
||||
@@ -283,11 +284,11 @@ func TestRunCommandWithVersion_DLsTF(t *testing.T) {
|
||||
return []ReturnValue{binPath, err}
|
||||
})
|
||||
|
||||
c, err := terraform.NewClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler)
|
||||
c, err := tfclient.NewClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler)
|
||||
Ok(t, err)
|
||||
Equals(t, "0.11.10", c.DefaultVersion().String())
|
||||
|
||||
output, err := c.RunCommandWithVersion(ctx, tmp, []string{"terraform", "init"}, map[string]string{}, v, "")
|
||||
output, err := c.RunCommandWithVersion(ctx, tmp, []string{"terraform", "init"}, map[string]string{}, distribution, v, "")
|
||||
|
||||
Assert(t, err == nil, "err: %s: %s", err, output)
|
||||
Equals(t, "\nTerraform v99.99.99\n\n", output)
|
||||
@@ -304,7 +305,7 @@ func TestEnsureVersion_downloaded(t *testing.T) {
|
||||
distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
|
||||
downloadsAllowed := true
|
||||
c, err := terraform.NewTestClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, downloadsAllowed, true, projectCmdOutputHandler)
|
||||
c, err := tfclient.NewTestClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, downloadsAllowed, true, projectCmdOutputHandler)
|
||||
Ok(t, err)
|
||||
|
||||
Equals(t, "0.11.10", c.DefaultVersion().String())
|
||||
@@ -318,7 +319,7 @@ func TestEnsureVersion_downloaded(t *testing.T) {
|
||||
return []ReturnValue{binPath, err}
|
||||
})
|
||||
|
||||
err = c.EnsureVersion(logger, v)
|
||||
err = c.EnsureVersion(logger, distribution, v)
|
||||
|
||||
Ok(t, err)
|
||||
|
||||
@@ -337,7 +338,7 @@ func TestEnsureVersion_downloaded_customURL(t *testing.T) {
|
||||
downloadsAllowed := true
|
||||
customURL := "http://releases.example.com"
|
||||
|
||||
c, err := terraform.NewTestClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, customURL, downloadsAllowed, true, projectCmdOutputHandler)
|
||||
c, err := tfclient.NewTestClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, customURL, downloadsAllowed, true, projectCmdOutputHandler)
|
||||
Ok(t, err)
|
||||
|
||||
Equals(t, "0.11.10", c.DefaultVersion().String())
|
||||
@@ -351,7 +352,7 @@ func TestEnsureVersion_downloaded_customURL(t *testing.T) {
|
||||
return []ReturnValue{binPath, err}
|
||||
})
|
||||
|
||||
err = c.EnsureVersion(logger, v)
|
||||
err = c.EnsureVersion(logger, distribution, v)
|
||||
|
||||
Ok(t, err)
|
||||
|
||||
@@ -369,7 +370,7 @@ func TestEnsureVersion_downloaded_downloadingDisabled(t *testing.T) {
|
||||
distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
|
||||
downloadsAllowed := false
|
||||
c, err := terraform.NewTestClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, downloadsAllowed, true, projectCmdOutputHandler)
|
||||
c, err := tfclient.NewTestClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, downloadsAllowed, true, projectCmdOutputHandler)
|
||||
Ok(t, err)
|
||||
|
||||
Equals(t, "0.11.10", c.DefaultVersion().String())
|
||||
@@ -377,7 +378,7 @@ func TestEnsureVersion_downloaded_downloadingDisabled(t *testing.T) {
|
||||
v, err := version.NewVersion("99.99.99")
|
||||
Ok(t, err)
|
||||
|
||||
err = c.EnsureVersion(logger, v)
|
||||
err = c.EnsureVersion(logger, distribution, v)
|
||||
ErrContains(t, "could not find terraform version", err)
|
||||
ErrContains(t, "downloads are disabled", err)
|
||||
mockDownloader.VerifyWasCalled(Never())
|
||||
@@ -501,7 +502,7 @@ terraform {
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
|
||||
c, err := terraform.NewTestClient(
|
||||
c, err := tfclient.NewTestClient(
|
||||
logger,
|
||||
distribution,
|
||||
binDir,
|
||||
@@ -548,7 +549,7 @@ func TestExtractExactRegex(t *testing.T) {
|
||||
mockDownloader := mocks.NewMockDownloader()
|
||||
distribution := terraform.NewDistributionTerraformWithDownloader(mockDownloader)
|
||||
|
||||
c, err := terraform.NewTestClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler)
|
||||
c, err := tfclient.NewTestClient(logger, distribution, binDir, cacheDir, "", "", "0.11.10", cmd.DefaultTFVersionFlag, cmd.DefaultTFDownloadURL, true, true, projectCmdOutputHandler)
|
||||
Ok(t, err)
|
||||
|
||||
tests := []struct {
|
||||
@@ -93,6 +93,10 @@ type ProjectContext struct {
|
||||
// Steps are the sequence of commands we need to run for this project and this
|
||||
// stage.
|
||||
Steps []valid.Step
|
||||
// TerraformDistribution is the distribution of terraform we should use when
|
||||
// executing commands for this project. This can be set to nil in which case
|
||||
// we will use the default Atlantis terraform distribution.
|
||||
TerraformDistribution *string
|
||||
// TerraformVersion is the version of terraform we should use when executing
|
||||
// commands for this project. This can be set to nil in which case we will
|
||||
// use the default Atlantis terraform version.
|
||||
|
||||
@@ -7,12 +7,13 @@ import (
|
||||
)
|
||||
|
||||
type ProjectScopeTags struct {
|
||||
BaseRepo string
|
||||
PrNumber string
|
||||
Project string
|
||||
ProjectPath string
|
||||
TerraformVersion string
|
||||
Workspace string
|
||||
BaseRepo string
|
||||
PrNumber string
|
||||
Project string
|
||||
ProjectPath string
|
||||
TerraformDistribution string
|
||||
TerraformVersion string
|
||||
Workspace string
|
||||
}
|
||||
|
||||
func (s ProjectScopeTags) Loadtags() map[string]string {
|
||||
|
||||
@@ -4,12 +4,11 @@
|
||||
package events
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"time"
|
||||
|
||||
pegomock "github.com/petergtz/pegomock/v4"
|
||||
models "github.com/runatlantis/atlantis/server/events/models"
|
||||
logging "github.com/runatlantis/atlantis/server/logging"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MockWorkingDir struct {
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
tally "github.com/uber-go/tally/v4"
|
||||
|
||||
"github.com/runatlantis/atlantis/server/core/config/valid"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform/tfclient"
|
||||
"github.com/runatlantis/atlantis/server/logging"
|
||||
"github.com/runatlantis/atlantis/server/metrics"
|
||||
|
||||
@@ -59,7 +59,7 @@ func NewInstrumentedProjectCommandBuilder(
|
||||
IncludeGitUntrackedFiles bool,
|
||||
AutoDiscoverMode string,
|
||||
scope tally.Scope,
|
||||
terraformClient terraform.Client,
|
||||
terraformClient tfclient.Client,
|
||||
) *InstrumentedProjectCommandBuilder {
|
||||
scope = scope.SubScope("builder")
|
||||
|
||||
@@ -119,7 +119,7 @@ func NewProjectCommandBuilder(
|
||||
IncludeGitUntrackedFiles bool,
|
||||
AutoDiscoverMode string,
|
||||
scope tally.Scope,
|
||||
terraformClient terraform.Client,
|
||||
terraformClient tfclient.Client,
|
||||
) *DefaultProjectCommandBuilder {
|
||||
return &DefaultProjectCommandBuilder{
|
||||
ParserValidator: parserValidator,
|
||||
@@ -249,7 +249,7 @@ type DefaultProjectCommandBuilder struct {
|
||||
// User config option: Controls auto-discovery of projects in a repository.
|
||||
AutoDiscoverMode string
|
||||
// Handles the actual running of Terraform commands.
|
||||
TerraformExecutor terraform.Client
|
||||
TerraformExecutor tfclient.Client
|
||||
}
|
||||
|
||||
// See ProjectCommandBuilder.BuildAutoplanCommands.
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
. "github.com/petergtz/pegomock/v4"
|
||||
"github.com/runatlantis/atlantis/server/core/config"
|
||||
"github.com/runatlantis/atlantis/server/core/config/valid"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform/mocks"
|
||||
tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/events/models"
|
||||
vcsmocks "github.com/runatlantis/atlantis/server/events/vcs/mocks"
|
||||
@@ -648,7 +648,7 @@ projects:
|
||||
Ok(t, os.WriteFile(filepath.Join(tmp, "atlantis.yaml"), []byte(c.repoCfg), 0600))
|
||||
}
|
||||
|
||||
terraformClient := mocks.NewMockClient()
|
||||
terraformClient := tfclientmocks.NewMockClient()
|
||||
|
||||
builder := NewProjectCommandBuilder(
|
||||
false,
|
||||
@@ -865,7 +865,7 @@ projects:
|
||||
|
||||
statsScope, _, _ := metrics.NewLoggingScope(logging.NewNoopLogger(t), "atlantis")
|
||||
|
||||
terraformClient := mocks.NewMockClient()
|
||||
terraformClient := tfclientmocks.NewMockClient()
|
||||
|
||||
builder := NewProjectCommandBuilder(
|
||||
false,
|
||||
@@ -1112,7 +1112,7 @@ workflows:
|
||||
}
|
||||
statsScope, _, _ := metrics.NewLoggingScope(logging.NewNoopLogger(t), "atlantis")
|
||||
|
||||
terraformClient := mocks.NewMockClient()
|
||||
terraformClient := tfclientmocks.NewMockClient()
|
||||
|
||||
builder := NewProjectCommandBuilder(
|
||||
true,
|
||||
@@ -1264,7 +1264,7 @@ projects:
|
||||
}
|
||||
statsScope, _, _ := metrics.NewLoggingScope(logging.NewNoopLogger(t), "atlantis")
|
||||
|
||||
terraformClient := mocks.NewMockClient()
|
||||
terraformClient := tfclientmocks.NewMockClient()
|
||||
|
||||
builder := NewProjectCommandBuilder(
|
||||
false,
|
||||
@@ -1406,7 +1406,7 @@ projects:
|
||||
}
|
||||
statsScope, _, _ := metrics.NewLoggingScope(logging.NewNoopLogger(t), "atlantis")
|
||||
|
||||
terraformClient := mocks.NewMockClient()
|
||||
terraformClient := tfclientmocks.NewMockClient()
|
||||
|
||||
builder := NewProjectCommandBuilder(
|
||||
false,
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
"github.com/hashicorp/go-version"
|
||||
. "github.com/petergtz/pegomock/v4"
|
||||
terraform_mocks "github.com/runatlantis/atlantis/server/core/terraform/mocks"
|
||||
tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks"
|
||||
|
||||
"github.com/runatlantis/atlantis/server/core/config"
|
||||
"github.com/runatlantis/atlantis/server/core/config/valid"
|
||||
@@ -233,7 +233,7 @@ terraform {
|
||||
scope, _, _ := metrics.NewLoggingScope(logger, "atlantis")
|
||||
userConfig := defaultUserConfig
|
||||
|
||||
terraformClient := terraform_mocks.NewMockClient()
|
||||
terraformClient := tfclientmocks.NewMockClient()
|
||||
|
||||
for _, c := range cases {
|
||||
t.Run(c.Description, func(t *testing.T) {
|
||||
@@ -616,7 +616,7 @@ projects:
|
||||
AllowAllRepoSettings: true,
|
||||
}
|
||||
|
||||
terraformClient := terraform_mocks.NewMockClient()
|
||||
terraformClient := tfclientmocks.NewMockClient()
|
||||
|
||||
builder := events.NewProjectCommandBuilder(
|
||||
false,
|
||||
@@ -804,7 +804,7 @@ projects:
|
||||
AllowAllRepoSettings: true,
|
||||
}
|
||||
|
||||
terraformClient := terraform_mocks.NewMockClient()
|
||||
terraformClient := tfclientmocks.NewMockClient()
|
||||
|
||||
builder := events.NewProjectCommandBuilder(
|
||||
false,
|
||||
@@ -1133,7 +1133,7 @@ projects:
|
||||
AllowAllRepoSettings: true,
|
||||
}
|
||||
|
||||
terraformClient := terraform_mocks.NewMockClient()
|
||||
terraformClient := tfclientmocks.NewMockClient()
|
||||
|
||||
builder := events.NewProjectCommandBuilder(
|
||||
false,
|
||||
@@ -1231,7 +1231,7 @@ func TestDefaultProjectCommandBuilder_BuildMultiApply(t *testing.T) {
|
||||
globalCfgArgs := valid.GlobalCfgArgs{}
|
||||
scope, _, _ := metrics.NewLoggingScope(logger, "atlantis")
|
||||
|
||||
terraformClient := terraform_mocks.NewMockClient()
|
||||
terraformClient := tfclientmocks.NewMockClient()
|
||||
|
||||
builder := events.NewProjectCommandBuilder(
|
||||
false,
|
||||
@@ -1317,7 +1317,7 @@ projects:
|
||||
scope, _, _ := metrics.NewLoggingScope(logger, "atlantis")
|
||||
userConfig := defaultUserConfig
|
||||
|
||||
terraformClient := terraform_mocks.NewMockClient()
|
||||
terraformClient := tfclientmocks.NewMockClient()
|
||||
|
||||
builder := events.NewProjectCommandBuilder(
|
||||
false,
|
||||
@@ -1405,7 +1405,7 @@ func TestDefaultProjectCommandBuilder_EscapeArgs(t *testing.T) {
|
||||
AllowAllRepoSettings: true,
|
||||
}
|
||||
|
||||
terraformClient := terraform_mocks.NewMockClient()
|
||||
terraformClient := tfclientmocks.NewMockClient()
|
||||
|
||||
builder := events.NewProjectCommandBuilder(
|
||||
false,
|
||||
@@ -1558,7 +1558,7 @@ projects:
|
||||
AllowAllRepoSettings: true,
|
||||
}
|
||||
|
||||
terraformClient := terraform_mocks.NewMockClient()
|
||||
terraformClient := tfclientmocks.NewMockClient()
|
||||
When(terraformClient.DetectVersion(Any[logging.SimpleLogging](), Any[string]())).Then(func(params []Param) ReturnValues {
|
||||
projectName := filepath.Base(params[1].(string))
|
||||
testVersion := testCase.Exp[projectName]
|
||||
@@ -1677,7 +1677,7 @@ projects:
|
||||
AllowAllRepoSettings: true,
|
||||
}
|
||||
scope, _, _ := metrics.NewLoggingScope(logger, "atlantis")
|
||||
terraformClient := terraform_mocks.NewMockClient()
|
||||
terraformClient := tfclientmocks.NewMockClient()
|
||||
|
||||
builder := events.NewProjectCommandBuilder(
|
||||
false,
|
||||
@@ -1746,7 +1746,7 @@ func TestDefaultProjectCommandBuilder_WithPolicyCheckEnabled_BuildAutoplanComman
|
||||
}
|
||||
|
||||
globalCfg := valid.NewGlobalCfgFromArgs(globalCfgArgs)
|
||||
terraformClient := terraform_mocks.NewMockClient()
|
||||
terraformClient := tfclientmocks.NewMockClient()
|
||||
|
||||
builder := events.NewProjectCommandBuilder(
|
||||
true,
|
||||
@@ -1834,7 +1834,7 @@ func TestDefaultProjectCommandBuilder_BuildVersionCommand(t *testing.T) {
|
||||
globalCfgArgs := valid.GlobalCfgArgs{
|
||||
AllowAllRepoSettings: false,
|
||||
}
|
||||
terraformClient := terraform_mocks.NewMockClient()
|
||||
terraformClient := tfclientmocks.NewMockClient()
|
||||
|
||||
builder := events.NewProjectCommandBuilder(
|
||||
false,
|
||||
@@ -1964,7 +1964,7 @@ func TestDefaultProjectCommandBuilder_BuildPlanCommands_Single_With_RestrictFile
|
||||
Ok(t, err)
|
||||
}
|
||||
|
||||
terraformClient := terraform_mocks.NewMockClient()
|
||||
terraformClient := tfclientmocks.NewMockClient()
|
||||
|
||||
builder := events.NewProjectCommandBuilder(
|
||||
false, // policyChecksSupported
|
||||
@@ -2075,7 +2075,7 @@ func TestDefaultProjectCommandBuilder_BuildPlanCommands_with_IncludeGitUntracked
|
||||
Ok(t, err)
|
||||
}
|
||||
|
||||
terraformClient := terraform_mocks.NewMockClient()
|
||||
terraformClient := tfclientmocks.NewMockClient()
|
||||
|
||||
builder := events.NewProjectCommandBuilder(
|
||||
false, // policyChecksSupported
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/runatlantis/atlantis/server/core/config/valid"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform/tfclient"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/events/models"
|
||||
tally "github.com/uber-go/tally/v4"
|
||||
@@ -38,7 +38,7 @@ type ProjectCommandContextBuilder interface {
|
||||
prjCfg valid.MergedProjectCfg,
|
||||
commentFlags []string,
|
||||
repoDir string,
|
||||
automerge, parallelApply, parallelPlan, verbose, abortOnExecutionOrderFail bool, terraformClient terraform.Client,
|
||||
automerge, parallelApply, parallelPlan, verbose, abortOnExecutionOrderFail bool, terraformClient tfclient.Client,
|
||||
) []command.ProjectContext
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ func (cb *CommandScopedStatsProjectCommandContextBuilder) BuildProjectContext(
|
||||
commentFlags []string,
|
||||
repoDir string,
|
||||
automerge, parallelApply, parallelPlan, verbose, abortOnExecutionOrderFail bool,
|
||||
terraformClient terraform.Client,
|
||||
terraformClient tfclient.Client,
|
||||
) (projectCmds []command.ProjectContext) {
|
||||
cb.ProjectCounter.Inc(1)
|
||||
|
||||
@@ -93,7 +93,7 @@ func (cb *DefaultProjectCommandContextBuilder) BuildProjectContext(
|
||||
commentFlags []string,
|
||||
repoDir string,
|
||||
automerge, parallelApply, parallelPlan, verbose, abortOnExecutionOrderFail bool,
|
||||
terraformClient terraform.Client,
|
||||
terraformClient tfclient.Client,
|
||||
) (projectCmds []command.ProjectContext) {
|
||||
ctx.Log.Debug("Building project command context for %s", cmdName)
|
||||
|
||||
@@ -166,7 +166,7 @@ func (cb *PolicyCheckProjectCommandContextBuilder) BuildProjectContext(
|
||||
commentFlags []string,
|
||||
repoDir string,
|
||||
automerge, parallelApply, parallelPlan, verbose, abortOnExecutionOrderFail bool,
|
||||
terraformClient terraform.Client,
|
||||
terraformClient tfclient.Client,
|
||||
) (projectCmds []command.ProjectContext) {
|
||||
if prjCfg.PolicyCheck {
|
||||
ctx.Log.Debug("PolicyChecks are enabled")
|
||||
@@ -297,6 +297,7 @@ func newProjectCommandContext(ctx *command.Context,
|
||||
RePlanCmd: planCmd,
|
||||
RepoRelDir: projCfg.RepoRelDir,
|
||||
RepoConfigVersion: projCfg.RepoCfgVersion,
|
||||
TerraformDistribution: projCfg.TerraformDistribution,
|
||||
TerraformVersion: projCfg.TerraformVersion,
|
||||
User: ctx.User,
|
||||
Verbose: verbose,
|
||||
|
||||
@@ -5,7 +5,7 @@ import (
|
||||
|
||||
. "github.com/petergtz/pegomock/v4"
|
||||
"github.com/runatlantis/atlantis/server/core/config/valid"
|
||||
terraform_mocks "github.com/runatlantis/atlantis/server/core/terraform/mocks"
|
||||
tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks"
|
||||
"github.com/runatlantis/atlantis/server/events"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/events/mocks"
|
||||
@@ -47,7 +47,7 @@ func TestProjectCommandContextBuilder_PullStatus(t *testing.T) {
|
||||
expectedApplyCmt := "Apply Comment"
|
||||
expectedPlanCmt := "Plan Comment"
|
||||
|
||||
terraformClient := terraform_mocks.NewMockClient()
|
||||
terraformClient := tfclientmocks.NewMockClient()
|
||||
|
||||
t.Run("with project name defined", func(t *testing.T) {
|
||||
When(mockCommentBuilder.BuildPlanComment(projRepoRelDir, projWorkspace, projName, []string{})).ThenReturn(expectedPlanCmt)
|
||||
|
||||
@@ -23,7 +23,9 @@ import (
|
||||
. "github.com/petergtz/pegomock/v4"
|
||||
"github.com/runatlantis/atlantis/server/core/config/valid"
|
||||
"github.com/runatlantis/atlantis/server/core/runtime"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform"
|
||||
tmocks "github.com/runatlantis/atlantis/server/core/terraform/mocks"
|
||||
tfclientmocks "github.com/runatlantis/atlantis/server/core/terraform/tfclient/mocks"
|
||||
"github.com/runatlantis/atlantis/server/events"
|
||||
"github.com/runatlantis/atlantis/server/events/command"
|
||||
"github.com/runatlantis/atlantis/server/events/mocks"
|
||||
@@ -542,12 +544,14 @@ func TestDefaultProjectCommandRunner_ApplyRunStepFailure(t *testing.T) {
|
||||
// not running any Terraform.
|
||||
func TestDefaultProjectCommandRunner_RunEnvSteps(t *testing.T) {
|
||||
RegisterMockTestingT(t)
|
||||
tfClient := tmocks.NewMockClient()
|
||||
tfClient := tfclientmocks.NewMockClient()
|
||||
tfDistribution := terraform.NewDistributionTerraformWithDownloader(tmocks.NewMockDownloader())
|
||||
tfVersion, err := version.NewVersion("0.12.0")
|
||||
Ok(t, err)
|
||||
projectCmdOutputHandler := jobmocks.NewMockProjectCommandOutputHandler()
|
||||
run := runtime.RunStepRunner{
|
||||
TerraformExecutor: tfClient,
|
||||
DefaultTFDistribution: tfDistribution,
|
||||
DefaultTFVersion: tfVersion,
|
||||
ProjectCmdOutputHandler: projectCmdOutputHandler,
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ import (
|
||||
"github.com/runatlantis/atlantis/server/core/config/valid"
|
||||
"github.com/runatlantis/atlantis/server/core/db"
|
||||
"github.com/runatlantis/atlantis/server/core/redis"
|
||||
"github.com/runatlantis/atlantis/server/core/terraform/tfclient"
|
||||
"github.com/runatlantis/atlantis/server/jobs"
|
||||
"github.com/runatlantis/atlantis/server/metrics"
|
||||
"github.com/runatlantis/atlantis/server/scheduled"
|
||||
@@ -127,12 +128,13 @@ type Server struct {
|
||||
|
||||
// Config holds config for server that isn't passed in by the user.
|
||||
type Config struct {
|
||||
AllowForkPRsFlag string
|
||||
AtlantisURLFlag string
|
||||
AtlantisVersion string
|
||||
DefaultTFVersionFlag string
|
||||
RepoConfigJSONFlag string
|
||||
SilenceForkPRErrorsFlag string
|
||||
AllowForkPRsFlag string
|
||||
AtlantisURLFlag string
|
||||
AtlantisVersion string
|
||||
DefaultTFDistributionFlag string
|
||||
DefaultTFVersionFlag string
|
||||
RepoConfigJSONFlag string
|
||||
SilenceForkPRErrorsFlag string
|
||||
}
|
||||
|
||||
// WebhookConfig is nested within UserConfig. It's used to configure webhooks.
|
||||
@@ -427,12 +429,9 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) {
|
||||
)
|
||||
}
|
||||
|
||||
distribution := terraform.NewDistributionTerraform()
|
||||
if userConfig.TFDistribution == "opentofu" {
|
||||
distribution = terraform.NewDistributionOpenTofu()
|
||||
}
|
||||
distribution := terraform.NewDistribution(userConfig.DefaultTFDistribution)
|
||||
|
||||
terraformClient, err := terraform.NewClient(
|
||||
terraformClient, err := tfclient.NewClient(
|
||||
logger,
|
||||
distribution,
|
||||
binDir,
|
||||
@@ -449,7 +448,7 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) {
|
||||
// are, then we don't error out because we don't have/want terraform
|
||||
// installed on our CI system where the unit tests run.
|
||||
if err != nil && flag.Lookup("test.v") == nil {
|
||||
return nil, errors.Wrap(err, fmt.Sprintf("initializing %s", userConfig.TFDistribution))
|
||||
return nil, errors.Wrap(err, fmt.Sprintf("initializing %s", userConfig.DefaultTFDistribution))
|
||||
}
|
||||
markdownRenderer := events.NewMarkdownRenderer(
|
||||
gitlabClient.SupportsCommonMark(),
|
||||
@@ -586,10 +585,12 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) {
|
||||
userConfig.ExecutableName,
|
||||
allowCommands,
|
||||
)
|
||||
defaultTfDistribution := terraformClient.DefaultDistribution()
|
||||
defaultTfVersion := terraformClient.DefaultVersion()
|
||||
pendingPlanFinder := &events.DefaultPendingPlanFinder{}
|
||||
runStepRunner := &runtime.RunStepRunner{
|
||||
TerraformExecutor: terraformClient,
|
||||
DefaultTFDistribution: defaultTfDistribution,
|
||||
DefaultTFVersion: defaultTfVersion,
|
||||
TerraformBinDir: terraformClient.TerraformBinDir(),
|
||||
ProjectCmdOutputHandler: projectCmdOutputHandler,
|
||||
@@ -648,13 +649,14 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) {
|
||||
terraformClient,
|
||||
)
|
||||
|
||||
showStepRunner, err := runtime.NewShowStepRunner(terraformClient, defaultTfVersion)
|
||||
showStepRunner, err := runtime.NewShowStepRunner(terraformClient, defaultTfDistribution, defaultTfVersion)
|
||||
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "initializing show step runner")
|
||||
}
|
||||
|
||||
policyCheckStepRunner, err := runtime.NewPolicyCheckStepRunner(
|
||||
defaultTfDistribution,
|
||||
defaultTfVersion,
|
||||
policy.NewConfTestExecutorWorkflow(logger, binDir, &policy.ConfTestGoGetterVersionDownloader{}),
|
||||
)
|
||||
@@ -672,17 +674,19 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) {
|
||||
Locker: projectLocker,
|
||||
LockURLGenerator: router,
|
||||
InitStepRunner: &runtime.InitStepRunner{
|
||||
TerraformExecutor: terraformClient,
|
||||
DefaultTFVersion: defaultTfVersion,
|
||||
TerraformExecutor: terraformClient,
|
||||
DefaultTFDistribution: defaultTfDistribution,
|
||||
DefaultTFVersion: defaultTfVersion,
|
||||
},
|
||||
PlanStepRunner: runtime.NewPlanStepRunner(terraformClient, defaultTfVersion, commitStatusUpdater, terraformClient),
|
||||
PlanStepRunner: runtime.NewPlanStepRunner(terraformClient, defaultTfDistribution, defaultTfVersion, commitStatusUpdater, terraformClient),
|
||||
ShowStepRunner: showStepRunner,
|
||||
PolicyCheckStepRunner: policyCheckStepRunner,
|
||||
ApplyStepRunner: &runtime.ApplyStepRunner{
|
||||
TerraformExecutor: terraformClient,
|
||||
DefaultTFVersion: defaultTfVersion,
|
||||
CommitStatusUpdater: commitStatusUpdater,
|
||||
AsyncTFExec: terraformClient,
|
||||
TerraformExecutor: terraformClient,
|
||||
DefaultTFDistribution: defaultTfDistribution,
|
||||
DefaultTFVersion: defaultTfVersion,
|
||||
CommitStatusUpdater: commitStatusUpdater,
|
||||
AsyncTFExec: terraformClient,
|
||||
},
|
||||
RunStepRunner: runStepRunner,
|
||||
EnvStepRunner: &runtime.EnvStepRunner{
|
||||
@@ -695,8 +699,8 @@ func NewServer(userConfig UserConfig, config Config) (*Server, error) {
|
||||
TerraformExecutor: terraformClient,
|
||||
DefaultTFVersion: defaultTfVersion,
|
||||
},
|
||||
ImportStepRunner: runtime.NewImportStepRunner(terraformClient, defaultTfVersion),
|
||||
StateRmStepRunner: runtime.NewStateRmStepRunner(terraformClient, defaultTfVersion),
|
||||
ImportStepRunner: runtime.NewImportStepRunner(terraformClient, defaultTfDistribution, defaultTfVersion),
|
||||
StateRmStepRunner: runtime.NewStateRmStepRunner(terraformClient, defaultTfDistribution, defaultTfVersion),
|
||||
WorkingDir: workingDir,
|
||||
Webhooks: webhooksManager,
|
||||
WorkingDirLocker: workingDirLocker,
|
||||
|
||||
@@ -109,7 +109,7 @@ type UserConfig struct {
|
||||
SSLCertFile string `mapstructure:"ssl-cert-file"`
|
||||
SSLKeyFile string `mapstructure:"ssl-key-file"`
|
||||
RestrictFileList bool `mapstructure:"restrict-file-list"`
|
||||
TFDistribution string `mapstructure:"tf-distribution"`
|
||||
TFDistribution string `mapstructure:"tf-distribution"` // deprecated in favor of DefaultTFDistribution
|
||||
TFDownload bool `mapstructure:"tf-download"`
|
||||
TFDownloadURL string `mapstructure:"tf-download-url"`
|
||||
TFEHostname string `mapstructure:"tfe-hostname"`
|
||||
@@ -117,6 +117,7 @@ type UserConfig struct {
|
||||
TFEToken string `mapstructure:"tfe-token"`
|
||||
VarFileAllowlist string `mapstructure:"var-file-allowlist"`
|
||||
VCSStatusName string `mapstructure:"vcs-status-name"`
|
||||
DefaultTFDistribution string `mapstructure:"default-tf-distribution"`
|
||||
DefaultTFVersion string `mapstructure:"default-tf-version"`
|
||||
Webhooks []WebhookConfig `mapstructure:"webhooks" flag:"false"`
|
||||
WebBasicAuth bool `mapstructure:"web-basic-auth"`
|
||||
|
||||
Reference in New Issue
Block a user