Repository: tektoncd/operator
Pull request #1162 (2022-11-16 13:23:13)

Refactors Tekton Dashboard reconciler to use tektoninstallerset client
Signed-off-by: Puneet Punamiya ppunamiy@redhat.com

# Changes

<!-- 🎉🎉🎉 Thank you for the PR!!! 🎉🎉🎉 -->

<!-- Describe your changes here- ideally you can get that description straight from
your descriptive commit message(s)! -->

# Submitter Checklist

These are the criteria that every PR should meet, please check them off as you
review them:

- [ ] Run `make test lint` before submitting a PR
- [ ] Includes [tests](https://github.com/tektoncd/community/blob/master/standards.md#principles) (if functionality changed/added)
- [ ] Includes [docs](https://github.com/tektoncd/community/blob/master/standards.md#principles) (if user facing)
- [ ] Commit messages follow [commit message best practices](https://github.com/tektoncd/community/blob/master/standards.md#commit-messages)

_See [the contribution guide](https://github.com/tektoncd/operator/blob/master/CONTRIBUTING.md) for more details._

# Release Notes

<!--
Describe any user facing changes here, or delete this block.

Examples of user facing changes:
- API changes
- Bug fixes
- Any changes in behavior
- Changes requiring upgrade notices or deprecation warnings

For pull requests with a release note:

```release-note
Your release note here
```

For pull requests that require additional action from users switching to the new release, include the string "action required" (case insensitive) in the release note:

```release-note
action required: your release note here
```

For pull requests that don't need to be mentioned at release time, use the `/release-note-none` Prow command to add the `release-note-none` label to the PR. You can also write the string "NONE" as a release note in your PR description:

```release-note
NONE
```
-->


tekton-robot: @PuneetPunamiya: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-tekton-operator-unit-tests | 13d468bfc5947d896d2e0307713e4b06717ebb99 | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1162/pull-tekton-operator-unit-tests/1592870916516220928) | true | `/test pull-tekton-operator-unit-tests`

[Full PR test history](https://prow.tekton.dev/pr-history?org=tektoncd&repo=operator&pr=1162). [Your PR dashboard](https://prow.tekton.dev/pr?query=is%3Apr%20state%3Aopen%20author%3APuneetPunamiya).

<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 [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
tekton-robot: The following is the coverage report on the affected files.
Say `/test pull-tekton-operator-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/reconciler/kubernetes/tektonconfig/extension/dashboard.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1162/pull-tekton-operator-go-coverage/1592870916591718400/artifacts/line-cov.html#file0) | 72.7% | 54.7% | -18.0

tekton-robot: @PuneetPunamiya: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-tekton-operator-unit-tests | 13d468bfc5947d896d2e0307713e4b06717ebb99 | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1162/pull-tekton-operator-unit-tests/1592870916516220928) | true | `/test pull-tekton-operator-unit-tests`
pull-tekton-operator-build-tests | 13d468bfc5947d896d2e0307713e4b06717ebb99 | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1162/pull-tekton-operator-build-tests/1592870916478472192) | true | `/test pull-tekton-operator-build-tests`

[Full PR test history](https://prow.tekton.dev/pr-history?org=tektoncd&repo=operator&pr=1162). [Your PR dashboard](https://prow.tekton.dev/pr?query=is%3Apr%20state%3Aopen%20author%3APuneetPunamiya).

<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 [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
tekton-robot: The following is the coverage report on the affected files.
Say `/test pull-tekton-operator-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/reconciler/kubernetes/tektonconfig/extension/dashboard.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1162/pull-tekton-operator-go-coverage/1592877998065848320/artifacts/line-cov.html#file0) | 72.7% | 69.8% | -2.9

tekton-robot: @PuneetPunamiya: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-tekton-operator-build-tests | 5bd1f881186b8f4aefff428a428c781003d19850 | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1162/pull-tekton-operator-build-tests/1592877997931630592) | true | `/test pull-tekton-operator-build-tests`

[Full PR test history](https://prow.tekton.dev/pr-history?org=tektoncd&repo=operator&pr=1162). [Your PR dashboard](https://prow.tekton.dev/pr?query=is%3Apr%20state%3Aopen%20author%3APuneetPunamiya).

<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 [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
tekton-robot: The following is the coverage report on the affected files.
Say `/test pull-tekton-operator-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/reconciler/kubernetes/tektonconfig/extension/dashboard.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1162/pull-tekton-operator-go-coverage/1592883231013736448/artifacts/line-cov.html#file0) | 72.7% | 69.8% | -2.9

tekton-robot: [APPROVALNOTIFIER] This PR is **APPROVED**

This pull-request has been approved by: *<a href="https://github.com/tektoncd/operator/pull/1162#pullrequestreview-1182689822" title="Approved">vdemeester</a>*

The full list of commands accepted by this bot can be found [here](https://prow.tekton.dev/command-help?repo=tektoncd%2Foperator).

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/tektoncd/operator/blob/main/OWNERS)~~ [vdemeester]

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":[]} -->
tekton-robot: @PuneetPunamiya: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-tekton-operator-build-tests | 5bd1f881186b8f4aefff428a428c781003d19850 | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1162/pull-tekton-operator-build-tests/1592883230816604160) | true | `/test pull-tekton-operator-build-tests`

[Full PR test history](https://prow.tekton.dev/pr-history?org=tektoncd&repo=operator&pr=1162). [Your PR dashboard](https://prow.tekton.dev/pr?query=is%3Apr%20state%3Aopen%20author%3APuneetPunamiya).

<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 [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
tekton-robot: @PuneetPunamiya: The following tests **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-tekton-operator-build-tests | 5bd1f881186b8f4aefff428a428c781003d19850 | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1162/pull-tekton-operator-build-tests/1592883230816604160) | true | `/test pull-tekton-operator-build-tests`
pull-tekton-operator-integration-tests | 5bd1f881186b8f4aefff428a428c781003d19850 | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1162/pull-tekton-operator-integration-tests/1592883231047290880) | true | `/test pull-tekton-operator-integration-tests`

[Full PR test history](https://prow.tekton.dev/pr-history?org=tektoncd&repo=operator&pr=1162). [Your PR dashboard](https://prow.tekton.dev/pr?query=is%3Apr%20state%3Aopen%20author%3APuneetPunamiya).

<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 [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
tekton-robot: The following is the coverage report on the affected files.
Say `/test pull-tekton-operator-go-coverage` to re-run this coverage report

File | Old Coverage | New Coverage | Delta
---- |:------------:|:------------:|:-----:
[pkg/reconciler/kubernetes/tektonconfig/extension/dashboard.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1162/pull-tekton-operator-go-coverage/1592928384046862336/artifacts/line-cov.html#file0) | 72.7% | 69.8% | -2.9

tekton-robot: @PuneetPunamiya: The following test **failed**, say `/retest` to rerun all failed tests or `/retest-required` to rerun all mandatory failed tests:

Test name | Commit | Details | Required | Rerun command
--- | --- | --- | --- | ---
pull-tekton-operator-integration-tests | df64ba9ab82e1fb30bd13cdf00c94c5cc26066f3 | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1162/pull-tekton-operator-integration-tests/1592928383950393344) | true | `/test pull-tekton-operator-integration-tests`

[Full PR test history](https://prow.tekton.dev/pr-history?org=tektoncd&repo=operator&pr=1162). [Your PR dashboard](https://prow.tekton.dev/pr?query=is%3Apr%20state%3Aopen%20author%3APuneetPunamiya).

<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 [kubernetes/test-infra](https://github.com/kubernetes/test-infra/issues/new?title=Prow%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->

Patch:
diff --git a/components.yaml b/components.yaml
index bf03ae83d..ee4653961 100644
--- a/components.yaml
+++ b/components.yaml
@@ -6,7 +6,7 @@ dashboard:
   version: v0.30.0
 hub:
   github: tektoncd/hub
-  version: v1.10.0
+  version: v1.11.0
 pipeline:
   github: tektoncd/pipeline
   version: v0.41.0
@@ -18,4 +18,4 @@ results:
   version: v0.4.0
 triggers:
   github: tektoncd/triggers
-  version: v0.21.0
+  version: v0.22.0
diff --git a/go.mod b/go.mod
index 99bbf8f14..88e54ccb8 100644
--- a/go.mod
+++ b/go.mod
@@ -20,11 +20,11 @@ require (
 	github.com/sigstore/cosign v1.13.1
 	github.com/tektoncd/pipeline v0.41.0
 	github.com/tektoncd/plumbing v0.0.0-20221102182345-5dbcfda657d7
-	github.com/tektoncd/triggers v0.21.0
+	github.com/tektoncd/triggers v0.22.0
 	github.com/titanous/rocacheck v0.0.0-20171023193734-afe73141d399
 	go.opencensus.io v0.24.0
 	go.uber.org/zap v1.23.0
-	golang.org/x/crypto v0.2.0
+	golang.org/x/crypto v0.3.0
 	golang.org/x/mod v0.7.0
 	gomodules.xyz/jsonpatch/v2 v2.2.0
 	google.golang.org/grpc v1.50.1
@@ -295,7 +295,7 @@ require (
 	gopkg.in/ini.v1 v1.67.0 // indirect
 	gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
-	k8s.io/apiextensions-apiserver v0.25.2 // indirect
+	k8s.io/apiextensions-apiserver v0.25.3 // indirect
 	k8s.io/gengo v0.0.0-20220613173612-397b4ae3bce7 // indirect
 	k8s.io/klog/v2 v2.80.1 // indirect
 	k8s.io/kube-openapi v0.0.0-20220803162953-67bda5d908f1 // indirect
diff --git a/go.sum b/go.sum
index 236b37a7d..136eac626 100644
--- a/go.sum
+++ b/go.sum
@@ -1710,8 +1710,8 @@ github.com/tektoncd/pipeline v0.41.0 h1:FksQuX83ZRasZygQPNmaR6hKBh6gy822XxRuoKBq
 github.com/tektoncd/pipeline v0.41.0/go.mod h1:YY4+PGfdsd6Qxn3PZXmCpKeS3heK8pIIcnUt37vRJ2Q=
 github.com/tektoncd/plumbing v0.0.0-20221102182345-5dbcfda657d7 h1:YsjQ83UBIIq4k/s2PzQ6pqe4tpPtm1hia3oyNBDDrDU=
 github.com/tektoncd/plumbing v0.0.0-20221102182345-5dbcfda657d7/go.mod h1:uJBaI0AL/kjPThiMYZcWRujEz7D401v643d6s/21GAg=
-github.com/tektoncd/triggers v0.21.0 h1:9k/sRHLZQC8AxDYAgcEE+atUoRIaWrehbro3EVXC9es=
-github.com/tektoncd/triggers v0.21.0/go.mod h1:80lSjy3A11KiZ9FhzD7qWX6ev5M+cEwTdKfryUXueyE=
+github.com/tektoncd/triggers v0.22.0 h1:xe9l+ebuUMuP4wzBLjvmUGUPZCz0qND4osFFLSVCAW0=
+github.com/tektoncd/triggers v0.22.0/go.mod h1:lYxFl8cKbr+DaHMQa47U4Y7uyhTAMsRAT0uOOY8xiGE=
 github.com/tent/canonical-json-go v0.0.0-20130607151641-96e4ba3a7613 h1:iGnD/q9160NWqKZZ5vY4p0dMiYMRknzctfSkqA4nBDw=
 github.com/tent/canonical-json-go v0.0.0-20130607151641-96e4ba3a7613/go.mod h1:g6AnIpDSYMcphz193otpSIzN+11Rs+AAIIC6rm1enug=
 github.com/thales-e-security/pool v0.0.2 h1:RAPs4q2EbWsTit6tpzuvTFlgFRJ3S8Evf5gtvVDbmPg=
@@ -1978,8 +1978,8 @@ golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0
 golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.2.0 h1:BRXPfhNivWL5Yq0BGQ39a2sW6t44aODpfxkWjYdzewE=
-golang.org/x/crypto v0.2.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
+golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A=
+golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -2738,8 +2738,8 @@ k8s.io/api v0.22.5/go.mod h1:mEhXyLaSD1qTOf40rRiKXkc+2iCem09rWLlFwhCEiAs=
 k8s.io/api v0.25.4 h1:3YO8J4RtmG7elEgaWMb4HgmpS2CfY1QlaOz9nwB+ZSs=
 k8s.io/api v0.25.4/go.mod h1:IG2+RzyPQLllQxnhzD8KQNEu4c4YvyDTpSMztf4A0OQ=
 k8s.io/apiextensions-apiserver v0.19.2/go.mod h1:EYNjpqIAvNZe+svXVx9j4uBaVhTB4C94HkY3w058qcg=
-k8s.io/apiextensions-apiserver v0.25.2 h1:8uOQX17RE7XL02ngtnh3TgifY7EhekpK+/piwzQNnBo=
-k8s.io/apiextensions-apiserver v0.25.2/go.mod h1:iRwwRDlWPfaHhuBfQ0WMa5skdQfrE18QXJaJvIDLvE8=
+k8s.io/apiextensions-apiserver v0.25.3 h1:bfI4KS31w2f9WM1KLGwnwuVlW3RSRPuIsfNF/3HzR0k=
+k8s.io/apiextensions-apiserver v0.25.3/go.mod h1:ZJqwpCkxIx9itilmZek7JgfUAM0dnTsA48I4krPqRmo=
 k8s.io/apimachinery v0.15.7/go.mod h1:Xc10RHc1U+F/e9GCloJ8QAeCGevSVP5xhOhqlE+e1kM=
 k8s.io/apimachinery v0.19.2/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA=
 k8s.io/apimachinery v0.19.7/go.mod h1:6sRbGRAVY5DOCuZwB5XkqguBqpqLU6q/kOaOdk29z6Q=
diff --git a/operatorhub/openshift/config.yaml b/operatorhub/openshift/config.yaml
index 9e65a9af2..9b2dd7061 100644
--- a/operatorhub/openshift/config.yaml
+++ b/operatorhub/openshift/config.yaml
@@ -32,6 +32,14 @@ image-substitutions:
       containerName: openshift-pipelines-operator-lifecycle
       envKeys:
       - IMAGE_PIPELINES_WEBHOOK
+- image: registry.redhat.io/openshift-pipelines/pipelines-resolvers-rhel8@
+  replaceLocations:
+    envTargets:
+    - deploymentName: openshift-pipelines-operator
+      containerName: openshift-pipelines-operator-lifecycle
+      envKeys:
+      # the container name for resolvers controller is "controller" :)
+      - IMAGE_PIPELINES_CONTROLLER
 - image: registry.redhat.io/openshift-pipelines/pipelines-entrypoint-rhel8@
   replaceLocations:
     envTargets:
diff --git a/pkg/reconciler/openshift/openshiftpipelinesascode/metrics.go b/pkg/reconciler/common/nometrics.go
similarity index 90%
rename from pkg/reconciler/openshift/openshiftpipelinesascode/metrics.go
rename to pkg/reconciler/common/nometrics.go
index 9a7eb34fe..75570a3da 100644
--- a/pkg/reconciler/openshift/openshiftpipelinesascode/metrics.go
+++ b/pkg/reconciler/common/nometrics.go
@@ -1,12 +1,9 @@
 /*
 Copyright 2022 The Tekton Authors
-
 Licensed under the Apache License, Version 2.0 (the "License");
 you may not use this file except in compliance with the License.
 You may obtain a copy of the License at
-
     http://www.apache.org/licenses/LICENSE-2.0
-
 Unless required by applicable law or agreed to in writing, software
 distributed under the License is distributed on an "AS IS" BASIS,
 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -14,14 +11,14 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-package openshiftpipelinesascode
+package common
 
 import "go.uber.org/zap"
 
 type Recorder struct {
 }
 
-func NewRecorder() (*Recorder, error) {
+func NoMetrics() (*Recorder, error) {
 	return &Recorder{}, nil
 }
 
diff --git a/pkg/reconciler/kubernetes/tektonconfig/extension/dashboard.go b/pkg/reconciler/kubernetes/tektonconfig/extension/dashboard.go
index d384b85e8..be4c9d1ed 100644
--- a/pkg/reconciler/kubernetes/tektonconfig/extension/dashboard.go
+++ b/pkg/reconciler/kubernetes/tektonconfig/extension/dashboard.go
@@ -19,11 +19,12 @@ package extension
 import (
 	"context"
 	"fmt"
+	"knative.dev/pkg/apis"
 	"reflect"
+	"strings"
 
 	"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
 	op "github.com/tektoncd/operator/pkg/client/clientset/versioned/typed/operator/v1alpha1"
-	"github.com/tektoncd/operator/pkg/reconciler/common"
 	apierrs "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
@@ -118,12 +119,10 @@ func updateDashboard(ctx context.Context, tdCR *v1alpha1.TektonDashboard, config
 
 // isTektonDashboardReady will check the status conditions of the TektonDashboard and return true if the TektonDashboard is ready.
 func isTektonDashboardReady(s *v1alpha1.TektonDashboard, err error) (bool, error) {
-	upgradePending, errInternal := common.CheckUpgradePending(s)
-	if err != nil {
-		return false, errInternal
-	}
-	if upgradePending {
-		return false, v1alpha1.DEPENDENCY_UPGRADE_PENDING_ERR
+	if s.GetStatus() != nil && s.GetStatus().GetCondition(apis.ConditionReady) != nil {
+		if strings.Contains(s.GetStatus().GetCondition(apis.ConditionReady).Message, v1alpha1.UpgradePending) {
+			return false, v1alpha1.DEPENDENCY_UPGRADE_PENDING_ERR
+		}
 	}
 	return s.Status.IsReady(), err
 }
diff --git a/pkg/reconciler/kubernetes/tektondashboard/controller.go b/pkg/reconciler/kubernetes/tektondashboard/controller.go
index c7a09703b..4c909546f 100644
--- a/pkg/reconciler/kubernetes/tektondashboard/controller.go
+++ b/pkg/reconciler/kubernetes/tektondashboard/controller.go
@@ -19,6 +19,8 @@ package tektondashboard
 import (
 	"context"
 
+	"github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektoninstallerset/client"
+
 	"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
 	operatorclient "github.com/tektoncd/operator/pkg/client/injection/client"
 	tektonDashboardinformer "github.com/tektoncd/operator/pkg/client/injection/informers/operator/v1alpha1/tektondashboard"
@@ -27,7 +29,6 @@ import (
 	tektonDashboardreconciler "github.com/tektoncd/operator/pkg/client/injection/reconciler/operator/v1alpha1/tektondashboard"
 	"github.com/tektoncd/operator/pkg/reconciler/common"
 	"k8s.io/client-go/tools/cache"
-	kubeclient "knative.dev/pkg/client/injection/kube/client"
 	"knative.dev/pkg/configmap"
 	"knative.dev/pkg/controller"
 	"knative.dev/pkg/injection"
@@ -47,7 +48,7 @@ func NewExtendedController(generator common.ExtensionGenerator) injection.Contro
 	return func(ctx context.Context, cmw configmap.Watcher) *controller.Impl {
 		tektonPipelineInformer := tektonPipelineinformer.Get(ctx)
 		tektonDashboardInformer := tektonDashboardinformer.Get(ctx)
-		kubeClient := kubeclient.Get(ctx)
+
 		logger := logging.FromContext(ctx)
 
 		ctrl := common.Controller{
@@ -64,13 +65,19 @@ func NewExtendedController(generator common.ExtensionGenerator) injection.Contro
 			logger.Fatal(err)
 		}
 
+		metrics, err := common.NoMetrics()
+		if err != nil {
+			logger.Errorf("Failed to create dashboard metrics recorder %v", err)
+		}
+
+		tisClient := operatorclient.Get(ctx).OperatorV1alpha1().TektonInstallerSets()
 		c := &Reconciler{
-			kubeClientSet:      kubeClient,
+			pipelineInformer:   tektonPipelineInformer,
+			installerSetClient: client.NewInstallerSetClient(tisClient, operatorVer, dashboardVer, v1alpha1.KindTektonDashboard, metrics),
 			operatorClientSet:  operatorclient.Get(ctx),
 			extension:          generator(ctx),
 			readonlyManifest:   readonlyManifest,
 			fullaccessManifest: fullaccessManifest,
-			pipelineInformer:   tektonPipelineInformer,
 			dashboardVersion:   dashboardVer,
 			operatorVersion:    operatorVer,
 		}
diff --git a/pkg/reconciler/kubernetes/tektondashboard/finalize.go b/pkg/reconciler/kubernetes/tektondashboard/finalize.go
new file mode 100644
index 000000000..f385a7610
--- /dev/null
+++ b/pkg/reconciler/kubernetes/tektondashboard/finalize.go
@@ -0,0 +1,55 @@
+/*
+Copyright 2020 The Tekton Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package tektondashboard
+
+import (
+	"context"
+	mf "github.com/manifestival/manifestival"
+	"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
+	"knative.dev/pkg/logging"
+	pkgreconciler "knative.dev/pkg/reconciler"
+)
+
+// FinalizeKind removes all resources after deletion of a TektonDashboards.
+func (r *Reconciler) FinalizeKind(ctx context.Context, original *v1alpha1.TektonDashboard) pkgreconciler.Event {
+	logger := logging.FromContext(ctx)
+
+	// Delete CRDs before deleting rest of resources so that any instance
+	// of CRDs which has finalizer set will get deleted before we remove
+	// the controller;s deployment for it
+
+	var manifest mf.Manifest
+	if original.Spec.Readonly {
+		manifest = r.readonlyManifest
+	} else {
+		manifest = r.fullaccessManifest
+	}
+
+	if err := manifest.Filter(mf.CRDs).Delete(); err != nil {
+		logger.Error("Failed to deleted CRDs for TektonDashboard")
+		return err
+	}
+
+	if err := r.installerSetClient.CleanupMainSet(ctx); err != nil {
+		logger.Error("failed to cleanup main installerset: ", err)
+	}
+
+	if err := r.extension.Finalize(ctx, original); err != nil {
+		logger.Error("Failed to finalize platform resources", err)
+	}
+	return nil
+}
diff --git a/pkg/reconciler/kubernetes/tektondashboard/reconcile.go b/pkg/reconciler/kubernetes/tektondashboard/reconcile.go
new file mode 100644
index 000000000..aed013c06
--- /dev/null
+++ b/pkg/reconciler/kubernetes/tektondashboard/reconcile.go
@@ -0,0 +1,128 @@
+/*
+Copyright 2020 The Tekton Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package tektondashboard
+
+import (
+	"context"
+	"fmt"
+
+	"github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektoninstallerset/client"
+
+	mf "github.com/manifestival/manifestival"
+	"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
+	clientset "github.com/tektoncd/operator/pkg/client/clientset/versioned"
+	pipelineinformer "github.com/tektoncd/operator/pkg/client/informers/externalversions/operator/v1alpha1"
+	tektondashboardreconciler "github.com/tektoncd/operator/pkg/client/injection/reconciler/operator/v1alpha1/tektondashboard"
+	"github.com/tektoncd/operator/pkg/reconciler/common"
+	"knative.dev/pkg/logging"
+	pkgreconciler "knative.dev/pkg/reconciler"
+)
+
+// Reconciler implements controller.Reconciler for TektonDashboard resources.
+type Reconciler struct {
+	// installer Set client to do CRUD operations for components
+	installerSetClient *client.InstallerSetClient
+	// operatorClientSet allows us to configure operator objects
+	operatorClientSet clientset.Interface
+	// readOnlyManifest has the source manifest of Tekton Dashboard for
+	// a particular version with readonly value as true
+	readonlyManifest mf.Manifest
+	// fullaccessManifest has the source manifest of Tekton Dashboard for
+	// a particular version with readonly value as false
+	fullaccessManifest mf.Manifest
+	// Platform-specific behavior to affect the transform
+	extension        common.Extension
+	pipelineInformer pipelineinformer.TektonPipelineInformer
+	operatorVersion  string
+	dashboardVersion string
+}
+
+// Check that our Reconciler implements controller.Reconciler
+var _ tektondashboardreconciler.Interface = (*Reconciler)(nil)
+var _ tektondashboardreconciler.Finalizer = (*Reconciler)(nil)
+
+// ReconcileKind compares the actual state with the desired, and attempts to
+// converge the two.
+func (r *Reconciler) ReconcileKind(ctx context.Context, td *v1alpha1.TektonDashboard) pkgreconciler.Event {
+	logger := logging.FromContext(ctx)
+	td.Status.InitializeConditions()
+	td.Status.ObservedGeneration = td.Generation
+	td.Status.SetVersion(r.dashboardVersion)
+
+	logger.Infow("Reconciling TektonDashboards", "status", td.Status)
+
+	if td.GetName() != v1alpha1.DashboardResourceName {
+		msg := fmt.Sprintf("Resource ignored, Expected Name: %s, Got Name: %s",
+			v1alpha1.DashboardResourceName,
+			td.GetName(),
+		)
+		logger.Error(msg)
+		td.Status.MarkNotReady(msg)
+		return nil
+	}
+
+	// find the valid tekton-pipeline installation
+	if _, err := common.PipelineReady(r.pipelineInformer); err != nil {
+		if err.Error() == common.PipelineNotReady || err == v1alpha1.DEPENDENCY_UPGRADE_PENDING_ERR {
+			td.Status.MarkDependencyInstalling("tekton-pipelines is still installing")
+			// wait for pipeline status to change
+			return v1alpha1.REQUEUE_EVENT_AFTER
+
+		}
+		// (tektonpipeline.opeator.tekton.dev instance not available yet)
+		td.Status.MarkDependencyMissing("tekton-pipelines does not exist")
+		return err
+	}
+	td.Status.MarkDependenciesInstalled()
+
+	if err := r.extension.PreReconcile(ctx, td); err != nil {
+		td.Status.MarkPreReconcilerFailed(fmt.Sprintf("PreReconciliation failed: %s", err.Error()))
+		return err
+	}
+
+	// Mark PreReconcile Complete
+	td.Status.MarkPreReconcilerComplete()
+
+	var manifest mf.Manifest
+	if td.Spec.Readonly {
+		manifest = r.readonlyManifest
+	} else {
+		manifest = r.fullaccessManifest
+	}
+	if err := r.installerSetClient.MainSet(ctx, td, &manifest, filterAndTransform(r.extension)); err != nil {
+		msg := fmt.Sprintf("Main Reconcilation failed: %s", err.Error())
+		logger.Error(msg)
+		if err == v1alpha1.REQUEUE_EVENT_AFTER {
+			return err
+		}
+		td.Status.MarkInstallerSetNotReady(msg)
+		return nil
+	}
+
+	if err := r.extension.PostReconcile(ctx, td); err != nil {
+		msg := fmt.Sprintf("PostReconciliation failed: %s", err.Error())
+		logger.Error(msg)
+		if err == v1alpha1.REQUEUE_EVENT_AFTER {
+			return err
+		}
+		td.Status.MarkPostReconcilerFailed(msg)
+		return nil
+	}
+
+	td.Status.MarkPostReconcilerComplete()
+	return nil
+}
diff --git a/pkg/reconciler/kubernetes/tektondashboard/tektondashboard.go b/pkg/reconciler/kubernetes/tektondashboard/tektondashboard.go
deleted file mode 100644
index 24261ca95..000000000
--- a/pkg/reconciler/kubernetes/tektondashboard/tektondashboard.go
+++ /dev/null
@@ -1,398 +0,0 @@
-/*
-Copyright 2020 The Tekton Authors
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package tektondashboard
-
-import (
-	"context"
-	"fmt"
-
-	mf "github.com/manifestival/manifestival"
-	"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
-	clientset "github.com/tektoncd/operator/pkg/client/clientset/versioned"
-	pipelineinformer "github.com/tektoncd/operator/pkg/client/informers/externalversions/operator/v1alpha1"
-	tektondashboardreconciler "github.com/tektoncd/operator/pkg/client/injection/reconciler/operator/v1alpha1/tektondashboard"
-	"github.com/tektoncd/operator/pkg/reconciler/common"
-	"github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektoninstallerset"
-	"github.com/tektoncd/operator/pkg/reconciler/shared/hash"
-	corev1 "k8s.io/api/core/v1"
-	apierrors "k8s.io/apimachinery/pkg/api/errors"
-	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/client-go/kubernetes"
-	"knative.dev/pkg/apis"
-	"knative.dev/pkg/logging"
-	pkgreconciler "knative.dev/pkg/reconciler"
-)
-
-// Reconciler implements controller.Reconciler for TektonDashboard resources.
-type Reconciler struct {
-	// kubeClientSet allows us to talk to the k8s for core APIs
-	kubeClientSet kubernetes.Interface
-	// operatorClientSet allows us to configure operator objects
-	operatorClientSet clientset.Interface
-	// readOnlyManifest has the source manifest of Tekton Dashboard for
-	// a particular version with readonly value as true
-	readonlyManifest mf.Manifest
-	// fullaccessManifest has the source manifest of Tekton Dashboard for
-	// a particular version with readonly value as false
-	fullaccessManifest mf.Manifest
-	// Platform-specific behavior to affect the transform
-	extension        common.Extension
-	pipelineInformer pipelineinformer.TektonPipelineInformer
-	operatorVersion  string
-	dashboardVersion string
-}
-
-// Check that our Reconciler implements controller.Reconciler
-var _ tektondashboardreconciler.Interface = (*Reconciler)(nil)
-var _ tektondashboardreconciler.Finalizer = (*Reconciler)(nil)
-
-var (
-	ls = metav1.LabelSelector{
-		MatchLabels: map[string]string{
-			v1alpha1.CreatedByKey:     createdByValue,
-			v1alpha1.InstallerSetType: v1alpha1.DashboardResourceName,
-		},
-	}
-)
-
-const createdByValue = "TektonDashboard"
-
-// FinalizeKind removes all resources after deletion of a TektonDashboards.
-func (r *Reconciler) FinalizeKind(ctx context.Context, original *v1alpha1.TektonDashboard) pkgreconciler.Event {
-	logger := logging.FromContext(ctx)
-
-	// Delete CRDs before deleting rest of resources so that any instance
-	// of CRDs which has finalizer set will get deleted before we remove
-	// the controller;s deployment for it
-
-	var manifest mf.Manifest
-	if original.Spec.Readonly {
-		manifest = r.readonlyManifest
-	} else {
-		manifest = r.fullaccessManifest
-	}
-
-	if err := manifest.Filter(mf.CRDs).Delete(); err != nil {
-		logger.Error("Failed to deleted CRDs for TektonDashboard")
-		return err
-	}
-
-	labelSelector, err := common.LabelSelector(ls)
-	if err != nil {
-		return err
-	}
-	if err := r.operatorClientSet.OperatorV1alpha1().TektonInstallerSets().
-		DeleteCollection(ctx, metav1.DeleteOptions{}, metav1.ListOptions{
-			LabelSelector: labelSelector,
-		}); err != nil {
-		logger.Error("Failed to delete installer set created by TektonDashboard", err)
-		return err
-	}
-
-	if err := r.extension.Finalize(ctx, original); err != nil {
-		logger.Error("Failed to finalize platform resources", err)
-	}
-	return nil
-}
-
-// ReconcileKind compares the actual state with the desired, and attempts to
-// converge the two.
-func (r *Reconciler) ReconcileKind(ctx context.Context, td *v1alpha1.TektonDashboard) pkgreconciler.Event {
-	logger := logging.FromContext(ctx)
-	td.Status.InitializeConditions()
-	td.Status.ObservedGeneration = td.Generation
-	td.Status.SetVersion(r.dashboardVersion)
-
-	logger.Infow("Reconciling TektonDashboards", "status", td.Status)
-
-	if td.GetName() != v1alpha1.DashboardResourceName {
-		msg := fmt.Sprintf("Resource ignored, Expected Name: %s, Got Name: %s",
-			v1alpha1.DashboardResourceName,
-			td.GetName(),
-		)
-		logger.Error(msg)
-		td.Status.MarkNotReady(msg)
-		return nil
-	}
-
-	// find the valid tekton-pipeline installation
-	if _, err := common.PipelineReady(r.pipelineInformer); err != nil {
-		if err.Error() == common.PipelineNotReady || err == v1alpha1.DEPENDENCY_UPGRADE_PENDING_ERR {
-			td.Status.MarkDependencyInstalling("tekton-pipelines is still installing")
-			// wait for pipeline status to change
-			return v1alpha1.REQUEUE_EVENT_AFTER
-
-		}
-		// (tektonpipeline.opeator.tekton.dev instance not available yet)
-		td.Status.MarkDependencyMissing("tekton-pipelines does not exist")
-		return err
-	}
-	td.Status.MarkDependenciesInstalled()
-
-	// Mark TektonDashboard Instance as Not Ready if an upgrade is needed
-	if err := r.markUpgrade(ctx, td); err != nil {
-		return err
-	}
-
-	if err := r.extension.PreReconcile(ctx, td); err != nil {
-		td.Status.MarkPreReconcilerFailed(fmt.Sprintf("PreReconciliation failed: %s", err.Error()))
-		return err
-	}
-
-	// Mark PreReconcile Complete
-	td.Status.MarkPreReconcilerComplete()
-
-	// Check if an tektoninstallerset already exists, if not then create
-	labelSelector, err := common.LabelSelector(ls)
-	if err != nil {
-		return err
-	}
-	existingInstallerSet, err := tektoninstallerset.CurrentInstallerSetName(ctx, r.operatorClientSet, labelSelector)
-	if err != nil {
-		return err
-	}
-	if existingInstallerSet == "" {
-		createdIs, err := r.createInstallerSet(ctx, td)
-		if err != nil {
-			return err
-		}
-
-		return r.updateTektonDashboardStatus(ctx, td, createdIs)
-	}
-
-	// If exists, then fetch the TektonInstallerSet
-	installedTIS, err := r.operatorClientSet.OperatorV1alpha1().TektonInstallerSets().
-		Get(ctx, existingInstallerSet, metav1.GetOptions{})
-	if err != nil {
-		if apierrors.IsNotFound(err) {
-			createdIs, err := r.createInstallerSet(ctx, td)
-			if err != nil {
-				return err
-			}
-			return r.updateTektonDashboardStatus(ctx, td, createdIs)
-		}
-		logger.Error("failed to get InstallerSet: %s", err)
-		return err
-	}
-
-	installerSetTargetNamespace := installedTIS.Annotations[v1alpha1.TargetNamespaceKey]
-	installerSetReleaseVersion := installedTIS.Labels[v1alpha1.ReleaseVersionKey]
-
-	// Check if TargetNamespace of existing TektonInstallerSet is same as expected
-	// Check if Release Version in TektonInstallerSet is same as expected
-	// If any of the thing above is not same then delete the existing TektonInstallerSet
-	// and create a new with expected properties
-
-	if installerSetTargetNamespace != td.Spec.TargetNamespace || installerSetReleaseVersion != r.operatorVersion {
-		// Delete the existing TektonInstallerSet
-		err := r.operatorClientSet.OperatorV1alpha1().TektonInstallerSets().
-			Delete(ctx, existingInstallerSet, metav1.DeleteOptions{})
-		if err != nil {
-			logger.Error("failed to delete InstallerSet: %s", err)
-			return err
-		}
-
-		// Make sure the TektonInstallerSet is deleted
-		_, err = r.operatorClientSet.OperatorV1alpha1().TektonInstallerSets().
-			Get(ctx, existingInstallerSet, metav1.GetOptions{})
-		if err == nil {
-			td.Status.MarkNotReady("Waiting for previous installer set to get deleted")
-			return v1alpha1.REQUEUE_EVENT_AFTER
-		}
-		if !apierrors.IsNotFound(err) {
-			logger.Error("failed to get InstallerSet: %s", err)
-			return err
-		}
-		return nil
-
-	} else {
-		// If target namespace and version are not changed then check if spec
-		// of TektonDashboard is changed by checking hash stored as annotation on
-		// TektonInstallerSet with computing new hash of TektonDashboard Spec
-
-		// Hash of TektonDashboard Spec
-
-		expectedSpecHash, err := hash.Compute(td.Spec)
-		if err != nil {
-			return err
-		}
-
-		// spec hash stored on installerSet
-		lastAppliedHash := installedTIS.GetAnnotations()[v1alpha1.LastAppliedHashKey]
-
-		if lastAppliedHash != expectedSpecHash {
-
-			var manifest mf.Manifest
-			if td.Spec.Readonly {
-				manifest = r.readonlyManifest
-			} else {
-				manifest = r.fullaccessManifest
-			}
-
-			if err := r.transform(ctx, &manifest, td); err != nil {
-				logger.Error("manifest transformation failed:  ", err)
-				return err
-			}
-
-			// Update the spec hash
-			current := installedTIS.GetAnnotations()
-			current[v1alpha1.LastAppliedHashKey] = expectedSpecHash
-			installedTIS.SetAnnotations(current)
-
-			// Update the manifests
-			installedTIS.Spec.Manifests = manifest.Resources()
-
-			if _, err = r.operatorClientSet.OperatorV1alpha1().TektonInstallerSets().
-				Update(ctx, installedTIS, metav1.UpdateOptions{}); err != nil {
-				return err
-			}
-
-			// after updating installer set enqueue after a duration
-			// to allow changes to get deployed
-			return v1alpha1.REQUEUE_EVENT_AFTER
-		}
-	}
-
-	// Mark InstallerSetAvailable
-	td.Status.MarkInstallerSetAvailable()
-
-	ready := installedTIS.Status.GetCondition(apis.ConditionReady)
-	if ready == nil {
-		td.Status.MarkInstallerSetNotReady("Waiting for installation")
-		return v1alpha1.REQUEUE_EVENT_AFTER
-	}
-
-	if ready.Status == corev1.ConditionUnknown {
-		td.Status.MarkInstallerSetNotReady("Waiting for installation")
-		return v1alpha1.REQUEUE_EVENT_AFTER
-	} else if ready.Status == corev1.ConditionFalse {
-		td.Status.MarkInstallerSetNotReady(ready.Message)
-		return v1alpha1.REQUEUE_EVENT_AFTER
-	}
-
-	// Mark InstallerSet Ready
-	td.Status.MarkInstallerSetReady()
-
-	if err := r.extension.PostReconcile(ctx, td); err != nil {
-		td.Status.MarkPostReconcilerFailed(fmt.Sprintf("PostReconciliation failed: %s", err.Error()))
-		return err
-	}
-
-	td.Status.MarkPostReconcilerComplete()
-	return nil
-}
-
-func (r *Reconciler) updateTektonDashboardStatus(ctx context.Context, td *v1alpha1.TektonDashboard, createdIs *v1alpha1.TektonInstallerSet) error {
-	// update the td with TektonInstallerSet and releaseVersion
-	td.Status.SetTektonInstallerSet(createdIs.Name)
-	td.Status.SetVersion(r.dashboardVersion)
-	return nil
-}
-
-// transform mutates the passed manifest to one with common, component
-// and platform transformations applied
-func (r *Reconciler) transform(ctx context.Context, manifest *mf.Manifest, comp v1alpha1.TektonComponent) error {
-	instance := comp.(*v1alpha1.TektonDashboard)
-	extra := []mf.Transformer{
-		common.InjectOperandNameLabelOverwriteExisting(v1alpha1.OperandTektoncdDashboard),
-		common.ApplyProxySettings,
-		common.AddConfiguration(instance.Spec.Config),
-		common.AddDeploymentRestrictedPSA(),
-	}
-	extra = append(extra, r.extension.Transformers(instance)...)
-	return common.Transform(ctx, manifest, instance, extra...)
-}
-
-func (r *Reconciler) createInstallerSet(ctx context.Context, td *v1alpha1.TektonDashboard) (*v1alpha1.TektonInstallerSet, error) {
-
-	var manifest mf.Manifest
-	if td.Spec.Readonly {
-		manifest = r.readonlyManifest
-	} else {
-		manifest = r.fullaccessManifest
-	}
-
-	if err := r.transform(ctx, &manifest, td); err != nil {
-		td.Status.MarkNotReady("transformation failed: " + err.Error())
-		return nil, err
-	}
-
-	// compute the hash of tektondashboard spec and store as an annotation
-	// in further reconciliation we compute hash of td spec and check with
-	// annotation, if they are same then we skip updating the object
-	// otherwise we update the manifest
-	specHash, err := hash.Compute(td.Spec)
-	if err != nil {
-		return nil, err
-	}
-
-	// create installer set
-	tis := r.makeInstallerSet(td, manifest, specHash)
-	createdIs, err := r.operatorClientSet.OperatorV1alpha1().TektonInstallerSets().
-		Create(ctx, tis, metav1.CreateOptions{})
-	if err != nil {
-		return nil, err
-	}
-	return createdIs, nil
-}
-
-func (r *Reconciler) makeInstallerSet(td *v1alpha1.TektonDashboard, manifest mf.Manifest, tdSpecHash string) *v1alpha1.TektonInstallerSet {
-	ownerRef := *metav1.NewControllerRef(td, td.GetGroupVersionKind())
-	return &v1alpha1.TektonInstallerSet{
-		ObjectMeta: metav1.ObjectMeta{
-			GenerateName: fmt.Sprintf("%s-", v1alpha1.DashboardResourceName),
-			Labels: map[string]string{
-				v1alpha1.CreatedByKey:      createdByValue,
-				v1alpha1.InstallerSetType:  v1alpha1.DashboardResourceName,
-				v1alpha1.ReleaseVersionKey: r.operatorVersion,
-			},
-			Annotations: map[string]string{
-				v1alpha1.TargetNamespaceKey: td.Spec.TargetNamespace,
-				v1alpha1.LastAppliedHashKey: tdSpecHash,
-			},
-			OwnerReferences: []metav1.OwnerReference{ownerRef},
-		},
-		Spec: v1alpha1.TektonInstallerSetSpec{
-			Manifests: manifest.Resources(),
-		},
-	}
-}
-
-func (r *Reconciler) markUpgrade(ctx context.Context, td *v1alpha1.TektonDashboard) error {
-	labels := td.GetLabels()
-	ver, ok := labels[v1alpha1.ReleaseVersionKey]
-	if ok && ver == r.operatorVersion {
-		return nil
-	}
-	if ok && ver != r.operatorVersion {
-		td.Status.MarkInstallerSetNotReady(v1alpha1.UpgradePending)
-		td.Status.MarkPreReconcilerFailed(v1alpha1.UpgradePending)
-		td.Status.MarkPostReconcilerFailed(v1alpha1.UpgradePending)
-		td.Status.MarkNotReady(v1alpha1.UpgradePending)
-	}
-	if labels == nil {
-		labels = map[string]string{}
-	}
-	labels[v1alpha1.ReleaseVersionKey] = r.operatorVersion
-	td.SetLabels(labels)
-
-	if _, err := r.operatorClientSet.OperatorV1alpha1().TektonDashboards().Update(ctx,
-		td, metav1.UpdateOptions{}); err != nil {
-		return err
-	}
-	return v1alpha1.RECONCILE_AGAIN_ERR
-}
diff --git a/pkg/reconciler/kubernetes/tektondashboard/transform.go b/pkg/reconciler/kubernetes/tektondashboard/transform.go
new file mode 100644
index 000000000..34e3fcb97
--- /dev/null
+++ b/pkg/reconciler/kubernetes/tektondashboard/transform.go
@@ -0,0 +1,45 @@
+/*
+Copyright 2020 The Tekton Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package tektondashboard
+
+import (
+	"context"
+	mf "github.com/manifestival/manifestival"
+	"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
+	"github.com/tektoncd/operator/pkg/reconciler/common"
+	"github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektoninstallerset/client"
+)
+
+func filterAndTransform(extension common.Extension) client.FilterAndTransform {
+	return func(ctx context.Context, manifest *mf.Manifest, comp v1alpha1.TektonComponent) (*mf.Manifest, error) {
+
+		dashboard := comp.(*v1alpha1.TektonDashboard)
+		trns := extension.Transformers(dashboard)
+		extra := []mf.Transformer{
+			common.InjectOperandNameLabelOverwriteExisting(v1alpha1.OperandTektoncdDashboard),
+			common.ApplyProxySettings,
+			common.AddConfiguration(dashboard.Spec.Config),
+			common.AddDeploymentRestrictedPSA(),
+		}
+		trns = append(trns, extra...)
+		if err := common.Transform(ctx, manifest, dashboard, trns...); err != nil {
+			return nil, err
+		}
+
+		return manifest, nil
+	}
+}
diff --git a/pkg/reconciler/openshift/openshiftpipelinesascode/controller.go b/pkg/reconciler/openshift/openshiftpipelinesascode/controller.go
index 121cfaff7..ae3f5f5f3 100644
--- a/pkg/reconciler/openshift/openshiftpipelinesascode/controller.go
+++ b/pkg/reconciler/openshift/openshiftpipelinesascode/controller.go
@@ -60,7 +60,7 @@ func NewExtendedController(generator common.ExtensionGenerator) injection.Contro
 
 		tisClient := operatorclient.Get(ctx).OperatorV1alpha1().TektonInstallerSets()
 
-		metrics, err := NewRecorder()
+		metrics, err := common.NoMetrics()
 		if err != nil {
 			logger.Errorf("Failed to create trigger metrics recorder %v", err)
 		}
diff --git a/vendor/github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1/event_listener_validation.go b/vendor/github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1/event_listener_validation.go
index f9f6a3d51..9d0828b83 100644
--- a/vendor/github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1/event_listener_validation.go
+++ b/vendor/github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1/event_listener_validation.go
@@ -22,8 +22,6 @@ import (
 	"encoding/json"
 	"fmt"
 
-	"github.com/tektoncd/triggers/pkg/apis/config"
-
 	"github.com/tektoncd/triggers/pkg/apis/triggers"
 	corev1 "k8s.io/api/core/v1"
 	"k8s.io/apimachinery/pkg/util/sets"
@@ -86,12 +84,6 @@ func (s *EventListenerSpec) validate(ctx context.Context) (errs *apis.FieldError
 		}
 	}
 
-	if s.CloudEventURI != "" {
-		err := ValidateEnabledAPIFields(ctx, "spec.CloudEventURI", config.AlphaAPIFieldValue)
-		if err != nil {
-			errs = errs.Also(err)
-		}
-	}
 	return errs
 }
 
diff --git a/vendor/github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1/openapi_generated.go b/vendor/github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1/openapi_generated.go
index 313e8c1bf..693fa5669 100644
--- a/vendor/github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1/openapi_generated.go
+++ b/vendor/github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1/openapi_generated.go
@@ -827,7 +827,7 @@ func schema_pkg_apis_triggers_v1beta1_InterceptorRef(ref common.ReferenceCallbac
 					},
 					"kind": {
 						SchemaProps: spec.SchemaProps{
-							Description: "InterceptorKind indicates the kind of the Interceptor, namespaced or cluster scoped. Currently only InterceptorKind is ClusterInterceptor, so the only valid value is the default one",
+							Description: "InterceptorKind indicates the kind of the Interceptor, namespaced or cluster scoped.",
 							Type:        []string{"string"},
 							Format:      "",
 						},
diff --git a/vendor/github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1/swagger.json b/vendor/github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1/swagger.json
index af1bc4aa8..d68c7d651 100644
--- a/vendor/github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1/swagger.json
+++ b/vendor/github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1/swagger.json
@@ -7,6 +7,138 @@
   },
   "paths": {},
   "definitions": {
+    "github.com.tektoncd.pipeline.pkg.apis.resolution.v1beta1.ResolutionRequest": {
+      "description": "ResolutionRequest is an object for requesting the content of a Tekton resource like a pipeline.yaml.",
+      "type": "object",
+      "properties": {
+        "apiVersion": {
+          "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
+          "type": "string"
+        },
+        "kind": {
+          "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
+          "type": "string"
+        },
+        "metadata": {
+          "default": {},
+          "$ref": "#/definitions/v1.ObjectMeta"
+        },
+        "spec": {
+          "description": "Spec holds the information for the request part of the resource request.",
+          "default": {},
+          "$ref": "#/definitions/github.com.tektoncd.pipeline.pkg.apis.resolution.v1beta1.ResolutionRequestSpec"
+        },
+        "status": {
+          "description": "Status communicates the state of the request and, ultimately, the content of the resolved resource.",
+          "default": {},
+          "$ref": "#/definitions/github.com.tektoncd.pipeline.pkg.apis.resolution.v1beta1.ResolutionRequestStatus"
+        }
+      }
+    },
+    "github.com.tektoncd.pipeline.pkg.apis.resolution.v1beta1.ResolutionRequestList": {
+      "description": "ResolutionRequestList is a list of ResolutionRequests.",
+      "type": "object",
+      "required": [
+        "items"
+      ],
+      "properties": {
+        "apiVersion": {
+          "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
+          "type": "string"
+        },
+        "items": {
+          "type": "array",
+          "items": {
+            "default": {},
+            "$ref": "#/definitions/github.com.tektoncd.pipeline.pkg.apis.resolution.v1beta1.ResolutionRequest"
+          }
+        },
+        "kind": {
+          "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
+          "type": "string"
+        },
+        "metadata": {
+          "default": {},
+          "$ref": "#/definitions/v1.ListMeta"
+        }
+      }
+    },
+    "github.com.tektoncd.pipeline.pkg.apis.resolution.v1beta1.ResolutionRequestSpec": {
+      "description": "ResolutionRequestSpec are all the fields in the spec of the ResolutionRequest CRD.",
+      "type": "object",
+      "properties": {
+        "params": {
+          "description": "Parameters are the runtime attributes passed to the resolver to help it figure out how to resolve the resource being requested. For example: repo URL, commit SHA, path to file, the kind of authentication to leverage, etc.",
+          "type": "array",
+          "items": {
+            "default": {},
+            "$ref": "#/definitions/v1beta1.Param"
+          },
+          "x-kubernetes-list-type": "atomic"
+        }
+      }
+    },
+    "github.com.tektoncd.pipeline.pkg.apis.resolution.v1beta1.ResolutionRequestStatus": {
+      "description": "ResolutionRequestStatus are all the fields in a ResolutionRequest's status subresource.",
+      "type": "object",
+      "required": [
+        "data",
+        "source"
+      ],
+      "properties": {
+        "annotations": {
+          "description": "Annotations is additional Status fields for the Resource to save some additional State as well as convey more information to the user. This is roughly akin to Annotations on any k8s resource, just the reconciler conveying richer information outwards.",
+          "type": "object",
+          "additionalProperties": {
+            "type": "string",
+            "default": ""
+          }
+        },
+        "conditions": {
+          "description": "Conditions the latest available observations of a resource's current state.",
+          "type": "array",
+          "items": {
+            "default": {},
+            "$ref": "#/definitions/knative.Condition"
+          },
+          "x-kubernetes-patch-merge-key": "type",
+          "x-kubernetes-patch-strategy": "merge"
+        },
+        "data": {
+          "description": "Data is a string representation of the resolved content of the requested resource in-lined into the ResolutionRequest object.",
+          "type": "string",
+          "default": ""
+        },
+        "observedGeneration": {
+          "description": "ObservedGeneration is the 'Generation' of the Service that was last processed by the controller.",
+          "type": "integer",
+          "format": "int64"
+        },
+        "source": {
+          "description": "Source is the source reference of the remote data that records the url, digest and the entrypoint.",
+          "$ref": "#/definitions/v1beta1.ConfigSource"
+        }
+      }
+    },
+    "github.com.tektoncd.pipeline.pkg.apis.resolution.v1beta1.ResolutionRequestStatusFields": {
+      "description": "ResolutionRequestStatusFields are the ResolutionRequest-specific fields for the status subresource.",
+      "type": "object",
+      "required": [
+        "data",
+        "source"
+      ],
+      "properties": {
+        "data": {
+          "description": "Data is a string representation of the resolved content of the requested resource in-lined into the ResolutionRequest object.",
+          "type": "string",
+          "default": ""
+        },
+        "source": {
+          "description": "Source is the source reference of the remote data that records the url, digest and the entrypoint.",
+          "$ref": "#/definitions/v1beta1.ConfigSource"
+        }
+      }
+    },
     "pod.AffinityAssistantTemplate": {
       "description": "AffinityAssistantTemplate holds pod specific configuration and is a subset of the generic pod Template",
       "type": "object",
@@ -380,7 +512,7 @@
       }
     },
     "v1beta1.ClusterTask": {
-      "description": "ClusterTask is a Task with a cluster scope. ClusterTasks are used to represent Tasks that should be publicly addressable from any namespace in the cluster.",
+      "description": "ClusterTask is a Task with a cluster scope. ClusterTasks are used to represent Tasks that should be publicly addressable from any namespace in the cluster. Deprecated: Please use the cluster resolver instead.",
       "type": "object",
       "properties": {
         "apiVersion": {
@@ -430,6 +562,154 @@
         }
       }
     },
+    "v1beta1.ConfigSource": {
+      "description": "ConfigSource identifies the source where a resource came from. This can include Git repositories, Task Bundles, file checksums, or other information that allows users to identify where the resource came from and what version was used.",
+      "type": "object",
+      "properties": {
+        "digest": {
+          "description": "Digest is a collection of cryptographic digests for the contents of the artifact specified by URI. Definition: https://slsa.dev/provenance/v0.2#invocation.configSource.digest Example: {\"sha1\": \"f99d13e554ffcb696dee719fa85b695cb5b0f428\"}",
+          "type": "object",
+          "additionalProperties": {
+            "type": "string",
+            "default": ""
+          }
+        },
+        "entryPoint": {
+          "description": "EntryPoint identifies the entry point into the build. This is often a path to a configuration file and/or a target label within that file. Definition: https://slsa.dev/provenance/v0.2#invocation.configSource.entryPoint Example: \"task/git-clone/0.8/git-clone.yaml\"",
+          "type": "string"
+        },
+        "uri": {
+          "description": "URI indicates the identity of the source of the config. Definition: https://slsa.dev/provenance/v0.2#invocation.configSource.uri Example: \"https://github.com/tektoncd/catalog\"",
+          "type": "string"
+        }
+      }
+    },
+    "v1beta1.CustomRun": {
+      "description": "CustomRun represents a single execution of a Custom Task.",
+      "type": "object",
+      "properties": {
+        "apiVersion": {
+          "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
+          "type": "string"
+        },
+        "kind": {
+          "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
+          "type": "string"
+        },
+        "metadata": {
+          "default": {},
+          "$ref": "#/definitions/v1.ObjectMeta"
+        },
+        "spec": {
+          "default": {},
+          "$ref": "#/definitions/v1beta1.CustomRunSpec"
+        },
+        "status": {
+          "default": {},
+          "$ref": "#/definitions/github.com.tektoncd.pipeline.pkg.apis.run.v1beta1.CustomRunStatus"
+        }
+      }
+    },
+    "v1beta1.CustomRunList": {
+      "description": "CustomRunList contains a list of CustomRun",
+      "type": "object",
+      "required": [
+        "items"
+      ],
+      "properties": {
+        "apiVersion": {
+          "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources",
+          "type": "string"
+        },
+        "items": {
+          "type": "array",
+          "items": {
+            "default": {},
+            "$ref": "#/definitions/v1beta1.CustomRun"
+          }
+        },
+        "kind": {
+          "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds",
+          "type": "string"
+        },
+        "metadata": {
+          "default": {},
+          "$ref": "#/definitions/v1.ListMeta"
+        }
+      }
+    },
+    "v1beta1.CustomRunSpec": {
+      "description": "CustomRunSpec defines the desired state of CustomRun",
+      "type": "object",
+      "properties": {
+        "customRef": {
+          "$ref": "#/definitions/v1beta1.TaskRef"
+        },
+        "customSpec": {
+          "description": "Spec is a specification of a custom task",
+          "$ref": "#/definitions/v1beta1.EmbeddedCustomRunSpec"
+        },
+        "params": {
+          "type": "array",
+          "items": {
+            "default": {},
+            "$ref": "#/definitions/v1beta1.Param"
+          },
+          "x-kubernetes-list-type": "atomic"
+        },
+        "retries": {
+          "description": "Used for propagating retries count to custom tasks",
+          "type": "integer",
+          "format": "int32"
+        },
+        "serviceAccountName": {
+          "type": "string",
+          "default": ""
+        },
+        "status": {
+          "description": "Used for cancelling a customrun (and maybe more later on)",
+          "type": "string"
+        },
+        "statusMessage": {
+          "description": "Status message for cancellation.",
+          "type": "string"
+        },
+        "timeout": {
+          "description": "Time after which the custom-task times out. Refer Go's ParseDuration documentation for expected format: https://golang.org/pkg/time/#ParseDuration",
+          "$ref": "#/definitions/v1.Duration"
+        },
+        "workspaces": {
+          "description": "Workspaces is a list of WorkspaceBindings from volumes to workspaces.",
+          "type": "array",
+          "items": {
+            "default": {},
+            "$ref": "#/definitions/v1beta1.WorkspaceBinding"
+          },
+          "x-kubernetes-list-type": "atomic"
+        }
+      }
+    },
+    "v1beta1.EmbeddedCustomRunSpec": {
+      "description": "EmbeddedCustomRunSpec allows custom task definitions to be embedded",
+      "type": "object",
+      "properties": {
+        "apiVersion": {
+          "type": "string"
+        },
+        "kind": {
+          "type": "string"
+        },
+        "metadata": {
+          "default": {},
+          "$ref": "#/definitions/v1beta1.PipelineTaskMetadata"
+        },
+        "spec": {
+          "description": "Spec is a specification of a custom task",
+          "default": {},
+          "$ref": "#/definitions/k8s.io.apimachinery.pkg.runtime.RawExtension"
+        }
+      }
+    },
     "v1beta1.EmbeddedTask": {
       "description": "EmbeddedTask is used to define a Task inline within a Pipeline's PipelineTasks.",
       "type": "object",
@@ -552,6 +832,21 @@
         }
       }
     },
+    "v1beta1.Matrix": {
+      "description": "Matrix is used to fan out Tasks in a Pipeline",
+      "type": "object",
+      "properties": {
+        "params": {
+          "description": "Params is a list of parameters used to fan out the pipelineTask Params takes only `Parameters` of type `\"array\"` Each array element is supplied to the `PipelineTask` by substituting `params` of type `\"string\"` in the underlying `Task`. The names of the `params` in the `Matrix` must match the names of the `params` in the underlying `Task` that they will be substituting.",
+          "type": "array",
+          "items": {
+            "default": {},
+            "$ref": "#/definitions/v1beta1.Param"
+          },
+          "x-kubernetes-list-type": "atomic"
+        }
+      }
+    },
     "v1beta1.Param": {
       "description": "Param declares an ParamValues to use for the parameter called name.",
       "type": "object",
@@ -724,7 +1019,7 @@
           "type": "string"
         },
         "bundle": {
-          "description": "Bundle url reference to a Tekton Bundle.",
+          "description": "Bundle url reference to a Tekton Bundle. Deprecated: Please use ResolverRef with the bundles resolver instead.",
           "type": "string"
         },
         "name": {
@@ -1015,6 +1310,10 @@
           "x-kubernetes-patch-merge-key": "type",
           "x-kubernetes-patch-strategy": "merge"
         },
+        "finallyStartTime": {
+          "description": "FinallyStartTime is when all non-finally tasks have been completed and only finally tasks are being executed.",
+          "$ref": "#/definitions/v1.Time"
+        },
         "observedGeneration": {
           "description": "ObservedGeneration is the 'Generation' of the Service that was last processed by the controller.",
           "type": "integer",
@@ -1033,6 +1332,10 @@
           "description": "PipelineRunSpec contains the exact spec used to instantiate the run",
           "$ref": "#/definitions/v1beta1.PipelineSpec"
         },
+        "provenance": {
+          "description": "Provenance contains some key authenticated metadata about how a software artifact was built (what sources, what inputs/outputs, etc.).",
+          "$ref": "#/definitions/v1beta1.Provenance"
+        },
         "runs": {
           "description": "Deprecated - use ChildReferences instead. map of PipelineRunRunStatus with the run name as the key",
           "type": "object",
@@ -1079,6 +1382,10 @@
           "description": "CompletionTime is the time the PipelineRun completed.",
           "$ref": "#/definitions/v1.Time"
         },
+        "finallyStartTime": {
+          "description": "FinallyStartTime is when all non-finally tasks have been completed and only finally tasks are being executed.",
+          "$ref": "#/definitions/v1.Time"
+        },
         "pipelineResults": {
           "description": "PipelineResults are the list of results written out by the pipeline task's containers",
           "type": "array",
@@ -1092,6 +1399,10 @@
           "description": "PipelineRunSpec contains the exact spec used to instantiate the run",
           "$ref": "#/definitions/v1beta1.PipelineSpec"
         },
+        "provenance": {
+          "description": "Provenance contains some key authenticated metadata about how a software artifact was built (what sources, what inputs/outputs, etc.).",
+          "$ref": "#/definitions/v1beta1.Provenance"
+        },
         "runs": {
           "description": "Deprecated - use ChildReferences instead. map of PipelineRunRunStatus with the run name as the key",
           "type": "object",
@@ -1214,12 +1525,7 @@
       "properties": {
         "matrix": {
           "description": "Matrix declares parameters used to fan out this task.",
-          "type": "array",
-          "items": {
-            "default": {},
-            "$ref": "#/definitions/v1beta1.Param"
-          },
-          "x-kubernetes-list-type": "atomic"
+          "$ref": "#/definitions/v1beta1.Matrix"
         },
         "name": {
           "description": "Name is the name of this task within the context of a Pipeline. Name is used as a coordinate with the `from` and `runAfter` fields to establish the execution order of tasks relative to one another.",
@@ -1472,42 +1778,32 @@
         }
       }
     },
-    "v1beta1.ResolverParam": {
-      "description": "ResolverParam is a single parameter passed to a resolver.",
+    "v1beta1.Provenance": {
+      "description": "Provenance contains some key authenticated metadata about how a software artifact was built (what sources, what inputs/outputs, etc.). For now, it only contains the subfield `ConfigSource` that identifies the source where a build config file came from. In future, it can be expanded as needed to include more metadata about the build. This field aims to be used to carry minimum amount of the authenticated metadata in *Run status so that Tekton Chains can pick it up and record in the provenance it generates.",
       "type": "object",
-      "required": [
-        "name",
-        "value"
-      ],
       "properties": {
-        "name": {
-          "description": "Name is the name of the parameter that will be passed to the resolver.",
-          "type": "string",
-          "default": ""
-        },
-        "value": {
-          "description": "Value is the string value of the parameter that will be passed to the resolver.",
-          "type": "string",
-          "default": ""
+        "configSource": {
+          "description": "ConfigSource identifies the source where a resource came from.",
+          "$ref": "#/definitions/v1beta1.ConfigSource"
         }
       }
     },
     "v1beta1.ResolverRef": {
-      "description": "ResolverRef can be used to refer to a Pipeline or Task in a remote location like a git repo. This feature is in alpha and these fields are only available when the alpha feature gate is enabled.",
+      "description": "ResolverRef can be used to refer to a Pipeline or Task in a remote location like a git repo.",
       "type": "object",
       "properties": {
-        "resolver": {
-          "description": "Resolver is the name of the resolver that should perform resolution of the referenced Tekton resource, such as \"git\".",
-          "type": "string"
-        },
-        "resource": {
-          "description": "Resource contains the parameters used to identify the referenced Tekton resource. Example entries might include \"repo\" or \"path\" but the set of params ultimately depends on the chosen resolver.",
+        "params": {
+          "description": "Params contains the parameters used to identify the referenced Tekton resource. Example entries might include \"repo\" or \"path\" but the set of params ultimately depends on the chosen resolver.",
           "type": "array",
           "items": {
             "default": {},
-            "$ref": "#/definitions/v1beta1.ResolverParam"
+            "$ref": "#/definitions/v1beta1.Param"
           },
           "x-kubernetes-list-type": "atomic"
+        },
+        "resolver": {
+          "description": "Resolver is the name of the resolver that should perform resolution of the referenced Tekton resource, such as \"git\".",
+          "type": "string"
         }
       }
     },
@@ -2173,7 +2469,7 @@
           "type": "string"
         },
         "bundle": {
-          "description": "Bundle url reference to a Tekton Bundle.",
+          "description": "Bundle url reference to a Tekton Bundle. Deprecated: Please use ResolverRef with the bundles resolver instead.",
           "type": "string"
         },
         "kind": {
@@ -2597,6 +2893,10 @@
           "type": "string",
           "default": ""
         },
+        "provenance": {
+          "description": "Provenance contains some key authenticated metadata about how a software artifact was built (what sources, what inputs/outputs, etc.).",
+          "$ref": "#/definitions/v1beta1.Provenance"
+        },
         "resourcesResult": {
           "description": "Results from Resources built during the taskRun. currently includes the digest of build container images",
           "type": "array",
@@ -2677,6 +2977,10 @@
           "type": "string",
           "default": ""
         },
+        "provenance": {
+          "description": "Provenance contains some key authenticated metadata about how a software artifact was built (what sources, what inputs/outputs, etc.).",
+          "$ref": "#/definitions/v1beta1.Provenance"
+        },
         "resourcesResult": {
           "description": "Results from Resources built during the taskRun. currently includes the digest of build container images",
           "type": "array",
diff --git a/vendor/github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1/trigger_types.go b/vendor/github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1/trigger_types.go
index 8fec73452..2eb83d6af 100644
--- a/vendor/github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1/trigger_types.go
+++ b/vendor/github.com/tektoncd/triggers/pkg/apis/triggers/v1beta1/trigger_types.go
@@ -109,8 +109,6 @@ type InterceptorRef struct {
 	// Name of the referent; More info: http://kubernetes.io/docs/user-guide/identifiers#names
 	Name string `json:"name,omitempty"`
 	// InterceptorKind indicates the kind of the Interceptor, namespaced or cluster scoped.
-	// Currently only InterceptorKind is ClusterInterceptor, so the only valid value
-	// is the default one
 	// +optional
 	Kind InterceptorKind `json:"kind,omitempty"`
 	// API version of the referent
@@ -122,8 +120,10 @@ type InterceptorRef struct {
 type InterceptorKind string
 
 const (
-	// ClusterTaskKind indicates that task type has a cluster scope.
+	// ClusterInterceptorKind indicates that Interceptor type has a cluster scope.
 	ClusterInterceptorKind InterceptorKind = "ClusterInterceptor"
+	// NamespacedInterceptorKind indicates that Interceptor type has a namespace scope.
+	NamespacedInterceptorKind InterceptorKind = "NamespacedInterceptor"
 )
 
 func (ti *TriggerInterceptor) defaultInterceptorKind() {
diff --git a/vendor/golang.org/x/crypto/bcrypt/bcrypt.go b/vendor/golang.org/x/crypto/bcrypt/bcrypt.go
index aeb73f81a..addf56b43 100644
--- a/vendor/golang.org/x/crypto/bcrypt/bcrypt.go
+++ b/vendor/golang.org/x/crypto/bcrypt/bcrypt.go
@@ -50,7 +50,7 @@ func (ih InvalidHashPrefixError) Error() string {
 type InvalidCostError int
 
 func (ic InvalidCostError) Error() string {
-	return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed range (%d,%d)", int(ic), int(MinCost), int(MaxCost))
+	return fmt.Sprintf("crypto/bcrypt: cost %d is outside allowed range (%d,%d)", int(ic), MinCost, MaxCost)
 }
 
 const (
diff --git a/vendor/golang.org/x/crypto/cryptobyte/asn1.go b/vendor/golang.org/x/crypto/cryptobyte/asn1.go
index 3a1674a1e..a64c1d752 100644
--- a/vendor/golang.org/x/crypto/cryptobyte/asn1.go
+++ b/vendor/golang.org/x/crypto/cryptobyte/asn1.go
@@ -532,7 +532,7 @@ func (s *String) ReadASN1BitString(out *encoding_asn1.BitString) bool {
 		return false
 	}
 
-	paddingBits := uint8(bytes[0])
+	paddingBits := bytes[0]
 	bytes = bytes[1:]
 	if paddingBits > 7 ||
 		len(bytes) == 0 && paddingBits != 0 ||
@@ -554,7 +554,7 @@ func (s *String) ReadASN1BitStringAsBytes(out *[]byte) bool {
 		return false
 	}
 
-	paddingBits := uint8(bytes[0])
+	paddingBits := bytes[0]
 	if paddingBits != 0 {
 		return false
 	}
diff --git a/vendor/golang.org/x/crypto/openpgp/armor/armor.go b/vendor/golang.org/x/crypto/openpgp/armor/armor.go
index be342ad47..8907183ec 100644
--- a/vendor/golang.org/x/crypto/openpgp/armor/armor.go
+++ b/vendor/golang.org/x/crypto/openpgp/armor/armor.go
@@ -156,7 +156,7 @@ func (r *openpgpReader) Read(p []byte) (n int, err error) {
 	n, err = r.b64Reader.Read(p)
 	r.currentCRC = crc24(r.currentCRC, p[:n])
 
-	if err == io.EOF && r.lReader.crcSet && r.lReader.crc != uint32(r.currentCRC&crc24Mask) {
+	if err == io.EOF && r.lReader.crcSet && r.lReader.crc != r.currentCRC&crc24Mask {
 		return 0, ArmorCorrupt
 	}
 
diff --git a/vendor/golang.org/x/crypto/ssh/common.go b/vendor/golang.org/x/crypto/ssh/common.go
index 7a5ff2d2e..c7964275d 100644
--- a/vendor/golang.org/x/crypto/ssh/common.go
+++ b/vendor/golang.org/x/crypto/ssh/common.go
@@ -10,6 +10,7 @@ import (
 	"fmt"
 	"io"
 	"math"
+	"strings"
 	"sync"
 
 	_ "crypto/sha1"
@@ -118,6 +119,20 @@ func algorithmsForKeyFormat(keyFormat string) []string {
 	}
 }
 
+// supportedPubKeyAuthAlgos specifies the supported client public key
+// authentication algorithms. Note that this doesn't include certificate types
+// since those use the underlying algorithm. This list is sent to the client if
+// it supports the server-sig-algs extension. Order is irrelevant.
+var supportedPubKeyAuthAlgos = []string{
+	KeyAlgoED25519,
+	KeyAlgoSKED25519, KeyAlgoSKECDSA256,
+	KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521,
+	KeyAlgoRSASHA256, KeyAlgoRSASHA512, KeyAlgoRSA,
+	KeyAlgoDSA,
+}
+
+var supportedPubKeyAuthAlgosList = strings.Join(supportedPubKeyAuthAlgos, ",")
+
 // unexpectedMessageError results when the SSH message that we received didn't
 // match what we wanted.
 func unexpectedMessageError(expected, got uint8) error {
diff --git a/vendor/golang.org/x/crypto/ssh/handshake.go b/vendor/golang.org/x/crypto/ssh/handshake.go
index 653dc4d2c..2b84c3571 100644
--- a/vendor/golang.org/x/crypto/ssh/handshake.go
+++ b/vendor/golang.org/x/crypto/ssh/handshake.go
@@ -615,7 +615,8 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
 		return err
 	}
 
-	if t.sessionID == nil {
+	firstKeyExchange := t.sessionID == nil
+	if firstKeyExchange {
 		t.sessionID = result.H
 	}
 	result.SessionID = t.sessionID
@@ -626,6 +627,24 @@ func (t *handshakeTransport) enterKeyExchange(otherInitPacket []byte) error {
 	if err = t.conn.writePacket([]byte{msgNewKeys}); err != nil {
 		return err
 	}
+
+	// On the server side, after the first SSH_MSG_NEWKEYS, send a SSH_MSG_EXT_INFO
+	// message with the server-sig-algs extension if the client supports it. See
+	// RFC 8308, Sections 2.4 and 3.1.
+	if !isClient && firstKeyExchange && contains(clientInit.KexAlgos, "ext-info-c") {
+		extInfo := &extInfoMsg{
+			NumExtensions: 1,
+			Payload:       make([]byte, 0, 4+15+4+len(supportedPubKeyAuthAlgosList)),
+		}
+		extInfo.Payload = appendInt(extInfo.Payload, len("server-sig-algs"))
+		extInfo.Payload = append(extInfo.Payload, "server-sig-algs"...)
+		extInfo.Payload = appendInt(extInfo.Payload, len(supportedPubKeyAuthAlgosList))
+		extInfo.Payload = append(extInfo.Payload, supportedPubKeyAuthAlgosList...)
+		if err := t.conn.writePacket(Marshal(extInfo)); err != nil {
+			return err
+		}
+	}
+
 	if packet, err := t.conn.readPacket(); err != nil {
 		return err
 	} else if packet[0] != msgNewKeys {
diff --git a/vendor/golang.org/x/crypto/ssh/server.go b/vendor/golang.org/x/crypto/ssh/server.go
index 2260b20af..9e3870292 100644
--- a/vendor/golang.org/x/crypto/ssh/server.go
+++ b/vendor/golang.org/x/crypto/ssh/server.go
@@ -291,15 +291,6 @@ func (s *connection) serverHandshake(config *ServerConfig) (*Permissions, error)
 	return perms, err
 }
 
-func isAcceptableAlgo(algo string) bool {
-	switch algo {
-	case KeyAlgoRSA, KeyAlgoRSASHA256, KeyAlgoRSASHA512, KeyAlgoDSA, KeyAlgoECDSA256, KeyAlgoECDSA384, KeyAlgoECDSA521, KeyAlgoSKECDSA256, KeyAlgoED25519, KeyAlgoSKED25519,
-		CertAlgoRSAv01, CertAlgoDSAv01, CertAlgoECDSA256v01, CertAlgoECDSA384v01, CertAlgoECDSA521v01, CertAlgoSKECDSA256v01, CertAlgoED25519v01, CertAlgoSKED25519v01:
-		return true
-	}
-	return false
-}
-
 func checkSourceAddress(addr net.Addr, sourceAddrs string) error {
 	if addr == nil {
 		return errors.New("ssh: no address known for client, but source-address match required")
@@ -514,7 +505,7 @@ userAuthLoop:
 				return nil, parseError(msgUserAuthRequest)
 			}
 			algo := string(algoBytes)
-			if !isAcceptableAlgo(algo) {
+			if !contains(supportedPubKeyAuthAlgos, underlyingAlgo(algo)) {
 				authErr = fmt.Errorf("ssh: algorithm %q not accepted", algo)
 				break
 			}
@@ -572,7 +563,7 @@ userAuthLoop:
 				// algorithm name that corresponds to algo with
 				// sig.Format.  This is usually the same, but
 				// for certs, the names differ.
-				if !isAcceptableAlgo(sig.Format) {
+				if !contains(supportedPubKeyAuthAlgos, sig.Format) {
 					authErr = fmt.Errorf("ssh: algorithm %q not accepted", sig.Format)
 					break
 				}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index 0cc2583b5..db6b0db69 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1198,7 +1198,7 @@ github.com/tektoncd/pipeline/test/parse
 ## explicit; go 1.13
 github.com/tektoncd/plumbing
 github.com/tektoncd/plumbing/scripts
-# github.com/tektoncd/triggers v0.21.0
+# github.com/tektoncd/triggers v0.22.0
 ## explicit; go 1.17
 github.com/tektoncd/triggers/pkg/apis/config
 github.com/tektoncd/triggers/pkg/apis/triggers
@@ -1497,7 +1497,7 @@ go.uber.org/zap/zapcore
 go.uber.org/zap/zapgrpc
 go.uber.org/zap/zaptest
 go.uber.org/zap/zaptest/observer
-# golang.org/x/crypto v0.2.0
+# golang.org/x/crypto v0.3.0
 ## explicit; go 1.17
 golang.org/x/crypto/bcrypt
 golang.org/x/crypto/blake2b
@@ -1901,7 +1901,7 @@ k8s.io/api/scheduling/v1beta1
 k8s.io/api/storage/v1
 k8s.io/api/storage/v1alpha1
 k8s.io/api/storage/v1beta1
-# k8s.io/apiextensions-apiserver v0.25.2
+# k8s.io/apiextensions-apiserver v0.25.3
 ## explicit; go 1.19
 k8s.io/apiextensions-apiserver/pkg/apis/apiextensions
 k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1


Test patch:
diff --git a/pkg/reconciler/kubernetes/tektonconfig/extension/dashboard_test.go b/pkg/reconciler/kubernetes/tektonconfig/extension/dashboard_test.go
index 8564f6ba0..af4a4fed8 100644
--- a/pkg/reconciler/kubernetes/tektonconfig/extension/dashboard_test.go
+++ b/pkg/reconciler/kubernetes/tektonconfig/extension/dashboard_test.go
@@ -41,9 +41,9 @@ func TestEnsureTektonDashbordExists(t *testing.T) {
 	util.AssertEqual(t, err, v1alpha1.RECONCILE_AGAIN_ERR)
 
 	// during second invocation instance exists but waiting on dependencies (pipeline, triggers)
-	// hence returns DEPENDENCY_UPGRADE_PENDING_ERR
+	// hence returns RECONCILE_AGAIN_ERR
 	_, err = EnsureTektonDashboardExists(ctx, c.OperatorV1alpha1().TektonDashboards(), tConfig)
-	util.AssertEqual(t, err, v1alpha1.DEPENDENCY_UPGRADE_PENDING_ERR)
+	util.AssertEqual(t, err, v1alpha1.RECONCILE_AGAIN_ERR)
 
 	// make upgrade checks pass
 	makeUpgradeCheckPass(t, ctx, c.OperatorV1alpha1().TektonDashboards())