Repository: jenkins-x/lighthouse
Pull request #1127 (2020-10-26 09:12:39)

fix: improve tekton catalog integration
this PR makes it easier to reuse tekton catalog Tasks/Pipelines/PipelineRuns when using the in-repo mode so that...

* we can use either of PipelineRun/Pipeline/Task/TaskRun files for a `presumit` or `postsubmit` entry in the `source` property in the triggers.yaml (so that its easy to consume existing `Pipeline/Task/TaskRun` files without the user having to convert them to a `PipelineRun` first. This avoids the boilerplate required wrapping Tasks => Pipelines => PipelineRuns

* if reusing a combination of PipelineRun / Pipeline / TaskRun / Task files from the tekton catalog, allow Pipeline/Task refs to be resolved to inline PipelineSpec / TaskSpec structs to that the resulting PipelineRun for the lighthouse tekton engine is equivalent and the files read from git directly

both of these changes mean developers can reuse tekton catalog tasks/pipelines mostly as-is (provided each resource is a separate file in git using the file name `$name.yaml` in the same directory as the `triggers.yaml` file

jenkins-x-bot: [APPROVALNOTIFIER] This PR is **NOT APPROVED**

This pull-request has been approved by:
To complete the [pull request process](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process), please assign **jstrachan**
You can assign the PR to them by writing `/assign @jstrachan` in a comment when ready.

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=jenkins-x%2Flighthouse).

<details open>
Needs approval from an approver in each of these files:

- **[OWNERS](https://github.com/jenkins-x/lighthouse/blob/master/OWNERS)**

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":["jstrachan"]} -->
jenkins-x-bot: @jstrachan: The following test **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
jenkins | 36ceeeff4e8109daf1a75d920199db4dc3ebc6e7 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-1127/4) | `/test jenkins`

[View all Builds for this Pull Request](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-1127) 

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [jenkins-x/lighthouse](https://github.com/jenkins-x/lighthouse/issues/new?title=Command%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
jstrachan: /retest
jenkins-x-bot: @jstrachan: The following test **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
jenkins | 36ceeeff4e8109daf1a75d920199db4dc3ebc6e7 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-1127/6) | `/test jenkins`

[View all Builds for this Pull Request](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-1127) 

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [jenkins-x/lighthouse](https://github.com/jenkins-x/lighthouse/issues/new?title=Command%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
jstrachan: /retest
jenkins-x-bot: @jstrachan: The following test **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
jenkins | 36ceeeff4e8109daf1a75d920199db4dc3ebc6e7 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-1127/7) | `/test jenkins`

[View all Builds for this Pull Request](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-1127) 

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [jenkins-x/lighthouse](https://github.com/jenkins-x/lighthouse/issues/new?title=Command%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
jstrachan: /retest
abayer: /lgtm
jenkins-x-bot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *[abayer](https://github.com/jenkins-x/lighthouse/pull/1127#issuecomment-716528883 "LGTM")*

The full list of commands accepted by this bot can be found [here](https://go.k8s.io/bot-commands?repo=jenkins-x%2Flighthouse).

The pull request process is described [here](https://git.k8s.io/community/contributors/guide/owners.md#the-code-review-process)

<details >
Needs approval from an approver in each of these files:

- ~~[OWNERS](https://github.com#issuecomment-716528883/jenkins-x/lighthouse/blob/master/OWNERS)~~ [abayer]

Approvers can indicate their approval by writing `/approve` in a comment
Approvers can cancel approval by writing `/approve cancel` in a comment
</details>
<!-- META={"approvers":[]} -->

Patch:
diff --git a/pkg/triggerconfig/inrepo/load_pipelinerun.go b/pkg/triggerconfig/inrepo/load_pipelinerun.go
new file mode 100644
index 00000000..08dab3b6
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/load_pipelinerun.go
@@ -0,0 +1,477 @@
+package inrepo
+
+import (
+	"fmt"
+	"os"
+	"path/filepath"
+	"regexp"
+	"strings"
+	"time"
+
+	"github.com/pkg/errors"
+	tektonv1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"sigs.k8s.io/yaml"
+)
+
+const (
+	// TektonAPIVersion the default tekton API version
+	TektonAPIVersion = "tekton.dev/v1beta1"
+
+	// LoadFileRefPattern the regular expression to match which Pipeline/Task references to load via files
+	LoadFileRefPattern = "lighthouse.jenkins-x.io/loadFileRefs"
+)
+
+// DefaultValues default values applied to a PipelineRun if wrapping a Pipeline/Task/TaskRun as a PipelineRun
+type DefaultValues struct {
+	// ServiceAccountName
+	ServiceAccountName string
+	//  Timeout
+	Timeout *metav1.Duration
+}
+
+// NewDefaultValues creatse a new default values
+func NewDefaultValues() (*DefaultValues, error) {
+	answer := &DefaultValues{
+		ServiceAccountName: os.Getenv("DEFAULT_PIPELINE_RUN_SERVICE_ACCOUNT"),
+	}
+	timeout := os.Getenv("DEFAULT_PIPELINE_RUN_TIMEOUT")
+	if timeout != "" {
+		duration, err := time.ParseDuration(timeout)
+		if err != nil {
+			return answer, errors.Wrapf(err, "failed to parse duration %s", timeout)
+		}
+		answer.Timeout = &metav1.Duration{
+			Duration: duration,
+		}
+	}
+	return answer, nil
+}
+
+// LoadTektonResourceAsPipelineRun loads a PipelineRun, Pipeline, Task or TaskRun and convert it to a PipelineRun
+// if necessary
+func LoadTektonResourceAsPipelineRun(data []byte, dir, message string, getData func(path string) ([]byte, error), defaultValues *DefaultValues) (*tektonv1beta1.PipelineRun, error) {
+	if defaultValues == nil {
+		var err error
+		defaultValues, err = NewDefaultValues()
+		if err != nil {
+			return nil, errors.Wrapf(err, "failed to parse default values")
+		}
+	}
+	kindPrefix := "kind:"
+	kind := "PipelineRun"
+	lines := strings.Split(string(data), "\n")
+	for _, line := range lines {
+		if !strings.HasPrefix(line, kindPrefix) {
+			continue
+		}
+		k := strings.TrimSpace(line[len(kindPrefix):])
+		if k != "" {
+			kind = k
+			break
+		}
+	}
+	switch kind {
+	case "Pipeline":
+		pipeline := &tektonv1beta1.Pipeline{}
+		err := yaml.Unmarshal(data, pipeline)
+		if err != nil {
+			return nil, errors.Wrapf(err, "failed to unmarshal Pipeline YAML %s", message)
+		}
+		prs, err := ConvertPipelineToPipelineRun(pipeline, message, defaultValues)
+		if err == nil {
+			re, err := loadTektonRefsFromFilesPattern(prs)
+			if err != nil {
+				return prs, err
+			}
+			if re != nil {
+				return loadPipelineRunRefs(prs, dir, message, re, getData)
+			}
+		}
+		return prs, err
+
+	case "PipelineRun":
+		prs := &tektonv1beta1.PipelineRun{}
+		err := yaml.Unmarshal(data, prs)
+		if err != nil {
+			return nil, errors.Wrapf(err, "failed to unmarshal PipelineRun YAML %s", message)
+		}
+
+		re, err := loadTektonRefsFromFilesPattern(prs)
+		if err != nil {
+			return prs, err
+		}
+		if re != nil {
+			return loadPipelineRunRefs(prs, dir, message, re, getData)
+		}
+		return prs, err
+	case "Task":
+		task := &tektonv1beta1.Task{}
+		err := yaml.Unmarshal(data, task)
+		if err != nil {
+			return nil, errors.Wrapf(err, "failed to unmarshal Task YAML %s", message)
+		}
+		prs, err := ConvertTaskToPipelineRun(task, message, defaultValues)
+		if err == nil {
+			re, err := loadTektonRefsFromFilesPattern(prs)
+			if err != nil {
+				return prs, err
+			}
+			if re != nil {
+				return loadPipelineRunRefs(prs, dir, message, re, getData)
+			}
+		}
+		return prs, err
+
+	case "TaskRun":
+		tr := &tektonv1beta1.TaskRun{}
+		err := yaml.Unmarshal(data, tr)
+		if err != nil {
+			return nil, errors.Wrapf(err, "failed to unmarshal TaskRun YAML %s", message)
+		}
+		prs, err := ConvertTaskRunToPipelineRun(tr, message, defaultValues)
+		if err == nil {
+			re, err := loadTektonRefsFromFilesPattern(prs)
+			if err != nil {
+				return prs, err
+			}
+			if re != nil {
+				return loadPipelineRunRefs(prs, dir, message, re, getData)
+			}
+		}
+		return prs, err
+
+	default:
+		return nil, errors.Errorf("kind %s is not supported for %s", kind, message)
+	}
+}
+
+// loadTektonRefsFromFilesPattern returns a regular expression matching the Pipeline/Task references we should load via the file system
+// as separate local files
+func loadTektonRefsFromFilesPattern(prs *tektonv1beta1.PipelineRun) (*regexp.Regexp, error) {
+	if prs.Annotations == nil {
+		return nil, nil
+	}
+	pattern := prs.Annotations[LoadFileRefPattern]
+	if pattern == "" {
+		return nil, nil
+	}
+	re, err := regexp.Compile(pattern)
+	if err != nil {
+		return nil, errors.Wrapf(err, "failed to parse annotation %s value %s as a regular expression", LoadFileRefPattern, pattern)
+	}
+	return re, nil
+}
+
+func loadPipelineRunRefs(prs *tektonv1beta1.PipelineRun, dir, message string, re *regexp.Regexp, getData func(path string) ([]byte, error)) (*tektonv1beta1.PipelineRun, error) {
+	// if we reference a local
+	if prs.Spec.PipelineSpec == nil && prs.Spec.PipelineRef != nil && prs.Spec.PipelineRef.Name != "" && re.MatchString(prs.Spec.PipelineRef.Name) {
+		pipelinePath := filepath.Join(dir, prs.Spec.PipelineRef.Name)
+		if !strings.HasSuffix(pipelinePath, ".yaml") {
+			pipelinePath += ".yaml"
+		}
+		data, err := getData(pipelinePath)
+		if err == nil && len(data) > 0 {
+			p := &tektonv1beta1.Pipeline{}
+			err = yaml.Unmarshal(data, p)
+			if err != nil {
+				return prs, errors.Wrapf(err, "failed to unmarshal Pipeline YAML file %s %s", pipelinePath, message)
+			}
+			prs.Spec.PipelineSpec = &p.Spec
+			prs.Spec.PipelineRef = nil
+		}
+	}
+
+	if prs.Spec.PipelineSpec != nil {
+		err := loadTaskRefs(prs.Spec.PipelineSpec, dir, message, re, getData)
+		if err != nil {
+			return prs, errors.Wrapf(err, "failed to load Task refs for %s", message)
+		}
+	}
+	return prs, nil
+}
+
+func loadTaskRefs(pipelineSpec *tektonv1beta1.PipelineSpec, dir, message string, re *regexp.Regexp, getData func(path string) ([]byte, error)) error {
+	for i := range pipelineSpec.Tasks {
+		t := &pipelineSpec.Tasks[i]
+		if t.TaskSpec == nil && t.TaskRef != nil && t.TaskRef.Name != "" && re.MatchString(t.TaskRef.Name) {
+			path := filepath.Join(dir, t.TaskRef.Name)
+			if !strings.HasSuffix(path, ".yaml") {
+				path += ".yaml"
+			}
+			data, err := getData(path)
+			if err == nil && len(data) > 0 {
+				t2 := &tektonv1beta1.Task{}
+				err = yaml.Unmarshal(data, t2)
+				if err != nil {
+					return errors.Wrapf(err, "failed to unmarshal Task YAML file %s %s", path, message)
+				}
+				t.TaskSpec = &t2.Spec
+				t.TaskRef = nil
+			}
+		}
+	}
+	return nil
+}
+
+// ConvertPipelineToPipelineRun converts the Pipeline to a PipelineRun
+func ConvertPipelineToPipelineRun(from *tektonv1beta1.Pipeline, message string, defaultValues *DefaultValues) (*tektonv1beta1.PipelineRun, error) {
+	prs := &tektonv1beta1.PipelineRun{
+		TypeMeta: metav1.TypeMeta{
+			Kind:       "PipelineRun",
+			APIVersion: TektonAPIVersion,
+		},
+	}
+	prs.Name = from.Name
+	prs.Annotations = from.Annotations
+	prs.Labels = from.Labels
+
+	prs.Spec.PipelineSpec = &from.Spec
+	defaultValues.Apply(prs)
+	return prs, nil
+}
+
+// ConvertTaskToPipelineRun converts the Task to a PipelineRun
+func ConvertTaskToPipelineRun(from *tektonv1beta1.Task, message string, defaultValues *DefaultValues) (*tektonv1beta1.PipelineRun, error) {
+	prs := &tektonv1beta1.PipelineRun{
+		TypeMeta: metav1.TypeMeta{
+			Kind:       "PipelineRun",
+			APIVersion: TektonAPIVersion,
+		},
+	}
+	prs.Name = from.Name
+	prs.Annotations = from.Annotations
+	prs.Labels = from.Labels
+
+	fs := &from.Spec
+	pipelineSpec := &tektonv1beta1.PipelineSpec{
+		Description: "",
+		Resources:   nil,
+		Tasks: []tektonv1beta1.PipelineTask{
+			{
+				Name:       from.Name,
+				TaskSpec:   fs,
+				Resources:  ToPipelineResources(fs.Resources),
+				Params:     ToParams(fs.Params),
+				Workspaces: ToWorkspacePipelineTaskBindingsFromDeclarations(fs.Workspaces),
+			},
+		},
+		Params:     fs.Params,
+		Workspaces: ToPipelineWorkspaceDeclarations(fs.Workspaces),
+		//Results:    fs.Results,
+		Finally: nil,
+	}
+	prs.Spec.PipelineSpec = pipelineSpec
+	prs.Spec.Params = ToParams(fs.Params)
+	//prs.Spec.Resources = fs.Resources
+	prs.Spec.Workspaces = ToWorkspaceBindings(fs.Workspaces)
+	defaultValues.Apply(prs)
+	return prs, nil
+}
+
+// ConvertTaskRunToPipelineRun converts the TaskRun to a PipelineRun
+func ConvertTaskRunToPipelineRun(from *tektonv1beta1.TaskRun, message string, defaultValues *DefaultValues) (*tektonv1beta1.PipelineRun, error) {
+	prs := &tektonv1beta1.PipelineRun{
+		TypeMeta: metav1.TypeMeta{
+			Kind:       "PipelineRun",
+			APIVersion: TektonAPIVersion,
+		},
+	}
+	prs.Name = from.Name
+	prs.Annotations = from.Annotations
+	prs.Labels = from.Labels
+
+	fs := &from.Spec
+	params := fs.Params
+	var paramSpecs []tektonv1beta1.ParamSpec
+	if len(params) == 0 && fs.TaskSpec != nil {
+		paramSpecs = fs.TaskSpec.Params
+		if len(params) == 0 {
+			params = ToParams(paramSpecs)
+		}
+	}
+	if len(paramSpecs) == 0 {
+		paramSpecs = ToParamSpecs(params)
+	}
+	pipelineSpec := &tektonv1beta1.PipelineSpec{
+		Description: "",
+		Resources:   nil,
+		Tasks: []tektonv1beta1.PipelineTask{
+			{
+				Name:     from.Name,
+				TaskRef:  fs.TaskRef,
+				TaskSpec: fs.TaskSpec,
+				//Resources: fs.Resources,
+				Params:     params,
+				Workspaces: ToWorkspacePipelineTaskBindings(fs.Workspaces),
+			},
+		},
+		Params:     paramSpecs,
+		Workspaces: nil,
+		Results:    nil,
+		Finally:    nil,
+	}
+	prs.Spec.PipelineSpec = pipelineSpec
+	prs.Spec.Params = params
+	prs.Spec.PodTemplate = fs.PodTemplate
+	//prs.Spec.Resources = fs.Resources
+	prs.Spec.ServiceAccountName = fs.ServiceAccountName
+	prs.Spec.Workspaces = fs.Workspaces
+	defaultValues.Apply(prs)
+	return prs, nil
+}
+
+// Apply adds any default values that are empty in the generated PipelineRun
+func (v *DefaultValues) Apply(prs *tektonv1beta1.PipelineRun) {
+	if prs.Spec.ServiceAccountName == "" && v.ServiceAccountName != "" {
+		prs.Spec.ServiceAccountName = v.ServiceAccountName
+	}
+	if prs.Spec.Timeout == nil && v.Timeout != nil {
+		prs.Spec.Timeout = v.Timeout
+	}
+}
+
+// ToParams convers the param specs to params
+func ToParams(params []tektonv1beta1.ParamSpec) []tektonv1beta1.Param {
+	var answer []tektonv1beta1.Param
+	for _, p := range params {
+		answer = append(answer, tektonv1beta1.Param{
+			Name: p.Name,
+			Value: tektonv1beta1.ArrayOrString{
+				Type:      tektonv1beta1.ParamTypeString,
+				StringVal: fmt.Sprintf("$(params.%s)", p.Name),
+			},
+		})
+	}
+	return answer
+}
+
+// ToParamSpecs generates param specs from the params
+func ToParamSpecs(params []tektonv1beta1.Param) []tektonv1beta1.ParamSpec {
+	var answer []tektonv1beta1.ParamSpec
+	for _, p := range params {
+		answer = append(answer, tektonv1beta1.ParamSpec{
+			Name: p.Name,
+			// lets assume strings for now
+			Type:        tektonv1beta1.ParamTypeString,
+			Description: "",
+			Default:     nil,
+		})
+	}
+	return answer
+}
+
+// ToPipelineResources converts the task resources to piepline resources
+func ToPipelineResources(resources *tektonv1beta1.TaskResources) *tektonv1beta1.PipelineTaskResources {
+	if resources == nil {
+		return nil
+	}
+	return &tektonv1beta1.PipelineTaskResources{
+		Inputs:  ToPipelineInputs(resources.Inputs),
+		Outputs: ToPipelineOutputs(resources.Inputs),
+	}
+}
+
+// ToPipelineInputs converts the task resources into pipeline inputs
+func ToPipelineInputs(inputs []tektonv1beta1.TaskResource) []tektonv1beta1.PipelineTaskInputResource {
+	var answer []tektonv1beta1.PipelineTaskInputResource
+	for _, from := range inputs {
+		answer = append(answer, ToPipelineInput(from))
+	}
+	return answer
+}
+
+// ToPipelineOutputs converts the task resources into pipeline outputs
+func ToPipelineOutputs(inputs []tektonv1beta1.TaskResource) []tektonv1beta1.PipelineTaskOutputResource {
+	var answer []tektonv1beta1.PipelineTaskOutputResource
+	for _, from := range inputs {
+		answer = append(answer, ToPipelineOutput(from))
+	}
+	return answer
+}
+
+// ToPipelineInput converts the task resource into pipeline inputs
+func ToPipelineInput(from tektonv1beta1.TaskResource) tektonv1beta1.PipelineTaskInputResource {
+	return tektonv1beta1.PipelineTaskInputResource{
+		Name:     from.Name,
+		Resource: from.ResourceDeclaration.Name,
+		From:     nil,
+	}
+}
+
+// ToPipelineOutput converts the task resource into pipeline outputs
+func ToPipelineOutput(from tektonv1beta1.TaskResource) tektonv1beta1.PipelineTaskOutputResource {
+	return tektonv1beta1.PipelineTaskOutputResource{
+		Name:     from.Name,
+		Resource: from.ResourceDeclaration.Name,
+	}
+}
+
+// ToWorkspaceBindings converts the workspace declarations to workspaces bindings
+func ToWorkspaceBindings(workspaces []tektonv1beta1.WorkspaceDeclaration) []tektonv1beta1.WorkspaceBinding {
+	var answer []tektonv1beta1.WorkspaceBinding
+	for _, from := range workspaces {
+		answer = append(answer, ToWorkspaceBinding(from))
+	}
+	return answer
+}
+
+// ToWorkspaceBinding converts the workspace declaration to a workspaces binding
+func ToWorkspaceBinding(from tektonv1beta1.WorkspaceDeclaration) tektonv1beta1.WorkspaceBinding {
+	return tektonv1beta1.WorkspaceBinding{
+		Name: from.Name,
+	}
+}
+
+// ToWorkspacePipelineTaskBindings converts the workspace bindings to pipeline task bindings
+func ToWorkspacePipelineTaskBindings(workspaces []tektonv1beta1.WorkspaceBinding) []tektonv1beta1.WorkspacePipelineTaskBinding {
+	var answer []tektonv1beta1.WorkspacePipelineTaskBinding
+	for _, from := range workspaces {
+		answer = append(answer, ToWorkspacePipelineTaskBinding(from))
+	}
+	return answer
+}
+
+// ToWorkspacePipelineTaskBinding converts the workspace binding to a pipeline task binding
+func ToWorkspacePipelineTaskBinding(from tektonv1beta1.WorkspaceBinding) tektonv1beta1.WorkspacePipelineTaskBinding {
+	return tektonv1beta1.WorkspacePipelineTaskBinding{
+		Name:      from.Name,
+		Workspace: from.Name,
+		SubPath:   from.SubPath,
+	}
+}
+
+// ToWorkspacePipelineTaskBindingsFromDeclarations converts the workspace declarations to pipeline task bindings
+func ToWorkspacePipelineTaskBindingsFromDeclarations(workspaces []tektonv1beta1.WorkspaceDeclaration) []tektonv1beta1.WorkspacePipelineTaskBinding {
+	var answer []tektonv1beta1.WorkspacePipelineTaskBinding
+	for _, from := range workspaces {
+		answer = append(answer, ToWorkspacePipelineTaskBindingsFromDeclaration(from))
+	}
+	return answer
+}
+
+// ToWorkspacePipelineTaskBindingsFromDeclaration converts the workspace declaration to a pipeline task binding
+func ToWorkspacePipelineTaskBindingsFromDeclaration(from tektonv1beta1.WorkspaceDeclaration) tektonv1beta1.WorkspacePipelineTaskBinding {
+	return tektonv1beta1.WorkspacePipelineTaskBinding{
+		Name:      from.Name,
+		Workspace: from.Name,
+		SubPath:   "",
+	}
+}
+
+// ToPipelineWorkspaceDeclarations converts the workspace declarations to pipeline workspace declarations
+func ToPipelineWorkspaceDeclarations(workspaces []tektonv1beta1.WorkspaceDeclaration) []tektonv1beta1.PipelineWorkspaceDeclaration {
+	var answer []tektonv1beta1.PipelineWorkspaceDeclaration
+	for _, from := range workspaces {
+		answer = append(answer, ToPipelineWorkspaceDeclaration(from))
+	}
+	return answer
+}
+
+// ToPipelineWorkspaceDeclaration converts the workspace declaration to a pipeline workspace declaration
+func ToPipelineWorkspaceDeclaration(from tektonv1beta1.WorkspaceDeclaration) tektonv1beta1.PipelineWorkspaceDeclaration {
+	return tektonv1beta1.PipelineWorkspaceDeclaration{
+		Name:        from.Name,
+		Description: from.Description,
+	}
+}
diff --git a/pkg/triggerconfig/inrepo/load_triggers.go b/pkg/triggerconfig/inrepo/load_triggers.go
index 03d034eb..1e556dcf 100644
--- a/pkg/triggerconfig/inrepo/load_triggers.go
+++ b/pkg/triggerconfig/inrepo/load_triggers.go
@@ -1,16 +1,17 @@
 package inrepo
 
 import (
+	"fmt"
 	"path/filepath"
 	"strings"
 
+	"github.com/jenkins-x/go-scm/scm"
 	"github.com/jenkins-x/lighthouse/pkg/config"
 	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/plugins"
 	"github.com/jenkins-x/lighthouse/pkg/triggerconfig"
 	"github.com/jenkins-x/lighthouse/pkg/triggerconfig/merge"
 	"github.com/pkg/errors"
-	tektonv1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
 	"sigs.k8s.io/yaml"
 )
 
@@ -148,12 +149,35 @@ func loadJobBaseFromSourcePath(client scmProviderClient, j *job.Base, ownerName,
 		return errors.Errorf("empty file file %s in repo %s/%s for sha %s", path, ownerName, repoName, sha)
 	}
 
-	// for now lets assume its a PipelineRun we could eventually support different kinds
-	prs := &tektonv1beta1.PipelineRun{}
-	err = yaml.Unmarshal(data, prs)
+	dir := filepath.Dir(path)
+
+	message := fmt.Sprintf("in repo %s/%s with sha %s", ownerName, repoName, sha)
+
+	getData := func(path string) ([]byte, error) {
+		data, err := client.GetFile(ownerName, repoName, path, sha)
+		if err != nil && IsScmNotFound(err) {
+			err = nil
+		}
+		if err != nil {
+			return nil, errors.Wrapf(err, "failed to find file %s in repo %s/%s with sha %s", path, ownerName, repoName, sha)
+		}
+		return data, nil
+	}
+
+	prs, err := LoadTektonResourceAsPipelineRun(data, dir, message, getData, nil)
 	if err != nil {
-		return errors.Wrapf(err, "failed to unmarshal YAML file %s/%s in repo %s with sha %s", path, ownerName, repoName, sha)
+		return errors.Wrapf(err, "failed to unmarshal YAML file %s in repo %s/%s with sha %s", path, ownerName, repoName, sha)
 	}
 	j.PipelineRunSpec = &prs.Spec
 	return nil
 }
+
+// IsScmNotFound returns true if the error is a not found error
+func IsScmNotFound(err error) bool {
+	if err != nil {
+		// I think that we should instead rely on the http status (404)
+		// until jenkins-x go-scm is updated t return that in the error this works for github and gitlab
+		return strings.Contains(err.Error(), scm.ErrNotFound.Error())
+	}
+	return false
+}


Test patch:
diff --git a/pkg/triggerconfig/inrepo/load_pipelinerun_test.go b/pkg/triggerconfig/inrepo/load_pipelinerun_test.go
new file mode 100644
index 00000000..72307460
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/load_pipelinerun_test.go
@@ -0,0 +1,63 @@
+package inrepo
+
+import (
+	"io/ioutil"
+	"path/filepath"
+	"strings"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
+	"sigs.k8s.io/yaml"
+)
+
+var (
+	// generateTestOutput enable to regenerate the expected output
+	generateTestOutput = false
+)
+
+func TestLoadPipelineRunTest(t *testing.T) {
+	sourceDir := filepath.Join("test_data", "load_pipelinerun")
+	fs, err := ioutil.ReadDir(sourceDir)
+	require.NoError(t, err, "failed to read source dir %s", sourceDir)
+
+	getData := func(path string) ([]byte, error) {
+		return ioutil.ReadFile(path)
+	}
+	for _, f := range fs {
+		if !f.IsDir() {
+			continue
+		}
+		name := f.Name()
+		if strings.HasPrefix(name, ".") {
+			continue
+		}
+		dir := filepath.Join(sourceDir, name)
+		path := filepath.Join(dir, "source.yaml")
+		expectedPath := filepath.Join(dir, "expected.yaml")
+
+		message := "load file " + path
+		data, err := ioutil.ReadFile(path)
+		require.NoError(t, err, "failed to load "+message)
+
+		pr, err := LoadTektonResourceAsPipelineRun(data, dir, message, getData, nil)
+		require.NoError(t, err, "failed to load PipelineRun for "+message)
+		require.NotNil(t, pr, "no PipelineRun for "+message)
+
+		data, err = yaml.Marshal(pr)
+		require.NoError(t, err, "failed to marshal generated PipelineRun for "+message)
+
+		if generateTestOutput {
+			err = ioutil.WriteFile(expectedPath, data, 0666)
+			require.NoError(t, err, "failed to save file %s", expectedPath)
+			continue
+		}
+		expectedData, err := ioutil.ReadFile(expectedPath)
+		require.NoError(t, err, "failed to load file "+expectedPath)
+
+		text := strings.TrimSpace(string(data))
+		expectedText := strings.TrimSpace(string(expectedData))
+
+		assert.Equal(t, expectedText, text, "PipelineRun loaded for "+message)
+	}
+}
diff --git a/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline-load-refs/demo-deploy-kubectl.yaml b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline-load-refs/demo-deploy-kubectl.yaml
new file mode 100644
index 00000000..16085bb5
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline-load-refs/demo-deploy-kubectl.yaml
@@ -0,0 +1,35 @@
+# This task deploys with kubectl apply -f <filename>
+apiVersion: tekton.dev/v1beta1
+kind: Task
+metadata:
+  name: demo-deploy-kubectl
+spec:
+  params:
+  - name: path
+    description: Path to the manifest to apply
+  - name: yqArg
+    description: Okay this is a hack, but I didn't feel right hard-coding `-d1` down below
+  - name: yamlPathToImage
+    description: The path to the image to replace in the yaml manifest (arg to yq)
+  - name: imageURL
+    description: The URL of the image to deploy
+  workspaces:
+  - name: source
+  steps:
+  - name: replace-image
+    image: mikefarah/yq
+    command: ['yq']
+    args:
+    - "w"
+    - "-i"
+    - "$(params.yqArg)"
+    - "$(params.path)"
+    - "$(params.yamlPathToImage)"
+    - "$(params.imageURL)"
+  - name: run-kubectl
+    image: lachlanevenson/k8s-kubectl
+    command: ['kubectl']
+    args:
+    - 'apply'
+    - '-f'
+    - '$(params.path)'
\ No newline at end of file
diff --git a/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline-load-refs/expected.yaml b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline-load-refs/expected.yaml
new file mode 100644
index 00000000..644a1807
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline-load-refs/expected.yaml
@@ -0,0 +1,349 @@
+apiVersion: tekton.dev/v1beta1
+kind: PipelineRun
+metadata:
+  annotations:
+    lighthouse.jenkins-x.io/loadFileRefs: .*
+  creationTimestamp: null
+  name: demo-pipeline
+spec:
+  pipelineSpec:
+    params:
+    - default: gcr.io/christiewilson-catfactory
+      name: image-registry
+    tasks:
+    - name: fetch-from-git
+      params:
+      - name: url
+        value: https://github.com/GoogleContainerTools/skaffold
+      - name: revision
+        value: v0.32.0
+      taskSpec:
+        params:
+        - description: git url to clone
+          name: url
+          type: string
+        - default: master
+          description: git revision to checkout (branch, tag, sha, ref…)
+          name: revision
+          type: string
+        - default: "true"
+          description: defines if the resource should initialize and fetch the submodules
+          name: submodules
+          type: string
+        - default: "1"
+          description: performs a shallow clone where only the most recent commit(s) will be fetched
+          name: depth
+          type: string
+        - default: "true"
+          description: defines if http.sslVerify should be set to true or false in the global git config
+          name: sslVerify
+          type: string
+        - default: ""
+          description: subdirectory inside the "output" workspace to clone the git repo into
+          name: subdirectory
+          type: string
+        - default: "false"
+          description: clean out the contents of the repo's destination directory (if it already exists) before trying to clone the repo there
+          name: deleteExisting
+          type: string
+        results:
+        - description: The precise commit SHA that was fetched by this Task
+          name: commit
+        steps:
+        - image: ko://github.com/tektoncd/pipeline/cmd/git-init
+          name: clone
+          resources: {}
+          script: |-
+            CHECKOUT_DIR="$(workspaces.output.path)/$(params.subdirectory)"
+            cleandir() {
+              # Delete any existing contents of the repo directory if it exists.
+              #
+              # We don't just "rm -rf $CHECKOUT_DIR" because $CHECKOUT_DIR might be "/"
+              # or the root of a mounted volume.
+              if [[ -d "$CHECKOUT_DIR" ]] ; then
+                # Delete non-hidden files and directories
+                rm -rf "$CHECKOUT_DIR"/*
+                # Delete files and directories starting with . but excluding ..
+                rm -rf "$CHECKOUT_DIR"/.[!.]*
+                # Delete files and directories starting with .. plus any other character
+                rm -rf "$CHECKOUT_DIR"/..?*
+              fi
+            }
+            if [[ "$(params.deleteExisting)" == "true" ]] ; then
+              cleandir
+            fi
+            /ko-app/git-init \
+              -url "$(params.url)" \
+              -revision "$(params.revision)" \
+              -path "$CHECKOUT_DIR" \
+              -sslVerify="$(params.sslVerify)" \
+              -submodules="$(params.submodules)" \
+              -depth="$(params.depth)"
+            cd "$CHECKOUT_DIR"
+            RESULT_SHA="$(git rev-parse HEAD | tr -d '\n')"
+            EXIT_CODE="$?"
+            if [ "$EXIT_CODE" != 0 ]
+            then
+              exit $EXIT_CODE
+            fi
+            # Make sure we don't add a trailing newline to the result!
+            echo -n "$RESULT_SHA" > $(results.commit.path)
+        workspaces:
+        - description: The git repo will be cloned onto the volume backing this workspace
+          name: output
+      workspaces:
+      - name: output
+        workspace: git-source
+    - name: skaffold-unit-tests
+      runAfter:
+      - fetch-from-git
+      taskSpec:
+        steps:
+        - env:
+          - name: GOPATH
+            value: /workspace/go
+          image: golang
+          name: run-tests
+          resources: {}
+          script: |-
+            # The intention behind this example Task is to run unit test, however we
+            # currently do nothing to ensure that a unit test issue doesn't cause this example
+            # to fail unnecessarily. In the future we could re-introduce the unit tests (since
+            # we are now pinning the version of Skaffold we pull) or use Tekton Pipelines unit tests.
+            echo "pass"
+          workingDir: $(workspaces.source.path)
+        workspaces:
+        - mountPath: /workspace/source/go/src/github.com/GoogleContainerTools/skaffold
+          name: source
+      workspaces:
+      - name: source
+        workspace: git-source
+    - name: build-skaffold-web
+      params:
+      - name: IMAGE
+        value: $(params.image-registry)/leeroy-web
+      - name: CONTEXT
+        value: examples/microservices/leeroy-web
+      - name: DOCKERFILE
+        value: $(workspaces.source.path)/examples/microservices/leeroy-web/Dockerfile
+      runAfter:
+      - skaffold-unit-tests
+      taskSpec:
+        params:
+        - description: Name (reference) of the image to build.
+          name: IMAGE
+        - default: ./Dockerfile
+          description: Path to the Dockerfile to build.
+          name: DOCKERFILE
+        - default: ./
+          description: The build context used by Kaniko.
+          name: CONTEXT
+        - default: ""
+          name: EXTRA_ARGS
+        - default: gcr.io/kaniko-project/executor:latest
+          description: The image on which builds will run
+          name: BUILDER_IMAGE
+        results:
+        - description: Digest of the image just built.
+          name: IMAGE_DIGEST
+        steps:
+        - command:
+          - /kaniko/executor
+          - $(params.EXTRA_ARGS)
+          - --dockerfile=$(params.DOCKERFILE)
+          - --context=$(workspaces.source.path)/$(params.CONTEXT)
+          - --destination=$(params.IMAGE)
+          - --oci-layout-path=$(workspaces.source.path)/$(params.CONTEXT)/image-digest
+          env:
+          - name: DOCKER_CONFIG
+            value: /tekton/home/.docker
+          image: $(params.BUILDER_IMAGE)
+          name: build-and-push
+          resources: {}
+          securityContext:
+            runAsUser: 0
+          workingDir: $(workspaces.source.path)
+        - args:
+          - -images=[{"name":"$(params.IMAGE)","type":"image","url":"$(params.IMAGE)","digest":"","OutputImageDir":"$(workspaces.source.path)/$(params.CONTEXT)/image-digest"}]
+          - -terminationMessagePath=$(params.CONTEXT)/image-digested
+          command:
+          - /ko-app/imagedigestexporter
+          image: ko://github.com/tektoncd/pipeline/cmd/imagedigestexporter
+          name: write-digest
+          resources: {}
+          securityContext:
+            runAsUser: 0
+          workingDir: $(workspaces.source.path)
+        - image: stedolan/jq
+          name: digest-to-results
+          resources: {}
+          script: cat $(params.CONTEXT)/image-digested | jq '.[0].value' -rj | tee /tekton/results/IMAGE_DIGEST
+          workingDir: $(workspaces.source.path)
+        workspaces:
+        - name: source
+      workspaces:
+      - name: source
+        workspace: git-source
+    - name: build-skaffold-app
+      params:
+      - name: IMAGE
+        value: $(params.image-registry)/leeroy-app
+      - name: CONTEXT
+        value: examples/microservices/leeroy-app
+      - name: DOCKERFILE
+        value: $(workspaces.source.path)/examples/microservices/leeroy-app/Dockerfile
+      runAfter:
+      - skaffold-unit-tests
+      taskSpec:
+        params:
+        - description: Name (reference) of the image to build.
+          name: IMAGE
+        - default: ./Dockerfile
+          description: Path to the Dockerfile to build.
+          name: DOCKERFILE
+        - default: ./
+          description: The build context used by Kaniko.
+          name: CONTEXT
+        - default: ""
+          name: EXTRA_ARGS
+        - default: gcr.io/kaniko-project/executor:latest
+          description: The image on which builds will run
+          name: BUILDER_IMAGE
+        results:
+        - description: Digest of the image just built.
+          name: IMAGE_DIGEST
+        steps:
+        - command:
+          - /kaniko/executor
+          - $(params.EXTRA_ARGS)
+          - --dockerfile=$(params.DOCKERFILE)
+          - --context=$(workspaces.source.path)/$(params.CONTEXT)
+          - --destination=$(params.IMAGE)
+          - --oci-layout-path=$(workspaces.source.path)/$(params.CONTEXT)/image-digest
+          env:
+          - name: DOCKER_CONFIG
+            value: /tekton/home/.docker
+          image: $(params.BUILDER_IMAGE)
+          name: build-and-push
+          resources: {}
+          securityContext:
+            runAsUser: 0
+          workingDir: $(workspaces.source.path)
+        - args:
+          - -images=[{"name":"$(params.IMAGE)","type":"image","url":"$(params.IMAGE)","digest":"","OutputImageDir":"$(workspaces.source.path)/$(params.CONTEXT)/image-digest"}]
+          - -terminationMessagePath=$(params.CONTEXT)/image-digested
+          command:
+          - /ko-app/imagedigestexporter
+          image: ko://github.com/tektoncd/pipeline/cmd/imagedigestexporter
+          name: write-digest
+          resources: {}
+          securityContext:
+            runAsUser: 0
+          workingDir: $(workspaces.source.path)
+        - image: stedolan/jq
+          name: digest-to-results
+          resources: {}
+          script: cat $(params.CONTEXT)/image-digested | jq '.[0].value' -rj | tee /tekton/results/IMAGE_DIGEST
+          workingDir: $(workspaces.source.path)
+        workspaces:
+        - name: source
+      workspaces:
+      - name: source
+        workspace: git-source
+    - name: deploy-app
+      params:
+      - name: imageURL
+        value: $(params.image-registry)/leeroy-app@$(tasks.build-skaffold-app.results.IMAGE_DIGEST)
+      - name: path
+        value: $(workspaces.source.path)/examples/microservices/leeroy-app/kubernetes/deployment.yaml
+      - name: yqArg
+        value: -d1
+      - name: yamlPathToImage
+        value: spec.template.spec.containers[0].image
+      taskSpec:
+        params:
+        - description: Path to the manifest to apply
+          name: path
+        - description: Okay this is a hack, but I didn't feel right hard-coding `-d1` down below
+          name: yqArg
+        - description: The path to the image to replace in the yaml manifest (arg to yq)
+          name: yamlPathToImage
+        - description: The URL of the image to deploy
+          name: imageURL
+        steps:
+        - args:
+          - w
+          - -i
+          - $(params.yqArg)
+          - $(params.path)
+          - $(params.yamlPathToImage)
+          - $(params.imageURL)
+          command:
+          - yq
+          image: mikefarah/yq
+          name: replace-image
+          resources: {}
+        - args:
+          - apply
+          - -f
+          - $(params.path)
+          command:
+          - kubectl
+          image: lachlanevenson/k8s-kubectl
+          name: run-kubectl
+          resources: {}
+        workspaces:
+        - name: source
+      workspaces:
+      - name: source
+        workspace: git-source
+    - name: deploy-web
+      params:
+      - name: imageURL
+        value: $(params.image-registry)/leeroy-web@$(tasks.build-skaffold-web.results.IMAGE_DIGEST)
+      - name: path
+        value: $(workspaces.source.path)/examples/microservices/leeroy-web/kubernetes/deployment.yaml
+      - name: yqArg
+        value: -d1
+      - name: yamlPathToImage
+        value: spec.template.spec.containers[0].image
+      taskSpec:
+        params:
+        - description: Path to the manifest to apply
+          name: path
+        - description: Okay this is a hack, but I didn't feel right hard-coding `-d1` down below
+          name: yqArg
+        - description: The path to the image to replace in the yaml manifest (arg to yq)
+          name: yamlPathToImage
+        - description: The URL of the image to deploy
+          name: imageURL
+        steps:
+        - args:
+          - w
+          - -i
+          - $(params.yqArg)
+          - $(params.path)
+          - $(params.yamlPathToImage)
+          - $(params.imageURL)
+          command:
+          - yq
+          image: mikefarah/yq
+          name: replace-image
+          resources: {}
+        - args:
+          - apply
+          - -f
+          - $(params.path)
+          command:
+          - kubectl
+          image: lachlanevenson/k8s-kubectl
+          name: run-kubectl
+          resources: {}
+        workspaces:
+        - name: source
+      workspaces:
+      - name: source
+        workspace: git-source
+    workspaces:
+    - name: git-source
+status: {}
diff --git a/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline-load-refs/git-clone.yaml b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline-load-refs/git-clone.yaml
new file mode 100644
index 00000000..ab919a87
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline-load-refs/git-clone.yaml
@@ -0,0 +1,80 @@
+# Copied from https://github.com/tektoncd/catalog/blob/v1beta1/git/git-clone.yaml
+# With a few fixes being ported over in https://github.com/tektoncd/catalog/pull/290
+# Post #1839 we can refer to the remote Task in a registry or post #2298 in git directly
+apiVersion: tekton.dev/v1beta1
+kind: Task
+metadata:
+  name: git-clone
+spec:
+  workspaces:
+  - name: output
+    description: The git repo will be cloned onto the volume backing this workspace
+  params:
+  - name: url
+    description: git url to clone
+    type: string
+  - name: revision
+    description: git revision to checkout (branch, tag, sha, ref…)
+    type: string
+    default: master
+  - name: submodules
+    description: defines if the resource should initialize and fetch the submodules
+    type: string
+    default: "true"
+  - name: depth
+    description: performs a shallow clone where only the most recent commit(s) will be fetched
+    type: string
+    default: "1"
+  - name: sslVerify
+    description: defines if http.sslVerify should be set to true or false in the global git config
+    type: string
+    default: "true"
+  - name: subdirectory
+    description: subdirectory inside the "output" workspace to clone the git repo into
+    type: string
+    default: ""
+  - name: deleteExisting
+    description: clean out the contents of the repo's destination directory (if it already exists) before trying to clone the repo there
+    type: string
+    default: "false"
+  results:
+  - name: commit
+    description: The precise commit SHA that was fetched by this Task
+  steps:
+  - name: clone
+    image: ko://github.com/tektoncd/pipeline/cmd/git-init
+    script: |
+      CHECKOUT_DIR="$(workspaces.output.path)/$(params.subdirectory)"
+      cleandir() {
+        # Delete any existing contents of the repo directory if it exists.
+        #
+        # We don't just "rm -rf $CHECKOUT_DIR" because $CHECKOUT_DIR might be "/"
+        # or the root of a mounted volume.
+        if [[ -d "$CHECKOUT_DIR" ]] ; then
+          # Delete non-hidden files and directories
+          rm -rf "$CHECKOUT_DIR"/*
+          # Delete files and directories starting with . but excluding ..
+          rm -rf "$CHECKOUT_DIR"/.[!.]*
+          # Delete files and directories starting with .. plus any other character
+          rm -rf "$CHECKOUT_DIR"/..?*
+        fi
+      }
+      if [[ "$(params.deleteExisting)" == "true" ]] ; then
+        cleandir
+      fi
+      /ko-app/git-init \
+        -url "$(params.url)" \
+        -revision "$(params.revision)" \
+        -path "$CHECKOUT_DIR" \
+        -sslVerify="$(params.sslVerify)" \
+        -submodules="$(params.submodules)" \
+        -depth="$(params.depth)"
+      cd "$CHECKOUT_DIR"
+      RESULT_SHA="$(git rev-parse HEAD | tr -d '\n')"
+      EXIT_CODE="$?"
+      if [ "$EXIT_CODE" != 0 ]
+      then
+        exit $EXIT_CODE
+      fi
+      # Make sure we don't add a trailing newline to the result!
+      echo -n "$RESULT_SHA" > $(results.commit.path)
\ No newline at end of file
diff --git a/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline-load-refs/kaniko.yaml b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline-load-refs/kaniko.yaml
new file mode 100644
index 00000000..07f2c512
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline-load-refs/kaniko.yaml
@@ -0,0 +1,63 @@
+# Copied from https://github.com/tektoncd/catalog/blob/v1beta1/kaniko/kaniko.yaml
+# with a few fixes that will be port over in https://github.com/tektoncd/catalog/pull/291
+# Post #1839 we can refer to the remote Task in a registry or post #2298 in git directly
+apiVersion: tekton.dev/v1beta1
+kind: Task
+metadata:
+  name: kaniko
+spec:
+  workspaces:
+  - name: source
+  params:
+  - name: IMAGE
+    description: Name (reference) of the image to build.
+  - name: DOCKERFILE
+    description: Path to the Dockerfile to build.
+    default: ./Dockerfile
+  - name: CONTEXT
+    description: The build context used by Kaniko.
+    default: ./
+  - name: EXTRA_ARGS
+    default: ""
+  - name: BUILDER_IMAGE
+    description: The image on which builds will run
+    default: gcr.io/kaniko-project/executor:latest
+  results:
+  - name: IMAGE_DIGEST
+    description: Digest of the image just built.
+  steps:
+  - name: build-and-push
+    workingDir: $(workspaces.source.path)
+    image: $(params.BUILDER_IMAGE)
+    # specifying DOCKER_CONFIG is required to allow kaniko to detect docker credential
+    # https://github.com/tektoncd/pipeline/pull/706
+    env:
+    - name: DOCKER_CONFIG
+      value: /tekton/home/.docker
+    command:
+    - /kaniko/executor
+    - $(params.EXTRA_ARGS)
+    - --dockerfile=$(params.DOCKERFILE)
+    - --context=$(workspaces.source.path)/$(params.CONTEXT)  # The user does not need to care the workspace and the source.
+    - --destination=$(params.IMAGE)
+    - --oci-layout-path=$(workspaces.source.path)/$(params.CONTEXT)/image-digest
+    # kaniko assumes it is running as root, which means this example fails on platforms
+    # that default to run containers as random uid (like OpenShift). Adding this securityContext
+    # makes it explicit that it needs to run as root.
+    securityContext:
+      runAsUser: 0
+  - name: write-digest
+    workingDir: $(workspaces.source.path)
+    image: ko://github.com/tektoncd/pipeline/cmd/imagedigestexporter
+    # output of imagedigestexport [{"name":"image","digest":"sha256:eed29..660"}]
+    command: ["/ko-app/imagedigestexporter"]
+    securityContext:
+      runAsUser: 0
+    args:
+    - -images=[{"name":"$(params.IMAGE)","type":"image","url":"$(params.IMAGE)","digest":"","OutputImageDir":"$(workspaces.source.path)/$(params.CONTEXT)/image-digest"}]
+    - -terminationMessagePath=$(params.CONTEXT)/image-digested
+  - name: digest-to-results
+    workingDir: $(workspaces.source.path)
+    image: stedolan/jq
+    script: |
+      cat $(params.CONTEXT)/image-digested | jq '.[0].value' -rj | tee /tekton/results/IMAGE_DIGEST
\ No newline at end of file
diff --git a/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline-load-refs/source.yaml b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline-load-refs/source.yaml
new file mode 100644
index 00000000..783552f7
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline-load-refs/source.yaml
@@ -0,0 +1,91 @@
+# This Pipeline Builds two microservice images(https://github.com/GoogleContainerTools/skaffold/tree/master/examples/microservices)
+# from the Skaffold repo (https://github.com/GoogleContainerTools/skaffold) and deploys them to the repo currently running Tekton Pipelines.
+apiVersion: tekton.dev/v1beta1
+kind: Pipeline
+metadata:
+  name: demo-pipeline
+  annotations:
+    lighthouse.jenkins-x.io/loadFileRefs: ".*"
+spec:
+  params:
+  - name: image-registry
+    default: gcr.io/christiewilson-catfactory
+  workspaces:
+  - name: git-source
+  tasks:
+  - name: fetch-from-git
+    taskRef:
+      name: git-clone
+    params:
+    - name: url
+      value: https://github.com/GoogleContainerTools/skaffold
+    - name: revision
+      value: v0.32.0
+    workspaces:
+    - name: output
+      workspace: git-source
+  - name: skaffold-unit-tests
+    runAfter: [fetch-from-git]
+    taskRef:
+      name: unit-tests
+    workspaces:
+    - name: source
+      workspace: git-source
+  - name: build-skaffold-web
+    runAfter: [skaffold-unit-tests]
+    taskRef:
+      name: kaniko
+    params:
+    - name: IMAGE
+      value: $(params.image-registry)/leeroy-web
+    - name: CONTEXT
+      value: examples/microservices/leeroy-web
+    - name: DOCKERFILE
+      value: $(workspaces.source.path)/examples/microservices/leeroy-web/Dockerfile
+    workspaces:
+    - name: source
+      workspace: git-source
+  - name: build-skaffold-app
+    runAfter: [skaffold-unit-tests]
+    taskRef:
+      name: kaniko
+    params:
+    - name: IMAGE
+      value: $(params.image-registry)/leeroy-app
+    - name: CONTEXT
+      value: examples/microservices/leeroy-app
+    - name: DOCKERFILE
+      value: $(workspaces.source.path)/examples/microservices/leeroy-app/Dockerfile
+    workspaces:
+    - name: source
+      workspace: git-source
+  - name: deploy-app
+    taskRef:
+      name: demo-deploy-kubectl
+    params:
+    - name: imageURL
+      value: $(params.image-registry)/leeroy-app@$(tasks.build-skaffold-app.results.IMAGE_DIGEST)
+    - name: path
+      value: $(workspaces.source.path)/examples/microservices/leeroy-app/kubernetes/deployment.yaml
+    - name: yqArg
+      value: "-d1"
+    - name: yamlPathToImage
+      value: "spec.template.spec.containers[0].image"
+    workspaces:
+    - name: source
+      workspace: git-source
+  - name: deploy-web
+    taskRef:
+      name: demo-deploy-kubectl
+    params:
+    - name: imageURL
+      value: $(params.image-registry)/leeroy-web@$(tasks.build-skaffold-web.results.IMAGE_DIGEST)
+    - name: path
+      value: $(workspaces.source.path)/examples/microservices/leeroy-web/kubernetes/deployment.yaml
+    - name: yqArg
+      value: "-d1"
+    - name: yamlPathToImage
+      value: "spec.template.spec.containers[0].image"
+    workspaces:
+    - name: source
+      workspace: git-source
\ No newline at end of file
diff --git a/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline-load-refs/unit-tests.yaml b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline-load-refs/unit-tests.yaml
new file mode 100644
index 00000000..f69fc779
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline-load-refs/unit-tests.yaml
@@ -0,0 +1,21 @@
+apiVersion: tekton.dev/v1beta1
+kind: Task
+metadata:
+  name: unit-tests
+spec:
+  workspaces:
+  - name: source
+    mountPath: /workspace/source/go/src/github.com/GoogleContainerTools/skaffold
+  steps:
+  - name: run-tests
+    image: golang
+    env:
+    - name: GOPATH
+      value: /workspace/go
+    workingDir: $(workspaces.source.path)
+    script: |
+      # The intention behind this example Task is to run unit test, however we
+      # currently do nothing to ensure that a unit test issue doesn't cause this example
+      # to fail unnecessarily. In the future we could re-introduce the unit tests (since
+      # we are now pinning the version of Skaffold we pull) or use Tekton Pipelines unit tests.
+      echo "pass"
\ No newline at end of file
diff --git a/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline/demo-deploy-kubectl.yaml b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline/demo-deploy-kubectl.yaml
new file mode 100644
index 00000000..16085bb5
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline/demo-deploy-kubectl.yaml
@@ -0,0 +1,35 @@
+# This task deploys with kubectl apply -f <filename>
+apiVersion: tekton.dev/v1beta1
+kind: Task
+metadata:
+  name: demo-deploy-kubectl
+spec:
+  params:
+  - name: path
+    description: Path to the manifest to apply
+  - name: yqArg
+    description: Okay this is a hack, but I didn't feel right hard-coding `-d1` down below
+  - name: yamlPathToImage
+    description: The path to the image to replace in the yaml manifest (arg to yq)
+  - name: imageURL
+    description: The URL of the image to deploy
+  workspaces:
+  - name: source
+  steps:
+  - name: replace-image
+    image: mikefarah/yq
+    command: ['yq']
+    args:
+    - "w"
+    - "-i"
+    - "$(params.yqArg)"
+    - "$(params.path)"
+    - "$(params.yamlPathToImage)"
+    - "$(params.imageURL)"
+  - name: run-kubectl
+    image: lachlanevenson/k8s-kubectl
+    command: ['kubectl']
+    args:
+    - 'apply'
+    - '-f'
+    - '$(params.path)'
\ No newline at end of file
diff --git a/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline/expected.yaml b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline/expected.yaml
new file mode 100644
index 00000000..5a2336c4
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline/expected.yaml
@@ -0,0 +1,93 @@
+apiVersion: tekton.dev/v1beta1
+kind: PipelineRun
+metadata:
+  creationTimestamp: null
+  name: demo-pipeline
+spec:
+  pipelineSpec:
+    params:
+    - default: gcr.io/christiewilson-catfactory
+      name: image-registry
+    tasks:
+    - name: fetch-from-git
+      params:
+      - name: url
+        value: https://github.com/GoogleContainerTools/skaffold
+      - name: revision
+        value: v0.32.0
+      taskRef:
+        name: git-clone
+      workspaces:
+      - name: output
+        workspace: git-source
+    - name: skaffold-unit-tests
+      runAfter:
+      - fetch-from-git
+      taskRef:
+        name: unit-tests
+      workspaces:
+      - name: source
+        workspace: git-source
+    - name: build-skaffold-web
+      params:
+      - name: IMAGE
+        value: $(params.image-registry)/leeroy-web
+      - name: CONTEXT
+        value: examples/microservices/leeroy-web
+      - name: DOCKERFILE
+        value: $(workspaces.source.path)/examples/microservices/leeroy-web/Dockerfile
+      runAfter:
+      - skaffold-unit-tests
+      taskRef:
+        name: kaniko
+      workspaces:
+      - name: source
+        workspace: git-source
+    - name: build-skaffold-app
+      params:
+      - name: IMAGE
+        value: $(params.image-registry)/leeroy-app
+      - name: CONTEXT
+        value: examples/microservices/leeroy-app
+      - name: DOCKERFILE
+        value: $(workspaces.source.path)/examples/microservices/leeroy-app/Dockerfile
+      runAfter:
+      - skaffold-unit-tests
+      taskRef:
+        name: kaniko
+      workspaces:
+      - name: source
+        workspace: git-source
+    - name: deploy-app
+      params:
+      - name: imageURL
+        value: $(params.image-registry)/leeroy-app@$(tasks.build-skaffold-app.results.IMAGE_DIGEST)
+      - name: path
+        value: $(workspaces.source.path)/examples/microservices/leeroy-app/kubernetes/deployment.yaml
+      - name: yqArg
+        value: -d1
+      - name: yamlPathToImage
+        value: spec.template.spec.containers[0].image
+      taskRef:
+        name: demo-deploy-kubectl
+      workspaces:
+      - name: source
+        workspace: git-source
+    - name: deploy-web
+      params:
+      - name: imageURL
+        value: $(params.image-registry)/leeroy-web@$(tasks.build-skaffold-web.results.IMAGE_DIGEST)
+      - name: path
+        value: $(workspaces.source.path)/examples/microservices/leeroy-web/kubernetes/deployment.yaml
+      - name: yqArg
+        value: -d1
+      - name: yamlPathToImage
+        value: spec.template.spec.containers[0].image
+      taskRef:
+        name: demo-deploy-kubectl
+      workspaces:
+      - name: source
+        workspace: git-source
+    workspaces:
+    - name: git-source
+status: {}
diff --git a/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline/git-clone.yaml b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline/git-clone.yaml
new file mode 100644
index 00000000..ab919a87
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline/git-clone.yaml
@@ -0,0 +1,80 @@
+# Copied from https://github.com/tektoncd/catalog/blob/v1beta1/git/git-clone.yaml
+# With a few fixes being ported over in https://github.com/tektoncd/catalog/pull/290
+# Post #1839 we can refer to the remote Task in a registry or post #2298 in git directly
+apiVersion: tekton.dev/v1beta1
+kind: Task
+metadata:
+  name: git-clone
+spec:
+  workspaces:
+  - name: output
+    description: The git repo will be cloned onto the volume backing this workspace
+  params:
+  - name: url
+    description: git url to clone
+    type: string
+  - name: revision
+    description: git revision to checkout (branch, tag, sha, ref…)
+    type: string
+    default: master
+  - name: submodules
+    description: defines if the resource should initialize and fetch the submodules
+    type: string
+    default: "true"
+  - name: depth
+    description: performs a shallow clone where only the most recent commit(s) will be fetched
+    type: string
+    default: "1"
+  - name: sslVerify
+    description: defines if http.sslVerify should be set to true or false in the global git config
+    type: string
+    default: "true"
+  - name: subdirectory
+    description: subdirectory inside the "output" workspace to clone the git repo into
+    type: string
+    default: ""
+  - name: deleteExisting
+    description: clean out the contents of the repo's destination directory (if it already exists) before trying to clone the repo there
+    type: string
+    default: "false"
+  results:
+  - name: commit
+    description: The precise commit SHA that was fetched by this Task
+  steps:
+  - name: clone
+    image: ko://github.com/tektoncd/pipeline/cmd/git-init
+    script: |
+      CHECKOUT_DIR="$(workspaces.output.path)/$(params.subdirectory)"
+      cleandir() {
+        # Delete any existing contents of the repo directory if it exists.
+        #
+        # We don't just "rm -rf $CHECKOUT_DIR" because $CHECKOUT_DIR might be "/"
+        # or the root of a mounted volume.
+        if [[ -d "$CHECKOUT_DIR" ]] ; then
+          # Delete non-hidden files and directories
+          rm -rf "$CHECKOUT_DIR"/*
+          # Delete files and directories starting with . but excluding ..
+          rm -rf "$CHECKOUT_DIR"/.[!.]*
+          # Delete files and directories starting with .. plus any other character
+          rm -rf "$CHECKOUT_DIR"/..?*
+        fi
+      }
+      if [[ "$(params.deleteExisting)" == "true" ]] ; then
+        cleandir
+      fi
+      /ko-app/git-init \
+        -url "$(params.url)" \
+        -revision "$(params.revision)" \
+        -path "$CHECKOUT_DIR" \
+        -sslVerify="$(params.sslVerify)" \
+        -submodules="$(params.submodules)" \
+        -depth="$(params.depth)"
+      cd "$CHECKOUT_DIR"
+      RESULT_SHA="$(git rev-parse HEAD | tr -d '\n')"
+      EXIT_CODE="$?"
+      if [ "$EXIT_CODE" != 0 ]
+      then
+        exit $EXIT_CODE
+      fi
+      # Make sure we don't add a trailing newline to the result!
+      echo -n "$RESULT_SHA" > $(results.commit.path)
\ No newline at end of file
diff --git a/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline/kaniko.yaml b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline/kaniko.yaml
new file mode 100644
index 00000000..07f2c512
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline/kaniko.yaml
@@ -0,0 +1,63 @@
+# Copied from https://github.com/tektoncd/catalog/blob/v1beta1/kaniko/kaniko.yaml
+# with a few fixes that will be port over in https://github.com/tektoncd/catalog/pull/291
+# Post #1839 we can refer to the remote Task in a registry or post #2298 in git directly
+apiVersion: tekton.dev/v1beta1
+kind: Task
+metadata:
+  name: kaniko
+spec:
+  workspaces:
+  - name: source
+  params:
+  - name: IMAGE
+    description: Name (reference) of the image to build.
+  - name: DOCKERFILE
+    description: Path to the Dockerfile to build.
+    default: ./Dockerfile
+  - name: CONTEXT
+    description: The build context used by Kaniko.
+    default: ./
+  - name: EXTRA_ARGS
+    default: ""
+  - name: BUILDER_IMAGE
+    description: The image on which builds will run
+    default: gcr.io/kaniko-project/executor:latest
+  results:
+  - name: IMAGE_DIGEST
+    description: Digest of the image just built.
+  steps:
+  - name: build-and-push
+    workingDir: $(workspaces.source.path)
+    image: $(params.BUILDER_IMAGE)
+    # specifying DOCKER_CONFIG is required to allow kaniko to detect docker credential
+    # https://github.com/tektoncd/pipeline/pull/706
+    env:
+    - name: DOCKER_CONFIG
+      value: /tekton/home/.docker
+    command:
+    - /kaniko/executor
+    - $(params.EXTRA_ARGS)
+    - --dockerfile=$(params.DOCKERFILE)
+    - --context=$(workspaces.source.path)/$(params.CONTEXT)  # The user does not need to care the workspace and the source.
+    - --destination=$(params.IMAGE)
+    - --oci-layout-path=$(workspaces.source.path)/$(params.CONTEXT)/image-digest
+    # kaniko assumes it is running as root, which means this example fails on platforms
+    # that default to run containers as random uid (like OpenShift). Adding this securityContext
+    # makes it explicit that it needs to run as root.
+    securityContext:
+      runAsUser: 0
+  - name: write-digest
+    workingDir: $(workspaces.source.path)
+    image: ko://github.com/tektoncd/pipeline/cmd/imagedigestexporter
+    # output of imagedigestexport [{"name":"image","digest":"sha256:eed29..660"}]
+    command: ["/ko-app/imagedigestexporter"]
+    securityContext:
+      runAsUser: 0
+    args:
+    - -images=[{"name":"$(params.IMAGE)","type":"image","url":"$(params.IMAGE)","digest":"","OutputImageDir":"$(workspaces.source.path)/$(params.CONTEXT)/image-digest"}]
+    - -terminationMessagePath=$(params.CONTEXT)/image-digested
+  - name: digest-to-results
+    workingDir: $(workspaces.source.path)
+    image: stedolan/jq
+    script: |
+      cat $(params.CONTEXT)/image-digested | jq '.[0].value' -rj | tee /tekton/results/IMAGE_DIGEST
\ No newline at end of file
diff --git a/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline/source.yaml b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline/source.yaml
new file mode 100644
index 00000000..8ae370bf
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline/source.yaml
@@ -0,0 +1,89 @@
+# This Pipeline Builds two microservice images(https://github.com/GoogleContainerTools/skaffold/tree/master/examples/microservices)
+# from the Skaffold repo (https://github.com/GoogleContainerTools/skaffold) and deploys them to the repo currently running Tekton Pipelines.
+apiVersion: tekton.dev/v1beta1
+kind: Pipeline
+metadata:
+  name: demo-pipeline
+spec:
+  params:
+  - name: image-registry
+    default: gcr.io/christiewilson-catfactory
+  workspaces:
+  - name: git-source
+  tasks:
+  - name: fetch-from-git
+    taskRef:
+      name: git-clone
+    params:
+    - name: url
+      value: https://github.com/GoogleContainerTools/skaffold
+    - name: revision
+      value: v0.32.0
+    workspaces:
+    - name: output
+      workspace: git-source
+  - name: skaffold-unit-tests
+    runAfter: [fetch-from-git]
+    taskRef:
+      name: unit-tests
+    workspaces:
+    - name: source
+      workspace: git-source
+  - name: build-skaffold-web
+    runAfter: [skaffold-unit-tests]
+    taskRef:
+      name: kaniko
+    params:
+    - name: IMAGE
+      value: $(params.image-registry)/leeroy-web
+    - name: CONTEXT
+      value: examples/microservices/leeroy-web
+    - name: DOCKERFILE
+      value: $(workspaces.source.path)/examples/microservices/leeroy-web/Dockerfile
+    workspaces:
+    - name: source
+      workspace: git-source
+  - name: build-skaffold-app
+    runAfter: [skaffold-unit-tests]
+    taskRef:
+      name: kaniko
+    params:
+    - name: IMAGE
+      value: $(params.image-registry)/leeroy-app
+    - name: CONTEXT
+      value: examples/microservices/leeroy-app
+    - name: DOCKERFILE
+      value: $(workspaces.source.path)/examples/microservices/leeroy-app/Dockerfile
+    workspaces:
+    - name: source
+      workspace: git-source
+  - name: deploy-app
+    taskRef:
+      name: demo-deploy-kubectl
+    params:
+    - name: imageURL
+      value: $(params.image-registry)/leeroy-app@$(tasks.build-skaffold-app.results.IMAGE_DIGEST)
+    - name: path
+      value: $(workspaces.source.path)/examples/microservices/leeroy-app/kubernetes/deployment.yaml
+    - name: yqArg
+      value: "-d1"
+    - name: yamlPathToImage
+      value: "spec.template.spec.containers[0].image"
+    workspaces:
+    - name: source
+      workspace: git-source
+  - name: deploy-web
+    taskRef:
+      name: demo-deploy-kubectl
+    params:
+    - name: imageURL
+      value: $(params.image-registry)/leeroy-web@$(tasks.build-skaffold-web.results.IMAGE_DIGEST)
+    - name: path
+      value: $(workspaces.source.path)/examples/microservices/leeroy-web/kubernetes/deployment.yaml
+    - name: yqArg
+      value: "-d1"
+    - name: yamlPathToImage
+      value: "spec.template.spec.containers[0].image"
+    workspaces:
+    - name: source
+      workspace: git-source
\ No newline at end of file
diff --git a/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline/unit-tests.yaml b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline/unit-tests.yaml
new file mode 100644
index 00000000..f69fc779
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pipeline/unit-tests.yaml
@@ -0,0 +1,21 @@
+apiVersion: tekton.dev/v1beta1
+kind: Task
+metadata:
+  name: unit-tests
+spec:
+  workspaces:
+  - name: source
+    mountPath: /workspace/source/go/src/github.com/GoogleContainerTools/skaffold
+  steps:
+  - name: run-tests
+    image: golang
+    env:
+    - name: GOPATH
+      value: /workspace/go
+    workingDir: $(workspaces.source.path)
+    script: |
+      # The intention behind this example Task is to run unit test, however we
+      # currently do nothing to ensure that a unit test issue doesn't cause this example
+      # to fail unnecessarily. In the future we could re-introduce the unit tests (since
+      # we are now pinning the version of Skaffold we pull) or use Tekton Pipelines unit tests.
+      echo "pass"
\ No newline at end of file
diff --git a/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pr-load-refs/add-params.yaml b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pr-load-refs/add-params.yaml
new file mode 100644
index 00000000..bc002209
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pr-load-refs/add-params.yaml
@@ -0,0 +1,21 @@
+apiVersion: tekton.dev/v1beta1
+kind: Task
+metadata:
+  name: add-params
+  annotations:
+    description: |
+      A simple task that sums the two provided integers
+spec:
+  params:
+  - name: a
+    type: string
+    description: The first integer
+  - name: b
+    type: string
+    description: The second integer
+  steps:
+  - name: sum
+    image: bash:latest
+    script: |
+      #!/usr/bin/env bash
+      echo -n $(( "$(inputs.params.a)" + "$(inputs.params.b)" ))
\ No newline at end of file
diff --git a/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pr-load-refs/expected.yaml b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pr-load-refs/expected.yaml
new file mode 100644
index 00000000..78d0971e
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pr-load-refs/expected.yaml
@@ -0,0 +1,44 @@
+apiVersion: tekton.dev/v1beta1
+kind: PipelineRun
+metadata:
+  annotations:
+    lighthouse.jenkins-x.io/loadFileRefs: .*
+  creationTimestamp: null
+  name: pipelinerun-with-extra-params
+spec:
+  params:
+  - name: pl-param-x
+    value: "100"
+  - name: pl-param-y
+    value: "200"
+  - name: pl-param-z
+    value: "300"
+  pipelineSpec:
+    params:
+    - name: pl-param-x
+      type: string
+    - name: pl-param-y
+      type: string
+    tasks:
+    - name: add-params
+      params:
+      - name: a
+        value: $(params.pl-param-x)
+      - name: b
+        value: $(params.pl-param-y)
+      taskSpec:
+        params:
+        - description: The first integer
+          name: a
+          type: string
+        - description: The second integer
+          name: b
+          type: string
+        steps:
+        - image: bash:latest
+          name: sum
+          resources: {}
+          script: |-
+            #!/usr/bin/env bash
+            echo -n $(( "$(inputs.params.a)" + "$(inputs.params.b)" ))
+status: {}
diff --git a/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pr-load-refs/pipeline-with-extra-params.yaml b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pr-load-refs/pipeline-with-extra-params.yaml
new file mode 100644
index 00000000..0b5b66b1
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pr-load-refs/pipeline-with-extra-params.yaml
@@ -0,0 +1,19 @@
+apiVersion: tekton.dev/v1beta1
+kind: Pipeline
+metadata:
+  name: pipeline-with-extra-params
+spec:
+  params:
+  - name: pl-param-x
+    type: string
+  - name: pl-param-y
+    type: string
+  tasks:
+  - name: add-params
+    taskRef:
+      name: add-params
+    params:
+    - name: a
+      value: "$(params.pl-param-x)"
+    - name: b
+      value: "$(params.pl-param-y)"
\ No newline at end of file
diff --git a/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pr-load-refs/source.yaml b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pr-load-refs/source.yaml
new file mode 100644
index 00000000..70f464e3
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pr-load-refs/source.yaml
@@ -0,0 +1,17 @@
+apiVersion: tekton.dev/v1beta1
+kind: PipelineRun
+metadata:
+  name: pipelinerun-with-extra-params
+  annotations:
+    lighthouse.jenkins-x.io/loadFileRefs: ".*"
+spec:
+  params:
+  - name: pl-param-x
+    value: "100"
+  - name: pl-param-y
+    value: "200"
+    # the extra parameter
+  - name: pl-param-z
+    value: "300"
+  pipelineRef:
+    name: pipeline-with-extra-params
\ No newline at end of file
diff --git a/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pr/expected.yaml b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pr/expected.yaml
new file mode 100644
index 00000000..34bf9aad
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pr/expected.yaml
@@ -0,0 +1,49 @@
+apiVersion: tekton.dev/v1beta1
+kind: PipelineRun
+metadata:
+  annotations:
+    lighthouse.jenkins-x.io/cloneURI: https://github.com/jenkins-x/jx.git
+  creationTimestamp: "2020-07-20T19:50:21Z"
+  generation: 1
+  labels:
+    branch: PR-7463
+    build: "17"
+    context: boot-vault
+    jenkins.io/pipelineType: build
+    lighthouse.jenkins-x.io/baseSHA: c47ce72d4e2991a9440e6d954ecbf79d596f9352
+    lighthouse.jenkins-x.io/branch: PR-7463
+    lighthouse.jenkins-x.io/buildNum: "17"
+    lighthouse.jenkins-x.io/context: boot-vault
+    lighthouse.jenkins-x.io/id: f46327af-b47e-11ea-b797-9256b7b8d9b0
+    lighthouse.jenkins-x.io/lastCommitSHA: 8a3c5f595cdc3162e46390c72a5d22fb9c89d1df
+    lighthouse.jenkins-x.io/refs.org: jenkins-x
+    lighthouse.jenkins-x.io/refs.repo: jx
+    owner: jenkins-x
+    repository: jx
+    tekton.dev/pipeline: jenkins-x-jx-pr-7463-boot-vault-9mbgb-17
+  name: jenkins-x-jx-pr-7463-boot-vault-9mbgb-17
+  namespace: jx
+  resourceVersion: "16726271"
+  selfLink: /apis/tekton.dev/v1beta1/namespaces/jx/pipelineruns/jenkins-x-jx-pr-7463-boot-vault-9mbgb-17
+  uid: 3edf18d1-cac2-11ea-a610-42010a8400cb
+spec:
+  params:
+  - name: version
+    value: 0.0.0-SNAPSHOT-PR-7463-17
+  - name: build_id
+    value: "17"
+  pipelineRef:
+    apiVersion: tekton.dev/v1alpha1
+    name: jenkins-x-jx-pr-7463-boot-vault-9mbgb-17
+  podTemplate:
+    ImagePullSecrets: null
+    hostNetwork: false
+    schedulerName: ""
+  resources:
+  - name: jenkins-x-jx-pr-7463-boot-vault-9mbgb
+    resourceRef:
+      apiVersion: tekton.dev/v1alpha1
+      name: jenkins-x-jx-pr-7463-boot-vault-9mbgb
+  serviceAccountName: tekton-bot
+  timeout: 240h0m0s
+status: {}
diff --git a/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pr/source.yaml b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pr/source.yaml
new file mode 100644
index 00000000..5993db46
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/pr/source.yaml
@@ -0,0 +1,46 @@
+apiVersion: tekton.dev/v1beta1
+kind: PipelineRun
+metadata:
+  annotations:
+    lighthouse.jenkins-x.io/cloneURI: https://github.com/jenkins-x/jx.git
+  creationTimestamp: "2020-07-20T19:50:21Z"
+  generation: 1
+  labels:
+    branch: PR-7463
+    build: "17"
+    context: boot-vault
+    jenkins.io/pipelineType: build
+    lighthouse.jenkins-x.io/baseSHA: c47ce72d4e2991a9440e6d954ecbf79d596f9352
+    lighthouse.jenkins-x.io/branch: PR-7463
+    lighthouse.jenkins-x.io/buildNum: "17"
+    lighthouse.jenkins-x.io/context: boot-vault
+    lighthouse.jenkins-x.io/id: f46327af-b47e-11ea-b797-9256b7b8d9b0
+    lighthouse.jenkins-x.io/lastCommitSHA: 8a3c5f595cdc3162e46390c72a5d22fb9c89d1df
+    lighthouse.jenkins-x.io/refs.org: jenkins-x
+    lighthouse.jenkins-x.io/refs.repo: jx
+    owner: jenkins-x
+    repository: jx
+    tekton.dev/pipeline: jenkins-x-jx-pr-7463-boot-vault-9mbgb-17
+  name: jenkins-x-jx-pr-7463-boot-vault-9mbgb-17
+  namespace: jx
+  resourceVersion: "16726271"
+  selfLink: /apis/tekton.dev/v1beta1/namespaces/jx/pipelineruns/jenkins-x-jx-pr-7463-boot-vault-9mbgb-17
+  uid: 3edf18d1-cac2-11ea-a610-42010a8400cb
+spec:
+  params:
+  - name: version
+    value: 0.0.0-SNAPSHOT-PR-7463-17
+  - name: build_id
+    value: "17"
+  pipelineRef:
+    apiVersion: tekton.dev/v1alpha1
+    name: jenkins-x-jx-pr-7463-boot-vault-9mbgb-17
+  podTemplate:
+    schedulerName: ""
+  resources:
+  - name: jenkins-x-jx-pr-7463-boot-vault-9mbgb
+    resourceRef:
+      apiVersion: tekton.dev/v1alpha1
+      name: jenkins-x-jx-pr-7463-boot-vault-9mbgb
+  serviceAccountName: tekton-bot
+  timeout: 240h0m0s
diff --git a/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/task/expected.yaml b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/task/expected.yaml
new file mode 100644
index 00000000..6db5fd72
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/task/expected.yaml
@@ -0,0 +1,308 @@
+apiVersion: tekton.dev/v1beta1
+kind: PipelineRun
+metadata:
+  creationTimestamp: null
+  name: cheese
+spec:
+  params:
+  - name: REPO_URL
+    value: $(params.REPO_URL)
+  - name: PULL_PULL_SHA
+    value: $(params.PULL_PULL_SHA)
+  - name: subdirectory
+    value: $(params.subdirectory)
+  - name: BUILD_ID
+    value: $(params.BUILD_ID)
+  - name: JOB_NAME
+    value: $(params.JOB_NAME)
+  - name: JOB_SPEC
+    value: $(params.JOB_SPEC)
+  - name: JOB_TYPE
+    value: $(params.JOB_TYPE)
+  - name: PULL_BASE_REF
+    value: $(params.PULL_BASE_REF)
+  - name: PULL_BASE_SHA
+    value: $(params.PULL_BASE_SHA)
+  - name: PULL_NUMBER
+    value: $(params.PULL_NUMBER)
+  - name: PULL_PULL_REF
+    value: $(params.PULL_PULL_REF)
+  - name: PULL_REFS
+    value: $(params.PULL_REFS)
+  - name: REPO_NAME
+    value: $(params.REPO_NAME)
+  - name: REPO_OWNER
+    value: $(params.REPO_OWNER)
+  pipelineSpec:
+    params:
+    - description: git url to clone
+      name: REPO_URL
+      type: string
+    - default: master
+      description: git revision to checkout (branch, tag, sha, ref…)
+      name: PULL_PULL_SHA
+      type: string
+    - default: source
+      description: subdirectory inside of /workspace to clone the git repo
+      name: subdirectory
+      type: string
+    - description: the unique build number
+      name: BUILD_ID
+      type: string
+    - description: the name of the job which is the trigger context name
+      name: JOB_NAME
+      type: string
+    - description: the specification of the job
+      name: JOB_SPEC
+      type: string
+    - description: 'the kind of job: postsubmit or presubmit'
+      name: JOB_TYPE
+      type: string
+    - default: master
+      description: the base git reference of the pull request
+      name: PULL_BASE_REF
+      type: string
+    - description: the git sha of the base of the pull request
+      name: PULL_BASE_SHA
+      type: string
+    - default: ""
+      description: git pull request number
+      name: PULL_NUMBER
+      type: string
+    - default: ""
+      description: git pull request ref in the form 'refs/pull/$PULL_NUMBER/head'
+      name: PULL_PULL_REF
+      type: string
+    - description: git pull reference strings of base and latest in the form 'master:$PULL_BASE_SHA,$PULL_NUMBER:$PULL_PULL_SHA:refs/pull/$PULL_NUMBER/head'
+      name: PULL_REFS
+      type: string
+    - description: git repository name
+      name: REPO_NAME
+      type: string
+    - description: git repository owner (user or organisation)
+      name: REPO_OWNER
+      type: string
+    tasks:
+    - name: cheese
+      params:
+      - name: REPO_URL
+        value: $(params.REPO_URL)
+      - name: PULL_PULL_SHA
+        value: $(params.PULL_PULL_SHA)
+      - name: subdirectory
+        value: $(params.subdirectory)
+      - name: BUILD_ID
+        value: $(params.BUILD_ID)
+      - name: JOB_NAME
+        value: $(params.JOB_NAME)
+      - name: JOB_SPEC
+        value: $(params.JOB_SPEC)
+      - name: JOB_TYPE
+        value: $(params.JOB_TYPE)
+      - name: PULL_BASE_REF
+        value: $(params.PULL_BASE_REF)
+      - name: PULL_BASE_SHA
+        value: $(params.PULL_BASE_SHA)
+      - name: PULL_NUMBER
+        value: $(params.PULL_NUMBER)
+      - name: PULL_PULL_REF
+        value: $(params.PULL_PULL_REF)
+      - name: PULL_REFS
+        value: $(params.PULL_REFS)
+      - name: REPO_NAME
+        value: $(params.REPO_NAME)
+      - name: REPO_OWNER
+        value: $(params.REPO_OWNER)
+      taskSpec:
+        params:
+        - description: git url to clone
+          name: REPO_URL
+          type: string
+        - default: master
+          description: git revision to checkout (branch, tag, sha, ref…)
+          name: PULL_PULL_SHA
+          type: string
+        - default: source
+          description: subdirectory inside of /workspace to clone the git repo
+          name: subdirectory
+          type: string
+        - description: the unique build number
+          name: BUILD_ID
+          type: string
+        - description: the name of the job which is the trigger context name
+          name: JOB_NAME
+          type: string
+        - description: the specification of the job
+          name: JOB_SPEC
+          type: string
+        - description: 'the kind of job: postsubmit or presubmit'
+          name: JOB_TYPE
+          type: string
+        - default: master
+          description: the base git reference of the pull request
+          name: PULL_BASE_REF
+          type: string
+        - description: the git sha of the base of the pull request
+          name: PULL_BASE_SHA
+          type: string
+        - default: ""
+          description: git pull request number
+          name: PULL_NUMBER
+          type: string
+        - default: ""
+          description: git pull request ref in the form 'refs/pull/$PULL_NUMBER/head'
+          name: PULL_PULL_REF
+          type: string
+        - description: git pull reference strings of base and latest in the form 'master:$PULL_BASE_SHA,$PULL_NUMBER:$PULL_PULL_SHA:refs/pull/$PULL_NUMBER/head'
+          name: PULL_REFS
+          type: string
+        - description: git repository name
+          name: REPO_NAME
+          type: string
+        - description: git repository owner (user or organisation)
+          name: REPO_OWNER
+          type: string
+        stepTemplate:
+          env:
+          - name: BUILD_ID
+            value: $(params.BUILD_ID)
+          - name: JOB_NAME
+            value: $(params.JOB_NAME)
+          - name: JOB_SPEC
+            value: $(params.JOB_SPEC)
+          - name: JOB_TYPE
+            value: $(params.JOB_TYPE)
+          - name: PULL_BASE_REF
+            value: $(params.PULL_BASE_REF)
+          - name: PULL_BASE_SHA
+            value: $(params.PULL_BASE_SHA)
+          - name: PULL_NUMBER
+            value: $(params.PULL_NUMBER)
+          - name: PULL_PULL_REF
+            value: $(params.PULL_PULL_REF)
+          - name: PULL_PULL_SHA
+            value: $(params.PULL_PULL_SHA)
+          - name: PULL_REFS
+            value: $(params.PULL_REFS)
+          - name: REPO_NAME
+            value: $(params.REPO_NAME)
+          - name: REPO_OWNER
+            value: $(params.REPO_OWNER)
+          - name: REPO_URL
+            value: $(params.REPO_URL)
+          name: ""
+          resources:
+            requests:
+              cpu: 400m
+              memory: 512Mi
+          volumeMounts:
+          - mountPath: /home/jenkins
+            name: workspace-volume
+          - mountPath: /etc/podinfo
+            name: podinfo
+            readOnly: true
+          workingDir: /workspace/source
+        steps:
+        - args:
+          - -c
+          - 'mkdir -p $HOME; git config --global --add user.name ${GIT_AUTHOR_NAME:-jenkins-x-bot}; git config --global --add user.email ${GIT_AUTHOR_EMAIL:-jenkins-x@googlegroups.com}; git config --global credential.helper store; git clone $(params.REPO_URL) $(params.subdirectory); echo cloned url: $(params.REPO_URL) to dir: $(params.subdirectory); cd $(params.subdirectory); git checkout $(params.PULL_PULL_SHA); echo checked out revision: $(params.PULL_PULL_SHA) to dir: $(params.subdirectory)'
+          command:
+          - /bin/sh
+          image: gcr.io/jenkinsxio/builder-jx:2.1.142-761
+          name: git-clone
+          resources: {}
+          workingDir: /workspace
+        - args:
+          - gitops
+          - git
+          - setup
+          - --namespace
+          - jx-git-operator
+          command:
+          - jx
+          image: gcr.io/jenkinsxio/jx-cli:latest
+          name: git-setup
+          resources: {}
+          workingDir: /workspace
+        - args:
+          - '[ -d /builder/home ] || mkdir -p /builder && ln -s /tekton/home /builder/home'
+          command:
+          - /bin/sh
+          - -c
+          image: gcr.io/jenkinsxio/builder-jx:2.1.142-761
+          name: setup-builder-home
+          resources: {}
+        - args:
+          - step
+          - git
+          - merge
+          - --verbose
+          - --baseSHA
+          - $(params.PULL_BASE_SHA)
+          - --sha
+          - $(params.PULL_PULL_SHA)
+          - --baseBranch
+          - $(params.PULL_BASE_REF)
+          command:
+          - jx
+          image: gcr.io/jenkinsxio/builder-jx:2.1.142-761
+          name: git-merge
+          resources: {}
+        - args:
+          - gitops
+          - variables
+          command:
+          - jx
+          image: gcr.io/jenkinsxio/jx-cli:latest
+          name: jx-variables
+          resources: {}
+        - args:
+          - jx step credential -s npm-token -k file -f /builder/home/.npmrc --optional=true
+          command:
+          - /bin/sh
+          - -c
+          image: gcr.io/jenkinsxio/builder-nodejs:2.1.150-769
+          name: build-npmrc
+          resources: {}
+        - args:
+          - npm install
+          command:
+          - /bin/sh
+          - -c
+          image: gcr.io/jenkinsxio/builder-nodejs:2.1.150-769
+          name: build-npm-install
+          resources: {}
+        - args:
+          - CI=true DISPLAY=:99 npm test
+          command:
+          - /bin/sh
+          - -c
+          image: gcr.io/jenkinsxio/builder-nodejs:2.1.150-769
+          name: build-npm-test
+          resources: {}
+        - args:
+          - source .jx/variables.sh && cp /tekton/creds-secrets/tekton-container-registry-auth/.dockerconfigjson /kaniko/.docker/config.json && /kaniko/executor $KANIKO_FLAGS --cache=true --cache-dir=/workspace --context=/workspace/source --dockerfile=/workspace/source/Dockerfile --destination=$DOCKER_REGISTRY/$DOCKER_REGISTRY_ORG/$APP_NAME:$VERSION --cache-repo=$DOCKER_REGISTRY/$DOCKER_REGISTRY_ORG/cache
+          command:
+          - /busybox/sh
+          - -c
+          image: gcr.io/jenkinsxio/kaniko:0.0.5
+          name: build-container-build
+          resources: {}
+        - args:
+          - source /workspace/source/.jx/variables.sh && jx preview create
+          command:
+          - /bin/bash
+          - -c
+          image: gcr.io/jenkinsxio/jx-cli:latest
+          name: promote-jx-preview
+          resources: {}
+        volumes:
+        - emptyDir: {}
+          name: workspace-volume
+        - downwardAPI:
+            items:
+            - fieldRef:
+                fieldPath: metadata.labels
+              path: labels
+          name: podinfo
+status: {}
diff --git a/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/task/source.yaml b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/task/source.yaml
new file mode 100644
index 00000000..27998430
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/task/source.yaml
@@ -0,0 +1,196 @@
+apiVersion: tekton.dev/v1beta1
+kind: Task
+metadata:
+  name: cheese
+spec:
+  params:
+  - description: git url to clone
+    name: REPO_URL
+    type: string
+  - default: master
+    description: git revision to checkout (branch, tag, sha, ref…)
+    name: PULL_PULL_SHA
+    type: string
+  - default: source
+    description: subdirectory inside of /workspace to clone the git repo
+    name: subdirectory
+    type: string
+  - description: the unique build number
+    name: BUILD_ID
+    type: string
+  - description: the name of the job which is the trigger context name
+    name: JOB_NAME
+    type: string
+  - description: the specification of the job
+    name: JOB_SPEC
+    type: string
+  - description: 'the kind of job: postsubmit or presubmit'
+    name: JOB_TYPE
+    type: string
+  - default: master
+    description: the base git reference of the pull request
+    name: PULL_BASE_REF
+    type: string
+  - description: the git sha of the base of the pull request
+    name: PULL_BASE_SHA
+    type: string
+  - default: ""
+    description: git pull request number
+    name: PULL_NUMBER
+    type: string
+  - default: ""
+    description: git pull request ref in the form 'refs/pull/$PULL_NUMBER/head'
+    name: PULL_PULL_REF
+    type: string
+  - description: git pull reference strings of base and latest in the form 'master:$PULL_BASE_SHA,$PULL_NUMBER:$PULL_PULL_SHA:refs/pull/$PULL_NUMBER/head'
+    name: PULL_REFS
+    type: string
+  - description: git repository name
+    name: REPO_NAME
+    type: string
+  - description: git repository owner (user or organisation)
+    name: REPO_OWNER
+    type: string
+  stepTemplate:
+    env:
+    - name: BUILD_ID
+      value: $(params.BUILD_ID)
+    - name: JOB_NAME
+      value: $(params.JOB_NAME)
+    - name: JOB_SPEC
+      value: $(params.JOB_SPEC)
+    - name: JOB_TYPE
+      value: $(params.JOB_TYPE)
+    - name: PULL_BASE_REF
+      value: $(params.PULL_BASE_REF)
+    - name: PULL_BASE_SHA
+      value: $(params.PULL_BASE_SHA)
+    - name: PULL_NUMBER
+      value: $(params.PULL_NUMBER)
+    - name: PULL_PULL_REF
+      value: $(params.PULL_PULL_REF)
+    - name: PULL_PULL_SHA
+      value: $(params.PULL_PULL_SHA)
+    - name: PULL_REFS
+      value: $(params.PULL_REFS)
+    - name: REPO_NAME
+      value: $(params.REPO_NAME)
+    - name: REPO_OWNER
+      value: $(params.REPO_OWNER)
+    - name: REPO_URL
+      value: $(params.REPO_URL)
+    name: ""
+    resources:
+      requests:
+        cpu: 400m
+        memory: 512Mi
+    volumeMounts:
+    - mountPath: /home/jenkins
+      name: workspace-volume
+    - mountPath: /etc/podinfo
+      name: podinfo
+      readOnly: true
+    workingDir: /workspace/source
+  steps:
+  - args:
+    - -c
+    - 'mkdir -p $HOME; git config --global --add user.name ${GIT_AUTHOR_NAME:-jenkins-x-bot}; git config --global --add user.email ${GIT_AUTHOR_EMAIL:-jenkins-x@googlegroups.com}; git config --global credential.helper store; git clone $(params.REPO_URL) $(params.subdirectory); echo cloned url: $(params.REPO_URL) to dir: $(params.subdirectory); cd $(params.subdirectory); git checkout $(params.PULL_PULL_SHA); echo checked out revision: $(params.PULL_PULL_SHA) to dir: $(params.subdirectory)'
+    command:
+    - /bin/sh
+    image: gcr.io/jenkinsxio/builder-jx:2.1.142-761
+    name: git-clone
+    resources: {}
+    workingDir: /workspace
+  - args:
+    - gitops
+    - git
+    - setup
+    - --namespace
+    - jx-git-operator
+    command:
+    - jx
+    image: gcr.io/jenkinsxio/jx-cli:latest
+    name: git-setup
+    resources: {}
+    workingDir: /workspace
+  - args:
+    - '[ -d /builder/home ] || mkdir -p /builder && ln -s /tekton/home /builder/home'
+    command:
+    - /bin/sh
+    - -c
+    image: gcr.io/jenkinsxio/builder-jx:2.1.142-761
+    name: setup-builder-home
+    resources: {}
+  - args:
+    - step
+    - git
+    - merge
+    - --verbose
+    - --baseSHA
+    - $(params.PULL_BASE_SHA)
+    - --sha
+    - $(params.PULL_PULL_SHA)
+    - --baseBranch
+    - $(params.PULL_BASE_REF)
+    command:
+    - jx
+    image: gcr.io/jenkinsxio/builder-jx:2.1.142-761
+    name: git-merge
+    resources: {}
+  - args:
+    - gitops
+    - variables
+    command:
+    - jx
+    image: gcr.io/jenkinsxio/jx-cli:latest
+    name: jx-variables
+    resources: {}
+  - args:
+    - jx step credential -s npm-token -k file -f /builder/home/.npmrc --optional=true
+    command:
+    - /bin/sh
+    - -c
+    image: gcr.io/jenkinsxio/builder-nodejs:2.1.150-769
+    name: build-npmrc
+    resources: {}
+  - args:
+    - npm install
+    command:
+    - /bin/sh
+    - -c
+    image: gcr.io/jenkinsxio/builder-nodejs:2.1.150-769
+    name: build-npm-install
+    resources: {}
+  - args:
+    - CI=true DISPLAY=:99 npm test
+    command:
+    - /bin/sh
+    - -c
+    image: gcr.io/jenkinsxio/builder-nodejs:2.1.150-769
+    name: build-npm-test
+    resources: {}
+  - args:
+    - source .jx/variables.sh && cp /tekton/creds-secrets/tekton-container-registry-auth/.dockerconfigjson /kaniko/.docker/config.json && /kaniko/executor $KANIKO_FLAGS --cache=true --cache-dir=/workspace --context=/workspace/source --dockerfile=/workspace/source/Dockerfile --destination=$DOCKER_REGISTRY/$DOCKER_REGISTRY_ORG/$APP_NAME:$VERSION --cache-repo=$DOCKER_REGISTRY/$DOCKER_REGISTRY_ORG/cache
+    command:
+    - /busybox/sh
+    - -c
+    image: gcr.io/jenkinsxio/kaniko:0.0.5
+    name: build-container-build
+    resources: {}
+  - args:
+    - source /workspace/source/.jx/variables.sh && jx preview create
+    command:
+    - /bin/bash
+    - -c
+    image: gcr.io/jenkinsxio/jx-cli:latest
+    name: promote-jx-preview
+    resources: {}
+  volumes:
+  - emptyDir: {}
+    name: workspace-volume
+  - downwardAPI:
+      items:
+      - fieldRef:
+          fieldPath: metadata.labels
+        path: labels
+    name: podinfo
diff --git a/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/taskrun/expected.yaml b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/taskrun/expected.yaml
new file mode 100644
index 00000000..d4543e2f
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/taskrun/expected.yaml
@@ -0,0 +1,102 @@
+apiVersion: tekton.dev/v1beta1
+kind: PipelineRun
+metadata:
+  creationTimestamp: null
+spec:
+  params:
+  - name: PARAM
+    value: $(params.PARAM)
+  pipelineSpec:
+    params:
+    - default: param-value
+      name: PARAM
+    tasks:
+    - params:
+      - name: PARAM
+        value: $(params.PARAM)
+      taskSpec:
+        params:
+        - default: param-value
+          name: PARAM
+        steps:
+        - image: ubuntu
+          name: noshebang
+          resources: {}
+          script: echo "no shebang"
+        - env:
+          - name: FOO
+            value: foooooooo
+          image: ubuntu
+          name: bash
+          resources: {}
+          script: |
+            #!/usr/bin/env bash
+            set -euxo pipefail
+            echo "Hello from Bash!"
+            echo FOO is ${FOO}
+            echo substring is ${FOO:2:4}
+            for i in {1..10}; do
+              echo line $i
+            done
+        - image: ubuntu
+          name: place-file
+          resources: {}
+          script: |
+            #!/usr/bin/env bash
+            echo "echo Hello from script file" > /workspace/hello
+            chmod +x /workspace/hello
+        - image: ubuntu
+          name: run-file
+          resources: {}
+          script: |
+            #!/usr/bin/env bash
+            /workspace/hello
+        - image: ubuntu
+          name: contains-eof
+          resources: {}
+          script: |
+            #!/usr/bin/env bash
+            cat > file << EOF
+            this file has some contents
+            EOF
+            cat file
+        - image: node
+          name: node
+          resources: {}
+          script: |
+            #!/usr/bin/env node
+            console.log("Hello from Node!")
+        - image: python
+          name: python
+          resources: {}
+          script: |
+            #!/usr/bin/env python3
+            print("Hello from Python!")
+        - image: perl
+          name: perl
+          resources: {}
+          script: |
+            #!/usr/bin/perl
+            print "Hello from Perl!"
+        - image: python
+          name: params-applied
+          resources: {}
+          script: |
+            #!/usr/bin/env python3
+            v = '$(params.PARAM)'
+            if v != 'param-value':
+              print('Param values not applied')
+              print('Got: ', v)
+              exit(1)
+        - args:
+          - hello
+          - world
+          image: ubuntu
+          name: args-allowed
+          resources: {}
+          script: |-
+            #!/usr/bin/env bash
+            [[ $# == 2 ]]
+            [[ $1 == "hello" ]]
+            [[ $2 == "world" ]]
+status: {}
diff --git a/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/taskrun/source.yaml b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/taskrun/source.yaml
new file mode 100644
index 00000000..6888d003
--- /dev/null
+++ b/pkg/triggerconfig/inrepo/test_data/load_pipelinerun/taskrun/source.yaml
@@ -0,0 +1,81 @@
+apiVersion: tekton.dev/v1beta1
+kind: TaskRun
+metadata:
+  generateName: step-script-
+spec:
+  taskSpec:
+    params:
+    - name: PARAM
+      default: param-value
+
+    steps:
+    - name: noshebang
+      image: ubuntu
+      script: echo "no shebang"
+    - name: bash
+      image: ubuntu
+      env:
+      - name: FOO
+        value: foooooooo
+      script: |
+        #!/usr/bin/env bash
+        set -euxo pipefail
+        echo "Hello from Bash!"
+        echo FOO is ${FOO}
+        echo substring is ${FOO:2:4}
+        for i in {1..10}; do
+          echo line $i
+        done
+    - name: place-file
+      image: ubuntu
+      script: |
+        #!/usr/bin/env bash
+        echo "echo Hello from script file" > /workspace/hello
+        chmod +x /workspace/hello
+    - name: run-file
+      image: ubuntu
+      script: |
+        #!/usr/bin/env bash
+        /workspace/hello
+    - name: contains-eof
+      image: ubuntu
+      script: |
+        #!/usr/bin/env bash
+        cat > file << EOF
+        this file has some contents
+        EOF
+        cat file
+    - name: node
+      image: node
+      script: |
+        #!/usr/bin/env node
+        console.log("Hello from Node!")
+    - name: python
+      image: python
+      script: |
+        #!/usr/bin/env python3
+        print("Hello from Python!")
+    - name: perl
+      image: perl
+      script: |
+        #!/usr/bin/perl
+        print "Hello from Perl!"
+    # Test that param values are replaced.
+    - name: params-applied
+      image: python
+      script: |
+        #!/usr/bin/env python3
+        v = '$(params.PARAM)'
+        if v != 'param-value':
+          print('Param values not applied')
+          print('Got: ', v)
+          exit(1)
+    # Test that args are allowed and passed to the script as expected.
+    - name: args-allowed
+      image: ubuntu
+      args: ['hello', 'world']
+      script: |
+        #!/usr/bin/env bash
+        [[ $# == 2 ]]
+        [[ $1 == "hello" ]]
+        [[ $2 == "world" ]]
\ No newline at end of file