feat: Add an output option to filter output for custom run steps (#3518)

* feat: Add an `output` option to filter output for custom run steps
This commit is contained in:
Yunchi Luo
2023-06-30 10:00:31 -04:00
committed by GitHub
parent 5998e9e741
commit a6161c9926
12 changed files with 175 additions and 60 deletions

View File

@@ -142,7 +142,11 @@ workflows:
myworkflow:
plan:
steps:
- run: terraform init -input=false
# If you want to hide command output from Atlantis's PR comment, use
# the output option on the run step's expanded form.
- run:
command: terraform init -input=false
output: hide
# If you're using workspaces you need to select the workspace using the
# $WORKSPACE environment variable.
@@ -264,7 +268,9 @@ workflows:
# Reduce Terraform suggestion output
name: TF_IN_AUTOMATION
value: 'true'
- run: terragrunt plan -input=false -out=$PLANFILE
- run:
command: terragrunt plan -input=false -out=$PLANFILE
output: strip_refreshing
- run: terragrunt show -json $PLANFILE > $SHOWFILE
apply:
steps:
@@ -297,7 +303,9 @@ workflows:
# Reduce Terraform suggestion output
name: TF_IN_AUTOMATION
value: 'true'
- run: terragrunt plan -out $PLANFILE
- run:
command: terragrunt plan -input=false -out=$PLANFILE
output: strip_refreshing
apply:
steps:
- env:
@@ -451,14 +459,28 @@ A map from string to `extra_args` for a built-in command with extra arguments.
| init/plan/apply/import/state_rm | map[`extra_args` -> array[string]] | none | no | Use a built-in command and append `extra_args`. Only `init`, `plan`, `apply`, `import` and `state_rm` are supported as keys and only `extra_args` is supported as a value |
#### Custom `run` Command
Or a custom command
A custom command can be written in 2 ways
Compact:
```yaml
- run: custom-command
- run: custom-command arg1 arg2
```
| Key | Type | Default | Required | Description |
|-----|--------|---------|----------|----------------------|
| run | string | none | no | Run a custom command |
Full
```yaml
- run:
command: custom-command arg1 arg2
output: show
```
| Key | Type | Default | Required | Description |
|-----|--------------------------------------------------------------|---------|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| run | map[string -> string] | none | no | Run a custom command |
| run.command | string | none | yes | Shell command to run |
| run.output | string | "show" | no | How to post-process the output of this command when posted in the PR comment. The options are<br/>* `show` - preserve the full output<br/>* `hide` - hide output from comment (still visible in the real-time streaming output)<br/> * `strip_refreshing` - hide all output up until and including the last line containing "Refreshing...". This matches the behavior of the built-in `plan` command |
::: tip Notes
* `run` steps in the main `workflow` are executed with the following environment variables:
note: these variables are not available to `pre` or `post` workflows
@@ -513,9 +535,12 @@ as the environment variable value.
name: ENV_NAME_2
command: 'echo "dynamic-value-$(date)"'
```
| Key | Type | Default | Required | Description |
|-----------------|------------------------------------|---------|----------|-----------------------------------------------------------------------------------------------------------------------------------------------------|
| env | map[`name` -> string, `value` -> string, `command` -> string] | none | no | Set environment variables for subsequent steps |
| Key | Type | Default | Required | Description |
|-----------------|-----------------------|---------|----------|-----------------------------------------------------------------------------------------------------------------|
| env | map[string -> string] | none | no | Set environment variables for subsequent steps |
| env.name | string | none | yes | Name of the environment variable |
| env.value | string | none | no | Set the value of the environment variable to a hard-coded string. Cannot be set at the same time as `command` |
| env.command | string | none | no | Set the value of the environment variable to the output of a command. Cannot be set at the same time as `value` |
::: tip Notes
* `env` `command`'s can use any of the built-in environment variables available

View File

@@ -72,6 +72,9 @@ workflows:
plan:
steps:
- run: my-custom-command arg1 arg2
- run:
command: my-custom-command arg1 arg2
output: hide
- init
- plan:
extra_args: ["-lock", "false"]

View File

@@ -16,6 +16,7 @@ const (
NameArgKey = "name"
CommandArgKey = "command"
ValueArgKey = "value"
OutputArgKey = "output"
RunStepName = "run"
PlanStepName = "plan"
ShowStepName = "show"
@@ -34,15 +35,18 @@ const (
// - plan
// - policy_check
//
// 2. A map for an env step with name and command or value
// 2. A map for an env step with name and command or value, or a run step with a command and output config
// - env:
// name: test
// command: echo 312
// value: value
// name: test
// command: echo 312
// value: value
// - run:
// command: my custom command
// output: hide
//
// 3. A map for a built-in command and extra_args:
// - plan:
// extra_args: [-var-file=staging.tfvars]
// extra_args: [-var-file=staging.tfvars]
//
// 4. A map for a custom run command:
// - run: my custom command
@@ -53,8 +57,8 @@ type Step struct {
// Key will be set in case #1 and #3 above to the key. In case #2, there
// could be multiple keys (since the element is a map) so we don't set Key.
Key *string
// Env will be set in case #2 above.
Env map[string]map[string]string
// EnvOrRun will be set in case #2 above.
EnvOrRun map[string]map[string]string
// Map will be set in case #3 above.
Map map[string]map[string][]string
// StringVal will be set in case #4 above.
@@ -142,7 +146,7 @@ func (s Step) Validate() error {
return nil
}
envStep := func(value interface{}) error {
envOrRunStep := func(value interface{}) error {
elem := value.(map[string]map[string]string)
var keys []string
for k := range elem {
@@ -155,10 +159,15 @@ func (s Step) Validate() error {
return fmt.Errorf("step element can only contain a single key, found %d: %s",
len(keys), strings.Join(keys, ","))
}
for stepName, args := range elem {
if stepName != EnvStepName {
return fmt.Errorf("%q is not a valid step type", stepName)
}
if len(keys) == 0 {
return fmt.Errorf("step element must contain at least 1 key")
}
stepName := keys[0]
args := elem[keys[0]]
switch stepName {
case EnvStepName:
var argKeys []string
for k := range args {
argKeys = append(argKeys, k)
@@ -183,7 +192,35 @@ func (s Step) Validate() error {
return fmt.Errorf("env steps only support one of the %q or %q keys, found both",
ValueArgKey, CommandArgKey)
}
case RunStepName:
argsCopy := make(map[string]string)
for k, v := range args {
argsCopy[k] = v
}
args = argsCopy
if _, ok := args[CommandArgKey]; !ok {
return fmt.Errorf("run step must have a %q key set", CommandArgKey)
}
delete(args, CommandArgKey)
if v, ok := args[OutputArgKey]; ok {
if !(v == valid.PostProcessRunOutputShow || v == valid.PostProcessRunOutputHide || v == valid.PostProcessRunOutputStripRefreshing) {
return fmt.Errorf("run step %q option must be one of %q, %q, or %q", OutputArgKey, valid.PostProcessRunOutputShow, valid.PostProcessRunOutputHide, valid.PostProcessRunOutputStripRefreshing)
}
}
delete(args, OutputArgKey)
if len(args) > 0 {
var argKeys []string
for k := range args {
argKeys = append(argKeys, k)
}
// Sort so tests can be deterministic.
sort.Strings(argKeys)
return fmt.Errorf("run steps only support keys %q, %q and %q, found extra keys %q", RunStepName, CommandArgKey, OutputArgKey, strings.Join(argKeys, ","))
}
default:
return fmt.Errorf("%q is not a valid step type", stepName)
}
return nil
}
@@ -214,8 +251,8 @@ func (s Step) Validate() error {
if len(s.Map) > 0 {
return validation.Validate(s.Map, validation.By(extraArgs))
}
if len(s.Env) > 0 {
return validation.Validate(s.Env, validation.By(envStep))
if len(s.EnvOrRun) > 0 {
return validation.Validate(s.EnvOrRun, validation.By(envOrRunStep))
}
if len(s.StringVal) > 0 {
return validation.Validate(s.StringVal, validation.By(runStep))
@@ -232,16 +269,21 @@ func (s Step) ToValid() valid.Step {
}
// This will trigger in case #2 (see Step docs).
if len(s.Env) > 0 {
if len(s.EnvOrRun) > 0 {
// After validation we assume there's only one key and it's a valid
// step name so we just use the first one.
for stepName, stepArgs := range s.Env {
return valid.Step{
for stepName, stepArgs := range s.EnvOrRun {
step := valid.Step{
StepName: stepName,
EnvVarName: stepArgs[NameArgKey],
RunCommand: stepArgs[CommandArgKey],
EnvVarValue: stepArgs[ValueArgKey],
Output: valid.PostProcessRunOutputOption(stepArgs[OutputArgKey]),
}
if step.StepName == RunStepName && step.Output == "" {
step.Output = valid.PostProcessRunOutputShow
}
return step
}
}
@@ -314,7 +356,7 @@ func (s *Step) unmarshalGeneric(unmarshal func(interface{}) error) error {
var envStep map[string]map[string]string
err = unmarshal(&envStep)
if err == nil {
s.Env = envStep
s.EnvOrRun = envStep
return nil
}
@@ -337,8 +379,8 @@ func (s Step) marshalGeneric() (interface{}, error) {
return s.StringVal, nil
} else if len(s.Map) != 0 {
return s.Map, nil
} else if len(s.Env) != 0 {
return s.Env, nil
} else if len(s.EnvOrRun) != 0 {
return s.EnvOrRun, nil
} else if s.Key != nil {
return s.Key, nil
}

View File

@@ -81,7 +81,7 @@ env:
value: direct_value
name: test`,
exp: raw.Step{
Env: EnvType{
EnvOrRun: EnvOrRunType{
"env": {
"value": "direct_value",
"name": "test",
@@ -96,7 +96,7 @@ env:
command: echo 123
name: test`,
exp: raw.Step{
Env: EnvType{
EnvOrRun: EnvOrRunType{
"env": {
"command": "echo 123",
"name": "test",
@@ -137,7 +137,7 @@ key: value`,
Key: nil,
Map: nil,
StringVal: nil,
Env: nil,
EnvOrRun: nil,
},
},
@@ -227,7 +227,7 @@ func TestStep_Validate(t *testing.T) {
{
description: "env",
input: raw.Step{
Env: EnvType{
EnvOrRun: EnvOrRunType{
"env": {
"name": "test",
"command": "echo 123",
@@ -283,7 +283,7 @@ func TestStep_Validate(t *testing.T) {
{
description: "multiple keys in env",
input: raw.Step{
Env: EnvType{
EnvOrRun: EnvOrRunType{
"key1": nil,
"key2": nil,
},
@@ -312,7 +312,7 @@ func TestStep_Validate(t *testing.T) {
{
description: "invalid key in env",
input: raw.Step{
Env: EnvType{
EnvOrRun: EnvOrRunType{
"invalid": nil,
},
},
@@ -353,7 +353,7 @@ func TestStep_Validate(t *testing.T) {
{
description: "env step with no name key set",
input: raw.Step{
Env: EnvType{
EnvOrRun: EnvOrRunType{
"env": {
"value": "value",
},
@@ -364,7 +364,7 @@ func TestStep_Validate(t *testing.T) {
{
description: "env step with invalid key",
input: raw.Step{
Env: EnvType{
EnvOrRun: EnvOrRunType{
"env": {
"abc": "",
"invalid2": "",
@@ -376,7 +376,7 @@ func TestStep_Validate(t *testing.T) {
{
description: "env step with both command and value set",
input: raw.Step{
Env: EnvType{
EnvOrRun: EnvOrRunType{
"env": {
"name": "name",
"command": "command",
@@ -454,7 +454,7 @@ func TestStep_ToValid(t *testing.T) {
{
description: "env step",
input: raw.Step{
Env: EnvType{
EnvOrRun: EnvOrRunType{
"env": {
"name": "test",
"command": "echo 123",
@@ -558,6 +558,22 @@ func TestStep_ToValid(t *testing.T) {
RunCommand: "my 'run command'",
},
},
{
description: "run step with output",
input: raw.Step{
EnvOrRun: EnvOrRunType{
"run": {
"command": "my 'run command'",
"output": "hide",
},
},
},
exp: valid.Step{
StepName: "run",
RunCommand: "my 'run command'",
Output: "hide",
},
},
}
for _, c := range cases {
t.Run(c.description, func(t *testing.T) {
@@ -567,4 +583,4 @@ func TestStep_ToValid(t *testing.T) {
}
type MapType map[string]map[string][]string
type EnvType map[string]map[string]string
type EnvOrRunType map[string]map[string]string

View File

@@ -150,6 +150,15 @@ type Autoplan struct {
Enabled bool
}
// PostProcessRunOutputOption is an enum of options for post-processing RunCommand output
type PostProcessRunOutputOption string
const (
PostProcessRunOutputShow = "show"
PostProcessRunOutputHide = "hide"
PostProcessRunOutputStripRefreshing = "strip_refreshing"
)
type Stage struct {
Steps []Step
}
@@ -160,6 +169,8 @@ type Step struct {
// RunCommand is either a custom run step or the command to run
// during an env step to populate the environment variable dynamically.
RunCommand string
// Output is option for post-processing a RunCommand output
Output PostProcessRunOutputOption
// EnvVarName is the name of the
// environment variable that should be set by this step.
EnvVarName string

View File

@@ -3,6 +3,7 @@ package runtime
import (
"strings"
"github.com/runatlantis/atlantis/server/core/config/valid"
"github.com/runatlantis/atlantis/server/events/command"
)
@@ -20,7 +21,7 @@ func (r *EnvStepRunner) Run(ctx command.ProjectContext, command string, value st
}
// Pass `false` for streamOutput because this isn't interesting to the user reading the build logs
// in the web UI.
res, err := r.RunStepRunner.Run(ctx, command, path, envs, false)
res, err := r.RunStepRunner.Run(ctx, command, path, envs, false, valid.PostProcessRunOutputShow)
// Trim newline from res to support running `echo env_value` which has
// a newline. We don't recommend users run echo -n env_value to remove the
// newline because -n doesn't work in the sh shell which is what we use

View File

@@ -4,6 +4,7 @@ import (
"fmt"
"strings"
"github.com/runatlantis/atlantis/server/core/config/valid"
"github.com/runatlantis/atlantis/server/events/command"
)
@@ -15,7 +16,7 @@ type MultiEnvStepRunner struct {
// Run runs the multienv step command.
// The command must return a json string containing the array of name-value pairs that are being added as extra environment variables
func (r *MultiEnvStepRunner) Run(ctx command.ProjectContext, command string, path string, envs map[string]string) (string, error) {
res, err := r.RunStepRunner.Run(ctx, command, path, envs, false)
res, err := r.RunStepRunner.Run(ctx, command, path, envs, false, valid.PostProcessRunOutputShow)
if err == nil {
if len(res) > 0 {
var sb strings.Builder

View File

@@ -7,6 +7,7 @@ import (
"strings"
"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/events/command"
"github.com/runatlantis/atlantis/server/jobs"
@@ -21,7 +22,7 @@ type RunStepRunner struct {
ProjectCmdOutputHandler jobs.ProjectCommandOutputHandler
}
func (r *RunStepRunner) Run(ctx command.ProjectContext, command string, path string, envs map[string]string, streamOutput bool) (string, error) {
func (r *RunStepRunner) Run(ctx command.ProjectContext, command string, path string, envs map[string]string, streamOutput bool, postProcessOutput valid.PostProcessRunOutputOption) (string, error) {
tfVersion := r.DefaultTFVersion
if ctx.TerraformVersion != nil {
tfVersion = ctx.TerraformVersion
@@ -75,5 +76,15 @@ func (r *RunStepRunner) Run(ctx command.ProjectContext, command string, path str
ctx.Log.Debug("error: %s", err)
return "", err
}
return output, nil
switch postProcessOutput {
case valid.PostProcessRunOutputHide:
return "", nil
case valid.PostProcessRunOutputStripRefreshing:
return StripRefreshingFromPlanOutput(output, tfVersion), nil
case valid.PostProcessRunOutputShow:
return output, nil
default:
return output, nil
}
}

View File

@@ -8,6 +8,7 @@ import (
"github.com/hashicorp/go-version"
. "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/events/command"
@@ -144,7 +145,7 @@ func TestRunStepRunner_Run(t *testing.T) {
ProjectName: c.ProjectName,
EscapedCommentArgs: []string{"-target=resource1", "-target=resource2"},
}
out, err := r.Run(ctx, c.Command, tmpDir, map[string]string{"test": "var"}, true)
out, err := r.Run(ctx, c.Command, tmpDir, map[string]string{"test": "var"}, true, valid.PostProcessRunOutputShow)
if c.ExpErr != "" {
ErrContains(t, c.ExpErr, err)
return

View File

@@ -5,6 +5,7 @@ package mocks
import (
pegomock "github.com/petergtz/pegomock/v4"
valid "github.com/runatlantis/atlantis/server/core/config/valid"
command "github.com/runatlantis/atlantis/server/events/command"
"reflect"
"time"
@@ -25,11 +26,11 @@ func NewMockCustomStepRunner(options ...pegomock.Option) *MockCustomStepRunner {
func (mock *MockCustomStepRunner) SetFailHandler(fh pegomock.FailHandler) { mock.fail = fh }
func (mock *MockCustomStepRunner) FailHandler() pegomock.FailHandler { return mock.fail }
func (mock *MockCustomStepRunner) Run(ctx command.ProjectContext, cmd string, path string, envs map[string]string, streamOutput bool) (string, error) {
func (mock *MockCustomStepRunner) Run(ctx command.ProjectContext, cmd string, path string, envs map[string]string, streamOutput bool, postProcessOutput valid.PostProcessRunOutputOption) (string, error) {
if mock == nil {
panic("mock must not be nil. Use myMock := NewMockCustomStepRunner().")
}
params := []pegomock.Param{ctx, cmd, path, envs, streamOutput}
params := []pegomock.Param{ctx, cmd, path, envs, streamOutput, postProcessOutput}
result := pegomock.GetGenericMockFrom(mock).Invoke("Run", params, []reflect.Type{reflect.TypeOf((*string)(nil)).Elem(), reflect.TypeOf((*error)(nil)).Elem()})
var ret0 string
var ret1 error
@@ -81,8 +82,8 @@ type VerifierMockCustomStepRunner struct {
timeout time.Duration
}
func (verifier *VerifierMockCustomStepRunner) Run(ctx command.ProjectContext, cmd string, path string, envs map[string]string, streamOutput bool) *MockCustomStepRunner_Run_OngoingVerification {
params := []pegomock.Param{ctx, cmd, path, envs, streamOutput}
func (verifier *VerifierMockCustomStepRunner) Run(ctx command.ProjectContext, cmd string, path string, envs map[string]string, streamOutput bool, postProcessOutput valid.PostProcessRunOutputOption) *MockCustomStepRunner_Run_OngoingVerification {
params := []pegomock.Param{ctx, cmd, path, envs, streamOutput, postProcessOutput}
methodInvocations := pegomock.GetGenericMockFrom(verifier.mock).Verify(verifier.inOrderContext, verifier.invocationCountMatcher, "Run", params, verifier.timeout)
return &MockCustomStepRunner_Run_OngoingVerification{mock: verifier.mock, methodInvocations: methodInvocations}
}
@@ -92,12 +93,12 @@ type MockCustomStepRunner_Run_OngoingVerification struct {
methodInvocations []pegomock.MethodInvocation
}
func (c *MockCustomStepRunner_Run_OngoingVerification) GetCapturedArguments() (command.ProjectContext, string, string, map[string]string, bool) {
ctx, cmd, path, envs, streamOutput := c.GetAllCapturedArguments()
return ctx[len(ctx)-1], cmd[len(cmd)-1], path[len(path)-1], envs[len(envs)-1], streamOutput[len(streamOutput)-1]
func (c *MockCustomStepRunner_Run_OngoingVerification) GetCapturedArguments() (command.ProjectContext, string, string, map[string]string, bool, valid.PostProcessRunOutputOption) {
ctx, cmd, path, envs, streamOutput, postProcessOutput := c.GetAllCapturedArguments()
return ctx[len(ctx)-1], cmd[len(cmd)-1], path[len(path)-1], envs[len(envs)-1], streamOutput[len(streamOutput)-1], postProcessOutput[len(postProcessOutput)-1]
}
func (c *MockCustomStepRunner_Run_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext, _param1 []string, _param2 []string, _param3 []map[string]string, _param4 []bool) {
func (c *MockCustomStepRunner_Run_OngoingVerification) GetAllCapturedArguments() (_param0 []command.ProjectContext, _param1 []string, _param2 []string, _param3 []map[string]string, _param4 []bool, _param5 []valid.PostProcessRunOutputOption) {
params := pegomock.GetGenericMockFrom(c.mock).GetInvocationParams(c.methodInvocations)
if len(params) > 0 {
_param0 = make([]command.ProjectContext, len(c.methodInvocations))
@@ -120,6 +121,10 @@ func (c *MockCustomStepRunner_Run_OngoingVerification) GetAllCapturedArguments()
for u, param := range params[4] {
_param4[u] = param.(bool)
}
_param5 = make([]valid.PostProcessRunOutputOption, len(c.methodInvocations))
for u, param := range params[5] {
_param5[u] = param.(valid.PostProcessRunOutputOption)
}
}
return
}

View File

@@ -14,13 +14,12 @@
package events
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"strings"
"encoding/json"
"github.com/hashicorp/go-multierror"
"github.com/pkg/errors"
"github.com/runatlantis/atlantis/server/core/config/valid"
@@ -66,7 +65,7 @@ type StepRunner interface {
// CustomStepRunner runs custom run steps.
type CustomStepRunner interface {
// Run cmd in path.
Run(ctx command.ProjectContext, cmd string, path string, envs map[string]string, streamOutput bool) (string, error)
Run(ctx command.ProjectContext, cmd string, path string, envs map[string]string, streamOutput bool, postProcessOutput valid.PostProcessRunOutputOption) (string, error)
}
//go:generate pegomock generate --package mocks -o mocks/mock_env_step_runner.go EnvStepRunner
@@ -764,7 +763,7 @@ func (p *DefaultProjectCommandRunner) runSteps(steps []valid.Step, ctx command.P
case "state_rm":
out, err = p.StateRmStepRunner.Run(ctx, step.ExtraArgs, absPath, envs)
case "run":
out, err = p.RunStepRunner.Run(ctx, step.RunCommand, absPath, envs, true)
out, err = p.RunStepRunner.Run(ctx, step.RunCommand, absPath, envs, true, step.Output)
case "env":
out, err = p.EnvStepRunner.Run(ctx, step.RunCommand, step.EnvVarValue, absPath, envs)
envs[step.EnvVarName] = out

View File

@@ -112,7 +112,7 @@ func TestDefaultProjectCommandRunner_Plan(t *testing.T) {
When(mockInit.Run(ctx, nil, repoDir, expEnvs)).ThenReturn("init", nil)
When(mockPlan.Run(ctx, nil, repoDir, expEnvs)).ThenReturn("plan", nil)
When(mockApply.Run(ctx, nil, repoDir, expEnvs)).ThenReturn("apply", nil)
When(mockRun.Run(ctx, "", repoDir, expEnvs, true)).ThenReturn("run", nil)
When(mockRun.Run(ctx, "", repoDir, expEnvs, true, "")).ThenReturn("run", nil)
res := runner.Plan(ctx)
Assert(t, res.PlanSuccess != nil, "exp plan success")
@@ -128,7 +128,7 @@ func TestDefaultProjectCommandRunner_Plan(t *testing.T) {
case "apply":
mockApply.VerifyWasCalledOnce().Run(ctx, nil, repoDir, expEnvs)
case "run":
mockRun.VerifyWasCalledOnce().Run(ctx, "", repoDir, expEnvs, true)
mockRun.VerifyWasCalledOnce().Run(ctx, "", repoDir, expEnvs, true, "")
}
}
}
@@ -457,7 +457,7 @@ func TestDefaultProjectCommandRunner_Apply(t *testing.T) {
When(mockInit.Run(ctx, nil, repoDir, expEnvs)).ThenReturn("init", nil)
When(mockPlan.Run(ctx, nil, repoDir, expEnvs)).ThenReturn("plan", nil)
When(mockApply.Run(ctx, nil, repoDir, expEnvs)).ThenReturn("apply", nil)
When(mockRun.Run(ctx, "", repoDir, expEnvs, true)).ThenReturn("run", nil)
When(mockRun.Run(ctx, "", repoDir, expEnvs, true, "")).ThenReturn("run", nil)
When(mockEnv.Run(ctx, "", "value", repoDir, make(map[string]string))).ThenReturn("value", nil)
res := runner.Apply(ctx)
@@ -473,7 +473,7 @@ func TestDefaultProjectCommandRunner_Apply(t *testing.T) {
case "apply":
mockApply.VerifyWasCalledOnce().Run(ctx, nil, repoDir, expEnvs)
case "run":
mockRun.VerifyWasCalledOnce().Run(ctx, "", repoDir, expEnvs, true)
mockRun.VerifyWasCalledOnce().Run(ctx, "", repoDir, expEnvs, true, "")
case "env":
mockEnv.VerifyWasCalledOnce().Run(ctx, "", "value", repoDir, expEnvs)
}