From 8d50ed64d0d6b4d4121faceb487671dafbfe5574 Mon Sep 17 00:00:00 2001 From: Vincent Demeester Date: Thu, 6 Feb 2020 10:00:39 +0100 Subject: [PATCH 1/4] =?UTF-8?q?Task=20auto-conversion=20from=20v1alpha1=20?= =?UTF-8?q?to=20v1alpha2=20=F0=9F=8E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds auto-conversion methods and tests for Task types in v1alpha1 and v1alpha2. In order to reduce the number of duplicated fields, we are using v1alpha2.TaskSpec embedded in v1alpha1.TaskSpec so that both types are compatible. Signed-off-by: Vincent Demeester --- .../pipeline/v1alpha1/conversion_error.go | 51 ++ .../pipeline/v1alpha1/pipeline_conversion.go | 49 ++ .../v1alpha1/pipeline_validation_test.go | 21 +- .../pipeline/v1alpha1/resource_types_test.go | 29 +- pkg/apis/pipeline/v1alpha1/task_conversion.go | 123 +++++ .../pipeline/v1alpha1/task_conversion_test.go | 321 ++++++++++++ pkg/apis/pipeline/v1alpha1/task_types.go | 25 +- pkg/apis/pipeline/v1alpha1/task_validation.go | 14 + .../pipeline/v1alpha1/task_validation_test.go | 94 +++- .../v1alpha1/taskrun_validation_test.go | 17 +- .../v1alpha1/zz_generated.deepcopy.go | 53 +- .../pipeline/v1alpha2/pipeline_conversion.go | 35 ++ pkg/apis/pipeline/v1alpha2/task_conversion.go | 36 ++ .../pipeline/v1alpha2/task_conversion_test.go | 34 ++ pkg/pod/pod_test.go | 56 +-- .../pipelinerun/pipelinerun_test.go | 5 +- .../resources/conditionresolution.go | 5 +- .../resources/conditionresolution_test.go | 45 +- .../resources/pipelinerunresolution_test.go | 21 +- .../taskrun/resources/apply_test.go | 264 +++++----- .../taskrun/resources/image_exporter_test.go | 21 +- .../taskrun/resources/input_resource_test.go | 473 ++++++++++-------- .../resources/taskresourceresolution_test.go | 9 +- .../taskrun/resources/taskspec_test.go | 9 +- pkg/workspace/apply_test.go | 65 +-- test/builder/pipeline_test.go | 13 +- test/builder/task_test.go | 83 +-- test/retry_test.go | 5 +- test/start_time_test.go | 5 +- 29 files changed, 1378 insertions(+), 603 deletions(-) create mode 100644 pkg/apis/pipeline/v1alpha1/conversion_error.go create mode 100644 pkg/apis/pipeline/v1alpha1/pipeline_conversion.go create mode 100644 pkg/apis/pipeline/v1alpha1/task_conversion.go create mode 100644 pkg/apis/pipeline/v1alpha1/task_conversion_test.go create mode 100644 pkg/apis/pipeline/v1alpha2/pipeline_conversion.go create mode 100644 pkg/apis/pipeline/v1alpha2/task_conversion.go create mode 100644 pkg/apis/pipeline/v1alpha2/task_conversion_test.go diff --git a/pkg/apis/pipeline/v1alpha1/conversion_error.go b/pkg/apis/pipeline/v1alpha1/conversion_error.go new file mode 100644 index 00000000000..7282ea9e1ca --- /dev/null +++ b/pkg/apis/pipeline/v1alpha1/conversion_error.go @@ -0,0 +1,51 @@ +/* +Copyright 2020 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 v1alpha1 + +import ( + "fmt" + + "knative.dev/pkg/apis" +) + +const ( + // ConditionTypeConvertible is a Warning condition that is set on + // resources when they cannot be converted to warn of a forthcoming + // breakage. + ConditionTypeConvertible apis.ConditionType = "Convertible" +) + +// CannotConvertError is returned when a field cannot be converted. +type CannotConvertError struct { + Message string + Field string +} + +var _ error = (*CannotConvertError)(nil) + +// Error implements error +func (cce *CannotConvertError) Error() string { + return cce.Message +} + +// ConvertErrorf creates a CannotConvertError from the field name and format string. +func ConvertErrorf(field, msg string, args ...interface{}) error { + return &CannotConvertError{ + Message: fmt.Sprintf(msg, args...), + Field: field, + } +} diff --git a/pkg/apis/pipeline/v1alpha1/pipeline_conversion.go b/pkg/apis/pipeline/v1alpha1/pipeline_conversion.go new file mode 100644 index 00000000000..6ec1c6320e1 --- /dev/null +++ b/pkg/apis/pipeline/v1alpha1/pipeline_conversion.go @@ -0,0 +1,49 @@ +/* +Copyright 2020 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 v1alpha1 + +import ( + "context" + "fmt" + + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" + "knative.dev/pkg/apis" +) + +var _ apis.Convertible = (*Pipeline)(nil) + +// ConvertUp implements api.Convertible +func (source *Pipeline) ConvertUp(ctx context.Context, obj apis.Convertible) error { + switch sink := obj.(type) { + case *v1alpha2.Pipeline: + sink.ObjectMeta = source.ObjectMeta + return nil // source.Spec.ConvertUp(ctx, &sink.Spec) + default: + return fmt.Errorf("unknown version, got: %T", sink) + } +} + +// ConvertDown implements api.Convertible +func (sink *Pipeline) ConvertDown(ctx context.Context, obj apis.Convertible) error { + switch source := obj.(type) { + case *v1alpha2.Pipeline: + sink.ObjectMeta = source.ObjectMeta + return nil // sink.Spec.ConvertDown(ctx, &source.Spec) + default: + return fmt.Errorf("unknown version, got: %T", sink) + } +} diff --git a/pkg/apis/pipeline/v1alpha1/pipeline_validation_test.go b/pkg/apis/pipeline/v1alpha1/pipeline_validation_test.go index 0cef1fee166..4ccb37b37a0 100644 --- a/pkg/apis/pipeline/v1alpha1/pipeline_validation_test.go +++ b/pkg/apis/pipeline/v1alpha1/pipeline_validation_test.go @@ -21,6 +21,7 @@ import ( "testing" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" tb "github.com/tektoncd/pipeline/test/builder" corev1 "k8s.io/api/core/v1" ) @@ -84,10 +85,12 @@ func TestPipeline_Validate(t *testing.T) { name: "pipeline spec with taskref and taskspec", p: tb.Pipeline("pipeline", "namespace", tb.PipelineSpec( tb.PipelineTask("foo", "foo-task", tb.PipelineTaskSpec(&v1alpha1.TaskSpec{ - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "foo", - Image: "bar", - }}}, + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "foo", + Image: "bar", + }}}, + }, }, )))), failureExpected: true, @@ -101,10 +104,12 @@ func TestPipeline_Validate(t *testing.T) { name: "pipeline spec valid taskspec", p: tb.Pipeline("pipeline", "namespace", tb.PipelineSpec( tb.PipelineTask("", "", tb.PipelineTaskSpec(&v1alpha1.TaskSpec{ - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "foo", - Image: "bar", - }}}, + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "foo", + Image: "bar", + }}}, + }, }, )))), failureExpected: false, diff --git a/pkg/apis/pipeline/v1alpha1/resource_types_test.go b/pkg/apis/pipeline/v1alpha1/resource_types_test.go index ef4449de0c3..1623e30ea65 100644 --- a/pkg/apis/pipeline/v1alpha1/resource_types_test.go +++ b/pkg/apis/pipeline/v1alpha1/resource_types_test.go @@ -18,6 +18,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" corev1 "k8s.io/api/core/v1" ) @@ -69,11 +70,11 @@ func TestApplyTaskModifier(t *testing.T) { ts: v1alpha1.TaskSpec{}, }, { name: "identical volume already added", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ // Trying to add the same Volume that has already been added shouldn't be an error // and it should not be added twice Volumes: []corev1.Volume{volume}, - }, + }}, }} for _, tc := range testcases { t.Run(tc.name, func(t *testing.T) { @@ -81,7 +82,7 @@ func TestApplyTaskModifier(t *testing.T) { t.Fatalf("Did not expect error modifying TaskSpec but got %v", err) } - expectedTaskSpec := v1alpha1.TaskSpec{ + expectedTaskSpec := v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{ Container: prependStep, }, { @@ -90,7 +91,7 @@ func TestApplyTaskModifier(t *testing.T) { Volumes: []corev1.Volume{ volume, }, - } + }} if d := cmp.Diff(expectedTaskSpec, tc.ts); d != "" { t.Errorf("TaskSpec was not modified as expected (-want, +got): %s", d) @@ -105,34 +106,34 @@ func TestApplyTaskModifier_AlreadyAdded(t *testing.T) { ts v1alpha1.TaskSpec }{{ name: "prepend already added", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: prependStep}}, - }, + }}, }, { name: "append already added", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: appendStep}}, - }, + }}, }, { name: "both steps already added", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: prependStep}, {Container: appendStep}}, - }, + }}, }, { name: "both steps already added reverse order", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: appendStep}, {Container: prependStep}}, - }, + }}, }, { name: "volume with same name but diff content already added", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Volumes: []corev1.Volume{{ Name: "magic-volume", VolumeSource: corev1.VolumeSource{ EmptyDir: &corev1.EmptyDirVolumeSource{}, }, }}, - }, + }}, }} for _, tc := range testcases { t.Run(tc.name, func(t *testing.T) { diff --git a/pkg/apis/pipeline/v1alpha1/task_conversion.go b/pkg/apis/pipeline/v1alpha1/task_conversion.go new file mode 100644 index 00000000000..18cd2d8db38 --- /dev/null +++ b/pkg/apis/pipeline/v1alpha1/task_conversion.go @@ -0,0 +1,123 @@ +/* +Copyright 2020 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 v1alpha1 + +import ( + "context" + "fmt" + + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" + "knative.dev/pkg/apis" +) + +var _ apis.Convertible = (*Task)(nil) + +// ConvertUp implements api.Convertible +func (source *Task) ConvertUp(ctx context.Context, obj apis.Convertible) error { + switch sink := obj.(type) { + case *v1alpha2.Task: + sink.ObjectMeta = source.ObjectMeta + return source.Spec.ConvertUp(ctx, &sink.Spec) + default: + return fmt.Errorf("unknown version, got: %T", sink) + } +} + +func (source *TaskSpec) ConvertUp(ctx context.Context, sink *v1alpha2.TaskSpec) error { + sink.Steps = source.Steps + sink.Volumes = source.Volumes + sink.StepTemplate = source.StepTemplate + sink.Sidecars = source.Sidecars + sink.Workspaces = source.Workspaces + sink.Results = source.Results + sink.Resources = source.Resources + sink.Params = source.Params + if source.Inputs != nil { + if len(source.Inputs.Params) > 0 && len(source.Params) > 0 { + // This shouldn't happen as it shouldn't pass validation + return apis.ErrMultipleOneOf("inputs.params", "params") + } + if len(source.Inputs.Params) > 0 { + sink.Params = make([]v1alpha2.ParamSpec, len(source.Inputs.Params)) + for i, param := range source.Inputs.Params { + sink.Params[i] = *param.DeepCopy() + } + } + if len(source.Inputs.Resources) > 0 { + if sink.Resources == nil { + sink.Resources = &v1alpha2.TaskResources{} + } + if len(source.Inputs.Resources) > 0 && source.Resources != nil && len(source.Resources.Inputs) > 0 { + // This shouldn't happen as it shouldn't pass validation but just in case + return apis.ErrMultipleOneOf("inputs.resources", "resources.inputs") + } + sink.Resources.Inputs = make([]v1alpha2.TaskResource, len(source.Inputs.Resources)) + for i, resource := range source.Inputs.Resources { + sink.Resources.Inputs[i] = v1alpha2.TaskResource{ResourceDeclaration: v1alpha2.ResourceDeclaration{ + Name: resource.Name, + Type: resource.Type, + Description: resource.Description, + TargetPath: resource.TargetPath, + Optional: resource.Optional, + }} + } + } + } + if source.Outputs != nil && len(source.Outputs.Resources) > 0 { + if sink.Resources == nil { + sink.Resources = &v1alpha2.TaskResources{} + } + if len(source.Outputs.Resources) > 0 && source.Resources != nil && len(source.Resources.Outputs) > 0 { + // This shouldn't happen as it shouldn't pass validation but just in case + return apis.ErrMultipleOneOf("outputs.resources", "resources.outputs") + } + sink.Resources.Outputs = make([]v1alpha2.TaskResource, len(source.Outputs.Resources)) + for i, resource := range source.Outputs.Resources { + sink.Resources.Outputs[i] = v1alpha2.TaskResource{ResourceDeclaration: v1alpha2.ResourceDeclaration{ + Name: resource.Name, + Type: resource.Type, + Description: resource.Description, + TargetPath: resource.TargetPath, + Optional: resource.Optional, + }} + } + } + return nil +} + +// ConvertDown implements api.Convertible +func (sink *Task) ConvertDown(ctx context.Context, obj apis.Convertible) error { + switch source := obj.(type) { + case *v1alpha2.Task: + sink.ObjectMeta = source.ObjectMeta + return sink.Spec.ConvertDown(ctx, &source.Spec) + default: + return fmt.Errorf("unknown version, got: %T", sink) + } +} + +func (sink *TaskSpec) ConvertDown(ctx context.Context, source *v1alpha2.TaskSpec) error { + sink.Steps = source.Steps + sink.Volumes = source.Volumes + sink.StepTemplate = source.StepTemplate + sink.Sidecars = source.Sidecars + sink.Workspaces = source.Workspaces + sink.Results = source.Results + sink.Params = source.Params + sink.Resources = source.Resources + return nil +} diff --git a/pkg/apis/pipeline/v1alpha1/task_conversion_test.go b/pkg/apis/pipeline/v1alpha1/task_conversion_test.go new file mode 100644 index 00000000000..35a9d971825 --- /dev/null +++ b/pkg/apis/pipeline/v1alpha1/task_conversion_test.go @@ -0,0 +1,321 @@ +/* +Copyright 2020 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 v1alpha1 + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" + resource "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/pkg/apis" +) + +func TestTaskConversionBadType(t *testing.T) { + good, bad := &Task{}, &Pipeline{} + + if err := good.ConvertUp(context.Background(), bad); err == nil { + t.Errorf("ConvertUp() = %#v, wanted error", bad) + } + + if err := good.ConvertDown(context.Background(), bad); err == nil { + t.Errorf("ConvertUp() = %#v, wanted error", bad) + } +} + +func TestTaskConversion(t *testing.T) { + versions := []apis.Convertible{&v1alpha2.Task{}} + + tests := []struct { + name string + in *Task + wantErr bool + }{{ + name: "simple conversion", + in: &Task{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Generation: 1, + }, + Spec: TaskSpec{ + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha2.Step{{Container: corev1.Container{ + Image: "foo", + }}}, + Volumes: []corev1.Volume{{}}, + Params: []v1alpha2.ParamSpec{{ + Name: "param-1", + Type: v1alpha2.ParamTypeString, + Description: "My first param", + }}, + Resources: &v1alpha2.TaskResources{ + Inputs: []v1alpha2.TaskResource{{ResourceDeclaration: v1alpha2.ResourceDeclaration{ + Name: "input-1", + Type: resource.PipelineResourceTypeGit, + }}}, + Outputs: []v1alpha2.TaskResource{{ResourceDeclaration: v1alpha2.ResourceDeclaration{ + Name: "output-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }, + }, + }, + }, + }, { + name: "deprecated and non deprecated inputs", + in: &Task{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Generation: 1, + }, + Spec: TaskSpec{ + TaskSpec: v1alpha2.TaskSpec{ + Resources: &v1alpha2.TaskResources{ + Inputs: []v1alpha2.TaskResource{{ResourceDeclaration: v1alpha2.ResourceDeclaration{ + Name: "input-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }, + }, + Inputs: &Inputs{ + Resources: []TaskResource{{ResourceDeclaration: ResourceDeclaration{ + Name: "input-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }, + }, + }, + wantErr: true, + }, { + name: "deprecated and non deprecated inputs", + in: &Task{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Generation: 1, + }, + Spec: TaskSpec{ + TaskSpec: v1alpha2.TaskSpec{ + Params: []v1alpha2.ParamSpec{{ + Name: "param-1", + Type: v1alpha2.ParamTypeString, + Description: "My first param", + }}, + }, + Inputs: &Inputs{ + Params: []ParamSpec{{ + Name: "param-1", + Type: v1alpha2.ParamTypeString, + Description: "My first param", + }}, + }, + }, + }, + wantErr: true, + }, { + name: "deprecated and non deprecated outputs", + in: &Task{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Generation: 1, + }, + Spec: TaskSpec{ + TaskSpec: v1alpha2.TaskSpec{ + Resources: &v1alpha2.TaskResources{ + Outputs: []v1alpha2.TaskResource{{ResourceDeclaration: v1alpha2.ResourceDeclaration{ + Name: "output-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }, + }, + Outputs: &Outputs{ + Resources: []TaskResource{{ResourceDeclaration: ResourceDeclaration{ + Name: "output-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }, + }, + }, + wantErr: true, + }} + + for _, test := range tests { + for _, version := range versions { + t.Run(test.name, func(t *testing.T) { + ver := version + if err := test.in.ConvertUp(context.Background(), ver); err != nil { + if !test.wantErr { + t.Errorf("ConvertUp() = %v", err) + } + return + } + t.Logf("ConvertUp() = %#v", ver) + got := &Task{} + if err := got.ConvertDown(context.Background(), ver); err != nil { + t.Errorf("ConvertDown() = %v", err) + } + t.Logf("ConvertDown() = %#v", got) + if diff := cmp.Diff(test.in, got); diff != "" { + t.Errorf("roundtrip (-want, +got) = %v", diff) + } + }) + } + } +} + +func TestTaskConversionFromDeprecated(t *testing.T) { + versions := []apis.Convertible{&v1alpha2.Task{}} + tests := []struct { + name string + in *Task + want *Task + badField string + }{{ + name: "inputs params", + in: &Task{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Generation: 1, + }, + Spec: TaskSpec{ + Inputs: &Inputs{ + Params: []ParamSpec{{ + Name: "param-1", + Type: v1alpha2.ParamTypeString, + Description: "My first param", + }}, + }, + }, + }, + want: &Task{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Generation: 1, + }, + Spec: TaskSpec{ + TaskSpec: v1alpha2.TaskSpec{ + Params: []v1alpha2.ParamSpec{{ + Name: "param-1", + Type: v1alpha2.ParamTypeString, + Description: "My first param", + }}, + }, + }, + }, + }, { + name: "inputs resource", + in: &Task{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Generation: 1, + }, + Spec: TaskSpec{ + Inputs: &Inputs{ + Resources: []TaskResource{{ResourceDeclaration: ResourceDeclaration{ + Name: "input-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }, + }, + }, + want: &Task{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Generation: 1, + }, + Spec: TaskSpec{ + TaskSpec: v1alpha2.TaskSpec{ + Resources: &v1alpha2.TaskResources{ + Inputs: []v1alpha2.TaskResource{{ResourceDeclaration: v1alpha2.ResourceDeclaration{ + Name: "input-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }, + }, + }, + }, + }, { + name: "outputs resource", + in: &Task{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Generation: 1, + }, + Spec: TaskSpec{ + Outputs: &Outputs{ + Resources: []TaskResource{{ResourceDeclaration: ResourceDeclaration{ + Name: "output-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }, + }, + }, + want: &Task{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Generation: 1, + }, + Spec: TaskSpec{ + TaskSpec: v1alpha2.TaskSpec{ + Resources: &v1alpha2.TaskResources{ + Outputs: []v1alpha2.TaskResource{{ResourceDeclaration: v1alpha2.ResourceDeclaration{ + Name: "output-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }, + }, + }, + }, + }} + for _, test := range tests { + for _, version := range versions { + t.Run(test.name, func(t *testing.T) { + ver := version + if err := test.in.ConvertUp(context.Background(), ver); err != nil { + if test.badField != "" { + cce, ok := err.(*CannotConvertError) + if ok && cce.Field == test.badField { + return + } + } + t.Errorf("ConvertUp() = %v", err) + } + t.Logf("ConvertUp() = %#v", ver) + got := &Task{} + if err := got.ConvertDown(context.Background(), ver); err != nil { + t.Errorf("ConvertDown() = %v", err) + } + t.Logf("ConvertDown() = %#v", got) + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("roundtrip (-want, +got) = %v", diff) + } + }) + } + } +} diff --git a/pkg/apis/pipeline/v1alpha1/task_types.go b/pkg/apis/pipeline/v1alpha1/task_types.go index f0675718f62..544e6e0b77c 100644 --- a/pkg/apis/pipeline/v1alpha1/task_types.go +++ b/pkg/apis/pipeline/v1alpha1/task_types.go @@ -17,7 +17,6 @@ limitations under the License. package v1alpha1 import ( - corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" @@ -46,6 +45,8 @@ func (t *Task) Copy() TaskInterface { // TaskSpec defines the desired state of Task. type TaskSpec struct { + v1alpha2.TaskSpec `json:",inline"` + // Inputs is an optional set of parameters and resources which must be // supplied by the user when a Task is executed by a TaskRun. // +optional @@ -54,28 +55,6 @@ type TaskSpec struct { // Task is run. // +optional Outputs *Outputs `json:"outputs,omitempty"` - - // Steps are the steps of the build; each step is run sequentially with the - // source mounted into /workspace. - Steps []Step `json:"steps,omitempty"` - - // Volumes is a collection of volumes that are available to mount into the - // steps of the build. - Volumes []corev1.Volume `json:"volumes,omitempty"` - - // StepTemplate can be used as the basis for all step containers within the - // Task, so that the steps inherit settings on the base container. - StepTemplate *corev1.Container `json:"stepTemplate,omitempty"` - - // Sidecars are run alongside the Task's step containers. They begin before - // the steps start and end after the steps complete. - Sidecars []Sidecar `json:"sidecars,omitempty"` - - // Workspaces are the volumes that this Task requires. - Workspaces []WorkspaceDeclaration `json:"workspaces,omitempty"` - - // Results are values that this Task can output - Results []TaskResult `json:"results,omitempty"` } // TaskResult used to describe the results of a task diff --git a/pkg/apis/pipeline/v1alpha1/task_validation.go b/pkg/apis/pipeline/v1alpha1/task_validation.go index 14d3ea69c2e..3209e8aceb6 100644 --- a/pkg/apis/pipeline/v1alpha1/task_validation.go +++ b/pkg/apis/pipeline/v1alpha1/task_validation.go @@ -65,6 +65,20 @@ func (ts *TaskSpec) Validate(ctx context.Context) *apis.FieldError { return err } + if ts.Inputs != nil { + if len(ts.Inputs.Params) > 0 && len(ts.Params) > 0 { + return apis.ErrMultipleOneOf("inputs.params", "params") + } + if ts.Resources != nil && len(ts.Resources.Inputs) > 0 && len(ts.Inputs.Resources) > 0 { + return apis.ErrMultipleOneOf("inputs.resources", "resources.inputs") + } + } + if ts.Outputs != nil { + if ts.Resources != nil && len(ts.Resources.Outputs) > 0 && len(ts.Outputs.Resources) > 0 { + return apis.ErrMultipleOneOf("outputs.resources", "resources.outputs") + } + } + // A task doesn't have to have inputs or outputs, but if it does they must be valid. // A task can't duplicate input or output names. diff --git a/pkg/apis/pipeline/v1alpha1/task_validation_test.go b/pkg/apis/pipeline/v1alpha1/task_validation_test.go index 32dc449ae3b..b4a37f4e335 100644 --- a/pkg/apis/pipeline/v1alpha1/task_validation_test.go +++ b/pkg/apis/pipeline/v1alpha1/task_validation_test.go @@ -23,6 +23,8 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" + resource "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" "github.com/tektoncd/pipeline/test/builder" corev1 "k8s.io/api/core/v1" "knative.dev/pkg/apis" @@ -296,11 +298,13 @@ func TestTaskSpecValidate(t *testing.T) { for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ts := &v1alpha1.TaskSpec{ - Inputs: tt.fields.Inputs, - Outputs: tt.fields.Outputs, - Steps: tt.fields.Steps, - StepTemplate: tt.fields.StepTemplate, - Workspaces: tt.fields.Workspaces, + TaskSpec: v1alpha2.TaskSpec{ + Steps: tt.fields.Steps, + StepTemplate: tt.fields.StepTemplate, + Workspaces: tt.fields.Workspaces, + }, + Inputs: tt.fields.Inputs, + Outputs: tt.fields.Outputs, } ctx := context.Background() ts.SetDefaults(ctx) @@ -319,6 +323,9 @@ func TestTaskSpecValidateError(t *testing.T) { Volumes []corev1.Volume StepTemplate *corev1.Container Workspaces []v1alpha1.WorkspaceDeclaration + // v1alpha2 + Params []v1alpha2.ParamSpec + Resources *v1alpha2.TaskResources } tests := []struct { name string @@ -864,16 +871,81 @@ func TestTaskSpecValidateError(t *testing.T) { Message: "workspace mount path \"/workspace/some-workspace\" must be unique", Paths: []string{"workspaces.mountpath"}, }, + }, { + name: "v1alpha2: params and deprecated inputs.params", + fields: fields{ + Steps: validSteps, + Params: []v1alpha2.ParamSpec{{ + Name: "param1", + Type: v1alpha2.ParamTypeString, + }}, + Inputs: &v1alpha1.Inputs{ + Params: []v1alpha1.ParamSpec{{ + Name: "param1", + Type: v1alpha2.ParamTypeString, + }}, + }, + }, + expectedError: apis.FieldError{ + Message: "expected exactly one, got both", + Paths: []string{"inputs.params", "params"}, + }, + }, { + name: "v1alpha2: resources.inputs and deprecated inputs.resource", + fields: fields{ + Steps: validSteps, + Resources: &v1alpha2.TaskResources{ + Inputs: []v1alpha2.TaskResource{{ResourceDeclaration: v1alpha2.ResourceDeclaration{ + Name: "input-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }, + Inputs: &v1alpha1.Inputs{ + Resources: []v1alpha1.TaskResource{{ResourceDeclaration: v1alpha1.ResourceDeclaration{ + Name: "input-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }, + }, + expectedError: apis.FieldError{ + Message: "expected exactly one, got both", + Paths: []string{"inputs.resources", "resources.inputs"}, + }, + }, { + name: "v1alpha2: resources.outputs and deprecated outputs.resource", + fields: fields{ + Steps: validSteps, + Resources: &v1alpha2.TaskResources{ + Outputs: []v1alpha2.TaskResource{{ResourceDeclaration: v1alpha2.ResourceDeclaration{ + Name: "output-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }, + Outputs: &v1alpha1.Outputs{ + Resources: []v1alpha1.TaskResource{{ResourceDeclaration: v1alpha1.ResourceDeclaration{ + Name: "output-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }, + }, + expectedError: apis.FieldError{ + Message: "expected exactly one, got both", + Paths: []string{"outputs.resources", "resources.outputs"}, + }, }} for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ts := &v1alpha1.TaskSpec{ - Inputs: tt.fields.Inputs, - Outputs: tt.fields.Outputs, - Steps: tt.fields.Steps, - Volumes: tt.fields.Volumes, - StepTemplate: tt.fields.StepTemplate, - Workspaces: tt.fields.Workspaces, + TaskSpec: v1alpha2.TaskSpec{ + Steps: tt.fields.Steps, + Volumes: tt.fields.Volumes, + StepTemplate: tt.fields.StepTemplate, + Workspaces: tt.fields.Workspaces, + Params: tt.fields.Params, + Resources: tt.fields.Resources, + }, + Inputs: tt.fields.Inputs, + Outputs: tt.fields.Outputs, } ctx := context.Background() ts.SetDefaults(ctx) diff --git a/pkg/apis/pipeline/v1alpha1/taskrun_validation_test.go b/pkg/apis/pipeline/v1alpha1/taskrun_validation_test.go index 557285fe0b2..7ca24ce0739 100644 --- a/pkg/apis/pipeline/v1alpha1/taskrun_validation_test.go +++ b/pkg/apis/pipeline/v1alpha1/taskrun_validation_test.go @@ -23,6 +23,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" "github.com/tektoncd/pipeline/test/builder" tb "github.com/tektoncd/pipeline/test/builder" corev1 "k8s.io/api/core/v1" @@ -122,12 +123,12 @@ func TestTaskRunSpec_Invalid(t *testing.T) { TaskRef: &v1alpha1.TaskRef{ Name: "taskrefname", }, - TaskSpec: &v1alpha1.TaskSpec{ + TaskSpec: &v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "mystep", Image: "myimage", }}}, - }, + }}, }, wantErr: apis.ErrDisallowedFields("spec.taskspec", "spec.taskref"), }, { @@ -142,12 +143,12 @@ func TestTaskRunSpec_Invalid(t *testing.T) { }, { name: "invalid taskspec", spec: v1alpha1.TaskRunSpec{ - TaskSpec: &v1alpha1.TaskSpec{ + TaskSpec: &v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "invalid-name-with-$weird-char*/%", Image: "myimage", }}}, - }, + }}, }, wantErr: &apis.FieldError{ Message: `invalid value "invalid-name-with-$weird-char*/%"`, @@ -172,23 +173,23 @@ func TestTaskRunSpec_Validate(t *testing.T) { }{{ name: "taskspec without a taskRef", spec: v1alpha1.TaskRunSpec{ - TaskSpec: &v1alpha1.TaskSpec{ + TaskSpec: &v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "mystep", Image: "myimage", }}}, - }, + }}, }, }, { name: "no timeout", spec: v1alpha1.TaskRunSpec{ Timeout: &metav1.Duration{Duration: 0}, - TaskSpec: &v1alpha1.TaskSpec{ + TaskSpec: &v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "mystep", Image: "myimage", }}}, - }, + }}, }, }} for _, ts := range tests { diff --git a/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go index 4065c6ae435..6821ae976bf 100644 --- a/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go @@ -87,6 +87,22 @@ func (in *BuildGCSResource) DeepCopy() *BuildGCSResource { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CannotConvertError) DeepCopyInto(out *CannotConvertError) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CannotConvertError. +func (in *CannotConvertError) DeepCopy() *CannotConvertError { + if in == nil { + return nil + } + out := new(CannotConvertError) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CloudEventDelivery) DeepCopyInto(out *CloudEventDelivery) { *out = *in @@ -1291,6 +1307,7 @@ func (in *TaskRunStatusFields) DeepCopy() *TaskRunStatusFields { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TaskSpec) DeepCopyInto(out *TaskSpec) { *out = *in + in.TaskSpec.DeepCopyInto(&out.TaskSpec) if in.Inputs != nil { in, out := &in.Inputs, &out.Inputs *out = new(Inputs) @@ -1301,42 +1318,6 @@ func (in *TaskSpec) DeepCopyInto(out *TaskSpec) { *out = new(Outputs) (*in).DeepCopyInto(*out) } - if in.Steps != nil { - in, out := &in.Steps, &out.Steps - *out = make([]v1alpha2.Step, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Volumes != nil { - in, out := &in.Volumes, &out.Volumes - *out = make([]v1.Volume, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.StepTemplate != nil { - in, out := &in.StepTemplate, &out.StepTemplate - *out = new(v1.Container) - (*in).DeepCopyInto(*out) - } - if in.Sidecars != nil { - in, out := &in.Sidecars, &out.Sidecars - *out = make([]v1alpha2.Step, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Workspaces != nil { - in, out := &in.Workspaces, &out.Workspaces - *out = make([]v1alpha2.WorkspaceDeclaration, len(*in)) - copy(*out, *in) - } - if in.Results != nil { - in, out := &in.Results, &out.Results - *out = make([]v1alpha2.TaskResult, len(*in)) - copy(*out, *in) - } return } diff --git a/pkg/apis/pipeline/v1alpha2/pipeline_conversion.go b/pkg/apis/pipeline/v1alpha2/pipeline_conversion.go new file mode 100644 index 00000000000..520827e836a --- /dev/null +++ b/pkg/apis/pipeline/v1alpha2/pipeline_conversion.go @@ -0,0 +1,35 @@ +/* +Copyright 2020 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 v1alpha2 + +import ( + "context" + "fmt" + + "knative.dev/pkg/apis" +) + +var _ apis.Convertible = (*Pipeline)(nil) + +func (source *Pipeline) ConvertUp(ctx context.Context, sink apis.Convertible) error { + return fmt.Errorf("v1alpha2 is the highest known version, got: %T", sink) +} + +// ConvertDown implements api.Convertible +func (sink *Pipeline) ConvertDown(ctx context.Context, source apis.Convertible) error { + return fmt.Errorf("v1alpha2 is the highest know version, got: %T", source) +} diff --git a/pkg/apis/pipeline/v1alpha2/task_conversion.go b/pkg/apis/pipeline/v1alpha2/task_conversion.go new file mode 100644 index 00000000000..887844890bf --- /dev/null +++ b/pkg/apis/pipeline/v1alpha2/task_conversion.go @@ -0,0 +1,36 @@ +/* +Copyright 2020 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 v1alpha2 + +import ( + "context" + "fmt" + + "knative.dev/pkg/apis" +) + +var _ apis.Convertible = (*Task)(nil) + +// ConvertUp implements api.Convertible +func (source *Task) ConvertUp(ctx context.Context, sink apis.Convertible) error { + return fmt.Errorf("v1alpha2 is the highest known version, got: %T", sink) +} + +// ConvertDown implements api.Convertible +func (sink *Task) ConvertDown(ctx context.Context, source apis.Convertible) error { + return fmt.Errorf("v1alpha2 is the highest know version, got: %T", source) +} diff --git a/pkg/apis/pipeline/v1alpha2/task_conversion_test.go b/pkg/apis/pipeline/v1alpha2/task_conversion_test.go new file mode 100644 index 00000000000..947f795148e --- /dev/null +++ b/pkg/apis/pipeline/v1alpha2/task_conversion_test.go @@ -0,0 +1,34 @@ +/* +Copyright 2020 The Tetkon 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 v1alpha2 + +import ( + "context" + "testing" +) + +func TestTaskConversionBadType(t *testing.T) { + good, bad := &Task{}, &Pipeline{} + + if err := good.ConvertUp(context.Background(), bad); err == nil { + t.Errorf("ConvertUp() = %#v, wanted error", bad) + } + + if err := good.ConvertDown(context.Background(), bad); err == nil { + t.Errorf("ConvertDown() = %#v, wanted error", good) + } +} diff --git a/pkg/pod/pod_test.go b/pkg/pod/pod_test.go index 1d2ec383380..942c4a2e700 100644 --- a/pkg/pod/pod_test.go +++ b/pkg/pod/pod_test.go @@ -25,6 +25,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/tektoncd/pipeline/pkg/apis/pipeline" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" "github.com/tektoncd/pipeline/test/names" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" @@ -73,13 +74,13 @@ func TestMakePod(t *testing.T) { wantAnnotations map[string]string }{{ desc: "simple", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "name", Image: "image", Command: []string{"cmd"}, // avoid entrypoint lookup. }}}, - }, + }}, want: &corev1.PodSpec{ RestartPolicy: corev1.RestartPolicyNever, InitContainers: []corev1.Container{placeToolsInit}, @@ -109,13 +110,13 @@ func TestMakePod(t *testing.T) { }, }, { desc: "with service account", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "name", Image: "image", Command: []string{"cmd"}, // avoid entrypoint lookup. }}}, - }, + }}, trs: v1alpha1.TaskRunSpec{ ServiceAccountName: "service-account", }, @@ -163,13 +164,13 @@ func TestMakePod(t *testing.T) { }, }, { desc: "with-pod-template", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "name", Image: "image", Command: []string{"cmd"}, // avoid entrypoint lookup. }}}, - }, + }}, trs: v1alpha1.TaskRunSpec{ PodTemplate: &v1alpha1.PodTemplate{ SecurityContext: &corev1.PodSecurityContext{ @@ -231,13 +232,13 @@ func TestMakePod(t *testing.T) { }, }, { desc: "very long step name", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "a-very-very-long-character-step-name-to-trigger-max-len----and-invalid-characters", Image: "image", Command: []string{"cmd"}, // avoid entrypoint lookup. }}}, - }, + }}, want: &corev1.PodSpec{ RestartPolicy: corev1.RestartPolicyNever, InitContainers: []corev1.Container{placeToolsInit}, @@ -267,13 +268,13 @@ func TestMakePod(t *testing.T) { }, }, { desc: "step name ends with non alphanumeric", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "ends-with-invalid-%%__$$", Image: "image", Command: []string{"cmd"}, // avoid entrypoint lookup. }}}, - }, + }}, want: &corev1.PodSpec{ RestartPolicy: corev1.RestartPolicyNever, InitContainers: []corev1.Container{placeToolsInit}, @@ -303,14 +304,14 @@ func TestMakePod(t *testing.T) { }, }, { desc: "workingDir in workspace", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "name", Image: "image", Command: []string{"cmd"}, // avoid entrypoint lookup. WorkingDir: filepath.Join(pipeline.WorkspaceDir, "test"), }}}, - }, + }}, want: &corev1.PodSpec{ RestartPolicy: corev1.RestartPolicyNever, InitContainers: []corev1.Container{{ @@ -349,21 +350,19 @@ func TestMakePod(t *testing.T) { }, }, { desc: "sidecar container", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "primary-name", Image: "primary-image", Command: []string{"cmd"}, // avoid entrypoint lookup. }}}, - Sidecars: []v1alpha1.Sidecar{ - { - Container: corev1.Container{ - Name: "sc-name", - Image: "sidecar-image", - }, + Sidecars: []v1alpha1.Sidecar{{ + Container: corev1.Container{ + Name: "sc-name", + Image: "sidecar-image", }, - }, - }, + }}, + }}, wantAnnotations: map[string]string{}, want: &corev1.PodSpec{ RestartPolicy: corev1.RestartPolicyNever, @@ -400,7 +399,7 @@ func TestMakePod(t *testing.T) { }, }, { desc: "sidecar container with script", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "primary-name", Image: "primary-image", @@ -412,9 +411,8 @@ func TestMakePod(t *testing.T) { Image: "sidecar-image", }, Script: "#!/bin/sh\necho hello from sidecar", - }, - }, - }, + }}, + }}, wantAnnotations: map[string]string{}, want: &corev1.PodSpec{ RestartPolicy: corev1.RestartPolicyNever, @@ -468,7 +466,7 @@ sidecar-script-heredoc-randomly-generated-mz4c7 }, }, { desc: "resource request", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Image: "image", Command: []string{"cmd"}, // avoid entrypoint lookup. @@ -488,7 +486,7 @@ sidecar-script-heredoc-randomly-generated-mz4c7 }, }, }}}, - }, + }}, want: &corev1.PodSpec{ RestartPolicy: corev1.RestartPolicyNever, InitContainers: []corev1.Container{placeToolsInit}, @@ -550,7 +548,7 @@ sidecar-script-heredoc-randomly-generated-mz4c7 }, }, { desc: "step with script and stepTemplate", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ StepTemplate: &corev1.Container{ Env: []corev1.EnvVar{{Name: "FOO", Value: "bar"}}, Args: []string{"template", "args"}, @@ -576,7 +574,7 @@ print("Hello from Python")`, Command: []string{"regular", "command"}, }, }}, - }, + }}, want: &corev1.PodSpec{ RestartPolicy: corev1.RestartPolicyNever, InitContainers: []corev1.Container{{ diff --git a/pkg/reconciler/pipelinerun/pipelinerun_test.go b/pkg/reconciler/pipelinerun/pipelinerun_test.go index c25e9c6dd82..702e9cbacbd 100644 --- a/pkg/reconciler/pipelinerun/pipelinerun_test.go +++ b/pkg/reconciler/pipelinerun/pipelinerun_test.go @@ -27,6 +27,7 @@ import ( "github.com/google/go-cmp/cmp/cmpopts" "github.com/tektoncd/pipeline/pkg/apis/pipeline" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" "github.com/tektoncd/pipeline/pkg/reconciler/pipelinerun/resources" taskrunresources "github.com/tektoncd/pipeline/pkg/reconciler/taskrun/resources" ttesting "github.com/tektoncd/pipeline/pkg/reconciler/testing" @@ -295,11 +296,11 @@ func TestReconcile_PipelineSpecTaskSpec(t *testing.T) { ps := []*v1alpha1.Pipeline{ tb.Pipeline("test-pipeline", "foo", tb.PipelineSpec( - tb.PipelineTask("unit-test-task-spec", "", tb.PipelineTaskSpec(&v1alpha1.TaskSpec{ + tb.PipelineTask("unit-test-task-spec", "", tb.PipelineTaskSpec(&v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "mystep", Image: "myimage"}}}, - })), + }})), ), ), } diff --git a/pkg/reconciler/pipelinerun/resources/conditionresolution.go b/pkg/reconciler/pipelinerun/resources/conditionresolution.go index fbd2191236c..48445928ab7 100644 --- a/pkg/reconciler/pipelinerun/resources/conditionresolution.go +++ b/pkg/reconciler/pipelinerun/resources/conditionresolution.go @@ -22,6 +22,7 @@ import ( "github.com/tektoncd/pipeline/pkg/apis/pipeline" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" corev1 "k8s.io/api/core/v1" ) @@ -96,7 +97,9 @@ func (rcc *ResolvedConditionCheck) ConditionToTaskSpec() (*v1alpha1.TaskSpec, er } t := &v1alpha1.TaskSpec{ - Steps: []v1alpha1.Step{rcc.Condition.Spec.Check}, + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{rcc.Condition.Spec.Check}, + }, } t.Inputs = &v1alpha1.Inputs{ diff --git a/pkg/reconciler/pipelinerun/resources/conditionresolution_test.go b/pkg/reconciler/pipelinerun/resources/conditionresolution_test.go index b1822ad4b0c..80aec7f805d 100644 --- a/pkg/reconciler/pipelinerun/resources/conditionresolution_test.go +++ b/pkg/reconciler/pipelinerun/resources/conditionresolution_test.go @@ -22,6 +22,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" tb "github.com/tektoncd/pipeline/test/builder" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -195,10 +196,12 @@ func TestResolvedConditionCheck_ConditionToTaskSpec(t *testing.T) { tb.ConditionSpecCheck("foo", "ubuntu"), )), want: v1alpha1.TaskSpec{ - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "foo", - Image: "ubuntu", - }}}, + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "foo", + Image: "ubuntu", + }}}, + }, Inputs: &v1alpha1.Inputs{}, }, }, { @@ -207,10 +210,12 @@ func TestResolvedConditionCheck_ConditionToTaskSpec(t *testing.T) { tb.ConditionSpecCheck("", "ubuntu"), )), want: v1alpha1.TaskSpec{ - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "condition-check-bar", - Image: "ubuntu", - }}}, + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "condition-check-bar", + Image: "ubuntu", + }}}, + }, Inputs: &v1alpha1.Inputs{}, }, }, { @@ -222,6 +227,13 @@ func TestResolvedConditionCheck_ConditionToTaskSpec(t *testing.T) { tb.ConditionParamSpec("img", v1alpha1.ParamTypeString), )), want: v1alpha1.TaskSpec{ + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "$(inputs.params.name)", + Image: "$(inputs.params.img)", + WorkingDir: "$(params.not.replaced)", + }}}, + }, Inputs: &v1alpha1.Inputs{ Params: []v1alpha1.ParamSpec{{ Name: "name", @@ -231,11 +243,6 @@ func TestResolvedConditionCheck_ConditionToTaskSpec(t *testing.T) { Type: "string", }}, }, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "$(inputs.params.name)", - Image: "$(inputs.params.img)", - WorkingDir: "$(params.not.replaced)", - }}}, }, }, { name: "with-resources", @@ -251,6 +258,13 @@ func TestResolvedConditionCheck_ConditionToTaskSpec(t *testing.T) { )), }, want: v1alpha1.TaskSpec{ + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "name", + Image: "ubuntu", + Args: []string{"master"}, + }}}, + }, Inputs: &v1alpha1.Inputs{ Resources: []v1alpha1.TaskResource{{ ResourceDeclaration: v1alpha1.ResourceDeclaration{ @@ -258,11 +272,6 @@ func TestResolvedConditionCheck_ConditionToTaskSpec(t *testing.T) { Type: "git", }}}, }, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "name", - Image: "ubuntu", - Args: []string{"master"}, - }}}, }, }} diff --git a/pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go b/pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go index 8469c841f25..acfc06c4cc5 100644 --- a/pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go +++ b/pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go @@ -24,6 +24,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" "github.com/tektoncd/pipeline/pkg/reconciler/pipeline/dag" "github.com/tektoncd/pipeline/pkg/reconciler/taskrun/resources" tb "github.com/tektoncd/pipeline/test/builder" @@ -91,22 +92,22 @@ var task = &v1alpha1.Task{ ObjectMeta: metav1.ObjectMeta{ Name: "task", }, - Spec: v1alpha1.TaskSpec{ + Spec: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "step1", }}}, - }, + }}, } var clustertask = &v1alpha1.ClusterTask{ ObjectMeta: metav1.ObjectMeta{ Name: "clustertask", }, - Spec: v1alpha1.TaskSpec{ + Spec: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "step1", }}}, - }, + }}, } var trs = []v1alpha1.TaskRun{{ @@ -457,6 +458,11 @@ var taskWithOptionalResources = &v1alpha1.Task{ Name: "task", }, Spec: v1alpha1.TaskSpec{ + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "step1", + }}}, + }, Inputs: &v1alpha1.Inputs{ Resources: []v1alpha1.TaskResource{{ResourceDeclaration: v1alpha1.ResourceDeclaration{ Name: "optional-input", @@ -478,9 +484,6 @@ var taskWithOptionalResources = &v1alpha1.Task{ Optional: false, }}}, }, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "step1", - }}}, }, } @@ -1151,11 +1154,11 @@ func TestResolvePipelineRun(t *testing.T) { tb.PipelineTaskOutputResource("output1", "git-resource"), ), tb.PipelineTask("mytask4", "", - tb.PipelineTaskSpec(&v1alpha1.TaskSpec{ + tb.PipelineTaskSpec(&v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "step1", }}}, - })), + }})), )) r := &v1alpha1.PipelineResource{ diff --git a/pkg/reconciler/taskrun/resources/apply_test.go b/pkg/reconciler/taskrun/resources/apply_test.go index c5ff0bef4ed..9e8601b6c7b 100644 --- a/pkg/reconciler/taskrun/resources/apply_test.go +++ b/pkg/reconciler/taskrun/resources/apply_test.go @@ -22,6 +22,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/tektoncd/pipeline/pkg/apis/pipeline" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" "github.com/tektoncd/pipeline/pkg/reconciler/taskrun/resources" "github.com/tektoncd/pipeline/test/builder" "github.com/tektoncd/pipeline/test/names" @@ -44,6 +45,121 @@ var ( } simpleTaskSpec = &v1alpha1.TaskSpec{ + TaskSpec: v1alpha2.TaskSpec{ + Sidecars: []v1alpha1.Sidecar{{ + Container: corev1.Container{ + Name: "foo", + Image: "$(inputs.params.myimage)", + Env: []corev1.EnvVar{{ + Name: "foo", + Value: "$(inputs.params.FOO)", + }}, + }, + }}, + StepTemplate: &corev1.Container{ + Env: []corev1.EnvVar{{ + Name: "template-var", + Value: "$(inputs.params.FOO)", + }}, + }, + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "foo", + Image: "$(inputs.params.myimage)", + }}, {Container: corev1.Container{ + Name: "baz", + Image: "bat", + WorkingDir: "$(inputs.resources.workspace.path)", + Args: []string{"$(inputs.resources.workspace.url)"}, + }}, {Container: corev1.Container{ + Name: "qux", + Image: "$(inputs.params.something)", + Args: []string{"$(outputs.resources.imageToUse.url)"}, + }}, {Container: corev1.Container{ + Name: "foo", + Image: "$(inputs.params.myimage)", + }}, {Container: corev1.Container{ + Name: "baz", + Image: "$(inputs.params.somethingelse)", + WorkingDir: "$(inputs.resources.workspace.path)", + Args: []string{"$(inputs.resources.workspace.url)"}, + }}, {Container: corev1.Container{ + Name: "qux", + Image: "quux", + Args: []string{"$(outputs.resources.imageToUse.url)"}, + }}, {Container: corev1.Container{ + Name: "foo", + Image: "busybox:$(inputs.params.FOO)", + VolumeMounts: []corev1.VolumeMount{{ + Name: "$(inputs.params.FOO)", + MountPath: "path/to/$(inputs.params.FOO)", + SubPath: "sub/$(inputs.params.FOO)/path", + }}, + }}, {Container: corev1.Container{ + Name: "foo", + Image: "busybox:$(inputs.params.FOO)", + Env: []corev1.EnvVar{{ + Name: "foo", + Value: "value-$(inputs.params.FOO)", + }, { + Name: "bar", + ValueFrom: &corev1.EnvVarSource{ + ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{Name: "config-$(inputs.params.FOO)"}, + Key: "config-key-$(inputs.params.FOO)", + }, + }, + }, { + Name: "baz", + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{Name: "secret-$(inputs.params.FOO)"}, + Key: "secret-key-$(inputs.params.FOO)", + }, + }, + }}, + EnvFrom: []corev1.EnvFromSource{{ + Prefix: "prefix-0-$(inputs.params.FOO)", + ConfigMapRef: &corev1.ConfigMapEnvSource{ + LocalObjectReference: corev1.LocalObjectReference{Name: "config-$(inputs.params.FOO)"}, + }, + }, { + Prefix: "prefix-1-$(inputs.params.FOO)", + SecretRef: &corev1.SecretEnvSource{ + LocalObjectReference: corev1.LocalObjectReference{Name: "secret-$(inputs.params.FOO)"}, + }, + }}, + }}, {Container: corev1.Container{ + Name: "outputs-resources-path-ab", + Image: "$(outputs.resources.imageToUse-ab.path)", + }}, {Container: corev1.Container{ + Name: "outputs-resources-path-re", + Image: "$(outputs.resources.imageToUse-re.path)", + }}}, + Volumes: []corev1.Volume{{ + Name: "$(inputs.params.FOO)", + VolumeSource: corev1.VolumeSource{ + ConfigMap: &corev1.ConfigMapVolumeSource{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "$(inputs.params.FOO)", + }, + }, + }, + }, { + Name: "some-secret", + VolumeSource: corev1.VolumeSource{ + Secret: &corev1.SecretVolumeSource{ + SecretName: "$(inputs.params.FOO)", + }, + }, + }, { + Name: "some-pvc", + VolumeSource: corev1.VolumeSource{ + PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ + ClaimName: "$(inputs.params.FOO)", + }, + }, + }}, + }, Inputs: &v1alpha1.Inputs{ Resources: []v1alpha1.TaskResource{{ ResourceDeclaration: v1alpha1.ResourceDeclaration{ @@ -64,122 +180,16 @@ var ( }, }}, }, - Sidecars: []v1alpha1.Sidecar{{ - Container: corev1.Container{ - Name: "foo", - Image: "$(inputs.params.myimage)", - Env: []corev1.EnvVar{{ - Name: "foo", - Value: "$(inputs.params.FOO)", - }}, - }, - }}, - StepTemplate: &corev1.Container{ - Env: []corev1.EnvVar{{ - Name: "template-var", - Value: "$(inputs.params.FOO)", - }}, - }, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "foo", - Image: "$(inputs.params.myimage)", - }}, {Container: corev1.Container{ - Name: "baz", - Image: "bat", - WorkingDir: "$(inputs.resources.workspace.path)", - Args: []string{"$(inputs.resources.workspace.url)"}, - }}, {Container: corev1.Container{ - Name: "qux", - Image: "$(inputs.params.something)", - Args: []string{"$(outputs.resources.imageToUse.url)"}, - }}, {Container: corev1.Container{ - Name: "foo", - Image: "$(inputs.params.myimage)", - }}, {Container: corev1.Container{ - Name: "baz", - Image: "$(inputs.params.somethingelse)", - WorkingDir: "$(inputs.resources.workspace.path)", - Args: []string{"$(inputs.resources.workspace.url)"}, - }}, {Container: corev1.Container{ - Name: "qux", - Image: "quux", - Args: []string{"$(outputs.resources.imageToUse.url)"}, - }}, {Container: corev1.Container{ - Name: "foo", - Image: "busybox:$(inputs.params.FOO)", - VolumeMounts: []corev1.VolumeMount{{ - Name: "$(inputs.params.FOO)", - MountPath: "path/to/$(inputs.params.FOO)", - SubPath: "sub/$(inputs.params.FOO)/path", - }}, - }}, {Container: corev1.Container{ - Name: "foo", - Image: "busybox:$(inputs.params.FOO)", - Env: []corev1.EnvVar{{ - Name: "foo", - Value: "value-$(inputs.params.FOO)", - }, { - Name: "bar", - ValueFrom: &corev1.EnvVarSource{ - ConfigMapKeyRef: &corev1.ConfigMapKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{Name: "config-$(inputs.params.FOO)"}, - Key: "config-key-$(inputs.params.FOO)", - }, - }, - }, { - Name: "baz", - ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{Name: "secret-$(inputs.params.FOO)"}, - Key: "secret-key-$(inputs.params.FOO)", - }, - }, - }}, - EnvFrom: []corev1.EnvFromSource{{ - Prefix: "prefix-0-$(inputs.params.FOO)", - ConfigMapRef: &corev1.ConfigMapEnvSource{ - LocalObjectReference: corev1.LocalObjectReference{Name: "config-$(inputs.params.FOO)"}, - }, - }, { - Prefix: "prefix-1-$(inputs.params.FOO)", - SecretRef: &corev1.SecretEnvSource{ - LocalObjectReference: corev1.LocalObjectReference{Name: "secret-$(inputs.params.FOO)"}, - }, - }}, - }}, {Container: corev1.Container{ - Name: "outputs-resources-path-ab", - Image: "$(outputs.resources.imageToUse-ab.path)", - }}, {Container: corev1.Container{ - Name: "outputs-resources-path-re", - Image: "$(outputs.resources.imageToUse-re.path)", - }}}, - Volumes: []corev1.Volume{{ - Name: "$(inputs.params.FOO)", - VolumeSource: corev1.VolumeSource{ - ConfigMap: &corev1.ConfigMapVolumeSource{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: "$(inputs.params.FOO)", - }, - }, - }, - }, { - Name: "some-secret", - VolumeSource: corev1.VolumeSource{ - Secret: &corev1.SecretVolumeSource{ - SecretName: "$(inputs.params.FOO)", - }, - }, - }, { - Name: "some-pvc", - VolumeSource: corev1.VolumeSource{ - PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ - ClaimName: "$(inputs.params.FOO)", - }, - }, - }}, } gcsTaskSpec = &v1alpha1.TaskSpec{ + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "foobar", + Image: "someImage", + Args: []string{"$(outputs.resources.bucket.path)"}, + }}}, + }, Outputs: &v1alpha1.Outputs{ Resources: []v1alpha1.TaskResource{{ ResourceDeclaration: v1alpha1.ResourceDeclaration{ @@ -187,14 +197,9 @@ var ( }, }}, }, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "foobar", - Image: "someImage", - Args: []string{"$(outputs.resources.bucket.path)"}, - }}}, } - arrayParamTaskSpec = &v1alpha1.TaskSpec{ + arrayParamTaskSpec = &v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "simple-image", Image: "some-image", @@ -204,9 +209,9 @@ var ( Command: []string{"echo"}, Args: []string{"first", "second", "$(inputs.params.array-param)", "last"}, }}}, - } + }} - arrayAndStringParamTaskSpec = &v1alpha1.TaskSpec{ + arrayAndStringParamTaskSpec = &v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "simple-image", Image: "some-image", @@ -216,9 +221,9 @@ var ( Command: []string{"echo"}, Args: []string{"$(inputs.params.normal-param)", "second", "$(inputs.params.array-param)", "last"}, }}}, - } + }} - multipleArrayParamsTaskSpec = &v1alpha1.TaskSpec{ + multipleArrayParamsTaskSpec = &v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "simple-image", Image: "some-image", @@ -228,9 +233,9 @@ var ( Command: []string{"cmd", "$(inputs.params.another-array-param)"}, Args: []string{"first", "second", "$(inputs.params.array-param)", "last"}, }}}, - } + }} - multipleArrayAndStringsParamsTaskSpec = &v1alpha1.TaskSpec{ + multipleArrayAndStringsParamsTaskSpec = &v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "simple-image", Image: "image-$(inputs.params.string-param2)", @@ -240,7 +245,7 @@ var ( Command: []string{"cmd", "$(inputs.params.array-param1)"}, Args: []string{"$(inputs.params.array-param2)", "second", "$(inputs.params.array-param1)", "$(inputs.params.string-param1)", "last"}, }}}, - } + }} arrayTaskRun0Elements = &v1alpha1.TaskRun{ Spec: v1alpha1.TaskRunSpec{ @@ -614,7 +619,7 @@ func TestApplyResources(t *testing.T) { func TestApplyWorkspaces(t *testing.T) { names.TestingSeed() - ts := &v1alpha1.TaskSpec{ + ts := &v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ StepTemplate: &corev1.Container{ Env: []corev1.EnvVar{{ Name: "template-var", @@ -677,9 +682,8 @@ func TestApplyWorkspaces(t *testing.T) { ClaimName: "$(workspaces.myws.volume)", }, }, - }, - }, - } + }}, + }} want := applyMutation(ts, func(spec *v1alpha1.TaskSpec) { spec.StepTemplate.Env[0].Value = "ws-9l9zj" diff --git a/pkg/reconciler/taskrun/resources/image_exporter_test.go b/pkg/reconciler/taskrun/resources/image_exporter_test.go index a6acd2efe12..e635973e1f9 100644 --- a/pkg/reconciler/taskrun/resources/image_exporter_test.go +++ b/pkg/reconciler/taskrun/resources/image_exporter_test.go @@ -21,6 +21,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" "github.com/tektoncd/pipeline/test/names" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -40,6 +41,11 @@ func TestAddOutputImageDigestExporter(t *testing.T) { Namespace: "marshmallow", }, Spec: v1alpha1.TaskSpec{ + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "step1", + }}}, + }, Inputs: &v1alpha1.Inputs{ Resources: []v1alpha1.TaskResource{{ ResourceDeclaration: v1alpha1.ResourceDeclaration{ @@ -55,9 +61,6 @@ func TestAddOutputImageDigestExporter(t *testing.T) { }, }}, }, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "step1", - }}}, }, }, taskRun: &v1alpha1.TaskRun{ @@ -105,6 +108,13 @@ func TestAddOutputImageDigestExporter(t *testing.T) { Namespace: "marshmallow", }, Spec: v1alpha1.TaskSpec{ + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "step1", + }}, {Container: corev1.Container{ + Name: "step2", + }}}, + }, Inputs: &v1alpha1.Inputs{ Resources: []v1alpha1.TaskResource{{ ResourceDeclaration: v1alpha1.ResourceDeclaration{ @@ -120,11 +130,6 @@ func TestAddOutputImageDigestExporter(t *testing.T) { }, }}, }, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "step1", - }}, {Container: corev1.Container{ - Name: "step2", - }}}, }, }, taskRun: &v1alpha1.TaskRun{ diff --git a/pkg/reconciler/taskrun/resources/input_resource_test.go b/pkg/reconciler/taskrun/resources/input_resource_test.go index 770aaac8410..e19b0b75de7 100644 --- a/pkg/reconciler/taskrun/resources/input_resource_test.go +++ b/pkg/reconciler/taskrun/resources/input_resource_test.go @@ -22,6 +22,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/tektoncd/pipeline/pkg/apis/pipeline" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" "github.com/tektoncd/pipeline/pkg/artifacts" "github.com/tektoncd/pipeline/pkg/logging" "github.com/tektoncd/pipeline/test/names" @@ -359,14 +360,16 @@ func TestAddResourceToTask(t *testing.T) { wantErr: false, want: &v1alpha1.TaskSpec{ Inputs: gitInputs, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "git-source-the-git-9l9zj", - Image: "override-with-git:latest", - Command: []string{"/ko-app/git-init"}, - Args: []string{"-url", "https://github.com/grafeas/kritis", "-revision", "master", "-path", "/workspace/gitspace"}, - WorkingDir: "/workspace", - Env: []corev1.EnvVar{{Name: "TEKTON_RESOURCE_NAME", Value: "the-git"}}, - }}}, + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "git-source-the-git-9l9zj", + Image: "override-with-git:latest", + Command: []string{"/ko-app/git-init"}, + Args: []string{"-url", "https://github.com/grafeas/kritis", "-revision", "master", "-path", "/workspace/gitspace"}, + WorkingDir: "/workspace", + Env: []corev1.EnvVar{{Name: "TEKTON_RESOURCE_NAME", Value: "the-git"}}, + }}}, + }, }, }, { desc: "simple with branch", @@ -395,14 +398,16 @@ func TestAddResourceToTask(t *testing.T) { wantErr: false, want: &v1alpha1.TaskSpec{ Inputs: gitInputs, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "git-source-the-git-with-branch-9l9zj", - Image: "override-with-git:latest", - Command: []string{"/ko-app/git-init"}, - Args: []string{"-url", "https://github.com/grafeas/kritis", "-revision", "branch", "-path", "/workspace/gitspace"}, - WorkingDir: "/workspace", - Env: []corev1.EnvVar{{Name: "TEKTON_RESOURCE_NAME", Value: "the-git-with-branch"}}, - }}}, + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "git-source-the-git-with-branch-9l9zj", + Image: "override-with-git:latest", + Command: []string{"/ko-app/git-init"}, + Args: []string{"-url", "https://github.com/grafeas/kritis", "-revision", "branch", "-path", "/workspace/gitspace"}, + WorkingDir: "/workspace", + Env: []corev1.EnvVar{{Name: "TEKTON_RESOURCE_NAME", Value: "the-git-with-branch"}}, + }}}, + }, }, }, { desc: "reuse git input resource and verify order", @@ -438,21 +443,23 @@ func TestAddResourceToTask(t *testing.T) { wantErr: false, want: &v1alpha1.TaskSpec{ Inputs: multipleGitInputs, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "git-source-the-git-with-branch-mz4c7", - Image: "override-with-git:latest", - Command: []string{"/ko-app/git-init"}, - Args: []string{"-url", "https://github.com/grafeas/kritis", "-revision", "branch", "-path", "/workspace/gitspace"}, - WorkingDir: "/workspace", - Env: []corev1.EnvVar{{Name: "TEKTON_RESOURCE_NAME", Value: "the-git-with-branch"}}, - }}, {Container: corev1.Container{ - Name: "git-source-the-git-with-branch-9l9zj", - Image: "override-with-git:latest", - Command: []string{"/ko-app/git-init"}, - Args: []string{"-url", "https://github.com/grafeas/kritis", "-revision", "branch", "-path", "/workspace/git-duplicate-space"}, - WorkingDir: "/workspace", - Env: []corev1.EnvVar{{Name: "TEKTON_RESOURCE_NAME", Value: "the-git-with-branch"}}, - }}}, + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "git-source-the-git-with-branch-mz4c7", + Image: "override-with-git:latest", + Command: []string{"/ko-app/git-init"}, + Args: []string{"-url", "https://github.com/grafeas/kritis", "-revision", "branch", "-path", "/workspace/gitspace"}, + WorkingDir: "/workspace", + Env: []corev1.EnvVar{{Name: "TEKTON_RESOURCE_NAME", Value: "the-git-with-branch"}}, + }}, {Container: corev1.Container{ + Name: "git-source-the-git-with-branch-9l9zj", + Image: "override-with-git:latest", + Command: []string{"/ko-app/git-init"}, + Args: []string{"-url", "https://github.com/grafeas/kritis", "-revision", "branch", "-path", "/workspace/git-duplicate-space"}, + WorkingDir: "/workspace", + Env: []corev1.EnvVar{{Name: "TEKTON_RESOURCE_NAME", Value: "the-git-with-branch"}}, + }}}, + }, }, }, { desc: "set revision to default value 1", @@ -481,14 +488,16 @@ func TestAddResourceToTask(t *testing.T) { wantErr: false, want: &v1alpha1.TaskSpec{ Inputs: gitInputs, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "git-source-the-git-9l9zj", - Image: "override-with-git:latest", - Command: []string{"/ko-app/git-init"}, - Args: []string{"-url", "https://github.com/grafeas/kritis", "-revision", "master", "-path", "/workspace/gitspace"}, - WorkingDir: "/workspace", - Env: []corev1.EnvVar{{Name: "TEKTON_RESOURCE_NAME", Value: "the-git"}}, - }}}, + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "git-source-the-git-9l9zj", + Image: "override-with-git:latest", + Command: []string{"/ko-app/git-init"}, + Args: []string{"-url", "https://github.com/grafeas/kritis", "-revision", "master", "-path", "/workspace/gitspace"}, + WorkingDir: "/workspace", + Env: []corev1.EnvVar{{Name: "TEKTON_RESOURCE_NAME", Value: "the-git"}}, + }}}, + }, }, }, { desc: "set revision to provdided branch", @@ -517,14 +526,16 @@ func TestAddResourceToTask(t *testing.T) { wantErr: false, want: &v1alpha1.TaskSpec{ Inputs: gitInputs, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "git-source-the-git-with-branch-9l9zj", - Image: "override-with-git:latest", - Command: []string{"/ko-app/git-init"}, - Args: []string{"-url", "https://github.com/grafeas/kritis", "-revision", "branch", "-path", "/workspace/gitspace"}, - WorkingDir: "/workspace", - Env: []corev1.EnvVar{{Name: "TEKTON_RESOURCE_NAME", Value: "the-git-with-branch"}}, - }}}, + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "git-source-the-git-with-branch-9l9zj", + Image: "override-with-git:latest", + Command: []string{"/ko-app/git-init"}, + Args: []string{"-url", "https://github.com/grafeas/kritis", "-revision", "branch", "-path", "/workspace/gitspace"}, + WorkingDir: "/workspace", + Env: []corev1.EnvVar{{Name: "TEKTON_RESOURCE_NAME", Value: "the-git-with-branch"}}, + }}}, + }, }, }, { desc: "git resource as input from previous task", @@ -555,22 +566,24 @@ func TestAddResourceToTask(t *testing.T) { wantErr: false, want: &v1alpha1.TaskSpec{ Inputs: gitInputs, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "create-dir-gitspace-mz4c7", - Image: "busybox", - Command: []string{"mkdir", "-p", "/workspace/gitspace"}, - }}, {Container: corev1.Container{ - Name: "source-copy-gitspace-9l9zj", - Image: "busybox", - Command: []string{"cp", "-r", "prev-task-path/.", "/workspace/gitspace"}, - VolumeMounts: []corev1.VolumeMount{{MountPath: "/pvc", Name: "pipelinerun-pvc"}}, - }}}, - Volumes: []corev1.Volume{{ - Name: "pipelinerun-pvc", - VolumeSource: corev1.VolumeSource{ - PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ClaimName: "pipelinerun-pvc"}, - }, - }}, + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "create-dir-gitspace-mz4c7", + Image: "busybox", + Command: []string{"mkdir", "-p", "/workspace/gitspace"}, + }}, {Container: corev1.Container{ + Name: "source-copy-gitspace-9l9zj", + Image: "busybox", + Command: []string{"cp", "-r", "prev-task-path/.", "/workspace/gitspace"}, + VolumeMounts: []corev1.VolumeMount{{MountPath: "/pvc", Name: "pipelinerun-pvc"}}, + }}}, + Volumes: []corev1.Volume{{ + Name: "pipelinerun-pvc", + VolumeSource: corev1.VolumeSource{ + PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ClaimName: "pipelinerun-pvc"}, + }, + }}, + }, }, }, { desc: "simple with sslVerify false", @@ -599,14 +612,16 @@ func TestAddResourceToTask(t *testing.T) { wantErr: false, want: &v1alpha1.TaskSpec{ Inputs: gitInputs, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "git-source-the-git-with-sslVerify-false-9l9zj", - Image: "override-with-git:latest", - Command: []string{"/ko-app/git-init"}, - Args: []string{"-url", "https://github.com/grafeas/kritis", "-revision", "branch", "-path", "/workspace/gitspace", "-sslVerify=false"}, - WorkingDir: "/workspace", - Env: []corev1.EnvVar{{Name: "TEKTON_RESOURCE_NAME", Value: "the-git-with-sslVerify-false"}}, - }}}, + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "git-source-the-git-with-sslVerify-false-9l9zj", + Image: "override-with-git:latest", + Command: []string{"/ko-app/git-init"}, + Args: []string{"-url", "https://github.com/grafeas/kritis", "-revision", "branch", "-path", "/workspace/gitspace", "-sslVerify=false"}, + WorkingDir: "/workspace", + Env: []corev1.EnvVar{{Name: "TEKTON_RESOURCE_NAME", Value: "the-git-with-sslVerify-false"}}, + }}}, + }, }, }, { desc: "storage resource as input with target path", @@ -632,23 +647,25 @@ func TestAddResourceToTask(t *testing.T) { wantErr: false, want: &v1alpha1.TaskSpec{ Inputs: gcsInputs, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "create-dir-storage1-9l9zj", - Image: "busybox", - Command: []string{"mkdir", "-p", "/workspace/gcs-dir"}, - }}, { - Script: `#!/usr/bin/env bash + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "create-dir-storage1-9l9zj", + Image: "busybox", + Command: []string{"mkdir", "-p", "/workspace/gcs-dir"}, + }}, { + Script: `#!/usr/bin/env bash if [[ "${GOOGLE_APPLICATION_CREDENTIALS}" != "" ]]; then echo GOOGLE_APPLICATION_CREDENTIALS is set, activating Service Account... gcloud auth activate-service-account --key-file=${GOOGLE_APPLICATION_CREDENTIALS} fi gsutil cp gs://fake-bucket/rules.zip /workspace/gcs-dir `, - Container: corev1.Container{ - Name: "fetch-storage1-mz4c7", - Image: "google/cloud-sdk", - }, - }}, + Container: corev1.Container{ + Name: "fetch-storage1-mz4c7", + Image: "google/cloud-sdk", + }, + }}, + }, }, }, { desc: "storage resource as input from previous task", @@ -679,22 +696,24 @@ gsutil cp gs://fake-bucket/rules.zip /workspace/gcs-dir wantErr: false, want: &v1alpha1.TaskSpec{ Inputs: gcsInputs, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "create-dir-workspace-mz4c7", - Image: "busybox", - Command: []string{"mkdir", "-p", "/workspace/gcs-dir"}, - }}, {Container: corev1.Container{ - Name: "source-copy-workspace-9l9zj", - Image: "busybox", - Command: []string{"cp", "-r", "prev-task-path/.", "/workspace/gcs-dir"}, - VolumeMounts: []corev1.VolumeMount{{MountPath: "/pvc", Name: "pipelinerun-pvc"}}, - }}}, - Volumes: []corev1.Volume{{ - Name: "pipelinerun-pvc", - VolumeSource: corev1.VolumeSource{ - PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ClaimName: "pipelinerun-pvc"}, - }, - }}, + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "create-dir-workspace-mz4c7", + Image: "busybox", + Command: []string{"mkdir", "-p", "/workspace/gcs-dir"}, + }}, {Container: corev1.Container{ + Name: "source-copy-workspace-9l9zj", + Image: "busybox", + Command: []string{"cp", "-r", "prev-task-path/.", "/workspace/gcs-dir"}, + VolumeMounts: []corev1.VolumeMount{{MountPath: "/pvc", Name: "pipelinerun-pvc"}}, + }}}, + Volumes: []corev1.Volume{{ + Name: "pipelinerun-pvc", + VolumeSource: corev1.VolumeSource{ + PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ClaimName: "pipelinerun-pvc"}, + }, + }}, + }, }, }, { desc: "invalid gcs resource type name", @@ -794,14 +813,16 @@ gsutil cp gs://fake-bucket/rules.zip /workspace/gcs-dir wantErr: false, want: &v1alpha1.TaskSpec{ Inputs: clusterInputs, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "kubeconfig-9l9zj", - Image: "override-with-kubeconfig-writer:latest", - Command: []string{"/ko-app/kubeconfigwriter"}, - Args: []string{ - "-clusterConfig", `{"name":"cluster3","type":"cluster","url":"http://10.10.10.10","revision":"","username":"","password":"","namespace":"namespace1","token":"","Insecure":false,"cadata":"bXktY2EtY2VydAo=","secrets":null}`, - }, - }}}, + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "kubeconfig-9l9zj", + Image: "override-with-kubeconfig-writer:latest", + Command: []string{"/ko-app/kubeconfigwriter"}, + Args: []string{ + "-clusterConfig", `{"name":"cluster3","type":"cluster","url":"http://10.10.10.10","revision":"","username":"","password":"","namespace":"namespace1","token":"","Insecure":false,"cadata":"bXktY2EtY2VydAo=","secrets":null}`, + }, + }}}, + }, }, }, { desc: "cluster resource with secrets", @@ -838,25 +859,27 @@ gsutil cp gs://fake-bucket/rules.zip /workspace/gcs-dir wantErr: false, want: &v1alpha1.TaskSpec{ Inputs: clusterInputs, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "kubeconfig-9l9zj", - Image: "override-with-kubeconfig-writer:latest", - Command: []string{"/ko-app/kubeconfigwriter"}, - Args: []string{ - "-clusterConfig", `{"name":"cluster2","type":"cluster","url":"http://10.10.10.10","revision":"","username":"","password":"","namespace":"","token":"","Insecure":false,"cadata":null,"secrets":[{"fieldName":"cadata","secretKey":"cadatakey","secretName":"secret1"}]}`, - }, - Env: []corev1.EnvVar{{ - ValueFrom: &corev1.EnvVarSource{ - SecretKeyRef: &corev1.SecretKeySelector{ - LocalObjectReference: corev1.LocalObjectReference{ - Name: "secret1", - }, - Key: "cadatakey", - }, + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "kubeconfig-9l9zj", + Image: "override-with-kubeconfig-writer:latest", + Command: []string{"/ko-app/kubeconfigwriter"}, + Args: []string{ + "-clusterConfig", `{"name":"cluster2","type":"cluster","url":"http://10.10.10.10","revision":"","username":"","password":"","namespace":"","token":"","Insecure":false,"cadata":null,"secrets":[{"fieldName":"cadata","secretKey":"cadatakey","secretName":"secret1"}]}`, }, - Name: "CADATA", - }}, - }}}, + Env: []corev1.EnvVar{{ + ValueFrom: &corev1.EnvVarSource{ + SecretKeyRef: &corev1.SecretKeySelector{ + LocalObjectReference: corev1.LocalObjectReference{ + Name: "secret1", + }, + Key: "cadatakey", + }, + }, + Name: "CADATA", + }}, + }}}, + }, }, }, { desc: "optional git input resource", @@ -885,14 +908,16 @@ gsutil cp gs://fake-bucket/rules.zip /workspace/gcs-dir wantErr: false, want: &v1alpha1.TaskSpec{ Inputs: optionalGitInputs, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "git-source-the-git-with-branch-9l9zj", - Image: "override-with-git:latest", - Command: []string{"/ko-app/git-init"}, - Args: []string{"-url", "https://github.com/grafeas/kritis", "-revision", "branch", "-path", "/workspace/gitspace"}, - WorkingDir: "/workspace", - Env: []corev1.EnvVar{{Name: "TEKTON_RESOURCE_NAME", Value: "the-git-with-branch"}}, - }}}, + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "git-source-the-git-with-branch-9l9zj", + Image: "override-with-git:latest", + Command: []string{"/ko-app/git-init"}, + Args: []string{"-url", "https://github.com/grafeas/kritis", "-revision", "branch", "-path", "/workspace/gitspace"}, + WorkingDir: "/workspace", + Env: []corev1.EnvVar{{Name: "TEKTON_RESOURCE_NAME", Value: "the-git-with-branch"}}, + }}}, + }, }, }} { t.Run(c.desc, func(t *testing.T) { @@ -999,23 +1024,25 @@ func TestStorageInputResource(t *testing.T) { wantErr: false, want: &v1alpha1.TaskSpec{ Inputs: gcsStorageInputs, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "create-dir-gcs-input-resource-9l9zj", - Image: "busybox", - Command: []string{"mkdir", "-p", "/workspace/gcs-input-resource"}, - }}, { - Script: `#!/usr/bin/env bash + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "create-dir-gcs-input-resource-9l9zj", + Image: "busybox", + Command: []string{"mkdir", "-p", "/workspace/gcs-input-resource"}, + }}, { + Script: `#!/usr/bin/env bash if [[ "${GOOGLE_APPLICATION_CREDENTIALS}" != "" ]]; then echo GOOGLE_APPLICATION_CREDENTIALS is set, activating Service Account... gcloud auth activate-service-account --key-file=${GOOGLE_APPLICATION_CREDENTIALS} fi gsutil cp gs://fake-bucket/rules.zip /workspace/gcs-input-resource `, - Container: corev1.Container{ - Name: "fetch-gcs-input-resource-mz4c7", - Image: "google/cloud-sdk", - }, - }}, + Container: corev1.Container{ + Name: "fetch-gcs-input-resource-mz4c7", + Image: "google/cloud-sdk", + }, + }}, + }, }, }, { desc: "no inputs", @@ -1065,36 +1092,38 @@ gsutil cp gs://fake-bucket/rules.zip /workspace/gcs-input-resource wantErr: false, want: &v1alpha1.TaskSpec{ Inputs: gcsStorageInputs, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "create-dir-storage-gcs-keys-9l9zj", - Image: "busybox", - Command: []string{"mkdir", "-p", "/workspace/gcs-input-resource"}, - }}, { - Script: `#!/usr/bin/env bash + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "create-dir-storage-gcs-keys-9l9zj", + Image: "busybox", + Command: []string{"mkdir", "-p", "/workspace/gcs-input-resource"}, + }}, { + Script: `#!/usr/bin/env bash if [[ "${GOOGLE_APPLICATION_CREDENTIALS}" != "" ]]; then echo GOOGLE_APPLICATION_CREDENTIALS is set, activating Service Account... gcloud auth activate-service-account --key-file=${GOOGLE_APPLICATION_CREDENTIALS} fi gsutil rsync -d -r gs://fake-bucket/rules.zip /workspace/gcs-input-resource `, - Container: corev1.Container{ - Name: "fetch-storage-gcs-keys-mz4c7", - Image: "google/cloud-sdk", - VolumeMounts: []corev1.VolumeMount{ - {Name: "volume-storage-gcs-keys-secret-name", MountPath: "/var/secret/secret-name"}, - }, - Env: []corev1.EnvVar{ - {Name: "GOOGLE_APPLICATION_CREDENTIALS", Value: "/var/secret/secret-name/key.json"}, - }, - }, - }}, - Volumes: []corev1.Volume{{ - Name: "volume-storage-gcs-keys-secret-name", - VolumeSource: corev1.VolumeSource{Secret: &corev1.SecretVolumeSource{SecretName: "secret-name"}}, - }, { - Name: "volume-storage-gcs-keys-secret-name2", - VolumeSource: corev1.VolumeSource{Secret: &corev1.SecretVolumeSource{SecretName: "secret-name2"}}, - }}, + Container: corev1.Container{ + Name: "fetch-storage-gcs-keys-mz4c7", + Image: "google/cloud-sdk", + VolumeMounts: []corev1.VolumeMount{ + {Name: "volume-storage-gcs-keys-secret-name", MountPath: "/var/secret/secret-name"}, + }, + Env: []corev1.EnvVar{ + {Name: "GOOGLE_APPLICATION_CREDENTIALS", Value: "/var/secret/secret-name/key.json"}, + }, + }, + }}, + Volumes: []corev1.Volume{{ + Name: "volume-storage-gcs-keys-secret-name", + VolumeSource: corev1.VolumeSource{Secret: &corev1.SecretVolumeSource{SecretName: "secret-name"}}, + }, { + Name: "volume-storage-gcs-keys-secret-name2", + VolumeSource: corev1.VolumeSource{Secret: &corev1.SecretVolumeSource{SecretName: "secret-name2"}}, + }}, + }, }, }, { desc: "optional inputs with no resource spec and no resource ref", @@ -1118,7 +1147,9 @@ gsutil rsync -d -r gs://fake-bucket/rules.zip /workspace/gcs-input-resource wantErr: false, want: &v1alpha1.TaskSpec{ Inputs: optionalStorageInputs, - Steps: nil, + TaskSpec: v1alpha2.TaskSpec{ + Steps: nil, + }, }, }} { t.Run(c.desc, func(t *testing.T) { @@ -1216,19 +1247,21 @@ func TestAddStepsToTaskWithBucketFromConfigMap(t *testing.T) { }, want: &v1alpha1.TaskSpec{ Inputs: gitInputs, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "artifact-dest-mkdir-gitspace-9l9zj", - Image: "busybox", - Command: []string{"mkdir", "-p", "/workspace/gitspace"}, - }}, {Container: corev1.Container{ - Name: "artifact-copy-from-gitspace-mz4c7", - Image: "google/cloud-sdk", - Command: []string{"gsutil"}, - Args: []string{"cp", "-P", "-r", "gs://fake-bucket/prev-task-path/*", "/workspace/gitspace"}, - Env: gcsEnv, - VolumeMounts: gcsVolumeMounts, - }}}, - Volumes: gcsVolumes, + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "artifact-dest-mkdir-gitspace-9l9zj", + Image: "busybox", + Command: []string{"mkdir", "-p", "/workspace/gitspace"}, + }}, {Container: corev1.Container{ + Name: "artifact-copy-from-gitspace-mz4c7", + Image: "google/cloud-sdk", + Command: []string{"gsutil"}, + Args: []string{"cp", "-P", "-r", "gs://fake-bucket/prev-task-path/*", "/workspace/gitspace"}, + Env: gcsEnv, + VolumeMounts: gcsVolumeMounts, + }}}, + Volumes: gcsVolumes, + }, }, }, { desc: "storage resource as input from previous task - copy from bucket", @@ -1258,19 +1291,21 @@ func TestAddStepsToTaskWithBucketFromConfigMap(t *testing.T) { }, want: &v1alpha1.TaskSpec{ Inputs: gcsInputs, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "artifact-dest-mkdir-workspace-mssqb", - Image: "busybox", - Command: []string{"mkdir", "-p", "/workspace/gcs-dir"}, - }}, {Container: corev1.Container{ - Name: "artifact-copy-from-workspace-78c5n", - Image: "google/cloud-sdk", - Command: []string{"gsutil"}, - Args: []string{"cp", "-P", "-r", "gs://fake-bucket/prev-task-path/*", "/workspace/gcs-dir"}, - Env: gcsEnv, - VolumeMounts: gcsVolumeMounts, - }}}, - Volumes: gcsVolumes, + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "artifact-dest-mkdir-workspace-mssqb", + Image: "busybox", + Command: []string{"mkdir", "-p", "/workspace/gcs-dir"}, + }}, {Container: corev1.Container{ + Name: "artifact-copy-from-workspace-78c5n", + Image: "google/cloud-sdk", + Command: []string{"gsutil"}, + Args: []string{"cp", "-P", "-r", "gs://fake-bucket/prev-task-path/*", "/workspace/gcs-dir"}, + Env: gcsEnv, + VolumeMounts: gcsVolumeMounts, + }}}, + Volumes: gcsVolumes, + }, }, }, { desc: "storage resource with multiple inputs from previous task - copy from bucket", @@ -1308,30 +1343,32 @@ func TestAddStepsToTaskWithBucketFromConfigMap(t *testing.T) { }, want: &v1alpha1.TaskSpec{ Inputs: multipleGcsInputs, - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "artifact-dest-mkdir-workspace-vr6ds", - Image: "busybox", - Command: []string{"mkdir", "-p", "/workspace/gcs-dir"}, - }}, {Container: corev1.Container{ - Name: "artifact-copy-from-workspace-l22wn", - Image: "google/cloud-sdk", - Command: []string{"gsutil"}, - Args: []string{"cp", "-P", "-r", "gs://fake-bucket/prev-task-path/*", "/workspace/gcs-dir"}, - Env: gcsEnv, - VolumeMounts: gcsVolumeMounts, - }}, {Container: corev1.Container{ - Name: "artifact-dest-mkdir-workspace2-6nl7g", - Image: "busybox", - Command: []string{"mkdir", "-p", "/workspace/gcs-dir"}, - }}, {Container: corev1.Container{ - Name: "artifact-copy-from-workspace2-j2tds", - Image: "google/cloud-sdk", - Command: []string{"gsutil"}, - Args: []string{"cp", "-P", "-r", "gs://fake-bucket/prev-task-path2/*", "/workspace/gcs-dir"}, - Env: gcsEnv, - VolumeMounts: gcsVolumeMounts, - }}}, - Volumes: gcsVolumes, + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "artifact-dest-mkdir-workspace-vr6ds", + Image: "busybox", + Command: []string{"mkdir", "-p", "/workspace/gcs-dir"}, + }}, {Container: corev1.Container{ + Name: "artifact-copy-from-workspace-l22wn", + Image: "google/cloud-sdk", + Command: []string{"gsutil"}, + Args: []string{"cp", "-P", "-r", "gs://fake-bucket/prev-task-path/*", "/workspace/gcs-dir"}, + Env: gcsEnv, + VolumeMounts: gcsVolumeMounts, + }}, {Container: corev1.Container{ + Name: "artifact-dest-mkdir-workspace2-6nl7g", + Image: "busybox", + Command: []string{"mkdir", "-p", "/workspace/gcs-dir"}, + }}, {Container: corev1.Container{ + Name: "artifact-copy-from-workspace2-j2tds", + Image: "google/cloud-sdk", + Command: []string{"gsutil"}, + Args: []string{"cp", "-P", "-r", "gs://fake-bucket/prev-task-path2/*", "/workspace/gcs-dir"}, + Env: gcsEnv, + VolumeMounts: gcsVolumeMounts, + }}}, + Volumes: gcsVolumes, + }, }, }} { t.Run(c.desc, func(t *testing.T) { diff --git a/pkg/reconciler/taskrun/resources/taskresourceresolution_test.go b/pkg/reconciler/taskrun/resources/taskresourceresolution_test.go index 36e387fb3b3..342214c9bc2 100644 --- a/pkg/reconciler/taskrun/resources/taskresourceresolution_test.go +++ b/pkg/reconciler/taskrun/resources/taskresourceresolution_test.go @@ -22,6 +22,7 @@ import ( "testing" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -75,11 +76,11 @@ func TestResolveTaskRun(t *testing.T) { taskName := "orchestrate" kind := v1alpha1.NamespacedTaskKind - taskSpec := v1alpha1.TaskSpec{ + taskSpec := v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "step1", }}}, - } + }} resources := []*v1alpha1.PipelineResource{{ ObjectMeta: metav1.ObjectMeta{ @@ -197,11 +198,11 @@ func TestResolveTaskRun_missingInput(t *testing.T) { } func TestResolveTaskRun_noResources(t *testing.T) { - taskSpec := v1alpha1.TaskSpec{ + taskSpec := v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "step1", }}}, - } + }} gr := func(n string) (*v1alpha1.PipelineResource, error) { return &v1alpha1.PipelineResource{}, nil } diff --git a/pkg/reconciler/taskrun/resources/taskspec_test.go b/pkg/reconciler/taskrun/resources/taskspec_test.go index e902da2b7d6..9a95ebd7c5d 100644 --- a/pkg/reconciler/taskrun/resources/taskspec_test.go +++ b/pkg/reconciler/taskrun/resources/taskspec_test.go @@ -21,6 +21,7 @@ import ( "testing" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -30,11 +31,11 @@ func TestGetTaskSpec_Ref(t *testing.T) { ObjectMeta: metav1.ObjectMeta{ Name: "orchestrate", }, - Spec: v1alpha1.TaskSpec{ + Spec: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "step1", }}}, - }, + }}, } tr := &v1alpha1.TaskRun{ ObjectMeta: metav1.ObjectMeta{ @@ -68,11 +69,11 @@ func TestGetTaskSpec_Embedded(t *testing.T) { Name: "mytaskrun", }, Spec: v1alpha1.TaskRunSpec{ - TaskSpec: &v1alpha1.TaskSpec{ + TaskSpec: &v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "step1", }}}, - }, + }}, }, } gt := func(n string) (v1alpha1.TaskInterface, error) { return nil, errors.New("shouldn't be called") } diff --git a/pkg/workspace/apply_test.go b/pkg/workspace/apply_test.go index 983f0f4a8c2..3471cb9041c 100644 --- a/pkg/workspace/apply_test.go +++ b/pkg/workspace/apply_test.go @@ -5,6 +5,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" "github.com/tektoncd/pipeline/pkg/workspace" "github.com/tektoncd/pipeline/test/names" corev1 "k8s.io/api/core/v1" @@ -201,11 +202,11 @@ func TestApply(t *testing.T) { expectedTaskSpec v1alpha1.TaskSpec }{{ name: "binding a single workspace with a PVC", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Workspaces: []v1alpha1.WorkspaceDeclaration{{ Name: "custom", }}, - }, + }}, workspaces: []v1alpha1.WorkspaceBinding{{ Name: "custom", PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ @@ -213,7 +214,7 @@ func TestApply(t *testing.T) { }, SubPath: "/foo/bar/baz", }}, - expectedTaskSpec: v1alpha1.TaskSpec{ + expectedTaskSpec: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ StepTemplate: &corev1.Container{ VolumeMounts: []corev1.VolumeMount{{ Name: "ws-9l9zj", @@ -232,14 +233,14 @@ func TestApply(t *testing.T) { Workspaces: []v1alpha1.WorkspaceDeclaration{{ Name: "custom", }}, - }, + }}, }, { name: "binding a single workspace with emptyDir", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Workspaces: []v1alpha1.WorkspaceDeclaration{{ Name: "custom", }}, - }, + }}, workspaces: []v1alpha1.WorkspaceBinding{{ Name: "custom", EmptyDir: &corev1.EmptyDirVolumeSource{ @@ -247,7 +248,7 @@ func TestApply(t *testing.T) { }, SubPath: "/foo/bar/baz", }}, - expectedTaskSpec: v1alpha1.TaskSpec{ + expectedTaskSpec: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ StepTemplate: &corev1.Container{ VolumeMounts: []corev1.VolumeMount{{ Name: "ws-mz4c7", @@ -266,10 +267,10 @@ func TestApply(t *testing.T) { Workspaces: []v1alpha1.WorkspaceDeclaration{{ Name: "custom", }}, - }, + }}, }, { name: "task spec already has volumes and stepTemplate", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ StepTemplate: &corev1.Container{ VolumeMounts: []corev1.VolumeMount{{ Name: "awesome-volume", @@ -285,7 +286,7 @@ func TestApply(t *testing.T) { Workspaces: []v1alpha1.WorkspaceDeclaration{{ Name: "custom", }}, - }, + }}, workspaces: []v1alpha1.WorkspaceBinding{{ Name: "custom", EmptyDir: &corev1.EmptyDirVolumeSource{ @@ -293,7 +294,7 @@ func TestApply(t *testing.T) { }, SubPath: "/foo/bar/baz", }}, - expectedTaskSpec: v1alpha1.TaskSpec{ + expectedTaskSpec: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ StepTemplate: &corev1.Container{ VolumeMounts: []corev1.VolumeMount{{ Name: "awesome-volume", @@ -320,31 +321,31 @@ func TestApply(t *testing.T) { Workspaces: []v1alpha1.WorkspaceDeclaration{{ Name: "custom", }}, - }, + }}, }, { name: "0 workspace bindings", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{ Container: corev1.Container{ Name: "foo", }}}, - }, + }}, workspaces: []v1alpha1.WorkspaceBinding{}, - expectedTaskSpec: v1alpha1.TaskSpec{ + expectedTaskSpec: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{ Container: corev1.Container{ Name: "foo", }}}, - }, + }}, }, { name: "binding multiple workspaces", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Workspaces: []v1alpha1.WorkspaceDeclaration{{ Name: "custom", }, { Name: "even-more-custom", }}, - }, + }}, workspaces: []v1alpha1.WorkspaceBinding{{ Name: "custom", PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ @@ -357,7 +358,7 @@ func TestApply(t *testing.T) { ClaimName: "myotherpvc", }, }}, - expectedTaskSpec: v1alpha1.TaskSpec{ + expectedTaskSpec: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ StepTemplate: &corev1.Container{ VolumeMounts: []corev1.VolumeMount{{ Name: "ws-78c5n", @@ -388,16 +389,16 @@ func TestApply(t *testing.T) { Name: "custom"}, { Name: "even-more-custom", }}, - }, + }}, }, { name: "multiple workspaces binding to the same volume with diff subpaths doesnt duplicate", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Workspaces: []v1alpha1.WorkspaceDeclaration{{ Name: "custom", }, { Name: "custom2", }}, - }, + }}, workspaces: []v1alpha1.WorkspaceBinding{{ Name: "custom", PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ @@ -411,7 +412,7 @@ func TestApply(t *testing.T) { }, SubPath: "/very/professional/work/space", }}, - expectedTaskSpec: v1alpha1.TaskSpec{ + expectedTaskSpec: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ StepTemplate: &corev1.Container{ VolumeMounts: []corev1.VolumeMount{{ Name: "ws-j2tds", @@ -436,22 +437,22 @@ func TestApply(t *testing.T) { }, { Name: "custom2", }}, - }, + }}, }, { name: "non default mount path", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Workspaces: []v1alpha1.WorkspaceDeclaration{{ Name: "custom", MountPath: "/my/fancy/mount/path", }}, - }, + }}, workspaces: []v1alpha1.WorkspaceBinding{{ Name: "custom", PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ ClaimName: "mypvc", }, }}, - expectedTaskSpec: v1alpha1.TaskSpec{ + expectedTaskSpec: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ StepTemplate: &corev1.Container{ VolumeMounts: []corev1.VolumeMount{{ Name: "ws-l22wn", @@ -470,23 +471,23 @@ func TestApply(t *testing.T) { Name: "custom", MountPath: "/my/fancy/mount/path", }}, - }, + }}, }, { name: "readOnly true marks volume mount readOnly", - ts: v1alpha1.TaskSpec{ + ts: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Workspaces: []v1alpha1.WorkspaceDeclaration{{ Name: "custom", MountPath: "/my/fancy/mount/path", ReadOnly: true, }}, - }, + }}, workspaces: []v1alpha1.WorkspaceBinding{{ Name: "custom", PersistentVolumeClaim: &corev1.PersistentVolumeClaimVolumeSource{ ClaimName: "mypvc", }, }}, - expectedTaskSpec: v1alpha1.TaskSpec{ + expectedTaskSpec: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ StepTemplate: &corev1.Container{ VolumeMounts: []corev1.VolumeMount{{ Name: "ws-twkr2", @@ -507,7 +508,7 @@ func TestApply(t *testing.T) { MountPath: "/my/fancy/mount/path", ReadOnly: true, }}, - }, + }}, }} { t.Run(tc.name, func(t *testing.T) { ts, err := workspace.Apply(tc.ts, tc.workspaces) diff --git a/test/builder/pipeline_test.go b/test/builder/pipeline_test.go index 63dfbc0797d..23a739a9430 100644 --- a/test/builder/pipeline_test.go +++ b/test/builder/pipeline_test.go @@ -27,6 +27,7 @@ import ( duckv1beta1 "knative.dev/pkg/apis/duck/v1beta1" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" tb "github.com/tektoncd/pipeline/test/builder" ) @@ -54,11 +55,12 @@ func TestPipeline(t *testing.T) { tb.PipelineTask("never-gonna", "give-you-up", tb.RunAfter("foo"), ), - tb.PipelineTask("foo", "", tb.PipelineTaskSpec(&v1alpha1.TaskSpec{ + tb.PipelineTask("foo", "", tb.PipelineTaskSpec(&v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "step", Image: "myimage", - }}}}, + }}}, + }}, )), tb.PipelineWorkspaceDeclaration("workspace1"), ), @@ -132,13 +134,12 @@ func TestPipeline(t *testing.T) { RunAfter: []string{"foo"}, }, { Name: "foo", - TaskSpec: &v1alpha1.TaskSpec{ + TaskSpec: &v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Name: "step", Image: "myimage", - }}, - }, - }, + }}}, + }}, }}, Workspaces: []v1alpha1.WorkspacePipelineDeclaration{{ Name: "workspace1", diff --git a/test/builder/task_test.go b/test/builder/task_test.go index 11a5cd96a59..abc3cc81e1f 100644 --- a/test/builder/task_test.go +++ b/test/builder/task_test.go @@ -23,6 +23,7 @@ import ( "github.com/google/go-cmp/cmp" "github.com/tektoncd/pipeline/pkg/apis/config" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" "github.com/tektoncd/pipeline/pkg/reconciler/taskrun/resources" tb "github.com/tektoncd/pipeline/test/builder" corev1 "k8s.io/api/core/v1" @@ -67,14 +68,34 @@ func TestTask(t *testing.T) { expectedTask := &v1alpha1.Task{ ObjectMeta: metav1.ObjectMeta{Name: "test-task", Namespace: "foo"}, Spec: v1alpha1.TaskSpec{ - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Name: "mycontainer", - Image: "myimage", - Command: []string{"/mycmd"}, - Args: []string{"--my-other-arg=$(inputs.resources.workspace.url)"}, - }}, {Script: "echo foo", Container: corev1.Container{ - Image: "myimage2", - }}}, + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Name: "mycontainer", + Image: "myimage", + Command: []string{"/mycmd"}, + Args: []string{"--my-other-arg=$(inputs.resources.workspace.url)"}, + }}, {Script: "echo foo", Container: corev1.Container{ + Image: "myimage2", + }}}, + Volumes: []corev1.Volume{{ + Name: "foo", + VolumeSource: corev1.VolumeSource{ + HostPath: &corev1.HostPathVolumeSource{Path: "/foo/bar"}, + }, + }}, + StepTemplate: &corev1.Container{ + Env: []corev1.EnvVar{{ + Name: "FRUIT", + Value: "BANANA", + }}, + }, + Workspaces: []v1alpha1.WorkspaceDeclaration{{ + Name: "bread", + Description: "kind of bread", + MountPath: "/bread/path", + ReadOnly: false, + }}, + }, Inputs: &v1alpha1.Inputs{ Resources: []v1alpha1.TaskResource{{ ResourceDeclaration: v1alpha1.ResourceDeclaration{ @@ -112,24 +133,6 @@ func TestTask(t *testing.T) { Optional: true, }}}, }, - Volumes: []corev1.Volume{{ - Name: "foo", - VolumeSource: corev1.VolumeSource{ - HostPath: &corev1.HostPathVolumeSource{Path: "/foo/bar"}, - }, - }}, - StepTemplate: &corev1.Container{ - Env: []corev1.EnvVar{{ - Name: "FRUIT", - Value: "BANANA", - }}, - }, - Workspaces: []v1alpha1.WorkspaceDeclaration{{ - Name: "bread", - Description: "kind of bread", - MountPath: "/bread/path", - ReadOnly: false, - }}, }, } if d := cmp.Diff(expectedTask, task); d != "" { @@ -145,13 +148,13 @@ func TestClusterTask(t *testing.T) { )) expectedTask := &v1alpha1.ClusterTask{ ObjectMeta: metav1.ObjectMeta{Name: "test-clustertask"}, - Spec: v1alpha1.TaskSpec{ + Spec: v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Image: "myimage", Command: []string{"/mycmd"}, Args: []string{"--my-other-arg=$(inputs.resources.workspace.url)"}, }}}, - }, + }}, } if d := cmp.Diff(expectedTask, task); d != "" { t.Fatalf("Task diff -want, +got: %v", d) @@ -307,10 +310,12 @@ func TestTaskRunWithTaskSpec(t *testing.T) { }, Spec: v1alpha1.TaskRunSpec{ TaskSpec: &v1alpha1.TaskSpec{ - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Image: "image", - Command: []string{"/mycmd"}, - }}}, + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Image: "image", + Command: []string{"/mycmd"}, + }}}, + }, Inputs: &v1alpha1.Inputs{ Resources: []v1alpha1.TaskResource{{ ResourceDeclaration: v1alpha1.ResourceDeclaration{ @@ -351,10 +356,12 @@ func TestTaskRunWithPodTemplate(t *testing.T) { }, Spec: v1alpha1.TaskRunSpec{ TaskSpec: &v1alpha1.TaskSpec{ - Steps: []v1alpha1.Step{{Container: corev1.Container{ - Image: "image", - Command: []string{"/mycmd"}, - }}}, + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha1.Step{{Container: corev1.Container{ + Image: "image", + Command: []string{"/mycmd"}, + }}}, + }, Inputs: &v1alpha1.Inputs{ Resources: []v1alpha1.TaskResource{{ ResourceDeclaration: v1alpha1.ResourceDeclaration{ @@ -389,12 +396,12 @@ func TestResolvedTaskResources(t *testing.T) { tb.ResolvedTaskResourcesOutputs("qux", tb.PipelineResource("quux", "quuz")), ) expectedResolvedTaskResources := &resources.ResolvedTaskResources{ - TaskSpec: &v1alpha1.TaskSpec{ + TaskSpec: &v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{Container: corev1.Container{ Image: "image", Command: []string{"/mycmd"}, }}}, - }, + }}, Inputs: map[string]*v1alpha1.PipelineResource{ "foo": { ObjectMeta: metav1.ObjectMeta{ diff --git a/test/retry_test.go b/test/retry_test.go index 25a5e07d592..e4463163e21 100644 --- a/test/retry_test.go +++ b/test/retry_test.go @@ -23,6 +23,7 @@ import ( "time" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "knative.dev/pkg/apis" @@ -47,12 +48,12 @@ func TestTaskRunRetry(t *testing.T) { PipelineSpec: &v1alpha1.PipelineSpec{ Tasks: []v1alpha1.PipelineTask{{ Name: "retry-me", - TaskSpec: &v1alpha1.TaskSpec{ + TaskSpec: &v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{ Container: corev1.Container{Image: "busybox"}, Script: "exit 1", }}, - }, + }}, Retries: numRetries, }}, }, diff --git a/test/start_time_test.go b/test/start_time_test.go index b370abaefc1..bcbda9d199a 100644 --- a/test/start_time_test.go +++ b/test/start_time_test.go @@ -19,6 +19,7 @@ import ( "time" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" knativetest "knative.dev/pkg/test" @@ -42,7 +43,7 @@ func TestStartTime(t *testing.T) { Namespace: namespace, }, Spec: v1alpha1.TaskRunSpec{ - TaskSpec: &v1alpha1.TaskSpec{ + TaskSpec: &v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Steps: []v1alpha1.Step{{ Container: corev1.Container{Image: "ubuntu"}, Script: "sleep 10", @@ -59,7 +60,7 @@ func TestStartTime(t *testing.T) { Container: corev1.Container{Image: "ubuntu"}, Script: "sleep 10", }}, - }, + }}, }, }) if err != nil { From bc0413dc3d7620992df61807468b170d9dafb143 Mon Sep 17 00:00:00 2001 From: Vincent Demeester Date: Thu, 6 Feb 2020 10:00:55 +0100 Subject: [PATCH 2/4] =?UTF-8?q?Pipeline=20auto-conversion=20from=20v1alpha?= =?UTF-8?q?1=20to=20v1alpha2=20=F0=9F=8E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds auto-conversion methods and tests for Pipeline types in v1alpha1 and v1alpha2. Signed-off-by: Vincent Demeester --- .../pipeline/v1alpha1/pipeline_conversion.go | 70 ++++++- .../v1alpha1/pipeline_conversion_test.go | 176 ++++++++++++++++++ .../v1alpha2/pipeline_conversion_test.go | 34 ++++ pkg/apis/pipeline/v1alpha2/pipeline_types.go | 13 -- .../v1alpha2/zz_generated.deepcopy.go | 21 --- .../taskrun/resources/input_resource_test.go | 4 +- 6 files changed, 280 insertions(+), 38 deletions(-) create mode 100644 pkg/apis/pipeline/v1alpha1/pipeline_conversion_test.go create mode 100644 pkg/apis/pipeline/v1alpha2/pipeline_conversion_test.go diff --git a/pkg/apis/pipeline/v1alpha1/pipeline_conversion.go b/pkg/apis/pipeline/v1alpha1/pipeline_conversion.go index 6ec1c6320e1..5990f4b09be 100644 --- a/pkg/apis/pipeline/v1alpha1/pipeline_conversion.go +++ b/pkg/apis/pipeline/v1alpha1/pipeline_conversion.go @@ -31,19 +31,85 @@ func (source *Pipeline) ConvertUp(ctx context.Context, obj apis.Convertible) err switch sink := obj.(type) { case *v1alpha2.Pipeline: sink.ObjectMeta = source.ObjectMeta - return nil // source.Spec.ConvertUp(ctx, &sink.Spec) + return source.Spec.ConvertUp(ctx, &sink.Spec) default: return fmt.Errorf("unknown version, got: %T", sink) } } +func (source *PipelineSpec) ConvertUp(ctx context.Context, sink *v1alpha2.PipelineSpec) error { + sink.Resources = source.Resources + sink.Params = source.Params + sink.Workspaces = source.Workspaces + if len(source.Tasks) > 0 { + sink.Tasks = make([]v1alpha2.PipelineTask, len(source.Tasks)) + for i := range source.Tasks { + if err := source.Tasks[i].ConvertUp(ctx, &sink.Tasks[i]); err != nil { + return err + } + } + } + return nil +} + +func (source *PipelineTask) ConvertUp(ctx context.Context, sink *v1alpha2.PipelineTask) error { + sink.Name = source.Name + sink.TaskRef = source.TaskRef + if source.TaskSpec != nil { + sink.TaskSpec = &v1alpha2.TaskSpec{} + if err := source.TaskSpec.ConvertUp(ctx, sink.TaskSpec); err != nil { + return err + } + } + sink.Conditions = source.Conditions + sink.Retries = source.Retries + sink.RunAfter = source.RunAfter + sink.Resources = source.Resources + sink.Params = source.Params + sink.Workspaces = source.Workspaces + return nil +} + // ConvertDown implements api.Convertible func (sink *Pipeline) ConvertDown(ctx context.Context, obj apis.Convertible) error { switch source := obj.(type) { case *v1alpha2.Pipeline: sink.ObjectMeta = source.ObjectMeta - return nil // sink.Spec.ConvertDown(ctx, &source.Spec) + return sink.Spec.ConvertDown(ctx, source.Spec) default: return fmt.Errorf("unknown version, got: %T", sink) } } + +func (sink *PipelineSpec) ConvertDown(ctx context.Context, source v1alpha2.PipelineSpec) error { + sink.Resources = source.Resources + sink.Params = source.Params + sink.Workspaces = source.Workspaces + if len(source.Tasks) > 0 { + sink.Tasks = make([]PipelineTask, len(source.Tasks)) + for i := range source.Tasks { + if err := sink.Tasks[i].ConvertDown(ctx, source.Tasks[i]); err != nil { + return err + } + } + } + return nil +} + +func (sink *PipelineTask) ConvertDown(ctx context.Context, source v1alpha2.PipelineTask) error { + sink.Name = source.Name + sink.TaskRef = source.TaskRef + if source.TaskSpec != nil { + sink.TaskSpec = &TaskSpec{} + if err := sink.TaskSpec.ConvertDown(ctx, source.TaskSpec); err != nil { + return err + } + } + sink.Conditions = source.Conditions + sink.Retries = source.Retries + sink.RunAfter = source.RunAfter + sink.Resources = source.Resources + sink.Params = source.Params + sink.Workspaces = source.Workspaces + return nil +} diff --git a/pkg/apis/pipeline/v1alpha1/pipeline_conversion_test.go b/pkg/apis/pipeline/v1alpha1/pipeline_conversion_test.go new file mode 100644 index 00000000000..cb23f42a84c --- /dev/null +++ b/pkg/apis/pipeline/v1alpha1/pipeline_conversion_test.go @@ -0,0 +1,176 @@ +/* +Copyright 2020 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 v1alpha1 + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" + resource "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/pkg/apis" +) + +func TestPipelineConversionBadType(t *testing.T) { + good, bad := &Pipeline{}, &Task{} + + if err := good.ConvertUp(context.Background(), bad); err == nil { + t.Errorf("ConvertUp() = %#v, wanted error", bad) + } + + if err := good.ConvertDown(context.Background(), bad); err == nil { + t.Errorf("ConvertUp() = %#v, wanted error", bad) + } +} + +func TestPipelineConversion(t *testing.T) { + versions := []apis.Convertible{&v1alpha2.Pipeline{}} + + tests := []struct { + name string + in *Pipeline + wantErr bool + }{{ + name: "simple conversion", + in: &Pipeline{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Generation: 1, + }, + Spec: PipelineSpec{ + Resources: []PipelineDeclaredResource{{ + Name: "resource1", + Type: resource.PipelineResourceTypeGit, + }, { + Name: "resource2", + Type: resource.PipelineResourceTypeImage, + }}, + Params: []ParamSpec{{ + Name: "param-1", + Type: v1alpha2.ParamTypeString, + Description: "My first param", + }}, + Workspaces: []WorkspacePipelineDeclaration{{ + Name: "workspace1", + }}, + Tasks: []PipelineTask{{ + Name: "task1", + TaskRef: &TaskRef{ + Name: "taskref", + }, + Conditions: []PipelineTaskCondition{{ + ConditionRef: "condition1", + }}, + Retries: 10, + RunAfter: []string{"task1"}, + Resources: &PipelineTaskResources{ + Inputs: []v1alpha2.PipelineTaskInputResource{{ + Name: "input1", + Resource: "resource1", + }}, + Outputs: []v1alpha2.PipelineTaskOutputResource{{ + Name: "output1", + Resource: "resource2", + }}, + }, + Params: []Param{{ + Name: "param1", + Value: v1alpha2.ArrayOrString{StringVal: "str", Type: v1alpha2.ParamTypeString}, + }}, + Workspaces: []WorkspacePipelineTaskBinding{{ + Name: "w1", + Workspace: "workspace1", + }}, + }, { + Name: "task2", + TaskSpec: &TaskSpec{TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha2.Step{{Container: corev1.Container{ + Image: "foo", + }}}, + }}, + RunAfter: []string{"task1"}, + }}, + }, + }, + }, { + name: "simple conversion with task spec error", + in: &Pipeline{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Generation: 1, + }, + Spec: PipelineSpec{ + Params: []ParamSpec{{ + Name: "param-1", + Type: v1alpha2.ParamTypeString, + Description: "My first param", + }}, + Tasks: []PipelineTask{{ + Name: "task2", + TaskSpec: &TaskSpec{ + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha2.Step{{Container: corev1.Container{ + Image: "foo", + }}}, + Resources: &v1alpha2.TaskResources{ + Inputs: []v1alpha2.TaskResource{{ResourceDeclaration: v1alpha2.ResourceDeclaration{ + Name: "input-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }, + }, + Inputs: &Inputs{ + Resources: []TaskResource{{ResourceDeclaration: ResourceDeclaration{ + Name: "input-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }}, + RunAfter: []string{"task1"}, + }}, + }, + }, + wantErr: true, + }} + + for _, test := range tests { + for _, version := range versions { + t.Run(test.name, func(t *testing.T) { + ver := version + if err := test.in.ConvertUp(context.Background(), ver); err != nil { + if !test.wantErr { + t.Errorf("ConvertUp() = %v", err) + } + return + } + t.Logf("ConvertUp() = %#v", ver) + got := &Pipeline{} + if err := got.ConvertDown(context.Background(), ver); err != nil { + t.Errorf("ConvertDown() = %v", err) + } + t.Logf("ConvertDown() = %#v", got) + if diff := cmp.Diff(test.in, got); diff != "" { + t.Errorf("roundtrip (-want, +got) = %v", diff) + } + }) + } + } +} diff --git a/pkg/apis/pipeline/v1alpha2/pipeline_conversion_test.go b/pkg/apis/pipeline/v1alpha2/pipeline_conversion_test.go new file mode 100644 index 00000000000..d24db7ba3a0 --- /dev/null +++ b/pkg/apis/pipeline/v1alpha2/pipeline_conversion_test.go @@ -0,0 +1,34 @@ +/* +Copyright 2020 The Tetkon 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 v1alpha2 + +import ( + "context" + "testing" +) + +func TestPipelineConversionBadType(t *testing.T) { + good, bad := &Pipeline{}, &Task{} + + if err := good.ConvertUp(context.Background(), bad); err == nil { + t.Errorf("ConvertUp() = %#v, wanted error", bad) + } + + if err := good.ConvertDown(context.Background(), bad); err == nil { + t.Errorf("ConvertDown() = %#v, wanted error", good) + } +} diff --git a/pkg/apis/pipeline/v1alpha2/pipeline_types.go b/pkg/apis/pipeline/v1alpha2/pipeline_types.go index 51ecca37bbe..d4154c2245f 100644 --- a/pkg/apis/pipeline/v1alpha2/pipeline_types.go +++ b/pkg/apis/pipeline/v1alpha2/pipeline_types.go @@ -36,19 +36,6 @@ type Pipeline struct { // Spec holds the desired state of the Pipeline from the client // +optional Spec PipelineSpec `json:"spec"` - - // Status is deprecated. - // It usually is used to communicate the observed state of the Pipeline from - // the controller, but was unused as there is no controller for Pipeline. - // +optional - Status *PipelineStatus `json:"status,omitempty"` -} - -// PipelineStatus does not contain anything because Pipelines on their own -// do not have a status, they just hold data which is later used by a -// PipelineRun. -// Deprecated -type PipelineStatus struct { } func (p *Pipeline) PipelineMetadata() metav1.ObjectMeta { diff --git a/pkg/apis/pipeline/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/pipeline/v1alpha2/zz_generated.deepcopy.go index 9f86545b13d..70511c0252b 100644 --- a/pkg/apis/pipeline/v1alpha2/zz_generated.deepcopy.go +++ b/pkg/apis/pipeline/v1alpha2/zz_generated.deepcopy.go @@ -270,11 +270,6 @@ func (in *Pipeline) DeepCopyInto(out *Pipeline) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - if in.Status != nil { - in, out := &in.Status, &out.Status - *out = new(PipelineStatus) - **out = **in - } return } @@ -713,22 +708,6 @@ func (in *PipelineSpec) DeepCopy() *PipelineSpec { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PipelineStatus) DeepCopyInto(out *PipelineStatus) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PipelineStatus. -func (in *PipelineStatus) DeepCopy() *PipelineStatus { - if in == nil { - return nil - } - out := new(PipelineStatus) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PipelineTask) DeepCopyInto(out *PipelineTask) { *out = *in diff --git a/pkg/reconciler/taskrun/resources/input_resource_test.go b/pkg/reconciler/taskrun/resources/input_resource_test.go index e19b0b75de7..ba55cc4501d 100644 --- a/pkg/reconciler/taskrun/resources/input_resource_test.go +++ b/pkg/reconciler/taskrun/resources/input_resource_test.go @@ -874,8 +874,8 @@ gsutil cp gs://fake-bucket/rules.zip /workspace/gcs-dir Name: "secret1", }, Key: "cadatakey", - }, }, + }, Name: "CADATA", }}, }}}, @@ -1114,7 +1114,7 @@ gsutil rsync -d -r gs://fake-bucket/rules.zip /workspace/gcs-input-resource Env: []corev1.EnvVar{ {Name: "GOOGLE_APPLICATION_CREDENTIALS", Value: "/var/secret/secret-name/key.json"}, }, - }, + }, }}, Volumes: []corev1.Volume{{ Name: "volume-storage-gcs-keys-secret-name", From c815d35dde3bd45b0c93b8568b8e5c9fa8ee73ae Mon Sep 17 00:00:00 2001 From: Vincent Demeester Date: Thu, 6 Feb 2020 10:01:08 +0100 Subject: [PATCH 3/4] =?UTF-8?q?ClusterTask=20auto-conversion=20from=20v1al?= =?UTF-8?q?pha1=20to=20v1alpha2=20=F0=9F=8E=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds auto-conversion methods and tests for ClusterTask types in v1alpha1 and v1alpha2. Signed-off-by: Vincent Demeester --- .../v1alpha1/cluster_task_conversion.go | 49 +++ .../v1alpha1/cluster_task_conversion_test.go | 321 ++++++++++++++++++ .../v1alpha2/cluster_task_conversion.go | 36 ++ .../v1alpha2/cluster_task_conversion_test.go | 34 ++ 4 files changed, 440 insertions(+) create mode 100644 pkg/apis/pipeline/v1alpha1/cluster_task_conversion.go create mode 100644 pkg/apis/pipeline/v1alpha1/cluster_task_conversion_test.go create mode 100644 pkg/apis/pipeline/v1alpha2/cluster_task_conversion.go create mode 100644 pkg/apis/pipeline/v1alpha2/cluster_task_conversion_test.go diff --git a/pkg/apis/pipeline/v1alpha1/cluster_task_conversion.go b/pkg/apis/pipeline/v1alpha1/cluster_task_conversion.go new file mode 100644 index 00000000000..8b43d2fa8e1 --- /dev/null +++ b/pkg/apis/pipeline/v1alpha1/cluster_task_conversion.go @@ -0,0 +1,49 @@ +/* +Copyright 2020 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 v1alpha1 + +import ( + "context" + "fmt" + + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" + "knative.dev/pkg/apis" +) + +var _ apis.Convertible = (*ClusterTask)(nil) + +// ConvertUp implements api.Convertible +func (source *ClusterTask) ConvertUp(ctx context.Context, obj apis.Convertible) error { + switch sink := obj.(type) { + case *v1alpha2.ClusterTask: + sink.ObjectMeta = source.ObjectMeta + return source.Spec.ConvertUp(ctx, &sink.Spec) + default: + return fmt.Errorf("unknown version, got: %T", sink) + } +} + +// ConvertDown implements api.Convertible +func (sink *ClusterTask) ConvertDown(ctx context.Context, obj apis.Convertible) error { + switch source := obj.(type) { + case *v1alpha2.ClusterTask: + sink.ObjectMeta = source.ObjectMeta + return sink.Spec.ConvertDown(ctx, &source.Spec) + default: + return fmt.Errorf("unknown version, got: %T", sink) + } +} diff --git a/pkg/apis/pipeline/v1alpha1/cluster_task_conversion_test.go b/pkg/apis/pipeline/v1alpha1/cluster_task_conversion_test.go new file mode 100644 index 00000000000..287897a6f2a --- /dev/null +++ b/pkg/apis/pipeline/v1alpha1/cluster_task_conversion_test.go @@ -0,0 +1,321 @@ +/* +Copyright 2020 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 v1alpha1 + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" + resource "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/pkg/apis" +) + +func TestClusterTaskConversionBadType(t *testing.T) { + good, bad := &ClusterTask{}, &Pipeline{} + + if err := good.ConvertUp(context.Background(), bad); err == nil { + t.Errorf("ConvertUp() = %#v, wanted error", bad) + } + + if err := good.ConvertDown(context.Background(), bad); err == nil { + t.Errorf("ConvertUp() = %#v, wanted error", bad) + } +} + +func TestClusterTaskConversion(t *testing.T) { + versions := []apis.Convertible{&v1alpha2.ClusterTask{}} + + tests := []struct { + name string + in *ClusterTask + wantErr bool + }{{ + name: "simple conversion", + in: &ClusterTask{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Generation: 1, + }, + Spec: TaskSpec{ + TaskSpec: v1alpha2.TaskSpec{ + Steps: []v1alpha2.Step{{Container: corev1.Container{ + Image: "foo", + }}}, + Volumes: []corev1.Volume{{}}, + Params: []v1alpha2.ParamSpec{{ + Name: "param-1", + Type: v1alpha2.ParamTypeString, + Description: "My first param", + }}, + Resources: &v1alpha2.TaskResources{ + Inputs: []v1alpha2.TaskResource{{ResourceDeclaration: v1alpha2.ResourceDeclaration{ + Name: "input-1", + Type: resource.PipelineResourceTypeGit, + }}}, + Outputs: []v1alpha2.TaskResource{{ResourceDeclaration: v1alpha2.ResourceDeclaration{ + Name: "output-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }, + }, + }, + }, + }, { + name: "deprecated and non deprecated inputs", + in: &ClusterTask{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Generation: 1, + }, + Spec: TaskSpec{ + TaskSpec: v1alpha2.TaskSpec{ + Resources: &v1alpha2.TaskResources{ + Inputs: []v1alpha2.TaskResource{{ResourceDeclaration: v1alpha2.ResourceDeclaration{ + Name: "input-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }, + }, + Inputs: &Inputs{ + Resources: []TaskResource{{ResourceDeclaration: ResourceDeclaration{ + Name: "input-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }, + }, + }, + wantErr: true, + }, { + name: "deprecated and non deprecated inputs", + in: &ClusterTask{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Generation: 1, + }, + Spec: TaskSpec{ + TaskSpec: v1alpha2.TaskSpec{ + Params: []v1alpha2.ParamSpec{{ + Name: "param-1", + Type: v1alpha2.ParamTypeString, + Description: "My first param", + }}, + }, + Inputs: &Inputs{ + Params: []ParamSpec{{ + Name: "param-1", + Type: v1alpha2.ParamTypeString, + Description: "My first param", + }}, + }, + }, + }, + wantErr: true, + }, { + name: "deprecated and non deprecated outputs", + in: &ClusterTask{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Generation: 1, + }, + Spec: TaskSpec{ + TaskSpec: v1alpha2.TaskSpec{ + Resources: &v1alpha2.TaskResources{ + Outputs: []v1alpha2.TaskResource{{ResourceDeclaration: v1alpha2.ResourceDeclaration{ + Name: "output-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }, + }, + Outputs: &Outputs{ + Resources: []TaskResource{{ResourceDeclaration: ResourceDeclaration{ + Name: "output-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }, + }, + }, + wantErr: true, + }} + + for _, test := range tests { + for _, version := range versions { + t.Run(test.name, func(t *testing.T) { + ver := version + if err := test.in.ConvertUp(context.Background(), ver); err != nil { + if !test.wantErr { + t.Errorf("ConvertUp() = %v", err) + } + return + } + t.Logf("ConvertUp() = %#v", ver) + got := &ClusterTask{} + if err := got.ConvertDown(context.Background(), ver); err != nil { + t.Errorf("ConvertDown() = %v", err) + } + t.Logf("ConvertDown() = %#v", got) + if diff := cmp.Diff(test.in, got); diff != "" { + t.Errorf("roundtrip (-want, +got) = %v", diff) + } + }) + } + } +} + +func TestClusterTaskConversionFromDeprecated(t *testing.T) { + versions := []apis.Convertible{&v1alpha2.ClusterTask{}} + tests := []struct { + name string + in *ClusterTask + want *ClusterTask + badField string + }{{ + name: "inputs params", + in: &ClusterTask{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Generation: 1, + }, + Spec: TaskSpec{ + Inputs: &Inputs{ + Params: []ParamSpec{{ + Name: "param-1", + Type: v1alpha2.ParamTypeString, + Description: "My first param", + }}, + }, + }, + }, + want: &ClusterTask{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Generation: 1, + }, + Spec: TaskSpec{ + TaskSpec: v1alpha2.TaskSpec{ + Params: []v1alpha2.ParamSpec{{ + Name: "param-1", + Type: v1alpha2.ParamTypeString, + Description: "My first param", + }}, + }, + }, + }, + }, { + name: "inputs resource", + in: &ClusterTask{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Generation: 1, + }, + Spec: TaskSpec{ + Inputs: &Inputs{ + Resources: []TaskResource{{ResourceDeclaration: ResourceDeclaration{ + Name: "input-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }, + }, + }, + want: &ClusterTask{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Generation: 1, + }, + Spec: TaskSpec{ + TaskSpec: v1alpha2.TaskSpec{ + Resources: &v1alpha2.TaskResources{ + Inputs: []v1alpha2.TaskResource{{ResourceDeclaration: v1alpha2.ResourceDeclaration{ + Name: "input-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }, + }, + }, + }, + }, { + name: "outputs resource", + in: &ClusterTask{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Generation: 1, + }, + Spec: TaskSpec{ + Outputs: &Outputs{ + Resources: []TaskResource{{ResourceDeclaration: ResourceDeclaration{ + Name: "output-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }, + }, + }, + want: &ClusterTask{ + ObjectMeta: metav1.ObjectMeta{ + Name: "foo", + Namespace: "bar", + Generation: 1, + }, + Spec: TaskSpec{ + TaskSpec: v1alpha2.TaskSpec{ + Resources: &v1alpha2.TaskResources{ + Outputs: []v1alpha2.TaskResource{{ResourceDeclaration: v1alpha2.ResourceDeclaration{ + Name: "output-1", + Type: resource.PipelineResourceTypeGit, + }}}, + }, + }, + }, + }, + }} + for _, test := range tests { + for _, version := range versions { + t.Run(test.name, func(t *testing.T) { + ver := version + if err := test.in.ConvertUp(context.Background(), ver); err != nil { + if test.badField != "" { + cce, ok := err.(*CannotConvertError) + if ok && cce.Field == test.badField { + return + } + } + t.Errorf("ConvertUp() = %v", err) + } + t.Logf("ConvertUp() = %#v", ver) + got := &ClusterTask{} + if err := got.ConvertDown(context.Background(), ver); err != nil { + t.Errorf("ConvertDown() = %v", err) + } + t.Logf("ConvertDown() = %#v", got) + if diff := cmp.Diff(test.want, got); diff != "" { + t.Errorf("roundtrip (-want, +got) = %v", diff) + } + }) + } + } +} diff --git a/pkg/apis/pipeline/v1alpha2/cluster_task_conversion.go b/pkg/apis/pipeline/v1alpha2/cluster_task_conversion.go new file mode 100644 index 00000000000..5751f7ee43d --- /dev/null +++ b/pkg/apis/pipeline/v1alpha2/cluster_task_conversion.go @@ -0,0 +1,36 @@ +/* +Copyright 2020 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 v1alpha2 + +import ( + "context" + "fmt" + + "knative.dev/pkg/apis" +) + +var _ apis.Convertible = (*ClusterTask)(nil) + +// ConvertUp implements api.Convertible +func (source *ClusterTask) ConvertUp(ctx context.Context, sink apis.Convertible) error { + return fmt.Errorf("v1alpha2 is the highest known version, got: %T", sink) +} + +// ConvertDown implements api.Convertible +func (sink *ClusterTask) ConvertDown(ctx context.Context, source apis.Convertible) error { + return fmt.Errorf("v1alpha2 is the highest know version, got: %T", source) +} diff --git a/pkg/apis/pipeline/v1alpha2/cluster_task_conversion_test.go b/pkg/apis/pipeline/v1alpha2/cluster_task_conversion_test.go new file mode 100644 index 00000000000..2c7c0acfc88 --- /dev/null +++ b/pkg/apis/pipeline/v1alpha2/cluster_task_conversion_test.go @@ -0,0 +1,34 @@ +/* +Copyright 2020 The Tetkon 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 v1alpha2 + +import ( + "context" + "testing" +) + +func TestClusterTaskConversionBadType(t *testing.T) { + good, bad := &ClusterTask{}, &Pipeline{} + + if err := good.ConvertUp(context.Background(), bad); err == nil { + t.Errorf("ConvertUp() = %#v, wanted error", bad) + } + + if err := good.ConvertDown(context.Background(), bad); err == nil { + t.Errorf("ConvertDown() = %#v, wanted error", good) + } +} From 620c4763ba55d500bc06f8d1ad12d97df5bde5c6 Mon Sep 17 00:00:00 2001 From: Vincent Demeester Date: Tue, 11 Feb 2020 10:53:45 +0100 Subject: [PATCH 4/4] =?UTF-8?q?Add=20nolint:=20golint=20to=20conversion=20?= =?UTF-8?q?file=20=F0=9F=91=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The main reason is to not run into error forcing us to use the same receiver name for all function. The receiver name are different for a good reason. Signed-off-by: Vincent Demeester --- pkg/apis/pipeline/v1alpha1/cluster_task_conversion.go | 1 + pkg/apis/pipeline/v1alpha1/pipeline_conversion.go | 1 + pkg/apis/pipeline/v1alpha1/task_conversion.go | 1 + pkg/apis/pipeline/v1alpha2/cluster_task_conversion.go | 1 + pkg/apis/pipeline/v1alpha2/pipeline_conversion.go | 1 + pkg/apis/pipeline/v1alpha2/task_conversion.go | 1 + pkg/reconciler/taskrun/resources/apply_test.go | 4 ++-- 7 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pkg/apis/pipeline/v1alpha1/cluster_task_conversion.go b/pkg/apis/pipeline/v1alpha1/cluster_task_conversion.go index 8b43d2fa8e1..cc08819fd10 100644 --- a/pkg/apis/pipeline/v1alpha1/cluster_task_conversion.go +++ b/pkg/apis/pipeline/v1alpha1/cluster_task_conversion.go @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +// nolint: golint package v1alpha1 import ( diff --git a/pkg/apis/pipeline/v1alpha1/pipeline_conversion.go b/pkg/apis/pipeline/v1alpha1/pipeline_conversion.go index 5990f4b09be..ea1f0491bf1 100644 --- a/pkg/apis/pipeline/v1alpha1/pipeline_conversion.go +++ b/pkg/apis/pipeline/v1alpha1/pipeline_conversion.go @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +// nolint: golint package v1alpha1 import ( diff --git a/pkg/apis/pipeline/v1alpha1/task_conversion.go b/pkg/apis/pipeline/v1alpha1/task_conversion.go index 18cd2d8db38..f614b75938b 100644 --- a/pkg/apis/pipeline/v1alpha1/task_conversion.go +++ b/pkg/apis/pipeline/v1alpha1/task_conversion.go @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +// nolint: golint package v1alpha1 import ( diff --git a/pkg/apis/pipeline/v1alpha2/cluster_task_conversion.go b/pkg/apis/pipeline/v1alpha2/cluster_task_conversion.go index 5751f7ee43d..c7a96c3c725 100644 --- a/pkg/apis/pipeline/v1alpha2/cluster_task_conversion.go +++ b/pkg/apis/pipeline/v1alpha2/cluster_task_conversion.go @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +// nolint: golint package v1alpha2 import ( diff --git a/pkg/apis/pipeline/v1alpha2/pipeline_conversion.go b/pkg/apis/pipeline/v1alpha2/pipeline_conversion.go index 520827e836a..658ecdb213c 100644 --- a/pkg/apis/pipeline/v1alpha2/pipeline_conversion.go +++ b/pkg/apis/pipeline/v1alpha2/pipeline_conversion.go @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +// nolint: golint package v1alpha2 import ( diff --git a/pkg/apis/pipeline/v1alpha2/task_conversion.go b/pkg/apis/pipeline/v1alpha2/task_conversion.go index 887844890bf..775a2295165 100644 --- a/pkg/apis/pipeline/v1alpha2/task_conversion.go +++ b/pkg/apis/pipeline/v1alpha2/task_conversion.go @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +// nolint: golint package v1alpha2 import ( diff --git a/pkg/reconciler/taskrun/resources/apply_test.go b/pkg/reconciler/taskrun/resources/apply_test.go index 9e8601b6c7b..b0e8dbf339b 100644 --- a/pkg/reconciler/taskrun/resources/apply_test.go +++ b/pkg/reconciler/taskrun/resources/apply_test.go @@ -730,7 +730,7 @@ func TestApplyWorkspaces(t *testing.T) { func TestTaskResults(t *testing.T) { names.TestingSeed() - ts := &v1alpha1.TaskSpec{ + ts := &v1alpha1.TaskSpec{TaskSpec: v1alpha2.TaskSpec{ Results: []v1alpha1.TaskResult{{ Name: "current-date-unix-timestamp", Description: "The current date in unix timestamp format", @@ -752,7 +752,7 @@ func TestTaskResults(t *testing.T) { }, Script: "#!/usr/bin/env bash\ndate | tee $(results.current-date-human-readable.path)", }}, - } + }} want := applyMutation(ts, func(spec *v1alpha1.TaskSpec) { spec.Steps[0].Script = "#!/usr/bin/env bash\ndate +%s | tee /tekton/results/current-date-unix-timestamp" spec.Steps[0].Args[0] = "/tekton/results/current-date-unix-timestamp"