diff --git a/docs/matrix.md b/docs/matrix.md index 1150fdda4ba..eabf5517bb1 100644 --- a/docs/matrix.md +++ b/docs/matrix.md @@ -30,6 +30,7 @@ Documentation for specifying `Matrix` in a `Pipeline`: > :seedling: **`Matrix` is an [alpha](install.md#alpha-features) feature.** > The `enable-api-fields` feature flag must be set to `"alpha"` to specify `Matrix` in a `PipelineTask`. +> The `embedded-status` feature flag must be set to `"minimal"` to specify `Matrix` in a `PipelineTask`. > > :warning: This feature is in a preview mode. > It is still in a very early stage of development and is not yet fully functional. diff --git a/pkg/apis/pipeline/v1beta1/pipeline_types.go b/pkg/apis/pipeline/v1beta1/pipeline_types.go index caa2f6a0523..a8aa208bbeb 100644 --- a/pkg/apis/pipeline/v1beta1/pipeline_types.go +++ b/pkg/apis/pipeline/v1beta1/pipeline_types.go @@ -302,6 +302,9 @@ func (pt *PipelineTask) validateMatrix(ctx context.Context) (errs *apis.FieldErr // This is an alpha feature and will fail validation if it's used in a pipeline spec // when the enable-api-fields feature gate is anything but "alpha". errs = errs.Also(ValidateEnabledAPIFields(ctx, "matrix", config.AlphaAPIFields)) + // Matrix requires "embedded-status" feature gate to be set to "minimal", and will fail + // validation if it is anything but "minimal". + errs = errs.Also(ValidateEmbeddedStatus(ctx, "matrix", config.MinimalEmbeddedStatus)) errs = errs.Also(pt.validateMatrixCombinationsCount(ctx)) } errs = errs.Also(validateParameterInOneOfMatrixOrParams(pt.Matrix, pt.Params)) diff --git a/pkg/apis/pipeline/v1beta1/pipeline_types_test.go b/pkg/apis/pipeline/v1beta1/pipeline_types_test.go index 948ae9dd23a..0492b82eb82 100644 --- a/pkg/apis/pipeline/v1beta1/pipeline_types_test.go +++ b/pkg/apis/pipeline/v1beta1/pipeline_types_test.go @@ -684,9 +684,10 @@ func TestPipelineTaskList_Validate(t *testing.T) { func TestPipelineTask_validateMatrix(t *testing.T) { tests := []struct { - name string - pt *PipelineTask - wantErrs *apis.FieldError + name string + pt *PipelineTask + embeddedStatus string + wantErrs *apis.FieldError }{{ name: "parameter duplicated in matrix and params", pt: &PipelineTask{ @@ -770,11 +771,43 @@ func TestPipelineTask_validateMatrix(t *testing.T) { Name: "browser", Value: ArrayOrString{Type: ParamTypeArray, ArrayVal: []string{"chrome", "firefox"}}, }}, }, + }, { + name: "pipeline has a matrix but embedded status is full", + pt: &PipelineTask{ + Name: "task", + Matrix: []Param{{ + Name: "foobar", Value: ArrayOrString{Type: ParamTypeArray, ArrayVal: []string{"foo", "bar"}}, + }, { + Name: "barfoo", Value: ArrayOrString{Type: ParamTypeArray, ArrayVal: []string{"bar", "foo"}}, + }}, + }, + embeddedStatus: config.FullEmbeddedStatus, + wantErrs: &apis.FieldError{ + Message: "matrix requires \"embedded-status\" feature gate to be \"minimal\" but it is \"full\"", + }, + }, { + name: "pipeline has a matrix but embedded status is both", + pt: &PipelineTask{ + Name: "task", + Matrix: []Param{{ + Name: "foobar", Value: ArrayOrString{Type: ParamTypeArray, ArrayVal: []string{"foo", "bar"}}, + }, { + Name: "barfoo", Value: ArrayOrString{Type: ParamTypeArray, ArrayVal: []string{"bar", "foo"}}, + }}, + }, + embeddedStatus: config.BothEmbeddedStatus, + wantErrs: &apis.FieldError{ + Message: "matrix requires \"embedded-status\" feature gate to be \"minimal\" but it is \"both\"", + }, }} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { + if tt.embeddedStatus == "" { + tt.embeddedStatus = config.MinimalEmbeddedStatus + } featureFlags, _ := config.NewFeatureFlagsFromMap(map[string]string{ "enable-api-fields": "alpha", + "embedded-status": tt.embeddedStatus, }) defaults := &config.Defaults{ DefaultMaxMatrixCombinationsCount: 4, diff --git a/pkg/apis/pipeline/v1beta1/pipeline_validation_test.go b/pkg/apis/pipeline/v1beta1/pipeline_validation_test.go index 90001fab347..583cb3f742d 100644 --- a/pkg/apis/pipeline/v1beta1/pipeline_validation_test.go +++ b/pkg/apis/pipeline/v1beta1/pipeline_validation_test.go @@ -2749,6 +2749,7 @@ func TestMatrixIncompatibleAPIVersions(t *testing.T) { ps := tt.spec featureFlags, _ := config.NewFeatureFlagsFromMap(map[string]string{ "enable-api-fields": version, + "embedded-status": "minimal", }) defaults := &config.Defaults{ DefaultMaxMatrixCombinationsCount: 4, @@ -2861,6 +2862,7 @@ func Test_validateMatrix(t *testing.T) { t.Run(tt.name, func(t *testing.T) { featureFlags, _ := config.NewFeatureFlagsFromMap(map[string]string{ "enable-api-fields": "alpha", + "embedded-status": "minimal", }) defaults := &config.Defaults{ DefaultMaxMatrixCombinationsCount: 4, diff --git a/pkg/apis/pipeline/v1beta1/status_validation.go b/pkg/apis/pipeline/v1beta1/status_validation.go new file mode 100644 index 00000000000..860bd7f1f8e --- /dev/null +++ b/pkg/apis/pipeline/v1beta1/status_validation.go @@ -0,0 +1,36 @@ +/* +Copyright 2022 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + "context" + "fmt" + + "github.com/tektoncd/pipeline/pkg/apis/config" + "knative.dev/pkg/apis" +) + +// ValidateEmbeddedStatus checks that the embedded-status feature gate is set to the wantEmbeddedStatus value and, +// if not, returns an error stating which feature is dependent on the status and what the current status actually is. +func ValidateEmbeddedStatus(ctx context.Context, featureName, wantEmbeddedStatus string) *apis.FieldError { + embeddedStatus := config.FromContextOrDefaults(ctx).FeatureFlags.EmbeddedStatus + if embeddedStatus != wantEmbeddedStatus { + message := fmt.Sprintf(`%s requires "embedded-status" feature gate to be %q but it is %q`, featureName, wantEmbeddedStatus, embeddedStatus) + return apis.ErrGeneric(message) + } + return nil +} diff --git a/pkg/apis/pipeline/v1beta1/status_validation_test.go b/pkg/apis/pipeline/v1beta1/status_validation_test.go new file mode 100644 index 00000000000..0a5e58b18d1 --- /dev/null +++ b/pkg/apis/pipeline/v1beta1/status_validation_test.go @@ -0,0 +1,58 @@ +/* +Copyright 2022 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1beta1 + +import ( + "context" + "testing" + + "github.com/tektoncd/pipeline/pkg/apis/config" +) + +func TestValidateEmbeddedStatus(t *testing.T) { + status := "minimal" + flags, err := config.NewFeatureFlagsFromMap(map[string]string{ + "embedded-status": status, + }) + if err != nil { + t.Fatalf("error creating feature flags from map: %v", err) + } + cfg := &config.Config{ + FeatureFlags: flags, + } + ctx := config.ToContext(context.Background(), cfg) + if err := ValidateEmbeddedStatus(ctx, "test feature", status); err != nil { + t.Errorf("unexpected error for compatible feature gates: %q", err) + } +} + +func TestValidateEmbeddedStatusError(t *testing.T) { + flags, err := config.NewFeatureFlagsFromMap(map[string]string{ + "embedded-status": config.FullEmbeddedStatus, + }) + if err != nil { + t.Fatalf("error creating feature flags from map: %v", err) + } + cfg := &config.Config{ + FeatureFlags: flags, + } + ctx := config.ToContext(context.Background(), cfg) + err = ValidateEmbeddedStatus(ctx, "test feature", config.MinimalEmbeddedStatus) + if err == nil { + t.Errorf("error expected for incompatible feature gates") + } +} diff --git a/pkg/reconciler/pipelinerun/pipelinerun_test.go b/pkg/reconciler/pipelinerun/pipelinerun_test.go index 09ed2d49394..c059e385309 100644 --- a/pkg/reconciler/pipelinerun/pipelinerun_test.go +++ b/pkg/reconciler/pipelinerun/pipelinerun_test.go @@ -7614,7 +7614,7 @@ spec: `), } - cms := []*corev1.ConfigMap{withEnabledAlphaAPIFields(newFeatureFlagsConfigMap())} + cms := []*corev1.ConfigMap{withEmbeddedStatus(withEnabledAlphaAPIFields(newFeatureFlagsConfigMap()), config.MinimalEmbeddedStatus)} cms = append(cms, withMaxMatrixCombinationsCount(newDefaultsConfigMap(), 10)) tests := []struct {