From 6df069dde34237c2d797d6270b60a2e49b352a11 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 | 58 +++++++++++++++ .../v1alpha1/pipelinerun_validation_test.go | 10 +-- pkg/apis/pipeline/v1alpha1/resource_types.go | 4 + .../resources/input_output_steps.go | 33 +++++++-- .../resources/pipelinerunresolution.go | 28 +++---- .../resources/pipelinerunresolution_test.go | 37 ++++++---- test/builder/pipeline.go | 10 ++- test/builder/pipeline_test.go | 73 +++++++++++++++++++ 9 files changed, 238 insertions(+), 46 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..df6b2cd14c1 --- /dev/null +++ b/examples/pipelineruns/pipelinerun-with-resourcespec.yaml @@ -0,0 +1,58 @@ +apiVersion: tekton.dev/v1alpha1 +kind: Task +metadata: + name: task-to-list-files +spec: + inputs: + 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: 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 +--- + +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/reconciler/pipelinerun/resources/input_output_steps.go b/pkg/reconciler/pipelinerun/resources/input_output_steps.go index ac4747abec8..c5f6ee39b87 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.Name != "" { + taskOutputResource.ResourceRef = v1alpha1.PipelineResourceRef{ Name: outputResource.Name, APIVersion: outputResource.APIVersion, - }, - Paths: []string{filepath.Join(storageBasePath, taskName, name)}, - }) + } + } else { + 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.Name != "" { + taskInputResource.ResourceRef = v1alpha1.PipelineResourceRef{ Name: inputResource.Name, APIVersion: inputResource.APIVersion, - }, + } + } else { + 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/pipelinerunresolution.go b/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go index ed75ef0b334..0dcac01eb45 100644 --- a/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go +++ b/pkg/reconciler/pipelinerun/resources/pipelinerunresolution.go @@ -172,8 +172,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 +189,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 { @@ -204,7 +204,8 @@ func getPipelineRunTaskResources(pt v1alpha1.PipelineTask, providedResources map } inputs = append(inputs, v1alpha1.TaskResourceBinding{ Name: taskInput.Name, - ResourceRef: resource, + ResourceRef: resource.ResourceRef, + ResourceSpec: resource.ResourceSpec, }) } for _, taskOutput := range pt.Resources.Outputs { @@ -214,7 +215,8 @@ func getPipelineRunTaskResources(pt v1alpha1.PipelineTask, providedResources map } outputs = append(outputs, v1alpha1.TaskResourceBinding{ Name: taskOutput.Name, - ResourceRef: resource, + ResourceRef: resource.ResourceRef, + ResourceSpec: resource.ResourceSpec, }) } } @@ -262,7 +264,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 +299,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 +496,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,22 +537,20 @@ 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) + gotResource, err := getResource(resourceBinding.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 } diff --git a/pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go b/pkg/reconciler/pipelinerun/resources/pipelinerunresolution_test.go index 06a8d6084e8..79325400aa3 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,12 +1859,12 @@ 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", }, @@ -1867,7 +1874,7 @@ func TestResolvedConditionCheck_WithResources(t *testing.T) { }, }, { name: "resource does not exist", - providedResources: map[string]v1alpha1.PipelineResourceRef{ + providedResources: map[string]v1alpha1.PipelineResourceBinding{ "blah": { Name: "some-other-repo", }, @@ -1875,7 +1882,7 @@ func TestResolvedConditionCheck_WithResources(t *testing.T) { wantErr: true, }, { name: "undeclared resource", - providedResources: map[string]v1alpha1.PipelineResourceRef{ + providedResources: map[string]v1alpha1.PipelineResourceBinding{ "foo": { Name: "some-repo", }}, diff --git a/test/builder/pipeline.go b/test/builder/pipeline.go index 1209ca70723..8d1f148cff9 100644 --- a/test/builder/pipeline.go +++ b/test/builder/pipeline.go @@ -306,9 +306,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) @@ -324,6 +321,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 434487ef107..7acf18e90a2 100644 --- a/test/builder/pipeline_test.go +++ b/test/builder/pipeline_test.go @@ -181,6 +181,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"),