diff --git a/docs/pipeline-resources.md b/docs/pipeline-resources.md index 1ff07b93218..1aabf25c33f 100644 --- a/docs/pipeline-resources.md +++ b/docs/pipeline-resources.md @@ -76,3 +76,21 @@ spec: - name: builtImage type: image ``` + +#### Templating + +Git Resources (like all Resources) support template expansion into BuildSpecs. +Git Resources support the following keys for replacement: + +* name +* url +* type +* revision + +These can be referenced in a TaskRun spec like: + +```shell +${inputs.resources.NAME.KEY} +``` + +where NAME is the Resource Name and KEY is the key from the above list. diff --git a/pkg/apis/pipeline/v1alpha1/git_resource.go b/pkg/apis/pipeline/v1alpha1/git_resource.go index de5364626f5..009e2bff395 100644 --- a/pkg/apis/pipeline/v1alpha1/git_resource.go +++ b/pkg/apis/pipeline/v1alpha1/git_resource.go @@ -81,3 +81,13 @@ func (s *GitResource) GetURL() string { // GetParams returns the resoruce params func (s GitResource) GetParams() []Param { return []Param{} } + +// Replacements is used for template replacement on a GitResource inside of a Taskrun. +func (s *GitResource) Replacements() map[string]string { + return map[string]string{ + "name": s.Name, + "type": string(s.Type), + "url": s.URL, + "revision": s.Revision, + } +} diff --git a/pkg/apis/pipeline/v1alpha1/resource_types.go b/pkg/apis/pipeline/v1alpha1/resource_types.go index dbf48bcec60..8a008bf50e1 100644 --- a/pkg/apis/pipeline/v1alpha1/resource_types.go +++ b/pkg/apis/pipeline/v1alpha1/resource_types.go @@ -17,6 +17,8 @@ limitations under the License. package v1alpha1 import ( + "fmt" + "github.com/knative/pkg/apis" "github.com/knative/pkg/webhook" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -46,6 +48,7 @@ type PipelineResourceInterface interface { GetType() PipelineResourceType GetParams() []Param GetVersion() string + Replacements() map[string]string } // PipelineResourceSpec defines an individual resources used in the pipeline. @@ -112,3 +115,12 @@ type PipelineResourceList struct { metav1.ListMeta `json:"metadata,omitempty"` Items []PipelineResource `json:"items"` } + +// ResourceFromType returns a +func ResourceFromType(r *PipelineResource) (PipelineResourceInterface, error) { + switch r.Spec.Type { + case PipelineResourceTypeGit: + return NewGitResource(r) + } + return nil, fmt.Errorf("%s is an invalid PipelineResource", r.Spec.Type) +} diff --git a/pkg/reconciler/v1alpha1/taskrun/taskrun.go b/pkg/reconciler/v1alpha1/taskrun/taskrun.go index 928eb69e222..9ecdf9d005d 100644 --- a/pkg/reconciler/v1alpha1/taskrun/taskrun.go +++ b/pkg/reconciler/v1alpha1/taskrun/taskrun.go @@ -233,7 +233,13 @@ func (c *Reconciler) createBuild(tr *v1alpha1.TaskRun) (*buildv1alpha1.Build, er } // Apply parameters from the taskrun. - build = applyParameters(b, t, tr) + build = applyParameters(build, t, tr) + + // Apply resources from the taskrun. + build, err = applyResources(build, t, tr, c.resourceLister) + if err != nil { + return nil, err + } return c.BuildClientSet.BuildV1alpha1().Builds(tr.Namespace).Create(build) } @@ -257,3 +263,23 @@ func applyParameters(b *buildv1alpha1.Build, t *v1alpha1.Task, tr *v1alpha1.Task return builder.ApplyReplacements(b, replacements) } + +func applyResources(b *buildv1alpha1.Build, t *v1alpha1.Task, tr *v1alpha1.TaskRun, lister listers.PipelineResourceLister) (*buildv1alpha1.Build, error) { + replacements := map[string]string{} + + for _, ir := range tr.Spec.Inputs.Resources { + pr, err := lister.PipelineResources(t.Namespace).Get(ir.ResourceRef.Name) + if err != nil { + return nil, err + } + + resource, err := v1alpha1.ResourceFromType(pr) + if err != nil { + return nil, err + } + for k, v := range resource.Replacements() { + replacements[fmt.Sprintf("inputs.resources.%s.%s", ir.ResourceRef.Name, k)] = v + } + } + return builder.ApplyReplacements(b, replacements), nil +} diff --git a/pkg/reconciler/v1alpha1/taskrun/taskrun_test.go b/pkg/reconciler/v1alpha1/taskrun/taskrun_test.go index 3a1c1ec8a1f..b5fa7988ee9 100644 --- a/pkg/reconciler/v1alpha1/taskrun/taskrun_test.go +++ b/pkg/reconciler/v1alpha1/taskrun/taskrun_test.go @@ -66,6 +66,27 @@ var templatedTask = &v1alpha1.Task{ Image: "myimage", Args: []string{"--my-arg=${inputs.params.myarg}"}, }, + { + Name: "myothercontainer", + Image: "myotherimage", + Args: []string{"--my-other-arg=${inputs.resources.git-resource.url}"}, + }, + }, + }, + }, +} + +var gitResource = &v1alpha1.PipelineResource{ + ObjectMeta: metav1.ObjectMeta{ + Name: "git-resource", + Namespace: "foo", + }, + Spec: v1alpha1.PipelineResourceSpec{ + Type: "git", + Params: []v1alpha1.Param{ + { + Name: "URL", + Value: "https://foo.git", }, }, }, @@ -102,14 +123,24 @@ func TestReconcileBuildsCreated(t *testing.T) { Value: "foo", }, }, + Resources: []v1alpha1.PipelineResourceVersion{ + { + ResourceRef: v1alpha1.PipelineResourceRef{ + Name: "git-resource", + APIVersion: "a1", + }, + Version: "myversion", + }, + }, }, }, }, } d := testData{ - taskruns: taskruns, - tasks: []*v1alpha1.Task{simpleTask, templatedTask}, + taskruns: taskruns, + tasks: []*v1alpha1.Task{simpleTask, templatedTask}, + resources: []*v1alpha1.PipelineResource{gitResource}, } testcases := []struct { name string @@ -138,6 +169,11 @@ func TestReconcileBuildsCreated(t *testing.T) { Image: "myimage", Args: []string{"--my-arg=foo"}, }, + { + Name: "myothercontainer", + Image: "myotherimage", + Args: []string{"--my-other-arg=https://foo.git"}, + }, }, }, }, @@ -227,6 +263,11 @@ func getController(d testData) (*controller.Impl, *observer.ObservedLogs, *fakeb for _, t := range d.tasks { taskInformer.Informer().GetIndexer().Add(t) } + + for _, r := range d.resources { + resourceInformer.Informer().GetIndexer().Add(r) + } + // Create a log observer to record all error logs. observer, logs := observer.New(zap.ErrorLevel) return NewController( @@ -252,6 +293,7 @@ func getLogMessages(logs *observer.ObservedLogs) []string { } type testData struct { - taskruns []*v1alpha1.TaskRun - tasks []*v1alpha1.Task + taskruns []*v1alpha1.TaskRun + tasks []*v1alpha1.Task + resources []*v1alpha1.PipelineResource }