diff --git a/internal/controller/promotions/promotions.go b/internal/controller/promotions/promotions.go index e82a30211..022328cf9 100644 --- a/internal/controller/promotions/promotions.go +++ b/internal/controller/promotions/promotions.go @@ -471,7 +471,7 @@ func (r *reconciler) promote( Kind: step.Uses, Alias: step.As, Retry: step.Retry, - Inputs: step.Inputs, + Vars: step.Vars, Config: step.Config.Raw, } } diff --git a/internal/directives/promotions.go b/internal/directives/promotions.go index f14caac46..255016047 100644 --- a/internal/directives/promotions.go +++ b/internal/directives/promotions.go @@ -96,8 +96,9 @@ type PromotionStep struct { Alias string // Retry is the retry configuration for the PromotionStep. Retry *kargoapi.PromotionStepRetry - // Inputs is a list of inputs to be made available to the Config of this step. - Inputs []kargoapi.PromotionStepInput + // Vars is a list of variables definitions that can be used by the + // PromotionStep. + Vars []kargoapi.PromotionVariable // Config is an opaque JSON to be passed to the PromotionStepRunner executing // this step. Config []byte @@ -146,8 +147,6 @@ func (s *PromotionStep) GetConfig( return nil, err } - inputs := s.GetInputs() - evaledCfgJSON, err := expressions.EvaluateJSONTemplate( s.Config, map[string]any{ @@ -157,7 +156,6 @@ func (s *PromotionStep) GetConfig( "stage": promoCtx.Stage, }, "vars": vars, - "inputs": inputs, "secrets": promoCtx.Secrets, "outputs": state, }, @@ -196,10 +194,18 @@ func (s *PromotionStep) GetConfig( // GetVars returns the variables defined in the PromotionStep. The variables are // evaluated in the context of the provided PromotionContext. func (s *PromotionStep) GetVars(promoCtx PromotionContext) (map[string]any, error) { - vars := make(map[string]any, len(promoCtx.Vars)) + var rawVars = make(map[string]string, len(promoCtx.Vars)) for _, v := range promoCtx.Vars { + rawVars[v.Name] = v.Value + } + for _, v := range s.Vars { + rawVars[v.Name] = v.Value + } + + vars := make(map[string]any, len(rawVars)) + for k, v := range rawVars { newVar, err := expressions.EvaluateTemplate( - v.Value, + v, map[string]any{ "ctx": map[string]any{ "project": promoCtx.Project, @@ -210,22 +216,13 @@ func (s *PromotionStep) GetVars(promoCtx PromotionContext) (map[string]any, erro }, ) if err != nil { - return nil, fmt.Errorf("error pre-processing promotion variable %q: %w", v.Name, err) + return nil, fmt.Errorf("error pre-processing promotion variable %q: %w", k, err) } - vars[v.Name] = newVar + vars[k] = newVar } return vars, nil } -// GetInputs returns the inputs of the PromotionStep as a map. -func (s *PromotionStep) GetInputs() map[string]any { - inputs := make(map[string]any, len(s.Inputs)) - for _, i := range s.Inputs { - inputs[i.Name] = i.Value - } - return inputs -} - // PromotionResult is the result of a user-defined promotion process executed by // the Engine. It aggregates the status and output of the individual // PromotionStepResults returned by the PromotionStepRunner executing each diff --git a/internal/kargo/promotion_builder.go b/internal/kargo/promotion_builder.go index 2deb446aa..ff3386fc4 100644 --- a/internal/kargo/promotion_builder.go +++ b/internal/kargo/promotion_builder.go @@ -7,10 +7,8 @@ import ( "strings" "github.com/oklog/ulid/v2" - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/client" - "sigs.k8s.io/yaml" kargoapi "github.com/akuity/kargo/api/v1alpha1" "github.com/akuity/kargo/internal/api/user" @@ -103,7 +101,13 @@ func (b *PromotionBuilder) buildSteps(ctx context.Context, stage kargoapi.Stage) switch { case step.Task != nil: alias := step.GetAlias(i) - taskSteps, err := b.inflateTaskSteps(ctx, stage.Namespace, alias, step) + taskSteps, err := b.inflateTaskSteps( + ctx, + stage.Namespace, + alias, + stage.Spec.PromotionTemplate.Spec.Vars, + step, + ) if err != nil { return nil, fmt.Errorf("inflate tasks steps for task %q (%q): %w", step.Task.Name, alias, err) } @@ -121,6 +125,7 @@ func (b *PromotionBuilder) buildSteps(ctx context.Context, stage kargoapi.Stage) func (b *PromotionBuilder) inflateTaskSteps( ctx context.Context, project, taskAlias string, + promoVars []kargoapi.PromotionVariable, taskStep kargoapi.PromotionStep, ) ([]kargoapi.PromotionStep, error) { task, err := b.getTaskSpec(ctx, project, taskStep.Task) @@ -128,7 +133,7 @@ func (b *PromotionBuilder) inflateTaskSteps( return nil, err } - inputs, err := promotionTaskInputsToStepInputs(task.Inputs, taskStep.Config) + vars, err := promotionTaskVarsToStepVars(task.Vars, promoVars, taskStep.Vars) if err != nil { return nil, err } @@ -142,9 +147,9 @@ func (b *PromotionBuilder) inflateTaskSteps( // the Promotion. step.As = generatePromotionTaskStepAlias(taskAlias, step.GetAlias(i)) - // With the inputs validated and mapped, they are now available to + // With the variables validated and mapped, they are now available to // the Config of the step during the Promotion execution. - step.Inputs = inputs + step.Vars = vars // Append the inflated step to the list of steps. steps = append(steps, *step) @@ -215,42 +220,45 @@ func generatePromotionTaskStepAlias(taskAlias, stepAlias string) string { return fmt.Sprintf("%s%s%s", taskAlias, aliasSeparator, stepAlias) } -// promotionTaskInputsToStepInputs validates the task step config against the task -// inputs, and maps the config to inputs for the inflated steps. -func promotionTaskInputsToStepInputs( - taskInputs []kargoapi.PromotionTaskInput, - stepConfig *apiextensionsv1.JSON, -) ([]kargoapi.PromotionStepInput, error) { - if len(taskInputs) == 0 { +// promotionTaskVarsToStepVars validates the presence of the PromotionTask +// variables and maps them to variables which can be used by the inflated +// PromotionStep. +func promotionTaskVarsToStepVars( + taskVars, promoVars, stepVars []kargoapi.PromotionVariable, +) ([]kargoapi.PromotionVariable, error) { + if len(taskVars) == 0 { return nil, nil } - if stepConfig == nil { - return nil, errors.New("missing step config") + promoVarsMap := make(map[string]kargoapi.PromotionVariable, len(promoVars)) + for _, v := range promoVars { + promoVarsMap[v.Name] = v } - config := make(map[string]any, len(taskInputs)) - if err := yaml.Unmarshal(stepConfig.Raw, &config); err != nil { - return nil, fmt.Errorf("unmarshal step config: %w", err) + stepVarsMap := make(map[string]kargoapi.PromotionVariable, len(stepVars)) + for _, v := range stepVars { + stepVarsMap[v.Name] = v } - inputs := make([]kargoapi.PromotionStepInput, 0, len(taskInputs)) - for _, input := range taskInputs { - iv := input.Default - if cv, exists := config[input.Name]; exists { - strVal, ok := cv.(string) - if !ok { - return nil, fmt.Errorf("input %q must be a string", input.Name) - } - iv = strVal + vars := make([]kargoapi.PromotionVariable, 0, len(taskVars)) + for _, v := range taskVars { + if stepVar, ok := stepVarsMap[v.Name]; ok && stepVar.Value != "" { + vars = append(vars, stepVar) + continue } - if iv == "" { - return nil, fmt.Errorf("missing required input %q", input.Name) + + if promoVar, ok := promoVarsMap[v.Name]; ok && promoVar.Value != "" { + // If the variable is defined in the Promotion, the engine will + // automatically use the value from the Promotion, and we do not + // have to explicitly set it here. + continue } - inputs = append(inputs, kargoapi.PromotionStepInput{ - Name: input.Name, - Value: iv, - }) + + if v.Value == "" { + return nil, fmt.Errorf("missing value for variable %q", v.Name) + } + + vars = append(vars, v) } - return inputs, nil + return vars, nil } diff --git a/internal/kargo/promotion_builder_test.go b/internal/kargo/promotion_builder_test.go index 81411f17d..a4b332d7d 100644 --- a/internal/kargo/promotion_builder_test.go +++ b/internal/kargo/promotion_builder_test.go @@ -8,14 +8,12 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/controller-runtime/pkg/client" "sigs.k8s.io/controller-runtime/pkg/client/fake" "sigs.k8s.io/controller-runtime/pkg/client/interceptor" - "sigs.k8s.io/yaml" kargoapi "github.com/akuity/kargo/api/v1alpha1" "github.com/akuity/kargo/internal/api/user" @@ -144,9 +142,9 @@ func TestPromotionBuilder_Build(t *testing.T) { Task: &kargoapi.PromotionTaskReference{ Name: "test-task", }, - Config: makeJSONObj(t, map[string]any{ - "input1": "value1", - }), + Vars: []kargoapi.PromotionVariable{ + {Name: "input1", Value: "value1"}, + }, }, }, }, @@ -164,7 +162,7 @@ func TestPromotionBuilder_Build(t *testing.T) { Namespace: "test-project", }, Spec: kargoapi.PromotionTaskSpec{ - Inputs: []kargoapi.PromotionTaskInput{ + Vars: []kargoapi.PromotionVariable{ {Name: "input1"}, }, Steps: []kargoapi.PromotionStep{ @@ -187,9 +185,9 @@ func TestPromotionBuilder_Build(t *testing.T) { require.Len(t, promotion.Spec.Steps, 1) assert.Equal(t, "task-step::sub-step", promotion.Spec.Steps[0].As) assert.Equal(t, "other-fake-step", promotion.Spec.Steps[0].Uses) - assert.ElementsMatch(t, []kargoapi.PromotionStepInput{ + assert.ElementsMatch(t, []kargoapi.PromotionVariable{ {Name: "input1", Value: "value1"}, - }, promotion.Spec.Steps[0].Inputs) + }, promotion.Spec.Steps[0].Vars) }, }, } @@ -294,9 +292,9 @@ func TestPromotionBuilder_buildSteps(t *testing.T) { Task: &kargoapi.PromotionTaskReference{ Name: "test-task", }, - Config: makeJSONObj(t, map[string]any{ - "input1": "value1", - }), + Vars: []kargoapi.PromotionVariable{ + {Name: "input1", Value: "value1"}, + }, }, }, }, @@ -310,7 +308,7 @@ func TestPromotionBuilder_buildSteps(t *testing.T) { Namespace: "test-project", }, Spec: kargoapi.PromotionTaskSpec{ - Inputs: []kargoapi.PromotionTaskInput{ + Vars: []kargoapi.PromotionVariable{ {Name: "input1"}, }, Steps: []kargoapi.PromotionStep{ @@ -333,9 +331,9 @@ func TestPromotionBuilder_buildSteps(t *testing.T) { // Check inflated task step assert.Equal(t, "task-step::sub-step", steps[1].As) assert.Equal(t, "other-fake-step", steps[1].Uses) - assert.ElementsMatch(t, []kargoapi.PromotionStepInput{ + assert.ElementsMatch(t, []kargoapi.PromotionVariable{ {Name: "input1", Value: "value1"}, - }, steps[1].Inputs) + }, steps[1].Vars) }, }, { @@ -354,9 +352,9 @@ func TestPromotionBuilder_buildSteps(t *testing.T) { Task: &kargoapi.PromotionTaskReference{ Name: "test-task-1", }, - Config: makeJSONObj(t, map[string]any{ - "input1": "value1", - }), + Vars: []kargoapi.PromotionVariable{ + {Name: "input1", Value: "value1"}, + }, }, { As: "task2", @@ -364,9 +362,9 @@ func TestPromotionBuilder_buildSteps(t *testing.T) { Kind: "ClusterPromotionTask", Name: "test-task-2", }, - Config: makeJSONObj(t, map[string]any{ - "input2": "value2", - }), + Vars: []kargoapi.PromotionVariable{ + {Name: "input2", Value: "value2"}, + }, }, }, }, @@ -380,7 +378,7 @@ func TestPromotionBuilder_buildSteps(t *testing.T) { Namespace: "test-project", }, Spec: kargoapi.PromotionTaskSpec{ - Inputs: []kargoapi.PromotionTaskInput{ + Vars: []kargoapi.PromotionVariable{ {Name: "input1"}, }, Steps: []kargoapi.PromotionStep{ @@ -396,7 +394,7 @@ func TestPromotionBuilder_buildSteps(t *testing.T) { Name: "test-task-2", }, Spec: kargoapi.PromotionTaskSpec{ - Inputs: []kargoapi.PromotionTaskInput{ + Vars: []kargoapi.PromotionVariable{ {Name: "input2"}, }, Steps: []kargoapi.PromotionStep{ @@ -414,15 +412,15 @@ func TestPromotionBuilder_buildSteps(t *testing.T) { assert.Equal(t, "task1::step1", steps[0].As) assert.Equal(t, "fake-step", steps[0].Uses) - assert.ElementsMatch(t, []kargoapi.PromotionStepInput{ + assert.ElementsMatch(t, []kargoapi.PromotionVariable{ {Name: "input1", Value: "value1"}, - }, steps[0].Inputs) + }, steps[0].Vars) assert.Equal(t, "task2::step2", steps[1].As) assert.Equal(t, "other-fake-step", steps[1].Uses) - assert.ElementsMatch(t, []kargoapi.PromotionStepInput{ + assert.ElementsMatch(t, []kargoapi.PromotionVariable{ {Name: "input2", Value: "value2"}, - }, steps[1].Inputs) + }, steps[1].Vars) }, }, } @@ -449,6 +447,7 @@ func TestPromotionBuilder_inflateTaskSteps(t *testing.T) { name string project string taskAlias string + promoVars []kargoapi.PromotionVariable taskStep kargoapi.PromotionStep objects []client.Object assertions func(*testing.T, []kargoapi.PromotionStep, error) @@ -468,14 +467,15 @@ func TestPromotionBuilder_inflateTaskSteps(t *testing.T) { }, }, { - name: "invalid config for task inputs", + name: "invalid config for task variables", project: "test-project", taskStep: kargoapi.PromotionStep{ Task: &kargoapi.PromotionTaskReference{ Name: "test-task", }, - Config: &apiextensionsv1.JSON{Raw: []byte(`{invalid json`)}, + // Missing values + Vars: nil, }, objects: []client.Object{ &kargoapi.PromotionTask{ @@ -484,14 +484,14 @@ func TestPromotionBuilder_inflateTaskSteps(t *testing.T) { Namespace: "test-project", }, Spec: kargoapi.PromotionTaskSpec{ - Inputs: []kargoapi.PromotionTaskInput{ + Vars: []kargoapi.PromotionVariable{ {Name: "input1"}, }, }, }, }, assertions: func(t *testing.T, steps []kargoapi.PromotionStep, err error) { - assert.ErrorContains(t, err, "unmarshal step config") + assert.ErrorContains(t, err, "missing value for variable") assert.Nil(t, steps) }, }, @@ -499,14 +499,17 @@ func TestPromotionBuilder_inflateTaskSteps(t *testing.T) { name: "successful task step inflation", project: "test-project", taskAlias: "task-1", + promoVars: []kargoapi.PromotionVariable{ + {Name: "input3", Value: "value1"}, + }, taskStep: kargoapi.PromotionStep{ Task: &kargoapi.PromotionTaskReference{ Name: "test-task", }, - Config: makeJSONObj(t, map[string]any{ - "input1": "value1", - "input2": "value2", - }), + Vars: []kargoapi.PromotionVariable{ + {Name: "input1", Value: "value1"}, + {Name: "input2", Value: "value2"}, + }, }, objects: []client.Object{ &kargoapi.PromotionTask{ @@ -515,9 +518,10 @@ func TestPromotionBuilder_inflateTaskSteps(t *testing.T) { Namespace: "test-project", }, Spec: kargoapi.PromotionTaskSpec{ - Inputs: []kargoapi.PromotionTaskInput{ + Vars: []kargoapi.PromotionVariable{ {Name: "input1"}, - {Name: "input2", Default: "default2"}, + {Name: "input2", Value: "default2"}, + {Name: "input3"}, }, Steps: []kargoapi.PromotionStep{ { @@ -538,17 +542,17 @@ func TestPromotionBuilder_inflateTaskSteps(t *testing.T) { assert.Equal(t, "task-1::step1", steps[0].As) assert.Equal(t, "fake-step", steps[0].Uses) - assert.ElementsMatch(t, []kargoapi.PromotionStepInput{ + assert.ElementsMatch(t, []kargoapi.PromotionVariable{ {Name: "input1", Value: "value1"}, {Name: "input2", Value: "value2"}, - }, steps[0].Inputs) + }, steps[0].Vars) assert.Equal(t, "task-1::step2", steps[1].As) assert.Equal(t, "other-fake-step", steps[1].Uses) - assert.ElementsMatch(t, []kargoapi.PromotionStepInput{ + assert.ElementsMatch(t, []kargoapi.PromotionVariable{ {Name: "input1", Value: "value1"}, {Name: "input2", Value: "value2"}, - }, steps[1].Inputs) + }, steps[1].Vars) }, }, { @@ -559,9 +563,9 @@ func TestPromotionBuilder_inflateTaskSteps(t *testing.T) { Task: &kargoapi.PromotionTaskReference{ Name: "test-task", }, - Config: makeJSONObj(t, map[string]any{ - "input1": "value1", - }), + Vars: []kargoapi.PromotionVariable{ + {Name: "input1", Value: "value1"}, + }, }, objects: []client.Object{ &kargoapi.PromotionTask{ @@ -570,7 +574,7 @@ func TestPromotionBuilder_inflateTaskSteps(t *testing.T) { Namespace: "test-project", }, Spec: kargoapi.PromotionTaskSpec{ - Inputs: []kargoapi.PromotionTaskInput{ + Vars: []kargoapi.PromotionVariable{ {Name: "input1"}, }, Steps: []kargoapi.PromotionStep{ @@ -601,9 +605,9 @@ func TestPromotionBuilder_inflateTaskSteps(t *testing.T) { Kind: "ClusterPromotionTask", Name: "test-cluster-task", }, - Config: makeJSONObj(t, map[string]any{ - "input1": "value1", - }), + Vars: []kargoapi.PromotionVariable{ + {Name: "input1", Value: "value1"}, + }, }, objects: []client.Object{ &kargoapi.ClusterPromotionTask{ @@ -611,7 +615,7 @@ func TestPromotionBuilder_inflateTaskSteps(t *testing.T) { Name: "test-cluster-task", }, Spec: kargoapi.PromotionTaskSpec{ - Inputs: []kargoapi.PromotionTaskInput{ + Vars: []kargoapi.PromotionVariable{ {Name: "input1"}, }, Steps: []kargoapi.PromotionStep{ @@ -639,7 +643,7 @@ func TestPromotionBuilder_inflateTaskSteps(t *testing.T) { Build() b := NewPromotionBuilder(c) - steps, err := b.inflateTaskSteps(context.Background(), tt.project, tt.taskAlias, tt.taskStep) + steps, err := b.inflateTaskSteps(context.Background(), tt.project, tt.taskAlias, tt.promoVars, tt.taskStep) tt.assertions(t, steps, err) }) } @@ -738,8 +742,8 @@ func TestPromotionBuilder_getTaskSpec(t *testing.T) { Namespace: "test-project", }, Spec: kargoapi.PromotionTaskSpec{ - Inputs: []kargoapi.PromotionTaskInput{ - {Name: "input1", Default: "value1"}, + Vars: []kargoapi.PromotionVariable{ + {Name: "input1", Value: "value1"}, }, }, }, @@ -748,9 +752,9 @@ func TestPromotionBuilder_getTaskSpec(t *testing.T) { require.NoError(t, err) require.NotNil(t, result) - assert.Len(t, result.Inputs, 1) - assert.Equal(t, "input1", result.Inputs[0].Name) - assert.Equal(t, "value1", result.Inputs[0].Default) + assert.Len(t, result.Vars, 1) + assert.Equal(t, "input1", result.Vars[0].Name) + assert.Equal(t, "value1", result.Vars[0].Value) }, }, { @@ -766,8 +770,8 @@ func TestPromotionBuilder_getTaskSpec(t *testing.T) { Name: "test-cluster-task", }, Spec: kargoapi.PromotionTaskSpec{ - Inputs: []kargoapi.PromotionTaskInput{ - {Name: "input1", Default: "value1"}, + Vars: []kargoapi.PromotionVariable{ + {Name: "input1", Value: "value1"}, }, }, }, @@ -776,9 +780,9 @@ func TestPromotionBuilder_getTaskSpec(t *testing.T) { require.NoError(t, err) require.NotNil(t, result) - assert.Len(t, result.Inputs, 1) - assert.Equal(t, "input1", result.Inputs[0].Name) - assert.Equal(t, "value1", result.Inputs[0].Default) + assert.Len(t, result.Vars, 1) + assert.Equal(t, "input1", result.Vars[0].Name) + assert.Equal(t, "value1", result.Vars[0].Value) }, }, { @@ -795,8 +799,8 @@ func TestPromotionBuilder_getTaskSpec(t *testing.T) { Namespace: "test-project", }, Spec: kargoapi.PromotionTaskSpec{ - Inputs: []kargoapi.PromotionTaskInput{ - {Name: "input1", Default: "value1"}, + Vars: []kargoapi.PromotionVariable{ + {Name: "input1", Value: "value1"}, }, }, }, @@ -805,9 +809,9 @@ func TestPromotionBuilder_getTaskSpec(t *testing.T) { require.NoError(t, err) require.NotNil(t, result) - assert.Len(t, result.Inputs, 1) - assert.Equal(t, "input1", result.Inputs[0].Name) - assert.Equal(t, "value1", result.Inputs[0].Default) + assert.Len(t, result.Vars, 1) + assert.Equal(t, "input1", result.Vars[0].Name) + assert.Equal(t, "value1", result.Vars[0].Value) }, }, } @@ -969,110 +973,102 @@ func Test_generatePromotionTaskStepName(t *testing.T) { } } -func Test_promotionTaskInputsToStepInputs(t *testing.T) { +func Test_promotionTaskVarsToStepVars(t *testing.T) { tests := []struct { name string - taskInputs []kargoapi.PromotionTaskInput - config map[string]any - assertions func(t *testing.T, result []kargoapi.PromotionStepInput, err error) + taskVars []kargoapi.PromotionVariable + promoVars []kargoapi.PromotionVariable + stepVars []kargoapi.PromotionVariable + assertions func(t *testing.T, result []kargoapi.PromotionVariable, err error) }{ { - name: "nil inputs returns nil map and no error", - taskInputs: nil, - config: nil, - assertions: func(t *testing.T, result []kargoapi.PromotionStepInput, err error) { + name: "nil inputs returns nil map and no error", + taskVars: nil, + stepVars: nil, + assertions: func(t *testing.T, result []kargoapi.PromotionVariable, err error) { require.NoError(t, err) assert.Nil(t, result) }, }, { - name: "empty inputs returns nil map and no error", - taskInputs: []kargoapi.PromotionTaskInput{}, - config: nil, - assertions: func(t *testing.T, result []kargoapi.PromotionStepInput, err error) { + name: "empty inputs returns nil map and no error", + taskVars: []kargoapi.PromotionVariable{}, + stepVars: nil, + assertions: func(t *testing.T, result []kargoapi.PromotionVariable, err error) { require.NoError(t, err) assert.Nil(t, result) }, }, { - name: "missing config when inputs required returns error", - taskInputs: []kargoapi.PromotionTaskInput{ - {Name: "input1"}, - }, - config: nil, - assertions: func(t *testing.T, result []kargoapi.PromotionStepInput, err error) { - assert.ErrorContains(t, err, "missing step config") - assert.Nil(t, result) - }, - }, - { - name: "non-string input value returns error", - taskInputs: []kargoapi.PromotionTaskInput{ + name: "missing required variable returns error", + taskVars: []kargoapi.PromotionVariable{ {Name: "input1"}, }, - config: map[string]any{ - "input1": 123, // number instead of string + stepVars: []kargoapi.PromotionVariable{ + {Name: "input1", Value: ""}, }, - assertions: func(t *testing.T, result []kargoapi.PromotionStepInput, err error) { - assert.ErrorContains(t, err, "input \"input1\" must be a string") - assert.Nil(t, result) - }, - }, - { - name: "missing required input returns error", - taskInputs: []kargoapi.PromotionTaskInput{ - {Name: "input1"}, - }, - config: map[string]any{ - "input1": "", // empty string is not allowed without default - }, - assertions: func(t *testing.T, result []kargoapi.PromotionStepInput, err error) { - assert.ErrorContains(t, err, "missing required input \"input1\"") + assertions: func(t *testing.T, result []kargoapi.PromotionVariable, err error) { + assert.ErrorContains(t, err, "missing value for variable \"input1\"") assert.Nil(t, result) }, }, { name: "default value used when config value not provided", - taskInputs: []kargoapi.PromotionTaskInput{ - {Name: "input1", Default: "default1"}, + taskVars: []kargoapi.PromotionVariable{ + {Name: "input1", Value: "default1"}, }, - config: map[string]any{}, - assertions: func(t *testing.T, result []kargoapi.PromotionStepInput, err error) { + stepVars: nil, + assertions: func(t *testing.T, result []kargoapi.PromotionVariable, err error) { require.NoError(t, err) - assert.ElementsMatch(t, []kargoapi.PromotionStepInput{ + assert.ElementsMatch(t, []kargoapi.PromotionVariable{ {Name: "input1", Value: "default1"}, }, result) }, }, { - name: "config value overrides default value", - taskInputs: []kargoapi.PromotionTaskInput{ - {Name: "input1", Default: "default1"}, + name: "step value overrides default value", + taskVars: []kargoapi.PromotionVariable{ + {Name: "input1", Value: "default1"}, }, - config: map[string]any{ - "input1": "override1", + stepVars: []kargoapi.PromotionVariable{ + {Name: "input1", Value: "override1"}, }, - assertions: func(t *testing.T, result []kargoapi.PromotionStepInput, err error) { + assertions: func(t *testing.T, result []kargoapi.PromotionVariable, err error) { require.NoError(t, err) - assert.ElementsMatch(t, []kargoapi.PromotionStepInput{ + assert.ElementsMatch(t, []kargoapi.PromotionVariable{ {Name: "input1", Value: "override1"}, }, result) }, }, + { + name: "promotion variable overrides default value", + taskVars: []kargoapi.PromotionVariable{ + {Name: "input1", Value: "default1"}, + }, + promoVars: []kargoapi.PromotionVariable{ + {Name: "input1", Value: "override1"}, + }, + stepVars: nil, + assertions: func(t *testing.T, result []kargoapi.PromotionVariable, err error) { + require.NoError(t, err) + // Variable is set by engine at runtime + assert.Empty(t, result) + }, + }, { name: "multiple inputs processed correctly", - taskInputs: []kargoapi.PromotionTaskInput{ - {Name: "input1", Default: "default1"}, - {Name: "input2", Default: "default2"}, + taskVars: []kargoapi.PromotionVariable{ + {Name: "input1", Value: "default1"}, + {Name: "input2", Value: "default2"}, {Name: "input3"}, }, - config: map[string]any{ - "input1": "override1", - "input3": "value3", + stepVars: []kargoapi.PromotionVariable{ + {Name: "input1", Value: "override1"}, + {Name: "input3", Value: "value3"}, }, - assertions: func(t *testing.T, result []kargoapi.PromotionStepInput, err error) { + assertions: func(t *testing.T, result []kargoapi.PromotionVariable, err error) { require.NoError(t, err) - assert.ElementsMatch(t, []kargoapi.PromotionStepInput{ + assert.ElementsMatch(t, []kargoapi.PromotionVariable{ {Name: "input1", Value: "override1"}, {Name: "input2", Value: "default2"}, {Name: "input3", Value: "value3"}, @@ -1083,23 +1079,8 @@ func Test_promotionTaskInputsToStepInputs(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - var configJSON *apiextensionsv1.JSON - if tt.config != nil { - configBytes, err := yaml.Marshal(tt.config) - require.NoError(t, err) - configJSON = &apiextensionsv1.JSON{Raw: configBytes} - } - - result, err := promotionTaskInputsToStepInputs(tt.taskInputs, configJSON) + result, err := promotionTaskVarsToStepVars(tt.taskVars, tt.promoVars, tt.stepVars) tt.assertions(t, result, err) }) } } - -// makeJSONObj is a helper function to create an API extension JSON object from -// a map. -func makeJSONObj(t *testing.T, m map[string]any) *apiextensionsv1.JSON { - data, err := yaml.Marshal(m) - require.NoError(t, err) - return &apiextensionsv1.JSON{Raw: data} -}