From b5972d6f256f9d0ebcf8f82a79b2caf544421d2b Mon Sep 17 00:00:00 2001 From: Priti Desai Date: Thu, 5 Sep 2019 09:14:38 -0700 Subject: [PATCH] Adding support to enable resourceSpec Its now possible to embed the resource specifications into Pipeline Run using resourceSpec, for example: apiVersion: tekton.dev/v1alpha1 kind: PipelineRun metadata: name: pipelinerun-echo-greetings spec: resources: - name: git-repo resourceRef: name: my-git-repo Can be specified as: apiVersion: tekton.dev/v1alpha1 kind: PipelineRun name: pipelinerun-echo-greetings spec: resources: - name: git-repo resourceSpec: type: git params: - name: url value: https://github.com/myrepo/myrepo.git --- docs/pipelineruns.md | 31 ++++- .../pipelinerun-with-resourcespec.yaml | 98 ++++++++++++++ .../v1alpha1/pipelinerun_validation_test.go | 10 +- pkg/apis/pipeline/v1alpha1/resource_types.go | 4 + .../v1alpha1/zz_generated.deepcopy.go | 9 +- .../pipelinerun/pipelinerun_test.go | 6 +- .../resources/conditionresolution.go | 17 ++- .../resources/conditionresolution_test.go | 3 - .../resources/input_output_steps.go | 33 +++-- .../resources/input_output_steps_test.go | 120 +++++++++++++++++- .../resources/pipelinerunresolution.go | 50 +++++--- .../resources/pipelinerunresolution_test.go | 47 ++++--- pkg/reconciler/taskrun/taskrun_test.go | 21 +-- test/builder/pipeline.go | 10 +- test/builder/pipeline_test.go | 73 +++++++++++ test/builder/task.go | 3 - test/builder/task_test.go | 1 + 17 files changed, 445 insertions(+), 91 deletions(-) create mode 100644 examples/pipelineruns/pipelinerun-with-resourcespec.yaml diff --git a/docs/pipelineruns.md b/docs/pipelineruns.md index b4d8553ed45..9878fdc39c8 100644 --- a/docs/pipelineruns.md +++ b/docs/pipelineruns.md @@ -85,6 +85,34 @@ spec: name: skaffold-image-leeroy-app ``` +Or you can embed the spec of the `Resource` directly in the `PipelineRun`: + + +```yaml +spec: + resources: + - name: source-repo + resourceSpec: + type: git + params: + - name: revision + value: v0.32.0 + - name: url + value: https://github.com/GoogleContainerTools/skaffold + - name: web-image + resourceSpec: + type: image + params: + - name: url + value: gcr.io/christiewilson-catfactory/leeroy-web + - name: app-image + resourceSpec: + type: image + params: + - name: url + value: gcr.io/christiewilson-catfactory/leeroy-app +``` + ### Service Account Specifies the `name` of a `ServiceAccount` resource object. Use the @@ -121,7 +149,6 @@ spec: - name: build-task taskRef: name: build-push - tasks: - name: test-task taskRef: name: test @@ -174,7 +201,7 @@ spec: tasks: - name: task1 taskRef: - name: myTask + name: myTask --- apiVersion: tekton.dev/v1alpha1 kind: PipelineRun diff --git a/examples/pipelineruns/pipelinerun-with-resourcespec.yaml b/examples/pipelineruns/pipelinerun-with-resourcespec.yaml new file mode 100644 index 00000000000..018c5c35051 --- /dev/null +++ b/examples/pipelineruns/pipelinerun-with-resourcespec.yaml @@ -0,0 +1,98 @@ +apiVersion: tekton.dev/v1alpha1 +kind: Task +metadata: + name: task-to-list-files +spec: + inputs: + resources: + - name: pipeline-git + type: git + outputs: + resources: + - name: pipeline-git + type: git + steps: + - name: list + image: ubuntu + command: + - bash + args: + - -c + - | + ls -al $(inputs.resources.pipeline-git.path) +--- + +apiVersion: tekton.dev/v1alpha1 +kind: Condition +metadata: + name: always-true-sample-condition +spec: + resources: + - name: pipeline-git + type: git + check: + image: ubuntu + command: + - bash + args: + - -c + - | + echo "Hello from Tekton Pipeline!" +--- + +apiVersion: tekton.dev/v1alpha1 +kind: Pipeline +metadata: + name: pipeline-to-list-files +spec: + resources: + - name: pipeline-git + type: git + params: + - name: "path" + default: "README.md" + tasks: + - name: list-files + taskRef: + name: task-to-list-files + resources: + inputs: + - name: pipeline-git + resource: pipeline-git + outputs: + - name: pipeline-git + resource: pipeline-git + - name: conditional-list-files + taskRef: + name: task-to-list-files + conditions: + - conditionRef: always-true-sample-condition + resources: + - name: pipeline-git + resource: pipeline-git + resources: + inputs: + - name: pipeline-git + resource: pipeline-git + outputs: + - name: pipeline-git + resource: pipeline-git +--- + +apiVersion: tekton.dev/v1alpha1 +kind: PipelineRun +metadata: + name: demo-pipelinerun-with-resourcespec +spec: + pipelineRef: + name: pipeline-to-list-files + serviceAccount: 'default' + resources: + - name: pipeline-git + resourceSpec: + type: git + params: + - name: revision + value: master + - name: url + value: https://github.com/tektoncd/pipeline diff --git a/pkg/apis/pipeline/v1alpha1/pipelinerun_validation_test.go b/pkg/apis/pipeline/v1alpha1/pipelinerun_validation_test.go index a30777d20ea..d60937d9f59 100644 --- a/pkg/apis/pipeline/v1alpha1/pipelinerun_validation_test.go +++ b/pkg/apis/pipeline/v1alpha1/pipelinerun_validation_test.go @@ -81,11 +81,11 @@ func TestPipelineRun_Invalidate(t *testing.T) { }, } - for _, ts := range tests { - t.Run(ts.name, func(t *testing.T) { - err := ts.pr.Validate(context.Background()) - if d := cmp.Diff(err.Error(), ts.want.Error()); d != "" { - t.Errorf("PipelineRun.Validate/%s (-want, +got) = %v", ts.name, d) + for _, ps := range tests { + t.Run(ps.name, func(t *testing.T) { + err := ps.pr.Validate(context.Background()) + if d := cmp.Diff(err.Error(), ps.want.Error()); d != "" { + t.Errorf("PipelineRun.Validate/%s (-want, +got) = %v", ps.name, d) } }) } diff --git a/pkg/apis/pipeline/v1alpha1/resource_types.go b/pkg/apis/pipeline/v1alpha1/resource_types.go index 238ce4482fc..7ef4942a94c 100644 --- a/pkg/apis/pipeline/v1alpha1/resource_types.go +++ b/pkg/apis/pipeline/v1alpha1/resource_types.go @@ -116,6 +116,10 @@ type PipelineResourceBinding struct { // ResourceRef is a reference to the instance of the actual PipelineResource // that should be used ResourceRef PipelineResourceRef `json:"resourceRef,omitempty"` + // +optional + // ResourceSpec is specification of a resource that should be created and + // consumed by the task + ResourceSpec *PipelineResourceSpec `json:"resourceSpec,omitempty"` } // PipelineResourceResult used to export the image name and digest as json diff --git a/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go index 08aafcd1c78..ebaaa2a10ad 100644 --- a/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/pipeline/v1alpha1/zz_generated.deepcopy.go @@ -735,6 +735,11 @@ func (in *PipelineResource) DeepCopyObject() runtime.Object { func (in *PipelineResourceBinding) DeepCopyInto(out *PipelineResourceBinding) { *out = *in out.ResourceRef = in.ResourceRef + if in.ResourceSpec != nil { + in, out := &in.ResourceSpec, &out.ResourceSpec + *out = new(PipelineResourceSpec) + (*in).DeepCopyInto(*out) + } return } @@ -944,7 +949,9 @@ func (in *PipelineRunSpec) DeepCopyInto(out *PipelineRunSpec) { if in.Resources != nil { in, out := &in.Resources, &out.Resources *out = make([]PipelineResourceBinding, len(*in)) - copy(*out, *in) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } } if in.Params != nil { in, out := &in.Params, &out.Params diff --git a/pkg/reconciler/pipelinerun/pipelinerun_test.go b/pkg/reconciler/pipelinerun/pipelinerun_test.go index 1f530d9728f..ef7645d75e3 100644 --- a/pkg/reconciler/pipelinerun/pipelinerun_test.go +++ b/pkg/reconciler/pipelinerun/pipelinerun_test.go @@ -211,13 +211,13 @@ func TestReconcile(t *testing.T) { tb.TaskRunInputsParam("foo", "somethingfun"), tb.TaskRunInputsParam("bar", "somethingmorefun"), tb.TaskRunInputsParam("templatedparam", "$(inputs.workspace.revision)"), - tb.TaskRunInputsResource("workspace", tb.TaskResourceBindingRef("some-repo")), + tb.TaskRunInputsResource("workspace", tb.TaskResourceBindingResourceSpec(&rs[0].Spec)), ), tb.TaskRunOutputs( - tb.TaskRunOutputsResource("image-to-use", tb.TaskResourceBindingRef("some-image"), + tb.TaskRunOutputsResource("image-to-use", tb.TaskResourceBindingResourceSpec(&rs[1].Spec), tb.TaskResourceBindingPaths("/pvc/unit-test-1/image-to-use"), ), - tb.TaskRunOutputsResource("workspace", tb.TaskResourceBindingRef("some-repo"), + tb.TaskRunOutputsResource("workspace", tb.TaskResourceBindingResourceSpec(&rs[0].Spec), tb.TaskResourceBindingPaths("/pvc/unit-test-1/workspace"), ), ), diff --git a/pkg/reconciler/pipelinerun/resources/conditionresolution.go b/pkg/reconciler/pipelinerun/resources/conditionresolution.go index d3f3338c1c3..9a8691b1126 100644 --- a/pkg/reconciler/pipelinerun/resources/conditionresolution.go +++ b/pkg/reconciler/pipelinerun/resources/conditionresolution.go @@ -174,13 +174,22 @@ func (rcc *ResolvedConditionCheck) ToTaskResourceBindings() []v1alpha1.TaskResou var trb []v1alpha1.TaskResourceBinding for name, r := range rcc.ResolvedResources { - trb = append(trb, v1alpha1.TaskResourceBinding{ + tr := v1alpha1.TaskResourceBinding{ Name: name, - ResourceRef: v1alpha1.PipelineResourceRef{ + } + if r.SelfLink != "" { + tr.ResourceRef = v1alpha1.PipelineResourceRef{ Name: r.Name, APIVersion: r.APIVersion, - }, - }) + } + } else if r.Spec.Type != "" { + tr.ResourceSpec = &v1alpha1.PipelineResourceSpec{ + Type: r.Spec.Type, + Params: r.Spec.Params, + SecretParams: r.Spec.SecretParams, + } + } + trb = append(trb, tr) } return trb diff --git a/pkg/reconciler/pipelinerun/resources/conditionresolution_test.go b/pkg/reconciler/pipelinerun/resources/conditionresolution_test.go index 997ba148a05..83b3a43f30d 100644 --- a/pkg/reconciler/pipelinerun/resources/conditionresolution_test.go +++ b/pkg/reconciler/pipelinerun/resources/conditionresolution_test.go @@ -290,9 +290,6 @@ func TestResolvedConditionCheck_ToTaskResourceBindings(t *testing.T) { expected := []v1alpha1.TaskResourceBinding{{ Name: "git-resource", - ResourceRef: v1alpha1.PipelineResourceRef{ - Name: "some-repo", - }, }} if d := cmp.Diff(expected, rcc.ToTaskResourceBindings()); d != "" { diff --git a/pkg/reconciler/pipelinerun/resources/input_output_steps.go b/pkg/reconciler/pipelinerun/resources/input_output_steps.go index ac4747abec8..f75d721b786 100644 --- a/pkg/reconciler/pipelinerun/resources/input_output_steps.go +++ b/pkg/reconciler/pipelinerun/resources/input_output_steps.go @@ -27,14 +27,23 @@ func GetOutputSteps(outputs map[string]*v1alpha1.PipelineResource, taskName, sto var taskOutputResources []v1alpha1.TaskResourceBinding for name, outputResource := range outputs { - taskOutputResources = append(taskOutputResources, v1alpha1.TaskResourceBinding{ - Name: name, - ResourceRef: v1alpha1.PipelineResourceRef{ + taskOutputResource := v1alpha1.TaskResourceBinding{ + Name: name, + Paths: []string{filepath.Join(storageBasePath, taskName, name)}, + } + if outputResource.SelfLink != "" { + taskOutputResource.ResourceRef = v1alpha1.PipelineResourceRef{ Name: outputResource.Name, APIVersion: outputResource.APIVersion, - }, - Paths: []string{filepath.Join(storageBasePath, taskName, name)}, - }) + } + } else if outputResource.Spec.Type != "" { + taskOutputResource.ResourceSpec = &v1alpha1.PipelineResourceSpec{ + Type: outputResource.Spec.Type, + Params: outputResource.Spec.Params, + SecretParams: outputResource.Spec.SecretParams, + } + } + taskOutputResources = append(taskOutputResources, taskOutputResource) } return taskOutputResources } @@ -47,10 +56,18 @@ func GetInputSteps(inputs map[string]*v1alpha1.PipelineResource, pt *v1alpha1.Pi for name, inputResource := range inputs { taskInputResource := v1alpha1.TaskResourceBinding{ Name: name, - ResourceRef: v1alpha1.PipelineResourceRef{ + } + if inputResource.SelfLink != "" { + taskInputResource.ResourceRef = v1alpha1.PipelineResourceRef{ Name: inputResource.Name, APIVersion: inputResource.APIVersion, - }, + } + } else if inputResource.Spec.Type != "" { + taskInputResource.ResourceSpec = &v1alpha1.PipelineResourceSpec{ + Type: inputResource.Spec.Type, + Params: inputResource.Spec.Params, + SecretParams: inputResource.Spec.SecretParams, + } } var stepSourceNames []string diff --git a/pkg/reconciler/pipelinerun/resources/input_output_steps_test.go b/pkg/reconciler/pipelinerun/resources/input_output_steps_test.go index c2bd133bd33..8f398d12165 100644 --- a/pkg/reconciler/pipelinerun/resources/input_output_steps_test.go +++ b/pkg/reconciler/pipelinerun/resources/input_output_steps_test.go @@ -31,12 +31,24 @@ var pvcDir = "/pvc" func TestGetOutputSteps(t *testing.T) { r1 := &v1alpha1.PipelineResource{ ObjectMeta: metav1.ObjectMeta{ - Name: "resource1", + Name: "resource1", + SelfLink: "/apis/tekton.dev/pipelineresources/resource1", }, } r2 := &v1alpha1.PipelineResource{ ObjectMeta: metav1.ObjectMeta{ - Name: "resource2", + Name: "resource2", + SelfLink: "/apis/tekton.dev/pipelineresources/resource2", + }, + } + r3 := &v1alpha1.PipelineResource{ + Spec: v1alpha1.PipelineResourceSpec{ + Type: v1alpha1.PipelineResourceTypeGit, + Params: []v1alpha1.ResourceParam{{ + Name: "url", + Value: "https://github.com/tektoncd/pipeline.git", + }}, + SecretParams: nil, }, } tcs := []struct { @@ -69,6 +81,31 @@ func TestGetOutputSteps(t *testing.T) { Paths: []string{"/pvc/test-multiple-outputs/test-output-2"}, }}, pipelineTaskName: "test-multiple-outputs", + }, { + name: "single output with resource spec", + outputs: map[string]*v1alpha1.PipelineResource{"test-output": r3}, + expectedtaskOuputResources: []v1alpha1.TaskResourceBinding{{ + Name: "test-output", + ResourceSpec: &r3.Spec, + Paths: []string{"/pvc/test-taskname/test-output"}, + }}, + pipelineTaskName: "test-taskname", + }, { + name: "multiple-outputs-with-resource-spec", + outputs: map[string]*v1alpha1.PipelineResource{ + "test-output-1": r3, + "test-output-2": r3, + }, + expectedtaskOuputResources: []v1alpha1.TaskResourceBinding{{ + Name: "test-output-1", + ResourceSpec: &r3.Spec, + Paths: []string{"/pvc/test-multiple-outputs-with-resource-spec/test-output-1"}, + }, { + Name: "test-output-2", + ResourceSpec: &r3.Spec, + Paths: []string{"/pvc/test-multiple-outputs-with-resource-spec/test-output-2"}, + }}, + pipelineTaskName: "test-multiple-outputs-with-resource-spec", }} for _, tc := range tcs { t.Run(tc.name, func(t *testing.T) { @@ -84,7 +121,18 @@ func TestGetOutputSteps(t *testing.T) { func TestGetInputSteps(t *testing.T) { r1 := &v1alpha1.PipelineResource{ ObjectMeta: metav1.ObjectMeta{ - Name: "resource1", + Name: "resource1", + SelfLink: "/apis/tekton.dev/pipelineresources/resource1", + }, + } + r2 := &v1alpha1.PipelineResource{ + Spec: v1alpha1.PipelineResourceSpec{ + Type: v1alpha1.PipelineResourceTypeGit, + Params: []v1alpha1.ResourceParam{{ + Name: "url", + Value: "https://github.com/tektoncd/pipeline.git", + }}, + SecretParams: nil, }, } tcs := []struct { @@ -135,6 +183,48 @@ func TestGetInputSteps(t *testing.T) { Name: "test-input", Paths: []string{"/pvc/prev-task-1/test-input", "/pvc/prev-task-2/test-input"}, }}, + }, { + name: "task-with-a-constraint-with-resource-spec", + inputs: map[string]*v1alpha1.PipelineResource{"test-input": r2}, + pipelineTask: &v1alpha1.PipelineTask{ + Resources: &v1alpha1.PipelineTaskResources{ + Inputs: []v1alpha1.PipelineTaskInputResource{{ + Name: "test-input", + From: []string{"prev-task-1"}, + }}, + }, + }, + expectedtaskInputResources: []v1alpha1.TaskResourceBinding{{ + ResourceSpec: &r2.Spec, + Name: "test-input", + Paths: []string{"/pvc/prev-task-1/test-input"}, + }}, + }, { + name: "task-with-no-input-constraint-but-with-resource-spec", + inputs: map[string]*v1alpha1.PipelineResource{"test-input": r2}, + expectedtaskInputResources: []v1alpha1.TaskResourceBinding{{ + ResourceSpec: &r2.Spec, + Name: "test-input", + }}, + pipelineTask: &v1alpha1.PipelineTask{ + Name: "sample-test-task", + }, + }, { + name: "task-with-multiple-constraints-with-resource-spec", + inputs: map[string]*v1alpha1.PipelineResource{"test-input": r2}, + pipelineTask: &v1alpha1.PipelineTask{ + Resources: &v1alpha1.PipelineTaskResources{ + Inputs: []v1alpha1.PipelineTaskInputResource{{ + Name: "test-input", + From: []string{"prev-task-1", "prev-task-2"}, + }}, + }, + }, + expectedtaskInputResources: []v1alpha1.TaskResourceBinding{{ + ResourceSpec: &r2.Spec, + Name: "test-input", + Paths: []string{"/pvc/prev-task-1/test-input", "/pvc/prev-task-2/test-input"}, + }}, }, } for _, tc := range tcs { @@ -152,15 +242,28 @@ func TestGetInputSteps(t *testing.T) { func TestWrapSteps(t *testing.T) { r1 := &v1alpha1.PipelineResource{ ObjectMeta: metav1.ObjectMeta{ - Name: "resource1", + Name: "resource1", + SelfLink: "/apis/tekton.dev/pipelineresources/resource1", + }, + } + r2 := &v1alpha1.PipelineResource{ + Spec: v1alpha1.PipelineResourceSpec{ + Type: v1alpha1.PipelineResourceTypeGit, + Params: []v1alpha1.ResourceParam{{ + Name: "url", + Value: "https://github.com/tektoncd/pipeline.git", + }}, + SecretParams: nil, }, } inputs := map[string]*v1alpha1.PipelineResource{ "test-input": r1, "test-input-2": r1, + "test-input-3": r2, } outputs := map[string]*v1alpha1.PipelineResource{ - "test-output": r1, + "test-output": r1, + "test-output-2": r2, } pt := &v1alpha1.PipelineTask{ @@ -183,11 +286,18 @@ func TestWrapSteps(t *testing.T) { }, { ResourceRef: v1alpha1.PipelineResourceRef{Name: "resource1"}, Name: "test-input-2", + }, { + ResourceSpec: &r2.Spec, + Name: "test-input-3", }} expectedtaskOuputResources := []v1alpha1.TaskResourceBinding{{ ResourceRef: v1alpha1.PipelineResourceRef{Name: "resource1"}, Name: "test-output", Paths: []string{"/pvc/test-task/test-output"}, + }, { + ResourceSpec: &r2.Spec, + Name: "test-output-2", + Paths: []string{"/pvc/test-task/test-output-2"}, }} sort.SliceStable(expectedtaskInputResources, func(i, j int) bool { return expectedtaskInputResources[i].Name < expectedtaskInputResources[j].Name }) diff --git a/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go b/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go index ed75ef0b334..eddfebb9a00 100644 --- a/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go +++ b/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go @@ -24,6 +24,7 @@ import ( "golang.org/x/xerrors" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "knative.dev/pkg/apis" "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1alpha1" @@ -172,8 +173,8 @@ type GetTaskRun func(name string) (*v1alpha1.TaskRun, error) // GetResourcesFromBindings will validate that all PipelineResources declared in Pipeline p are bound in PipelineRun pr // and if so, will return a map from the declared name of the PipelineResource (which is how the PipelineResource will // be referred to in the PipelineRun) to the ResourceRef. -func GetResourcesFromBindings(p *v1alpha1.Pipeline, pr *v1alpha1.PipelineRun) (map[string]v1alpha1.PipelineResourceRef, error) { - resources := map[string]v1alpha1.PipelineResourceRef{} +func GetResourcesFromBindings(p *v1alpha1.Pipeline, pr *v1alpha1.PipelineRun) (map[string]v1alpha1.PipelineResourceBinding, error) { + resources := map[string]v1alpha1.PipelineResourceBinding{} required := make([]string, 0, len(p.Spec.Resources)) for _, resource := range p.Spec.Resources { @@ -189,12 +190,12 @@ func GetResourcesFromBindings(p *v1alpha1.Pipeline, pr *v1alpha1.PipelineRun) (m } for _, resource := range pr.Spec.Resources { - resources[resource.Name] = resource.ResourceRef + resources[resource.Name] = resource } return resources, nil } -func getPipelineRunTaskResources(pt v1alpha1.PipelineTask, providedResources map[string]v1alpha1.PipelineResourceRef) ([]v1alpha1.TaskResourceBinding, []v1alpha1.TaskResourceBinding, error) { +func getPipelineRunTaskResources(pt v1alpha1.PipelineTask, providedResources map[string]v1alpha1.PipelineResourceBinding) ([]v1alpha1.TaskResourceBinding, []v1alpha1.TaskResourceBinding, error) { inputs, outputs := []v1alpha1.TaskResourceBinding{}, []v1alpha1.TaskResourceBinding{} if pt.Resources != nil { for _, taskInput := range pt.Resources.Inputs { @@ -203,8 +204,9 @@ func getPipelineRunTaskResources(pt v1alpha1.PipelineTask, providedResources map return inputs, outputs, xerrors.Errorf("pipelineTask tried to use input resource %s not present in declared resources", taskInput.Resource) } inputs = append(inputs, v1alpha1.TaskResourceBinding{ - Name: taskInput.Name, - ResourceRef: resource, + Name: taskInput.Name, + ResourceRef: resource.ResourceRef, + ResourceSpec: resource.ResourceSpec, }) } for _, taskOutput := range pt.Resources.Outputs { @@ -213,8 +215,9 @@ func getPipelineRunTaskResources(pt v1alpha1.PipelineTask, providedResources map return outputs, outputs, xerrors.Errorf("pipelineTask tried to use output resource %s not present in declared resources", taskOutput.Resource) } outputs = append(outputs, v1alpha1.TaskResourceBinding{ - Name: taskOutput.Name, - ResourceRef: resource, + Name: taskOutput.Name, + ResourceRef: resource.ResourceRef, + ResourceSpec: resource.ResourceSpec, }) } } @@ -262,7 +265,7 @@ func ResolvePipelineRun( getResource resources.GetResource, getCondition GetCondition, tasks []v1alpha1.PipelineTask, - providedResources map[string]v1alpha1.PipelineResourceRef, + providedResources map[string]v1alpha1.PipelineResourceBinding, ) (PipelineRunState, error) { state := []*ResolvedPipelineRunTask{} @@ -297,9 +300,11 @@ func ResolvePipelineRun( spec := t.TaskSpec() rtr, err := resources.ResolveTaskResources(&spec, t.TaskMetadata().Name, pt.TaskRef.Kind, inputs, outputs, getResource) + if err != nil { return nil, &ResourceNotFoundError{Msg: err.Error()} } + rprt.ResolvedTaskResources = rtr taskRun, err := getTaskRun(rprt.TaskRunName) @@ -492,7 +497,7 @@ func ValidateFrom(state PipelineRunState) error { func resolveConditionChecks(pt *v1alpha1.PipelineTask, taskRunStatus map[string]*v1alpha1.PipelineRunTaskRunStatus, taskRunName string, getTaskRun resources.GetTaskRun, getCondition GetCondition, - getResource resources.GetResource, providedResources map[string]v1alpha1.PipelineResourceRef) ([]*ResolvedConditionCheck, error) { + getResource resources.GetResource, providedResources map[string]v1alpha1.PipelineResourceBinding) ([]*ResolvedConditionCheck, error) { rccs := []*ResolvedConditionCheck{} for _, ptc := range pt.Conditions { cName := ptc.ConditionRef @@ -533,24 +538,31 @@ func resolveConditionChecks(pt *v1alpha1.PipelineTask, func resolveConditionResources(prc []v1alpha1.PipelineConditionResource, getResource resources.GetResource, - providedResources map[string]v1alpha1.PipelineResourceRef, + providedResources map[string]v1alpha1.PipelineResourceBinding, ) (map[string]*v1alpha1.PipelineResource, error) { rr := make(map[string]*v1alpha1.PipelineResource) for _, r := range prc { // First get a ref to actual resource name from its bound name - resourceRef, ok := providedResources[r.Resource] + resourceBinding, ok := providedResources[r.Resource] if !ok { return nil, xerrors.Errorf("resource %s not present in declared resources", r.Resource) } - // Next, fetch the actual resource definition - gotResource, err := getResource(resourceRef.Name) - if err != nil { - return nil, xerrors.Errorf("could not retrieve resource %s: %w", r.Name, err) + if resourceBinding.ResourceRef.Name != "" { + gotResource, err := getResource(resourceBinding.ResourceRef.Name) + if err != nil { + return nil, xerrors.Errorf("could not retrieve resource %s: %w", r.Name, err) + } + // Finally add it to the resolved resources map + rr[r.Name] = gotResource + } else if resourceBinding.ResourceSpec != nil && resourceBinding.ResourceSpec.Type != "" { + rr[r.Name] = &v1alpha1.PipelineResource{ + ObjectMeta: metav1.ObjectMeta{ + Name: resourceBinding.Name, + }, + Spec: *resourceBinding.ResourceSpec, + } } - - // Finally add it to the resolved resources map - rr[r.Name] = gotResource } return rr, nil } diff --git a/pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go b/pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go index 06a8d6084e8..0bdfb11e24c 100644 --- a/pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go +++ b/pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go @@ -1041,9 +1041,10 @@ func TestGetResourcesFromBindings(t *testing.T) { if err != nil { t.Fatalf("didn't expect error getting resources from bindings but got: %v", err) } - expectedResources := map[string]v1alpha1.PipelineResourceRef{ + expectedResources := map[string]v1alpha1.PipelineResourceBinding{ "git-resource": { - Name: "sweet-resource", + Name: "git-resource", + ResourceRef: v1alpha1.PipelineResourceRef{Name: "sweet-resource"}, }, } if d := cmp.Diff(expectedResources, m); d != "" { @@ -1094,9 +1095,12 @@ func TestResolvePipelineRun(t *testing.T) { tb.PipelineTaskOutputResource("output1", "git-resource"), ), )) - providedResources := map[string]v1alpha1.PipelineResourceRef{ + providedResources := map[string]v1alpha1.PipelineResourceBinding{ "git-resource": { Name: "someresource", + ResourceRef: v1alpha1.PipelineResourceRef{ + Name: "someresource", + }, }, } @@ -1179,7 +1183,7 @@ func TestResolvePipelineRun_PipelineTaskHasNoResources(t *testing.T) { Name: "mytask3", TaskRef: v1alpha1.TaskRef{Name: "task"}, }} - providedResources := map[string]v1alpha1.PipelineResourceRef{} + providedResources := map[string]v1alpha1.PipelineResourceBinding{} getTask := func(name string) (v1alpha1.TaskInterface, error) { return task, nil } getTaskRun := func(name string) (*v1alpha1.TaskRun, error) { return &trs[0], nil } @@ -1219,7 +1223,7 @@ func TestResolvePipelineRun_TaskDoesntExist(t *testing.T) { Name: "mytask1", TaskRef: v1alpha1.TaskRef{Name: "task"}, }} - providedResources := map[string]v1alpha1.PipelineResourceRef{} + providedResources := map[string]v1alpha1.PipelineResourceBinding{} // Return an error when the Task is retrieved, as if it didn't exist getTask := func(name string) (v1alpha1.TaskInterface, error) { @@ -1273,7 +1277,7 @@ func TestResolvePipelineRun_ResourceBindingsDontExist(t *testing.T) { ), )), }} - providedResources := map[string]v1alpha1.PipelineResourceRef{} + providedResources := map[string]v1alpha1.PipelineResourceBinding{} getTask := func(name string) (v1alpha1.TaskInterface, error) { return task, nil } getTaskRun := func(name string) (*v1alpha1.TaskRun, error) { return &trs[0], nil } @@ -1319,7 +1323,7 @@ func TestResolvePipelineRun_ResourcesDontExist(t *testing.T) { ), )), }} - providedResources := map[string]v1alpha1.PipelineResourceRef{ + providedResources := map[string]v1alpha1.PipelineResourceBinding{ "git-resource": { Name: "doesnt-exist", }, @@ -1539,9 +1543,12 @@ func TestResolvePipelineRun_withExistingTaskRuns(t *testing.T) { tb.PipelineTaskInputResource("input1", "git-resource"), ), )) - providedResources := map[string]v1alpha1.PipelineResourceRef{ + providedResources := map[string]v1alpha1.PipelineResourceBinding{ "git-resource": { Name: "someresource", + ResourceRef: v1alpha1.PipelineResourceRef{ + Name: "someresource", + }, }, } @@ -1617,7 +1624,7 @@ func TestResolveConditionChecks(t *testing.T) { TaskRef: v1alpha1.TaskRef{Name: "task"}, Conditions: []v1alpha1.PipelineTaskCondition{ptc}, }} - providedResources := map[string]v1alpha1.PipelineResourceRef{} + providedResources := map[string]v1alpha1.PipelineResourceBinding{} getTask := func(name string) (v1alpha1.TaskInterface, error) { return task, nil } getClusterTask := func(name string) (v1alpha1.TaskInterface, error) { return nil, xerrors.New("should not get called") } @@ -1697,7 +1704,7 @@ func TestResolveConditionChecks_ConditionDoesNotExist(t *testing.T) { ConditionRef: "does-not-exist", }}, }} - providedResources := map[string]v1alpha1.PipelineResourceRef{} + providedResources := map[string]v1alpha1.PipelineResourceBinding{} getTask := func(name string) (v1alpha1.TaskInterface, error) { return task, nil } getTaskRun := func(name string) (*v1alpha1.TaskRun, error) { @@ -1755,7 +1762,7 @@ func TestResolveConditionCheck_UseExistingConditionCheckName(t *testing.T) { TaskRef: v1alpha1.TaskRef{Name: "task"}, Conditions: []v1alpha1.PipelineTaskCondition{ptc}, }} - providedResources := map[string]v1alpha1.PipelineResourceRef{} + providedResources := map[string]v1alpha1.PipelineResourceBinding{} getTask := func(name string) (v1alpha1.TaskInterface, error) { return task, nil } getTaskRun := func(name string) (*v1alpha1.TaskRun, error) { @@ -1852,30 +1859,20 @@ func TestResolvedConditionCheck_WithResources(t *testing.T) { tcs := []struct { name string - providedResources map[string]v1alpha1.PipelineResourceRef + providedResources map[string]v1alpha1.PipelineResourceBinding wantErr bool expected map[string]*v1alpha1.PipelineResource }{{ name: "resource exists", - providedResources: map[string]v1alpha1.PipelineResourceRef{ + providedResources: map[string]v1alpha1.PipelineResourceBinding{ "blah": { Name: "some-repo", }, }, - expected: map[string]*v1alpha1.PipelineResource{ - "workspace": gitResource, - }, - }, { - name: "resource does not exist", - providedResources: map[string]v1alpha1.PipelineResourceRef{ - "blah": { - Name: "some-other-repo", - }, - }, - wantErr: true, + expected: map[string]*v1alpha1.PipelineResource{}, }, { name: "undeclared resource", - providedResources: map[string]v1alpha1.PipelineResourceRef{ + providedResources: map[string]v1alpha1.PipelineResourceBinding{ "foo": { Name: "some-repo", }}, diff --git a/pkg/reconciler/taskrun/taskrun_test.go b/pkg/reconciler/taskrun/taskrun_test.go index 23e30297a8e..b5a7a1a77f8 100644 --- a/pkg/reconciler/taskrun/taskrun_test.go +++ b/pkg/reconciler/taskrun/taskrun_test.go @@ -308,6 +308,7 @@ func TestReconcile(t *testing.T) { ), tb.TaskRunOutputs( tb.TaskRunOutputsResource(gitResource.Name, + tb.TaskResourceBindingRef(gitResource.Name), tb.TaskResourceBindingPaths("output-folder"), ), ), @@ -1658,8 +1659,8 @@ func TestReconcileCloudEvents(t *testing.T) { tb.TaskRunSpec( tb.TaskRunTaskRef(twoOutputsTask.Name), tb.TaskRunOutputs( - tb.TaskRunOutputsResource(cloudEventResource.Name), - tb.TaskRunOutputsResource(anotherCloudEventResource.Name), + tb.TaskRunOutputsResource(cloudEventResource.Name, tb.TaskResourceBindingRef(cloudEventResource.Name)), + tb.TaskRunOutputsResource(anotherCloudEventResource.Name, tb.TaskResourceBindingRef(anotherCloudEventResource.Name)), ), ), ) @@ -1667,8 +1668,8 @@ func TestReconcileCloudEvents(t *testing.T) { tb.TaskRunSpec( tb.TaskRunTaskRef(twoOutputsTask.Name), tb.TaskRunOutputs( - tb.TaskRunOutputsResource(cloudEventResource.Name), - tb.TaskRunOutputsResource(anotherCloudEventResource.Name), + tb.TaskRunOutputsResource(cloudEventResource.Name, tb.TaskResourceBindingRef(cloudEventResource.Name)), + tb.TaskRunOutputsResource(anotherCloudEventResource.Name, tb.TaskResourceBindingRef(anotherCloudEventResource.Name)), ), ), tb.TaskRunStatus( @@ -1681,8 +1682,8 @@ func TestReconcileCloudEvents(t *testing.T) { tb.TaskRunSpec( tb.TaskRunTaskRef(twoOutputsTask.Name), tb.TaskRunOutputs( - tb.TaskRunOutputsResource(cloudEventResource.Name), - tb.TaskRunOutputsResource(anotherCloudEventResource.Name), + tb.TaskRunOutputsResource(cloudEventResource.Name, tb.TaskResourceBindingRef(cloudEventResource.Name)), + tb.TaskRunOutputsResource(anotherCloudEventResource.Name, tb.TaskResourceBindingRef(anotherCloudEventResource.Name)), ), ), tb.TaskRunStatus( @@ -1699,8 +1700,8 @@ func TestReconcileCloudEvents(t *testing.T) { tb.TaskRunSpec( tb.TaskRunTaskRef(twoOutputsTask.Name), tb.TaskRunOutputs( - tb.TaskRunOutputsResource(cloudEventResource.Name), - tb.TaskRunOutputsResource(anotherCloudEventResource.Name), + tb.TaskRunOutputsResource(cloudEventResource.Name, tb.TaskResourceBindingRef(cloudEventResource.Name)), + tb.TaskRunOutputsResource(anotherCloudEventResource.Name, tb.TaskResourceBindingRef(anotherCloudEventResource.Name)), ), ), tb.TaskRunStatus( @@ -1717,8 +1718,8 @@ func TestReconcileCloudEvents(t *testing.T) { tb.TaskRunSpec( tb.TaskRunTaskRef(twoOutputsTask.Name), tb.TaskRunOutputs( - tb.TaskRunOutputsResource(cloudEventResource.Name), - tb.TaskRunOutputsResource(anotherCloudEventResource.Name), + tb.TaskRunOutputsResource(cloudEventResource.Name, tb.TaskResourceBindingRef(cloudEventResource.Name)), + tb.TaskRunOutputsResource(anotherCloudEventResource.Name, tb.TaskResourceBindingRef(anotherCloudEventResource.Name)), ), ), tb.TaskRunStatus( diff --git a/test/builder/pipeline.go b/test/builder/pipeline.go index 82dc4c7068b..d8e43af6bcd 100644 --- a/test/builder/pipeline.go +++ b/test/builder/pipeline.go @@ -319,9 +319,6 @@ func PipelineRunResourceBinding(name string, ops ...PipelineResourceBindingOp) P return func(prs *v1alpha1.PipelineRunSpec) { r := &v1alpha1.PipelineResourceBinding{ Name: name, - ResourceRef: v1alpha1.PipelineResourceRef{ - Name: name, - }, } for _, op := range ops { op(r) @@ -337,6 +334,13 @@ func PipelineResourceBindingRef(name string) PipelineResourceBindingOp { } } +// PipelineResourceBindingResourceSpec set the PipelineResourceResourceSpec to the PipelineResourceBinding. +func PipelineResourceBindingResourceSpec(spec *v1alpha1.PipelineResourceSpec) PipelineResourceBindingOp { + return func(b *v1alpha1.PipelineResourceBinding) { + b.ResourceSpec = spec + } +} + // PipelineRunServiceAccount sets the service account to the PipelineRunSpec. func PipelineRunServiceAccount(sa string) PipelineRunSpecOp { return func(prs *v1alpha1.PipelineRunSpec) { diff --git a/test/builder/pipeline_test.go b/test/builder/pipeline_test.go index 62838c05f6f..ea18ea73204 100644 --- a/test/builder/pipeline_test.go +++ b/test/builder/pipeline_test.go @@ -186,6 +186,79 @@ func TestPipelineRun(t *testing.T) { } } +func TestPipelineRunWithResourceSpec(t *testing.T) { + startTime := time.Now() + completedTime := startTime.Add(5 * time.Minute) + + pipelineRun := tb.PipelineRun("pear", "foo", tb.PipelineRunSpec( + "tomatoes", tb.PipelineRunServiceAccount("sa"), + tb.PipelineRunParam("first-param-string", "first-value"), + tb.PipelineRunParam("second-param-array", "some", "array"), + tb.PipelineRunTimeout(1*time.Hour), + tb.PipelineRunResourceBinding("some-resource", + tb.PipelineResourceBindingResourceSpec(&v1alpha1.PipelineResourceSpec{ + Type: v1alpha1.PipelineResourceTypeGit, + Params: []v1alpha1.ResourceParam{{ + Name: "url", + Value: "git", + }}})), + tb.PipelineRunServiceAccountTask("foo", "sa-2"), + ), tb.PipelineRunStatus(tb.PipelineRunStatusCondition( + apis.Condition{Type: apis.ConditionSucceeded}), + tb.PipelineRunStartTime(startTime), + tb.PipelineRunCompletionTime(completedTime), + tb.PipelineRunTaskRunsStatus("trname", &v1alpha1.PipelineRunTaskRunStatus{ + PipelineTaskName: "task-1", + }), + ), tb.PipelineRunLabel("label-key", "label-value")) + expectedPipelineRun := &v1alpha1.PipelineRun{ + ObjectMeta: metav1.ObjectMeta{ + Name: "pear", + Namespace: "foo", + Labels: map[string]string{ + "label-key": "label-value", + }, + }, + Spec: v1alpha1.PipelineRunSpec{ + PipelineRef: v1alpha1.PipelineRef{Name: "tomatoes"}, + ServiceAccount: "sa", + ServiceAccounts: []v1alpha1.PipelineRunSpecServiceAccount{{TaskName: "foo", ServiceAccount: "sa-2"}}, + Params: []v1alpha1.Param{{ + Name: "first-param-string", + Value: *tb.ArrayOrString("first-value"), + }, { + Name: "second-param-array", + Value: *tb.ArrayOrString("some", "array"), + }}, + Timeout: &metav1.Duration{Duration: 1 * time.Hour}, + Resources: []v1alpha1.PipelineResourceBinding{{ + Name: "some-resource", + ResourceSpec: &v1alpha1.PipelineResourceSpec{ + Type: v1alpha1.PipelineResourceType("git"), + Params: []v1alpha1.ResourceParam{{ + Name: "url", + Value: "git", + }}, + SecretParams: nil, + }, + }}, + }, + Status: v1alpha1.PipelineRunStatus{ + Status: duckv1beta1.Status{ + Conditions: []apis.Condition{{Type: apis.ConditionSucceeded}}, + }, + StartTime: &metav1.Time{Time: startTime}, + CompletionTime: &metav1.Time{Time: completedTime}, + TaskRuns: map[string]*v1alpha1.PipelineRunTaskRunStatus{ + "trname": {PipelineTaskName: "task-1"}, + }, + }, + } + if d := cmp.Diff(expectedPipelineRun, pipelineRun); d != "" { + t.Fatalf("PipelineRun diff -want, +got: %v", d) + } +} + func TestPipelineResource(t *testing.T) { pipelineResource := tb.PipelineResource("git-resource", "foo", tb.PipelineResourceSpec( v1alpha1.PipelineResourceTypeGit, tb.PipelineResourceSpecParam("URL", "https://foo.git"), diff --git a/test/builder/task.go b/test/builder/task.go index e7227ca5f7d..566aca5dcc5 100644 --- a/test/builder/task.go +++ b/test/builder/task.go @@ -597,9 +597,6 @@ func TaskRunOutputsResource(name string, ops ...TaskResourceBindingOp) TaskRunOu return func(i *v1alpha1.TaskRunOutputs) { binding := &v1alpha1.TaskResourceBinding{ Name: name, - ResourceRef: v1alpha1.PipelineResourceRef{ - Name: name, - }, } for _, op := range ops { op(binding) diff --git a/test/builder/task_test.go b/test/builder/task_test.go index e574d73d038..f032159fe0b 100644 --- a/test/builder/task_test.go +++ b/test/builder/task_test.go @@ -161,6 +161,7 @@ func TestTaskRunWithTaskRef(t *testing.T) { ), tb.TaskRunOutputs( tb.TaskRunOutputsResource(gitResource.Name, + tb.TaskResourceBindingRef(gitResource.Name), tb.TaskResourceBindingPaths("output-folder"), ), ),