From 71fc0d57a42c53175e46085af1c08b816270d550 Mon Sep 17 00:00:00 2001 From: Vincent Demeester Date: Wed, 5 Feb 2020 16:21:30 +0100 Subject: [PATCH] Pipeline auto-conversion from v1alpha1 to v1alpha2 This adds auto-conversion methods and tests for Pipeline types in v1alpha1 and v1alpha2. Signed-off-by: Vincent Demeester Signed-off-by: Vincent Demeester --- .../pipeline/v1alpha1/pipeline_conversion.go | 70 ++++++- .../v1alpha1/pipeline_conversion_test.go | 176 ++++++++++++++++++ pkg/apis/pipeline/v1alpha2/pipeline_types.go | 13 -- .../v1alpha2/zz_generated.deepcopy.go | 21 --- .../taskrun/resources/input_resource_test.go | 4 +- 5 files changed, 246 insertions(+), 38 deletions(-) create mode 100644 pkg/apis/pipeline/v1alpha1/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_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 af212fda1f5..12259fc5725 100644 --- a/pkg/apis/pipeline/v1alpha2/zz_generated.deepcopy.go +++ b/pkg/apis/pipeline/v1alpha2/zz_generated.deepcopy.go @@ -226,11 +226,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 } @@ -400,22 +395,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",