Repository: tektoncd/operator
Pull request #1115 (2022-10-18 11:40:25)

Moves PipelinesAsCode from Addon to a separate component 
# Changes

this adds a new API OpenShiftPipelinesAsCode for PipelinesAsCode installation
and clean it up from tekton addon.

TODO:
Create OpenShiftPipelinesAsCode CR through TektonConfig
Expose PAC Configuration, will be done after https://github.com/openshift-pipelines/pipelines-as-code/issues/932


<!-- 🎉🎉🎉 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:

- [x] Run `make test lint` before submitting a PR
- [x] 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)
- [x] 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: [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 ask for approval from **sm43** after the PR has been reviewed.

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

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

- **[OWNERS](https://github.com/tektoncd/operator/blob/main/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":["sm43"]} -->
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/apis/operator/v1alpha1/openshiftpipelinesascode_lifecycle.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1582335797854474240/artifacts/line-cov.html#file0) | Do not exist | 44.0% | 
[pkg/apis/operator/v1alpha1/openshiftpipelinesascode_types.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1582335797854474240/artifacts/line-cov.html#file1) | Do not exist | 0.0% | 
[pkg/apis/operator/v1alpha1/tektonconfig_defaults.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1582335797854474240/artifacts/line-cov.html#file4) | 72.7% | 76.9% | 4.2
[pkg/apis/operator/v1alpha1/tektonpipeline_defaults.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1582335797854474240/artifacts/line-cov.html#file5) | 100.0% | 88.4% | -11.6
[pkg/apis/operator/v1alpha1/tektontrigger_defaults.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1582335797854474240/artifacts/line-cov.html#file6) | 57.1% | 100.0% | 42.9
[pkg/reconciler/kubernetes/tektoninstallerset/client/check.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1582335797854474240/artifacts/line-cov.html#file10) | 86.6% | 85.2% | -1.3
[pkg/reconciler/kubernetes/tektoninstallerset/client/cleanup.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1582335797854474240/artifacts/line-cov.html#file11) | 72.7% | 76.5% | 3.7
[pkg/reconciler/kubernetes/tektoninstallerset/client/labels.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1582335797854474240/artifacts/line-cov.html#file14) | Do not exist | 100.0% | 

tekton-robot: @sm43: 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 | a596b2f219f5e9e23c7bc5fe6c9b2bd18a6561fd | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-unit-tests/1582335797770588160) | true | `/test pull-tekton-operator-unit-tests`

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

<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: @sm43: 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 | a596b2f219f5e9e23c7bc5fe6c9b2bd18a6561fd | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-unit-tests/1582335797770588160) | true | `/test pull-tekton-operator-unit-tests`
pull-tekton-operator-build-tests | a596b2f219f5e9e23c7bc5fe6c9b2bd18a6561fd | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-build-tests/1582335797745422336) | true | `/test pull-tekton-operator-build-tests`

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

<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: @sm43: 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 | a596b2f219f5e9e23c7bc5fe6c9b2bd18a6561fd | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-unit-tests/1582335797770588160) | true | `/test pull-tekton-operator-unit-tests`
pull-tekton-operator-build-tests | a596b2f219f5e9e23c7bc5fe6c9b2bd18a6561fd | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-build-tests/1582335797745422336) | true | `/test pull-tekton-operator-build-tests`
pull-tekton-operator-go-coverage | 87e038c99b4e4a44cffa61fb7e5a03d36ed151ab | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583006211232501760) | false | `/test pull-tekton-operator-go-coverage`

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

<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: @sm43: 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 | a596b2f219f5e9e23c7bc5fe6c9b2bd18a6561fd | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-unit-tests/1582335797770588160) | true | `/test pull-tekton-operator-unit-tests`
pull-tekton-operator-go-coverage | 87e038c99b4e4a44cffa61fb7e5a03d36ed151ab | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583006211232501760) | false | `/test pull-tekton-operator-go-coverage`
pull-tekton-operator-integration-tests | 87e038c99b4e4a44cffa61fb7e5a03d36ed151ab | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-integration-tests/1583006211182170112) | true | `/test pull-tekton-operator-integration-tests`
pull-tekton-operator-build-tests | 87e038c99b4e4a44cffa61fb7e5a03d36ed151ab | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-build-tests/1583006211094089728) | true | `/test pull-tekton-operator-build-tests`

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

<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: @sm43: 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-go-coverage | 87e038c99b4e4a44cffa61fb7e5a03d36ed151ab | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583006211232501760) | false | `/test pull-tekton-operator-go-coverage`
pull-tekton-operator-integration-tests | 87e038c99b4e4a44cffa61fb7e5a03d36ed151ab | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-integration-tests/1583006211182170112) | true | `/test pull-tekton-operator-integration-tests`
pull-tekton-operator-build-tests | 87e038c99b4e4a44cffa61fb7e5a03d36ed151ab | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-build-tests/1583006211094089728) | true | `/test pull-tekton-operator-build-tests`
pull-tekton-operator-unit-tests | 87e038c99b4e4a44cffa61fb7e5a03d36ed151ab | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-unit-tests/1583006211136032768) | true | `/test pull-tekton-operator-unit-tests`

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

<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/apis/operator/v1alpha1/openshiftpipelinesascode_lifecycle.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583006607787167744/artifacts/line-cov.html#file0) | Do not exist | 48.0% | 
[pkg/apis/operator/v1alpha1/openshiftpipelinesascode_types.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583006607787167744/artifacts/line-cov.html#file1) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/controller.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583006607787167744/artifacts/line-cov.html#file7) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/extension.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583006607787167744/artifacts/line-cov.html#file8) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/metrics.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583006607787167744/artifacts/line-cov.html#file9) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/pipelinerun_templates.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583006607787167744/artifacts/line-cov.html#file10) | Do not exist | 54.8% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/reconcile.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583006607787167744/artifacts/line-cov.html#file11) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/transform.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583006607787167744/artifacts/line-cov.html#file12) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/update_route_in_configmap.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583006607787167744/artifacts/line-cov.html#file13) | Do not exist | 74.4% | 
[pkg/reconciler/openshift/tektonaddon/pipelinesascode.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583006607787167744/artifacts/line-cov.html#file14) | 13.0% | 0.0% | -13.0

tekton-robot: @sm43: 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-integration-tests | 87e038c99b4e4a44cffa61fb7e5a03d36ed151ab | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-integration-tests/1583006211182170112) | true | `/test pull-tekton-operator-integration-tests`
pull-tekton-operator-build-tests | b6a432f177821acdf25156214a2f08514d054f9d | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-build-tests/1583006607644561408) | true | `/test pull-tekton-operator-build-tests`

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

