diff --git a/pkg/apis/pipeline/v1alpha1/pipeline_types.go b/pkg/apis/pipeline/v1alpha1/pipeline_types.go index de19f38e23a..c8f363ef6a0 100644 --- a/pkg/apis/pipeline/v1alpha1/pipeline_types.go +++ b/pkg/apis/pipeline/v1alpha1/pipeline_types.go @@ -17,6 +17,7 @@ limitations under the License. package v1alpha1 import ( + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" "github.com/tektoncd/pipeline/pkg/reconciler/pipeline/dag" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) @@ -35,13 +36,13 @@ type PipelineSpec struct { // Check that Pipeline may be validated and defaulted. // TaskKind defines the type of Task used by the pipeline. -type TaskKind string +type TaskKind = v1alpha2.TaskKind const ( // NamespacedTaskKind indicates that the task type has a namepace scope. - NamespacedTaskKind TaskKind = "Task" + NamespacedTaskKind TaskKind = v1alpha2.NamespacedTaskKind // ClusterTaskKind indicates that task type has a cluster scope. - ClusterTaskKind TaskKind = "ClusterTask" + ClusterTaskKind TaskKind = v1alpha2.ClusterTaskKind ) // +genclient @@ -209,15 +210,7 @@ type PipelineTaskOutputResource struct { // TaskRef can be used to refer to a specific instance of a task. // Copied from CrossVersionObjectReference: https://github.com/kubernetes/kubernetes/blob/169df7434155cbbc22f1532cba8e0a9588e29ad8/pkg/apis/autoscaling/types.go#L64 -type TaskRef struct { - // Name of the referent; More info: http://kubernetes.io/docs/user-guide/identifiers#names - Name string `json:"name,omitempty"` - // TaskKind inficates the kind of the task, namespaced or cluster scoped. - Kind TaskKind `json:"kind,omitempty"` - // API version of the referent - // +optional - APIVersion string `json:"apiVersion,omitempty"` -} +type TaskRef = v1alpha2.TaskRef // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object diff --git a/pkg/apis/pipeline/v1alpha1/pod.go b/pkg/apis/pipeline/v1alpha1/pod.go index 51cd147bdc7..9df601ac1bf 100644 --- a/pkg/apis/pipeline/v1alpha1/pod.go +++ b/pkg/apis/pipeline/v1alpha1/pod.go @@ -16,43 +16,7 @@ limitations under the License. package v1alpha1 -import ( - corev1 "k8s.io/api/core/v1" -) +import "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" // PodTemplate holds pod specific configuration -type PodTemplate struct { - // NodeSelector is a selector which must be true for the pod to fit on a node. - // Selector which must match a node's labels for the pod to be scheduled on that node. - // More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ - // +optional - NodeSelector map[string]string `json:"nodeSelector,omitempty"` - - // If specified, the pod's tolerations. - // +optional - Tolerations []corev1.Toleration `json:"tolerations,omitempty"` - - // If specified, the pod's scheduling constraints - // +optional - Affinity *corev1.Affinity `json:"affinity,omitempty"` - - // SecurityContext holds pod-level security attributes and common container settings. - // Optional: Defaults to empty. See type description for default values of each field. - // +optional - SecurityContext *corev1.PodSecurityContext `json:"securityContext,omitempty"` - - // List of volumes that can be mounted by containers belonging to the pod. - // More info: https://kubernetes.io/docs/concepts/storage/volumes - // +optional - Volumes []corev1.Volume `json:"volumes,omitempty" patchStrategy:"merge,retainKeys" patchMergeKey:"name" protobuf:"bytes,1,rep,name=volumes"` - - // RuntimeClassName refers to a RuntimeClass object in the node.k8s.io - // group, which should be used to run this pod. If no RuntimeClass resource - // matches the named class, the pod will not be run. If unset or empty, the - // "legacy" RuntimeClass will be used, which is an implicit class with an - // empty definition that uses the default runtime handler. - // More info: https://git.k8s.io/enhancements/keps/sig-node/runtime-class.md - // This is a beta feature as of Kubernetes v1.14. - // +optional - RuntimeClassName *string `json:"runtimeClassName,omitempty" protobuf:"bytes,2,opt,name=runtimeClassName"` -} +type PodTemplate = v1alpha2.PodTemplate diff --git a/pkg/apis/pipeline/v1alpha1/taskrun_types.go b/pkg/apis/pipeline/v1alpha1/taskrun_types.go index 6bfb65c8acb..0020eaf1194 100644 --- a/pkg/apis/pipeline/v1alpha1/taskrun_types.go +++ b/pkg/apis/pipeline/v1alpha1/taskrun_types.go @@ -21,6 +21,7 @@ import ( "time" "github.com/tektoncd/pipeline/pkg/apis/pipeline" + "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" @@ -54,12 +55,12 @@ type TaskRunSpec struct { } // TaskRunSpecStatus defines the taskrun spec status the user can provide -type TaskRunSpecStatus string +type TaskRunSpecStatus = v1alpha2.TaskRunSpecStatus const ( // TaskRunSpecStatusCancelled indicates that the user wants to cancel the task, // if not already cancelled or terminated - TaskRunSpecStatusCancelled = "TaskRunCancelled" + TaskRunSpecStatusCancelled = v1alpha2.TaskRunSpecStatusCancelled ) // TaskRunInputs holds the input values that this task was invoked with. diff --git a/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go index 8fb1ba6b550..98aebd1bf2f 100644 --- a/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go @@ -1201,58 +1201,6 @@ func (in *PipelineTaskRun) DeepCopy() *PipelineTaskRun { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PodTemplate) DeepCopyInto(out *PodTemplate) { - *out = *in - if in.NodeSelector != nil { - in, out := &in.NodeSelector, &out.NodeSelector - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - if in.Tolerations != nil { - in, out := &in.Tolerations, &out.Tolerations - *out = make([]v1.Toleration, len(*in)) - for i := range *in { - (*in)[i].DeepCopyInto(&(*out)[i]) - } - } - if in.Affinity != nil { - in, out := &in.Affinity, &out.Affinity - *out = new(v1.Affinity) - (*in).DeepCopyInto(*out) - } - if in.SecurityContext != nil { - in, out := &in.SecurityContext, &out.SecurityContext - *out = new(v1.PodSecurityContext) - (*in).DeepCopyInto(*out) - } - 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.RuntimeClassName != nil { - in, out := &in.RuntimeClassName, &out.RuntimeClassName - *out = new(string) - **out = **in - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodTemplate. -func (in *PodTemplate) DeepCopy() *PodTemplate { - if in == nil { - return nil - } - out := new(PodTemplate) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PullRequestResource) DeepCopyInto(out *PullRequestResource) { *out = *in @@ -1383,22 +1331,6 @@ func (in *TaskList) DeepCopyObject() runtime.Object { return nil } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *TaskRef) DeepCopyInto(out *TaskRef) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TaskRef. -func (in *TaskRef) DeepCopy() *TaskRef { - if in == nil { - return nil - } - out := new(TaskRef) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TaskResourceBinding) DeepCopyInto(out *TaskResourceBinding) { *out = *in @@ -1542,7 +1474,7 @@ func (in *TaskRunSpec) DeepCopyInto(out *TaskRunSpec) { in.Outputs.DeepCopyInto(&out.Outputs) if in.TaskRef != nil { in, out := &in.TaskRef, &out.TaskRef - *out = new(TaskRef) + *out = new(v1alpha2.TaskRef) **out = **in } if in.TaskSpec != nil { diff --git a/pkg/apis/pipeline/v1alpha2/pod.go b/pkg/apis/pipeline/v1alpha2/pod.go new file mode 100644 index 00000000000..f38243c4721 --- /dev/null +++ b/pkg/apis/pipeline/v1alpha2/pod.go @@ -0,0 +1,58 @@ +/* +Copyright 2019 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 ( + corev1 "k8s.io/api/core/v1" +) + +// PodTemplate holds pod specific configuration +type PodTemplate struct { + // NodeSelector is a selector which must be true for the pod to fit on a node. + // Selector which must match a node's labels for the pod to be scheduled on that node. + // More info: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/ + // +optional + NodeSelector map[string]string `json:"nodeSelector,omitempty"` + + // If specified, the pod's tolerations. + // +optional + Tolerations []corev1.Toleration `json:"tolerations,omitempty"` + + // If specified, the pod's scheduling constraints + // +optional + Affinity *corev1.Affinity `json:"affinity,omitempty"` + + // SecurityContext holds pod-level security attributes and common container settings. + // Optional: Defaults to empty. See type description for default values of each field. + // +optional + SecurityContext *corev1.PodSecurityContext `json:"securityContext,omitempty"` + + // List of volumes that can be mounted by containers belonging to the pod. + // More info: https://kubernetes.io/docs/concepts/storage/volumes + // +optional + Volumes []corev1.Volume `json:"volumes,omitempty" patchStrategy:"merge,retainKeys" patchMergeKey:"name" protobuf:"bytes,1,rep,name=volumes"` + + // RuntimeClassName refers to a RuntimeClass object in the node.k8s.io + // group, which should be used to run this pod. If no RuntimeClass resource + // matches the named class, the pod will not be run. If unset or empty, the + // "legacy" RuntimeClass will be used, which is an implicit class with an + // empty definition that uses the default runtime handler. + // More info: https://git.k8s.io/enhancements/keps/sig-node/runtime-class.md + // This is a beta feature as of Kubernetes v1.14. + // +optional + RuntimeClassName *string `json:"runtimeClassName,omitempty" protobuf:"bytes,2,opt,name=runtimeClassName"` +} diff --git a/pkg/apis/pipeline/v1alpha2/pod_test.go b/pkg/apis/pipeline/v1alpha2/pod_test.go new file mode 100644 index 00000000000..ab6dd76d66d --- /dev/null +++ b/pkg/apis/pipeline/v1alpha2/pod_test.go @@ -0,0 +1,17 @@ +/* +Copyright 2019 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_test diff --git a/pkg/apis/pipeline/v1alpha2/resource_types.go b/pkg/apis/pipeline/v1alpha2/resource_types.go index f9cd8be13a2..fce7dd58215 100644 --- a/pkg/apis/pipeline/v1alpha2/resource_types.go +++ b/pkg/apis/pipeline/v1alpha2/resource_types.go @@ -78,6 +78,14 @@ type TaskResource struct { ResourceDeclaration `json:",inline"` } +// TaskRunResources allows a TaskRun to declare inputs and outputs TaskResourceBinding +type TaskRunResources struct { + // Inputs holds the inputs resources this task was invoked with + Inputs []TaskResourceBinding `json:"inputs,omitempty"` + // Outputs holds the inputs resources this task was invoked with + Outputs []TaskResourceBinding `json:"outputs,omitempty"` +} + // ResourceDeclaration defines an input or output PipelineResource declared as a requirement // by another type such as a Task or Condition. The Name field will be used to refer to these // PipelineResources within the type's definition, and when provided as an Input, the Name will be the @@ -101,6 +109,39 @@ type ResourceDeclaration struct { Optional bool `json:"optional,omitempty"` } +// PipelineResourceBinding connects a reference to an instance of a PipelineResource +// with a PipelineResource dependency that the Pipeline has declared +type PipelineResourceBinding struct { + // Name is the name of the PipelineResource in the Pipeline's declaration + Name string `json:"name,omitempty"` + // ResourceRef is a reference to the instance of the actual PipelineResource + // that should be used + // +optional + ResourceRef *PipelineResourceRef `json:"resourceRef,omitempty"` + + // FIXME(vdemeester) cannot support this if PipelineResource stays in alpha and on the same group + // ResourceSpec is specification of a resource that should be created and + // consumed by the task + // +optional + // ResourceSpec *PipelineResourceSpec `json:"resourceSpec,omitempty"` +} + +// PipelineResourceResult used to export the image name and digest as json +type PipelineResourceResult struct { + Key string `json:"key"` + Value string `json:"value"` + ResourceRef PipelineResourceRef `json:"resourceRef,omitempty"` +} + +// PipelineResourceRef can be used to refer to a specific instance of a Resource +type PipelineResourceRef struct { + // Name of the referent; More info: http://kubernetes.io/docs/user-guide/identifiers#names + Name string `json:"name,omitempty"` + // API version of the referent + // +optional + APIVersion string `json:"apiVersion,omitempty"` +} + // TaskModifier is an interface to be implemented by different PipelineResources type TaskModifier interface { GetStepsToPrepend() []Step diff --git a/pkg/apis/pipeline/v1alpha2/resource_types_validation.go b/pkg/apis/pipeline/v1alpha2/resource_types_validation.go index 8020375cab9..fa2f21cfb4e 100644 --- a/pkg/apis/pipeline/v1alpha2/resource_types_validation.go +++ b/pkg/apis/pipeline/v1alpha2/resource_types_validation.go @@ -68,3 +68,50 @@ func validateResourceType(r TaskResource, path string) *apis.FieldError { } return apis.ErrInvalidValue(string(r.Type), path) } + +func (tr *TaskRunResources) Validate(ctx context.Context) *apis.FieldError { + if tr == nil { + return nil + } + if err := validateTaskRunResources(tr.Inputs, "spec.resources.inputs.name"); err != nil { + return err + } + if err := validateTaskRunResources(tr.Outputs, "spec.resources.outputs.name"); err != nil { + return err + } + return nil +} + +// validateTaskRunResources validates that +// 1. resource is not declared more than once +// 2. if both resource reference and resource spec is defined at the same time +// 3. at least resource ref or resource spec is defined +func validateTaskRunResources(resources []TaskResourceBinding, path string) *apis.FieldError { + encountered := map[string]struct{}{} + for _, r := range resources { + // We should provide only one binding for each resource required by the Task. + name := strings.ToLower(r.Name) + if _, ok := encountered[strings.ToLower(name)]; ok { + return apis.ErrMultipleOneOf(path) + } + encountered[name] = struct{}{} + if r.ResourceRef == nil { + return apis.ErrMissingField(fmt.Sprintf("%s.resourceRef", path)) + } + // FIXME(vdemeester) cannot support this if PipelineResource stays in alpha and on the same group + /* + // Check that both resource ref and resource Spec are not present + if r.ResourceRef != nil && r.ResourceSpec != nil { + return apis.ErrDisallowedFields(fmt.Sprintf("%s.ResourceRef", path), fmt.Sprintf("%s.ResourceSpec", path)) + } + // Check that one of resource ref and resource Spec is present + if (r.ResourceRef == nil || r.ResourceRef.Name == "") && r.ResourceSpec == nil { + return apis.ErrMissingField(fmt.Sprintf("%s.ResourceRef", path), fmt.Sprintf("%s.ResourceSpec", path)) + } + if r.ResourceSpec != nil && r.ResourceSpec.Validate(ctx) != nil { + return r.ResourceSpec.Validate(ctx) + } + */ + } + return nil +} diff --git a/pkg/apis/pipeline/v1alpha2/task_types.go b/pkg/apis/pipeline/v1alpha2/task_types.go index e5d96efd56a..9d9c58cabbc 100644 --- a/pkg/apis/pipeline/v1alpha2/task_types.go +++ b/pkg/apis/pipeline/v1alpha2/task_types.go @@ -103,3 +103,26 @@ type TaskList struct { metav1.ListMeta `json:"metadata,omitempty"` Items []Task `json:"items"` } + +// TaskRef can be used to refer to a specific instance of a task. +// Copied from CrossVersionObjectReference: https://github.com/kubernetes/kubernetes/blob/169df7434155cbbc22f1532cba8e0a9588e29ad8/pkg/apis/autoscaling/types.go#L64 +type TaskRef struct { + // Name of the referent; More info: http://kubernetes.io/docs/user-guide/identifiers#names + Name string `json:"name,omitempty"` + // TaskKind inficates the kind of the task, namespaced or cluster scoped. + Kind TaskKind `json:"kind,omitempty"` + // API version of the referent + // +optional + APIVersion string `json:"apiVersion,omitempty"` +} + +// Check that Pipeline may be validated and defaulted. +// TaskKind defines the type of Task used by the pipeline. +type TaskKind string + +const ( + // NamespacedTaskKind indicates that the task type has a namepace scope. + NamespacedTaskKind TaskKind = "Task" + // ClusterTaskKind indicates that task type has a cluster scope. + ClusterTaskKind TaskKind = "ClusterTask" +) diff --git a/pkg/apis/pipeline/v1alpha2/taskrun_defaults.go b/pkg/apis/pipeline/v1alpha2/taskrun_defaults.go new file mode 100644 index 00000000000..be6bf46e3b9 --- /dev/null +++ b/pkg/apis/pipeline/v1alpha2/taskrun_defaults.go @@ -0,0 +1,63 @@ +/* +Copyright 2019 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" + "time" + + "github.com/tektoncd/pipeline/pkg/apis/config" + "github.com/tektoncd/pipeline/pkg/contexts" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/pkg/apis" +) + +var _ apis.Defaultable = (*TaskRun)(nil) + +func (tr *TaskRun) SetDefaults(ctx context.Context) { + tr.Spec.SetDefaults(ctx) +} + +func (trs *TaskRunSpec) SetDefaults(ctx context.Context) { + cfg := config.FromContextOrDefaults(ctx) + if trs.TaskRef != nil && trs.TaskRef.Kind == "" { + trs.TaskRef.Kind = NamespacedTaskKind + } + + if trs.Timeout == nil { + var timeout *metav1.Duration + if contexts.IsUpgradeViaDefaulting(ctx) { + // This case is for preexisting `TaskRun` before 0.5.0, so let's + // add the old default timeout. + // Most likely those TaskRun passing here are already done and/or already running + timeout = &metav1.Duration{Duration: config.DefaultTimeoutMinutes * time.Minute} + } else { + timeout = &metav1.Duration{Duration: time.Duration(cfg.Defaults.DefaultTimeoutMinutes) * time.Minute} + } + trs.Timeout = timeout + } + + defaultSA := cfg.Defaults.DefaultServiceAccount + if trs.ServiceAccountName == "" && defaultSA != "" { + trs.ServiceAccountName = defaultSA + } + + // If this taskrun has an embedded task, apply the usual task defaults + if trs.TaskSpec != nil { + trs.TaskSpec.SetDefaults(ctx) + } +} diff --git a/pkg/apis/pipeline/v1alpha2/taskrun_defaults_test.go b/pkg/apis/pipeline/v1alpha2/taskrun_defaults_test.go new file mode 100644 index 00000000000..503e8445314 --- /dev/null +++ b/pkg/apis/pipeline/v1alpha2/taskrun_defaults_test.go @@ -0,0 +1,211 @@ +/* +Copyright 2019 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_test + +import ( + "context" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/google/go-cmp/cmp/cmpopts" + "github.com/tektoncd/pipeline/pkg/apis/config" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" + "github.com/tektoncd/pipeline/pkg/contexts" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + logtesting "knative.dev/pkg/logging/testing" +) + +var ( + ignoreUnexportedResources = cmpopts.IgnoreUnexported() +) + +func TestTaskRunSpec_SetDefaults(t *testing.T) { + cases := []struct { + desc string + trs *v1alpha2.TaskRunSpec + want *v1alpha2.TaskRunSpec + }{{ + desc: "taskref is nil", + trs: &v1alpha2.TaskRunSpec{ + TaskRef: nil, + Timeout: &metav1.Duration{Duration: 500 * time.Millisecond}, + }, + want: &v1alpha2.TaskRunSpec{ + TaskRef: nil, + Timeout: &metav1.Duration{Duration: 500 * time.Millisecond}, + }, + }, { + desc: "taskref kind is empty", + trs: &v1alpha2.TaskRunSpec{ + TaskRef: &v1alpha2.TaskRef{}, + Timeout: &metav1.Duration{Duration: 500 * time.Millisecond}, + }, + want: &v1alpha2.TaskRunSpec{ + TaskRef: &v1alpha2.TaskRef{Kind: v1alpha2.NamespacedTaskKind}, + Timeout: &metav1.Duration{Duration: 500 * time.Millisecond}, + }, + }, { + desc: "timeout is nil", + trs: &v1alpha2.TaskRunSpec{ + TaskRef: &v1alpha2.TaskRef{Kind: v1alpha2.ClusterTaskKind}, + }, + want: &v1alpha2.TaskRunSpec{ + TaskRef: &v1alpha2.TaskRef{Kind: v1alpha2.ClusterTaskKind}, + Timeout: &metav1.Duration{Duration: config.DefaultTimeoutMinutes * time.Minute}, + }, + }, { + desc: "embedded taskSpec", + trs: &v1alpha2.TaskRunSpec{ + TaskSpec: &v1alpha2.TaskSpec{ + Params: []v1alpha2.ParamSpec{{ + Name: "param-name", + }}, + }, + }, + want: &v1alpha2.TaskRunSpec{ + TaskSpec: &v1alpha2.TaskSpec{ + Params: []v1alpha2.ParamSpec{{ + Name: "param-name", + Type: v1alpha2.ParamTypeString, + }}, + }, + Timeout: &metav1.Duration{Duration: config.DefaultTimeoutMinutes * time.Minute}, + }, + }} + for _, tc := range cases { + t.Run(tc.desc, func(t *testing.T) { + ctx := context.Background() + tc.trs.SetDefaults(ctx) + + if diff := cmp.Diff(tc.want, tc.trs); diff != "" { + t.Errorf("Mismatch of TaskRunSpec: %s", diff) + } + }) + } +} + +func TestTaskRunDefaulting(t *testing.T) { + tests := []struct { + name string + in *v1alpha2.TaskRun + want *v1alpha2.TaskRun + wc func(context.Context) context.Context + }{{ + name: "empty no context", + in: &v1alpha2.TaskRun{}, + want: &v1alpha2.TaskRun{ + Spec: v1alpha2.TaskRunSpec{ + Timeout: &metav1.Duration{Duration: config.DefaultTimeoutMinutes * time.Minute}, + }, + }, + }, { + name: "TaskRef default to namespace kind", + in: &v1alpha2.TaskRun{ + Spec: v1alpha2.TaskRunSpec{ + TaskRef: &v1alpha2.TaskRef{Name: "foo"}, + }, + }, + want: &v1alpha2.TaskRun{ + Spec: v1alpha2.TaskRunSpec{ + TaskRef: &v1alpha2.TaskRef{Name: "foo", Kind: v1alpha2.NamespacedTaskKind}, + Timeout: &metav1.Duration{Duration: config.DefaultTimeoutMinutes * time.Minute}, + }, + }, + }, { + name: "TaskRef upgrade context", + in: &v1alpha2.TaskRun{ + Spec: v1alpha2.TaskRunSpec{ + TaskRef: &v1alpha2.TaskRef{Name: "foo"}, + }, + }, + want: &v1alpha2.TaskRun{ + Spec: v1alpha2.TaskRunSpec{ + TaskRef: &v1alpha2.TaskRef{Name: "foo", Kind: v1alpha2.NamespacedTaskKind}, + Timeout: &metav1.Duration{Duration: config.DefaultTimeoutMinutes * time.Minute}, + }, + }, + wc: contexts.WithUpgradeViaDefaulting, + }, { + name: "TaskRef default config context", + in: &v1alpha2.TaskRun{ + Spec: v1alpha2.TaskRunSpec{ + TaskRef: &v1alpha2.TaskRef{Name: "foo"}, + }, + }, + want: &v1alpha2.TaskRun{ + Spec: v1alpha2.TaskRunSpec{ + TaskRef: &v1alpha2.TaskRef{Name: "foo", Kind: v1alpha2.NamespacedTaskKind}, + Timeout: &metav1.Duration{Duration: 5 * time.Minute}, + }, + }, + wc: func(ctx context.Context) context.Context { + s := config.NewStore(logtesting.TestLogger(t)) + s.OnConfigChanged(&corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: config.DefaultsConfigName, + }, + Data: map[string]string{ + "default-timeout-minutes": "5", + }, + }) + return s.ToContext(ctx) + }, + }, { + name: "TaskRef default config context with SA", + in: &v1alpha2.TaskRun{ + Spec: v1alpha2.TaskRunSpec{ + TaskRef: &v1alpha2.TaskRef{Name: "foo"}, + }, + }, + want: &v1alpha2.TaskRun{ + Spec: v1alpha2.TaskRunSpec{ + TaskRef: &v1alpha2.TaskRef{Name: "foo", Kind: v1alpha2.NamespacedTaskKind}, + Timeout: &metav1.Duration{Duration: 5 * time.Minute}, + ServiceAccountName: "tekton", + }, + }, + wc: func(ctx context.Context) context.Context { + s := config.NewStore(logtesting.TestLogger(t)) + s.OnConfigChanged(&corev1.ConfigMap{ + ObjectMeta: metav1.ObjectMeta{ + Name: config.DefaultsConfigName, + }, + Data: map[string]string{ + "default-timeout-minutes": "5", + "default-service-account": "tekton", + }, + }) + return s.ToContext(ctx) + }, + }} + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + got := tc.in + ctx := context.Background() + if tc.wc != nil { + ctx = tc.wc(ctx) + } + got.SetDefaults(ctx) + if !cmp.Equal(got, tc.want, ignoreUnexportedResources) { + t.Errorf("SetDefaults (-want, +got) = %v", + cmp.Diff(got, tc.want, ignoreUnexportedResources)) + } + }) + } +} diff --git a/pkg/apis/pipeline/v1alpha2/taskrun_types.go b/pkg/apis/pipeline/v1alpha2/taskrun_types.go new file mode 100644 index 00000000000..df3b0da4157 --- /dev/null +++ b/pkg/apis/pipeline/v1alpha2/taskrun_types.go @@ -0,0 +1,302 @@ +/* +Copyright 2019 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 ( + "fmt" + "time" + + "github.com/tektoncd/pipeline/pkg/apis/pipeline" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/pkg/apis" + duckv1beta1 "knative.dev/pkg/apis/duck/v1beta1" +) + +// TaskRunSpec defines the desired state of TaskRun +type TaskRunSpec struct { + // +optional + Params []Param `json:"params,omitempty"` + // +optional + Resources *TaskRunResources `json:"resources,omitempty"` + // +optional + ServiceAccountName string `json:"serviceAccountName"` + // no more than one of the TaskRef and TaskSpec may be specified. + // +optional + TaskRef *TaskRef `json:"taskRef,omitempty"` + // +optional + TaskSpec *TaskSpec `json:"taskSpec,omitempty"` + // Used for cancelling a taskrun (and maybe more later on) + // +optional + Status TaskRunSpecStatus `json:"status,omitempty"` + // Time after which the build times out. Defaults to 10 minutes. + // Specified build timeout should be less than 24h. + // Refer Go's ParseDuration documentation for expected format: https://golang.org/pkg/time/#ParseDuration + // +optional + Timeout *metav1.Duration `json:"timeout,omitempty"` + + // PodTemplate holds pod specific configuration + PodTemplate PodTemplate `json:"podTemplate,omitempty"` +} + +// TaskRunSpecStatus defines the taskrun spec status the user can provide +type TaskRunSpecStatus string + +const ( + // TaskRunSpecStatusCancelled indicates that the user wants to cancel the task, + // if not already cancelled or terminated + TaskRunSpecStatusCancelled = "TaskRunCancelled" +) + +// TaskRunInputs holds the input values that this task was invoked with. +type TaskRunInputs struct { + // +optional + Resources []TaskResourceBinding `json:"resources,omitempty"` + // +optional + Params []Param `json:"params,omitempty"` +} + +// TaskResourceBinding points to the PipelineResource that +// will be used for the Task input or output called Name. +type TaskResourceBinding struct { + PipelineResourceBinding + // Paths will probably be removed in #1284, and then PipelineResourceBinding can be used instead. + // The optional Path field corresponds to a path on disk at which the Resource can be found + // (used when providing the resource via mounted volume, overriding the default logic to fetch the Resource). + // +optional + Paths []string `json:"paths,omitempty"` +} + +// TaskRunOutputs holds the output values that this task was invoked with. +type TaskRunOutputs struct { + // +optional + Resources []TaskResourceBinding `json:"resources,omitempty"` +} + +var taskRunCondSet = apis.NewBatchConditionSet() + +// TaskRunStatus defines the observed state of TaskRun +type TaskRunStatus struct { + duckv1beta1.Status `json:",inline"` + + // PodName is the name of the pod responsible for executing this task's steps. + PodName string `json:"podName"` + + // StartTime is the time the build is actually started. + // +optional + StartTime *metav1.Time `json:"startTime,omitempty"` + + // CompletionTime is the time the build completed. + // +optional + CompletionTime *metav1.Time `json:"completionTime,omitempty"` + + // Steps describes the state of each build step container. + // +optional + Steps []StepState `json:"steps,omitempty"` + + // CloudEvents describe the state of each cloud event requested via a + // CloudEventResource. + // +optional + CloudEvents []CloudEventDelivery `json:"cloudEvents,omitempty"` + + // RetriesStatus contains the history of TaskRunStatus in case of a retry in order to keep record of failures. + // All TaskRunStatus stored in RetriesStatus will have no date within the RetriesStatus as is redundant. + // +optional + RetriesStatus []TaskRunStatus `json:"retriesStatus,omitempty"` + // Results from Resources built during the taskRun. currently includes + // the digest of build container images + // optional + ResourcesResult []PipelineResourceResult `json:"resourcesResult,omitempty"` + + // The list has one entry per sidecar in the manifest. Each entry is + // represents the imageid of the corresponding sidecar. + Sidecars []SidecarState `json:"sidecars,omitempty"` +} + +// GetCondition returns the Condition matching the given type. +func (tr *TaskRunStatus) GetCondition(t apis.ConditionType) *apis.Condition { + return taskRunCondSet.Manage(tr).GetCondition(t) +} + +// InitializeConditions will set all conditions in taskRunCondSet to unknown for the TaskRun +// and set the started time to the current time +func (tr *TaskRunStatus) InitializeConditions() { + if tr.StartTime.IsZero() { + tr.StartTime = &metav1.Time{Time: time.Now()} + } + taskRunCondSet.Manage(tr).InitializeConditions() +} + +// SetCondition sets the condition, unsetting previous conditions with the same +// type as necessary. +func (tr *TaskRunStatus) SetCondition(newCond *apis.Condition) { + if newCond != nil { + taskRunCondSet.Manage(tr).SetCondition(*newCond) + } +} + +// StepState reports the results of running a step in the Task. +type StepState struct { + corev1.ContainerState + Name string `json:"name,omitempty"` + ContainerName string `json:"container,omitempty"` + ImageID string `json:"imageID,omitempty"` +} + +// SidecarState reports the results of sidecar in the Task. +type SidecarState struct { + Name string `json:"name,omitempty"` + ImageID string `json:"imageID,omitempty"` +} + +// CloudEventDelivery is the target of a cloud event along with the state of +// delivery. +type CloudEventDelivery struct { + // Target points to an addressable + Target string `json:"target,omitempty"` + Status CloudEventDeliveryState `json:"status,omitempty"` +} + +// CloudEventCondition is a string that represents the condition of the event. +type CloudEventCondition string + +const ( + // CloudEventConditionUnknown means that the condition for the event to be + // triggered was not met yet, or we don't know the state yet. + CloudEventConditionUnknown CloudEventCondition = "Unknown" + // CloudEventConditionSent means that the event was sent successfully + CloudEventConditionSent CloudEventCondition = "Sent" + // CloudEventConditionFailed means that there was one or more attempts to + // send the event, and none was successful so far. + CloudEventConditionFailed CloudEventCondition = "Failed" +) + +// CloudEventDeliveryState reports the state of a cloud event to be sent. +type CloudEventDeliveryState struct { + // Current status + Condition CloudEventCondition `json:"condition,omitempty"` + // SentAt is the time at which the last attempt to send the event was made + // +optional + SentAt *metav1.Time `json:"sentAt,omitempty"` + // Error is the text of error (if any) + Error string `json:"message"` + // RetryCount is the number of attempts of sending the cloud event + RetryCount int32 `json:"retryCount"` +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TaskRun represents a single execution of a Task. TaskRuns are how the steps +// specified in a Task are executed; they specify the parameters and resources +// used to run the steps in a Task. +// +// +k8s:openapi-gen=true +type TaskRun struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // +optional + Spec TaskRunSpec `json:"spec,omitempty"` + // +optional + Status TaskRunStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// TaskRunList contains a list of TaskRun +type TaskRunList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + Items []TaskRun `json:"items"` +} + +// GetBuildPodRef for task +func (tr *TaskRun) GetBuildPodRef() corev1.ObjectReference { + return corev1.ObjectReference{ + APIVersion: "v1", + Kind: "Pod", + Namespace: tr.Namespace, + Name: tr.Name, + } +} + +// GetPipelineRunPVCName for taskrun gets pipelinerun +func (tr *TaskRun) GetPipelineRunPVCName() string { + if tr == nil { + return "" + } + for _, ref := range tr.GetOwnerReferences() { + if ref.Kind == pipeline.PipelineRunControllerName { + return fmt.Sprintf("%s-pvc", ref.Name) + } + } + return "" +} + +// HasPipelineRunOwnerReference returns true of TaskRun has +// owner reference of type PipelineRun +func (tr *TaskRun) HasPipelineRunOwnerReference() bool { + for _, ref := range tr.GetOwnerReferences() { + if ref.Kind == pipeline.PipelineRunControllerName { + return true + } + } + return false +} + +// IsDone returns true if the TaskRun's status indicates that it is done. +func (tr *TaskRun) IsDone() bool { + return !tr.Status.GetCondition(apis.ConditionSucceeded).IsUnknown() +} + +// HasStarted function check whether taskrun has valid start time set in its status +func (tr *TaskRun) HasStarted() bool { + return tr.Status.StartTime != nil && !tr.Status.StartTime.IsZero() +} + +// IsSuccessful returns true if the TaskRun's status indicates that it is done. +func (tr *TaskRun) IsSuccessful() bool { + return tr.Status.GetCondition(apis.ConditionSucceeded).IsTrue() +} + +// IsCancelled returns true if the TaskRun's spec status is set to Cancelled state +func (tr *TaskRun) IsCancelled() bool { + return tr.Spec.Status == TaskRunSpecStatusCancelled +} + +// GetRunKey return the taskrun key for timeout handler map +func (tr *TaskRun) GetRunKey() string { + // The address of the pointer is a threadsafe unique identifier for the taskrun + return fmt.Sprintf("%s/%p", "TaskRun", tr) +} + +// IsPartOfPipeline return true if TaskRun is a part of a Pipeline. +// It also return the name of Pipeline and PipelineRun +func (tr *TaskRun) IsPartOfPipeline() (bool, string, string) { + if tr == nil || len(tr.Labels) == 0 { + return false, "", "" + } + + if pl, ok := tr.Labels[pipeline.GroupName+pipeline.PipelineLabelKey]; ok { + return true, pl, tr.Labels[pipeline.GroupName+pipeline.PipelineRunLabelKey] + } + + return false, "", "" +} diff --git a/pkg/apis/pipeline/v1alpha2/taskrun_types_test.go b/pkg/apis/pipeline/v1alpha2/taskrun_types_test.go new file mode 100644 index 00000000000..f4f6a049503 --- /dev/null +++ b/pkg/apis/pipeline/v1alpha2/taskrun_types_test.go @@ -0,0 +1,242 @@ +/* +Copyright 2019 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_test + +import ( + "fmt" + "testing" + "time" + + "github.com/google/go-cmp/cmp" + "github.com/tektoncd/pipeline/pkg/apis/pipeline" + "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" + duckv1beta1 "knative.dev/pkg/apis/duck/v1beta1" +) + +func TestTaskRun_GetBuildPodRef(t *testing.T) { + tr := &v1alpha2.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Namespace: "testns", + Name: "taskrunname", + }, + } + if d := cmp.Diff(tr.GetBuildPodRef(), corev1.ObjectReference{ + APIVersion: "v1", + Kind: "Pod", + Namespace: "testns", + Name: "taskrunname", + }); d != "" { + t.Fatalf("taskrun build pod ref mismatch: %s", d) + } +} + +func TestTaskRun_GetPipelineRunPVCName(t *testing.T) { + tests := []struct { + name string + tr *v1alpha2.TaskRun + expectedPVCName string + }{{ + name: "invalid owner reference", + // tr: tb.TaskRun(tb.WithOwnerReference(tb.OwnerKind("SomeOtherOwner"))) + tr: &v1alpha2.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + OwnerReferences: []metav1.OwnerReference{{ + Kind: "SomeOtherOwner", + Name: "testpr", + }}, + }, + }, + expectedPVCName: "", + }, { + name: "valid pipelinerun owner", + tr: &v1alpha2.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + OwnerReferences: []metav1.OwnerReference{{ + Kind: "PipelineRun", + Name: "testpr", + }}, + }, + }, + expectedPVCName: "testpr-pvc", + }, { + name: "nil taskrun", + expectedPVCName: "", + }} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.tr.GetPipelineRunPVCName() != tt.expectedPVCName { + t.Fatalf("taskrun pipeline run pvc name mismatch: got %s ; expected %s", tt.tr.GetPipelineRunPVCName(), tt.expectedPVCName) + } + }) + } +} + +func TestTaskRun_HasPipelineRun(t *testing.T) { + tests := []struct { + name string + tr *v1alpha2.TaskRun + want bool + }{{ + name: "invalid owner reference", + tr: &v1alpha2.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + OwnerReferences: []metav1.OwnerReference{{ + Kind: "SomeOtherOwner", + Name: "testpr", + }}, + }, + }, + want: false, + }, { + name: "valid pipelinerun owner", + tr: &v1alpha2.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + OwnerReferences: []metav1.OwnerReference{{ + Kind: "PipelineRun", + Name: "testpr", + }}, + }, + }, + want: true, + }} + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if tt.tr.HasPipelineRunOwnerReference() != tt.want { + t.Fatalf("taskrun pipeline run pvc name mismatch: got %s ; expected %t", tt.tr.GetPipelineRunPVCName(), tt.want) + } + }) + } +} + +func TestTaskRunIsDone(t *testing.T) { + tr := &v1alpha2.TaskRun{ + Status: v1alpha2.TaskRunStatus{ + Status: duckv1beta1.Status{ + Conditions: []apis.Condition{{ + Type: apis.ConditionSucceeded, + Status: corev1.ConditionFalse, + }}, + }, + }, + } + if !tr.IsDone() { + t.Fatal("Expected pipelinerun status to be done") + } +} + +func TestTaskRunIsCancelled(t *testing.T) { + tr := &v1alpha2.TaskRun{ + Spec: v1alpha2.TaskRunSpec{ + Status: v1alpha2.TaskRunSpecStatusCancelled, + }, + } + if !tr.IsCancelled() { + t.Fatal("Expected pipelinerun status to be cancelled") + } +} + +func TestTaskRunKey(t *testing.T) { + tr := &v1alpha2.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "taskrunname", + }, + } + expectedKey := fmt.Sprintf("TaskRun/%p", tr) + if tr.GetRunKey() != expectedKey { + t.Fatalf("Expected taskrun key to be %s but got %s", expectedKey, tr.GetRunKey()) + } +} + +func TestTaskRunHasStarted(t *testing.T) { + params := []struct { + name string + trStatus v1alpha2.TaskRunStatus + expectedValue bool + }{{ + name: "trWithNoStartTime", + trStatus: v1alpha2.TaskRunStatus{}, + expectedValue: false, + }, { + name: "trWithStartTime", + trStatus: v1alpha2.TaskRunStatus{ + StartTime: &metav1.Time{Time: time.Now()}, + }, + expectedValue: true, + }, { + name: "trWithZeroStartTime", + trStatus: v1alpha2.TaskRunStatus{ + StartTime: &metav1.Time{}, + }, + expectedValue: false, + }} + for _, tc := range params { + t.Run(tc.name, func(t *testing.T) { + tr := &v1alpha2.TaskRun{} + tr.Status = tc.trStatus + if tr.HasStarted() != tc.expectedValue { + t.Fatalf("Expected taskrun HasStarted() to return %t but got %t", tc.expectedValue, tr.HasStarted()) + } + }) + } +} + +func TestTaskRunIsOfPipelinerun(t *testing.T) { + tests := []struct { + name string + tr *v1alpha2.TaskRun + expectedValue bool + expetectedPipeline string + expetectedPipelineRun string + }{{ + name: "yes", + tr: &v1alpha2.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Labels: map[string]string{ + pipeline.GroupName + pipeline.PipelineLabelKey: "pipeline", + pipeline.GroupName + pipeline.PipelineRunLabelKey: "pipelinerun", + }, + }, + }, + expectedValue: true, + expetectedPipeline: "pipeline", + expetectedPipelineRun: "pipelinerun", + }, { + name: "no", + tr: &v1alpha2.TaskRun{}, + expectedValue: false, + }} + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + value, pipeline, pipelineRun := test.tr.IsPartOfPipeline() + if value != test.expectedValue { + t.Fatalf("Expecting %v got %v", test.expectedValue, value) + } + + if pipeline != test.expetectedPipeline { + t.Fatalf("Mismatch in pipeline: got %s expected %s", pipeline, test.expetectedPipeline) + } + + if pipelineRun != test.expetectedPipelineRun { + t.Fatalf("Mismatch in pipelinerun: got %s expected %s", pipelineRun, test.expetectedPipelineRun) + } + }) + } +} diff --git a/pkg/apis/pipeline/v1alpha2/taskrun_validation.go b/pkg/apis/pipeline/v1alpha2/taskrun_validation.go new file mode 100644 index 00000000000..63dcb3f5157 --- /dev/null +++ b/pkg/apis/pipeline/v1alpha2/taskrun_validation.go @@ -0,0 +1,91 @@ +/* +Copyright 2019 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" + "strings" + + "github.com/tektoncd/pipeline/pkg/apis/validate" + "k8s.io/apimachinery/pkg/api/equality" + "knative.dev/pkg/apis" +) + +var _ apis.Validatable = (*TaskRun)(nil) + +// Validate taskrun +func (tr *TaskRun) Validate(ctx context.Context) *apis.FieldError { + if err := validate.ObjectMetadata(tr.GetObjectMeta()).ViaField("metadata"); err != nil { + return err + } + return tr.Spec.Validate(ctx) +} + +// Validate taskrun spec +func (ts *TaskRunSpec) Validate(ctx context.Context) *apis.FieldError { + if equality.Semantic.DeepEqual(ts, &TaskRunSpec{}) { + return apis.ErrMissingField("spec") + } + + // can't have both taskRef and taskSpec at the same time + if (ts.TaskRef != nil && ts.TaskRef.Name != "") && ts.TaskSpec != nil { + return apis.ErrDisallowedFields("spec.taskref", "spec.taskspec") + } + + // Check that one of TaskRef and TaskSpec is present + if (ts.TaskRef == nil || (ts.TaskRef != nil && ts.TaskRef.Name == "")) && ts.TaskSpec == nil { + return apis.ErrMissingField("spec.taskref.name", "spec.taskspec") + } + + // Validate TaskSpec if it's present + if ts.TaskSpec != nil { + if err := ts.TaskSpec.Validate(ctx); err != nil { + return err + } + } + + if err := validateParameters(ts.Params); err != nil { + return err + } + + // Validate Resources declaration + if err := ts.Resources.Validate(ctx); err != nil { + return err + } + + if ts.Timeout != nil { + // timeout should be a valid duration of at least 0. + if ts.Timeout.Duration < 0 { + return apis.ErrInvalidValue(fmt.Sprintf("%s should be >= 0", ts.Timeout.Duration.String()), "spec.timeout") + } + } + + return nil +} + +func validateParameters(params []Param) *apis.FieldError { + // Template must not duplicate parameter names. + seen := map[string]struct{}{} + for _, p := range params { + if _, ok := seen[strings.ToLower(p.Name)]; ok { + return apis.ErrMultipleOneOf("spec.inputs.params") + } + seen[p.Name] = struct{}{} + } + return nil +} diff --git a/pkg/apis/pipeline/v1alpha2/taskrun_validation_test.go b/pkg/apis/pipeline/v1alpha2/taskrun_validation_test.go new file mode 100644 index 00000000000..24b3c4778cf --- /dev/null +++ b/pkg/apis/pipeline/v1alpha2/taskrun_validation_test.go @@ -0,0 +1,438 @@ +/* +Copyright 2019 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_test + +import ( + "context" + "testing" + "time" + + "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" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/pkg/apis" +) + +func TestTaskRun_Invalidate(t *testing.T) { + tests := []struct { + name string + task *v1alpha2.TaskRun + want *apis.FieldError + }{{ + name: "invalid taskspec", + task: &v1alpha2.TaskRun{}, + want: apis.ErrMissingField("spec"), + }, { + name: "invalid taskrun metadata", + task: &v1alpha2.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "task.name", + }, + }, + want: &apis.FieldError{ + Message: "Invalid resource name: special character . must not be present", + Paths: []string{"metadata.name"}, + }, + }} + for _, ts := range tests { + t.Run(ts.name, func(t *testing.T) { + err := ts.task.Validate(context.Background()) + if d := cmp.Diff(err.Error(), ts.want.Error()); d != "" { + t.Errorf("TaskRun.Validate/%s (-want, +got) = %v", ts.name, d) + } + }) + } +} + +func TestTaskRun_Validate(t *testing.T) { + tr := &v1alpha2.TaskRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "taskrname", + }, + Spec: v1alpha2.TaskRunSpec{ + TaskRef: &v1alpha2.TaskRef{Name: "taskrefname"}, + }, + } + if err := tr.Validate(context.Background()); err != nil { + t.Errorf("TaskRun.Validate() error = %v", err) + } +} + +func TestTaskRunSpec_Invalidate(t *testing.T) { + tests := []struct { + name string + spec v1alpha2.TaskRunSpec + wantErr *apis.FieldError + }{{ + name: "invalid taskspec", + spec: v1alpha2.TaskRunSpec{}, + wantErr: apis.ErrMissingField("spec"), + }, { + name: "invalid taskref name", + spec: v1alpha2.TaskRunSpec{ + TaskRef: &v1alpha2.TaskRef{}, + }, + wantErr: apis.ErrMissingField("spec.taskref.name, spec.taskspec"), + }, { + name: "invalid taskref and taskspec together", + spec: v1alpha2.TaskRunSpec{ + TaskRef: &v1alpha2.TaskRef{ + Name: "taskrefname", + }, + TaskSpec: &v1alpha2.TaskSpec{ + Steps: []v1alpha2.Step{{Container: corev1.Container{ + Name: "mystep", + Image: "myimage", + }}}, + }, + }, + wantErr: apis.ErrDisallowedFields("spec.taskspec", "spec.taskref"), + }, { + name: "negative pipeline timeout", + spec: v1alpha2.TaskRunSpec{ + TaskRef: &v1alpha2.TaskRef{ + Name: "taskrefname", + }, + Timeout: &metav1.Duration{Duration: -48 * time.Hour}, + }, + wantErr: apis.ErrInvalidValue("-48h0m0s should be >= 0", "spec.timeout"), + }, { + name: "invalid taskspec", + spec: v1alpha2.TaskRunSpec{ + TaskSpec: &v1alpha2.TaskSpec{ + Steps: []v1alpha2.Step{{Container: corev1.Container{ + Name: "invalid-name-with-$weird-char/%", + Image: "myimage", + }}}, + }, + }, + wantErr: &apis.FieldError{ + Message: `invalid value "invalid-name-with-$weird-char/%"`, + Paths: []string{"taskspec.steps.name"}, + Details: "Task step name must be a valid DNS Label, For more info refer to https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names", + }, + }, { + name: "invalid params", + spec: v1alpha2.TaskRunSpec{ + Params: []v1alpha1.Param{{ + Name: "name", + Value: *builder.ArrayOrString("value"), + }, { + Name: "name", + Value: *builder.ArrayOrString("value"), + }}, + TaskRef: &v1alpha2.TaskRef{Name: "mytask"}, + }, + wantErr: apis.ErrMultipleOneOf("spec.inputs.params"), + }} + for _, ts := range tests { + t.Run(ts.name, func(t *testing.T) { + err := ts.spec.Validate(context.Background()) + if d := cmp.Diff(ts.wantErr.Error(), err.Error()); d != "" { + t.Errorf("TaskRunSpec.Validate/%s (-want, +got) = %v", ts.name, d) + } + }) + } +} + +func TestTaskRunSpec_Validate(t *testing.T) { + tests := []struct { + name string + spec v1alpha2.TaskRunSpec + }{{ + name: "taskspec without a taskRef", + spec: v1alpha2.TaskRunSpec{ + TaskSpec: &v1alpha2.TaskSpec{ + Steps: []v1alpha2.Step{{Container: corev1.Container{ + Name: "mystep", + Image: "myimage", + }}}, + }, + }, + }, { + name: "no timeout", + spec: v1alpha2.TaskRunSpec{ + Timeout: &metav1.Duration{Duration: 0}, + TaskSpec: &v1alpha2.TaskSpec{ + Steps: []v1alpha2.Step{{Container: corev1.Container{ + Name: "mystep", + Image: "myimage", + }}}, + }, + }, + }, { + name: "parameters", + spec: v1alpha2.TaskRunSpec{ + Timeout: &metav1.Duration{Duration: 0}, + Params: []v1alpha2.Param{{ + Name: "name", + Value: *builder.ArrayOrString("value"), + }}, + TaskSpec: &v1alpha2.TaskSpec{ + Steps: []v1alpha2.Step{{Container: corev1.Container{ + Name: "mystep", + Image: "myimage", + }}}, + }, + }, + }} + for _, ts := range tests { + t.Run(ts.name, func(t *testing.T) { + if err := ts.spec.Validate(context.Background()); err != nil { + t.Errorf("TaskRunSpec.Validate()/%s error = %v", ts.name, err) + } + }) + } +} + +func TestResources_Validate(t *testing.T) { + tests := []struct { + name string + resources *v1alpha2.TaskRunResources + }{{ + name: "no resources is valid", + }, { + name: "inputs only", + resources: &v1alpha2.TaskRunResources{ + Inputs: []v1alpha2.TaskResourceBinding{{ + PipelineResourceBinding: v1alpha2.PipelineResourceBinding{ + ResourceRef: &v1alpha2.PipelineResourceRef{ + Name: "testresource", + }, + Name: "workspace", + }, + }}, + }, + }, { + name: "multiple inputs only", + resources: &v1alpha2.TaskRunResources{ + Inputs: []v1alpha2.TaskResourceBinding{{ + PipelineResourceBinding: v1alpha2.PipelineResourceBinding{ + ResourceRef: &v1alpha2.PipelineResourceRef{ + Name: "testresource1", + }, + Name: "workspace1", + }, + }, { + PipelineResourceBinding: v1alpha2.PipelineResourceBinding{ + ResourceRef: &v1alpha2.PipelineResourceRef{ + Name: "testresource2", + }, + Name: "workspace2", + }, + }}, + }, + }, { + name: "outputs only", + resources: &v1alpha2.TaskRunResources{ + Outputs: []v1alpha2.TaskResourceBinding{{ + PipelineResourceBinding: v1alpha2.PipelineResourceBinding{ + ResourceRef: &v1alpha2.PipelineResourceRef{ + Name: "testresource", + }, + Name: "workspace", + }, + }}, + }, + }, { + name: "multiple outputs only", + resources: &v1alpha2.TaskRunResources{ + Outputs: []v1alpha2.TaskResourceBinding{{ + PipelineResourceBinding: v1alpha2.PipelineResourceBinding{ + ResourceRef: &v1alpha2.PipelineResourceRef{ + Name: "testresource1", + }, + Name: "workspace1", + }, + }, { + PipelineResourceBinding: v1alpha2.PipelineResourceBinding{ + ResourceRef: &v1alpha2.PipelineResourceRef{ + Name: "testresource2", + }, + Name: "workspace2", + }, + }}, + }, + }, { + name: "inputs and outputs", + resources: &v1alpha2.TaskRunResources{ + Inputs: []v1alpha2.TaskResourceBinding{{ + PipelineResourceBinding: v1alpha2.PipelineResourceBinding{ + ResourceRef: &v1alpha2.PipelineResourceRef{ + Name: "testresource", + }, + Name: "workspace", + }, + }}, + Outputs: []v1alpha2.TaskResourceBinding{{ + PipelineResourceBinding: v1alpha2.PipelineResourceBinding{ + ResourceRef: &v1alpha2.PipelineResourceRef{ + Name: "testresource", + }, + Name: "workspace", + }, + }}, + }, + }} + for _, ts := range tests { + t.Run(ts.name, func(t *testing.T) { + if err := ts.resources.Validate(context.Background()); err != nil { + t.Errorf("TaskRunInputs.Validate() error = %v", err) + } + }) + } + +} + +func TestResources_Invalidate(t *testing.T) { + tests := []struct { + name string + resources *v1alpha2.TaskRunResources + wantErr *apis.FieldError + }{{ + name: "duplicate task inputs", + resources: &v1alpha2.TaskRunResources{ + Inputs: []v1alpha2.TaskResourceBinding{{ + PipelineResourceBinding: v1alpha2.PipelineResourceBinding{ + ResourceRef: &v1alpha2.PipelineResourceRef{ + Name: "testresource1", + }, + Name: "workspace", + }, + }, { + PipelineResourceBinding: v1alpha2.PipelineResourceBinding{ + ResourceRef: &v1alpha2.PipelineResourceRef{ + Name: "testresource2", + }, + Name: "workspace", + }, + }}, + }, + wantErr: apis.ErrMultipleOneOf("spec.resources.inputs.name"), + }, /*{ + name: "duplicate resource ref and resource spec", + resources: &v1alpha2.TaskRunResources{ + Inputs: []v1alpha2.TaskResourceBinding{{ + PipelineResourceBinding: v1alpha2.PipelineResourceBinding{ + ResourceRef: &v1alpha2.PipelineResourceRef{ + Name: "testresource", + }, + ResourceSpec: &v1alpha2.PipelineResourceSpec{ + Type: v1alpha2.PipelineResourceTypeGit, + }, + Name: "resource-dup", + }, + }}, + }, + wantErr: apis.ErrDisallowedFields("spec.resources.inputs.name.resourceRef", "spec.resources.inputs.name.resourceSpec"), + },*/ /*{ + name: "invalid resource spec", + resources: &v1alpha2.TaskRunResources{ + Inputs: []v1alpha2.TaskResourceBinding{{ + PipelineResourceBinding: v1alpha2.PipelineResourceBinding{ + ResourceSpec: &v1alpha2.PipelineResourceSpec{ + Type: "non-existent", + }, + Name: "resource-inv", + }, + }}, + }, + wantErr: apis.ErrInvalidValue("spec.type", "non-existent"), + },*/{ + name: "no resource ref ", // and resource spec + resources: &v1alpha2.TaskRunResources{ + Inputs: []v1alpha2.TaskResourceBinding{{ + PipelineResourceBinding: v1alpha2.PipelineResourceBinding{ + Name: "resource", + }, + }}, + }, + wantErr: apis.ErrMissingField("spec.resources.inputs.name.resourceRef"), + // wantErr: apis.ErrMissingField("spec.resources.inputs.name.resourceRef", "spec.resources.inputs.name.resourceSpec"), + }, { + name: "duplicate task outputs", + resources: &v1alpha2.TaskRunResources{ + Outputs: []v1alpha2.TaskResourceBinding{{ + PipelineResourceBinding: v1alpha2.PipelineResourceBinding{ + ResourceRef: &v1alpha2.PipelineResourceRef{ + Name: "testresource1", + }, + Name: "workspace", + }, + }, { + PipelineResourceBinding: v1alpha2.PipelineResourceBinding{ + ResourceRef: &v1alpha2.PipelineResourceRef{ + Name: "testresource2", + }, + Name: "workspace", + }, + }}, + }, + wantErr: apis.ErrMultipleOneOf("spec.resources.outputs.name"), + }, /*{ + name: "duplicate resource ref and resource spec", + resources: &v1alpha2.TaskRunResources{ + Outputs: []v1alpha2.TaskResourceBinding{{ + PipelineResourceBinding: v1alpha2.PipelineResourceBinding{ + ResourceRef: &v1alpha2.PipelineResourceRef{ + Name: "testresource", + }, + ResourceSpec: &v1alpha2.PipelineResourceSpec{ + Type: v1alpha2.PipelineResourceTypeGit, + }, + Name: "resource-dup", + }, + }}, + }, + wantErr: apis.ErrDisallowedFields("spec.resources.outputs.name.resourceRef", "spec.resources.outputs.name.resourceSpec"), + },*/ /*{ + name: "invalid resource spec", + resources: &v1alpha2.TaskRunResources{ + Inputs: []v1alpha2.TaskResourceBinding{{ + PipelineResourceBinding: v1alpha2.PipelineResourceBinding{ + ResourceSpec: &v1alpha2.PipelineResourceSpec{ + Type: "non-existent", + }, + Name: "resource-inv", + }, + }}, + }, + wantErr: apis.ErrInvalidValue("spec.type", "non-existent"), + },*/{ + name: "no resource ref ", // and resource spec + resources: &v1alpha2.TaskRunResources{ + Outputs: []v1alpha2.TaskResourceBinding{{ + PipelineResourceBinding: v1alpha2.PipelineResourceBinding{ + Name: "resource", + }, + }}, + }, + wantErr: apis.ErrMissingField("spec.resources.outputs.name.resourceRef"), + // wantErr: apis.ErrMissingField("spec.resources.outputs.name.resourceRef", "spec.resources.outputs.name.resourceSpec"), + }} + for _, ts := range tests { + t.Run(ts.name, func(t *testing.T) { + err := ts.resources.Validate(context.Background()) + if d := cmp.Diff(err.Error(), ts.wantErr.Error()); d != "" { + t.Errorf("TaskRunInputs.Validate/%s (-want, +got) = %v", ts.name, d) + } + }) + } +} diff --git a/pkg/apis/pipeline/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/pipeline/v1alpha2/zz_generated.deepcopy.go index f9a7702a544..03e96af4469 100644 --- a/pkg/apis/pipeline/v1alpha2/zz_generated.deepcopy.go +++ b/pkg/apis/pipeline/v1alpha2/zz_generated.deepcopy.go @@ -22,6 +22,7 @@ package v1alpha2 import ( v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -46,6 +47,43 @@ func (in *ArrayOrString) DeepCopy() *ArrayOrString { 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 + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CloudEventDelivery. +func (in *CloudEventDelivery) DeepCopy() *CloudEventDelivery { + if in == nil { + return nil + } + out := new(CloudEventDelivery) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CloudEventDeliveryState) DeepCopyInto(out *CloudEventDeliveryState) { + *out = *in + if in.SentAt != nil { + in, out := &in.SentAt, &out.SentAt + *out = (*in).DeepCopy() + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CloudEventDeliveryState. +func (in *CloudEventDeliveryState) DeepCopy() *CloudEventDeliveryState { + if in == nil { + return nil + } + out := new(CloudEventDeliveryState) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *InternalTaskModifier) DeepCopyInto(out *InternalTaskModifier) { *out = *in @@ -121,6 +159,112 @@ func (in *ParamSpec) DeepCopy() *ParamSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PipelineResourceBinding) DeepCopyInto(out *PipelineResourceBinding) { + *out = *in + if in.ResourceRef != nil { + in, out := &in.ResourceRef, &out.ResourceRef + *out = new(PipelineResourceRef) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PipelineResourceBinding. +func (in *PipelineResourceBinding) DeepCopy() *PipelineResourceBinding { + if in == nil { + return nil + } + out := new(PipelineResourceBinding) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PipelineResourceRef) DeepCopyInto(out *PipelineResourceRef) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PipelineResourceRef. +func (in *PipelineResourceRef) DeepCopy() *PipelineResourceRef { + if in == nil { + return nil + } + out := new(PipelineResourceRef) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PipelineResourceResult) DeepCopyInto(out *PipelineResourceResult) { + *out = *in + out.ResourceRef = in.ResourceRef + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PipelineResourceResult. +func (in *PipelineResourceResult) DeepCopy() *PipelineResourceResult { + if in == nil { + return nil + } + out := new(PipelineResourceResult) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PodTemplate) DeepCopyInto(out *PodTemplate) { + *out = *in + if in.NodeSelector != nil { + in, out := &in.NodeSelector, &out.NodeSelector + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Tolerations != nil { + in, out := &in.Tolerations, &out.Tolerations + *out = make([]v1.Toleration, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Affinity != nil { + in, out := &in.Affinity, &out.Affinity + *out = new(v1.Affinity) + (*in).DeepCopyInto(*out) + } + if in.SecurityContext != nil { + in, out := &in.SecurityContext, &out.SecurityContext + *out = new(v1.PodSecurityContext) + (*in).DeepCopyInto(*out) + } + 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.RuntimeClassName != nil { + in, out := &in.RuntimeClassName, &out.RuntimeClassName + *out = new(string) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodTemplate. +func (in *PodTemplate) DeepCopy() *PodTemplate { + if in == nil { + return nil + } + out := new(PodTemplate) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ResourceDeclaration) DeepCopyInto(out *ResourceDeclaration) { *out = *in @@ -153,6 +297,22 @@ func (in *ResourceParam) DeepCopy() *ResourceParam { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *SidecarState) DeepCopyInto(out *SidecarState) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SidecarState. +func (in *SidecarState) DeepCopy() *SidecarState { + if in == nil { + return nil + } + out := new(SidecarState) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Step) DeepCopyInto(out *Step) { *out = *in @@ -170,6 +330,23 @@ func (in *Step) DeepCopy() *Step { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *StepState) DeepCopyInto(out *StepState) { + *out = *in + in.ContainerState.DeepCopyInto(&out.ContainerState) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StepState. +func (in *StepState) DeepCopy() *StepState { + if in == nil { + return nil + } + out := new(StepState) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Task) DeepCopyInto(out *Task) { *out = *in @@ -230,6 +407,22 @@ func (in *TaskList) DeepCopyObject() runtime.Object { return nil } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TaskRef) DeepCopyInto(out *TaskRef) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TaskRef. +func (in *TaskRef) DeepCopy() *TaskRef { + if in == nil { + return nil + } + out := new(TaskRef) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TaskResource) DeepCopyInto(out *TaskResource) { *out = *in @@ -247,6 +440,28 @@ func (in *TaskResource) DeepCopy() *TaskResource { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TaskResourceBinding) DeepCopyInto(out *TaskResourceBinding) { + *out = *in + in.PipelineResourceBinding.DeepCopyInto(&out.PipelineResourceBinding) + if in.Paths != nil { + in, out := &in.Paths, &out.Paths + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TaskResourceBinding. +func (in *TaskResourceBinding) DeepCopy() *TaskResourceBinding { + if in == nil { + return nil + } + out := new(TaskResourceBinding) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *TaskResources) DeepCopyInto(out *TaskResources) { *out = *in @@ -273,6 +488,250 @@ func (in *TaskResources) DeepCopy() *TaskResources { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TaskRun) DeepCopyInto(out *TaskRun) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TaskRun. +func (in *TaskRun) DeepCopy() *TaskRun { + if in == nil { + return nil + } + out := new(TaskRun) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TaskRun) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TaskRunInputs) DeepCopyInto(out *TaskRunInputs) { + *out = *in + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = make([]TaskResourceBinding, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Params != nil { + in, out := &in.Params, &out.Params + *out = make([]Param, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TaskRunInputs. +func (in *TaskRunInputs) DeepCopy() *TaskRunInputs { + if in == nil { + return nil + } + out := new(TaskRunInputs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TaskRunList) DeepCopyInto(out *TaskRunList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]TaskRun, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TaskRunList. +func (in *TaskRunList) DeepCopy() *TaskRunList { + if in == nil { + return nil + } + out := new(TaskRunList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *TaskRunList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TaskRunOutputs) DeepCopyInto(out *TaskRunOutputs) { + *out = *in + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = make([]TaskResourceBinding, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TaskRunOutputs. +func (in *TaskRunOutputs) DeepCopy() *TaskRunOutputs { + if in == nil { + return nil + } + out := new(TaskRunOutputs) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TaskRunResources) DeepCopyInto(out *TaskRunResources) { + *out = *in + if in.Inputs != nil { + in, out := &in.Inputs, &out.Inputs + *out = make([]TaskResourceBinding, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Outputs != nil { + in, out := &in.Outputs, &out.Outputs + *out = make([]TaskResourceBinding, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TaskRunResources. +func (in *TaskRunResources) DeepCopy() *TaskRunResources { + if in == nil { + return nil + } + out := new(TaskRunResources) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TaskRunSpec) DeepCopyInto(out *TaskRunSpec) { + *out = *in + if in.Params != nil { + in, out := &in.Params, &out.Params + *out = make([]Param, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.Resources != nil { + in, out := &in.Resources, &out.Resources + *out = new(TaskRunResources) + (*in).DeepCopyInto(*out) + } + if in.TaskRef != nil { + in, out := &in.TaskRef, &out.TaskRef + *out = new(TaskRef) + **out = **in + } + if in.TaskSpec != nil { + in, out := &in.TaskSpec, &out.TaskSpec + *out = new(TaskSpec) + (*in).DeepCopyInto(*out) + } + if in.Timeout != nil { + in, out := &in.Timeout, &out.Timeout + *out = new(metav1.Duration) + **out = **in + } + in.PodTemplate.DeepCopyInto(&out.PodTemplate) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TaskRunSpec. +func (in *TaskRunSpec) DeepCopy() *TaskRunSpec { + if in == nil { + return nil + } + out := new(TaskRunSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TaskRunStatus) DeepCopyInto(out *TaskRunStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + if in.StartTime != nil { + in, out := &in.StartTime, &out.StartTime + *out = (*in).DeepCopy() + } + if in.CompletionTime != nil { + in, out := &in.CompletionTime, &out.CompletionTime + *out = (*in).DeepCopy() + } + if in.Steps != nil { + in, out := &in.Steps, &out.Steps + *out = make([]StepState, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.CloudEvents != nil { + in, out := &in.CloudEvents, &out.CloudEvents + *out = make([]CloudEventDelivery, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.RetriesStatus != nil { + in, out := &in.RetriesStatus, &out.RetriesStatus + *out = make([]TaskRunStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ResourcesResult != nil { + in, out := &in.ResourcesResult, &out.ResourcesResult + *out = make([]PipelineResourceResult, len(*in)) + copy(*out, *in) + } + if in.Sidecars != nil { + in, out := &in.Sidecars, &out.Sidecars + *out = make([]SidecarState, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TaskRunStatus. +func (in *TaskRunStatus) DeepCopy() *TaskRunStatus { + if in == nil { + return nil + } + out := new(TaskRunStatus) + in.DeepCopyInto(out) + return out +} + // 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 diff --git a/pkg/client/clientset/versioned/typed/pipeline/v1alpha2/fake/fake_pipeline_client.go b/pkg/client/clientset/versioned/typed/pipeline/v1alpha2/fake/fake_pipeline_client.go index b01051d0d42..55e27ae1a9f 100644 --- a/pkg/client/clientset/versioned/typed/pipeline/v1alpha2/fake/fake_pipeline_client.go +++ b/pkg/client/clientset/versioned/typed/pipeline/v1alpha2/fake/fake_pipeline_client.go @@ -32,6 +32,10 @@ func (c *FakeTektonV1alpha2) Tasks(namespace string) v1alpha2.TaskInterface { return &FakeTasks{c, namespace} } +func (c *FakeTektonV1alpha2) TaskRuns(namespace string) v1alpha2.TaskRunInterface { + return &FakeTaskRuns{c, namespace} +} + // RESTClient returns a RESTClient that is used to communicate // with API server by this client implementation. func (c *FakeTektonV1alpha2) RESTClient() rest.Interface { diff --git a/pkg/client/clientset/versioned/typed/pipeline/v1alpha2/fake/fake_taskrun.go b/pkg/client/clientset/versioned/typed/pipeline/v1alpha2/fake/fake_taskrun.go new file mode 100644 index 00000000000..6d1592efc40 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/pipeline/v1alpha2/fake/fake_taskrun.go @@ -0,0 +1,140 @@ +/* +Copyright 2019 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha2 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeTaskRuns implements TaskRunInterface +type FakeTaskRuns struct { + Fake *FakeTektonV1alpha2 + ns string +} + +var taskrunsResource = schema.GroupVersionResource{Group: "tekton.dev", Version: "v1alpha2", Resource: "taskruns"} + +var taskrunsKind = schema.GroupVersionKind{Group: "tekton.dev", Version: "v1alpha2", Kind: "TaskRun"} + +// Get takes name of the taskRun, and returns the corresponding taskRun object, and an error if there is any. +func (c *FakeTaskRuns) Get(name string, options v1.GetOptions) (result *v1alpha2.TaskRun, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(taskrunsResource, c.ns, name), &v1alpha2.TaskRun{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.TaskRun), err +} + +// List takes label and field selectors, and returns the list of TaskRuns that match those selectors. +func (c *FakeTaskRuns) List(opts v1.ListOptions) (result *v1alpha2.TaskRunList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(taskrunsResource, taskrunsKind, c.ns, opts), &v1alpha2.TaskRunList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha2.TaskRunList{ListMeta: obj.(*v1alpha2.TaskRunList).ListMeta} + for _, item := range obj.(*v1alpha2.TaskRunList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested taskRuns. +func (c *FakeTaskRuns) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(taskrunsResource, c.ns, opts)) + +} + +// Create takes the representation of a taskRun and creates it. Returns the server's representation of the taskRun, and an error, if there is any. +func (c *FakeTaskRuns) Create(taskRun *v1alpha2.TaskRun) (result *v1alpha2.TaskRun, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(taskrunsResource, c.ns, taskRun), &v1alpha2.TaskRun{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.TaskRun), err +} + +// Update takes the representation of a taskRun and updates it. Returns the server's representation of the taskRun, and an error, if there is any. +func (c *FakeTaskRuns) Update(taskRun *v1alpha2.TaskRun) (result *v1alpha2.TaskRun, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(taskrunsResource, c.ns, taskRun), &v1alpha2.TaskRun{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.TaskRun), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeTaskRuns) UpdateStatus(taskRun *v1alpha2.TaskRun) (*v1alpha2.TaskRun, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(taskrunsResource, "status", c.ns, taskRun), &v1alpha2.TaskRun{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.TaskRun), err +} + +// Delete takes name of the taskRun and deletes it. Returns an error if one occurs. +func (c *FakeTaskRuns) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(taskrunsResource, c.ns, name), &v1alpha2.TaskRun{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeTaskRuns) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(taskrunsResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &v1alpha2.TaskRunList{}) + return err +} + +// Patch applies the patch and returns the patched taskRun. +func (c *FakeTaskRuns) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.TaskRun, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(taskrunsResource, c.ns, name, pt, data, subresources...), &v1alpha2.TaskRun{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha2.TaskRun), err +} diff --git a/pkg/client/clientset/versioned/typed/pipeline/v1alpha2/generated_expansion.go b/pkg/client/clientset/versioned/typed/pipeline/v1alpha2/generated_expansion.go index 61dab461677..d44576277a4 100644 --- a/pkg/client/clientset/versioned/typed/pipeline/v1alpha2/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/pipeline/v1alpha2/generated_expansion.go @@ -19,3 +19,5 @@ limitations under the License. package v1alpha2 type TaskExpansion interface{} + +type TaskRunExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/pipeline/v1alpha2/pipeline_client.go b/pkg/client/clientset/versioned/typed/pipeline/v1alpha2/pipeline_client.go index 52493bbea87..38437b4d1de 100644 --- a/pkg/client/clientset/versioned/typed/pipeline/v1alpha2/pipeline_client.go +++ b/pkg/client/clientset/versioned/typed/pipeline/v1alpha2/pipeline_client.go @@ -28,6 +28,7 @@ import ( type TektonV1alpha2Interface interface { RESTClient() rest.Interface TasksGetter + TaskRunsGetter } // TektonV1alpha2Client is used to interact with features provided by the tekton.dev group. @@ -39,6 +40,10 @@ func (c *TektonV1alpha2Client) Tasks(namespace string) TaskInterface { return newTasks(c, namespace) } +func (c *TektonV1alpha2Client) TaskRuns(namespace string) TaskRunInterface { + return newTaskRuns(c, namespace) +} + // NewForConfig creates a new TektonV1alpha2Client for the given config. func NewForConfig(c *rest.Config) (*TektonV1alpha2Client, error) { config := *c diff --git a/pkg/client/clientset/versioned/typed/pipeline/v1alpha2/taskrun.go b/pkg/client/clientset/versioned/typed/pipeline/v1alpha2/taskrun.go new file mode 100644 index 00000000000..f56e6e50d4b --- /dev/null +++ b/pkg/client/clientset/versioned/typed/pipeline/v1alpha2/taskrun.go @@ -0,0 +1,191 @@ +/* +Copyright 2019 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + "time" + + v1alpha2 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" + scheme "github.com/tektoncd/pipeline/pkg/client/clientset/versioned/scheme" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// TaskRunsGetter has a method to return a TaskRunInterface. +// A group's client should implement this interface. +type TaskRunsGetter interface { + TaskRuns(namespace string) TaskRunInterface +} + +// TaskRunInterface has methods to work with TaskRun resources. +type TaskRunInterface interface { + Create(*v1alpha2.TaskRun) (*v1alpha2.TaskRun, error) + Update(*v1alpha2.TaskRun) (*v1alpha2.TaskRun, error) + UpdateStatus(*v1alpha2.TaskRun) (*v1alpha2.TaskRun, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha2.TaskRun, error) + List(opts v1.ListOptions) (*v1alpha2.TaskRunList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.TaskRun, err error) + TaskRunExpansion +} + +// taskRuns implements TaskRunInterface +type taskRuns struct { + client rest.Interface + ns string +} + +// newTaskRuns returns a TaskRuns +func newTaskRuns(c *TektonV1alpha2Client, namespace string) *taskRuns { + return &taskRuns{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the taskRun, and returns the corresponding taskRun object, and an error if there is any. +func (c *taskRuns) Get(name string, options v1.GetOptions) (result *v1alpha2.TaskRun, err error) { + result = &v1alpha2.TaskRun{} + err = c.client.Get(). + Namespace(c.ns). + Resource("taskruns"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of TaskRuns that match those selectors. +func (c *taskRuns) List(opts v1.ListOptions) (result *v1alpha2.TaskRunList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha2.TaskRunList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("taskruns"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested taskRuns. +func (c *taskRuns) Watch(opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("taskruns"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a taskRun and creates it. Returns the server's representation of the taskRun, and an error, if there is any. +func (c *taskRuns) Create(taskRun *v1alpha2.TaskRun) (result *v1alpha2.TaskRun, err error) { + result = &v1alpha2.TaskRun{} + err = c.client.Post(). + Namespace(c.ns). + Resource("taskruns"). + Body(taskRun). + Do(). + Into(result) + return +} + +// Update takes the representation of a taskRun and updates it. Returns the server's representation of the taskRun, and an error, if there is any. +func (c *taskRuns) Update(taskRun *v1alpha2.TaskRun) (result *v1alpha2.TaskRun, err error) { + result = &v1alpha2.TaskRun{} + err = c.client.Put(). + Namespace(c.ns). + Resource("taskruns"). + Name(taskRun.Name). + Body(taskRun). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *taskRuns) UpdateStatus(taskRun *v1alpha2.TaskRun) (result *v1alpha2.TaskRun, err error) { + result = &v1alpha2.TaskRun{} + err = c.client.Put(). + Namespace(c.ns). + Resource("taskruns"). + Name(taskRun.Name). + SubResource("status"). + Body(taskRun). + Do(). + Into(result) + return +} + +// Delete takes name of the taskRun and deletes it. Returns an error if one occurs. +func (c *taskRuns) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("taskruns"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *taskRuns) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + var timeout time.Duration + if listOptions.TimeoutSeconds != nil { + timeout = time.Duration(*listOptions.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Namespace(c.ns). + Resource("taskruns"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched taskRun. +func (c *taskRuns) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha2.TaskRun, err error) { + result = &v1alpha2.TaskRun{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("taskruns"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 9ef0cdd5a7c..77acafcebed 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -72,6 +72,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource // Group=tekton.dev, Version=v1alpha2 case v1alpha2.SchemeGroupVersion.WithResource("tasks"): return &genericInformer{resource: resource.GroupResource(), informer: f.Tekton().V1alpha2().Tasks().Informer()}, nil + case v1alpha2.SchemeGroupVersion.WithResource("taskruns"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Tekton().V1alpha2().TaskRuns().Informer()}, nil } diff --git a/pkg/client/informers/externalversions/pipeline/v1alpha2/interface.go b/pkg/client/informers/externalversions/pipeline/v1alpha2/interface.go index 994beeea500..0711f39c21f 100644 --- a/pkg/client/informers/externalversions/pipeline/v1alpha2/interface.go +++ b/pkg/client/informers/externalversions/pipeline/v1alpha2/interface.go @@ -26,6 +26,8 @@ import ( type Interface interface { // Tasks returns a TaskInformer. Tasks() TaskInformer + // TaskRuns returns a TaskRunInformer. + TaskRuns() TaskRunInformer } type version struct { @@ -43,3 +45,8 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList func (v *version) Tasks() TaskInformer { return &taskInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } + +// TaskRuns returns a TaskRunInformer. +func (v *version) TaskRuns() TaskRunInformer { + return &taskRunInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/client/informers/externalversions/pipeline/v1alpha2/taskrun.go b/pkg/client/informers/externalversions/pipeline/v1alpha2/taskrun.go new file mode 100644 index 00000000000..614ff931881 --- /dev/null +++ b/pkg/client/informers/externalversions/pipeline/v1alpha2/taskrun.go @@ -0,0 +1,89 @@ +/* +Copyright 2019 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + time "time" + + pipelinev1alpha2 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" + versioned "github.com/tektoncd/pipeline/pkg/client/clientset/versioned" + internalinterfaces "github.com/tektoncd/pipeline/pkg/client/informers/externalversions/internalinterfaces" + v1alpha2 "github.com/tektoncd/pipeline/pkg/client/listers/pipeline/v1alpha2" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// TaskRunInformer provides access to a shared informer and lister for +// TaskRuns. +type TaskRunInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha2.TaskRunLister +} + +type taskRunInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewTaskRunInformer constructs a new informer for TaskRun type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewTaskRunInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredTaskRunInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredTaskRunInformer constructs a new informer for TaskRun type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredTaskRunInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.TektonV1alpha2().TaskRuns(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.TektonV1alpha2().TaskRuns(namespace).Watch(options) + }, + }, + &pipelinev1alpha2.TaskRun{}, + resyncPeriod, + indexers, + ) +} + +func (f *taskRunInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredTaskRunInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *taskRunInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&pipelinev1alpha2.TaskRun{}, f.defaultInformer) +} + +func (f *taskRunInformer) Lister() v1alpha2.TaskRunLister { + return v1alpha2.NewTaskRunLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/injection/informers/pipeline/v1alpha2/taskrun/fake/fake.go b/pkg/client/injection/informers/pipeline/v1alpha2/taskrun/fake/fake.go new file mode 100644 index 00000000000..33ea930befa --- /dev/null +++ b/pkg/client/injection/informers/pipeline/v1alpha2/taskrun/fake/fake.go @@ -0,0 +1,40 @@ +/* +Copyright 2019 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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + fake "github.com/tektoncd/pipeline/pkg/client/injection/informers/factory/fake" + taskrun "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1alpha2/taskrun" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" +) + +var Get = taskrun.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Tekton().V1alpha2().TaskRuns() + return context.WithValue(ctx, taskrun.Key{}, inf), inf.Informer() +} diff --git a/pkg/client/injection/informers/pipeline/v1alpha2/taskrun/taskrun.go b/pkg/client/injection/informers/pipeline/v1alpha2/taskrun/taskrun.go new file mode 100644 index 00000000000..52addcae9c7 --- /dev/null +++ b/pkg/client/injection/informers/pipeline/v1alpha2/taskrun/taskrun.go @@ -0,0 +1,52 @@ +/* +Copyright 2019 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. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package taskrun + +import ( + "context" + + v1alpha2 "github.com/tektoncd/pipeline/pkg/client/informers/externalversions/pipeline/v1alpha2" + factory "github.com/tektoncd/pipeline/pkg/client/injection/informers/factory" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" + logging "knative.dev/pkg/logging" +) + +func init() { + injection.Default.RegisterInformer(withInformer) +} + +// Key is used for associating the Informer inside the context.Context. +type Key struct{} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := factory.Get(ctx) + inf := f.Tekton().V1alpha2().TaskRuns() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1alpha2.TaskRunInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch github.com/tektoncd/pipeline/pkg/client/informers/externalversions/pipeline/v1alpha2.TaskRunInformer from context.") + } + return untyped.(v1alpha2.TaskRunInformer) +} diff --git a/pkg/client/listers/pipeline/v1alpha2/expansion_generated.go b/pkg/client/listers/pipeline/v1alpha2/expansion_generated.go index 0bdeafb14e8..58e60aefb5d 100644 --- a/pkg/client/listers/pipeline/v1alpha2/expansion_generated.go +++ b/pkg/client/listers/pipeline/v1alpha2/expansion_generated.go @@ -25,3 +25,11 @@ type TaskListerExpansion interface{} // TaskNamespaceListerExpansion allows custom methods to be added to // TaskNamespaceLister. type TaskNamespaceListerExpansion interface{} + +// TaskRunListerExpansion allows custom methods to be added to +// TaskRunLister. +type TaskRunListerExpansion interface{} + +// TaskRunNamespaceListerExpansion allows custom methods to be added to +// TaskRunNamespaceLister. +type TaskRunNamespaceListerExpansion interface{} diff --git a/pkg/client/listers/pipeline/v1alpha2/taskrun.go b/pkg/client/listers/pipeline/v1alpha2/taskrun.go new file mode 100644 index 00000000000..53302307ef6 --- /dev/null +++ b/pkg/client/listers/pipeline/v1alpha2/taskrun.go @@ -0,0 +1,94 @@ +/* +Copyright 2019 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha2 + +import ( + v1alpha2 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha2" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// TaskRunLister helps list TaskRuns. +type TaskRunLister interface { + // List lists all TaskRuns in the indexer. + List(selector labels.Selector) (ret []*v1alpha2.TaskRun, err error) + // TaskRuns returns an object that can list and get TaskRuns. + TaskRuns(namespace string) TaskRunNamespaceLister + TaskRunListerExpansion +} + +// taskRunLister implements the TaskRunLister interface. +type taskRunLister struct { + indexer cache.Indexer +} + +// NewTaskRunLister returns a new TaskRunLister. +func NewTaskRunLister(indexer cache.Indexer) TaskRunLister { + return &taskRunLister{indexer: indexer} +} + +// List lists all TaskRuns in the indexer. +func (s *taskRunLister) List(selector labels.Selector) (ret []*v1alpha2.TaskRun, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha2.TaskRun)) + }) + return ret, err +} + +// TaskRuns returns an object that can list and get TaskRuns. +func (s *taskRunLister) TaskRuns(namespace string) TaskRunNamespaceLister { + return taskRunNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// TaskRunNamespaceLister helps list and get TaskRuns. +type TaskRunNamespaceLister interface { + // List lists all TaskRuns in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1alpha2.TaskRun, err error) + // Get retrieves the TaskRun from the indexer for a given namespace and name. + Get(name string) (*v1alpha2.TaskRun, error) + TaskRunNamespaceListerExpansion +} + +// taskRunNamespaceLister implements the TaskRunNamespaceLister +// interface. +type taskRunNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all TaskRuns in the indexer for a given namespace. +func (s taskRunNamespaceLister) List(selector labels.Selector) (ret []*v1alpha2.TaskRun, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha2.TaskRun)) + }) + return ret, err +} + +// Get retrieves the TaskRun from the indexer for a given namespace and name. +func (s taskRunNamespaceLister) Get(name string) (*v1alpha2.TaskRun, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha2.Resource("taskrun"), name) + } + return obj.(*v1alpha2.TaskRun), nil +}