From 3240550c87316314403304c164ac3b0aa73a63f0 Mon Sep 17 00:00:00 2001 From: Jason Hall Date: Sat, 27 Jun 2020 00:03:02 -0400 Subject: [PATCH] Define v1alpha1 Run type and generated scaffolding This defines the basic Run type, which will be used to specify executions of Custom Tasks and report status of those executions. This change doesn't wire the new type in to any controllers or validating webhooks, so that this time nothing will happen when a Run is created. It also doesn't wire in to PipelineRun execution to enable Pipelines to specify Custom Tasks. --- config/300-run.yaml | 71 ++++ pkg/apis/pipeline/controller.go | 5 +- pkg/apis/pipeline/register.go | 8 + pkg/apis/pipeline/v1alpha1/register.go | 2 + pkg/apis/pipeline/v1alpha1/run_defaults.go | 34 ++ pkg/apis/pipeline/v1alpha1/run_types.go | 154 ++++++++ pkg/apis/pipeline/v1alpha1/run_types_test.go | 97 +++++ pkg/apis/pipeline/v1alpha1/run_validation.go | 58 +++ .../pipeline/v1alpha1/run_validation_test.go | 155 ++++++++ .../pipeline/v1alpha1/taskrun_validation.go | 9 +- .../v1alpha1/zz_generated.deepcopy.go | 136 +++++++ .../v1alpha1/fake/fake_pipeline_client.go | 4 + .../typed/pipeline/v1alpha1/fake/fake_run.go | 140 +++++++ .../pipeline/v1alpha1/generated_expansion.go | 2 + .../pipeline/v1alpha1/pipeline_client.go | 5 + .../versioned/typed/pipeline/v1alpha1/run.go | 191 ++++++++++ .../informers/externalversions/generic.go | 2 + .../pipeline/v1alpha1/interface.go | 7 + .../externalversions/pipeline/v1alpha1/run.go | 89 +++++ .../pipeline/v1alpha1/run/fake/fake.go | 40 ++ .../informers/pipeline/v1alpha1/run/run.go | 52 +++ .../pipeline/v1alpha1/run/controller.go | 118 ++++++ .../pipeline/v1alpha1/run/reconciler.go | 352 ++++++++++++++++++ .../pipeline/v1alpha1/run/stub/controller.go | 54 +++ .../pipeline/v1alpha1/run/stub/reconciler.go | 66 ++++ .../pipeline/v1alpha1/expansion_generated.go | 8 + pkg/client/listers/pipeline/v1alpha1/run.go | 94 +++++ 27 files changed, 1948 insertions(+), 5 deletions(-) create mode 100644 config/300-run.yaml create mode 100644 pkg/apis/pipeline/v1alpha1/run_defaults.go create mode 100644 pkg/apis/pipeline/v1alpha1/run_types.go create mode 100644 pkg/apis/pipeline/v1alpha1/run_types_test.go create mode 100644 pkg/apis/pipeline/v1alpha1/run_validation.go create mode 100644 pkg/apis/pipeline/v1alpha1/run_validation_test.go create mode 100644 pkg/client/clientset/versioned/typed/pipeline/v1alpha1/fake/fake_run.go create mode 100644 pkg/client/clientset/versioned/typed/pipeline/v1alpha1/run.go create mode 100644 pkg/client/informers/externalversions/pipeline/v1alpha1/run.go create mode 100644 pkg/client/injection/informers/pipeline/v1alpha1/run/fake/fake.go create mode 100644 pkg/client/injection/informers/pipeline/v1alpha1/run/run.go create mode 100644 pkg/client/injection/reconciler/pipeline/v1alpha1/run/controller.go create mode 100644 pkg/client/injection/reconciler/pipeline/v1alpha1/run/reconciler.go create mode 100644 pkg/client/injection/reconciler/pipeline/v1alpha1/run/stub/controller.go create mode 100644 pkg/client/injection/reconciler/pipeline/v1alpha1/run/stub/reconciler.go create mode 100644 pkg/client/listers/pipeline/v1alpha1/run.go diff --git a/config/300-run.yaml b/config/300-run.yaml new file mode 100644 index 00000000000..b699c13b646 --- /dev/null +++ b/config/300-run.yaml @@ -0,0 +1,71 @@ +# 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 +# +# https://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. + +apiVersion: apiextensions.k8s.io/v1beta1 +kind: CustomResourceDefinition +metadata: + name: runs.tekton.dev + labels: + app.kubernetes.io/instance: default + app.kubernetes.io/part-of: tekton-pipelines + pipeline.tekton.dev/release: "devel" + version: "devel" +spec: + group: tekton.dev + preserveUnknownFields: false + validation: + openAPIV3Schema: + type: object + # One can use x-kubernetes-preserve-unknown-fields: true + # at the root of the schema (and inside any properties, additionalProperties) + # to get the traditional CRD behaviour that nothing is pruned, despite + # setting spec.preserveUnknownProperties: false. + # + # See https://kubernetes.io/blog/2019/06/20/crd-structural-schema/ + # See issue: https://github.com/knative/serving/issues/912 + x-kubernetes-preserve-unknown-fields: true + versions: + - name: v1alpha1 + served: true + storage: true + names: + kind: Run + plural: runs + categories: + - tekton + - tekton-pipelines + scope: Namespaced + additionalPrinterColumns: + - name: Succeeded + type: string + JSONPath: ".status.conditions[?(@.type==\"Succeeded\")].status" + - name: Reason + type: string + JSONPath: ".status.conditions[?(@.type==\"Succeeded\")].reason" + - name: StartTime + type: date + JSONPath: .status.startTime + - name: CompletionTime + type: date + JSONPath: .status.completionTime + # Opt into the status subresource so metadata.generation + # starts to increment + subresources: + status: {} + conversion: + strategy: Webhook + webhookClientConfig: + service: + name: tekton-pipelines-webhook + namespace: tekton-pipelines diff --git a/pkg/apis/pipeline/controller.go b/pkg/apis/pipeline/controller.go index 38fe60b4be9..6332e371e4d 100644 --- a/pkg/apis/pipeline/controller.go +++ b/pkg/apis/pipeline/controller.go @@ -21,6 +21,9 @@ const ( // nolint: golint PipelineRunControllerName = "PipelineRun" - // TaskRunControllerName holds the name of the PipelineRun controller + // TaskRunControllerName holds the name of the TaskRun controller TaskRunControllerName = "TaskRun" + + // TaskRunControllerName holds the name of the PipelineRun controller + RunControllerName = "Run" ) diff --git a/pkg/apis/pipeline/register.go b/pkg/apis/pipeline/register.go index c65484d9763..f34e682c67a 100644 --- a/pkg/apis/pipeline/register.go +++ b/pkg/apis/pipeline/register.go @@ -45,6 +45,9 @@ const ( // ConditionNameKey is used as the label identifier for a Condition ConditionNameKey = "/conditionName" + + // RunKey is used as the label identifier for a Run + RunKey = "/run" ) var ( @@ -63,6 +66,11 @@ var ( Group: GroupName, Resource: "taskruns", } + // RunResource represents a Tekton Run + RunResource = schema.GroupResource{ + Group: GroupName, + Resource: "runs", + } // PipelineResource represents a Tekton Pipeline PipelineResource = schema.GroupResource{ Group: GroupName, diff --git a/pkg/apis/pipeline/v1alpha1/register.go b/pkg/apis/pipeline/v1alpha1/register.go index a8d52721405..78b59bfdce1 100644 --- a/pkg/apis/pipeline/v1alpha1/register.go +++ b/pkg/apis/pipeline/v1alpha1/register.go @@ -60,6 +60,8 @@ func addKnownTypes(scheme *runtime.Scheme) error { &PipelineRunList{}, &PipelineResource{}, &PipelineResourceList{}, + &Run{}, + &RunList{}, ) metav1.AddToGroupVersion(scheme, SchemeGroupVersion) return nil diff --git a/pkg/apis/pipeline/v1alpha1/run_defaults.go b/pkg/apis/pipeline/v1alpha1/run_defaults.go new file mode 100644 index 00000000000..77d6d7861f6 --- /dev/null +++ b/pkg/apis/pipeline/v1alpha1/run_defaults.go @@ -0,0 +1,34 @@ +/* +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 v1alpha1 + +import ( + "context" + + "knative.dev/pkg/apis" +) + +var _ apis.Defaultable = (*Run)(nil) + +func (r *Run) SetDefaults(ctx context.Context) { + ctx = apis.WithinParent(ctx, r.ObjectMeta) + r.Spec.SetDefaults(apis.WithinSpec(ctx)) +} + +func (rs *RunSpec) SetDefaults(ctx context.Context) { + // No defaults to set. +} diff --git a/pkg/apis/pipeline/v1alpha1/run_types.go b/pkg/apis/pipeline/v1alpha1/run_types.go new file mode 100644 index 00000000000..89c1f6b5b0c --- /dev/null +++ b/pkg/apis/pipeline/v1alpha1/run_types.go @@ -0,0 +1,154 @@ +/* +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 v1alpha1 + +import ( + "fmt" + + "github.com/tektoncd/pipeline/pkg/apis/pipeline" + v1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime/schema" + "knative.dev/pkg/apis" + duckv1beta1 "knative.dev/pkg/apis/duck/v1beta1" +) + +var ( + runGroupVersionKind = schema.GroupVersionKind{ + Group: SchemeGroupVersion.Group, + Version: SchemeGroupVersion.Version, + Kind: pipeline.RunControllerName, + } +) + +// RunSpec defines the desired state of Run +type RunSpec struct { + // +optional + Ref *TaskRef `json:"ref,omitempty"` + + // +optional + Params []v1beta1.Param `json:"params,omitempty"` + + // TODO(https://github.com/tektoncd/community/pull/128) + // - cancellation + // - timeout + // - inline task spec + // - workspaces ? +} + +// TODO(jasonhall): Move this to a Params type so other code can use it? +func (rs RunSpec) GetParam(name string) *v1beta1.Param { + for _, p := range rs.Params { + if p.Name == name { + return &p + } + } + return nil +} + +type RunStatus struct { + duckv1beta1.Status `json:",inline"` + + // RunStatusFields inlines the status fields. + RunStatusFields `json:",inline"` +} + +// RunStatusFields holds the fields of Run's status. This is defined +// separately and inlined so that other types can readily consume these fields +// via duck typing. +type RunStatusFields struct { + // 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"` + + // Results reports any output result values to be consumed by later + // tasks in a pipeline. + // +optional + Results []v1beta1.TaskRunResult `json:"results,omitempty"` + + // TODO(jasonhall): Add a field to hold additional arbitrary fields as + // a map[string]interface{}. +} + +// +genclient +// +genreconciler +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Run represents a single execution of a Custom Task. +// +// +k8s:openapi-gen=true +type Run struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata,omitempty"` + + // +optional + Spec RunSpec `json:"spec,omitempty"` + // +optional + Status RunStatus `json:"status,omitempty"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// RunList contains a list of Run +type RunList struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ListMeta `json:"metadata,omitempty"` + Items []Run `json:"items"` +} + +// GetOwnerReference gets the task run as owner reference for any related objects +func (r *Run) GetOwnerReference() metav1.OwnerReference { + return *metav1.NewControllerRef(r, runGroupVersionKind) +} + +// HasPipelineRunOwnerReference returns true of Run has +// owner reference of type PipelineRun +func (r *Run) HasPipelineRunOwnerReference() bool { + for _, ref := range r.GetOwnerReferences() { + if ref.Kind == pipeline.PipelineRunControllerName { + return true + } + } + return false +} + +// IsDone returns true if the Run's status indicates that it is done. +func (r *Run) IsDone() bool { + return !r.Status.GetCondition(apis.ConditionSucceeded).IsUnknown() +} + +// HasStarted function check whether taskrun has valid start time set in its status +func (r *Run) HasStarted() bool { + return r.Status.StartTime != nil && !r.Status.StartTime.IsZero() +} + +// IsSuccessful returns true if the Run's status indicates that it is done. +func (r *Run) IsSuccessful() bool { + return r.Status.GetCondition(apis.ConditionSucceeded).IsTrue() +} + +// GetRunKey return the taskrun key for timeout handler map +func (r *Run) GetRunKey() string { + // The address of the pointer is a threadsafe unique identifier for the taskrun + return fmt.Sprintf("%s/%p", "Run", r) +} diff --git a/pkg/apis/pipeline/v1alpha1/run_types_test.go b/pkg/apis/pipeline/v1alpha1/run_types_test.go new file mode 100644 index 00000000000..f6cc9a1dbd1 --- /dev/null +++ b/pkg/apis/pipeline/v1alpha1/run_types_test.go @@ -0,0 +1,97 @@ +/* +Copyright 2020 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1_test + +import ( + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + v1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" +) + +func TestGetParams(t *testing.T) { + for _, c := range []struct { + desc string + spec v1alpha1.RunSpec + name string + want *v1beta1.Param + }{{ + desc: "no params", + spec: v1alpha1.RunSpec{}, + name: "anything", + want: nil, + }, { + desc: "found", + spec: v1alpha1.RunSpec{ + Params: []v1beta1.Param{{ + Name: "first", + Value: v1beta1.NewArrayOrString("blah"), + }, { + Name: "foo", + Value: v1beta1.NewArrayOrString("bar"), + }}, + }, + name: "foo", + want: &v1beta1.Param{ + Name: "foo", + Value: v1beta1.NewArrayOrString("bar"), + }, + }, { + desc: "not found", + spec: v1alpha1.RunSpec{ + Params: []v1beta1.Param{{ + Name: "first", + Value: v1beta1.NewArrayOrString("blah"), + }, { + Name: "foo", + Value: v1beta1.NewArrayOrString("bar"), + }}, + }, + name: "bar", + want: nil, + }, { + // This shouldn't happen since it's invalid, but just in + // case, GetParams just returns the first param it finds with + // the specified name. + desc: "multiple with same name", + spec: v1alpha1.RunSpec{ + Params: []v1beta1.Param{{ + Name: "first", + Value: v1beta1.NewArrayOrString("blah"), + }, { + Name: "foo", + Value: v1beta1.NewArrayOrString("bar"), + }, { + Name: "foo", + Value: v1beta1.NewArrayOrString("second bar"), + }}, + }, + name: "foo", + want: &v1beta1.Param{ + Name: "foo", + Value: v1beta1.NewArrayOrString("bar"), + }, + }} { + t.Run(c.desc, func(t *testing.T) { + got := c.spec.GetParam(c.name) + if d := cmp.Diff(c.want, got); d != "" { + t.Fatalf("Diff(-want,+got): %v", d) + } + }) + } +} diff --git a/pkg/apis/pipeline/v1alpha1/run_validation.go b/pkg/apis/pipeline/v1alpha1/run_validation.go new file mode 100644 index 00000000000..d7feb75545f --- /dev/null +++ b/pkg/apis/pipeline/v1alpha1/run_validation.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 v1alpha1 + +import ( + "context" + + "github.com/tektoncd/pipeline/pkg/apis/validate" + "k8s.io/apimachinery/pkg/api/equality" + "knative.dev/pkg/apis" +) + +var _ apis.Validatable = (*Run)(nil) + +// Validate taskrun +func (r *Run) Validate(ctx context.Context) *apis.FieldError { + if err := validate.ObjectMetadata(r.GetObjectMeta()).ViaField("metadata"); err != nil { + return err + } + return r.Spec.Validate(ctx) +} + +// Validate Run spec +func (rs *RunSpec) Validate(ctx context.Context) *apis.FieldError { + if equality.Semantic.DeepEqual(rs, &RunSpec{}) { + return apis.ErrMissingField("spec") + } + + if rs.Ref == nil { + return apis.ErrMissingField("spec.ref") + } + if rs.Ref.APIVersion == "" { + return apis.ErrMissingField("spec.ref.apiVersion") + } + if rs.Ref.Kind == "" { + return apis.ErrMissingField("spec.ref.kind") + } + + if err := validateParameters("spec.params", rs.Params); err != nil { + return err + } + + return nil +} diff --git a/pkg/apis/pipeline/v1alpha1/run_validation_test.go b/pkg/apis/pipeline/v1alpha1/run_validation_test.go new file mode 100644 index 00000000000..b1fce95e92f --- /dev/null +++ b/pkg/apis/pipeline/v1alpha1/run_validation_test.go @@ -0,0 +1,155 @@ +/* +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 v1alpha1_test + +import ( + "context" + "testing" + + "github.com/google/go-cmp/cmp" + "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + v1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" + "github.com/tektoncd/pipeline/test/diff" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "knative.dev/pkg/apis" +) + +func TestRun_Invalid(t *testing.T) { + for _, c := range []struct { + name string + run *v1alpha1.Run + want *apis.FieldError + }{{ + name: "missing spec", + run: &v1alpha1.Run{}, + want: apis.ErrMissingField("spec"), + }, { + name: "invalid metadata", + run: &v1alpha1.Run{ + ObjectMeta: metav1.ObjectMeta{Name: "run.name"}, + }, + want: &apis.FieldError{ + Message: "Invalid resource name: special character . must not be present", + Paths: []string{"metadata.name"}, + }, + }, { + name: "missing ref", + run: &v1alpha1.Run{ + Spec: v1alpha1.RunSpec{ + Ref: nil, + }, + }, + want: apis.ErrMissingField("spec"), + }, { + name: "missing apiVersion", + run: &v1alpha1.Run{ + Spec: v1alpha1.RunSpec{ + Ref: &v1alpha1.TaskRef{ + APIVersion: "", + }, + }, + }, + want: apis.ErrMissingField("spec.ref.apiVersion"), + }, { + name: "missing kind", + run: &v1alpha1.Run{ + Spec: v1alpha1.RunSpec{ + Ref: &v1alpha1.TaskRef{ + APIVersion: "blah", + Kind: "", + }, + }, + }, + want: apis.ErrMissingField("spec.ref.kind"), + }, { + name: "non-unique params", + run: &v1alpha1.Run{ + Spec: v1alpha1.RunSpec{ + Ref: &v1alpha1.TaskRef{ + APIVersion: "blah", + Kind: "blah", + }, + Params: []v1beta1.Param{{ + Name: "foo", + Value: v1beta1.NewArrayOrString("foo"), + }, { + Name: "foo", + Value: v1beta1.NewArrayOrString("foo"), + }}, + }, + }, + want: apis.ErrMultipleOneOf("spec.params"), + }} { + t.Run(c.name, func(t *testing.T) { + err := c.run.Validate(context.Background()) + if d := cmp.Diff(err.Error(), c.want.Error()); d != "" { + t.Error(diff.PrintWantGot(d)) + } + }) + } +} + +func TestRun_Valid(t *testing.T) { + for _, c := range []struct { + name string + run *v1alpha1.Run + }{{ + name: "no params", + run: &v1alpha1.Run{ + Spec: v1alpha1.RunSpec{ + Ref: &v1alpha1.TaskRef{ + APIVersion: "blah", + Kind: "blah", + Name: "blah", + }, + }, + }, + }, { + name: "unnamed", + run: &v1alpha1.Run{ + Spec: v1alpha1.RunSpec{ + Ref: &v1alpha1.TaskRef{ + APIVersion: "blah", + Kind: "blah", + }, + }, + }, + }, { + name: "unique params", + run: &v1alpha1.Run{ + Spec: v1alpha1.RunSpec{ + Ref: &v1alpha1.TaskRef{ + APIVersion: "blah", + Kind: "blah", + }, + Params: []v1beta1.Param{{ + Name: "foo", + Value: v1beta1.NewArrayOrString("foo"), + }, { + Name: "bar", + Value: v1beta1.NewArrayOrString("bar"), + }}, + }, + }, + }} { + t.Run(c.name, func(t *testing.T) { + if err := c.run.Validate(context.Background()); err != nil { + t.Fatalf("validating valid Run: %v", err) + } + }) + } +} diff --git a/pkg/apis/pipeline/v1alpha1/taskrun_validation.go b/pkg/apis/pipeline/v1alpha1/taskrun_validation.go index 9aeeaed8b63..ceccb737b68 100644 --- a/pkg/apis/pipeline/v1alpha1/taskrun_validation.go +++ b/pkg/apis/pipeline/v1alpha1/taskrun_validation.go @@ -83,7 +83,7 @@ func (ts *TaskRunSpec) Validate(ctx context.Context) *apis.FieldError { if err := validateWorkspaceBindings(ctx, ts.Workspaces); err != nil { return err } - if err := validateParameters(ts.Params); err != nil { + if err := validateParameters("spec.inputs.params", ts.Params); err != nil { return err } @@ -101,7 +101,7 @@ func (i TaskRunInputs) Validate(ctx context.Context, path string) *apis.FieldErr if err := validatePipelineResources(ctx, i.Resources, fmt.Sprintf("%s.Resources.Name", path)); err != nil { return err } - return validateParameters(i.Params) + return validateParameters("spec.inputs.params", i.Params) } func (o TaskRunOutputs) Validate(ctx context.Context, path string) *apis.FieldError { @@ -154,12 +154,13 @@ func validatePipelineResources(ctx context.Context, resources []TaskResourceBind return nil } -func validateParameters(params []Param) *apis.FieldError { +// TODO(jasonhall): Share this with v1beta1/taskrun_validation.go +func validateParameters(path string, 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") + return apis.ErrMultipleOneOf(path) } seen[p.Name] = struct{}{} } diff --git a/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go index 55e61fb5d07..8854c9fe4da 100644 --- a/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go @@ -610,6 +610,142 @@ func (in *PipelineTaskRunSpec) DeepCopy() *PipelineTaskRunSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Run) DeepCopyInto(out *Run) { + *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 Run. +func (in *Run) DeepCopy() *Run { + if in == nil { + return nil + } + out := new(Run) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Run) 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 *RunList) DeepCopyInto(out *RunList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]Run, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunList. +func (in *RunList) DeepCopy() *RunList { + if in == nil { + return nil + } + out := new(RunList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *RunList) 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 *RunSpec) DeepCopyInto(out *RunSpec) { + *out = *in + if in.Ref != nil { + in, out := &in.Ref, &out.Ref + *out = new(v1beta1.TaskRef) + **out = **in + } + if in.Params != nil { + in, out := &in.Params, &out.Params + *out = make([]v1beta1.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 RunSpec. +func (in *RunSpec) DeepCopy() *RunSpec { + if in == nil { + return nil + } + out := new(RunSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RunStatus) DeepCopyInto(out *RunStatus) { + *out = *in + in.Status.DeepCopyInto(&out.Status) + in.RunStatusFields.DeepCopyInto(&out.RunStatusFields) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunStatus. +func (in *RunStatus) DeepCopy() *RunStatus { + if in == nil { + return nil + } + out := new(RunStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *RunStatusFields) DeepCopyInto(out *RunStatusFields) { + *out = *in + 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.Results != nil { + in, out := &in.Results, &out.Results + *out = make([]v1beta1.TaskRunResult, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunStatusFields. +func (in *RunStatusFields) DeepCopy() *RunStatusFields { + if in == nil { + return nil + } + out := new(RunStatusFields) + 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 diff --git a/pkg/client/clientset/versioned/typed/pipeline/v1alpha1/fake/fake_pipeline_client.go b/pkg/client/clientset/versioned/typed/pipeline/v1alpha1/fake/fake_pipeline_client.go index 5bcbcb1cd5a..f04cb586314 100644 --- a/pkg/client/clientset/versioned/typed/pipeline/v1alpha1/fake/fake_pipeline_client.go +++ b/pkg/client/clientset/versioned/typed/pipeline/v1alpha1/fake/fake_pipeline_client.go @@ -44,6 +44,10 @@ func (c *FakeTektonV1alpha1) PipelineRuns(namespace string) v1alpha1.PipelineRun return &FakePipelineRuns{c, namespace} } +func (c *FakeTektonV1alpha1) Runs(namespace string) v1alpha1.RunInterface { + return &FakeRuns{c, namespace} +} + func (c *FakeTektonV1alpha1) Tasks(namespace string) v1alpha1.TaskInterface { return &FakeTasks{c, namespace} } diff --git a/pkg/client/clientset/versioned/typed/pipeline/v1alpha1/fake/fake_run.go b/pkg/client/clientset/versioned/typed/pipeline/v1alpha1/fake/fake_run.go new file mode 100644 index 00000000000..354630d2a96 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/pipeline/v1alpha1/fake/fake_run.go @@ -0,0 +1,140 @@ +/* +Copyright 2020 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + v1alpha1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + 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" +) + +// FakeRuns implements RunInterface +type FakeRuns struct { + Fake *FakeTektonV1alpha1 + ns string +} + +var runsResource = schema.GroupVersionResource{Group: "tekton.dev", Version: "v1alpha1", Resource: "runs"} + +var runsKind = schema.GroupVersionKind{Group: "tekton.dev", Version: "v1alpha1", Kind: "Run"} + +// Get takes name of the run, and returns the corresponding run object, and an error if there is any. +func (c *FakeRuns) Get(name string, options v1.GetOptions) (result *v1alpha1.Run, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(runsResource, c.ns, name), &v1alpha1.Run{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Run), err +} + +// List takes label and field selectors, and returns the list of Runs that match those selectors. +func (c *FakeRuns) List(opts v1.ListOptions) (result *v1alpha1.RunList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(runsResource, runsKind, c.ns, opts), &v1alpha1.RunList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.RunList{ListMeta: obj.(*v1alpha1.RunList).ListMeta} + for _, item := range obj.(*v1alpha1.RunList).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 runs. +func (c *FakeRuns) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(runsResource, c.ns, opts)) + +} + +// Create takes the representation of a run and creates it. Returns the server's representation of the run, and an error, if there is any. +func (c *FakeRuns) Create(run *v1alpha1.Run) (result *v1alpha1.Run, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(runsResource, c.ns, run), &v1alpha1.Run{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Run), err +} + +// Update takes the representation of a run and updates it. Returns the server's representation of the run, and an error, if there is any. +func (c *FakeRuns) Update(run *v1alpha1.Run) (result *v1alpha1.Run, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(runsResource, c.ns, run), &v1alpha1.Run{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Run), 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 *FakeRuns) UpdateStatus(run *v1alpha1.Run) (*v1alpha1.Run, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(runsResource, "status", c.ns, run), &v1alpha1.Run{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Run), err +} + +// Delete takes name of the run and deletes it. Returns an error if one occurs. +func (c *FakeRuns) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(runsResource, c.ns, name), &v1alpha1.Run{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeRuns) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(runsResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &v1alpha1.RunList{}) + return err +} + +// Patch applies the patch and returns the patched run. +func (c *FakeRuns) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Run, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(runsResource, c.ns, name, pt, data, subresources...), &v1alpha1.Run{}) + + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.Run), err +} diff --git a/pkg/client/clientset/versioned/typed/pipeline/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/pipeline/v1alpha1/generated_expansion.go index a3b6b03b044..6942df0f45e 100644 --- a/pkg/client/clientset/versioned/typed/pipeline/v1alpha1/generated_expansion.go +++ b/pkg/client/clientset/versioned/typed/pipeline/v1alpha1/generated_expansion.go @@ -26,6 +26,8 @@ type PipelineExpansion interface{} type PipelineRunExpansion interface{} +type RunExpansion interface{} + type TaskExpansion interface{} type TaskRunExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/pipeline/v1alpha1/pipeline_client.go b/pkg/client/clientset/versioned/typed/pipeline/v1alpha1/pipeline_client.go index f96f3e34db9..5797a3003a7 100644 --- a/pkg/client/clientset/versioned/typed/pipeline/v1alpha1/pipeline_client.go +++ b/pkg/client/clientset/versioned/typed/pipeline/v1alpha1/pipeline_client.go @@ -30,6 +30,7 @@ type TektonV1alpha1Interface interface { ConditionsGetter PipelinesGetter PipelineRunsGetter + RunsGetter TasksGetter TaskRunsGetter } @@ -55,6 +56,10 @@ func (c *TektonV1alpha1Client) PipelineRuns(namespace string) PipelineRunInterfa return newPipelineRuns(c, namespace) } +func (c *TektonV1alpha1Client) Runs(namespace string) RunInterface { + return newRuns(c, namespace) +} + func (c *TektonV1alpha1Client) Tasks(namespace string) TaskInterface { return newTasks(c, namespace) } diff --git a/pkg/client/clientset/versioned/typed/pipeline/v1alpha1/run.go b/pkg/client/clientset/versioned/typed/pipeline/v1alpha1/run.go new file mode 100644 index 00000000000..9efaff0baad --- /dev/null +++ b/pkg/client/clientset/versioned/typed/pipeline/v1alpha1/run.go @@ -0,0 +1,191 @@ +/* +Copyright 2020 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "time" + + v1alpha1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + 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" +) + +// RunsGetter has a method to return a RunInterface. +// A group's client should implement this interface. +type RunsGetter interface { + Runs(namespace string) RunInterface +} + +// RunInterface has methods to work with Run resources. +type RunInterface interface { + Create(*v1alpha1.Run) (*v1alpha1.Run, error) + Update(*v1alpha1.Run) (*v1alpha1.Run, error) + UpdateStatus(*v1alpha1.Run) (*v1alpha1.Run, error) + Delete(name string, options *v1.DeleteOptions) error + DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error + Get(name string, options v1.GetOptions) (*v1alpha1.Run, error) + List(opts v1.ListOptions) (*v1alpha1.RunList, error) + Watch(opts v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Run, err error) + RunExpansion +} + +// runs implements RunInterface +type runs struct { + client rest.Interface + ns string +} + +// newRuns returns a Runs +func newRuns(c *TektonV1alpha1Client, namespace string) *runs { + return &runs{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the run, and returns the corresponding run object, and an error if there is any. +func (c *runs) Get(name string, options v1.GetOptions) (result *v1alpha1.Run, err error) { + result = &v1alpha1.Run{} + err = c.client.Get(). + Namespace(c.ns). + Resource("runs"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of Runs that match those selectors. +func (c *runs) List(opts v1.ListOptions) (result *v1alpha1.RunList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.RunList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("runs"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested runs. +func (c *runs) 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("runs"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch() +} + +// Create takes the representation of a run and creates it. Returns the server's representation of the run, and an error, if there is any. +func (c *runs) Create(run *v1alpha1.Run) (result *v1alpha1.Run, err error) { + result = &v1alpha1.Run{} + err = c.client.Post(). + Namespace(c.ns). + Resource("runs"). + Body(run). + Do(). + Into(result) + return +} + +// Update takes the representation of a run and updates it. Returns the server's representation of the run, and an error, if there is any. +func (c *runs) Update(run *v1alpha1.Run) (result *v1alpha1.Run, err error) { + result = &v1alpha1.Run{} + err = c.client.Put(). + Namespace(c.ns). + Resource("runs"). + Name(run.Name). + Body(run). + 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 *runs) UpdateStatus(run *v1alpha1.Run) (result *v1alpha1.Run, err error) { + result = &v1alpha1.Run{} + err = c.client.Put(). + Namespace(c.ns). + Resource("runs"). + Name(run.Name). + SubResource("status"). + Body(run). + Do(). + Into(result) + return +} + +// Delete takes name of the run and deletes it. Returns an error if one occurs. +func (c *runs) Delete(name string, options *v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("runs"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *runs) 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("runs"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Timeout(timeout). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched run. +func (c *runs) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1alpha1.Run, err error) { + result = &v1alpha1.Run{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("runs"). + 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 b7c6452058a..3d05774d1c5 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -62,6 +62,8 @@ func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource return &genericInformer{resource: resource.GroupResource(), informer: f.Tekton().V1alpha1().Pipelines().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("pipelineruns"): return &genericInformer{resource: resource.GroupResource(), informer: f.Tekton().V1alpha1().PipelineRuns().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("runs"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Tekton().V1alpha1().Runs().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("tasks"): return &genericInformer{resource: resource.GroupResource(), informer: f.Tekton().V1alpha1().Tasks().Informer()}, nil case v1alpha1.SchemeGroupVersion.WithResource("taskruns"): diff --git a/pkg/client/informers/externalversions/pipeline/v1alpha1/interface.go b/pkg/client/informers/externalversions/pipeline/v1alpha1/interface.go index fa069ae3945..5b9882c30d7 100644 --- a/pkg/client/informers/externalversions/pipeline/v1alpha1/interface.go +++ b/pkg/client/informers/externalversions/pipeline/v1alpha1/interface.go @@ -32,6 +32,8 @@ type Interface interface { Pipelines() PipelineInformer // PipelineRuns returns a PipelineRunInformer. PipelineRuns() PipelineRunInformer + // Runs returns a RunInformer. + Runs() RunInformer // Tasks returns a TaskInformer. Tasks() TaskInformer // TaskRuns returns a TaskRunInformer. @@ -69,6 +71,11 @@ func (v *version) PipelineRuns() PipelineRunInformer { return &pipelineRunInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} } +// Runs returns a RunInformer. +func (v *version) Runs() RunInformer { + return &runInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + // Tasks returns a TaskInformer. func (v *version) Tasks() TaskInformer { return &taskInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} diff --git a/pkg/client/informers/externalversions/pipeline/v1alpha1/run.go b/pkg/client/informers/externalversions/pipeline/v1alpha1/run.go new file mode 100644 index 00000000000..3fa4984b1b6 --- /dev/null +++ b/pkg/client/informers/externalversions/pipeline/v1alpha1/run.go @@ -0,0 +1,89 @@ +/* +Copyright 2020 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + time "time" + + pipelinev1alpha1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + versioned "github.com/tektoncd/pipeline/pkg/client/clientset/versioned" + internalinterfaces "github.com/tektoncd/pipeline/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "github.com/tektoncd/pipeline/pkg/client/listers/pipeline/v1alpha1" + 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" +) + +// RunInformer provides access to a shared informer and lister for +// Runs. +type RunInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.RunLister +} + +type runInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewRunInformer constructs a new informer for Run 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 NewRunInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredRunInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredRunInformer constructs a new informer for Run 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 NewFilteredRunInformer(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.TektonV1alpha1().Runs(namespace).List(options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.TektonV1alpha1().Runs(namespace).Watch(options) + }, + }, + &pipelinev1alpha1.Run{}, + resyncPeriod, + indexers, + ) +} + +func (f *runInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredRunInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *runInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&pipelinev1alpha1.Run{}, f.defaultInformer) +} + +func (f *runInformer) Lister() v1alpha1.RunLister { + return v1alpha1.NewRunLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/injection/informers/pipeline/v1alpha1/run/fake/fake.go b/pkg/client/injection/informers/pipeline/v1alpha1/run/fake/fake.go new file mode 100644 index 00000000000..14d4c6fa1d4 --- /dev/null +++ b/pkg/client/injection/informers/pipeline/v1alpha1/run/fake/fake.go @@ -0,0 +1,40 @@ +/* +Copyright 2020 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package fake + +import ( + context "context" + + fake "github.com/tektoncd/pipeline/pkg/client/injection/informers/factory/fake" + run "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1alpha1/run" + controller "knative.dev/pkg/controller" + injection "knative.dev/pkg/injection" +) + +var Get = run.Get + +func init() { + injection.Fake.RegisterInformer(withInformer) +} + +func withInformer(ctx context.Context) (context.Context, controller.Informer) { + f := fake.Get(ctx) + inf := f.Tekton().V1alpha1().Runs() + return context.WithValue(ctx, run.Key{}, inf), inf.Informer() +} diff --git a/pkg/client/injection/informers/pipeline/v1alpha1/run/run.go b/pkg/client/injection/informers/pipeline/v1alpha1/run/run.go new file mode 100644 index 00000000000..fc3b89bb9c4 --- /dev/null +++ b/pkg/client/injection/informers/pipeline/v1alpha1/run/run.go @@ -0,0 +1,52 @@ +/* +Copyright 2020 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package run + +import ( + context "context" + + v1alpha1 "github.com/tektoncd/pipeline/pkg/client/informers/externalversions/pipeline/v1alpha1" + 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().V1alpha1().Runs() + return context.WithValue(ctx, Key{}, inf), inf.Informer() +} + +// Get extracts the typed informer from the context. +func Get(ctx context.Context) v1alpha1.RunInformer { + untyped := ctx.Value(Key{}) + if untyped == nil { + logging.FromContext(ctx).Panic( + "Unable to fetch github.com/tektoncd/pipeline/pkg/client/informers/externalversions/pipeline/v1alpha1.RunInformer from context.") + } + return untyped.(v1alpha1.RunInformer) +} diff --git a/pkg/client/injection/reconciler/pipeline/v1alpha1/run/controller.go b/pkg/client/injection/reconciler/pipeline/v1alpha1/run/controller.go new file mode 100644 index 00000000000..bbae77bbba6 --- /dev/null +++ b/pkg/client/injection/reconciler/pipeline/v1alpha1/run/controller.go @@ -0,0 +1,118 @@ +/* +Copyright 2020 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package run + +import ( + context "context" + fmt "fmt" + reflect "reflect" + strings "strings" + + versionedscheme "github.com/tektoncd/pipeline/pkg/client/clientset/versioned/scheme" + client "github.com/tektoncd/pipeline/pkg/client/injection/client" + run "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1alpha1/run" + corev1 "k8s.io/api/core/v1" + watch "k8s.io/apimachinery/pkg/watch" + scheme "k8s.io/client-go/kubernetes/scheme" + v1 "k8s.io/client-go/kubernetes/typed/core/v1" + record "k8s.io/client-go/tools/record" + kubeclient "knative.dev/pkg/client/injection/kube/client" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" +) + +const ( + defaultControllerAgentName = "run-controller" + defaultFinalizerName = "runs.tekton.dev" +) + +// NewImpl returns a controller.Impl that handles queuing and feeding work from +// the queue through an implementation of controller.Reconciler, delegating to +// the provided Interface and optional Finalizer methods. OptionsFn is used to return +// controller.Options to be used but the internal reconciler. +func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl { + logger := logging.FromContext(ctx) + + // Check the options function input. It should be 0 or 1. + if len(optionsFns) > 1 { + logger.Fatalf("up to one options function is supported, found %d", len(optionsFns)) + } + + runInformer := run.Get(ctx) + + rec := &reconcilerImpl{ + Client: client.Get(ctx), + Lister: runInformer.Lister(), + reconciler: r, + finalizerName: defaultFinalizerName, + } + + t := reflect.TypeOf(r).Elem() + queueName := fmt.Sprintf("%s.%s", strings.ReplaceAll(t.PkgPath(), "/", "-"), t.Name()) + + impl := controller.NewImpl(rec, logger, queueName) + agentName := defaultControllerAgentName + + // Pass impl to the options. Save any optional results. + for _, fn := range optionsFns { + opts := fn(impl) + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + if opts.FinalizerName != "" { + rec.finalizerName = opts.FinalizerName + } + if opts.AgentName != "" { + agentName = opts.AgentName + } + } + + rec.Recorder = createRecorder(ctx, agentName) + + return impl +} + +func createRecorder(ctx context.Context, agentName string) record.EventRecorder { + logger := logging.FromContext(ctx) + + recorder := controller.GetEventRecorder(ctx) + if recorder == nil { + // Create event broadcaster + logger.Debug("Creating event broadcaster") + eventBroadcaster := record.NewBroadcaster() + watches := []watch.Interface{ + eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof), + eventBroadcaster.StartRecordingToSink( + &v1.EventSinkImpl{Interface: kubeclient.Get(ctx).CoreV1().Events("")}), + } + recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: agentName}) + go func() { + <-ctx.Done() + for _, w := range watches { + w.Stop() + } + }() + } + + return recorder +} + +func init() { + versionedscheme.AddToScheme(scheme.Scheme) +} diff --git a/pkg/client/injection/reconciler/pipeline/v1alpha1/run/reconciler.go b/pkg/client/injection/reconciler/pipeline/v1alpha1/run/reconciler.go new file mode 100644 index 00000000000..043e30d9acc --- /dev/null +++ b/pkg/client/injection/reconciler/pipeline/v1alpha1/run/reconciler.go @@ -0,0 +1,352 @@ +/* +Copyright 2020 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package run + +import ( + context "context" + json "encoding/json" + reflect "reflect" + + v1alpha1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + versioned "github.com/tektoncd/pipeline/pkg/client/clientset/versioned" + pipelinev1alpha1 "github.com/tektoncd/pipeline/pkg/client/listers/pipeline/v1alpha1" + zap "go.uber.org/zap" + v1 "k8s.io/api/core/v1" + equality "k8s.io/apimachinery/pkg/api/equality" + errors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + sets "k8s.io/apimachinery/pkg/util/sets" + cache "k8s.io/client-go/tools/cache" + record "k8s.io/client-go/tools/record" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" + reconciler "knative.dev/pkg/reconciler" +) + +// Interface defines the strongly typed interfaces to be implemented by a +// controller reconciling v1alpha1.Run. +type Interface interface { + // ReconcileKind implements custom logic to reconcile v1alpha1.Run. Any changes + // to the objects .Status or .Finalizers will be propagated to the stored + // object. It is recommended that implementors do not call any update calls + // for the Kind inside of ReconcileKind, it is the responsibility of the calling + // controller to propagate those properties. The resource passed to ReconcileKind + // will always have an empty deletion timestamp. + ReconcileKind(ctx context.Context, o *v1alpha1.Run) reconciler.Event +} + +// Finalizer defines the strongly typed interfaces to be implemented by a +// controller finalizing v1alpha1.Run. +type Finalizer interface { + // FinalizeKind implements custom logic to finalize v1alpha1.Run. Any changes + // to the objects .Status or .Finalizers will be ignored. Returning a nil or + // Normal type reconciler.Event will allow the finalizer to be deleted on + // the resource. The resource passed to FinalizeKind will always have a set + // deletion timestamp. + FinalizeKind(ctx context.Context, o *v1alpha1.Run) reconciler.Event +} + +// reconcilerImpl implements controller.Reconciler for v1alpha1.Run resources. +type reconcilerImpl struct { + // Client is used to write back status updates. + Client versioned.Interface + + // Listers index properties about resources + Lister pipelinev1alpha1.RunLister + + // Recorder is an event recorder for recording Event resources to the + // Kubernetes API. + Recorder record.EventRecorder + + // configStore allows for decorating a context with config maps. + // +optional + configStore reconciler.ConfigStore + + // reconciler is the implementation of the business logic of the resource. + reconciler Interface + + // finalizerName is the name of the finalizer to reconcile. + finalizerName string +} + +// Check that our Reconciler implements controller.Reconciler +var _ controller.Reconciler = (*reconcilerImpl)(nil) + +func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister pipelinev1alpha1.RunLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler { + // Check the options function input. It should be 0 or 1. + if len(options) > 1 { + logger.Fatalf("up to one options struct is supported, found %d", len(options)) + } + + rec := &reconcilerImpl{ + Client: client, + Lister: lister, + Recorder: recorder, + reconciler: r, + finalizerName: defaultFinalizerName, + } + + for _, opts := range options { + if opts.ConfigStore != nil { + rec.configStore = opts.ConfigStore + } + if opts.FinalizerName != "" { + rec.finalizerName = opts.FinalizerName + } + } + + return rec +} + +// Reconcile implements controller.Reconciler +func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error { + logger := logging.FromContext(ctx) + + // If configStore is set, attach the frozen configuration to the context. + if r.configStore != nil { + ctx = r.configStore.ToContext(ctx) + } + + // Add the recorder to context. + ctx = controller.WithEventRecorder(ctx, r.Recorder) + + // Convert the namespace/name string into a distinct namespace and name + + namespace, name, err := cache.SplitMetaNamespaceKey(key) + + if err != nil { + logger.Errorf("invalid resource key: %s", key) + return nil + } + + // Get the resource with this namespace/name. + + getter := r.Lister.Runs(namespace) + + original, err := getter.Get(name) + + if errors.IsNotFound(err) { + // The resource may no longer exist, in which case we stop processing. + logger.Debugf("resource %q no longer exists", key) + return nil + } else if err != nil { + return err + } + + // Don't modify the informers copy. + resource := original.DeepCopy() + + var reconcileEvent reconciler.Event + if resource.GetDeletionTimestamp().IsZero() { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "ReconcileKind")) + + // Set and update the finalizer on resource if r.reconciler + // implements Finalizer. + if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil { + logger.Warnw("Failed to set finalizers", zap.Error(err)) + } + + // Reconcile this copy of the resource and then write back any status + // updates regardless of whether the reconciliation errored out. + reconcileEvent = r.reconciler.ReconcileKind(ctx, resource) + + } else if fin, ok := r.reconciler.(Finalizer); ok { + // Append the target method to the logger. + logger = logger.With(zap.String("targetMethod", "FinalizeKind")) + + // For finalizing reconcilers, if this resource being marked for deletion + // and reconciled cleanly (nil or normal event), remove the finalizer. + reconcileEvent = fin.FinalizeKind(ctx, resource) + if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil { + logger.Warnw("Failed to clear finalizers", zap.Error(err)) + } + } + + // Synchronize the status. + if equality.Semantic.DeepEqual(original.Status, resource.Status) { + // If we didn't change anything then don't call updateStatus. + // This is important because the copy we loaded from the injectionInformer's + // cache may be stale and we don't want to overwrite a prior update + // to status with this stale state. + } else if err = r.updateStatus(original, resource); err != nil { + logger.Warnw("Failed to update resource status", zap.Error(err)) + r.Recorder.Eventf(resource, v1.EventTypeWarning, "UpdateFailed", + "Failed to update status for %q: %v", resource.Name, err) + return err + } + + // Report the reconciler event, if any. + if reconcileEvent != nil { + var event *reconciler.ReconcilerEvent + if reconciler.EventAs(reconcileEvent, &event) { + logger.Infow("Returned an event", zap.Any("event", reconcileEvent)) + r.Recorder.Eventf(resource, event.EventType, event.Reason, event.Format, event.Args...) + + // the event was wrapped inside an error, consider the reconciliation as failed + if _, isEvent := reconcileEvent.(*reconciler.ReconcilerEvent); !isEvent { + return reconcileEvent + } + return nil + } + + logger.Errorw("Returned an error", zap.Error(reconcileEvent)) + r.Recorder.Event(resource, v1.EventTypeWarning, "InternalError", reconcileEvent.Error()) + return reconcileEvent + } + + return nil +} + +func (r *reconcilerImpl) updateStatus(existing *v1alpha1.Run, desired *v1alpha1.Run) error { + existing = existing.DeepCopy() + return reconciler.RetryUpdateConflicts(func(attempts int) (err error) { + // The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API. + if attempts > 0 { + + getter := r.Client.TektonV1alpha1().Runs(desired.Namespace) + + existing, err = getter.Get(desired.Name, metav1.GetOptions{}) + if err != nil { + return err + } + } + + // If there's nothing to update, just return. + if reflect.DeepEqual(existing.Status, desired.Status) { + return nil + } + + existing.Status = desired.Status + + updater := r.Client.TektonV1alpha1().Runs(existing.Namespace) + + _, err = updater.UpdateStatus(existing) + return err + }) +} + +// updateFinalizersFiltered will update the Finalizers of the resource. +// TODO: this method could be generic and sync all finalizers. For now it only +// updates defaultFinalizerName or its override. +func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1alpha1.Run) (*v1alpha1.Run, error) { + + getter := r.Lister.Runs(resource.Namespace) + + actual, err := getter.Get(resource.Name) + if err != nil { + return resource, err + } + + // Don't modify the informers copy. + existing := actual.DeepCopy() + + var finalizers []string + + // If there's nothing to update, just return. + existingFinalizers := sets.NewString(existing.Finalizers...) + desiredFinalizers := sets.NewString(resource.Finalizers...) + + if desiredFinalizers.Has(r.finalizerName) { + if existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Add the finalizer. + finalizers = append(existing.Finalizers, r.finalizerName) + } else { + if !existingFinalizers.Has(r.finalizerName) { + // Nothing to do. + return resource, nil + } + // Remove the finalizer. + existingFinalizers.Delete(r.finalizerName) + finalizers = existingFinalizers.List() + } + + mergePatch := map[string]interface{}{ + "metadata": map[string]interface{}{ + "finalizers": finalizers, + "resourceVersion": existing.ResourceVersion, + }, + } + + patch, err := json.Marshal(mergePatch) + if err != nil { + return resource, err + } + + patcher := r.Client.TektonV1alpha1().Runs(resource.Namespace) + + resource, err = patcher.Patch(resource.Name, types.MergePatchType, patch) + if err != nil { + r.Recorder.Eventf(resource, v1.EventTypeWarning, "FinalizerUpdateFailed", + "Failed to update finalizers for %q: %v", resource.Name, err) + } else { + r.Recorder.Eventf(resource, v1.EventTypeNormal, "FinalizerUpdate", + "Updated %q finalizers", resource.GetName()) + } + return resource, err +} + +func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1alpha1.Run) (*v1alpha1.Run, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + + finalizers := sets.NewString(resource.Finalizers...) + + // If this resource is not being deleted, mark the finalizer. + if resource.GetDeletionTimestamp().IsZero() { + finalizers.Insert(r.finalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} + +func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1alpha1.Run, reconcileEvent reconciler.Event) (*v1alpha1.Run, error) { + if _, ok := r.reconciler.(Finalizer); !ok { + return resource, nil + } + if resource.GetDeletionTimestamp().IsZero() { + return resource, nil + } + + finalizers := sets.NewString(resource.Finalizers...) + + if reconcileEvent != nil { + var event *reconciler.ReconcilerEvent + if reconciler.EventAs(reconcileEvent, &event) { + if event.EventType == v1.EventTypeNormal { + finalizers.Delete(r.finalizerName) + } + } + } else { + finalizers.Delete(r.finalizerName) + } + + resource.Finalizers = finalizers.List() + + // Synchronize the finalizers filtered by r.finalizerName. + return r.updateFinalizersFiltered(ctx, resource) +} diff --git a/pkg/client/injection/reconciler/pipeline/v1alpha1/run/stub/controller.go b/pkg/client/injection/reconciler/pipeline/v1alpha1/run/stub/controller.go new file mode 100644 index 00000000000..144ec4f89d1 --- /dev/null +++ b/pkg/client/injection/reconciler/pipeline/v1alpha1/run/stub/controller.go @@ -0,0 +1,54 @@ +/* +Copyright 2020 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package run + +import ( + context "context" + + run "github.com/tektoncd/pipeline/pkg/client/injection/informers/pipeline/v1alpha1/run" + v1alpha1run "github.com/tektoncd/pipeline/pkg/client/injection/reconciler/pipeline/v1alpha1/run" + configmap "knative.dev/pkg/configmap" + controller "knative.dev/pkg/controller" + logging "knative.dev/pkg/logging" +) + +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// NewController creates a Reconciler for Run and returns the result of NewImpl. +func NewController( + ctx context.Context, + cmw configmap.Watcher, +) *controller.Impl { + logger := logging.FromContext(ctx) + + runInformer := run.Get(ctx) + + // TODO: setup additional informers here. + + r := &Reconciler{} + impl := v1alpha1run.NewImpl(ctx, r) + + logger.Info("Setting up event handlers.") + + runInformer.Informer().AddEventHandler(controller.HandleAll(impl.Enqueue)) + + // TODO: add additional informer event handlers here. + + return impl +} diff --git a/pkg/client/injection/reconciler/pipeline/v1alpha1/run/stub/reconciler.go b/pkg/client/injection/reconciler/pipeline/v1alpha1/run/stub/reconciler.go new file mode 100644 index 00000000000..d7322fb125b --- /dev/null +++ b/pkg/client/injection/reconciler/pipeline/v1alpha1/run/stub/reconciler.go @@ -0,0 +1,66 @@ +/* +Copyright 2020 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by injection-gen. DO NOT EDIT. + +package run + +import ( + context "context" + + v1alpha1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + run "github.com/tektoncd/pipeline/pkg/client/injection/reconciler/pipeline/v1alpha1/run" + v1 "k8s.io/api/core/v1" + reconciler "knative.dev/pkg/reconciler" +) + +// TODO: PLEASE COPY AND MODIFY THIS FILE AS A STARTING POINT + +// newReconciledNormal makes a new reconciler event with event type Normal, and +// reason RunReconciled. +func newReconciledNormal(namespace, name string) reconciler.Event { + return reconciler.NewEvent(v1.EventTypeNormal, "RunReconciled", "Run reconciled: \"%s/%s\"", namespace, name) +} + +// Reconciler implements controller.Reconciler for Run resources. +type Reconciler struct { + // TODO: add additional requirements here. +} + +// Check that our Reconciler implements Interface +var _ run.Interface = (*Reconciler)(nil) + +// Optionally check that our Reconciler implements Finalizer +//var _ run.Finalizer = (*Reconciler)(nil) + +// ReconcileKind implements Interface.ReconcileKind. +func (r *Reconciler) ReconcileKind(ctx context.Context, o *v1alpha1.Run) reconciler.Event { + // TODO: use this if the resource implements InitializeConditions. + // o.Status.InitializeConditions() + + // TODO: add custom reconciliation logic here. + + // TODO: use this if the object has .status.ObservedGeneration. + // o.Status.ObservedGeneration = o.Generation + return newReconciledNormal(o.Namespace, o.Name) +} + +// Optionally, use FinalizeKind to add finalizers. FinalizeKind will be called +// when the resource is deleted. +//func (r *Reconciler) FinalizeKind(ctx context.Context, o *v1alpha1.Run) reconciler.Event { +// // TODO: add custom finalization logic here. +// return nil +//} diff --git a/pkg/client/listers/pipeline/v1alpha1/expansion_generated.go b/pkg/client/listers/pipeline/v1alpha1/expansion_generated.go index 9e4b934db74..fc4bd080d6a 100644 --- a/pkg/client/listers/pipeline/v1alpha1/expansion_generated.go +++ b/pkg/client/listers/pipeline/v1alpha1/expansion_generated.go @@ -46,6 +46,14 @@ type PipelineRunListerExpansion interface{} // PipelineRunNamespaceLister. type PipelineRunNamespaceListerExpansion interface{} +// RunListerExpansion allows custom methods to be added to +// RunLister. +type RunListerExpansion interface{} + +// RunNamespaceListerExpansion allows custom methods to be added to +// RunNamespaceLister. +type RunNamespaceListerExpansion interface{} + // TaskListerExpansion allows custom methods to be added to // TaskLister. type TaskListerExpansion interface{} diff --git a/pkg/client/listers/pipeline/v1alpha1/run.go b/pkg/client/listers/pipeline/v1alpha1/run.go new file mode 100644 index 00000000000..194d1a2bf5f --- /dev/null +++ b/pkg/client/listers/pipeline/v1alpha1/run.go @@ -0,0 +1,94 @@ +/* +Copyright 2020 The Tekton Authors + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + v1alpha1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// RunLister helps list Runs. +type RunLister interface { + // List lists all Runs in the indexer. + List(selector labels.Selector) (ret []*v1alpha1.Run, err error) + // Runs returns an object that can list and get Runs. + Runs(namespace string) RunNamespaceLister + RunListerExpansion +} + +// runLister implements the RunLister interface. +type runLister struct { + indexer cache.Indexer +} + +// NewRunLister returns a new RunLister. +func NewRunLister(indexer cache.Indexer) RunLister { + return &runLister{indexer: indexer} +} + +// List lists all Runs in the indexer. +func (s *runLister) List(selector labels.Selector) (ret []*v1alpha1.Run, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.Run)) + }) + return ret, err +} + +// Runs returns an object that can list and get Runs. +func (s *runLister) Runs(namespace string) RunNamespaceLister { + return runNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// RunNamespaceLister helps list and get Runs. +type RunNamespaceLister interface { + // List lists all Runs in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1alpha1.Run, err error) + // Get retrieves the Run from the indexer for a given namespace and name. + Get(name string) (*v1alpha1.Run, error) + RunNamespaceListerExpansion +} + +// runNamespaceLister implements the RunNamespaceLister +// interface. +type runNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all Runs in the indexer for a given namespace. +func (s runNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.Run, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.Run)) + }) + return ret, err +} + +// Get retrieves the Run from the indexer for a given namespace and name. +func (s runNamespaceLister) Get(name string) (*v1alpha1.Run, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("run"), name) + } + return obj.(*v1alpha1.Run), nil +}