<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/apis/operator/v1alpha1/openshiftpipelinesascode_lifecycle.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583056214286143488/artifacts/line-cov.html#file0) | Do not exist | 48.0% | 
[pkg/apis/operator/v1alpha1/openshiftpipelinesascode_types.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583056214286143488/artifacts/line-cov.html#file1) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/controller.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583056214286143488/artifacts/line-cov.html#file7) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/extension.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583056214286143488/artifacts/line-cov.html#file8) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/metrics.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583056214286143488/artifacts/line-cov.html#file9) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/pipelinerun_templates.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583056214286143488/artifacts/line-cov.html#file10) | Do not exist | 54.8% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/reconcile.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583056214286143488/artifacts/line-cov.html#file11) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/transform.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583056214286143488/artifacts/line-cov.html#file12) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/update_route_in_configmap.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583056214286143488/artifacts/line-cov.html#file13) | Do not exist | 74.4% | 
[pkg/reconciler/openshift/tektonaddon/pipelinesascode.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583056214286143488/artifacts/line-cov.html#file14) | 13.0% | 0.0% | -13.0

tekton-robot: @sm43: 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 | 2d990b059e314dee8aeea9d0d7f52e0f31887d01 | [link](https://prow.tekton.dev/view/gs/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-build-tests/1583056214143537152) | true | `/test pull-tekton-operator-build-tests`

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

<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/apis/operator/v1alpha1/openshiftpipelinesascode_lifecycle.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583060930000850944/artifacts/line-cov.html#file0) | Do not exist | 48.0% | 
[pkg/apis/operator/v1alpha1/openshiftpipelinesascode_types.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583060930000850944/artifacts/line-cov.html#file1) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/controller.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583060930000850944/artifacts/line-cov.html#file7) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/extension.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583060930000850944/artifacts/line-cov.html#file8) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/metrics.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583060930000850944/artifacts/line-cov.html#file9) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/pipelinerun_templates.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583060930000850944/artifacts/line-cov.html#file10) | Do not exist | 54.8% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/reconcile.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583060930000850944/artifacts/line-cov.html#file11) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/transform.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583060930000850944/artifacts/line-cov.html#file12) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/update_route_in_configmap.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583060930000850944/artifacts/line-cov.html#file13) | Do not exist | 74.4% | 
[pkg/reconciler/openshift/tektonaddon/pipelinesascode.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1583060930000850944/artifacts/line-cov.html#file14) | 13.0% | 0.0% | -13.0

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/apis/operator/v1alpha1/openshiftpipelinesascode_lifecycle.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1585169359288930304/artifacts/line-cov.html#file0) | Do not exist | 48.0% | 
[pkg/apis/operator/v1alpha1/openshiftpipelinesascode_types.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1585169359288930304/artifacts/line-cov.html#file1) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/controller.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1585169359288930304/artifacts/line-cov.html#file7) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/extension.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1585169359288930304/artifacts/line-cov.html#file8) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/metrics.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1585169359288930304/artifacts/line-cov.html#file9) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/pipelinerun_templates.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1585169359288930304/artifacts/line-cov.html#file10) | Do not exist | 54.8% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/reconcile.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1585169359288930304/artifacts/line-cov.html#file11) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/transform.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1585169359288930304/artifacts/line-cov.html#file12) | Do not exist | 0.0% | 
[pkg/reconciler/openshift/openshiftpipelinesascode/update_route_in_configmap.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1585169359288930304/artifacts/line-cov.html#file13) | Do not exist | 74.4% | 
[pkg/reconciler/openshift/tektonaddon/pipelinesascode.go](https://storage.cloud.google.com/tekton-prow/pr-logs/pull/tektoncd_operator/1115/pull-tekton-operator-go-coverage/1585169359288930304/artifacts/line-cov.html#file14) | 13.0% | 0.0% | -13.0

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

This pull-request has been approved by: *<a href="https://github.com/tektoncd/operator/pull/1115#pullrequestreview-1156015522" 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":[]} -->

Patch:
diff --git a/config/crs/openshift/pac/operator_v1alpha1_openshiftpipelinesascode_cr.yaml b/config/crs/openshift/pac/operator_v1alpha1_openshiftpipelinesascode_cr.yaml
new file mode 100644
index 000000000..e2d001a12
--- /dev/null
+++ b/config/crs/openshift/pac/operator_v1alpha1_openshiftpipelinesascode_cr.yaml
@@ -0,0 +1,20 @@
+# 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.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+apiVersion: operator.tekton.dev/v1alpha1
+kind: OpenShiftPipelinesAsCode
+metadata:
+  name: pipelines-as-code
+spec:
+  targetNamespace: openshift-pipelines
diff --git a/config/openshift/base/300-operator_v1alpha1_openshiftpipelinesascode_crd.yaml b/config/openshift/base/300-operator_v1alpha1_openshiftpipelinesascode_crd.yaml
new file mode 100644
index 000000000..741452d92
--- /dev/null
+++ b/config/openshift/base/300-operator_v1alpha1_openshiftpipelinesascode_crd.yaml
@@ -0,0 +1,54 @@
+# 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.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+apiVersion: apiextensions.k8s.io/v1
+kind: CustomResourceDefinition
+metadata:
+  name: openshiftpipelinesascodes.operator.tekton.dev
+  labels:
+    version: "devel"
+    operator.tekton.dev/release: "devel"
+spec:
+  group: operator.tekton.dev
+  names:
+    kind: OpenShiftPipelinesAsCode
+    listKind: OpenShiftPipelinesAsCodeList
+    plural: openshiftpipelinesascodes
+    singular: openshiftpipelinesascode
+    shortNames:
+    - opac
+    - pac
+  preserveUnknownFields: false
+  scope: Cluster
+  versions:
+  - name: v1alpha1
+    served: true
+    storage: true
+    subresources:
+      status: {}
+    additionalPrinterColumns:
+    - jsonPath: .status.version
+      name: Version
+      type: string
+    - jsonPath: .status.conditions[?(@.type=="Ready")].status
+      name: Ready
+      type: string
+    - jsonPath: ".status.conditions[?(@.type==\"Ready\")].reason"
+      name: Reason
+      type: string
+    schema:
+      openAPIV3Schema:
+        type: object
+        description: Schema for the OpenShiftPipelinesAsCode API
+        x-kubernetes-preserve-unknown-fields: true
diff --git a/config/openshift/base/kustomization.yaml b/config/openshift/base/kustomization.yaml
index 0cc333b0a..51782e5b8 100644
--- a/config/openshift/base/kustomization.yaml
+++ b/config/openshift/base/kustomization.yaml
@@ -44,6 +44,7 @@ resources:
 - ../../base/
 - ../../webhooks
 - 300-operator_v1alpha1_addon_crd.yaml
+- 300-operator_v1alpha1_openshiftpipelinesascode_crd.yaml
 - operator_service.yaml
 - operator_servicemonitor.yaml
 apiVersion: kustomize.config.k8s.io/v1beta1
diff --git a/config/openshift/base/operator.yaml b/config/openshift/base/operator.yaml
index 02271092a..06e93c2d1 100644
--- a/config/openshift/base/operator.yaml
+++ b/config/openshift/base/operator.yaml
@@ -38,7 +38,7 @@ spec:
         image: ko://github.com/tektoncd/operator/cmd/openshift/operator
         args:
         - "-controllers"
-        - "tektonconfig,tektonpipeline,tektontrigger,tektonhub,tektonchain,tektonaddon"
+        - "tektonconfig,tektonpipeline,tektontrigger,tektonhub,tektonchain,tektonaddon,openshiftpipelinesascode"
         - "-unique-process-name"
         - "tekton-operator-lifecycle"
         imagePullPolicy: Always
diff --git a/pkg/apis/operator/v1alpha1/const.go b/pkg/apis/operator/v1alpha1/const.go
index 2843d99b7..cd440dfcc 100644
--- a/pkg/apis/operator/v1alpha1/const.go
+++ b/pkg/apis/operator/v1alpha1/const.go
@@ -102,18 +102,19 @@ var (
 )
 
 var (
-	ConfigResourceName       = "config"
-	PipelineResourceName     = "pipeline"
-	OperandTektoncdPipeline  = "tektoncd-pipelines"
-	TriggerResourceName      = "trigger"
-	OperandTektoncdTriggers  = "tektoncd-triggers"
-	DashboardResourceName    = "dashboard"
-	OperandTektoncdDashboard = "tektoncd-dashboard"
-	AddonResourceName        = "addon"
-	ResultResourceName       = "result"
-	OperandTektoncdResults   = "tektoncd-results"
-	HubResourceName          = "hub"
-	OperandTektoncdHub       = "tektoncd-hub"
-	ChainResourceName        = "chain"
-	OperandTektoncdChains    = "tektoncd-chains"
+	ConfigResourceName           = "config"
+	PipelineResourceName         = "pipeline"
+	OperandTektoncdPipeline      = "tektoncd-pipelines"
+	TriggerResourceName          = "trigger"
+	OperandTektoncdTriggers      = "tektoncd-triggers"
+	DashboardResourceName        = "dashboard"
+	OperandTektoncdDashboard     = "tektoncd-dashboard"
+	AddonResourceName            = "addon"
+	ResultResourceName           = "result"
+	OperandTektoncdResults       = "tektoncd-results"
+	HubResourceName              = "hub"
+	OperandTektoncdHub           = "tektoncd-hub"
+	ChainResourceName            = "chain"
+	OperandTektoncdChains        = "tektoncd-chains"
+	OpenShiftPipelinesAsCodeName = "pipelines-as-code"
 )
diff --git a/pkg/apis/operator/v1alpha1/openshiftpipelinesascode_lifecycle.go b/pkg/apis/operator/v1alpha1/openshiftpipelinesascode_lifecycle.go
new file mode 100644
index 000000000..e75f19caa
--- /dev/null
+++ b/pkg/apis/operator/v1alpha1/openshiftpipelinesascode_lifecycle.go
@@ -0,0 +1,137 @@
+/*
+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.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1alpha1
+
+import (
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	"knative.dev/pkg/apis"
+)
+
+var (
+	_ TektonComponentStatus = (*OpenShiftPipelinesAsCodeStatus)(nil)
+
+	opacCondSet = apis.NewLivingConditionSet(
+		DependenciesInstalled,
+		PreReconciler,
+		InstallerSetAvailable,
+		InstallerSetReady,
+		PostReconciler,
+	)
+)
+
+func (pac *OpenShiftPipelinesAsCode) GroupVersionKind() schema.GroupVersionKind {
+	return SchemeGroupVersion.WithKind(KindOpenShiftPipelinesAsCode)
+}
+
+func (pac *OpenShiftPipelinesAsCode) GetGroupVersionKind() schema.GroupVersionKind {
+	return SchemeGroupVersion.WithKind(KindOpenShiftPipelinesAsCode)
+}
+
+func (pac *OpenShiftPipelinesAsCodeStatus) GetCondition(t apis.ConditionType) *apis.Condition {
+	return opacCondSet.Manage(pac).GetCondition(t)
+}
+
+func (pac *OpenShiftPipelinesAsCodeStatus) InitializeConditions() {
+	opacCondSet.Manage(pac).InitializeConditions()
+}
+
+func (pac *OpenShiftPipelinesAsCodeStatus) IsReady() bool {
+	return opacCondSet.Manage(pac).IsHappy()
+}
+
+func (pac *OpenShiftPipelinesAsCodeStatus) MarkPreReconcilerComplete() {
+	opacCondSet.Manage(pac).MarkTrue(PreReconciler)
+}
+
+func (pac *OpenShiftPipelinesAsCodeStatus) MarkInstallerSetAvailable() {
+	opacCondSet.Manage(pac).MarkTrue(InstallerSetAvailable)
+}
+
+func (pac *OpenShiftPipelinesAsCodeStatus) MarkInstallerSetReady() {
+	opacCondSet.Manage(pac).MarkTrue(InstallerSetReady)
+}
+
+func (pac *OpenShiftPipelinesAsCodeStatus) MarkPostReconcilerComplete() {
+	opacCondSet.Manage(pac).MarkTrue(PostReconciler)
+}
+
+func (pac *OpenShiftPipelinesAsCodeStatus) MarkNotReady(msg string) {
+	opacCondSet.Manage(pac).MarkFalse(
+		apis.ConditionReady,
+		"Error",
+		"Ready: %s", msg)
+}
+
+func (pac *OpenShiftPipelinesAsCodeStatus) MarkPreReconcilerFailed(msg string) {
+	pac.MarkNotReady("PreReconciliation failed")
+	opacCondSet.Manage(pac).MarkFalse(
+		PreReconciler,
+		"Error",
+		"PreReconciliation failed with message: %s", msg)
+}
+
+func (pac *OpenShiftPipelinesAsCodeStatus) MarkInstallerSetNotAvailable(msg string) {
+	pac.MarkNotReady("TektonInstallerSet not ready")
+	opacCondSet.Manage(pac).MarkFalse(
+		InstallerSetAvailable,
+		"Error",
+		"Installer set not ready: %s", msg)
+}
+
+func (pac *OpenShiftPipelinesAsCodeStatus) MarkInstallerSetNotReady(msg string) {
+	pac.MarkNotReady("TektonInstallerSet not ready")
+	opacCondSet.Manage(pac).MarkFalse(
+		InstallerSetReady,
+		"Error",
+		"Installer set not ready: %s", msg)
+}
+
+func (pac *OpenShiftPipelinesAsCodeStatus) MarkPostReconcilerFailed(msg string) {
+	pac.MarkNotReady("PostReconciliation failed")
+	opacCondSet.Manage(pac).MarkFalse(
+		PostReconciler,
+		"Error",
+		"PostReconciliation failed with message: %s", msg)
+}
+
+func (pac *OpenShiftPipelinesAsCodeStatus) MarkDependenciesInstalled() {
+	opacCondSet.Manage(pac).MarkTrue(DependenciesInstalled)
+}
+
+func (pac *OpenShiftPipelinesAsCodeStatus) MarkDependencyInstalling(msg string) {
+	pac.MarkNotReady("Dependencies installing")
+	opacCondSet.Manage(pac).MarkFalse(
+		DependenciesInstalled,
+		"Error",
+		"Dependencies are installing: %s", msg)
+}
+
+func (pac *OpenShiftPipelinesAsCodeStatus) MarkDependencyMissing(msg string) {
+	pac.MarkNotReady("Missing Dependencies for TektonTriggers")
+	opacCondSet.Manage(pac).MarkFalse(
+		DependenciesInstalled,
+		"Error",
+		"Dependencies are missing: %s", msg)
+}
+
+func (pac *OpenShiftPipelinesAsCodeStatus) GetVersion() string {
+	return pac.Version
+}
+
+func (pac *OpenShiftPipelinesAsCodeStatus) SetVersion(version string) {
+	pac.Version = version
+}
diff --git a/pkg/apis/operator/v1alpha1/openshiftpipelinesascode_types.go b/pkg/apis/operator/v1alpha1/openshiftpipelinesascode_types.go
new file mode 100644
index 000000000..73376aa8d
--- /dev/null
+++ b/pkg/apis/operator/v1alpha1/openshiftpipelinesascode_types.go
@@ -0,0 +1,68 @@
+/*
+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.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1alpha1
+
+import (
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	duckv1 "knative.dev/pkg/apis/duck/v1"
+)
+
+// OpenShiftPipelinesAsCode is the Schema for the OpenShiftPipelinesAsCode API
+// +genclient
+// +genreconciler:krshapedlogic=false
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+// +genclient:nonNamespaced
+type OpenShiftPipelinesAsCode struct {
+	metav1.TypeMeta   `json:",inline"`
+	metav1.ObjectMeta `json:"metadata,omitempty"`
+
+	Spec   OpenShiftPipelinesAsCodeSpec   `json:"spec,omitempty"`
+	Status OpenShiftPipelinesAsCodeStatus `json:"status,omitempty"`
+}
+
+// GetSpec implements TektonComponent
+func (pac *OpenShiftPipelinesAsCode) GetSpec() TektonComponentSpec {
+	return &pac.Spec
+}
+
+// GetStatus implements TektonComponent
+func (pac *OpenShiftPipelinesAsCode) GetStatus() TektonComponentStatus {
+	return &pac.Status
+}
+
+// OpenShiftPipelinesAsCodeSpec defines the desired state of OpenShiftPipelinesAsCode
+type OpenShiftPipelinesAsCodeSpec struct {
+	CommonSpec `json:",inline"`
+	Config     Config `json:"config,omitempty"`
+}
+
+// OpenShiftPipelinesAsCodeStatus defines the observed state of OpenShiftPipelinesAsCode
+type OpenShiftPipelinesAsCodeStatus struct {
+	duckv1.Status `json:",inline"`
+
+	// The version of the installed release
+	// +optional
+	Version string `json:"version,omitempty"`
+}
+
+// OpenShiftPipelinesAsCodeList contains a list of OpenShiftPipelinesAsCode
+// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
+type OpenShiftPipelinesAsCodeList struct {
+	metav1.TypeMeta `json:",inline"`
+	metav1.ListMeta `json:"metadata,omitempty"`
+	Items           []OpenShiftPipelinesAsCode `json:"items"`
+}
diff --git a/pkg/apis/operator/v1alpha1/register.go b/pkg/apis/operator/v1alpha1/register.go
index 0bdfcfee3..ec88c2bf7 100644
--- a/pkg/apis/operator/v1alpha1/register.go
+++ b/pkg/apis/operator/v1alpha1/register.go
@@ -55,6 +55,9 @@ const (
 
 	// KindTektonChain is the Kind of Tekton Chain in a GVK context.
 	KindTektonChain = "TektonChain"
+
+	// KindOpenShiftPipelinesAsCode is the Kind of OpenShiftPipelinesAsCode in a GVK context.
+	KindOpenShiftPipelinesAsCode = "OpenShiftPipelinesAsCode"
 )
 
 // Resource takes an unqualified resource and returns a Group qualified GroupResource
@@ -84,6 +87,8 @@ func addKnownTypes(s *runtime.Scheme) error {
 		&TektonHubList{},
 		&TektonChain{},
 		&TektonChainList{},
+		&OpenShiftPipelinesAsCode{},
+		&OpenShiftPipelinesAsCodeList{},
 	)
 	metav1.AddToGroupVersion(s, SchemeGroupVersion)
 	return nil
diff --git a/pkg/apis/operator/v1alpha1/tektonaddon_defaults.go b/pkg/apis/operator/v1alpha1/tektonaddon_defaults.go
index e5820ee54..02a72ccea 100644
--- a/pkg/apis/operator/v1alpha1/tektonaddon_defaults.go
+++ b/pkg/apis/operator/v1alpha1/tektonaddon_defaults.go
@@ -56,6 +56,6 @@ func setAddonDefaults(addon *Addon) {
 
 	// by default enable pac
 	if addon.EnablePAC == nil {
-		addon.EnablePAC = ptr.Bool(true)
+		addon.EnablePAC = ptr.Bool(false)
 	}
 }
diff --git a/pkg/apis/operator/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/operator/v1alpha1/zz_generated.deepcopy.go
index 6284c1a72..7b075134d 100644
--- a/pkg/apis/operator/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/operator/v1alpha1/zz_generated.deepcopy.go
@@ -216,6 +216,102 @@ func (in *Hub) DeepCopy() *Hub {
 	return out
 }
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *OpenShiftPipelinesAsCode) DeepCopyInto(out *OpenShiftPipelinesAsCode) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
+	in.Spec.DeepCopyInto(&out.Spec)
+	in.Status.DeepCopyInto(&out.Status)
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenShiftPipelinesAsCode.
+func (in *OpenShiftPipelinesAsCode) DeepCopy() *OpenShiftPipelinesAsCode {
+	if in == nil {
+		return nil
+	}
+	out := new(OpenShiftPipelinesAsCode)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *OpenShiftPipelinesAsCode) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *OpenShiftPipelinesAsCodeList) DeepCopyInto(out *OpenShiftPipelinesAsCodeList) {
+	*out = *in
+	out.TypeMeta = in.TypeMeta
+	in.ListMeta.DeepCopyInto(&out.ListMeta)
+	if in.Items != nil {
+		in, out := &in.Items, &out.Items
+		*out = make([]OpenShiftPipelinesAsCode, len(*in))
+		for i := range *in {
+			(*in)[i].DeepCopyInto(&(*out)[i])
+		}
+	}
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenShiftPipelinesAsCodeList.
+func (in *OpenShiftPipelinesAsCodeList) DeepCopy() *OpenShiftPipelinesAsCodeList {
+	if in == nil {
+		return nil
+	}
+	out := new(OpenShiftPipelinesAsCodeList)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
+func (in *OpenShiftPipelinesAsCodeList) DeepCopyObject() runtime.Object {
+	if c := in.DeepCopy(); c != nil {
+		return c
+	}
+	return nil
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *OpenShiftPipelinesAsCodeSpec) DeepCopyInto(out *OpenShiftPipelinesAsCodeSpec) {
+	*out = *in
+	out.CommonSpec = in.CommonSpec
+	in.Config.DeepCopyInto(&out.Config)
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenShiftPipelinesAsCodeSpec.
+func (in *OpenShiftPipelinesAsCodeSpec) DeepCopy() *OpenShiftPipelinesAsCodeSpec {
+	if in == nil {
+		return nil
+	}
+	out := new(OpenShiftPipelinesAsCodeSpec)
+	in.DeepCopyInto(out)
+	return out
+}
+
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *OpenShiftPipelinesAsCodeStatus) DeepCopyInto(out *OpenShiftPipelinesAsCodeStatus) {
+	*out = *in
+	in.Status.DeepCopyInto(&out.Status)
+	return
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OpenShiftPipelinesAsCodeStatus.
+func (in *OpenShiftPipelinesAsCodeStatus) DeepCopy() *OpenShiftPipelinesAsCodeStatus {
+	if in == nil {
+		return nil
+	}
+	out := new(OpenShiftPipelinesAsCodeStatus)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *OptionalPipelineProperties) DeepCopyInto(out *OptionalPipelineProperties) {
 	*out = *in
diff --git a/pkg/client/clientset/versioned/typed/operator/v1alpha1/fake/fake_openshiftpipelinesascode.go b/pkg/client/clientset/versioned/typed/operator/v1alpha1/fake/fake_openshiftpipelinesascode.go
new file mode 100644
index 000000000..3130ec0ed
--- /dev/null
+++ b/pkg/client/clientset/versioned/typed/operator/v1alpha1/fake/fake_openshiftpipelinesascode.go
@@ -0,0 +1,133 @@
+/*
+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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package fake
+
+import (
+	"context"
+
+	v1alpha1 "github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	labels "k8s.io/apimachinery/pkg/labels"
+	schema "k8s.io/apimachinery/pkg/runtime/schema"
+	types "k8s.io/apimachinery/pkg/types"
+	watch "k8s.io/apimachinery/pkg/watch"
+	testing "k8s.io/client-go/testing"
+)
+
+// FakeOpenShiftPipelinesAsCodes implements OpenShiftPipelinesAsCodeInterface
+type FakeOpenShiftPipelinesAsCodes struct {
+	Fake *FakeOperatorV1alpha1
+}
+
+var openshiftpipelinesascodesResource = schema.GroupVersionResource{Group: "operator.tekton.dev", Version: "v1alpha1", Resource: "openshiftpipelinesascodes"}
+
+var openshiftpipelinesascodesKind = schema.GroupVersionKind{Group: "operator.tekton.dev", Version: "v1alpha1", Kind: "OpenShiftPipelinesAsCode"}
+
+// Get takes name of the openShiftPipelinesAsCode, and returns the corresponding openShiftPipelinesAsCode object, and an error if there is any.
+func (c *FakeOpenShiftPipelinesAsCodes) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.OpenShiftPipelinesAsCode, err error) {
+	obj, err := c.Fake.
+		Invokes(testing.NewRootGetAction(openshiftpipelinesascodesResource, name), &v1alpha1.OpenShiftPipelinesAsCode{})
+	if obj == nil {
+		return nil, err
+	}
+	return obj.(*v1alpha1.OpenShiftPipelinesAsCode), err
+}
+
+// List takes label and field selectors, and returns the list of OpenShiftPipelinesAsCodes that match those selectors.
+func (c *FakeOpenShiftPipelinesAsCodes) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.OpenShiftPipelinesAsCodeList, err error) {
+	obj, err := c.Fake.
+		Invokes(testing.NewRootListAction(openshiftpipelinesascodesResource, openshiftpipelinesascodesKind, opts), &v1alpha1.OpenShiftPipelinesAsCodeList{})
+	if obj == nil {
+		return nil, err
+	}
+
+	label, _, _ := testing.ExtractFromListOptions(opts)
+	if label == nil {
+		label = labels.Everything()
+	}
+	list := &v1alpha1.OpenShiftPipelinesAsCodeList{ListMeta: obj.(*v1alpha1.OpenShiftPipelinesAsCodeList).ListMeta}
+	for _, item := range obj.(*v1alpha1.OpenShiftPipelinesAsCodeList).Items {
+		if label.Matches(labels.Set(item.Labels)) {
+			list.Items = append(list.Items, item)
+		}
+	}
+	return list, err
+}
+
+// Watch returns a watch.Interface that watches the requested openShiftPipelinesAsCodes.
+func (c *FakeOpenShiftPipelinesAsCodes) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
+	return c.Fake.
+		InvokesWatch(testing.NewRootWatchAction(openshiftpipelinesascodesResource, opts))
+}
+
+// Create takes the representation of a openShiftPipelinesAsCode and creates it.  Returns the server's representation of the openShiftPipelinesAsCode, and an error, if there is any.
+func (c *FakeOpenShiftPipelinesAsCodes) Create(ctx context.Context, openShiftPipelinesAsCode *v1alpha1.OpenShiftPipelinesAsCode, opts v1.CreateOptions) (result *v1alpha1.OpenShiftPipelinesAsCode, err error) {
+	obj, err := c.Fake.
+		Invokes(testing.NewRootCreateAction(openshiftpipelinesascodesResource, openShiftPipelinesAsCode), &v1alpha1.OpenShiftPipelinesAsCode{})
+	if obj == nil {
+		return nil, err
+	}
+	return obj.(*v1alpha1.OpenShiftPipelinesAsCode), err
+}
+
+// Update takes the representation of a openShiftPipelinesAsCode and updates it. Returns the server's representation of the openShiftPipelinesAsCode, and an error, if there is any.
+func (c *FakeOpenShiftPipelinesAsCodes) Update(ctx context.Context, openShiftPipelinesAsCode *v1alpha1.OpenShiftPipelinesAsCode, opts v1.UpdateOptions) (result *v1alpha1.OpenShiftPipelinesAsCode, err error) {
+	obj, err := c.Fake.
+		Invokes(testing.NewRootUpdateAction(openshiftpipelinesascodesResource, openShiftPipelinesAsCode), &v1alpha1.OpenShiftPipelinesAsCode{})
+	if obj == nil {
+		return nil, err
+	}
+	return obj.(*v1alpha1.OpenShiftPipelinesAsCode), err
+}
+
+// UpdateStatus was generated because the type contains a Status member.
+// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
+func (c *FakeOpenShiftPipelinesAsCodes) UpdateStatus(ctx context.Context, openShiftPipelinesAsCode *v1alpha1.OpenShiftPipelinesAsCode, opts v1.UpdateOptions) (*v1alpha1.OpenShiftPipelinesAsCode, error) {
+	obj, err := c.Fake.
+		Invokes(testing.NewRootUpdateSubresourceAction(openshiftpipelinesascodesResource, "status", openShiftPipelinesAsCode), &v1alpha1.OpenShiftPipelinesAsCode{})
+	if obj == nil {
+		return nil, err
+	}
+	return obj.(*v1alpha1.OpenShiftPipelinesAsCode), err
+}
+
+// Delete takes name of the openShiftPipelinesAsCode and deletes it. Returns an error if one occurs.
+func (c *FakeOpenShiftPipelinesAsCodes) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
+	_, err := c.Fake.
+		Invokes(testing.NewRootDeleteActionWithOptions(openshiftpipelinesascodesResource, name, opts), &v1alpha1.OpenShiftPipelinesAsCode{})
+	return err
+}
+
+// DeleteCollection deletes a collection of objects.
+func (c *FakeOpenShiftPipelinesAsCodes) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
+	action := testing.NewRootDeleteCollectionAction(openshiftpipelinesascodesResource, listOpts)
+
+	_, err := c.Fake.Invokes(action, &v1alpha1.OpenShiftPipelinesAsCodeList{})
+	return err
+}
+
+// Patch applies the patch and returns the patched openShiftPipelinesAsCode.
+func (c *FakeOpenShiftPipelinesAsCodes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.OpenShiftPipelinesAsCode, err error) {
+	obj, err := c.Fake.
+		Invokes(testing.NewRootPatchSubresourceAction(openshiftpipelinesascodesResource, name, pt, data, subresources...), &v1alpha1.OpenShiftPipelinesAsCode{})
+	if obj == nil {
+		return nil, err
+	}
+	return obj.(*v1alpha1.OpenShiftPipelinesAsCode), err
+}
diff --git a/pkg/client/clientset/versioned/typed/operator/v1alpha1/fake/fake_operator_client.go b/pkg/client/clientset/versioned/typed/operator/v1alpha1/fake/fake_operator_client.go
index 59de0dfda..feea5bec3 100644
--- a/pkg/client/clientset/versioned/typed/operator/v1alpha1/fake/fake_operator_client.go
+++ b/pkg/client/clientset/versioned/typed/operator/v1alpha1/fake/fake_operator_client.go
@@ -28,6 +28,10 @@ type FakeOperatorV1alpha1 struct {
 	*testing.Fake
 }
 
+func (c *FakeOperatorV1alpha1) OpenShiftPipelinesAsCodes() v1alpha1.OpenShiftPipelinesAsCodeInterface {
+	return &FakeOpenShiftPipelinesAsCodes{c}
+}
+
 func (c *FakeOperatorV1alpha1) TektonAddons() v1alpha1.TektonAddonInterface {
 	return &FakeTektonAddons{c}
 }
diff --git a/pkg/client/clientset/versioned/typed/operator/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/operator/v1alpha1/generated_expansion.go
index e2437abdd..cc9a2b1f5 100644
--- a/pkg/client/clientset/versioned/typed/operator/v1alpha1/generated_expansion.go
+++ b/pkg/client/clientset/versioned/typed/operator/v1alpha1/generated_expansion.go
@@ -18,6 +18,8 @@ limitations under the License.
 
 package v1alpha1
 
+type OpenShiftPipelinesAsCodeExpansion interface{}
+
 type TektonAddonExpansion interface{}
 
 type TektonChainExpansion interface{}
diff --git a/pkg/client/clientset/versioned/typed/operator/v1alpha1/openshiftpipelinesascode.go b/pkg/client/clientset/versioned/typed/operator/v1alpha1/openshiftpipelinesascode.go
new file mode 100644
index 000000000..2391ace7a
--- /dev/null
+++ b/pkg/client/clientset/versioned/typed/operator/v1alpha1/openshiftpipelinesascode.go
@@ -0,0 +1,184 @@
+/*
+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.
+*/
+
+// Code generated by client-gen. DO NOT EDIT.
+
+package v1alpha1
+
+import (
+	"context"
+	"time"
+
+	v1alpha1 "github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
+	scheme "github.com/tektoncd/operator/pkg/client/clientset/versioned/scheme"
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	types "k8s.io/apimachinery/pkg/types"
+	watch "k8s.io/apimachinery/pkg/watch"
+	rest "k8s.io/client-go/rest"
+)
+
+// OpenShiftPipelinesAsCodesGetter has a method to return a OpenShiftPipelinesAsCodeInterface.
+// A group's client should implement this interface.
+type OpenShiftPipelinesAsCodesGetter interface {
+	OpenShiftPipelinesAsCodes() OpenShiftPipelinesAsCodeInterface
+}
+
+// OpenShiftPipelinesAsCodeInterface has methods to work with OpenShiftPipelinesAsCode resources.
+type OpenShiftPipelinesAsCodeInterface interface {
+	Create(ctx context.Context, openShiftPipelinesAsCode *v1alpha1.OpenShiftPipelinesAsCode, opts v1.CreateOptions) (*v1alpha1.OpenShiftPipelinesAsCode, error)
+	Update(ctx context.Context, openShiftPipelinesAsCode *v1alpha1.OpenShiftPipelinesAsCode, opts v1.UpdateOptions) (*v1alpha1.OpenShiftPipelinesAsCode, error)
+	UpdateStatus(ctx context.Context, openShiftPipelinesAsCode *v1alpha1.OpenShiftPipelinesAsCode, opts v1.UpdateOptions) (*v1alpha1.OpenShiftPipelinesAsCode, error)
+	Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
+	DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
+	Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.OpenShiftPipelinesAsCode, error)
+	List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.OpenShiftPipelinesAsCodeList, error)
+	Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
+	Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.OpenShiftPipelinesAsCode, err error)
+	OpenShiftPipelinesAsCodeExpansion
+}
+
+// openShiftPipelinesAsCodes implements OpenShiftPipelinesAsCodeInterface
+type openShiftPipelinesAsCodes struct {
+	client rest.Interface
+}
+
+// newOpenShiftPipelinesAsCodes returns a OpenShiftPipelinesAsCodes
+func newOpenShiftPipelinesAsCodes(c *OperatorV1alpha1Client) *openShiftPipelinesAsCodes {
+	return &openShiftPipelinesAsCodes{
+		client: c.RESTClient(),
+	}
+}
+
+// Get takes name of the openShiftPipelinesAsCode, and returns the corresponding openShiftPipelinesAsCode object, and an error if there is any.
+func (c *openShiftPipelinesAsCodes) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.OpenShiftPipelinesAsCode, err error) {
+	result = &v1alpha1.OpenShiftPipelinesAsCode{}
+	err = c.client.Get().
+		Resource("openshiftpipelinesascodes").
+		Name(name).
+		VersionedParams(&options, scheme.ParameterCodec).
+		Do(ctx).
+		Into(result)
+	return
+}
+
+// List takes label and field selectors, and returns the list of OpenShiftPipelinesAsCodes that match those selectors.
+func (c *openShiftPipelinesAsCodes) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.OpenShiftPipelinesAsCodeList, err error) {
+	var timeout time.Duration
+	if opts.TimeoutSeconds != nil {
+		timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
+	}
+	result = &v1alpha1.OpenShiftPipelinesAsCodeList{}
+	err = c.client.Get().
+		Resource("openshiftpipelinesascodes").
+		VersionedParams(&opts, scheme.ParameterCodec).
+		Timeout(timeout).
+		Do(ctx).
+		Into(result)
+	return
+}
+
+// Watch returns a watch.Interface that watches the requested openShiftPipelinesAsCodes.
+func (c *openShiftPipelinesAsCodes) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
+	var timeout time.Duration
+	if opts.TimeoutSeconds != nil {
+		timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
+	}
+	opts.Watch = true
+	return c.client.Get().
+		Resource("openshiftpipelinesascodes").
+		VersionedParams(&opts, scheme.ParameterCodec).
+		Timeout(timeout).
+		Watch(ctx)
+}
+
+// Create takes the representation of a openShiftPipelinesAsCode and creates it.  Returns the server's representation of the openShiftPipelinesAsCode, and an error, if there is any.
+func (c *openShiftPipelinesAsCodes) Create(ctx context.Context, openShiftPipelinesAsCode *v1alpha1.OpenShiftPipelinesAsCode, opts v1.CreateOptions) (result *v1alpha1.OpenShiftPipelinesAsCode, err error) {
+	result = &v1alpha1.OpenShiftPipelinesAsCode{}
+	err = c.client.Post().
+		Resource("openshiftpipelinesascodes").
+		VersionedParams(&opts, scheme.ParameterCodec).
+		Body(openShiftPipelinesAsCode).
+		Do(ctx).
+		Into(result)
+	return
+}
+
+// Update takes the representation of a openShiftPipelinesAsCode and updates it. Returns the server's representation of the openShiftPipelinesAsCode, and an error, if there is any.
+func (c *openShiftPipelinesAsCodes) Update(ctx context.Context, openShiftPipelinesAsCode *v1alpha1.OpenShiftPipelinesAsCode, opts v1.UpdateOptions) (result *v1alpha1.OpenShiftPipelinesAsCode, err error) {
+	result = &v1alpha1.OpenShiftPipelinesAsCode{}
+	err = c.client.Put().
+		Resource("openshiftpipelinesascodes").
+		Name(openShiftPipelinesAsCode.Name).
+		VersionedParams(&opts, scheme.ParameterCodec).
+		Body(openShiftPipelinesAsCode).
+		Do(ctx).
+		Into(result)
+	return
+}
+
+// UpdateStatus was generated because the type contains a Status member.
+// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
+func (c *openShiftPipelinesAsCodes) UpdateStatus(ctx context.Context, openShiftPipelinesAsCode *v1alpha1.OpenShiftPipelinesAsCode, opts v1.UpdateOptions) (result *v1alpha1.OpenShiftPipelinesAsCode, err error) {
+	result = &v1alpha1.OpenShiftPipelinesAsCode{}
+	err = c.client.Put().
+		Resource("openshiftpipelinesascodes").
+		Name(openShiftPipelinesAsCode.Name).
+		SubResource("status").
+		VersionedParams(&opts, scheme.ParameterCodec).
+		Body(openShiftPipelinesAsCode).
+		Do(ctx).
+		Into(result)
+	return
+}
+
+// Delete takes name of the openShiftPipelinesAsCode and deletes it. Returns an error if one occurs.
+func (c *openShiftPipelinesAsCodes) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
+	return c.client.Delete().
+		Resource("openshiftpipelinesascodes").
+		Name(name).
+		Body(&opts).
+		Do(ctx).
+		Error()
+}
+
+// DeleteCollection deletes a collection of objects.
+func (c *openShiftPipelinesAsCodes) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
+	var timeout time.Duration
+	if listOpts.TimeoutSeconds != nil {
+		timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
+	}
+	return c.client.Delete().
+		Resource("openshiftpipelinesascodes").
+		VersionedParams(&listOpts, scheme.ParameterCodec).
+		Timeout(timeout).
+		Body(&opts).
+		Do(ctx).
+		Error()
+}
+
+// Patch applies the patch and returns the patched openShiftPipelinesAsCode.
+func (c *openShiftPipelinesAsCodes) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.OpenShiftPipelinesAsCode, err error) {
+	result = &v1alpha1.OpenShiftPipelinesAsCode{}
+	err = c.client.Patch(pt).
+		Resource("openshiftpipelinesascodes").
+		Name(name).
+		SubResource(subresources...).
+		VersionedParams(&opts, scheme.ParameterCodec).
+		Body(data).
+		Do(ctx).
+		Into(result)
+	return
+}
diff --git a/pkg/client/clientset/versioned/typed/operator/v1alpha1/operator_client.go b/pkg/client/clientset/versioned/typed/operator/v1alpha1/operator_client.go
index 4e69e1884..879e4f9f7 100644
--- a/pkg/client/clientset/versioned/typed/operator/v1alpha1/operator_client.go
+++ b/pkg/client/clientset/versioned/typed/operator/v1alpha1/operator_client.go
@@ -28,6 +28,7 @@ import (
 
 type OperatorV1alpha1Interface interface {
 	RESTClient() rest.Interface
+	OpenShiftPipelinesAsCodesGetter
 	TektonAddonsGetter
 	TektonChainsGetter
 	TektonConfigsGetter
@@ -44,6 +45,10 @@ type OperatorV1alpha1Client struct {
 	restClient rest.Interface
 }
 
+func (c *OperatorV1alpha1Client) OpenShiftPipelinesAsCodes() OpenShiftPipelinesAsCodeInterface {
+	return newOpenShiftPipelinesAsCodes(c)
+}
+
 func (c *OperatorV1alpha1Client) TektonAddons() TektonAddonInterface {
 	return newTektonAddons(c)
 }
diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go
index 1464bb83e..de95b5c4f 100644
--- a/pkg/client/informers/externalversions/generic.go
+++ b/pkg/client/informers/externalversions/generic.go
@@ -53,6 +53,8 @@ func (f *genericInformer) Lister() cache.GenericLister {
 func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) {
 	switch resource {
 	// Group=operator.tekton.dev, Version=v1alpha1
+	case v1alpha1.SchemeGroupVersion.WithResource("openshiftpipelinesascodes"):
+		return &genericInformer{resource: resource.GroupResource(), informer: f.Operator().V1alpha1().OpenShiftPipelinesAsCodes().Informer()}, nil
 	case v1alpha1.SchemeGroupVersion.WithResource("tektonaddons"):
 		return &genericInformer{resource: resource.GroupResource(), informer: f.Operator().V1alpha1().TektonAddons().Informer()}, nil
 	case v1alpha1.SchemeGroupVersion.WithResource("tektonchains"):
diff --git a/pkg/client/informers/externalversions/operator/v1alpha1/interface.go b/pkg/client/informers/externalversions/operator/v1alpha1/interface.go
index 3ea6e60fb..40aca3b11 100644
--- a/pkg/client/informers/externalversions/operator/v1alpha1/interface.go
+++ b/pkg/client/informers/externalversions/operator/v1alpha1/interface.go
@@ -24,6 +24,8 @@ import (
 
 // Interface provides access to all the informers in this group version.
 type Interface interface {
+	// OpenShiftPipelinesAsCodes returns a OpenShiftPipelinesAsCodeInformer.
+	OpenShiftPipelinesAsCodes() OpenShiftPipelinesAsCodeInformer
 	// TektonAddons returns a TektonAddonInformer.
 	TektonAddons() TektonAddonInformer
 	// TektonChains returns a TektonChainInformer.
@@ -55,6 +57,11 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList
 	return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
 }
 
+// OpenShiftPipelinesAsCodes returns a OpenShiftPipelinesAsCodeInformer.
+func (v *version) OpenShiftPipelinesAsCodes() OpenShiftPipelinesAsCodeInformer {
+	return &openShiftPipelinesAsCodeInformer{factory: v.factory, tweakListOptions: v.tweakListOptions}
+}
+
 // TektonAddons returns a TektonAddonInformer.
 func (v *version) TektonAddons() TektonAddonInformer {
 	return &tektonAddonInformer{factory: v.factory, tweakListOptions: v.tweakListOptions}
diff --git a/pkg/client/informers/externalversions/operator/v1alpha1/openshiftpipelinesascode.go b/pkg/client/informers/externalversions/operator/v1alpha1/openshiftpipelinesascode.go
new file mode 100644
index 000000000..927766c23
--- /dev/null
+++ b/pkg/client/informers/externalversions/operator/v1alpha1/openshiftpipelinesascode.go
@@ -0,0 +1,89 @@
+/*
+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.
+*/
+
+// Code generated by informer-gen. DO NOT EDIT.
+
+package v1alpha1
+
+import (
+	"context"
+	time "time"
+
+	operatorv1alpha1 "github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
+	versioned "github.com/tektoncd/operator/pkg/client/clientset/versioned"
+	internalinterfaces "github.com/tektoncd/operator/pkg/client/informers/externalversions/internalinterfaces"
+	v1alpha1 "github.com/tektoncd/operator/pkg/client/listers/operator/v1alpha1"
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	runtime "k8s.io/apimachinery/pkg/runtime"
+	watch "k8s.io/apimachinery/pkg/watch"
+	cache "k8s.io/client-go/tools/cache"
+)
+
+// OpenShiftPipelinesAsCodeInformer provides access to a shared informer and lister for
+// OpenShiftPipelinesAsCodes.
+type OpenShiftPipelinesAsCodeInformer interface {
+	Informer() cache.SharedIndexInformer
+	Lister() v1alpha1.OpenShiftPipelinesAsCodeLister
+}
+
+type openShiftPipelinesAsCodeInformer struct {
+	factory          internalinterfaces.SharedInformerFactory
+	tweakListOptions internalinterfaces.TweakListOptionsFunc
+}
+
+// NewOpenShiftPipelinesAsCodeInformer constructs a new informer for OpenShiftPipelinesAsCode type.
+// Always prefer using an informer factory to get a shared informer instead of getting an independent
+// one. This reduces memory footprint and number of connections to the server.
+func NewOpenShiftPipelinesAsCodeInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
+	return NewFilteredOpenShiftPipelinesAsCodeInformer(client, resyncPeriod, indexers, nil)
+}
+
+// NewFilteredOpenShiftPipelinesAsCodeInformer constructs a new informer for OpenShiftPipelinesAsCode type.
+// Always prefer using an informer factory to get a shared informer instead of getting an independent
+// one. This reduces memory footprint and number of connections to the server.
+func NewFilteredOpenShiftPipelinesAsCodeInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
+	return cache.NewSharedIndexInformer(
+		&cache.ListWatch{
+			ListFunc: func(options v1.ListOptions) (runtime.Object, error) {
+				if tweakListOptions != nil {
+					tweakListOptions(&options)
+				}
+				return client.OperatorV1alpha1().OpenShiftPipelinesAsCodes().List(context.TODO(), options)
+			},
+			WatchFunc: func(options v1.ListOptions) (watch.Interface, error) {
+				if tweakListOptions != nil {
+					tweakListOptions(&options)
+				}
+				return client.OperatorV1alpha1().OpenShiftPipelinesAsCodes().Watch(context.TODO(), options)
+			},
+		},
+		&operatorv1alpha1.OpenShiftPipelinesAsCode{},
+		resyncPeriod,
+		indexers,
+	)
+}
+
+func (f *openShiftPipelinesAsCodeInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
+	return NewFilteredOpenShiftPipelinesAsCodeInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
+}
+
+func (f *openShiftPipelinesAsCodeInformer) Informer() cache.SharedIndexInformer {
+	return f.factory.InformerFor(&operatorv1alpha1.OpenShiftPipelinesAsCode{}, f.defaultInformer)
+}
+
+func (f *openShiftPipelinesAsCodeInformer) Lister() v1alpha1.OpenShiftPipelinesAsCodeLister {
+	return v1alpha1.NewOpenShiftPipelinesAsCodeLister(f.Informer().GetIndexer())
+}
diff --git a/pkg/client/injection/client/client.go b/pkg/client/injection/client/client.go
index caed4e34d..f7a98883f 100644
--- a/pkg/client/injection/client/client.go
+++ b/pkg/client/injection/client/client.go
@@ -111,6 +111,133 @@ func (w *wrapOperatorV1alpha1) RESTClient() rest.Interface {
 	panic("RESTClient called on dynamic client!")
 }
 
+func (w *wrapOperatorV1alpha1) OpenShiftPipelinesAsCodes() typedoperatorv1alpha1.OpenShiftPipelinesAsCodeInterface {
+	return &wrapOperatorV1alpha1OpenShiftPipelinesAsCodeImpl{
+		dyn: w.dyn.Resource(schema.GroupVersionResource{
+			Group:    "operator.tekton.dev",
+			Version:  "v1alpha1",
+			Resource: "openshiftpipelinesascodes",
+		}),
+	}
+}
+
+type wrapOperatorV1alpha1OpenShiftPipelinesAsCodeImpl struct {
+	dyn dynamic.NamespaceableResourceInterface
+}
+
+var _ typedoperatorv1alpha1.OpenShiftPipelinesAsCodeInterface = (*wrapOperatorV1alpha1OpenShiftPipelinesAsCodeImpl)(nil)
+
+func (w *wrapOperatorV1alpha1OpenShiftPipelinesAsCodeImpl) Create(ctx context.Context, in *v1alpha1.OpenShiftPipelinesAsCode, opts v1.CreateOptions) (*v1alpha1.OpenShiftPipelinesAsCode, error) {
+	in.SetGroupVersionKind(schema.GroupVersionKind{
+		Group:   "operator.tekton.dev",
+		Version: "v1alpha1",
+		Kind:    "OpenShiftPipelinesAsCode",
+	})
+	uo := &unstructured.Unstructured{}
+	if err := convert(in, uo); err != nil {
+		return nil, err
+	}
+	uo, err := w.dyn.Create(ctx, uo, opts)
+	if err != nil {
+		return nil, err
+	}
+	out := &v1alpha1.OpenShiftPipelinesAsCode{}
+	if err := convert(uo, out); err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (w *wrapOperatorV1alpha1OpenShiftPipelinesAsCodeImpl) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
+	return w.dyn.Delete(ctx, name, opts)
+}
+
+func (w *wrapOperatorV1alpha1OpenShiftPipelinesAsCodeImpl) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
+	return w.dyn.DeleteCollection(ctx, opts, listOpts)
+}
+
+func (w *wrapOperatorV1alpha1OpenShiftPipelinesAsCodeImpl) Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.OpenShiftPipelinesAsCode, error) {
+	uo, err := w.dyn.Get(ctx, name, opts)
+	if err != nil {
+		return nil, err
+	}
+	out := &v1alpha1.OpenShiftPipelinesAsCode{}
+	if err := convert(uo, out); err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (w *wrapOperatorV1alpha1OpenShiftPipelinesAsCodeImpl) List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.OpenShiftPipelinesAsCodeList, error) {
+	uo, err := w.dyn.List(ctx, opts)
+	if err != nil {
+		return nil, err
+	}
+	out := &v1alpha1.OpenShiftPipelinesAsCodeList{}
+	if err := convert(uo, out); err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (w *wrapOperatorV1alpha1OpenShiftPipelinesAsCodeImpl) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.OpenShiftPipelinesAsCode, err error) {
+	uo, err := w.dyn.Patch(ctx, name, pt, data, opts)
+	if err != nil {
+		return nil, err
+	}
+	out := &v1alpha1.OpenShiftPipelinesAsCode{}
+	if err := convert(uo, out); err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (w *wrapOperatorV1alpha1OpenShiftPipelinesAsCodeImpl) Update(ctx context.Context, in *v1alpha1.OpenShiftPipelinesAsCode, opts v1.UpdateOptions) (*v1alpha1.OpenShiftPipelinesAsCode, error) {
+	in.SetGroupVersionKind(schema.GroupVersionKind{
+		Group:   "operator.tekton.dev",
+		Version: "v1alpha1",
+		Kind:    "OpenShiftPipelinesAsCode",
+	})
+	uo := &unstructured.Unstructured{}
+	if err := convert(in, uo); err != nil {
+		return nil, err
+	}
+	uo, err := w.dyn.Update(ctx, uo, opts)
+	if err != nil {
+		return nil, err
+	}
+	out := &v1alpha1.OpenShiftPipelinesAsCode{}
+	if err := convert(uo, out); err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (w *wrapOperatorV1alpha1OpenShiftPipelinesAsCodeImpl) UpdateStatus(ctx context.Context, in *v1alpha1.OpenShiftPipelinesAsCode, opts v1.UpdateOptions) (*v1alpha1.OpenShiftPipelinesAsCode, error) {
+	in.SetGroupVersionKind(schema.GroupVersionKind{
+		Group:   "operator.tekton.dev",
+		Version: "v1alpha1",
+		Kind:    "OpenShiftPipelinesAsCode",
+	})
+	uo := &unstructured.Unstructured{}
+	if err := convert(in, uo); err != nil {
+		return nil, err
+	}
+	uo, err := w.dyn.UpdateStatus(ctx, uo, opts)
+	if err != nil {
+		return nil, err
+	}
+	out := &v1alpha1.OpenShiftPipelinesAsCode{}
+	if err := convert(uo, out); err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
+func (w *wrapOperatorV1alpha1OpenShiftPipelinesAsCodeImpl) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
+	return nil, errors.New("NYI: Watch")
+}
+
 func (w *wrapOperatorV1alpha1) TektonAddons() typedoperatorv1alpha1.TektonAddonInterface {
 	return &wrapOperatorV1alpha1TektonAddonImpl{
 		dyn: w.dyn.Resource(schema.GroupVersionResource{
diff --git a/pkg/client/injection/informers/operator/v1alpha1/openshiftpipelinesascode/fake/fake.go b/pkg/client/injection/informers/operator/v1alpha1/openshiftpipelinesascode/fake/fake.go
new file mode 100644
index 000000000..6a90aaf84
--- /dev/null
+++ b/pkg/client/injection/informers/operator/v1alpha1/openshiftpipelinesascode/fake/fake.go
@@ -0,0 +1,40 @@
+/*
+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.
+*/
+
+// Code generated by injection-gen. DO NOT EDIT.
+
+package fake
+
+import (
+	context "context"
+
+	fake "github.com/tektoncd/operator/pkg/client/injection/informers/factory/fake"
+	openshiftpipelinesascode "github.com/tektoncd/operator/pkg/client/injection/informers/operator/v1alpha1/openshiftpipelinesascode"
+	controller "knative.dev/pkg/controller"
+	injection "knative.dev/pkg/injection"
+)
+
+var Get = openshiftpipelinesascode.Get
+
+func init() {
+	injection.Fake.RegisterInformer(withInformer)
+}
+
+func withInformer(ctx context.Context) (context.Context, controller.Informer) {
+	f := fake.Get(ctx)
+	inf := f.Operator().V1alpha1().OpenShiftPipelinesAsCodes()
+	return context.WithValue(ctx, openshiftpipelinesascode.Key{}, inf), inf.Informer()
+}
diff --git a/pkg/client/injection/informers/operator/v1alpha1/openshiftpipelinesascode/filtered/fake/fake.go b/pkg/client/injection/informers/operator/v1alpha1/openshiftpipelinesascode/filtered/fake/fake.go
new file mode 100644
index 000000000..524ca291a
--- /dev/null
+++ b/pkg/client/injection/informers/operator/v1alpha1/openshiftpipelinesascode/filtered/fake/fake.go
@@ -0,0 +1,52 @@
+/*
+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.
+*/
+
+// Code generated by injection-gen. DO NOT EDIT.
+
+package fake
+
+import (
+	context "context"
+
+	factoryfiltered "github.com/tektoncd/operator/pkg/client/injection/informers/factory/filtered"
+	filtered "github.com/tektoncd/operator/pkg/client/injection/informers/operator/v1alpha1/openshiftpipelinesascode/filtered"
+	controller "knative.dev/pkg/controller"
+	injection "knative.dev/pkg/injection"
+	logging "knative.dev/pkg/logging"
+)
+
+var Get = filtered.Get
+
+func init() {
+	injection.Fake.RegisterFilteredInformers(withInformer)
+}
+
+func withInformer(ctx context.Context) (context.Context, []controller.Informer) {
+	untyped := ctx.Value(factoryfiltered.LabelKey{})
+	if untyped == nil {
+		logging.FromContext(ctx).Panic(
+			"Unable to fetch labelkey from context.")
+	}
+	labelSelectors := untyped.([]string)
+	infs := []controller.Informer{}
+	for _, selector := range labelSelectors {
+		f := factoryfiltered.Get(ctx, selector)
+		inf := f.Operator().V1alpha1().OpenShiftPipelinesAsCodes()
+		ctx = context.WithValue(ctx, filtered.Key{Selector: selector}, inf)
+		infs = append(infs, inf.Informer())
+	}
+	return ctx, infs
+}
diff --git a/pkg/client/injection/informers/operator/v1alpha1/openshiftpipelinesascode/filtered/openshiftpipelinesascode.go b/pkg/client/injection/informers/operator/v1alpha1/openshiftpipelinesascode/filtered/openshiftpipelinesascode.go
new file mode 100644
index 000000000..207fff1d5
--- /dev/null
+++ b/pkg/client/injection/informers/operator/v1alpha1/openshiftpipelinesascode/filtered/openshiftpipelinesascode.go
@@ -0,0 +1,130 @@
+/*
+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.
+*/
+
+// Code generated by injection-gen. DO NOT EDIT.
+
+package filtered
+
+import (
+	context "context"
+
+	apisoperatorv1alpha1 "github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
+	versioned "github.com/tektoncd/operator/pkg/client/clientset/versioned"
+	v1alpha1 "github.com/tektoncd/operator/pkg/client/informers/externalversions/operator/v1alpha1"
+	client "github.com/tektoncd/operator/pkg/client/injection/client"
+	filtered "github.com/tektoncd/operator/pkg/client/injection/informers/factory/filtered"
+	operatorv1alpha1 "github.com/tektoncd/operator/pkg/client/listers/operator/v1alpha1"
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	labels "k8s.io/apimachinery/pkg/labels"
+	cache "k8s.io/client-go/tools/cache"
+	controller "knative.dev/pkg/controller"
+	injection "knative.dev/pkg/injection"
+	logging "knative.dev/pkg/logging"
+)
+
+func init() {
+	injection.Default.RegisterFilteredInformers(withInformer)
+	injection.Dynamic.RegisterDynamicInformer(withDynamicInformer)
+}
+
+// Key is used for associating the Informer inside the context.Context.
+type Key struct {
+	Selector string
+}
+
+func withInformer(ctx context.Context) (context.Context, []controller.Informer) {
+	untyped := ctx.Value(filtered.LabelKey{})
+	if untyped == nil {
+		logging.FromContext(ctx).Panic(
+			"Unable to fetch labelkey from context.")
+	}
+	labelSelectors := untyped.([]string)
+	infs := []controller.Informer{}
+	for _, selector := range labelSelectors {
+		f := filtered.Get(ctx, selector)
+		inf := f.Operator().V1alpha1().OpenShiftPipelinesAsCodes()
+		ctx = context.WithValue(ctx, Key{Selector: selector}, inf)
+		infs = append(infs, inf.Informer())
+	}
+	return ctx, infs
+}
+
+func withDynamicInformer(ctx context.Context) context.Context {
+	untyped := ctx.Value(filtered.LabelKey{})
+	if untyped == nil {
+		logging.FromContext(ctx).Panic(
+			"Unable to fetch labelkey from context.")
+	}
+	labelSelectors := untyped.([]string)
+	for _, selector := range labelSelectors {
+		inf := &wrapper{client: client.Get(ctx), selector: selector}
+		ctx = context.WithValue(ctx, Key{Selector: selector}, inf)
+	}
+	return ctx
+}
+
+// Get extracts the typed informer from the context.
+func Get(ctx context.Context, selector string) v1alpha1.OpenShiftPipelinesAsCodeInformer {
+	untyped := ctx.Value(Key{Selector: selector})
+	if untyped == nil {
+		logging.FromContext(ctx).Panicf(
+			"Unable to fetch github.com/tektoncd/operator/pkg/client/informers/externalversions/operator/v1alpha1.OpenShiftPipelinesAsCodeInformer with selector %s from context.", selector)
+	}
+	return untyped.(v1alpha1.OpenShiftPipelinesAsCodeInformer)
+}
+
+type wrapper struct {
+	client versioned.Interface
+
+	selector string
+}
+
+var _ v1alpha1.OpenShiftPipelinesAsCodeInformer = (*wrapper)(nil)
+var _ operatorv1alpha1.OpenShiftPipelinesAsCodeLister = (*wrapper)(nil)
+
+func (w *wrapper) Informer() cache.SharedIndexInformer {
+	return cache.NewSharedIndexInformer(nil, &apisoperatorv1alpha1.OpenShiftPipelinesAsCode{}, 0, nil)
+}
+
+func (w *wrapper) Lister() operatorv1alpha1.OpenShiftPipelinesAsCodeLister {
+	return w
+}
+
+func (w *wrapper) List(selector labels.Selector) (ret []*apisoperatorv1alpha1.OpenShiftPipelinesAsCode, err error) {
+	reqs, err := labels.ParseToRequirements(w.selector)
+	if err != nil {
+		return nil, err
+	}
+	selector = selector.Add(reqs...)
+	lo, err := w.client.OperatorV1alpha1().OpenShiftPipelinesAsCodes().List(context.TODO(), v1.ListOptions{
+		LabelSelector: selector.String(),
+		// TODO(mattmoor): Incorporate resourceVersion bounds based on staleness criteria.
+	})
+	if err != nil {
+		return nil, err
+	}
+	for idx := range lo.Items {
+		ret = append(ret, &lo.Items[idx])
+	}
+	return ret, nil
+}
+
+func (w *wrapper) Get(name string) (*apisoperatorv1alpha1.OpenShiftPipelinesAsCode, error) {
+	// TODO(mattmoor): Check that the fetched object matches the selector.
+	return w.client.OperatorV1alpha1().OpenShiftPipelinesAsCodes().Get(context.TODO(), name, v1.GetOptions{
+		// TODO(mattmoor): Incorporate resourceVersion bounds based on staleness criteria.
+	})
+}
diff --git a/pkg/client/injection/informers/operator/v1alpha1/openshiftpipelinesascode/openshiftpipelinesascode.go b/pkg/client/injection/informers/operator/v1alpha1/openshiftpipelinesascode/openshiftpipelinesascode.go
new file mode 100644
index 000000000..0b5366ee6
--- /dev/null
+++ b/pkg/client/injection/informers/operator/v1alpha1/openshiftpipelinesascode/openshiftpipelinesascode.go
@@ -0,0 +1,110 @@
+/*
+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.
+*/
+
+// Code generated by injection-gen. DO NOT EDIT.
+
+package openshiftpipelinesascode
+
+import (
+	context "context"
+
+	apisoperatorv1alpha1 "github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
+	versioned "github.com/tektoncd/operator/pkg/client/clientset/versioned"
+	v1alpha1 "github.com/tektoncd/operator/pkg/client/informers/externalversions/operator/v1alpha1"
+	client "github.com/tektoncd/operator/pkg/client/injection/client"
+	factory "github.com/tektoncd/operator/pkg/client/injection/informers/factory"
+	operatorv1alpha1 "github.com/tektoncd/operator/pkg/client/listers/operator/v1alpha1"
+	v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	labels "k8s.io/apimachinery/pkg/labels"
+	cache "k8s.io/client-go/tools/cache"
+	controller "knative.dev/pkg/controller"
+	injection "knative.dev/pkg/injection"
+	logging "knative.dev/pkg/logging"
+)
+
+func init() {
+	injection.Default.RegisterInformer(withInformer)
+	injection.Dynamic.RegisterDynamicInformer(withDynamicInformer)
+}
+
+// Key is used for associating the Informer inside the context.Context.
+type Key struct{}
+
+func withInformer(ctx context.Context) (context.Context, controller.Informer) {
+	f := factory.Get(ctx)
+	inf := f.Operator().V1alpha1().OpenShiftPipelinesAsCodes()
+	return context.WithValue(ctx, Key{}, inf), inf.Informer()
+}
+
+func withDynamicInformer(ctx context.Context) context.Context {
+	inf := &wrapper{client: client.Get(ctx), resourceVersion: injection.GetResourceVersion(ctx)}
+	return context.WithValue(ctx, Key{}, inf)
+}
+
+// Get extracts the typed informer from the context.
+func Get(ctx context.Context) v1alpha1.OpenShiftPipelinesAsCodeInformer {
+	untyped := ctx.Value(Key{})
+	if untyped == nil {
+		logging.FromContext(ctx).Panic(
+			"Unable to fetch github.com/tektoncd/operator/pkg/client/informers/externalversions/operator/v1alpha1.OpenShiftPipelinesAsCodeInformer from context.")
+	}
+	return untyped.(v1alpha1.OpenShiftPipelinesAsCodeInformer)
+}
+
+type wrapper struct {
+	client versioned.Interface
+
+	resourceVersion string
+}
+
+var _ v1alpha1.OpenShiftPipelinesAsCodeInformer = (*wrapper)(nil)
+var _ operatorv1alpha1.OpenShiftPipelinesAsCodeLister = (*wrapper)(nil)
+
+func (w *wrapper) Informer() cache.SharedIndexInformer {
+	return cache.NewSharedIndexInformer(nil, &apisoperatorv1alpha1.OpenShiftPipelinesAsCode{}, 0, nil)
+}
+
+func (w *wrapper) Lister() operatorv1alpha1.OpenShiftPipelinesAsCodeLister {
+	return w
+}
+
+// SetResourceVersion allows consumers to adjust the minimum resourceVersion
+// used by the underlying client.  It is not accessible via the standard
+// lister interface, but can be accessed through a user-defined interface and
+// an implementation check e.g. rvs, ok := foo.(ResourceVersionSetter)
+func (w *wrapper) SetResourceVersion(resourceVersion string) {
+	w.resourceVersion = resourceVersion
+}
+
+func (w *wrapper) List(selector labels.Selector) (ret []*apisoperatorv1alpha1.OpenShiftPipelinesAsCode, err error) {
+	lo, err := w.client.OperatorV1alpha1().OpenShiftPipelinesAsCodes().List(context.TODO(), v1.ListOptions{
+		LabelSelector:   selector.String(),
+		ResourceVersion: w.resourceVersion,
+	})
+	if err != nil {
+		return nil, err
+	}
+	for idx := range lo.Items {
+		ret = append(ret, &lo.Items[idx])
+	}
+	return ret, nil
+}
+
+func (w *wrapper) Get(name string) (*apisoperatorv1alpha1.OpenShiftPipelinesAsCode, error) {
+	return w.client.OperatorV1alpha1().OpenShiftPipelinesAsCodes().Get(context.TODO(), name, v1.GetOptions{
+		ResourceVersion: w.resourceVersion,
+	})
+}
diff --git a/pkg/client/injection/reconciler/operator/v1alpha1/openshiftpipelinesascode/controller.go b/pkg/client/injection/reconciler/operator/v1alpha1/openshiftpipelinesascode/controller.go
new file mode 100644
index 000000000..4e02271a9
--- /dev/null
+++ b/pkg/client/injection/reconciler/operator/v1alpha1/openshiftpipelinesascode/controller.go
@@ -0,0 +1,162 @@
+/*
+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.
+*/
+
+// Code generated by injection-gen. DO NOT EDIT.
+
+package openshiftpipelinesascode
+
+import (
+	context "context"
+	fmt "fmt"
+	reflect "reflect"
+	strings "strings"
+
+	versionedscheme "github.com/tektoncd/operator/pkg/client/clientset/versioned/scheme"
+	client "github.com/tektoncd/operator/pkg/client/injection/client"
+	openshiftpipelinesascode "github.com/tektoncd/operator/pkg/client/injection/informers/operator/v1alpha1/openshiftpipelinesascode"
+	zap "go.uber.org/zap"
+	corev1 "k8s.io/api/core/v1"
+	labels "k8s.io/apimachinery/pkg/labels"
+	types "k8s.io/apimachinery/pkg/types"
+	watch "k8s.io/apimachinery/pkg/watch"
+	scheme "k8s.io/client-go/kubernetes/scheme"
+	v1 "k8s.io/client-go/kubernetes/typed/core/v1"
+	record "k8s.io/client-go/tools/record"
+	kubeclient "knative.dev/pkg/client/injection/kube/client"
+	controller "knative.dev/pkg/controller"
+	logging "knative.dev/pkg/logging"
+	logkey "knative.dev/pkg/logging/logkey"
+	reconciler "knative.dev/pkg/reconciler"
+)
+
+const (
+	defaultControllerAgentName = "openshiftpipelinesascode-controller"
+	defaultFinalizerName       = "openshiftpipelinesascodes.operator.tekton.dev"
+)
+
+// NewImpl returns a controller.Impl that handles queuing and feeding work from
+// the queue through an implementation of controller.Reconciler, delegating to
+// the provided Interface and optional Finalizer methods. OptionsFn is used to return
+// controller.ControllerOptions to be used by the internal reconciler.
+func NewImpl(ctx context.Context, r Interface, optionsFns ...controller.OptionsFn) *controller.Impl {
+	logger := logging.FromContext(ctx)
+
+	// Check the options function input. It should be 0 or 1.
+	if len(optionsFns) > 1 {
+		logger.Fatal("Up to one options function is supported, found: ", len(optionsFns))
+	}
+
+	openshiftpipelinesascodeInformer := openshiftpipelinesascode.Get(ctx)
+
+	lister := openshiftpipelinesascodeInformer.Lister()
+
+	var promoteFilterFunc func(obj interface{}) bool
+
+	rec := &reconcilerImpl{
+		LeaderAwareFuncs: reconciler.LeaderAwareFuncs{
+			PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error {
+				all, err := lister.List(labels.Everything())
+				if err != nil {
+					return err
+				}
+				for _, elt := range all {
+					if promoteFilterFunc != nil {
+						if ok := promoteFilterFunc(elt); !ok {
+							continue
+						}
+					}
+					enq(bkt, types.NamespacedName{
+						Namespace: elt.GetNamespace(),
+						Name:      elt.GetName(),
+					})
+				}
+				return nil
+			},
+		},
+		Client:        client.Get(ctx),
+		Lister:        lister,
+		reconciler:    r,
+		finalizerName: defaultFinalizerName,
+	}
+
+	ctrType := reflect.TypeOf(r).Elem()
+	ctrTypeName := fmt.Sprintf("%s.%s", ctrType.PkgPath(), ctrType.Name())
+	ctrTypeName = strings.ReplaceAll(ctrTypeName, "/", ".")
+
+	logger = logger.With(
+		zap.String(logkey.ControllerType, ctrTypeName),
+		zap.String(logkey.Kind, "operator.tekton.dev.OpenShiftPipelinesAsCode"),
+	)
+
+	impl := controller.NewContext(ctx, rec, controller.ControllerOptions{WorkQueueName: ctrTypeName, Logger: logger})
+	agentName := defaultControllerAgentName
+
+	// Pass impl to the options. Save any optional results.
+	for _, fn := range optionsFns {
+		opts := fn(impl)
+		if opts.ConfigStore != nil {
+			rec.configStore = opts.ConfigStore
+		}
+		if opts.FinalizerName != "" {
+			rec.finalizerName = opts.FinalizerName
+		}
+		if opts.AgentName != "" {
+			agentName = opts.AgentName
+		}
+		if opts.SkipStatusUpdates {
+			rec.skipStatusUpdates = true
+		}
+		if opts.DemoteFunc != nil {
+			rec.DemoteFunc = opts.DemoteFunc
+		}
+		if opts.PromoteFilterFunc != nil {
+			promoteFilterFunc = opts.PromoteFilterFunc
+		}
+	}
+
+	rec.Recorder = createRecorder(ctx, agentName)
+
+	return impl
+}
+
+func createRecorder(ctx context.Context, agentName string) record.EventRecorder {
+	logger := logging.FromContext(ctx)
+
+	recorder := controller.GetEventRecorder(ctx)
+	if recorder == nil {
+		// Create event broadcaster
+		logger.Debug("Creating event broadcaster")
+		eventBroadcaster := record.NewBroadcaster()
+		watches := []watch.Interface{
+			eventBroadcaster.StartLogging(logger.Named("event-broadcaster").Infof),
+			eventBroadcaster.StartRecordingToSink(
+				&v1.EventSinkImpl{Interface: kubeclient.Get(ctx).CoreV1().Events("")}),
+		}
+		recorder = eventBroadcaster.NewRecorder(scheme.Scheme, corev1.EventSource{Component: agentName})
+		go func() {
+			<-ctx.Done()
+			for _, w := range watches {
+				w.Stop()
+			}
+		}()
+	}
+
+	return recorder
+}
+
+func init() {
+	versionedscheme.AddToScheme(scheme.Scheme)
+}
diff --git a/pkg/client/injection/reconciler/operator/v1alpha1/openshiftpipelinesascode/reconciler.go b/pkg/client/injection/reconciler/operator/v1alpha1/openshiftpipelinesascode/reconciler.go
new file mode 100644
index 000000000..4e3714bfc
--- /dev/null
+++ b/pkg/client/injection/reconciler/operator/v1alpha1/openshiftpipelinesascode/reconciler.go
@@ -0,0 +1,442 @@
+/*
+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.
+*/
+
+// Code generated by injection-gen. DO NOT EDIT.
+
+package openshiftpipelinesascode
+
+import (
+	context "context"
+	json "encoding/json"
+	fmt "fmt"
+
+	v1alpha1 "github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
+	versioned "github.com/tektoncd/operator/pkg/client/clientset/versioned"
+	operatorv1alpha1 "github.com/tektoncd/operator/pkg/client/listers/operator/v1alpha1"
+	zap "go.uber.org/zap"
+	v1 "k8s.io/api/core/v1"
+	equality "k8s.io/apimachinery/pkg/api/equality"
+	errors "k8s.io/apimachinery/pkg/api/errors"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	labels "k8s.io/apimachinery/pkg/labels"
+	types "k8s.io/apimachinery/pkg/types"
+	sets "k8s.io/apimachinery/pkg/util/sets"
+	record "k8s.io/client-go/tools/record"
+	controller "knative.dev/pkg/controller"
+	kmp "knative.dev/pkg/kmp"
+	logging "knative.dev/pkg/logging"
+	reconciler "knative.dev/pkg/reconciler"
+)
+
+// Interface defines the strongly typed interfaces to be implemented by a
+// controller reconciling v1alpha1.OpenShiftPipelinesAsCode.
+type Interface interface {
+	// ReconcileKind implements custom logic to reconcile v1alpha1.OpenShiftPipelinesAsCode. Any changes
+	// to the objects .Status or .Finalizers will be propagated to the stored
+	// object. It is recommended that implementors do not call any update calls
+	// for the Kind inside of ReconcileKind, it is the responsibility of the calling
+	// controller to propagate those properties. The resource passed to ReconcileKind
+	// will always have an empty deletion timestamp.
+	ReconcileKind(ctx context.Context, o *v1alpha1.OpenShiftPipelinesAsCode) reconciler.Event
+}
+
+// Finalizer defines the strongly typed interfaces to be implemented by a
+// controller finalizing v1alpha1.OpenShiftPipelinesAsCode.
+type Finalizer interface {
+	// FinalizeKind implements custom logic to finalize v1alpha1.OpenShiftPipelinesAsCode. Any changes
+	// to the objects .Status or .Finalizers will be ignored. Returning a nil or
+	// Normal type reconciler.Event will allow the finalizer to be deleted on
+	// the resource. The resource passed to FinalizeKind will always have a set
+	// deletion timestamp.
+	FinalizeKind(ctx context.Context, o *v1alpha1.OpenShiftPipelinesAsCode) reconciler.Event
+}
+
+// ReadOnlyInterface defines the strongly typed interfaces to be implemented by a
+// controller reconciling v1alpha1.OpenShiftPipelinesAsCode if they want to process resources for which
+// they are not the leader.
+type ReadOnlyInterface interface {
+	// ObserveKind implements logic to observe v1alpha1.OpenShiftPipelinesAsCode.
+	// This method should not write to the API.
+	ObserveKind(ctx context.Context, o *v1alpha1.OpenShiftPipelinesAsCode) reconciler.Event
+}
+
+type doReconcile func(ctx context.Context, o *v1alpha1.OpenShiftPipelinesAsCode) reconciler.Event
+
+// reconcilerImpl implements controller.Reconciler for v1alpha1.OpenShiftPipelinesAsCode resources.
+type reconcilerImpl struct {
+	// LeaderAwareFuncs is inlined to help us implement reconciler.LeaderAware.
+	reconciler.LeaderAwareFuncs
+
+	// Client is used to write back status updates.
+	Client versioned.Interface
+
+	// Listers index properties about resources.
+	Lister operatorv1alpha1.OpenShiftPipelinesAsCodeLister
+
+	// Recorder is an event recorder for recording Event resources to the
+	// Kubernetes API.
+	Recorder record.EventRecorder
+
+	// configStore allows for decorating a context with config maps.
+	// +optional
+	configStore reconciler.ConfigStore
+
+	// reconciler is the implementation of the business logic of the resource.
+	reconciler Interface
+
+	// finalizerName is the name of the finalizer to reconcile.
+	finalizerName string
+
+	// skipStatusUpdates configures whether or not this reconciler automatically updates
+	// the status of the reconciled resource.
+	skipStatusUpdates bool
+}
+
+// Check that our Reconciler implements controller.Reconciler.
+var _ controller.Reconciler = (*reconcilerImpl)(nil)
+
+// Check that our generated Reconciler is always LeaderAware.
+var _ reconciler.LeaderAware = (*reconcilerImpl)(nil)
+
+func NewReconciler(ctx context.Context, logger *zap.SugaredLogger, client versioned.Interface, lister operatorv1alpha1.OpenShiftPipelinesAsCodeLister, recorder record.EventRecorder, r Interface, options ...controller.Options) controller.Reconciler {
+	// Check the options function input. It should be 0 or 1.
+	if len(options) > 1 {
+		logger.Fatal("Up to one options struct is supported, found: ", len(options))
+	}
+
+	// Fail fast when users inadvertently implement the other LeaderAware interface.
+	// For the typed reconcilers, Promote shouldn't take any arguments.
+	if _, ok := r.(reconciler.LeaderAware); ok {
+		logger.Fatalf("%T implements the incorrect LeaderAware interface. Promote() should not take an argument as genreconciler handles the enqueuing automatically.", r)
+	}
+
+	rec := &reconcilerImpl{
+		LeaderAwareFuncs: reconciler.LeaderAwareFuncs{
+			PromoteFunc: func(bkt reconciler.Bucket, enq func(reconciler.Bucket, types.NamespacedName)) error {
+				all, err := lister.List(labels.Everything())
+				if err != nil {
+					return err
+				}
+				for _, elt := range all {
+					// TODO: Consider letting users specify a filter in options.
+					enq(bkt, types.NamespacedName{
+						Namespace: elt.GetNamespace(),
+						Name:      elt.GetName(),
+					})
+				}
+				return nil
+			},
+		},
+		Client:        client,
+		Lister:        lister,
+		Recorder:      recorder,
+		reconciler:    r,
+		finalizerName: defaultFinalizerName,
+	}
+
+	for _, opts := range options {
+		if opts.ConfigStore != nil {
+			rec.configStore = opts.ConfigStore
+		}
+		if opts.FinalizerName != "" {
+			rec.finalizerName = opts.FinalizerName
+		}
+		if opts.SkipStatusUpdates {
+			rec.skipStatusUpdates = true
+		}
+		if opts.DemoteFunc != nil {
+			rec.DemoteFunc = opts.DemoteFunc
+		}
+	}
+
+	return rec
+}
+
+// Reconcile implements controller.Reconciler
+func (r *reconcilerImpl) Reconcile(ctx context.Context, key string) error {
+	logger := logging.FromContext(ctx)
+
+	// Initialize the reconciler state. This will convert the namespace/name
+	// string into a distinct namespace and name, determine if this instance of
+	// the reconciler is the leader, and any additional interfaces implemented
+	// by the reconciler. Returns an error is the resource key is invalid.
+	s, err := newState(key, r)
+	if err != nil {
+		logger.Error("Invalid resource key: ", key)
+		return nil
+	}
+
+	// If we are not the leader, and we don't implement either ReadOnly
+	// observer interfaces, then take a fast-path out.
+	if s.isNotLeaderNorObserver() {
+		return controller.NewSkipKey(key)
+	}
+
+	// If configStore is set, attach the frozen configuration to the context.
+	if r.configStore != nil {
+		ctx = r.configStore.ToContext(ctx)
+	}
+
+	// Add the recorder to context.
+	ctx = controller.WithEventRecorder(ctx, r.Recorder)
+
+	// Get the resource with this namespace/name.
+
+	getter := r.Lister
+
+	original, err := getter.Get(s.name)
+
+	if errors.IsNotFound(err) {
+		// The resource may no longer exist, in which case we stop processing and call
+		// the ObserveDeletion handler if appropriate.
+		logger.Debugf("Resource %q no longer exists", key)
+		if del, ok := r.reconciler.(reconciler.OnDeletionInterface); ok {
+			return del.ObserveDeletion(ctx, types.NamespacedName{
+				Namespace: s.namespace,
+				Name:      s.name,
+			})
+		}
+		return nil
+	} else if err != nil {
+		return err
+	}
+
+	// Don't modify the informers copy.
+	resource := original.DeepCopy()
+
+	var reconcileEvent reconciler.Event
+
+	name, do := s.reconcileMethodFor(resource)
+	// Append the target method to the logger.
+	logger = logger.With(zap.String("targetMethod", name))
+	switch name {
+	case reconciler.DoReconcileKind:
+		// Set and update the finalizer on resource if r.reconciler
+		// implements Finalizer.
+		if resource, err = r.setFinalizerIfFinalizer(ctx, resource); err != nil {
+			return fmt.Errorf("failed to set finalizers: %w", err)
+		}
+
+		// Reconcile this copy of the resource and then write back any status
+		// updates regardless of whether the reconciliation errored out.
+		reconcileEvent = do(ctx, resource)
+
+	case reconciler.DoFinalizeKind:
+		// For finalizing reconcilers, if this resource being marked for deletion
+		// and reconciled cleanly (nil or normal event), remove the finalizer.
+		reconcileEvent = do(ctx, resource)
+
+		if resource, err = r.clearFinalizer(ctx, resource, reconcileEvent); err != nil {
+			return fmt.Errorf("failed to clear finalizers: %w", err)
+		}
+
+	case reconciler.DoObserveKind:
+		// Observe any changes to this resource, since we are not the leader.
+		reconcileEvent = do(ctx, resource)
+
+	}
+
+	// Synchronize the status.
+	switch {
+	case r.skipStatusUpdates:
+		// This reconciler implementation is configured to skip resource updates.
+		// This may mean this reconciler does not observe spec, but reconciles external changes.
+	case equality.Semantic.DeepEqual(original.Status, resource.Status):
+		// If we didn't change anything then don't call updateStatus.
+		// This is important because the copy we loaded from the injectionInformer's
+		// cache may be stale and we don't want to overwrite a prior update
+		// to status with this stale state.
+	case !s.isLeader:
+		// High-availability reconcilers may have many replicas watching the resource, but only
+		// the elected leader is expected to write modifications.
+		logger.Warn("Saw status changes when we aren't the leader!")
+	default:
+		if err = r.updateStatus(ctx, original, resource); err != nil {
+			logger.Warnw("Failed to update resource status", zap.Error(err))
+			r.Recorder.Eventf(resource, v1.EventTypeWarning, "UpdateFailed",
+				"Failed to update status for %q: %v", resource.Name, err)
+			return err
+		}
+	}
+
+	// Report the reconciler event, if any.
+	if reconcileEvent != nil {
+		var event *reconciler.ReconcilerEvent
+		if reconciler.EventAs(reconcileEvent, &event) {
+			logger.Infow("Returned an event", zap.Any("event", reconcileEvent))
+			r.Recorder.Event(resource, event.EventType, event.Reason, event.Error())
+
+			// the event was wrapped inside an error, consider the reconciliation as failed
+			if _, isEvent := reconcileEvent.(*reconciler.ReconcilerEvent); !isEvent {
+				return reconcileEvent
+			}
+			return nil
+		}
+
+		if controller.IsSkipKey(reconcileEvent) {
+			// This is a wrapped error, don't emit an event.
+		} else if ok, _ := controller.IsRequeueKey(reconcileEvent); ok {
+			// This is a wrapped error, don't emit an event.
+		} else {
+			logger.Errorw("Returned an error", zap.Error(reconcileEvent))
+			r.Recorder.Event(resource, v1.EventTypeWarning, "InternalError", reconcileEvent.Error())
+		}
+		return reconcileEvent
+	}
+
+	return nil
+}
+
+func (r *reconcilerImpl) updateStatus(ctx context.Context, existing *v1alpha1.OpenShiftPipelinesAsCode, desired *v1alpha1.OpenShiftPipelinesAsCode) error {
+	existing = existing.DeepCopy()
+	return reconciler.RetryUpdateConflicts(func(attempts int) (err error) {
+		// The first iteration tries to use the injectionInformer's state, subsequent attempts fetch the latest state via API.
+		if attempts > 0 {
+
+			getter := r.Client.OperatorV1alpha1().OpenShiftPipelinesAsCodes()
+
+			existing, err = getter.Get(ctx, desired.Name, metav1.GetOptions{})
+			if err != nil {
+				return err
+			}
+		}
+
+		// If there's nothing to update, just return.
+		if equality.Semantic.DeepEqual(existing.Status, desired.Status) {
+			return nil
+		}
+
+		if diff, err := kmp.SafeDiff(existing.Status, desired.Status); err == nil && diff != "" {
+			logging.FromContext(ctx).Debug("Updating status with: ", diff)
+		}
+
+		existing.Status = desired.Status
+
+		updater := r.Client.OperatorV1alpha1().OpenShiftPipelinesAsCodes()
+
+		_, err = updater.UpdateStatus(ctx, existing, metav1.UpdateOptions{})
+		return err
+	})
+}
+
+// updateFinalizersFiltered will update the Finalizers of the resource.
+// TODO: this method could be generic and sync all finalizers. For now it only
+// updates defaultFinalizerName or its override.
+func (r *reconcilerImpl) updateFinalizersFiltered(ctx context.Context, resource *v1alpha1.OpenShiftPipelinesAsCode) (*v1alpha1.OpenShiftPipelinesAsCode, error) {
+
+	getter := r.Lister
+
+	actual, err := getter.Get(resource.Name)
+	if err != nil {
+		return resource, err
+	}
+
+	// Don't modify the informers copy.
+	existing := actual.DeepCopy()
+
+	var finalizers []string
+
+	// If there's nothing to update, just return.
+	existingFinalizers := sets.NewString(existing.Finalizers...)
+	desiredFinalizers := sets.NewString(resource.Finalizers...)
+
+	if desiredFinalizers.Has(r.finalizerName) {
+		if existingFinalizers.Has(r.finalizerName) {
+			// Nothing to do.
+			return resource, nil
+		}
+		// Add the finalizer.
+		finalizers = append(existing.Finalizers, r.finalizerName)
+	} else {
+		if !existingFinalizers.Has(r.finalizerName) {
+			// Nothing to do.
+			return resource, nil
+		}
+		// Remove the finalizer.
+		existingFinalizers.Delete(r.finalizerName)
+		finalizers = existingFinalizers.List()
+	}
+
+	mergePatch := map[string]interface{}{
+		"metadata": map[string]interface{}{
+			"finalizers":      finalizers,
+			"resourceVersion": existing.ResourceVersion,
+		},
+	}
+
+	patch, err := json.Marshal(mergePatch)
+	if err != nil {
+		return resource, err
+	}
+
+	patcher := r.Client.OperatorV1alpha1().OpenShiftPipelinesAsCodes()
+
+	resourceName := resource.Name
+	updated, err := patcher.Patch(ctx, resourceName, types.MergePatchType, patch, metav1.PatchOptions{})
+	if err != nil {
+		r.Recorder.Eventf(existing, v1.EventTypeWarning, "FinalizerUpdateFailed",
+			"Failed to update finalizers for %q: %v", resourceName, err)
+	} else {
+		r.Recorder.Eventf(updated, v1.EventTypeNormal, "FinalizerUpdate",
+			"Updated %q finalizers", resource.GetName())
+	}
+	return updated, err
+}
+
+func (r *reconcilerImpl) setFinalizerIfFinalizer(ctx context.Context, resource *v1alpha1.OpenShiftPipelinesAsCode) (*v1alpha1.OpenShiftPipelinesAsCode, error) {
+	if _, ok := r.reconciler.(Finalizer); !ok {
+		return resource, nil
+	}
+
+	finalizers := sets.NewString(resource.Finalizers...)
+
+	// If this resource is not being deleted, mark the finalizer.
+	if resource.GetDeletionTimestamp().IsZero() {
+		finalizers.Insert(r.finalizerName)
+	}
+
+	resource.Finalizers = finalizers.List()
+
+	// Synchronize the finalizers filtered by r.finalizerName.
+	return r.updateFinalizersFiltered(ctx, resource)
+}
+
+func (r *reconcilerImpl) clearFinalizer(ctx context.Context, resource *v1alpha1.OpenShiftPipelinesAsCode, reconcileEvent reconciler.Event) (*v1alpha1.OpenShiftPipelinesAsCode, error) {
+	if _, ok := r.reconciler.(Finalizer); !ok {
+		return resource, nil
+	}
+	if resource.GetDeletionTimestamp().IsZero() {
+		return resource, nil
+	}
+
+	finalizers := sets.NewString(resource.Finalizers...)
+
+	if reconcileEvent != nil {
+		var event *reconciler.ReconcilerEvent
+		if reconciler.EventAs(reconcileEvent, &event) {
+			if event.EventType == v1.EventTypeNormal {
+				finalizers.Delete(r.finalizerName)
+			}
+		}
+	} else {
+		finalizers.Delete(r.finalizerName)
+	}
+
+	resource.Finalizers = finalizers.List()
+
+	// Synchronize the finalizers filtered by r.finalizerName.
+	return r.updateFinalizersFiltered(ctx, resource)
+}
diff --git a/pkg/client/injection/reconciler/operator/v1alpha1/openshiftpipelinesascode/state.go b/pkg/client/injection/reconciler/operator/v1alpha1/openshiftpipelinesascode/state.go
new file mode 100644
index 000000000..066cfbf60
--- /dev/null
+++ b/pkg/client/injection/reconciler/operator/v1alpha1/openshiftpipelinesascode/state.go
@@ -0,0 +1,97 @@
+/*
+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.
+*/
+
+// Code generated by injection-gen. DO NOT EDIT.
+
+package openshiftpipelinesascode
+
+import (
+	fmt "fmt"
+
+	v1alpha1 "github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
+	types "k8s.io/apimachinery/pkg/types"
+	cache "k8s.io/client-go/tools/cache"
+	reconciler "knative.dev/pkg/reconciler"
+)
+
+// state is used to track the state of a reconciler in a single run.
+type state struct {
+	// key is the original reconciliation key from the queue.
+	key string
+	// namespace is the namespace split from the reconciliation key.
+	namespace string
+	// name is the name split from the reconciliation key.
+	name string
+	// reconciler is the reconciler.
+	reconciler Interface
+	// roi is the read only interface cast of the reconciler.
+	roi ReadOnlyInterface
+	// isROI (Read Only Interface) the reconciler only observes reconciliation.
+	isROI bool
+	// isLeader the instance of the reconciler is the elected leader.
+	isLeader bool
+}
+
+func newState(key string, r *reconcilerImpl) (*state, error) {
+	// Convert the namespace/name string into a distinct namespace and name.
+	namespace, name, err := cache.SplitMetaNamespaceKey(key)
+	if err != nil {
+		return nil, fmt.Errorf("invalid resource key: %s", key)
+	}
+
+	roi, isROI := r.reconciler.(ReadOnlyInterface)
+
+	isLeader := r.IsLeaderFor(types.NamespacedName{
+		Namespace: namespace,
+		Name:      name,
+	})
+
+	return &state{
+		key:        key,
+		namespace:  namespace,
+		name:       name,
+		reconciler: r.reconciler,
+		roi:        roi,
+		isROI:      isROI,
+		isLeader:   isLeader,
+	}, nil
+}
+
+// isNotLeaderNorObserver checks to see if this reconciler with the current
+// state is enabled to do any work or not.
+// isNotLeaderNorObserver returns true when there is no work possible for the
+// reconciler.
+func (s *state) isNotLeaderNorObserver() bool {
+	if !s.isLeader && !s.isROI {
+		// If we are not the leader, and we don't implement the ReadOnly
+		// interface, then take a fast-path out.
+		return true
+	}
+	return false
+}
+
+func (s *state) reconcileMethodFor(o *v1alpha1.OpenShiftPipelinesAsCode) (string, doReconcile) {
+	if o.GetDeletionTimestamp().IsZero() {
+		if s.isLeader {
+			return reconciler.DoReconcileKind, s.reconciler.ReconcileKind
+		} else if s.isROI {
+			return reconciler.DoObserveKind, s.roi.ObserveKind
+		}
+	} else if fin, ok := s.reconciler.(Finalizer); s.isLeader && ok {
+		return reconciler.DoFinalizeKind, fin.FinalizeKind
+	}
+	return "unknown", nil
+}
diff --git a/pkg/client/listers/operator/v1alpha1/expansion_generated.go b/pkg/client/listers/operator/v1alpha1/expansion_generated.go
index 88701b8f4..217141461 100644
--- a/pkg/client/listers/operator/v1alpha1/expansion_generated.go
+++ b/pkg/client/listers/operator/v1alpha1/expansion_generated.go
@@ -18,6 +18,10 @@ limitations under the License.
 
 package v1alpha1
 
+// OpenShiftPipelinesAsCodeListerExpansion allows custom methods to be added to
+// OpenShiftPipelinesAsCodeLister.
+type OpenShiftPipelinesAsCodeListerExpansion interface{}
+
 // TektonAddonListerExpansion allows custom methods to be added to
 // TektonAddonLister.
 type TektonAddonListerExpansion interface{}
diff --git a/pkg/client/listers/operator/v1alpha1/openshiftpipelinesascode.go b/pkg/client/listers/operator/v1alpha1/openshiftpipelinesascode.go
new file mode 100644
index 000000000..862573999
--- /dev/null
+++ b/pkg/client/listers/operator/v1alpha1/openshiftpipelinesascode.go
@@ -0,0 +1,68 @@
+/*
+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.
+*/
+
+// Code generated by lister-gen. DO NOT EDIT.
+
+package v1alpha1
+
+import (
+	v1alpha1 "github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
+	"k8s.io/apimachinery/pkg/api/errors"
+	"k8s.io/apimachinery/pkg/labels"
+	"k8s.io/client-go/tools/cache"
+)
+
+// OpenShiftPipelinesAsCodeLister helps list OpenShiftPipelinesAsCodes.
+// All objects returned here must be treated as read-only.
+type OpenShiftPipelinesAsCodeLister interface {
+	// List lists all OpenShiftPipelinesAsCodes in the indexer.
+	// Objects returned here must be treated as read-only.
+	List(selector labels.Selector) (ret []*v1alpha1.OpenShiftPipelinesAsCode, err error)
+	// Get retrieves the OpenShiftPipelinesAsCode from the index for a given name.
+	// Objects returned here must be treated as read-only.
+	Get(name string) (*v1alpha1.OpenShiftPipelinesAsCode, error)
+	OpenShiftPipelinesAsCodeListerExpansion
+}
+
+// openShiftPipelinesAsCodeLister implements the OpenShiftPipelinesAsCodeLister interface.
+type openShiftPipelinesAsCodeLister struct {
+	indexer cache.Indexer
+}
+
+// NewOpenShiftPipelinesAsCodeLister returns a new OpenShiftPipelinesAsCodeLister.
+func NewOpenShiftPipelinesAsCodeLister(indexer cache.Indexer) OpenShiftPipelinesAsCodeLister {
+	return &openShiftPipelinesAsCodeLister{indexer: indexer}
+}
+
+// List lists all OpenShiftPipelinesAsCodes in the indexer.
+func (s *openShiftPipelinesAsCodeLister) List(selector labels.Selector) (ret []*v1alpha1.OpenShiftPipelinesAsCode, err error) {
+	err = cache.ListAll(s.indexer, selector, func(m interface{}) {
+		ret = append(ret, m.(*v1alpha1.OpenShiftPipelinesAsCode))
+	})
+	return ret, err
+}
+
+// Get retrieves the OpenShiftPipelinesAsCode from the index for a given name.
+func (s *openShiftPipelinesAsCodeLister) Get(name string) (*v1alpha1.OpenShiftPipelinesAsCode, error) {
+	obj, exists, err := s.indexer.GetByKey(name)
+	if err != nil {
+		return nil, err
+	}
+	if !exists {
+		return nil, errors.NewNotFound(v1alpha1.Resource("openshiftpipelinesascode"), name)
+	}
+	return obj.(*v1alpha1.OpenShiftPipelinesAsCode), nil
+}
diff --git a/pkg/reconciler/common/common.go b/pkg/reconciler/common/common.go
index e6b141abf..87e07417a 100644
--- a/pkg/reconciler/common/common.go
+++ b/pkg/reconciler/common/common.go
@@ -43,7 +43,7 @@ func PipelineReady(informer informer.TektonPipelineInformer) (*v1alpha1.TektonPi
 		}
 		return nil, err
 	}
-	if strings.Contains(ppln.GetStatus().GetCondition(apis.ConditionReady).Message, v1alpha1.UpgradePending) {
+	if ppln.GetStatus() != nil && strings.Contains(ppln.GetStatus().GetCondition(apis.ConditionReady).Message, v1alpha1.UpgradePending) {
 		return nil, v1alpha1.DEPENDENCY_UPGRADE_PENDING_ERR
 	}
 	if !ppln.Status.IsReady() {
@@ -76,7 +76,7 @@ func TriggerReady(informer informer.TektonTriggerInformer) (*v1alpha1.TektonTrig
 		}
 		return nil, err
 	}
-	if strings.Contains(trigger.GetStatus().GetCondition(apis.ConditionReady).Message, v1alpha1.UpgradePending) {
+	if trigger.GetStatus() != nil && strings.Contains(trigger.GetStatus().GetCondition(apis.ConditionReady).Message, v1alpha1.UpgradePending) {
 		return nil, v1alpha1.DEPENDENCY_UPGRADE_PENDING_ERR
 	}
 	if !trigger.Status.IsReady() {
diff --git a/pkg/reconciler/common/initcontroller.go b/pkg/reconciler/common/initcontroller.go
index 6d957e086..2505742a6 100644
--- a/pkg/reconciler/common/initcontroller.go
+++ b/pkg/reconciler/common/initcontroller.go
@@ -87,28 +87,34 @@ func (ctrl Controller) InitController(ctx context.Context, opts PayloadOptions)
 // fetchSourceManifests mutates the passed manifest by appending one
 // appropriate for the passed TektonComponent
 func (ctrl Controller) fetchSourceManifests(ctx context.Context, opts PayloadOptions) error {
-	switch {
-	case strings.Contains(ctrl.VersionConfigMap, "pipeline"):
+	component := strings.TrimSuffix(ctrl.VersionConfigMap, "-info")
+	switch component {
+	case "pipelines":
 		var pipeline *v1alpha1.TektonPipeline
 		if err := AppendTarget(ctx, ctrl.Manifest, pipeline); err != nil {
 			return err
 		}
 		// add proxy configs to pipeline if any
 		return addProxy(ctrl.Manifest)
-	case strings.Contains(ctrl.VersionConfigMap, "triggers"):
+	case "triggers":
 		var trigger *v1alpha1.TektonTrigger
 		return AppendTarget(ctx, ctrl.Manifest, trigger)
-	case strings.Contains(ctrl.VersionConfigMap, "dashboard") && opts.ReadOnly:
-		var dashboard v1alpha1.TektonDashboard
-		dashboard.Spec.Readonly = true
-		return AppendTarget(ctx, ctrl.Manifest, &dashboard)
-	case strings.Contains(ctrl.VersionConfigMap, "dashboard") && !opts.ReadOnly:
-		var dashboard v1alpha1.TektonDashboard
-		dashboard.Spec.Readonly = false
-		return AppendTarget(ctx, ctrl.Manifest, &dashboard)
-	case strings.Contains(ctrl.VersionConfigMap, "chains"):
+	case "dashboard":
+		if opts.ReadOnly {
+			var dashboard v1alpha1.TektonDashboard
+			dashboard.Spec.Readonly = true
+			return AppendTarget(ctx, ctrl.Manifest, &dashboard)
+		} else {
+			var dashboard v1alpha1.TektonDashboard
+			dashboard.Spec.Readonly = false
+			return AppendTarget(ctx, ctrl.Manifest, &dashboard)
+		}
+	case "chains":
 		var chain v1alpha1.TektonChain
 		return AppendTarget(ctx, ctrl.Manifest, &chain)
+	case "pipelines-as-code":
+		pacLocation := filepath.Join(os.Getenv(KoEnvKey), "tekton-addon", "pipelines-as-code")
+		return AppendManifest(ctrl.Manifest, pacLocation)
 	}
 
 	return nil
diff --git a/pkg/reconciler/openshift/openshiftpipelinesascode/controller.go b/pkg/reconciler/openshift/openshiftpipelinesascode/controller.go
new file mode 100644
index 000000000..121cfaff7
--- /dev/null
+++ b/pkg/reconciler/openshift/openshiftpipelinesascode/controller.go
@@ -0,0 +1,87 @@
+/*
+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.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package openshiftpipelinesascode
+
+import (
+	"context"
+
+	"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
+	operatorclient "github.com/tektoncd/operator/pkg/client/injection/client"
+	pacInformer "github.com/tektoncd/operator/pkg/client/injection/informers/operator/v1alpha1/openshiftpipelinesascode"
+	tektonInstallerinformer "github.com/tektoncd/operator/pkg/client/injection/informers/operator/v1alpha1/tektoninstallerset"
+	tektonPipelineinformer "github.com/tektoncd/operator/pkg/client/injection/informers/operator/v1alpha1/tektonpipeline"
+	pacreconciler "github.com/tektoncd/operator/pkg/client/injection/reconciler/operator/v1alpha1/openshiftpipelinesascode"
+	"github.com/tektoncd/operator/pkg/reconciler/common"
+	"github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektoninstallerset/client"
+	"k8s.io/client-go/tools/cache"
+	"knative.dev/pkg/configmap"
+	"knative.dev/pkg/controller"
+	"knative.dev/pkg/injection"
+	"knative.dev/pkg/logging"
+)
+
+const versionConfigMap = "pipelines-as-code-info"
+
+// NewController initializes the controller and is called by the generated code
+// Registers event handlers to enqueue events
+func NewController(ctx context.Context, cmw configmap.Watcher) *controller.Impl {
+	return NewExtendedController(OpenShiftExtension)(ctx, cmw)
+}
+
+// NewExtendedController returns a controller extended to a specific platform
+func NewExtendedController(generator common.ExtensionGenerator) injection.ControllerConstructor {
+	return func(ctx context.Context, cmw configmap.Watcher) *controller.Impl {
+		logger := logging.FromContext(ctx)
+
+		ctrl := common.Controller{
+			Logger:           logger,
+			VersionConfigMap: versionConfigMap,
+		}
+		manifest, pacVersion := ctrl.InitController(ctx, common.PayloadOptions{})
+
+		operatorVer, err := common.OperatorVersion(ctx)
+		if err != nil {
+			logger.Fatal(err)
+		}
+
+		tisClient := operatorclient.Get(ctx).OperatorV1alpha1().TektonInstallerSets()
+
+		metrics, err := NewRecorder()
+		if err != nil {
+			logger.Errorf("Failed to create trigger metrics recorder %v", err)
+		}
+
+		c := &Reconciler{
+			pipelineInformer:   tektonPipelineinformer.Get(ctx),
+			installerSetClient: client.NewInstallerSetClient(tisClient, operatorVer, pacVersion, v1alpha1.KindOpenShiftPipelinesAsCode, metrics),
+			extension:          generator(ctx),
+			manifest:           manifest,
+			pacVersion:         pacVersion,
+		}
+		impl := pacreconciler.NewImpl(ctx, c)
+
+		logger.Info("Setting up event handlers for OpenShiftPipelinesAsCode")
+
+		pacInformer.Get(ctx).Informer().AddEventHandler(controller.HandleAll(impl.Enqueue))
+
+		tektonInstallerinformer.Get(ctx).Informer().AddEventHandler(cache.FilteringResourceEventHandler{
+			FilterFunc: controller.FilterController(&v1alpha1.OpenShiftPipelinesAsCode{}),
+			Handler:    controller.HandleAll(impl.EnqueueControllerOf),
+		})
+		return impl
+	}
+}
diff --git a/pkg/reconciler/openshift/openshiftpipelinesascode/extension.go b/pkg/reconciler/openshift/openshiftpipelinesascode/extension.go
new file mode 100644
index 000000000..148be7a66
--- /dev/null
+++ b/pkg/reconciler/openshift/openshiftpipelinesascode/extension.go
@@ -0,0 +1,114 @@
+/*
+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.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package openshiftpipelinesascode
+
+import (
+	"context"
+	"os"
+	"path/filepath"
+
+	mfc "github.com/manifestival/client-go-client"
+	mf "github.com/manifestival/manifestival"
+	"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
+	operatorclient "github.com/tektoncd/operator/pkg/client/injection/client"
+	"github.com/tektoncd/operator/pkg/reconciler/common"
+	"github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektoninstallerset/client"
+	"go.uber.org/zap"
+	"knative.dev/pkg/injection"
+	"knative.dev/pkg/logging"
+)
+
+const (
+	openshiftNS = "openshift"
+)
+
+func OpenShiftExtension(ctx context.Context) common.Extension {
+	logger := logging.FromContext(ctx)
+
+	mfclient, err := mfc.NewClient(injection.GetConfig(ctx))
+	if err != nil {
+		logger.Fatalw("Error creating client from injected config", zap.Error(err))
+	}
+	pacManifest, err := mf.ManifestFrom(mf.Slice{}, mf.UseClient(mfclient))
+	if err != nil {
+		logger.Fatalw("Error creating initial manifest", zap.Error(err))
+	}
+
+	pacLocation := filepath.Join(os.Getenv(common.KoEnvKey), "tekton-addon", "pipelines-as-code")
+	if err := common.AppendManifest(&pacManifest, pacLocation); err != nil {
+		logger.Fatalf("failed to fetch PAC manifest: %v", err)
+	}
+
+	prTemplates, err := fetchPipelineRunTemplates()
+	if err != nil {
+		logger.Fatalf("failed to fetch pipelineRun templates: %v", err)
+	}
+
+	operatorVer, err := common.OperatorVersion(ctx)
+	if err != nil {
+		logger.Fatal(err)
+	}
+
+	tisClient := operatorclient.Get(ctx).OperatorV1alpha1().TektonInstallerSets()
+	return openshiftExtension{
+		// component version is used for metrics, passing a dummy
+		// value through extension not going to affect execution
+		installerSetClient:   client.NewInstallerSetClient(tisClient, operatorVer, "pipelines-as-code-ext", v1alpha1.KindOpenShiftPipelinesAsCode, nil),
+		pacManifest:          &pacManifest,
+		pipelineRunTemplates: prTemplates,
+	}
+}
+
+type openshiftExtension struct {
+	installerSetClient   *client.InstallerSetClient
+	pacManifest          *mf.Manifest
+	pipelineRunTemplates *mf.Manifest
+}
+
+func (oe openshiftExtension) Transformers(comp v1alpha1.TektonComponent) []mf.Transformer {
+	return nil
+}
+func (oe openshiftExtension) PreReconcile(context.Context, v1alpha1.TektonComponent) error {
+	return nil
+}
+func (oe openshiftExtension) PostReconcile(ctx context.Context, comp v1alpha1.TektonComponent) error {
+	logger := logging.FromContext(ctx)
+
+	if err := oe.installerSetClient.PostSet(ctx, comp, oe.pipelineRunTemplates, extFilterAndTransform()); err != nil {
+		logger.Error("failed post set creation: ", err)
+		return err
+	}
+
+	if err := updateControllerRouteInConfigMap(oe.pacManifest, comp.GetSpec().GetTargetNamespace()); err != nil {
+		logger.Error("failed to update controller route: ", err)
+		return err
+	}
+	return nil
+}
+func (oe openshiftExtension) Finalize(context.Context, v1alpha1.TektonComponent) error {
+	return nil
+}
+
+func extFilterAndTransform() client.FilterAndTransform {
+	return func(ctx context.Context, manifest *mf.Manifest, comp v1alpha1.TektonComponent) (*mf.Manifest, error) {
+		prTemplates, err := manifest.Transform(mf.InjectNamespace(openshiftNS))
+		if err != nil {
+			return nil, err
+		}
+		return &prTemplates, nil
+	}
+}
diff --git a/pkg/reconciler/openshift/openshiftpipelinesascode/metrics.go b/pkg/reconciler/openshift/openshiftpipelinesascode/metrics.go
new file mode 100644
index 000000000..9a7eb34fe
--- /dev/null
+++ b/pkg/reconciler/openshift/openshiftpipelinesascode/metrics.go
@@ -0,0 +1,30 @@
+/*
+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.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package openshiftpipelinesascode
+
+import "go.uber.org/zap"
+
+type Recorder struct {
+}
+
+func NewRecorder() (*Recorder, error) {
+	return &Recorder{}, nil
+}
+
+func (m *Recorder) LogMetrics(status, version string, logger *zap.SugaredLogger) {
+	// TODO
+}
diff --git a/pkg/reconciler/openshift/openshiftpipelinesascode/pipelinerun_templates.go b/pkg/reconciler/openshift/openshiftpipelinesascode/pipelinerun_templates.go
new file mode 100644
index 000000000..421ecfd63
--- /dev/null
+++ b/pkg/reconciler/openshift/openshiftpipelinesascode/pipelinerun_templates.go
@@ -0,0 +1,95 @@
+/*
+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.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package openshiftpipelinesascode
+
+import (
+	"os"
+	"path/filepath"
+	"strings"
+
+	mf "github.com/manifestival/manifestival"
+	"github.com/tektoncd/operator/pkg/reconciler/common"
+	v1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+	"k8s.io/apimachinery/pkg/runtime"
+	"sigs.k8s.io/yaml"
+)
+
+const (
+	pacRuntimeLabel = "pipelinesascode.openshift.io/runtime"
+)
+
+var configmapTemplate = `apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: pipelines-as-code-template
+  labels:
+    app.kubernetes.io/part-of: pipelines-as-code
+data:
+  template: ""`
+
+func fetchPipelineRunTemplates() (*mf.Manifest, error) {
+	prManifests := mf.Manifest{}
+	koDataDir := os.Getenv(common.KoEnvKey)
+	templateLocation := filepath.Join(koDataDir, "tekton-addon", "pipelines-as-code-templates")
+	if err := common.AppendManifest(&prManifests, templateLocation); err != nil {
+		return nil, err
+	}
+	cmManifest, err := pipelineRunToConfigMapConverter(&prManifests)
+	if err != nil {
+		return nil, err
+	}
+	return cmManifest, nil
+}
+
+func pipelineRunToConfigMapConverter(prManifests *mf.Manifest) (*mf.Manifest, error) {
+	cm := &v1.ConfigMap{}
+	err := yaml.Unmarshal([]byte(configmapTemplate), cm)
+	if err != nil {
+		return nil, err
+	}
+
+	var temp []unstructured.Unstructured
+	for _, res := range prManifests.Resources() {
+		if res.GetKind() != "PipelineRun" {
+			temp = append(temp, res)
+			continue
+		}
+
+		data, err := yaml.Marshal(res.Object)
+		if err != nil {
+			return nil, err
+		}
+
+		// set pipelineRun
+		cm.Data["template"] = string(data)
+
+		// set metadata
+		prname := res.GetName()
+		cm.SetName("pipelines-as-code-" + prname)
+		cm.Labels[pacRuntimeLabel] = strings.TrimPrefix(prname, "pipelinerun-")
+
+		unstrObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(cm)
+		if err != nil {
+			return nil, err
+		}
+
+		temp = append(temp, unstructured.Unstructured{Object: unstrObj})
+	}
+	manifest, _ := mf.ManifestFrom(mf.Slice(temp))
+	return &manifest, nil
+}
diff --git a/pkg/reconciler/openshift/openshiftpipelinesascode/reconcile.go b/pkg/reconciler/openshift/openshiftpipelinesascode/reconcile.go
new file mode 100644
index 000000000..4e6c15dc8
--- /dev/null
+++ b/pkg/reconciler/openshift/openshiftpipelinesascode/reconcile.go
@@ -0,0 +1,105 @@
+/*
+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
+
+    hpacp://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 openshiftpipelinesascode
+
+import (
+	"context"
+	"fmt"
+
+	mf "github.com/manifestival/manifestival"
+	"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
+	pipelineinformer "github.com/tektoncd/operator/pkg/client/informers/externalversions/operator/v1alpha1"
+	pacreconciler "github.com/tektoncd/operator/pkg/client/injection/reconciler/operator/v1alpha1/openshiftpipelinesascode"
+	"github.com/tektoncd/operator/pkg/reconciler/common"
+	"github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektoninstallerset/client"
+	"knative.dev/pkg/logging"
+	pkgreconciler "knative.dev/pkg/reconciler"
+)
+
+// Reconciler implements controller.Reconciler for OpenShiftPipelinesAsCode resources.
+type Reconciler struct {
+	// installer Set client to do CRUD operations for components
+	installerSetClient *client.InstallerSetClient
+	// pipelineInformer to query for TektonPipeline
+	pipelineInformer pipelineinformer.TektonPipelineInformer
+	// manifest has the source manifest of Openshift Pipelines As Code for a
+	// particular version
+	manifest mf.Manifest
+	// Platform-specific behavior to affect the transform
+	extension common.Extension
+	// version of PipelinesAsCode which we are installing
+	pacVersion string
+}
+
+// Check that our Reconciler implements controller.Reconciler
+var _ pacreconciler.Interface = (*Reconciler)(nil)
+
+// ReconcileKind compares the actual state with the desired, and apacempts to
+// converge the two.
+func (r *Reconciler) ReconcileKind(ctx context.Context, pac *v1alpha1.OpenShiftPipelinesAsCode) pkgreconciler.Event {
+	logger := logging.FromContext(ctx).With("name", pac.GetName())
+	pac.Status.InitializeConditions()
+	pac.Status.SetVersion(r.pacVersion)
+
+	if pac.GetName() != v1alpha1.OpenShiftPipelinesAsCodeName {
+		msg := fmt.Sprintf("Resource ignored, Expected Name: %s, Got Name: %s",
+			v1alpha1.OpenShiftPipelinesAsCodeName,
+			pac.GetName(),
+		)
+		logger.Error(msg)
+		pac.Status.MarkNotReady(msg)
+		return nil
+	}
+
+	//Make sure TektonPipeline is installed before proceeding with OpenShiftPipelinesAsCode
+	if _, err := common.PipelineReady(r.pipelineInformer); err != nil {
+		if err.Error() == common.PipelineNotReady || err == v1alpha1.DEPENDENCY_UPGRADE_PENDING_ERR {
+			pac.Status.MarkDependencyInstalling("tekton-pipelines is still installing")
+			// wait for pipeline status to change
+			return v1alpha1.REQUEUE_EVENT_AFTER
+		}
+		// (tektonpipeline.operator.tekton.dev instance not available yet)
+		pac.Status.MarkDependencyMissing("tekton-pipelines does not exist")
+		return err
+	}
+	pac.Status.MarkDependenciesInstalled()
+
+	if err := r.extension.PreReconcile(ctx, pac); err != nil {
+		return err
+	}
+
+	//Mark PreReconcile Complete
+	pac.Status.MarkPreReconcilerComplete()
+
+	if err := r.installerSetClient.MainSet(ctx, pac, &r.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 nil
+		}
+		pac.Status.MarkInstallerSetNotReady(msg)
+		return err
+	}
+
+	if err := r.extension.PostReconcile(ctx, pac); err != nil {
+		return err
+	}
+
+	// Mark PostReconcile Complete
+	pac.Status.MarkPostReconcilerComplete()
+	return nil
+}
diff --git a/pkg/reconciler/openshift/openshiftpipelinesascode/transform.go b/pkg/reconciler/openshift/openshiftpipelinesascode/transform.go
new file mode 100644
index 000000000..95ddac48f
--- /dev/null
+++ b/pkg/reconciler/openshift/openshiftpipelinesascode/transform.go
@@ -0,0 +1,54 @@
+/*
+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.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package openshiftpipelinesascode
+
+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"
+	"github.com/tektoncd/operator/pkg/reconciler/openshift"
+	occommon "github.com/tektoncd/operator/pkg/reconciler/openshift/common"
+)
+
+func filterAndTransform(extension common.Extension) client.FilterAndTransform {
+	return func(ctx context.Context, manifest *mf.Manifest, comp v1alpha1.TektonComponent) (*mf.Manifest, error) {
+		pac := comp.(*v1alpha1.OpenShiftPipelinesAsCode)
+		// installerSet adds it's owner as namespace's owner
+		// so deleting tekton addon deletes target namespace too
+		// to skip it we filter out namespace
+		pacManifest := manifest.Filter(mf.Not(mf.ByKind("Namespace")))
+
+		images := common.ToLowerCaseKeys(common.ImagesFromEnv(common.PacImagePrefix))
+		// Run transformers
+		tfs := []mf.Transformer{
+			common.InjectOperandNameLabelOverwriteExisting(openshift.OperandOpenShiftPipelineAsCode),
+			common.DeploymentImages(images),
+			common.AddConfiguration(pac.Spec.Config),
+			common.ApplyProxySettings,
+			occommon.ApplyCABundles,
+		}
+
+		allTfs := append(tfs, extension.Transformers(pac)...)
+		if err := common.Transform(ctx, &pacManifest, pac, allTfs...); err != nil {
+			return nil, err
+		}
+		return &pacManifest, nil
+	}
+}
diff --git a/pkg/reconciler/openshift/openshiftpipelinesascode/update_route_in_configmap.go b/pkg/reconciler/openshift/openshiftpipelinesascode/update_route_in_configmap.go
new file mode 100644
index 000000000..6d2cd5d7f
--- /dev/null
+++ b/pkg/reconciler/openshift/openshiftpipelinesascode/update_route_in_configmap.go
@@ -0,0 +1,102 @@
+/*
+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.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package openshiftpipelinesascode
+
+import (
+	"fmt"
+
+	mf "github.com/manifestival/manifestival"
+	routev1 "github.com/openshift/api/route/v1"
+	"github.com/openshift/client-go/route/clientset/versioned/scheme"
+	v1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+)
+
+const (
+	controllerRouteName = "pipelines-as-code-controller"
+	infoConfigMapName   = "pipelines-as-code-info"
+)
+
+func updateControllerRouteInConfigMap(pacManifest *mf.Manifest, targetNs string) error {
+	controllerRoute, err := getControllerRouteHost(pacManifest, targetNs)
+	if err != nil {
+		return fmt.Errorf("failed to get controller route: %v", err)
+	}
+	if controllerRoute == "" {
+		return fmt.Errorf("failed to get host in route, will try again")
+	}
+	if err := updateInfoConfigMap(controllerRoute, pacManifest, targetNs); err != nil {
+		return err
+	}
+	return nil
+}
+
+func getControllerRouteHost(manifest *mf.Manifest, targetNs string) (string, error) {
+	var hostUrl string
+	for _, r := range manifest.Filter(mf.ByKind("Route")).Resources() {
+		r.SetNamespace(targetNs)
+		u, err := manifest.Client.Get(&r)
+		if err != nil {
+			return "", err
+		}
+		if u.GetName() == controllerRouteName {
+			route := &routev1.Route{}
+			if err := scheme.Scheme.Convert(u, route, nil); err != nil {
+				return "", err
+			}
+			hostUrl = route.Spec.Host
+		}
+	}
+	return hostUrl, nil
+}
+
+func updateInfoConfigMap(route string, pacManifest *mf.Manifest, targetNs string) error {
+	for _, r := range pacManifest.Filter(mf.ByKind("ConfigMap")).Resources() {
+		if r.GetName() != infoConfigMapName {
+			continue
+		}
+		r.SetNamespace(targetNs)
+		u, err := pacManifest.Client.Get(&r)
+		if err != nil {
+			return err
+		}
+		cm := &v1.ConfigMap{}
+		err = runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, cm)
+		if err != nil {
+			return err
+		}
+		routeURL := "https://" + route
+
+		// set controller url if not the same
+		if cm.Data["controller-url"] == routeURL {
+			return nil
+		}
+		cm.Data["controller-url"] = routeURL
+
+		unstrObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(cm)
+		if err != nil {
+			return err
+		}
+		u.SetUnstructuredContent(unstrObj)
+
+		err = pacManifest.Client.Update(u)
+		if err != nil {
+			return err
+		}
+	}
+	return nil
+}
diff --git a/pkg/reconciler/openshift/openshiftplatform/config.go b/pkg/reconciler/openshift/openshiftplatform/config.go
index 3bf5d741f..5392218ae 100644
--- a/pkg/reconciler/openshift/openshiftplatform/config.go
+++ b/pkg/reconciler/openshift/openshiftplatform/config.go
@@ -18,6 +18,7 @@ package openshiftplatform
 
 import (
 	k8sInstallerSet "github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektoninstallerset"
+	"github.com/tektoncd/operator/pkg/reconciler/openshift/openshiftpipelinesascode"
 	openshiftAddon "github.com/tektoncd/operator/pkg/reconciler/openshift/tektonaddon"
 	openshiftChain "github.com/tektoncd/operator/pkg/reconciler/openshift/tektonchain"
 	openshiftConfig "github.com/tektoncd/operator/pkg/reconciler/openshift/tektonconfig"
@@ -29,8 +30,9 @@ import (
 )
 
 const (
-	ControllerTektonAddon platform.ControllerName = "tektonaddon"
-	PlatformNameOpenShift string                  = "openshift"
+	ControllerTektonAddon              platform.ControllerName = "tektonaddon"
+	ControllerOpenShiftPipelinesAsCode platform.ControllerName = "openshiftpipelinesascode"
+	PlatformNameOpenShift              string                  = "openshift"
 )
 
 var (
@@ -61,6 +63,10 @@ var (
 			Name:                  string(ControllerTektonAddon),
 			ControllerConstructor: openshiftAddon.NewController,
 		},
+		ControllerOpenShiftPipelinesAsCode: injection.NamedControllerConstructor{
+			Name:                  string(ControllerOpenShiftPipelinesAsCode),
+			ControllerConstructor: openshiftpipelinesascode.NewController,
+		},
 		// there is no openshift specific extension for TektonInstallerSet Reconciler (yet 🤓)
 		platform.ControllerTektonInstallerSet: injection.NamedControllerConstructor{
 			Name:                  string(platform.ControllerTektonInstallerSet),
diff --git a/pkg/reconciler/openshift/tektonaddon/pipelinesascode.go b/pkg/reconciler/openshift/tektonaddon/pipelinesascode.go
index f00dad131..339b9d2ab 100644
--- a/pkg/reconciler/openshift/tektonaddon/pipelinesascode.go
+++ b/pkg/reconciler/openshift/tektonaddon/pipelinesascode.go
@@ -18,286 +18,25 @@ package tektonaddon
 
 import (
 	"context"
-	"os"
-	"path/filepath"
-	"strings"
 
-	occommon "github.com/tektoncd/operator/pkg/reconciler/openshift/common"
-
-	routev1 "github.com/openshift/api/route/v1"
-	"github.com/openshift/client-go/route/clientset/versioned/scheme"
-	"github.com/tektoncd/operator/pkg/reconciler/openshift"
-	"github.com/tektoncd/operator/pkg/reconciler/shared/hash"
-	v1 "k8s.io/api/core/v1"
-	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
-	"k8s.io/apimachinery/pkg/runtime"
-	"sigs.k8s.io/yaml"
-
-	mf "github.com/manifestival/manifestival"
 	"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
 	"github.com/tektoncd/operator/pkg/reconciler/common"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
 
-const (
-	pacRuntimeLabel = "pipelinesascode.openshift.io/runtime"
-	openshiftNS     = "openshift"
-)
-
-var configmapTemplate = `apiVersion: v1
-kind: ConfigMap
-metadata:
-  name: pipelines-as-code-template
-  labels:
-    app.kubernetes.io/part-of: pipelines-as-code
-data:
-  template: ""`
-
 var pacLS = metav1.LabelSelector{
 	MatchLabels: map[string]string{
 		v1alpha1.InstallerSetType: PACInstallerSet,
 	},
 }
 
-func (r *Reconciler) EnsurePipelinesAsCode(ctx context.Context, ta *v1alpha1.TektonAddon) error {
-
+func (r *Reconciler) CleanupPipelinesAsCode(ctx context.Context, ta *v1alpha1.TektonAddon) error {
 	pacLabelSelector, err := common.LabelSelector(pacLS)
 	if err != nil {
 		return err
 	}
-
-	if *ta.Spec.EnablePAC {
-		exist, currentTIS, err := checkIfInstallerSetExist(ctx, r.operatorClientSet, r.operatorVersion, pacLabelSelector)
-		if err != nil {
-			return err
-		}
-		if !exist {
-			return r.ensurePAC(ctx, ta)
-		}
-
-		expectedHash, err := hash.Compute(ta.Spec)
-		if err != nil {
-			return err
-		}
-
-		hashOnTIS := currentTIS.Annotations[v1alpha1.LastAppliedHashKey]
-		if expectedHash != hashOnTIS {
-			updatedManifest, err := r.getManifest(ctx, ta)
-			if err != nil {
-				return err
-			}
-			currentTIS.Spec.Manifests = updatedManifest.Resources()
-			currentTIS.Annotations[v1alpha1.LastAppliedHashKey] = expectedHash
-
-			if _, err = r.operatorClientSet.OperatorV1alpha1().TektonInstallerSets().
-				Update(ctx, currentTIS, metav1.UpdateOptions{}); err != nil {
-				return err
-			}
-		}
-
-		return r.updateControllerURL(ta)
-
-	} else {
-		// if disabled then delete the installer Set if exist
-		if err := r.deleteInstallerSet(ctx, pacLabelSelector); err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-func (r *Reconciler) updateControllerURL(ta *v1alpha1.TektonAddon) error {
-	var err error
-	pacManifest := mf.Manifest{
-		Client: r.manifest.Client,
-	}
-
-	koDataDir := os.Getenv(common.KoEnvKey)
-	pacLocation := filepath.Join(koDataDir, "tekton-addon", "pipelines-as-code")
-	if err := common.AppendManifest(&pacManifest, pacLocation); err != nil {
-		return err
-	}
-	pacManifest, err = pacManifest.Transform(mf.InjectNamespace(ta.Spec.TargetNamespace))
-	if err != nil {
+	if err := r.deleteInstallerSet(ctx, pacLabelSelector); err != nil {
 		return err
 	}
-
-	route, err := getControllerRouteHost(&pacManifest)
-	if err != nil {
-		return err
-	}
-	if route == "" {
-		return v1alpha1.RECONCILE_AGAIN_ERR
-	}
-
-	if err := updateInfoConfigMap(route, &pacManifest); err != nil {
-		return err
-	}
-	return nil
-}
-
-func (r *Reconciler) ensurePAC(ctx context.Context, ta *v1alpha1.TektonAddon) error {
-	pacManifest, err := r.getManifest(ctx, ta)
-	if err != nil {
-		return err
-	}
-
-	if err := createInstallerSet(ctx, r.operatorClientSet, ta, *pacManifest, r.operatorVersion,
-		PACInstallerSet, "addon-pac"); err != nil {
-		return err
-	}
-
-	return nil
-}
-
-func (r *Reconciler) getManifest(ctx context.Context, ta *v1alpha1.TektonAddon) (*mf.Manifest, error) {
-	pacManifest := mf.Manifest{}
-
-	// core manifest
-	koDataDir := os.Getenv(common.KoEnvKey)
-	pacLocation := filepath.Join(koDataDir, "tekton-addon", "pipelines-as-code")
-	if err := common.AppendManifest(&pacManifest, pacLocation); err != nil {
-		return nil, err
-	}
-
-	prTemplates := mf.Manifest{}
-	if err := fetchPRTemplates(&prTemplates); err != nil {
-		return nil, err
-	}
-	var err error
-	prTemplates, err = prTemplates.Transform(mf.InjectNamespace(openshiftNS))
-	if err != nil {
-		return nil, err
-	}
-
-	// installerSet adds it's owner as namespace's owner
-	// so deleting tekton addon deletes target namespace too
-	// to skip it we filter out namespace
-	pacManifest = pacManifest.Filter(mf.Not(mf.ByKind("Namespace")))
-
-	images := common.ToLowerCaseKeys(common.ImagesFromEnv(common.PacImagePrefix))
-	// Run transformers
-	tfs := []mf.Transformer{
-		common.InjectOperandNameLabelOverwriteExisting(openshift.OperandOpenShiftPipelineAsCode),
-		common.DeploymentImages(images),
-		common.AddConfiguration(ta.Spec.Config),
-		common.ApplyProxySettings,
-		occommon.ApplyCABundles,
-	}
-
-	if err := r.addonTransform(ctx, &pacManifest, ta, tfs...); err != nil {
-		return nil, err
-	}
-
-	pacManifest = pacManifest.Append(prTemplates)
-
-	return &pacManifest, nil
-}
-
-func fetchPRTemplates(manifest *mf.Manifest) error {
-	prManifests := mf.Manifest{}
-	koDataDir := os.Getenv(common.KoEnvKey)
-	templateLocation := filepath.Join(koDataDir, "tekton-addon", "pipelines-as-code-templates")
-	if err := common.AppendManifest(&prManifests, templateLocation); err != nil {
-		return err
-	}
-
-	cmManifest, err := pipelineRunToConfigMapConverter(&prManifests)
-	if err != nil {
-		return err
-	}
-	*manifest = manifest.Append(*cmManifest)
-	return nil
-}
-
-func pipelineRunToConfigMapConverter(prManifests *mf.Manifest) (*mf.Manifest, error) {
-	cm := &v1.ConfigMap{}
-	err := yaml.Unmarshal([]byte(configmapTemplate), cm)
-	if err != nil {
-		return nil, err
-	}
-
-	var temp []unstructured.Unstructured
-	for _, res := range prManifests.Resources() {
-		if res.GetKind() != "PipelineRun" {
-			temp = append(temp, res)
-			continue
-		}
-
-		data, err := yaml.Marshal(res.Object)
-		if err != nil {
-			return nil, err
-		}
-
-		// set pipelineRun
-		cm.Data["template"] = string(data)
-
-		// set metadata
-		prname := res.GetName()
-		cm.SetName("pipelines-as-code-" + prname)
-		cm.Labels[pacRuntimeLabel] = strings.TrimPrefix(prname, "pipelinerun-")
-
-		unstrObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(cm)
-		if err != nil {
-			return nil, err
-		}
-
-		temp = append(temp, unstructured.Unstructured{Object: unstrObj})
-	}
-	manifest, _ := mf.ManifestFrom(mf.Slice(temp))
-	return &manifest, nil
-}
-
-func getControllerRouteHost(manifest *mf.Manifest) (string, error) {
-	var hostUrl string
-	for _, r := range manifest.Filter(mf.ByKind("Route")).Resources() {
-		u, err := manifest.Client.Get(&r)
-		if err != nil {
-			return "", err
-		}
-		if u.GetName() == "pipelines-as-code-controller" {
-			route := &routev1.Route{}
-			if err := scheme.Scheme.Convert(u, route, nil); err != nil {
-				return "", err
-			}
-			hostUrl = route.Spec.Host
-		}
-	}
-	return hostUrl, nil
-}
-
-func updateInfoConfigMap(route string, pacManifest *mf.Manifest) error {
-	for _, r := range pacManifest.Filter(mf.ByKind("ConfigMap")).Resources() {
-		if r.GetName() != "pipelines-as-code-info" {
-			continue
-		}
-		u, err := pacManifest.Client.Get(&r)
-		if err != nil {
-			return err
-		}
-		cm := &v1.ConfigMap{}
-		err = runtime.DefaultUnstructuredConverter.FromUnstructured(u.Object, cm)
-		if err != nil {
-			return err
-		}
-
-		// set controller url
-		if cm.Data["controller-url"] != "" {
-			return nil
-		}
-
-		cm.Data["controller-url"] = "https://" + route
-
-		unstrObj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(cm)
-		if err != nil {
-			return err
-		}
-		u.SetUnstructuredContent(unstrObj)
-
-		err = pacManifest.Client.Update(u)
-		if err != nil {
-			return err
-		}
-	}
 	return nil
 }
diff --git a/pkg/reconciler/openshift/tektonaddon/tektonaddon.go b/pkg/reconciler/openshift/tektonaddon/tektonaddon.go
index 1f14a4f0f..24a9eaa79 100644
--- a/pkg/reconciler/openshift/tektonaddon/tektonaddon.go
+++ b/pkg/reconciler/openshift/tektonaddon/tektonaddon.go
@@ -183,7 +183,10 @@ func (r *Reconciler) ReconcileKind(ctx context.Context, ta *v1alpha1.TektonAddon
 		return err
 	}
 
-	if err := r.EnsurePipelinesAsCode(ctx, ta); err != nil {
+	// Pipelines As Code is installed as a separate component now, so
+	// cleanup any of its installer set created previously
+	// this can be removed in future release
+	if err := r.CleanupPipelinesAsCode(ctx, ta); err != nil {
 		return err
 	}
 
diff --git a/pkg/reconciler/openshift/tektonpipeline/extension.go b/pkg/reconciler/openshift/tektonpipeline/extension.go
index 0f153f057..fc66d2652 100644
--- a/pkg/reconciler/openshift/tektonpipeline/extension.go
+++ b/pkg/reconciler/openshift/tektonpipeline/extension.go
@@ -44,8 +44,10 @@ func OpenShiftExtension(ctx context.Context) common.Extension {
 	}
 
 	ext := openshiftExtension{
+		// component version is used for metrics, passing a dummy
+		// value through extension not going to affect execution
 		installerSetClient: client.NewInstallerSetClient(operatorclient.Get(ctx).OperatorV1alpha1().TektonInstallerSets(),
-			version, "pre-pipeline", v1alpha1.KindTektonPipeline, nil),
+			version, "pipelines-ext", v1alpha1.KindTektonPipeline, nil),
 	}
 	return ext
 }


Test patch:
diff --git a/pkg/apis/operator/v1alpha1/openshiftpipelinesaascode_lifecycle_test.go b/pkg/apis/operator/v1alpha1/openshiftpipelinesaascode_lifecycle_test.go
new file mode 100644
index 000000000..603e12e0a
--- /dev/null
+++ b/pkg/apis/operator/v1alpha1/openshiftpipelinesaascode_lifecycle_test.go
@@ -0,0 +1,121 @@
+/*
+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.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package v1alpha1
+
+import (
+	"testing"
+
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	apistest "knative.dev/pkg/apis/testing"
+)
+
+func TestOpenShiftPipelinesAsCodeGroupVersionKind(t *testing.T) {
+	r := &OpenShiftPipelinesAsCode{}
+	want := schema.GroupVersionKind{
+		Group:   GroupName,
+		Version: SchemaVersion,
+		Kind:    KindOpenShiftPipelinesAsCode,
+	}
+	if got := r.GetGroupVersionKind(); got != want {
+		t.Errorf("got: %v, want: %v", got, want)
+	}
+}
+
+func TestOpenShiftPipelinesAsCodeHappyPath(t *testing.T) {
+	pac := &OpenShiftPipelinesAsCodeStatus{}
+	pac.InitializeConditions()
+
+	apistest.CheckConditionOngoing(pac, DependenciesInstalled, t)
+	apistest.CheckConditionOngoing(pac, PreReconciler, t)
+	apistest.CheckConditionOngoing(pac, InstallerSetAvailable, t)
+	apistest.CheckConditionOngoing(pac, InstallerSetReady, t)
+	apistest.CheckConditionOngoing(pac, PostReconciler, t)
+
+	// Dependencies installed
+	pac.MarkDependenciesInstalled()
+	apistest.CheckConditionSucceeded(pac, DependenciesInstalled, t)
+
+	// Pre reconciler completes execution
+	pac.MarkPreReconcilerComplete()
+	apistest.CheckConditionSucceeded(pac, PreReconciler, t)
+
+	// Installer set created
+	pac.MarkInstallerSetAvailable()
+	apistest.CheckConditionSucceeded(pac, InstallerSetAvailable, t)
+
+	// InstallerSet is not ready when deployment pods are not up
+	pac.MarkInstallerSetNotReady("waiting for deployments")
+	apistest.CheckConditionFailed(pac, InstallerSetReady, t)
+
+	// InstallerSet and then PostReconciler become ready and we're good.
+	pac.MarkInstallerSetReady()
+	apistest.CheckConditionSucceeded(pac, InstallerSetReady, t)
+
+	pac.MarkPostReconcilerComplete()
+	apistest.CheckConditionSucceeded(pac, PostReconciler, t)
+
+	if ready := pac.IsReady(); !ready {
+		t.Errorf("pac.IsReady() = %v, want true", ready)
+	}
+}
+
+func TestOpenShiftPipelinesAsCodeErrorPath(t *testing.T) {
+	pac := &OpenShiftPipelinesAsCodeStatus{}
+	pac.InitializeConditions()
+
+	apistest.CheckConditionOngoing(pac, DependenciesInstalled, t)
+	apistest.CheckConditionOngoing(pac, PreReconciler, t)
+	apistest.CheckConditionOngoing(pac, InstallerSetAvailable, t)
+	apistest.CheckConditionOngoing(pac, InstallerSetReady, t)
+	apistest.CheckConditionOngoing(pac, PostReconciler, t)
+
+	// Dependencies installed
+	pac.MarkDependenciesInstalled()
+	apistest.CheckConditionSucceeded(pac, DependenciesInstalled, t)
+
+	// Pre reconciler completes execution
+	pac.MarkPreReconcilerComplete()
+	apistest.CheckConditionSucceeded(pac, PreReconciler, t)
+
+	// Installer set created
+	pac.MarkInstallerSetAvailable()
+	apistest.CheckConditionSucceeded(pac, InstallerSetAvailable, t)
+
+	// InstallerSet is not ready when deployment pods are not up
+	pac.MarkInstallerSetNotReady("waiting for deployments")
+	apistest.CheckConditionFailed(pac, InstallerSetReady, t)
+
+	// InstallerSet and then PostReconciler become ready and we're good.
+	pac.MarkInstallerSetReady()
+	apistest.CheckConditionSucceeded(pac, InstallerSetReady, t)
+
+	pac.MarkPostReconcilerComplete()
+	apistest.CheckConditionSucceeded(pac, PostReconciler, t)
+
+	if ready := pac.IsReady(); !ready {
+		t.Errorf("pac.IsReady() = %v, want true", ready)
+	}
+
+	// In further reconciliation deployment might fail and installer
+	// set will change to not ready
+
+	pac.MarkInstallerSetNotReady("webhook not ready")
+	apistest.CheckConditionFailed(pac, InstallerSetReady, t)
+	if ready := pac.IsReady(); ready {
+		t.Errorf("pac.IsReady() = %v, want false", ready)
+	}
+}
diff --git a/pkg/reconciler/openshift/tektonaddon/pipelinesascode_test.go b/pkg/reconciler/openshift/openshiftpipelinesascode/pipelinerun_templates_test.go
similarity index 64%
rename from pkg/reconciler/openshift/tektonaddon/pipelinesascode_test.go
rename to pkg/reconciler/openshift/openshiftpipelinesascode/pipelinerun_templates_test.go
index 119d68477..f7aed2147 100644
--- a/pkg/reconciler/openshift/tektonaddon/pipelinesascode_test.go
+++ b/pkg/reconciler/openshift/openshiftpipelinesascode/pipelinerun_templates_test.go
@@ -1,4 +1,20 @@
-package tektonaddon
+/*
+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.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package openshiftpipelinesascode
 
 import (
 	"path"
diff --git a/pkg/reconciler/openshift/openshiftpipelinesascode/testdata/test-expected-pac-pr-template.yaml b/pkg/reconciler/openshift/openshiftpipelinesascode/testdata/test-expected-pac-pr-template.yaml
new file mode 100644
index 000000000..d8794a399
--- /dev/null
+++ b/pkg/reconciler/openshift/openshiftpipelinesascode/testdata/test-expected-pac-pr-template.yaml
@@ -0,0 +1,69 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: pipelines-as-code-pipelinerun-go
+  labels:
+    pipelinesascode.openshift.io/runtime: "go"
+    app.kubernetes.io/part-of: pipelines-as-code
+data:
+  template: |
+    apiVersion: tekton.dev/v1beta1
+    kind: PipelineRun
+    metadata:
+      annotations:
+        pipelinesascode.tekton.dev/max-keep-runs: "5"
+        pipelinesascode.tekton.dev/on-event: pull_request
+        pipelinesascode.tekton.dev/on-target-branch: main
+        pipelinesascode.tekton.dev/task: git-clone
+        pipelinesascode.tekton.dev/task-1: '[golangci-lint]'
+      name: go-template
+    spec:
+      params:
+        - name: repo_url
+          value: "{{ repo_url }}"
+        - name: revision
+          value: "{{ revision }}"
+      pipelineSpec:
+        params:
+          - name: repo_url
+          - name: revision
+        workspaces:
+          - name: source
+          - name: basic-auth
+        tasks:
+          - name: fetch-repository
+            taskRef:
+              name: git-clone
+            workspaces:
+              - name: output
+                workspace: source
+              - name: basic-auth
+                workspace: basic-auth
+            params:
+              - name: url
+                value: $(params.repo_url)
+              - name: revision
+                value: $(params.revision)
+          - name: golangci-lint
+            taskRef:
+              name: golangci-lint
+            runAfter:
+              - fetch-repository
+            params:
+              - name: package
+                value: .
+            workspaces:
+              - name: source
+                workspace: source
+      workspaces:
+        - name: source
+          volumeClaimTemplate:
+            spec:
+              accessModes:
+                - ReadWriteOnce
+              resources:
+                requests:
+                  storage: 1Gi
+        - name: basic-auth
+          secret:
+            secretName: "{{ git_auth_secret }}"
diff --git a/pkg/reconciler/openshift/openshiftpipelinesascode/testdata/test-pac-pr-template.yaml b/pkg/reconciler/openshift/openshiftpipelinesascode/testdata/test-pac-pr-template.yaml
new file mode 100644
index 000000000..1c8da24fb
--- /dev/null
+++ b/pkg/reconciler/openshift/openshiftpipelinesascode/testdata/test-pac-pr-template.yaml
@@ -0,0 +1,83 @@
+---
+apiVersion: tekton.dev/v1beta1
+kind: PipelineRun
+metadata:
+  name: pipelinerun-go
+  annotations:
+    # The event we are targeting as seen from the webhook payload
+    # this can be an array too, i.e: [pull_request, push]
+    pipelinesascode.tekton.dev/on-event: "pull_request"
+
+    # The branch or tag we are targeting (ie: main, refs/tags/*)
+    pipelinesascode.tekton.dev/on-target-branch: "main"
+
+    # Fetch the git-clone task from hub, we are able to reference later on it
+    # with taskRef and it will automatically be embedded into our pipeline.
+    pipelinesascode.tekton.dev/task: "git-clone"
+
+
+    # Task for Golang
+    pipelinesascode.tekton.dev/task-1: "[golangci-lint]"
+
+    # You can add more tasks in here to reuse, browse the one you like from here
+    # https://hub.tekton.dev/
+    # example:
+    # pipelinesascode.tekton.dev/task-2: "[maven, buildah]"
+
+    # How many runs we want to keep attached to this event
+    pipelinesascode.tekton.dev/max-keep-runs: "5"
+spec:
+  params:
+    # The variable with brackets are special to Pipelines as Code
+    # They will automatically be expanded with the events from Github.
+    - name: repo_url
+      value: "{{ repo_url }}"
+    - name: revision
+      value: "{{ revision }}"
+  pipelineSpec:
+    params:
+      - name: repo_url
+      - name: revision
+    workspaces:
+      - name: source
+      - name: basic-auth
+    tasks:
+      - name: fetch-repository
+        taskRef:
+          name: git-clone
+        workspaces:
+          - name: output
+            workspace: source
+          - name: basic-auth
+            workspace: basic-auth
+        params:
+          - name: url
+            value: $(params.repo_url)
+          - name: revision
+            value: $(params.revision)
+      - name: golangci-lint
+        taskRef:
+          name: golangci-lint
+        runAfter:
+          - fetch-repository
+        params:
+          - name: package
+            value: .
+        workspaces:
+          - name: source
+            workspace: source
+
+  workspaces:
+    - name: source
+      volumeClaimTemplate:
+        spec:
+          accessModes:
+            - ReadWriteOnce
+          resources:
+            requests:
+              storage: 1Gi
+    # This workspace will inject secret to help the git-clone task to be able to
+    # checkout the private repositories
+    - name: basic-auth
+      secret:
+        secretName: "{{ git_auth_secret }}"
diff --git a/pkg/reconciler/openshift/openshiftpipelinesascode/testdata/test-update-route.yaml b/pkg/reconciler/openshift/openshiftpipelinesascode/testdata/test-update-route.yaml
new file mode 100644
index 000000000..4dd5713ca
--- /dev/null
+++ b/pkg/reconciler/openshift/openshiftpipelinesascode/testdata/test-update-route.yaml
@@ -0,0 +1,44 @@
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: pipelines-as-code-info
+  namespace: pipelines-as-code
+  labels:
+    app.kubernetes.io/version: "devel"
+    app.kubernetes.io/part-of: pipelines-as-code
+data:
+  # pipelines as code controller version
+  version: "devel"
+
+  # controller url to be used for configuring webhook using cli
+  controller-url: ""
+
+  # display the configured provider on the platform
+  # only one provider type to be configured at a time
+  # eg. if GitHub App is configured, then webhooks should not be configured
+  provider: ""
+---
+apiVersion: route.openshift.io/v1
+kind: Route
+metadata:
+  labels:
+    app.kubernetes.io/component: controller
+    app.kubernetes.io/instance: default
+    app.kubernetes.io/part-of: pipelines-as-code
+    app.kubernetes.io/version: "devel"
+    pipelines-as-code/route: controller
+  name: pipelines-as-code-controller
+  namespace: pipelines-as-code
+spec:
+  host: pac.controller.test.com
+  port:
+    targetPort: http-listener
+  tls:
+    insecureEdgeTerminationPolicy: Redirect
+    termination: edge
+  to:
+    kind: Service
+    name: pipelines-as-code-controller
+    weight: 100
+  wildcardPolicy: None
diff --git a/pkg/reconciler/openshift/openshiftpipelinesascode/update_route_in_configmap_test.go b/pkg/reconciler/openshift/openshiftpipelinesascode/update_route_in_configmap_test.go
new file mode 100644
index 000000000..1ff65797a
--- /dev/null
+++ b/pkg/reconciler/openshift/openshiftpipelinesascode/update_route_in_configmap_test.go
@@ -0,0 +1,69 @@
+/*
+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.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package openshiftpipelinesascode
+
+import (
+	"path"
+	"testing"
+
+	mf "github.com/manifestival/manifestival"
+	"github.com/manifestival/manifestival/fake"
+	"gotest.tools/v3/assert"
+	v1 "k8s.io/api/core/v1"
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+	"k8s.io/apimachinery/pkg/runtime"
+)
+
+func TestUpdateControllerRouteInConfigMap(t *testing.T) {
+	testNamspace := "osp"
+	testData := path.Join("testdata", "test-update-route.yaml")
+	manifest, err := mf.ManifestFrom(mf.Recursive(testData))
+	assert.NilError(t, err)
+
+	res := []runtime.Object{}
+	for _, r := range manifest.Resources() {
+		// change the namespace while adding in client
+		// namespace in manifest should be different from one installed on cluster
+		// to test this properly
+		r.SetNamespace(testNamspace)
+		newRes := r
+		res = append(res, &newRes)
+	}
+
+	fakeClient := fake.New(res...)
+	manifest.Client = fakeClient
+
+	err = updateControllerRouteInConfigMap(&manifest, testNamspace)
+	assert.NilError(t, err)
+
+	// check if configmap is updated
+	var unstructuredRes unstructured.Unstructured
+	if manifest.Resources()[0].GetKind() == "ConfigMap" {
+		unstructuredRes = manifest.Resources()[0]
+	} else {
+		unstructuredRes = manifest.Resources()[1]
+	}
+	unstructuredRes.SetNamespace(testNamspace)
+
+	cmUnstr, err := fakeClient.Get(&unstructuredRes)
+	assert.NilError(t, err)
+
+	cm := &v1.ConfigMap{}
+	err = runtime.DefaultUnstructuredConverter.FromUnstructured(cmUnstr.Object, cm)
+	assert.NilError(t, err)
+	assert.Equal(t, cm.Data["controller-url"], "https://pac.controller.test.com")
+}