Repository: jenkins-x/lighthouse
Pull request #968 (2020-08-24 18:24:44)

refactor: rework jobs config
This PR moves all job related config into its own package.

This is work in progress, i feel like there some improvements that can be done around initialization/validation.

Related issue #965 



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

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

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

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

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

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pr-build | d29ba18a5f1a7e69835b2b16c75396ec7903802f | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/1) | `/test pr-build`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pr-build | d29ba18a5f1a7e69835b2b16c75396ec7903802f | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/1) | `/test pr-build`
gitlab | d29ba18a5f1a7e69835b2b16c75396ec7903802f | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/5) | `/test gitlab`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
gitlab | d29ba18a5f1a7e69835b2b16c75396ec7903802f | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/5) | `/test gitlab`
pr-build | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/7) | `/test pr-build`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
gitlab | d29ba18a5f1a7e69835b2b16c75396ec7903802f | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/5) | `/test gitlab`
pr-build | e6318b0f8047bc90a522f1203652e5e885b50565 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/13) | `/test pr-build`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
gitlab | d29ba18a5f1a7e69835b2b16c75396ec7903802f | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/5) | `/test gitlab`
pr-build | e6318b0f8047bc90a522f1203652e5e885b50565 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/13) | `/test pr-build`
ghe | d29ba18a5f1a7e69835b2b16c75396ec7903802f | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/2) | `/test ghe`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
gitlab | d29ba18a5f1a7e69835b2b16c75396ec7903802f | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/5) | `/test gitlab`
pr-build | e6318b0f8047bc90a522f1203652e5e885b50565 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/13) | `/test pr-build`
ghe | d29ba18a5f1a7e69835b2b16c75396ec7903802f | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/2) | `/test ghe`
github | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/9) | `/test github`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
gitlab | d29ba18a5f1a7e69835b2b16c75396ec7903802f | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/5) | `/test gitlab`
pr-build | e6318b0f8047bc90a522f1203652e5e885b50565 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/13) | `/test pr-build`
ghe | d29ba18a5f1a7e69835b2b16c75396ec7903802f | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/2) | `/test ghe`
github | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/9) | `/test github`
bbs | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/11) | `/test bbs`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pr-build | e6318b0f8047bc90a522f1203652e5e885b50565 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/13) | `/test pr-build`
ghe | d29ba18a5f1a7e69835b2b16c75396ec7903802f | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/2) | `/test ghe`
github | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/9) | `/test github`
bbs | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/11) | `/test bbs`
gitlab | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/10) | `/test gitlab`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pr-build | e6318b0f8047bc90a522f1203652e5e885b50565 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/13) | `/test pr-build`
github | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/9) | `/test github`
bbs | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/11) | `/test bbs`
gitlab | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/10) | `/test gitlab`
ghe | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/8) | `/test ghe`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pr-build | e6318b0f8047bc90a522f1203652e5e885b50565 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/13) | `/test pr-build`
github | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/9) | `/test github`
gitlab | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/10) | `/test gitlab`
ghe | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/8) | `/test ghe`
bbs | d29ba18a5f1a7e69835b2b16c75396ec7903802f | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/4) | `/test bbs`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pr-build | e6318b0f8047bc90a522f1203652e5e885b50565 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/13) | `/test pr-build`
github | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/9) | `/test github`
gitlab | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/10) | `/test gitlab`
ghe | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/8) | `/test ghe`
bbs | d29ba18a5f1a7e69835b2b16c75396ec7903802f | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/4) | `/test bbs`
tekton | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/12) | `/test tekton`

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

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [jenkins-x/lighthouse](https://github.com/jenkins-x/lighthouse/issues/new?title=Command%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
abayer: fwiw, lint failures:
```
pkg/config/job/base.go:25:6: type name will be used as job.JobBase by other packages, and that stutters; consider calling this Base
pkg/config/job/brancher.go:45:1: exported method Brancher.SetBrancherRegexes should have comment or be unexported
pkg/config/job/regexpchangematcher.go:61:1: exported method RegexpChangeMatcher.SetChangeRegexes should have comment or be unexported
```
jenkins-x-bot: @eddycharly: The following tests **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pr-build | e6318b0f8047bc90a522f1203652e5e885b50565 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/13) | `/test pr-build`
tekton | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/12) | `/test tekton`
github | d29ba18a5f1a7e69835b2b16c75396ec7903802f | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/3) | `/test github`

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

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [jenkins-x/lighthouse](https://github.com/jenkins-x/lighthouse/issues/new?title=Command%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
eddycharly: Yeah, I didn’t focus on linting yet.
Moving code around, fixing tests, identifying some strange constructs that I would like to implement differently...
eddycharly: I was thinking about using dot imports but not sure if it’s good practice or not...
jenkins-x-bot: @eddycharly: The following tests **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
tekton | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/12) | `/test tekton`
github | d29ba18a5f1a7e69835b2b16c75396ec7903802f | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/3) | `/test github`
pr-build | 6c5562e17b53d9a93275d4c1b401642311828fd0 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/19) | `/test pr-build`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
tekton | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/12) | `/test tekton`
github | d29ba18a5f1a7e69835b2b16c75396ec7903802f | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/3) | `/test github`
pr-build | 6c5562e17b53d9a93275d4c1b401642311828fd0 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/19) | `/test pr-build`
gitlab | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/28) | `/test gitlab`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
tekton | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/12) | `/test tekton`
github | d29ba18a5f1a7e69835b2b16c75396ec7903802f | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/3) | `/test github`
gitlab | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/28) | `/test gitlab`
pr-build | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/24) | `/test pr-build`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
tekton | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/12) | `/test tekton`
github | d29ba18a5f1a7e69835b2b16c75396ec7903802f | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/3) | `/test github`
gitlab | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/28) | `/test gitlab`
pr-build | 79a430da7ab227797d142448049ad63234020007 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/30) | `/test pr-build`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
tekton | 9fa05284ee821402e2ff3fbc6287a5206f57a083 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/12) | `/test tekton`
github | d29ba18a5f1a7e69835b2b16c75396ec7903802f | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/3) | `/test github`
gitlab | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/28) | `/test gitlab`
pr-build | 79a430da7ab227797d142448049ad63234020007 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/30) | `/test pr-build`
bbs | 6c5562e17b53d9a93275d4c1b401642311828fd0 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/22) | `/test bbs`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
github | d29ba18a5f1a7e69835b2b16c75396ec7903802f | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/3) | `/test github`
gitlab | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/28) | `/test gitlab`
pr-build | 79a430da7ab227797d142448049ad63234020007 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/30) | `/test pr-build`
bbs | 6c5562e17b53d9a93275d4c1b401642311828fd0 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/22) | `/test bbs`
tekton | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/29) | `/test tekton`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
gitlab | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/28) | `/test gitlab`
pr-build | 79a430da7ab227797d142448049ad63234020007 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/30) | `/test pr-build`
bbs | 6c5562e17b53d9a93275d4c1b401642311828fd0 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/22) | `/test bbs`
tekton | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/29) | `/test tekton`
github | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/26) | `/test github`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
gitlab | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/28) | `/test gitlab`
pr-build | 79a430da7ab227797d142448049ad63234020007 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/30) | `/test pr-build`
bbs | 6c5562e17b53d9a93275d4c1b401642311828fd0 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/22) | `/test bbs`
tekton | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/29) | `/test tekton`
github | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/26) | `/test github`
ghe | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/25) | `/test ghe`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
gitlab | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/28) | `/test gitlab`
pr-build | 79a430da7ab227797d142448049ad63234020007 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/30) | `/test pr-build`
bbs | 6c5562e17b53d9a93275d4c1b401642311828fd0 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/22) | `/test bbs`
github | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/26) | `/test github`
ghe | 6c5562e17b53d9a93275d4c1b401642311828fd0 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/20) | `/test ghe`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
gitlab | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/28) | `/test gitlab`
bbs | 6c5562e17b53d9a93275d4c1b401642311828fd0 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/22) | `/test bbs`
github | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/26) | `/test github`
ghe | 6c5562e17b53d9a93275d4c1b401642311828fd0 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/20) | `/test ghe`
pr-build | 83a125d2c0bd8d67adbaa9391aea12b845640946 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/37) | `/test pr-build`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
gitlab | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/28) | `/test gitlab`
bbs | 6c5562e17b53d9a93275d4c1b401642311828fd0 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/22) | `/test bbs`
github | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/26) | `/test github`
ghe | 6c5562e17b53d9a93275d4c1b401642311828fd0 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/20) | `/test ghe`
pr-build | 052109b93e15364c31d1316f5d456bc0de44cb53 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/42) | `/test pr-build`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
gitlab | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/28) | `/test gitlab`
bbs | 6c5562e17b53d9a93275d4c1b401642311828fd0 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/22) | `/test bbs`
ghe | 6c5562e17b53d9a93275d4c1b401642311828fd0 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/20) | `/test ghe`
pr-build | 052109b93e15364c31d1316f5d456bc0de44cb53 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/42) | `/test pr-build`
github | 83a125d2c0bd8d67adbaa9391aea12b845640946 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/38) | `/test github`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
gitlab | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/28) | `/test gitlab`
bbs | 6c5562e17b53d9a93275d4c1b401642311828fd0 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/22) | `/test bbs`
pr-build | 052109b93e15364c31d1316f5d456bc0de44cb53 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/42) | `/test pr-build`
github | 83a125d2c0bd8d67adbaa9391aea12b845640946 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/38) | `/test github`
ghe | 83a125d2c0bd8d67adbaa9391aea12b845640946 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/36) | `/test ghe`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
gitlab | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/28) | `/test gitlab`
bbs | 6c5562e17b53d9a93275d4c1b401642311828fd0 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/22) | `/test bbs`
pr-build | 052109b93e15364c31d1316f5d456bc0de44cb53 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/42) | `/test pr-build`
github | 83a125d2c0bd8d67adbaa9391aea12b845640946 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/38) | `/test github`
ghe | 83a125d2c0bd8d67adbaa9391aea12b845640946 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/36) | `/test ghe`
tekton | 83a125d2c0bd8d67adbaa9391aea12b845640946 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/41) | `/test tekton`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
gitlab | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/28) | `/test gitlab`
pr-build | 052109b93e15364c31d1316f5d456bc0de44cb53 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/42) | `/test pr-build`
github | 83a125d2c0bd8d67adbaa9391aea12b845640946 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/38) | `/test github`
ghe | 83a125d2c0bd8d67adbaa9391aea12b845640946 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/36) | `/test ghe`
tekton | 83a125d2c0bd8d67adbaa9391aea12b845640946 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/41) | `/test tekton`
bbs | 79a430da7ab227797d142448049ad63234020007 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/33) | `/test bbs`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
gitlab | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/28) | `/test gitlab`
pr-build | 052109b93e15364c31d1316f5d456bc0de44cb53 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/42) | `/test pr-build`
github | 83a125d2c0bd8d67adbaa9391aea12b845640946 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/38) | `/test github`
ghe | 83a125d2c0bd8d67adbaa9391aea12b845640946 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/36) | `/test ghe`
bbs | 83a125d2c0bd8d67adbaa9391aea12b845640946 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/39) | `/test bbs`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pr-build | 052109b93e15364c31d1316f5d456bc0de44cb53 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/42) | `/test pr-build`
github | 83a125d2c0bd8d67adbaa9391aea12b845640946 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/38) | `/test github`
ghe | 83a125d2c0bd8d67adbaa9391aea12b845640946 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/36) | `/test ghe`
bbs | 83a125d2c0bd8d67adbaa9391aea12b845640946 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/39) | `/test bbs`
gitlab | 83a125d2c0bd8d67adbaa9391aea12b845640946 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/40) | `/test gitlab`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pr-build | 052109b93e15364c31d1316f5d456bc0de44cb53 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/42) | `/test pr-build`
bbs | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/27) | `/test bbs`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pr-build | 052109b93e15364c31d1316f5d456bc0de44cb53 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/42) | `/test pr-build`
bbs | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/27) | `/test bbs`
ghe | 79a430da7ab227797d142448049ad63234020007 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/31) | `/test ghe`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pr-build | 052109b93e15364c31d1316f5d456bc0de44cb53 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/42) | `/test pr-build`
bbs | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/27) | `/test bbs`
ghe | 79a430da7ab227797d142448049ad63234020007 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/31) | `/test ghe`
github | 79a430da7ab227797d142448049ad63234020007 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/32) | `/test github`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
pr-build | 052109b93e15364c31d1316f5d456bc0de44cb53 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/42) | `/test pr-build`
bbs | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/27) | `/test bbs`
ghe | 79a430da7ab227797d142448049ad63234020007 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/31) | `/test ghe`
github | 79a430da7ab227797d142448049ad63234020007 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/32) | `/test github`
gitlab | 79a430da7ab227797d142448049ad63234020007 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/34) | `/test gitlab`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
bbs | 5d7b35f87baf703b92fc5478c719c6aed7146c75 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/27) | `/test bbs`
ghe | 79a430da7ab227797d142448049ad63234020007 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/31) | `/test ghe`
github | 79a430da7ab227797d142448049ad63234020007 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/32) | `/test github`
gitlab | 79a430da7ab227797d142448049ad63234020007 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/34) | `/test gitlab`
pr-build | c3eeb5a181620ea4f40a570ffde98416ba07bdd8 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/48) | `/test pr-build`

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

<details>

Instructions for interacting with me using PR comments are available [here](https://git.k8s.io/community/contributors/guide/pull-requests.md).  If you have questions or suggestions related to my behavior, please file an issue against the [jenkins-x/lighthouse](https://github.com/jenkins-x/lighthouse/issues/new?title=Command%20issue:) repository. I understand the commands that are listed [here](https://go.k8s.io/bot-commands).
</details>
<!-- test report -->
eddycharly: It should be ready for review. There are probably a few things that could be improved but most of the work has been done.

I will continue with lighthouse config related concern now.
jenkins-x-bot: @eddycharly: The following tests **failed**, say `/retest` to rerun them all:

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ghe | 79a430da7ab227797d142448049ad63234020007 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/31) | `/test ghe`
github | 79a430da7ab227797d142448049ad63234020007 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/32) | `/test github`
gitlab | 79a430da7ab227797d142448049ad63234020007 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/34) | `/test gitlab`
bbs | c3eeb5a181620ea4f40a570ffde98416ba07bdd8 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/51) | `/test bbs`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
ghe | 79a430da7ab227797d142448049ad63234020007 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/31) | `/test ghe`
gitlab | 79a430da7ab227797d142448049ad63234020007 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/34) | `/test gitlab`
bbs | c3eeb5a181620ea4f40a570ffde98416ba07bdd8 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/51) | `/test bbs`
github | c3eeb5a181620ea4f40a570ffde98416ba07bdd8 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/50) | `/test github`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
gitlab | 79a430da7ab227797d142448049ad63234020007 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/34) | `/test gitlab`
bbs | c3eeb5a181620ea4f40a570ffde98416ba07bdd8 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/51) | `/test bbs`
github | c3eeb5a181620ea4f40a570ffde98416ba07bdd8 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/50) | `/test github`
ghe | c3eeb5a181620ea4f40a570ffde98416ba07bdd8 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/49) | `/test ghe`

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

<details>

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

Test name | Commit | Details | Rerun command
--- | --- | --- | ---
bbs | c3eeb5a181620ea4f40a570ffde98416ba07bdd8 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/51) | `/test bbs`
github | c3eeb5a181620ea4f40a570ffde98416ba07bdd8 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/50) | `/test github`
ghe | c3eeb5a181620ea4f40a570ffde98416ba07bdd8 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/49) | `/test ghe`
gitlab | c3eeb5a181620ea4f40a570ffde98416ba07bdd8 | [link](https://dashboard-jx.jenkins-x.live/teams/jx/projects/jenkins-x/lighthouse/PR-968/52) | `/test gitlab`

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

<details>

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

Patch:
diff --git a/Makefile b/Makefile
index c0b29540..5ee06a3f 100644
--- a/Makefile
+++ b/Makefile
@@ -28,7 +28,7 @@ GO_LDFLAGS :=  -X $(PROJECT)/pkg/version.Version='$(VERSION)'
 GO_DEPENDENCIES := $(call rwildcard,pkg/,*.go) $(call rwildcard,cmd/,*.go)
 
 .PHONY: all
-all: docs build test check
+all: build test check docs
 
 .PHONY: test
 test: 
@@ -188,7 +188,6 @@ config-docs:
 		--input-file ../pkg/config/config.go \
 		--input-file ../pkg/config/constants.go \
 		--input-file ../pkg/config/githuboauth.go \
-		--input-file ../pkg/config/jobs.go \
 		--input-file ../pkg/config/keeper.go \
 		--title "Lighthouse config" \
 		--output-path ../docs/config
diff --git a/cmd/foghorn/main.go b/cmd/foghorn/main.go
index 01867b57..1f62674a 100644
--- a/cmd/foghorn/main.go
+++ b/cmd/foghorn/main.go
@@ -5,11 +5,11 @@ import (
 	"os"
 
 	lighthousev1alpha1 "github.com/jenkins-x/lighthouse/pkg/apis/lighthouse/v1alpha1"
+	"github.com/jenkins-x/lighthouse/pkg/clients"
 	"github.com/jenkins-x/lighthouse/pkg/foghorn"
 	"github.com/jenkins-x/lighthouse/pkg/logrusutil"
 	"github.com/sirupsen/logrus"
 	"k8s.io/apimachinery/pkg/runtime"
-	"k8s.io/client-go/tools/clientcmd"
 	ctrl "sigs.k8s.io/controller-runtime"
 )
 
@@ -46,7 +46,7 @@ func main() {
 		logrus.WithError(err).Fatal("Invalid options")
 	}
 
-	cfg, err := clientcmd.BuildConfigFromFlags("", "")
+	cfg, err := clients.GetConfig("", "")
 	if err != nil {
 		logrus.WithError(err).Fatal("Could not create kubeconfig")
 	}
diff --git a/cmd/gc/main.go b/cmd/gc/main.go
index 1dec2274..f6dadcef 100644
--- a/cmd/gc/main.go
+++ b/cmd/gc/main.go
@@ -9,10 +9,10 @@ import (
 	"github.com/jenkins-x/lighthouse/pkg/apis/lighthouse/v1alpha1"
 	clientset "github.com/jenkins-x/lighthouse/pkg/client/clientset/versioned"
 	lhclient "github.com/jenkins-x/lighthouse/pkg/client/clientset/versioned/typed/lighthouse/v1alpha1"
+	"github.com/jenkins-x/lighthouse/pkg/clients"
 	"github.com/jenkins-x/lighthouse/pkg/logrusutil"
 	"github.com/sirupsen/logrus"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
-	"k8s.io/client-go/tools/clientcmd"
 )
 
 type options struct {
@@ -48,7 +48,7 @@ func main() {
 		logrus.WithError(err).Fatal("Invalid options")
 	}
 
-	cfg, err := clientcmd.BuildConfigFromFlags("", "")
+	cfg, err := clients.GetConfig("", "")
 	if err != nil {
 		logrus.WithError(err).Fatal("Could not create kubeconfig")
 	}
diff --git a/cmd/keeper/main.go b/cmd/keeper/main.go
index e851c84e..c80b5109 100644
--- a/cmd/keeper/main.go
+++ b/cmd/keeper/main.go
@@ -24,6 +24,7 @@ import (
 	"time"
 
 	"github.com/jenkins-x/lighthouse/pkg/config"
+	configutil "github.com/jenkins-x/lighthouse/pkg/config/util"
 	"github.com/jenkins-x/lighthouse/pkg/interrupts"
 	"github.com/jenkins-x/lighthouse/pkg/jobutil"
 	"github.com/jenkins-x/lighthouse/pkg/keeper"
@@ -86,7 +87,7 @@ func gatherOptions(fs *flag.FlagSet, args ...string) options {
 	if err != nil {
 		logrus.WithError(err).Fatal("Invalid options")
 	}
-	o.configPath = config.Path(o.configPath)
+	o.configPath = configutil.PathOrDefault(o.configPath)
 	return o
 }
 
diff --git a/cmd/tektoncontroller/main.go b/cmd/tektoncontroller/main.go
index ffb2dc2e..82c1c477 100644
--- a/cmd/tektoncontroller/main.go
+++ b/cmd/tektoncontroller/main.go
@@ -5,13 +5,13 @@ import (
 	"os"
 
 	lighthousev1alpha1 "github.com/jenkins-x/lighthouse/pkg/apis/lighthouse/v1alpha1"
+	"github.com/jenkins-x/lighthouse/pkg/clients"
 	tektonengine "github.com/jenkins-x/lighthouse/pkg/engines/tekton"
 	"github.com/jenkins-x/lighthouse/pkg/interrupts"
 	"github.com/jenkins-x/lighthouse/pkg/logrusutil"
 	"github.com/sirupsen/logrus"
 	pipelinev1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
 	"k8s.io/apimachinery/pkg/runtime"
-	"k8s.io/client-go/tools/clientcmd"
 	ctrl "sigs.k8s.io/controller-runtime"
 )
 
@@ -52,7 +52,7 @@ func main() {
 		logrus.WithError(err).Fatal("Invalid options")
 	}
 
-	cfg, err := clientcmd.BuildConfigFromFlags("", "")
+	cfg, err := clients.GetConfig("", "")
 	if err != nil {
 		logrus.WithError(err).Fatal("Could not create kubeconfig")
 	}
diff --git a/docs/config/Lighthouse config.md b/docs/config/Lighthouse config.md
index 528e5a9f..cdb32b8c 100644
--- a/docs/config/Lighthouse config.md
+++ b/docs/config/Lighthouse config.md
@@ -2,8 +2,6 @@
 
 - [Branch](#Branch)
 - [BranchProtection](#BranchProtection)
-- [Brancher](#Brancher)
-- [ChangedFilesProvider](#ChangedFilesProvider)
 - [Config](#Config)
 - [ContextPolicy](#ContextPolicy)
 - [Controller](#Controller)
@@ -11,7 +9,6 @@
 - [GitHubOptions](#GitHubOptions)
 - [GithubOAuthConfig](#GithubOAuthConfig)
 - [JenkinsOperator](#JenkinsOperator)
-- [JobBase](#JobBase)
 - [JobConfig](#JobConfig)
 - [Keeper](#Keeper)
 - [KeeperContextPolicy](#KeeperContextPolicy)
@@ -23,26 +20,18 @@
 - [KeeperRepoContextPolicy](#KeeperRepoContextPolicy)
 - [Org](#Org)
 - [OwnersDirExcludes](#OwnersDirExcludes)
-- [Periodic](#Periodic)
 - [PipelineKind](#PipelineKind)
-- [PipelineRunParam](#PipelineRunParam)
 - [Plank](#Plank)
 - [Policy](#Policy)
-- [Postsubmit](#Postsubmit)
-- [Preset](#Preset)
-- [Presubmit](#Presubmit)
 - [ProviderConfig](#ProviderConfig)
 - [ProwConfig](#ProwConfig)
 - [PubsubSubscriptions](#PubsubSubscriptions)
 - [PullRequestMergeType](#PullRequestMergeType)
 - [PushGateway](#PushGateway)
 - [QueryMap](#QueryMap)
-- [RegexpChangeMatcher](#RegexpChangeMatcher)
 - [Repo](#Repo)
-- [Reporter](#Reporter)
 - [Restrictions](#Restrictions)
 - [ReviewPolicy](#ReviewPolicy)
-- [UtilityConfig](#UtilityConfig)
 
 
 ## Branch
@@ -65,23 +54,6 @@ BranchProtection specifies the global branch protection policy
 | AllowDisabledPolicies | `allow_disabled_policies` | bool | No | AllowDisabledPolicies allows a child to disable all protection even if the<br />branch has inherited protection options from a parent. |
 | AllowDisabledJobPolicies | `allow_disabled_job_policies` | bool | No | AllowDisabledJobPolicies allows a branch to choose to opt out of branch protection<br />even if Prow has registered required jobs for that branch. |
 
-## Brancher
-
-Brancher is for shared code between jobs that only run against certain<br />branches. An empty brancher runs against all branches.
-
-| Variable Name | Stanza | Type | Required | Description |
-|---|---|---|---|---|
-| SkipBranches | `skip_branches` | []string | No | Do not run against these branches. Default is no branches. |
-| Branches | `branches` | []string | No | Only run against these branches. Default is all branches. |
-| re |  | *regexp.Regexp | No | We'll set these when we load it. |
-| reSkip |  | *regexp.Regexp | No |  |
-
-## ChangedFilesProvider
-
-ChangedFilesProvider returns a slice of modified files.
-
-
-
 ## Config
 
 Config is a read-only snapshot of the config.
@@ -154,36 +126,11 @@ JenkinsOperator is config for the jenkins-operator controller.
 | LabelSelectorString | `label_selector` | string | No | LabelSelectorString compiles into LabelSelector at load time.<br />If set, this option needs to match --label-selector used by<br />the desired jenkins-operator. This option is considered<br />invalid when provided with a single jenkins-operator config.<br /><br />For label selector syntax, see below:<br />https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/#label-selectors |
 | LabelSelector | `-` | labels.Selector | Yes | LabelSelector is used so different jenkins-operator replicas<br />can use their own configuration. |
 
-## JobBase
-
-JobBase contains attributes common to all job types
-
-| Variable Name | Stanza | Type | Required | Description |
-|---|---|---|---|---|
-| Name | `name` | string | Yes | The name of the job. Must match regex [A-Za-z0-9-._]+<br />e.g. pull-test-infra-bazel-build |
-| Labels | `labels` | map[string]string | No | Labels are added to LighthouseJobs and pods created for this job. |
-| Annotations | `annotations` | map[string]string | No | Annotations are unused by prow itself, but provide a space to configure other automation. |
-| MaxConcurrency | `max_concurrency` | int | No | MaximumConcurrency of this job, 0 implies no limit. |
-| Agent | `agent` | string | Yes | Agent that will take care of running this job. |
-| Cluster | `cluster` | string | No | Cluster is the alias of the cluster to run this job in.<br />(Default: kube.DefaultClusterAlias) |
-| Namespace | `namespace` | *string | No | Namespace is the namespace in which pods schedule.<br />  nil: results in config.PodNamespace (aka pod default)<br />  empty: results in config.LighthouseJobNamespace (aka same as LighthouseJob) |
-| ErrorOnEviction | `error_on_eviction` | bool | No | ErrorOnEviction indicates that the LighthouseJob should be completed and given<br />the ErrorState status if the pod that is executing the job is evicted.<br />If this field is unspecified or false, a new pod will be created to replace<br />the evicted one. |
-| SourcePath | `-` | string | Yes | SourcePath contains the path where this job is defined |
-| Spec | `spec` | *v1.PodSpec | No | Spec is the Kubernetes pod spec used if Agent is kubernetes. |
-| PipelineRunSpec | `pipeline_run_spec` | *tektonv1beta1.PipelineRunSpec | No | PipelineRunSpec is the Tekton PipelineRun spec used if agent is tekton-pipeline |
-| PipelineRunParams | `pipeline_run_params` | [][PipelineRunParam](#PipelineRunParam) | No | PipelineRunParams are the params used by the pipeline run |
-|  |  | [UtilityConfig](#UtilityConfig) | Yes |  |
-
 ## JobConfig
 
-JobConfig is config for all prow jobs
+JobConfig is a type alias for job.Config
+
 
-| Variable Name | Stanza | Type | Required | Description |
-|---|---|---|---|---|
-| Presets | `presets` | [][Preset](#Preset) | No | Presets apply to all job types. |
-| Presubmits | `presubmits` | map[string][][Presubmit](#Presubmit) | No | Full repo name (such as "kubernetes/kubernetes") -> list of jobs. |
-| Postsubmits | `postsubmits` | map[string][][Postsubmit](#Postsubmit) | No |  |
-| Periodics | `periodics` | [][Periodic](#Periodic) | No | Periodics are not associated with any repo. |
 
 ## Keeper
 
@@ -298,33 +245,12 @@ OwnersDirExcludes is used to configure which directories to ignore when<br />sea
 | Repos | `repos` | map[string][]string | No | Repos configures a directory blacklist per repo (or org) |
 | Default | `default` | []string | No | Default configures a default blacklist for repos (or orgs) not<br />specifically configured |
 
-## Periodic
-
-Periodic runs on a timer.
-
-| Variable Name | Stanza | Type | Required | Description |
-|---|---|---|---|---|
-|  |  | [JobBase](#JobBase) | Yes |  |
-| Interval | `interval` | string | Yes | (deprecated)Interval to wait between two runs of the job. |
-| Cron | `cron` | string | Yes | Cron representation of job trigger time |
-| Tags | `tags` | []string | No | Tags for config entries |
-| interval |  | time.Duration | Yes |  |
-
 ## PipelineKind
 
 PipelineKind specifies how the job is triggered.
 
 
 
-## PipelineRunParam
-
-PipelineRunParam represents a param used by the pipeline run
-
-| Variable Name | Stanza | Type | Required | Description |
-|---|---|---|---|---|
-| Name | `name` | string | No | Name is the name of the param |
-| ValueTemplate | `value_template` | string | No | ValueTemplate is the template used to build the value from well know variables |
-
 ## Plank
 
 Plank is config for the plank controller.
@@ -347,43 +273,6 @@ Policy for the config/org/repo/branch.<br />When merging policies, a nil value r
 | RequiredPullRequestReviews | `required_pull_request_reviews` | *[ReviewPolicy](#ReviewPolicy) | No | RequiredPullRequestReviews specifies github approval/review criteria. |
 | Exclude | `exclude` | []string | No | Exclude specifies a set of regular expressions which identify branches<br />that should be excluded from the protection policy |
 
-## Postsubmit
-
-Postsubmit runs on push events.
-
-| Variable Name | Stanza | Type | Required | Description |
-|---|---|---|---|---|
-|  |  | [JobBase](#JobBase) | Yes |  |
-|  |  | [RegexpChangeMatcher](#RegexpChangeMatcher) | Yes |  |
-|  |  | [Brancher](#Brancher) | Yes |  |
-|  |  | [Reporter](#Reporter) | Yes | TODO(krzyzacy): Move existing `Report` into `Skip_Report` once this is deployed |
-
-## Preset
-
-Preset is intended to match the k8s' PodPreset feature, and may be removed<br />if that feature goes beta.
-
-| Variable Name | Stanza | Type | Required | Description |
-|---|---|---|---|---|
-| Labels | `labels` | map[string]string | No |  |
-| Env | `env` | []v1.EnvVar | No |  |
-| Volumes | `volumes` | []v1.Volume | No |  |
-| VolumeMounts | `volumeMounts` | []v1.VolumeMount | No |  |
-
-## Presubmit
-
-Presubmit runs on PRs.
-
-| Variable Name | Stanza | Type | Required | Description |
-|---|---|---|---|---|
-|  |  | [JobBase](#JobBase) | Yes |  |
-| AlwaysRun | `always_run` | bool | Yes | AlwaysRun automatically for every PR, or only when a comment triggers it. |
-| Optional | `optional` | bool | No | Optional indicates that the job's status context should not be required for merge. |
-| Trigger | `trigger` | string | No | Trigger is the regular expression to trigger the job.<br />e.g. `@k8s-bot e2e test this`<br />RerunCommand must also be specified if this field is specified.<br />(Default: `(?m)^/test (?:.*? )?<job name>(?: .*?)?$`) |
-| RerunCommand | `rerun_command` | string | No | The RerunCommand to give users. Must match Trigger.<br />Trigger must also be specified if this field is specified.<br />(Default: `/test <job name>`) |
-|  |  | [Brancher](#Brancher) | Yes |  |
-|  |  | [RegexpChangeMatcher](#RegexpChangeMatcher) | Yes |  |
-|  |  | [Reporter](#Reporter) | Yes |  |
-
 ## ProviderConfig
 
 ProviderConfig is optionally used to configure information about the SCM provider being used. These values will be<br />used as fallbacks if environment variables aren't set.
@@ -448,15 +337,6 @@ QueryMap is a struct mapping from "org/repo" -> KeeperQueries that<br />apply to
 | cache |  | map[string][KeeperQueries](#KeeperQueries) | No |  |
 |  |  | sync.Mutex | Yes |  |
 
-## RegexpChangeMatcher
-
-RegexpChangeMatcher is for code shared between jobs that run only when certain files are changed.
-
-| Variable Name | Stanza | Type | Required | Description |
-|---|---|---|---|---|
-| RunIfChanged | `run_if_changed` | string | No | RunIfChanged defines a regex used to select which subset of file changes should trigger this job.<br />If any file in the changeset matches this regex, the job will be triggered |
-| reChanges |  | *regexp.Regexp | No |  |
-
 ## Repo
 
 Repo holds protection policy overrides for all branches in a repo, as well as specific branch overrides.
@@ -466,15 +346,6 @@ Repo holds protection policy overrides for all branches in a repo, as well as sp
 |  |  | [Policy](#Policy) | Yes |  |
 | Branches | `branches` | map[string][Branch](#Branch) | No |  |
 
-## Reporter
-
-Reporter keeps various details for status reporting
-
-| Variable Name | Stanza | Type | Required | Description |
-|---|---|---|---|---|
-| Context | `context` | string | No | Context is the name of the GitHub status context for the job.<br />Defaults: the same as the name of the job. |
-| SkipReport | `skip_report` | bool | No | SkipReport skips commenting and setting status on GitHub. |
-
 ## Restrictions
 
 Restrictions limits who can merge<br />Users and Teams items are appended to parent lists.
@@ -495,16 +366,4 @@ ReviewPolicy specifies github approval/review criteria.<br />Any nil values inhe
 | RequireOwners | `require_code_owner_reviews` | *bool | No | RequireOwners overrides whether CODEOWNERS must approve PRs if set |
 | Approvals | `required_approving_review_count` | *int | No | Approvals overrides the number of approvals required if set (set to 0 to disable) |
 
-## UtilityConfig
-
-UtilityConfig holds decoration metadata, such as how to clone and additional containers/etc
-
-| Variable Name | Stanza | Type | Required | Description |
-|---|---|---|---|---|
-| Decorate | `decorate` | bool | No | Decorate determines if we decorate the PodSpec or not |
-| PathAlias | `path_alias` | string | No | PathAlias is the location under <root-dir>/src<br />where the repository under test is cloned. If this<br />is not set, <root-dir>/src/github.com/org/repo will<br />be used as the default. |
-| CloneURI | `clone_uri` | string | No | CloneURI is the URI that is used to clone the<br />repository. If unset, will default to<br />`https://github.com/org/repo.git`. |
-| SkipSubmodules | `skip_submodules` | bool | No | SkipSubmodules determines if submodules should be<br />cloned when the job is run. Defaults to true. |
-| CloneDepth | `clone_depth` | int | No | CloneDepth is the depth of the clone that will be used.<br />A depth of zero will do a full clone. |
-
 
diff --git a/docs/crds/Lighthouse (v1alpha1).md b/docs/crds/Lighthouse (v1alpha1).md
index 78df9373..214738a0 100644
--- a/docs/crds/Lighthouse (v1alpha1).md
+++ b/docs/crds/Lighthouse (v1alpha1).md
@@ -116,7 +116,7 @@ LighthouseJobSpec the spec of a pipeline request
 | RerunCommand | `rerun_command` | string | No | RerunCommand is the command a user would write to<br />trigger this job on their pull request |
 | MaxConcurrency | `max_concurrency` | int | No | MaxConcurrency restricts the total number of instances<br />of this job that can run in parallel at once |
 | PipelineRunSpec | `pipeline_run_spec` | *tektonv1beta1.PipelineRunSpec | No | PipelineRunSpec provides the basis for running the test as a Tekton Pipeline<br />https://github.com/tektoncd/pipeline |
-| PipelineRunParams | `pipeline_run_params` | []config.PipelineRunParam | No | PipelineRunParams are the params used by the pipeline run |
+| PipelineRunParams | `pipeline_run_params` | []job.PipelineRunParam | No | PipelineRunParams are the params used by the pipeline run |
 | PodSpec | `pod_spec` | *corev1.PodSpec | No | PodSpec provides the basis for running the test under a Kubernetes agent |
 
 ## LighthouseJobStatus
diff --git a/pkg/apis/lighthouse/v1alpha1/types.go b/pkg/apis/lighthouse/v1alpha1/types.go
index 37936233..b1be16e3 100644
--- a/pkg/apis/lighthouse/v1alpha1/types.go
+++ b/pkg/apis/lighthouse/v1alpha1/types.go
@@ -8,6 +8,7 @@ import (
 	"time"
 
 	"github.com/jenkins-x/lighthouse/pkg/config"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	tektonv1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -145,7 +146,7 @@ type LighthouseJobSpec struct {
 	// https://github.com/tektoncd/pipeline
 	PipelineRunSpec *tektonv1beta1.PipelineRunSpec `json:"pipeline_run_spec,omitempty"`
 	// PipelineRunParams are the params used by the pipeline run
-	PipelineRunParams []config.PipelineRunParam `json:"pipeline_run_params,omitempty"`
+	PipelineRunParams []job.PipelineRunParam `json:"pipeline_run_params,omitempty"`
 	// PodSpec provides the basis for running the test under a Kubernetes agent
 	PodSpec *corev1.PodSpec `json:"pod_spec,omitempty"`
 }
diff --git a/pkg/apis/lighthouse/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/lighthouse/v1alpha1/zz_generated.deepcopy.go
index e3030e43..1ae74de9 100644
--- a/pkg/apis/lighthouse/v1alpha1/zz_generated.deepcopy.go
+++ b/pkg/apis/lighthouse/v1alpha1/zz_generated.deepcopy.go
@@ -5,7 +5,7 @@
 package v1alpha1
 
 import (
-	config "github.com/jenkins-x/lighthouse/pkg/config"
+	job "github.com/jenkins-x/lighthouse/pkg/config/job"
 	v1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
 	v1 "k8s.io/api/core/v1"
 	runtime "k8s.io/apimachinery/pkg/runtime"
@@ -263,7 +263,7 @@ func (in *LighthouseJobSpec) DeepCopyInto(out *LighthouseJobSpec) {
 	}
 	if in.PipelineRunParams != nil {
 		in, out := &in.PipelineRunParams, &out.PipelineRunParams
-		*out = make([]config.PipelineRunParam, len(*in))
+		*out = make([]job.PipelineRunParam, len(*in))
 		copy(*out, *in)
 	}
 	if in.PodSpec != nil {
diff --git a/pkg/clients/clients.go b/pkg/clients/clients.go
index 69145b96..f050b0fa 100644
--- a/pkg/clients/clients.go
+++ b/pkg/clients/clients.go
@@ -1,6 +1,11 @@
 package clients
 
 import (
+	"fmt"
+	"os"
+	"os/user"
+	"path/filepath"
+
 	clientset "github.com/jenkins-x/lighthouse/pkg/client/clientset/versioned"
 	"github.com/pkg/errors"
 	"k8s.io/client-go/rest"
@@ -15,7 +20,7 @@ import (
 
 // GetAPIClients returns the tekton, kube, and Lighthouse clients and the kubeconfig used to create them
 func GetAPIClients() (tektonclient.Interface, kubeclient.Interface, clientset.Interface, *rest.Config, error) {
-	kubeCfg, err := clientcmd.BuildConfigFromFlags("", "")
+	kubeCfg, err := GetConfig("", "")
 	if err != nil {
 		return nil, nil, nil, nil, errors.Wrap(err, "unable to get kubeconfig")
 	}
@@ -37,3 +42,31 @@ func GetAPIClients() (tektonclient.Interface, kubeclient.Interface, clientset.In
 
 	return tektonClient, kubeClient, lhClient, kubeCfg, nil
 }
+
+// GetConfig returns a rest.Config to be used for kubernetes client creation.
+// It does so in the following order:
+//   1. Use the passed kubeconfig/masterURL.
+//   2. Fallback to the KUBECONFIG environment variable.
+//   3. Fallback to in-cluster config.
+//   4. Fallback to the ~/.kube/config.
+func GetConfig(masterURL, kubeconfig string) (*rest.Config, error) {
+	if kubeconfig == "" {
+		kubeconfig = os.Getenv("KUBECONFIG")
+	}
+	// If we have an explicit indication of where the kubernetes config lives, read that.
+	if kubeconfig != "" {
+		return clientcmd.BuildConfigFromFlags(masterURL, kubeconfig)
+	}
+	// If not, try the in-cluster config.
+	if c, err := rest.InClusterConfig(); err == nil {
+		return c, nil
+	}
+	// If no in-cluster config, try the default location in the user's home directory.
+	if usr, err := user.Current(); err == nil {
+		if c, err := clientcmd.BuildConfigFromFlags("", filepath.Join(usr.HomeDir, ".kube", "config")); err == nil {
+			return c, nil
+		}
+	}
+
+	return nil, fmt.Errorf("could not create a valid kubeconfig")
+}
diff --git a/pkg/config/branch_protection.go b/pkg/config/branch_protection.go
index 7eff4a36..d4bc1193 100644
--- a/pkg/config/branch_protection.go
+++ b/pkg/config/branch_protection.go
@@ -20,6 +20,7 @@ import (
 	"errors"
 	"fmt"
 
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/sirupsen/logrus"
 	"k8s.io/apimachinery/pkg/util/sets"
 )
@@ -298,7 +299,7 @@ func (c *Config) GetPolicy(org, repo, branch string, b Branch) (*Policy, error)
 //  - contexts that are always required to be present
 //  - contexts that are required, _if_ present
 //  - contexts that are always optional
-func BranchRequirements(org, repo, branch string, presubmits map[string][]Presubmit) ([]string, []string, []string) {
+func BranchRequirements(org, repo, branch string, presubmits map[string][]job.Presubmit) ([]string, []string, []string) {
 	jobs, ok := presubmits[org+"/"+repo]
 	if !ok {
 		return nil, nil, nil
diff --git a/pkg/config/config.go b/pkg/config/config.go
index 1558e13d..d89f68aa 100644
--- a/pkg/config/config.go
+++ b/pkg/config/config.go
@@ -30,7 +30,9 @@ import (
 	"time"
 
 	"github.com/jenkins-x/go-scm/scm"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/config/org"
+	"github.com/jenkins-x/lighthouse/pkg/config/util"
 	"github.com/sirupsen/logrus"
 	"gopkg.in/robfig/cron.v2"
 	v1 "k8s.io/api/core/v1"
@@ -51,24 +53,17 @@ const (
 	gcsCredentialsMountPath = "/secrets/gcs"
 )
 
+var jobNameRegex = regexp.MustCompile(`^[A-Za-z0-9-._]+$`)
+
+// JobConfig is a type alias for job.Config
+type JobConfig = job.Config
+
 // Config is a read-only snapshot of the config.
 type Config struct {
 	JobConfig
 	ProwConfig
 }
 
-// JobConfig is config for all prow jobs
-type JobConfig struct {
-	// Presets apply to all job types.
-	Presets []Preset `json:"presets,omitempty"`
-	// Full repo name (such as "kubernetes/kubernetes") -> list of jobs.
-	Presubmits  map[string][]Presubmit  `json:"presubmits,omitempty"`
-	Postsubmits map[string][]Postsubmit `json:"postsubmits,omitempty"`
-
-	// Periodics are not associated with any repo.
-	Periodics []Periodic `json:"periodics,omitempty"`
-}
-
 // ProwConfig is config for all prow controllers
 type ProwConfig struct {
 	Keeper           Keeper                `json:"tide,omitempty"`
@@ -289,7 +284,7 @@ func loadConfigFromFiles(prowConfig, jobConfig string) (*Config, error) {
 
 	if !stat.IsDir() {
 		// still support a single file
-		var jc JobConfig
+		var jc job.Config
 		if err := yamlToConfig(jobConfig, &jc); err != nil {
 			return nil, err
 		}
@@ -333,7 +328,7 @@ func loadConfigFromFiles(prowConfig, jobConfig string) (*Config, error) {
 		}
 		uniqueBasenames.Insert(base)
 
-		var subConfig JobConfig
+		var subConfig job.Config
 		if err := yamlToConfig(path, &subConfig); err != nil {
 			return err
 		}
@@ -356,15 +351,15 @@ func yamlToConfig(path string, nc interface{}) error {
 	if err := yaml.Unmarshal(b, nc); err != nil {
 		return fmt.Errorf("error unmarshaling %s: %v", path, err)
 	}
-	var jc *JobConfig
+	var jc *job.Config
 	switch v := nc.(type) {
-	case *JobConfig:
+	case *job.Config:
 		jc = v
 	case *Config:
 		jc = &v.JobConfig
 	}
 	for rep := range jc.Presubmits {
-		fix := func(job *Presubmit) {
+		fix := func(job *job.Presubmit) {
 			job.SourcePath = path
 		}
 		for i := range jc.Presubmits[rep] {
@@ -372,7 +367,7 @@ func yamlToConfig(path string, nc interface{}) error {
 		}
 	}
 	for rep := range jc.Postsubmits {
-		fix := func(job *Postsubmit) {
+		fix := func(job *job.Postsubmit) {
 			job.SourcePath = path
 		}
 		for i := range jc.Postsubmits[rep] {
@@ -380,7 +375,7 @@ func yamlToConfig(path string, nc interface{}) error {
 		}
 	}
 
-	fix := func(job *Periodic) {
+	fix := func(job *job.Periodic) {
 		job.SourcePath = path
 	}
 	for i := range jc.Periodics {
@@ -389,13 +384,13 @@ func yamlToConfig(path string, nc interface{}) error {
 	return nil
 }
 
-// mergeConfig merges two JobConfig together
+// mergeConfig merges two job.Config together
 // It will try to merge:
 //	- Presubmits
 //	- Postsubmits
 // 	- Periodics
 //	- PodPresets
-func (c *Config) mergeJobConfig(jc JobConfig) error {
+func (c *Config) mergeJobConfig(jc job.Config) error {
 	// Merge everything
 	// *** Presets ***
 	c.Presets = append(c.Presets, jc.Presets...)
@@ -417,7 +412,7 @@ func (c *Config) mergeJobConfig(jc JobConfig) error {
 
 	// *** Presubmits ***
 	if c.Presubmits == nil {
-		c.Presubmits = make(map[string][]Presubmit)
+		c.Presubmits = make(map[string][]job.Presubmit)
 	}
 	for repo, jobs := range jc.Presubmits {
 		c.Presubmits[repo] = append(c.Presubmits[repo], jobs...)
@@ -425,7 +420,7 @@ func (c *Config) mergeJobConfig(jc JobConfig) error {
 
 	// *** Postsubmits ***
 	if c.Postsubmits == nil {
-		c.Postsubmits = make(map[string][]Postsubmit)
+		c.Postsubmits = make(map[string][]job.Postsubmit)
 	}
 	for repo, jobs := range jc.Postsubmits {
 		c.Postsubmits[repo] = append(c.Postsubmits[repo], jobs...)
@@ -434,14 +429,14 @@ func (c *Config) mergeJobConfig(jc JobConfig) error {
 	return nil
 }
 
-func setPresubmitDecorationDefaults(c *Config, ps *Presubmit) {
+func setPresubmitDecorationDefaults(c *Config, ps *job.Presubmit) {
 	/*	if ps.Decorate {
 			ps.DecorationConfig = ps.DecorationConfig.ApplyDefault(c.Plank.DefaultDecorationConfig)
 		}
 	*/
 }
 
-func setPostsubmitDecorationDefaults(c *Config, ps *Postsubmit) {
+func setPostsubmitDecorationDefaults(c *Config, ps *job.Postsubmit) {
 	/*
 		if ps.Decorate {
 			ps.DecorationConfig = ps.DecorationConfig.ApplyDefault(c.Plank.DefaultDecorationConfig)
@@ -450,7 +445,7 @@ func setPostsubmitDecorationDefaults(c *Config, ps *Postsubmit) {
 	*/
 }
 
-func setPeriodicDecorationDefaults(c *Config, ps *Periodic) {
+func setPeriodicDecorationDefaults(c *Config, ps *job.Periodic) {
 	/*
 		if ps.Decorate {
 			ps.DecorationConfig = ps.DecorationConfig.ApplyDefault(c.Plank.DefaultDecorationConfig)
@@ -471,7 +466,7 @@ func (c *Config) finalizeAndValidate() (*Config, error) {
 
 // finalizeJobConfig mutates and fixes entries for jobspecs
 func (c *Config) finalizeJobConfig() error {
-	if c.decorationRequested() {
+	if c.DecorationRequested() {
 		/*		if c.Plank.DefaultDecorationConfig == nil {
 					return errors.New("no default decoration config provided for plank")
 				}
@@ -503,35 +498,33 @@ func (c *Config) finalizeJobConfig() error {
 	}
 
 	// Ensure that regexes are valid and set defaults.
-	for _, vs := range c.Presubmits {
-		c.defaultPresubmitFields(vs)
-		if err := SetPresubmitRegexes(vs); err != nil {
-			return fmt.Errorf("could not set regex: %v", err)
-		}
-	}
-	for _, js := range c.Postsubmits {
-		c.defaultPostsubmitFields(js)
-		if err := SetPostsubmitRegexes(js); err != nil {
-			return fmt.Errorf("could not set regex: %v", err)
-		}
-	}
-
-	c.defaultPeriodicFields(c.Periodics)
-
-	for _, v := range c.AllPresubmits(nil) {
-		if err := resolvePresets(v.Name, v.Labels, v.Spec, c.Presets); err != nil {
-			return err
+	for _, ps := range c.Presubmits {
+		for i := range ps {
+			ps[i].SetDefaults(c.PodNamespace)
+			if err := ps[i].SetRegexes(); err != nil {
+				return fmt.Errorf("could not set regex: %v", err)
+			}
+			if err := resolvePresets(ps[i].Name, ps[i].Labels, ps[i].Spec, c.Presets); err != nil {
+				return err
+			}
 		}
 	}
 
-	for _, v := range c.AllPostsubmits(nil) {
-		if err := resolvePresets(v.Name, v.Labels, v.Spec, c.Presets); err != nil {
-			return err
+	for _, ps := range c.Postsubmits {
+		for i := range ps {
+			ps[i].SetDefaults(c.PodNamespace)
+			if err := ps[i].SetRegexes(); err != nil {
+				return fmt.Errorf("could not set regex: %v", err)
+			}
+			if err := resolvePresets(ps[i].Name, ps[i].Labels, ps[i].Spec, c.Presets); err != nil {
+				return err
+			}
 		}
 	}
 
-	for _, v := range c.AllPeriodics() {
-		if err := resolvePresets(v.Name, v.Labels, v.Spec, c.Presets); err != nil {
+	for i := range c.Periodics {
+		c.Periodics[i].SetDefaults(c.PodNamespace)
+		if err := resolvePresets(c.Periodics[i].Name, c.Periodics[i].Labels, c.Periodics[i].Spec, c.Presets); err != nil {
 			return err
 		}
 	}
@@ -543,9 +536,7 @@ func (c *Config) finalizeJobConfig() error {
 	return nil
 }
 
-var jobNameRegex = regexp.MustCompile(`^[A-Za-z0-9-._]+$`)
-
-func validateJobBase(v JobBase, jobType PipelineKind, podNamespace string) error {
+func validateJobBase(v job.Base, jobType PipelineKind, podNamespace string) error {
 	if !jobNameRegex.MatchString(v.Name) {
 		return fmt.Errorf("name: must match regex %q", jobNameRegex.String())
 	}
@@ -577,7 +568,7 @@ func (c *Config) validateJobConfig() error {
 
 	// Validate presubmits.
 	// Checking that no duplicate job in prow config exists on the same org / repo / branch.
-	validPresubmits := map[orgRepoJobName][]Presubmit{}
+	validPresubmits := map[orgRepoJobName][]job.Presubmit{}
 	for repo, jobs := range c.Presubmits {
 		for _, job := range jobs {
 			repoJobName := orgRepoJobName{repo, job.Name}
@@ -590,18 +581,20 @@ func (c *Config) validateJobConfig() error {
 		}
 	}
 
-	for _, v := range c.AllPresubmits(nil) {
-		if err := validateJobBase(v.JobBase, PresubmitJob, c.PodNamespace); err != nil {
-			return fmt.Errorf("invalid presubmit job %s: %v", v.Name, err)
-		}
-		if err := validateTriggering(v); err != nil {
-			return err
+	for _, ps := range c.Presubmits {
+		for _, j := range ps {
+			if err := validateJobBase(j.Base, PresubmitJob, c.PodNamespace); err != nil {
+				return fmt.Errorf("invalid presubmit job %s: %v", j.Name, err)
+			}
+			if err := validateTriggering(j); err != nil {
+				return err
+			}
 		}
 	}
 
 	// Validate postsubmits.
 	// Checking that no duplicate job in prow config exists on the same org / repo / branch.
-	validPostsubmits := map[orgRepoJobName][]Postsubmit{}
+	validPostsubmits := map[orgRepoJobName][]job.Postsubmit{}
 	for repo, jobs := range c.Postsubmits {
 		for _, job := range jobs {
 			repoJobName := orgRepoJobName{repo, job.Name}
@@ -614,24 +607,27 @@ func (c *Config) validateJobConfig() error {
 		}
 	}
 
-	for _, j := range c.AllPostsubmits(nil) {
-		if err := validateJobBase(j.JobBase, PostsubmitJob, c.PodNamespace); err != nil {
-			return fmt.Errorf("invalid postsubmit job %s: %v", j.Name, err)
+	for _, ps := range c.Postsubmits {
+		for _, j := range ps {
+			if err := validateJobBase(j.Base, PostsubmitJob, c.PodNamespace); err != nil {
+				return fmt.Errorf("invalid postsubmit job %s: %v", j.Name, err)
+			}
 		}
 	}
 
 	// validate no duplicated periodics
 	validPeriodics := sets.NewString()
 	// Ensure that the periodic durations are valid and specs exist.
-	for _, p := range c.AllPeriodics() {
+	for _, p := range c.Periodics {
 		if validPeriodics.Has(p.Name) {
 			return fmt.Errorf("duplicated periodic job : %s", p.Name)
 		}
 		validPeriodics.Insert(p.Name)
-		if err := validateJobBase(p.JobBase, PeriodicJob, c.PodNamespace); err != nil {
+		if err := validateJobBase(p.Base, PeriodicJob, c.PodNamespace); err != nil {
 			return fmt.Errorf("invalid periodic job %s: %v", p.Name, err)
 		}
 	}
+
 	// Set the interval on the periodic jobs. It doesn't make sense to do this
 	// for child jobs.
 	for j, p := range c.Periodics {
@@ -648,7 +644,7 @@ func (c *Config) validateJobConfig() error {
 			if err != nil {
 				return fmt.Errorf("cannot parse duration for %s: %v", c.Periodics[j].Name, err)
 			}
-			c.Periodics[j].interval = d
+			c.Periodics[j].SetInterval(d)
 		}
 	}
 
@@ -656,9 +652,9 @@ func (c *Config) validateJobConfig() error {
 }
 
 // GetPostsubmits lets return all the post submits
-func (c *Config) GetPostsubmits(repository scm.Repository) []Postsubmit {
-	fullNames := c.fullNames(repository)
-	var answer []Postsubmit
+func (c *Config) GetPostsubmits(repository scm.Repository) []job.Postsubmit {
+	fullNames := util.FullNames(repository)
+	var answer []job.Postsubmit
 	for _, fn := range fullNames {
 		answer = append(answer, c.Postsubmits[fn]...)
 	}
@@ -666,43 +662,15 @@ func (c *Config) GetPostsubmits(repository scm.Repository) []Postsubmit {
 }
 
 // GetPresubmits lets return all the pre submits for the given repo
-func (c *Config) GetPresubmits(repository scm.Repository) []Presubmit {
-	fullNames := c.fullNames(repository)
-	var answer []Presubmit
+func (c *Config) GetPresubmits(repository scm.Repository) []job.Presubmit {
+	fullNames := util.FullNames(repository)
+	var answer []job.Presubmit
 	for _, fn := range fullNames {
 		answer = append(answer, c.Presubmits[fn]...)
 	}
 	return answer
 }
 
-func (c *Config) fullNames(repository scm.Repository) []string {
-	owner := repository.Namespace
-	name := repository.Name
-	fullName := repository.FullName
-	if fullName == "" {
-		fullName = scm.Join(owner, name)
-	}
-	fullNames := []string{fullName}
-	lowerOwner := strings.ToLower(owner)
-	if lowerOwner != owner {
-		fullNames = append(fullNames, scm.Join(lowerOwner, name))
-	}
-	return fullNames
-}
-
-// DefaultConfigPath will be used if a --config-path is unset
-const DefaultConfigPath = "/etc/config/config.yaml"
-
-// Path returns the value for the component's configPath if provided
-// explicitly or default otherwise.
-func Path(value string) string {
-	if value != "" {
-		return value
-	}
-	logrus.Warningf("defaulting to %s until 15 July 2019, please migrate", DefaultConfigPath)
-	return DefaultConfigPath
-}
-
 func parseProwConfig(c *Config) error {
 	reportTmpl, err := template.New("Report").Parse(c.Plank.ReportTemplateString)
 	if err != nil {
@@ -810,32 +778,6 @@ func parseProwConfig(c *Config) error {
 	return nil
 }
 
-func (c *JobConfig) decorationRequested() bool {
-	for _, vs := range c.Presubmits {
-		for i := range vs {
-			if vs[i].Decorate {
-				return true
-			}
-		}
-	}
-
-	for _, js := range c.Postsubmits {
-		for i := range js {
-			if js[i].Decorate {
-				return true
-			}
-		}
-	}
-
-	for i := range c.Periodics {
-		if c.Periodics[i].Decorate {
-			return true
-		}
-	}
-
-	return false
-}
-
 func validateLabels(labels map[string]string) error {
 	for label, value := range labels {
 		for _, prowLabel := range Labels() {
@@ -853,8 +795,8 @@ func validateLabels(labels map[string]string) error {
 	return nil
 }
 
-func validateAgent(v JobBase, podNamespace string) error {
-	agents := sets.NewString(AvailablePipelineAgentTypes()...)
+func validateAgent(v job.Base, podNamespace string) error {
+	agents := sets.NewString(job.AvailablePipelineAgentTypes()...)
 	agent := v.Agent
 	switch {
 	case !agents.Has(agent):
@@ -882,9 +824,9 @@ func validateAgent(v JobBase, podNamespace string) error {
 	return nil
 }
 
-func resolvePresets(name string, labels map[string]string, spec *v1.PodSpec, presets []Preset) error {
+func resolvePresets(name string, labels map[string]string, spec *v1.PodSpec, presets []job.Preset) error {
 	for _, preset := range presets {
-		if err := mergePreset(preset, labels, spec); err != nil {
+		if err := job.MergePreset(preset, labels, spec); err != nil {
 			return fmt.Errorf("job %s failed to merge presets: %v", name, err)
 		}
 	}
@@ -939,7 +881,7 @@ func validatePodSpec(jobType PipelineKind, spec *v1.PodSpec) error {
 	return nil
 }
 
-func validateTriggering(job Presubmit) error {
+func validateTriggering(job job.Presubmit) error {
 	if job.AlwaysRun && job.RunIfChanged != "" {
 		return fmt.Errorf("job %s is set to always run but also declares run_if_changed targets, which are mutually exclusive", job.Name)
 	}
@@ -976,139 +918,6 @@ func ValidateController(c *Controller) error {
 	return nil
 }
 
-// DefaultTriggerFor returns the default regexp string used to match comments
-// that should trigger the job with this name.
-func DefaultTriggerFor(name string) string {
-	return fmt.Sprintf(`(?m)^/test( | .* )%s,?($|\s.*)`, name)
-}
-
-// DefaultRerunCommandFor returns the default rerun command for the job with
-// this name.
-func DefaultRerunCommandFor(name string) string {
-	return fmt.Sprintf("/test %s", name)
-}
-
-// defaultJobBase configures common parameters, currently Agent and Namespace.
-func (c *ProwConfig) defaultJobBase(base *JobBase) {
-	if base.Agent == "" { // Use the Jenkins X type by default
-		base.Agent = JenkinsXAgent
-	}
-	if base.Namespace == nil || *base.Namespace == "" {
-		s := c.PodNamespace
-		base.Namespace = &s
-	}
-	if base.Cluster == "" {
-		base.Cluster = "default"
-	}
-}
-
-func (c *ProwConfig) defaultPresubmitFields(js []Presubmit) {
-	for i := range js {
-		c.defaultJobBase(&js[i].JobBase)
-		if js[i].Context == "" {
-			js[i].Context = js[i].Name
-		}
-		// Default the values of Trigger and RerunCommand if both fields are
-		// specified. Otherwise let validation fail as both or neither should have
-		// been specified.
-		if js[i].Trigger == "" && js[i].RerunCommand == "" {
-			js[i].Trigger = DefaultTriggerFor(js[i].Name)
-			js[i].RerunCommand = DefaultRerunCommandFor(js[i].Name)
-		}
-	}
-}
-
-func (c *ProwConfig) defaultPostsubmitFields(js []Postsubmit) {
-	for i := range js {
-		c.defaultJobBase(&js[i].JobBase)
-		if js[i].Context == "" {
-			js[i].Context = js[i].Name
-		}
-	}
-}
-
-func (c *ProwConfig) defaultPeriodicFields(js []Periodic) {
-	for i := range js {
-		c.defaultJobBase(&js[i].JobBase)
-	}
-}
-
-// SetPresubmitRegexes compiles and validates all the regular expressions for
-// the provided presubmits.
-func SetPresubmitRegexes(js []Presubmit) error {
-	for i, j := range js {
-		if re, err := regexp.Compile(j.Trigger); err == nil {
-			js[i].re = re
-		} else {
-			return fmt.Errorf("could not compile trigger regex for %s: %v", j.Name, err)
-		}
-		if !js[i].re.MatchString(j.RerunCommand) {
-			return fmt.Errorf("for job %s, rerun command \"%s\" does not match trigger \"%s\"", j.Name, j.RerunCommand, j.Trigger)
-		}
-		b, err := setBrancherRegexes(j.Brancher)
-		if err != nil {
-			return fmt.Errorf("could not set branch regexes for %s: %v", j.Name, err)
-		}
-		js[i].Brancher = b
-
-		c, err := setChangeRegexes(j.RegexpChangeMatcher)
-		if err != nil {
-			return fmt.Errorf("could not set change regexes for %s: %v", j.Name, err)
-		}
-		js[i].RegexpChangeMatcher = c
-	}
-	return nil
-}
-
-// setBrancherRegexes compiles and validates all the regular expressions for
-// the provided branch specifiers.
-func setBrancherRegexes(br Brancher) (Brancher, error) {
-	if len(br.Branches) > 0 {
-		if re, err := regexp.Compile(strings.Join(br.Branches, `|`)); err == nil {
-			br.re = re
-		} else {
-			return br, fmt.Errorf("could not compile positive branch regex: %v", err)
-		}
-	}
-	if len(br.SkipBranches) > 0 {
-		if re, err := regexp.Compile(strings.Join(br.SkipBranches, `|`)); err == nil {
-			br.reSkip = re
-		} else {
-			return br, fmt.Errorf("could not compile negative branch regex: %v", err)
-		}
-	}
-	return br, nil
-}
-
-func setChangeRegexes(cm RegexpChangeMatcher) (RegexpChangeMatcher, error) {
-	if cm.RunIfChanged != "" {
-		re, err := regexp.Compile(cm.RunIfChanged)
-		if err != nil {
-			return cm, fmt.Errorf("could not compile run_if_changed regex: %v", err)
-		}
-		cm.reChanges = re
-	}
-	return cm, nil
-}
-
-// SetPostsubmitRegexes compiles and validates all the regular expressions for
-// the provided postsubmits.
-func SetPostsubmitRegexes(ps []Postsubmit) error {
-	for i, j := range ps {
-		b, err := setBrancherRegexes(j.Brancher)
-		if err != nil {
-			return fmt.Errorf("could not set branch regexes for %s: %v", j.Name, err)
-		}
-		ps[i].Brancher = b
-		c, err := setChangeRegexes(j.RegexpChangeMatcher)
-		if err != nil {
-			return fmt.Errorf("could not set change regexes for %s: %v", j.Name, err)
-		}
-		ps[i].RegexpChangeMatcher = c
-	}
-	return nil
-}
-
 // Labels returns a string slice with label consts from kube.
 func Labels() []string {
 	return []string{LighthouseJobTypeLabel, CreatedByLighthouse, LighthouseJobIDLabel}
diff --git a/pkg/config/constants.go b/pkg/config/constants.go
index 08f2a190..7a86308a 100644
--- a/pkg/config/constants.go
+++ b/pkg/config/constants.go
@@ -70,18 +70,4 @@ const (
 
 	// DefaultClusterAlias specifies the default context for resources owned by jobs (pods/builds).
 	DefaultClusterAlias = "default"
-
-	// JenkinsXAgent is the agent type for running Jenkins X pipelines
-	JenkinsXAgent = "jenkins-x"
-
-	// LegacyDefaultAgent is a backwards compatible way of dealing with legacy cases of "tekton" as the default agent, but meaning Jenkins X
-	LegacyDefaultAgent = "tekton"
-
-	// TektonPipelineAgent is the agent type for running Tekton Pipeline pipelines
-	TektonPipelineAgent = "tekton-pipeline"
 )
-
-// AvailablePipelineAgentTypes returns a slice of all available pipeline agent types
-func AvailablePipelineAgentTypes() []string {
-	return []string{JenkinsXAgent, LegacyDefaultAgent, TektonPipelineAgent}
-}
diff --git a/pkg/config/job/base.go b/pkg/config/job/base.go
new file mode 100644
index 00000000..f1d95f85
--- /dev/null
+++ b/pkg/config/job/base.go
@@ -0,0 +1,74 @@
+/*
+Copyright 2017 The Kubernetes 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 job
+
+import (
+	tektonv1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
+	v1 "k8s.io/api/core/v1"
+)
+
+// Base contains attributes common to all job types
+type Base struct {
+	// The name of the job. Must match regex [A-Za-z0-9-._]+
+	// e.g. pull-test-infra-bazel-build
+	Name string `json:"name"`
+	// Labels are added to LighthouseJobs and pods created for this job.
+	Labels map[string]string `json:"labels,omitempty"`
+	// Annotations are unused by prow itself, but provide a space to configure other automation.
+	Annotations map[string]string `json:"annotations,omitempty"`
+	// MaximumConcurrency of this job, 0 implies no limit.
+	MaxConcurrency int `json:"max_concurrency,omitempty"`
+	// Agent that will take care of running this job.
+	Agent string `json:"agent"`
+	// Cluster is the alias of the cluster to run this job in.
+	// (Default: kube.DefaultClusterAlias)
+	Cluster string `json:"cluster,omitempty"`
+	// Namespace is the namespace in which pods schedule.
+	//   nil: results in config.PodNamespace (aka pod default)
+	//   empty: results in config.LighthouseJobNamespace (aka same as LighthouseJob)
+	Namespace *string `json:"namespace,omitempty"`
+	// ErrorOnEviction indicates that the LighthouseJob should be completed and given
+	// the ErrorState status if the pod that is executing the job is evicted.
+	// If this field is unspecified or false, a new pod will be created to replace
+	// the evicted one.
+	ErrorOnEviction bool `json:"error_on_eviction,omitempty"`
+	// SourcePath contains the path where this job is defined
+	SourcePath string `json:"-"`
+	// Spec is the Kubernetes pod spec used if Agent is kubernetes.
+	Spec *v1.PodSpec `json:"spec,omitempty"`
+	// PipelineRunSpec is the Tekton PipelineRun spec used if agent is tekton-pipeline
+	PipelineRunSpec *tektonv1beta1.PipelineRunSpec `json:"pipeline_run_spec,omitempty"`
+	// PipelineRunParams are the params used by the pipeline run
+	PipelineRunParams []PipelineRunParam `json:"pipeline_run_params,omitempty"`
+
+	UtilityConfig
+}
+
+// SetDefaults initializes default values
+func (b *Base) SetDefaults(namespace string) {
+	// Use the Jenkins X type by default
+	if b.Agent == "" {
+		b.Agent = JenkinsXAgent
+	}
+	if b.Namespace == nil || *b.Namespace == "" {
+		s := namespace
+		b.Namespace = &s
+	}
+	if b.Cluster == "" {
+		b.Cluster = "default"
+	}
+}
diff --git a/pkg/config/job/brancher.go b/pkg/config/job/brancher.go
new file mode 100644
index 00000000..28e762e3
--- /dev/null
+++ b/pkg/config/job/brancher.go
@@ -0,0 +1,119 @@
+/*
+Copyright 2017 The Kubernetes 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 job
+
+import (
+	"fmt"
+	"regexp"
+	"strings"
+
+	"k8s.io/apimachinery/pkg/util/sets"
+)
+
+// Brancher is for shared code between jobs that only run against certain
+// branches. An empty brancher runs against all branches.
+type Brancher struct {
+	// Do not run against these branches. Default is no branches.
+	SkipBranches []string `json:"skip_branches,omitempty"`
+	// Only run against these branches. Default is all branches.
+	Branches []string `json:"branches,omitempty"`
+
+	// We'll set these when we load it.
+	re     *regexp.Regexp
+	reSkip *regexp.Regexp
+}
+
+// RunsAgainstAllBranch returns true if there are both branches and skip_branches are unset
+func (br Brancher) RunsAgainstAllBranch() bool {
+	return len(br.SkipBranches) == 0 && len(br.Branches) == 0
+}
+
+// SetBrancherRegexes validates and compiles internal regexes
+func (br Brancher) SetBrancherRegexes() (Brancher, error) {
+	if len(br.Branches) > 0 {
+		if re, err := regexp.Compile(strings.Join(br.Branches, `|`)); err == nil {
+			br.re = re
+		} else {
+			return br, fmt.Errorf("could not compile positive branch regex: %v", err)
+		}
+	}
+	if len(br.SkipBranches) > 0 {
+		if re, err := regexp.Compile(strings.Join(br.SkipBranches, `|`)); err == nil {
+			br.reSkip = re
+		} else {
+			return br, fmt.Errorf("could not compile negative branch regex: %v", err)
+		}
+	}
+	return br, nil
+}
+
+// GetRESkip return the branch skip regexp
+func (br Brancher) GetRESkip() *regexp.Regexp {
+	if br.reSkip == nil {
+		br2, _ := br.SetBrancherRegexes()
+		return br2.reSkip
+	}
+	return br.reSkip
+}
+
+// GetRE returns the branch regexp
+func (br Brancher) GetRE() *regexp.Regexp {
+	if br.re == nil {
+		br2, _ := br.SetBrancherRegexes()
+		return br2.re
+	}
+	return br.re
+}
+
+// ShouldRun returns true if the input branch matches, given the includes/excludes.
+func (br Brancher) ShouldRun(branch string) bool {
+	if br.RunsAgainstAllBranch() {
+		return true
+	}
+
+	// Favor SkipBranches over Branches
+	if len(br.SkipBranches) != 0 && br.GetRESkip().MatchString(branch) {
+		return false
+	}
+	if len(br.Branches) == 0 || br.GetRE().MatchString(branch) {
+		return true
+	}
+	return false
+}
+
+// Intersects checks if other Brancher would trigger for the same branch.
+func (br Brancher) Intersects(other Brancher) bool {
+	if br.RunsAgainstAllBranch() || other.RunsAgainstAllBranch() {
+		return true
+	}
+	if len(br.Branches) > 0 {
+		baseBranches := sets.NewString(br.Branches...)
+		if len(other.Branches) > 0 {
+			otherBranches := sets.NewString(other.Branches...)
+			return baseBranches.Intersection(otherBranches).Len() > 0
+		}
+		if !baseBranches.Intersection(sets.NewString(other.SkipBranches...)).Equal(baseBranches) {
+			return true
+		}
+		return false
+	}
+	if len(other.Branches) == 0 {
+		// There can only be one Brancher with skip_branches.
+		return true
+	}
+	return other.Intersects(br)
+}
diff --git a/pkg/config/job/changedfilesprovider.go b/pkg/config/job/changedfilesprovider.go
new file mode 100644
index 00000000..0cbaac0c
--- /dev/null
+++ b/pkg/config/job/changedfilesprovider.go
@@ -0,0 +1,50 @@
+/*
+Copyright 2017 The Kubernetes 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 job
+
+import (
+	"fmt"
+
+	"github.com/jenkins-x/go-scm/scm"
+)
+
+// ChangedFilesProvider returns a slice of modified files.
+type ChangedFilesProvider func() ([]string, error)
+
+type scmClient interface {
+	GetPullRequestChanges(org, repo string, number int) ([]*scm.Change, error)
+}
+
+// NewGitHubDeferredChangedFilesProvider uses a closure to lazily retrieve the file changes only if they are needed.
+// We only have to fetch the changes if there is at least one RunIfChanged job that is not being force run (due to
+// a `/retest` after a failure or because it is explicitly triggered with `/test foo`).
+func NewGitHubDeferredChangedFilesProvider(client scmClient, org, repo string, num int) ChangedFilesProvider {
+	var changedFiles []string
+	return func() ([]string, error) {
+		// Fetch the changed files from github at most once.
+		if changedFiles == nil {
+			changes, err := client.GetPullRequestChanges(org, repo, num)
+			if err != nil {
+				return nil, fmt.Errorf("error getting pull request changes: %v", err)
+			}
+			for _, change := range changes {
+				changedFiles = append(changedFiles, change.Path)
+			}
+		}
+		return changedFiles, nil
+	}
+}
diff --git a/pkg/config/job/config.go b/pkg/config/job/config.go
new file mode 100644
index 00000000..6afc3d4d
--- /dev/null
+++ b/pkg/config/job/config.go
@@ -0,0 +1,170 @@
+/*
+Copyright 2017 The Kubernetes 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 job
+
+// Config is config for all prow jobs
+type Config struct {
+	// Presets apply to all job types.
+	Presets []Preset `json:"presets,omitempty"`
+	// Full repo name (such as "kubernetes/kubernetes") -> list of jobs.
+	Presubmits  map[string][]Presubmit  `json:"presubmits,omitempty"`
+	Postsubmits map[string][]Postsubmit `json:"postsubmits,omitempty"`
+
+	// Periodics are not associated with any repo.
+	Periodics []Periodic `json:"periodics,omitempty"`
+}
+
+// DecorationRequested checks if decoration was requested
+func (c *Config) DecorationRequested() bool {
+	for _, vs := range c.Presubmits {
+		for i := range vs {
+			if vs[i].Decorate {
+				return true
+			}
+		}
+	}
+
+	for _, js := range c.Postsubmits {
+		for i := range js {
+			if js[i].Decorate {
+				return true
+			}
+		}
+	}
+
+	for i := range c.Periodics {
+		if c.Periodics[i].Decorate {
+			return true
+		}
+	}
+
+	return false
+}
+
+// AllPresubmits returns all prow presubmit jobs in repos.
+// if repos is empty, return all presubmits.
+func (c *Config) AllPresubmits(repos []string) []Presubmit {
+	var res []Presubmit
+
+	for repo, v := range c.Presubmits {
+		if len(repos) == 0 {
+			res = append(res, v...)
+		} else {
+			for _, r := range repos {
+				if r == repo {
+					res = append(res, v...)
+					break
+				}
+			}
+		}
+	}
+
+	return res
+}
+
+// AllPostsubmits returns all prow postsubmit jobs in repos.
+// if repos is empty, return all postsubmits.
+func (c *Config) AllPostsubmits(repos []string) []Postsubmit {
+	var res []Postsubmit
+
+	for repo, v := range c.Postsubmits {
+		if len(repos) == 0 {
+			res = append(res, v...)
+		} else {
+			for _, r := range repos {
+				if r == repo {
+					res = append(res, v...)
+					break
+				}
+			}
+		}
+	}
+
+	return res
+}
+
+// AllPeriodics returns all prow periodic jobs.
+func (c *Config) AllPeriodics() []Periodic {
+	listPeriodic := func(ps []Periodic) []Periodic {
+		var res []Periodic
+		res = append(res, ps...)
+		return res
+	}
+
+	return listPeriodic(c.Periodics)
+}
+
+// SetPresubmits updates c.Presubmits to jobs, after compiling and validating their regexes.
+func (c *Config) SetPresubmits(jobs map[string][]Presubmit) error {
+	nj := map[string][]Presubmit{}
+	for k, v := range jobs {
+		nj[k] = make([]Presubmit, len(v))
+		copy(nj[k], v)
+		if err := SetPresubmitRegexes(nj[k]); err != nil {
+			return err
+		}
+	}
+	c.Presubmits = nj
+	return nil
+}
+
+// SetPostsubmits updates c.Postsubmits to jobs, after compiling and validating their regexes.
+func (c *Config) SetPostsubmits(jobs map[string][]Postsubmit) error {
+	nj := map[string][]Postsubmit{}
+	for k, v := range jobs {
+		nj[k] = make([]Postsubmit, len(v))
+		copy(nj[k], v)
+		if err := SetPostsubmitRegexes(nj[k]); err != nil {
+			return err
+		}
+	}
+	c.Postsubmits = nj
+	return nil
+}
+
+// SetPresubmitRegexes compiles and validates all the regular expressions for
+// the provided presubmits.
+func SetPresubmitRegexes(ps []Presubmit) error {
+	for i := range ps {
+		if err := ps[i].SetRegexes(); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// SetPostsubmitRegexes compiles and validates all the regular expressions for
+// the provided postsubmits.
+func SetPostsubmitRegexes(ps []Postsubmit) error {
+	for i := range ps {
+		if err := ps[i].SetRegexes(); err != nil {
+			return err
+		}
+	}
+	return nil
+}
+
+// ClearCompiledRegexes removes compiled regexes from the presubmits,
+// useful for testing when deep equality is needed between presubmits
+func ClearCompiledRegexes(presubmits []Presubmit) {
+	for i := range presubmits {
+		presubmits[i].re = nil
+		presubmits[i].Brancher.re = nil
+		presubmits[i].Brancher.reSkip = nil
+		presubmits[i].RegexpChangeMatcher.reChanges = nil
+	}
+}
diff --git a/pkg/config/job/constants.go b/pkg/config/job/constants.go
new file mode 100644
index 00000000..fcb1015a
--- /dev/null
+++ b/pkg/config/job/constants.go
@@ -0,0 +1,41 @@
+/*
+ * The MIT License
+ *
+ * Copyright (c) 2020, CloudBees, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+package job
+
+const (
+	// JenkinsXAgent is the agent type for running Jenkins X pipelines
+	JenkinsXAgent = "jenkins-x"
+
+	// LegacyDefaultAgent is a backwards compatible way of dealing with legacy cases of "tekton" as the default agent, but meaning Jenkins X
+	LegacyDefaultAgent = "tekton"
+
+	// TektonPipelineAgent is the agent type for running Tekton Pipeline pipelines
+	TektonPipelineAgent = "tekton-pipeline"
+)
+
+// AvailablePipelineAgentTypes returns a slice of all available pipeline agent types
+func AvailablePipelineAgentTypes() []string {
+	return []string{JenkinsXAgent, LegacyDefaultAgent, TektonPipelineAgent}
+}
diff --git a/pkg/config/job/jobs.go b/pkg/config/job/jobs.go
new file mode 100644
index 00000000..26c1dc5a
--- /dev/null
+++ b/pkg/config/job/jobs.go
@@ -0,0 +1,46 @@
+/*
+Copyright 2017 The Kubernetes 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 job
+
+// // RetestPresubmits returns all presubmits that should be run given a /retest command.
+// // This is the set of all presubmits intersected with ((alwaysRun + runContexts) - skipContexts)
+// func (c *JobConfig) RetestPresubmits(fullRepoName string, skipContexts, runContexts sets.String) []Presubmit {
+// 	var result []Presubmit
+// 	if jobs, ok := c.Presubmits[fullRepoName]; ok {
+// 		for _, job := range jobs {
+// 			if skipContexts.Has(job.Context) {
+// 				continue
+// 			}
+// 			if job.AlwaysRun || job.RunIfChanged != "" || runContexts.Has(job.Context) {
+// 				result = append(result, job)
+// 			}
+// 		}
+// 	}
+// 	return result
+// }
+
+// // GetPresubmit returns the presubmit job for the provided repo and job name.
+// func (c *JobConfig) GetPresubmit(repo, jobName string) *Presubmit {
+// 	presubmits := c.AllPresubmits([]string{repo})
+// 	for i := range presubmits {
+// 		ps := presubmits[i]
+// 		if ps.Name == jobName {
+// 			return &ps
+// 		}
+// 	}
+// 	return nil
+// }
diff --git a/pkg/config/job/periodic.go b/pkg/config/job/periodic.go
new file mode 100644
index 00000000..c333fb9f
--- /dev/null
+++ b/pkg/config/job/periodic.go
@@ -0,0 +1,50 @@
+/*
+Copyright 2017 The Kubernetes 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 job
+
+import (
+	"time"
+)
+
+// Periodic runs on a timer.
+type Periodic struct {
+	Base
+
+	// (deprecated)Interval to wait between two runs of the job.
+	Interval string `json:"interval"`
+	// Cron representation of job trigger time
+	Cron string `json:"cron"`
+	// Tags for config entries
+	Tags []string `json:"tags,omitempty"`
+
+	interval time.Duration
+}
+
+// SetDefaults initializes default values
+func (p *Periodic) SetDefaults(namespace string) {
+	p.Base.SetDefaults(namespace)
+}
+
+// SetInterval updates interval, the frequency duration it runs.
+func (p *Periodic) SetInterval(d time.Duration) {
+	p.interval = d
+}
+
+// GetInterval returns interval, the frequency duration it runs.
+func (p *Periodic) GetInterval() time.Duration {
+	return p.interval
+}
diff --git a/pkg/config/job/pipelinerunparam.go b/pkg/config/job/pipelinerunparam.go
new file mode 100644
index 00000000..1cd56edc
--- /dev/null
+++ b/pkg/config/job/pipelinerunparam.go
@@ -0,0 +1,25 @@
+/*
+Copyright 2017 The Kubernetes 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 job
+
+// PipelineRunParam represents a param used by the pipeline run
+type PipelineRunParam struct {
+	// Name is the name of the param
+	Name string `json:"name,omitempty"`
+	// ValueTemplate is the template used to build the value from well know variables
+	ValueTemplate string `json:"value_template,omitempty"`
+}
diff --git a/pkg/config/job/postsubmit.go b/pkg/config/job/postsubmit.go
new file mode 100644
index 00000000..92b8e502
--- /dev/null
+++ b/pkg/config/job/postsubmit.go
@@ -0,0 +1,75 @@
+/*
+Copyright 2017 The Kubernetes 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 job
+
+import "fmt"
+
+// Postsubmit runs on push events.
+type Postsubmit struct {
+	Base
+
+	RegexpChangeMatcher
+
+	Brancher
+
+	// TODO(krzyzacy): Move existing `Report` into `Skip_Report` once this is deployed
+	Reporter
+}
+
+// SetDefaults initializes default values
+func (p *Postsubmit) SetDefaults(namespace string) {
+	p.Base.SetDefaults(namespace)
+	if p.Context == "" {
+		p.Context = p.Name
+	}
+}
+
+// SetRegexes compiles and validates all the regular expressions
+func (p *Postsubmit) SetRegexes() error {
+	b, err := p.Brancher.SetBrancherRegexes()
+	if err != nil {
+		return fmt.Errorf("could not set branch regexes for %s: %v", p.Name, err)
+	}
+	p.Brancher = b
+	c, err := p.RegexpChangeMatcher.SetChangeRegexes()
+	if err != nil {
+		return fmt.Errorf("could not set change regexes for %s: %v", p.Name, err)
+	}
+	p.RegexpChangeMatcher = c
+	return nil
+}
+
+// CouldRun determines if the postsubmit could run against a specific
+// base ref
+func (p Postsubmit) CouldRun(baseRef string) bool {
+	return p.Brancher.ShouldRun(baseRef)
+}
+
+// ShouldRun determines if the postsubmit should run in response to a
+// set of changes. This is evaluated lazily, if necessary.
+func (p Postsubmit) ShouldRun(baseRef string, changes ChangedFilesProvider) (bool, error) {
+	if !p.CouldRun(baseRef) {
+		return false, nil
+	}
+	if determined, shouldRun, err := p.RegexpChangeMatcher.ShouldRun(changes); err != nil {
+		return false, err
+	} else if determined {
+		return shouldRun, nil
+	}
+	// Postsubmits default to always run
+	return true, nil
+}
diff --git a/pkg/config/job/preset.go b/pkg/config/job/preset.go
new file mode 100644
index 00000000..57eeb024
--- /dev/null
+++ b/pkg/config/job/preset.go
@@ -0,0 +1,73 @@
+/*
+Copyright 2017 The Kubernetes 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 job
+
+import (
+	"fmt"
+
+	v1 "k8s.io/api/core/v1"
+)
+
+// Preset is intended to match the k8s' PodPreset feature, and may be removed
+// if that feature goes beta.
+type Preset struct {
+	Labels       map[string]string `json:"labels"`
+	Env          []v1.EnvVar       `json:"env"`
+	Volumes      []v1.Volume       `json:"volumes"`
+	VolumeMounts []v1.VolumeMount  `json:"volumeMounts"`
+}
+
+// MergePreset merges a preset and labels with a pod spec
+func MergePreset(preset Preset, labels map[string]string, pod *v1.PodSpec) error {
+	if pod == nil {
+		return nil
+	}
+	for l, v := range preset.Labels {
+		if v2, ok := labels[l]; !ok || v2 != v {
+			return nil
+		}
+	}
+	for _, e1 := range preset.Env {
+		for i := range pod.Containers {
+			for _, e2 := range pod.Containers[i].Env {
+				if e1.Name == e2.Name {
+					return fmt.Errorf("env var duplicated in pod spec: %s", e1.Name)
+				}
+			}
+			pod.Containers[i].Env = append(pod.Containers[i].Env, e1)
+		}
+	}
+	for _, v1 := range preset.Volumes {
+		for _, v2 := range pod.Volumes {
+			if v1.Name == v2.Name {
+				return fmt.Errorf("volume duplicated in pod spec: %s", v1.Name)
+			}
+		}
+		pod.Volumes = append(pod.Volumes, v1)
+	}
+	for _, vm1 := range preset.VolumeMounts {
+		for i := range pod.Containers {
+			for _, vm2 := range pod.Containers[i].VolumeMounts {
+				if vm1.Name == vm2.Name {
+					return fmt.Errorf("volume mount duplicated in pod spec: %s", vm1.Name)
+				}
+			}
+			pod.Containers[i].VolumeMounts = append(pod.Containers[i].VolumeMounts, vm1)
+		}
+	}
+	return nil
+}
diff --git a/pkg/config/job/presubmit.go b/pkg/config/job/presubmit.go
new file mode 100644
index 00000000..082227a9
--- /dev/null
+++ b/pkg/config/job/presubmit.go
@@ -0,0 +1,153 @@
+/*
+Copyright 2017 The Kubernetes 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 job
+
+import (
+	"fmt"
+	"regexp"
+
+	"github.com/jenkins-x/lighthouse/pkg/config/util"
+)
+
+// Presubmit runs on PRs.
+type Presubmit struct {
+	Base
+
+	// AlwaysRun automatically for every PR, or only when a comment triggers it.
+	AlwaysRun bool `json:"always_run"`
+
+	// Optional indicates that the job's status context should not be required for merge.
+	Optional bool `json:"optional,omitempty"`
+
+	// Trigger is the regular expression to trigger the job.
+	// e.g. `@k8s-bot e2e test this`
+	// RerunCommand must also be specified if this field is specified.
+	// (Default: `(?m)^/test (?:.*? )?<job name>(?: .*?)?$`)
+	Trigger string `json:"trigger,omitempty"`
+
+	// The RerunCommand to give users. Must match Trigger.
+	// Trigger must also be specified if this field is specified.
+	// (Default: `/test <job name>`)
+	RerunCommand string `json:"rerun_command,omitempty"`
+
+	Brancher
+
+	RegexpChangeMatcher
+
+	Reporter
+
+	// We'll set these when we load it.
+	//re *regexp.Regexp // from Trigger.
+}
+
+// SetDefaults initializes default values
+func (p *Presubmit) SetDefaults(namespace string) {
+	p.Base.SetDefaults(namespace)
+	if p.Context == "" {
+		p.Context = p.Name
+	}
+	// Default the values of Trigger and RerunCommand if both fields are
+	// specified. Otherwise let validation fail as both or neither should have
+	// been specified.
+	if p.Trigger == "" && p.RerunCommand == "" {
+		p.Trigger = util.DefaultTriggerFor(p.Name)
+		p.RerunCommand = util.DefaultRerunCommandFor(p.Name)
+	}
+}
+
+// SetRegexes compiles and validates all the regular expressions
+func (p *Presubmit) SetRegexes() error {
+	if re, err := regexp.Compile(p.Trigger); err == nil {
+		p.re = re
+	} else {
+		return fmt.Errorf("could not compile trigger regex for %s: %v", p.Name, err)
+	}
+	if !p.re.MatchString(p.RerunCommand) {
+		return fmt.Errorf("for job %s, rerun command \"%s\" does not match trigger \"%s\"", p.Name, p.RerunCommand, p.Trigger)
+	}
+	b, err := p.Brancher.SetBrancherRegexes()
+	if err != nil {
+		return fmt.Errorf("could not set branch regexes for %s: %v", p.Name, err)
+	}
+	p.Brancher = b
+	c, err := p.RegexpChangeMatcher.SetChangeRegexes()
+	if err != nil {
+		return fmt.Errorf("could not set change regexes for %s: %v", p.Name, err)
+	}
+	p.RegexpChangeMatcher = c
+	return nil
+}
+
+// CouldRun determines if the presubmit could run against a specific
+// base ref
+func (p Presubmit) CouldRun(baseRef string) bool {
+	return p.Brancher.ShouldRun(baseRef)
+}
+
+// ShouldRun determines if the presubmit should run against a specific
+// base ref, or in response to a set of changes. The latter mechanism
+// is evaluated lazily, if necessary.
+func (p Presubmit) ShouldRun(baseRef string, changes ChangedFilesProvider, forced, defaults bool) (bool, error) {
+	if !p.CouldRun(baseRef) {
+		return false, nil
+	}
+	if p.AlwaysRun {
+		return true, nil
+	}
+	if forced {
+		return true, nil
+	}
+	if determined, shouldRun, err := p.RegexpChangeMatcher.ShouldRun(changes); err != nil {
+		return false, err
+	} else if determined {
+		return shouldRun, nil
+	}
+	return defaults, nil
+}
+
+// TriggersConditionally determines if the presubmit triggers conditionally (if it may or may not trigger).
+func (p Presubmit) TriggersConditionally() bool {
+	return p.NeedsExplicitTrigger() || p.RegexpChangeMatcher.CouldRun()
+}
+
+// NeedsExplicitTrigger determines if the presubmit requires a human action to trigger it or not.
+func (p Presubmit) NeedsExplicitTrigger() bool {
+	return !p.AlwaysRun && !p.RegexpChangeMatcher.CouldRun()
+}
+
+// TriggerMatches returns true if the comment body should trigger this presubmit.
+//
+// This is usually a /test foo string.
+func (p Presubmit) TriggerMatches(body string) bool {
+	re := p.re
+	if p.Trigger == "" {
+		return false
+	}
+	if re == nil {
+		var err error
+		re, err = regexp.Compile(p.Trigger)
+		if err != nil {
+			return body == p.Trigger
+		}
+	}
+	return p.Trigger != "" && re != nil && re.MatchString(body)
+}
+
+// ContextRequired checks whether a context is required from github points of view (required check).
+func (p Presubmit) ContextRequired() bool {
+	return !p.Optional && !p.SkipReport
+}
diff --git a/pkg/config/job/regexpchangematcher.go b/pkg/config/job/regexpchangematcher.go
new file mode 100644
index 00000000..8b63a270
--- /dev/null
+++ b/pkg/config/job/regexpchangematcher.go
@@ -0,0 +1,71 @@
+/*
+Copyright 2017 The Kubernetes 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 job
+
+import (
+	"fmt"
+	"regexp"
+)
+
+// RegexpChangeMatcher is for code shared between jobs that run only when certain files are changed.
+type RegexpChangeMatcher struct {
+	// RunIfChanged defines a regex used to select which subset of file changes should trigger this job.
+	// If any file in the changeset matches this regex, the job will be triggered
+	RunIfChanged string         `json:"run_if_changed,omitempty"`
+	reChanges    *regexp.Regexp // from RunIfChanged
+}
+
+// CouldRun determines if its possible for a set of changes to trigger this condition
+func (cm RegexpChangeMatcher) CouldRun() bool {
+	return cm.RunIfChanged != ""
+}
+
+// ShouldRun determines if we can know for certain that the job should run. We can either
+// know for certain that the job should or should not run based on the matcher, or we can
+// not be able to determine that fact at all.
+func (cm RegexpChangeMatcher) ShouldRun(changes ChangedFilesProvider) (determined bool, shouldRun bool, err error) {
+	if cm.CouldRun() {
+		changeList, err := changes()
+		if err != nil {
+			return true, false, err
+		}
+		return true, cm.RunsAgainstChanges(changeList), nil
+	}
+	return false, false, nil
+}
+
+// RunsAgainstChanges returns true if any of the changed input paths match the run_if_changed regex.
+func (cm RegexpChangeMatcher) RunsAgainstChanges(changes []string) bool {
+	for _, change := range changes {
+		if cm.reChanges.MatchString(change) {
+			return true
+		}
+	}
+	return false
+}
+
+// SetChangeRegexes validates and compiles internal regexes
+func (cm RegexpChangeMatcher) SetChangeRegexes() (RegexpChangeMatcher, error) {
+	if cm.RunIfChanged != "" {
+		re, err := regexp.Compile(cm.RunIfChanged)
+		if err != nil {
+			return cm, fmt.Errorf("could not compile run_if_changed regex: %v", err)
+		}
+		cm.reChanges = re
+	}
+	return cm, nil
+}
diff --git a/pkg/config/job/reporter.go b/pkg/config/job/reporter.go
new file mode 100644
index 00000000..2b5bee50
--- /dev/null
+++ b/pkg/config/job/reporter.go
@@ -0,0 +1,26 @@
+/*
+Copyright 2017 The Kubernetes 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 job
+
+// Reporter keeps various details for status reporting
+type Reporter struct {
+	// Context is the name of the GitHub status context for the job.
+	// Defaults: the same as the name of the job.
+	Context string `json:"context,omitempty"`
+	// SkipReport skips commenting and setting status on GitHub.
+	SkipReport bool `json:"skip_report,omitempty"`
+}
diff --git a/pkg/config/job/utilityconfig.go b/pkg/config/job/utilityconfig.go
new file mode 100644
index 00000000..f079c696
--- /dev/null
+++ b/pkg/config/job/utilityconfig.go
@@ -0,0 +1,39 @@
+/*
+Copyright 2017 The Kubernetes 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 job
+
+// UtilityConfig holds decoration metadata, such as how to clone and additional containers/etc
+type UtilityConfig struct {
+	// Decorate determines if we decorate the PodSpec or not
+	Decorate bool `json:"decorate,omitempty"`
+
+	// PathAlias is the location under <root-dir>/src
+	// where the repository under test is cloned. If this
+	// is not set, <root-dir>/src/github.com/org/repo will
+	// be used as the default.
+	PathAlias string `json:"path_alias,omitempty"`
+	// CloneURI is the URI that is used to clone the
+	// repository. If unset, will default to
+	// `https://github.com/org/repo.git`.
+	CloneURI string `json:"clone_uri,omitempty"`
+	// SkipSubmodules determines if submodules should be
+	// cloned when the job is run. Defaults to true.
+	SkipSubmodules bool `json:"skip_submodules,omitempty"`
+	// CloneDepth is the depth of the clone that will be used.
+	// A depth of zero will do a full clone.
+	CloneDepth int `json:"clone_depth,omitempty"`
+}
diff --git a/pkg/config/jobs.go b/pkg/config/jobs.go
deleted file mode 100644
index ef023237..00000000
--- a/pkg/config/jobs.go
+++ /dev/null
@@ -1,561 +0,0 @@
-/*
-Copyright 2017 The Kubernetes 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 config
-
-import (
-	"fmt"
-	"regexp"
-	"time"
-
-	"github.com/jenkins-x/go-scm/scm"
-	tektonv1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
-	v1 "k8s.io/api/core/v1"
-	"k8s.io/apimachinery/pkg/util/sets"
-)
-
-// Preset is intended to match the k8s' PodPreset feature, and may be removed
-// if that feature goes beta.
-type Preset struct {
-	Labels       map[string]string `json:"labels"`
-	Env          []v1.EnvVar       `json:"env"`
-	Volumes      []v1.Volume       `json:"volumes"`
-	VolumeMounts []v1.VolumeMount  `json:"volumeMounts"`
-}
-
-func mergePreset(preset Preset, labels map[string]string, pod *v1.PodSpec) error {
-	if pod == nil {
-		return nil
-	}
-	for l, v := range preset.Labels {
-		if v2, ok := labels[l]; !ok || v2 != v {
-			return nil
-		}
-	}
-	for _, e1 := range preset.Env {
-		for i := range pod.Containers {
-			for _, e2 := range pod.Containers[i].Env {
-				if e1.Name == e2.Name {
-					return fmt.Errorf("env var duplicated in pod spec: %s", e1.Name)
-				}
-			}
-			pod.Containers[i].Env = append(pod.Containers[i].Env, e1)
-		}
-	}
-	for _, v1 := range preset.Volumes {
-		for _, v2 := range pod.Volumes {
-			if v1.Name == v2.Name {
-				return fmt.Errorf("volume duplicated in pod spec: %s", v1.Name)
-			}
-		}
-		pod.Volumes = append(pod.Volumes, v1)
-	}
-	for _, vm1 := range preset.VolumeMounts {
-		for i := range pod.Containers {
-			for _, vm2 := range pod.Containers[i].VolumeMounts {
-				if vm1.Name == vm2.Name {
-					return fmt.Errorf("volume mount duplicated in pod spec: %s", vm1.Name)
-				}
-			}
-			pod.Containers[i].VolumeMounts = append(pod.Containers[i].VolumeMounts, vm1)
-		}
-	}
-	return nil
-}
-
-// PipelineRunParam represents a param used by the pipeline run
-type PipelineRunParam struct {
-	// Name is the name of the param
-	Name string `json:"name,omitempty"`
-	// ValueTemplate is the template used to build the value from well know variables
-	ValueTemplate string `json:"value_template,omitempty"`
-}
-
-// JobBase contains attributes common to all job types
-type JobBase struct {
-	// The name of the job. Must match regex [A-Za-z0-9-._]+
-	// e.g. pull-test-infra-bazel-build
-	Name string `json:"name"`
-	// Labels are added to LighthouseJobs and pods created for this job.
-	Labels map[string]string `json:"labels,omitempty"`
-	// Annotations are unused by prow itself, but provide a space to configure other automation.
-	Annotations map[string]string `json:"annotations,omitempty"`
-	// MaximumConcurrency of this job, 0 implies no limit.
-	MaxConcurrency int `json:"max_concurrency,omitempty"`
-	// Agent that will take care of running this job.
-	Agent string `json:"agent"`
-	// Cluster is the alias of the cluster to run this job in.
-	// (Default: kube.DefaultClusterAlias)
-	Cluster string `json:"cluster,omitempty"`
-	// Namespace is the namespace in which pods schedule.
-	//   nil: results in config.PodNamespace (aka pod default)
-	//   empty: results in config.LighthouseJobNamespace (aka same as LighthouseJob)
-	Namespace *string `json:"namespace,omitempty"`
-	// ErrorOnEviction indicates that the LighthouseJob should be completed and given
-	// the ErrorState status if the pod that is executing the job is evicted.
-	// If this field is unspecified or false, a new pod will be created to replace
-	// the evicted one.
-	ErrorOnEviction bool `json:"error_on_eviction,omitempty"`
-	// SourcePath contains the path where this job is defined
-	SourcePath string `json:"-"`
-	// Spec is the Kubernetes pod spec used if Agent is kubernetes.
-	Spec *v1.PodSpec `json:"spec,omitempty"`
-	// PipelineRunSpec is the Tekton PipelineRun spec used if agent is tekton-pipeline
-	PipelineRunSpec *tektonv1beta1.PipelineRunSpec `json:"pipeline_run_spec,omitempty"`
-	// PipelineRunParams are the params used by the pipeline run
-	PipelineRunParams []PipelineRunParam `json:"pipeline_run_params,omitempty"`
-
-	UtilityConfig
-}
-
-// Presubmit runs on PRs.
-type Presubmit struct {
-	JobBase
-
-	// AlwaysRun automatically for every PR, or only when a comment triggers it.
-	AlwaysRun bool `json:"always_run"`
-
-	// Optional indicates that the job's status context should not be required for merge.
-	Optional bool `json:"optional,omitempty"`
-
-	// Trigger is the regular expression to trigger the job.
-	// e.g. `@k8s-bot e2e test this`
-	// RerunCommand must also be specified if this field is specified.
-	// (Default: `(?m)^/test (?:.*? )?<job name>(?: .*?)?$`)
-	Trigger string `json:"trigger,omitempty"`
-
-	// The RerunCommand to give users. Must match Trigger.
-	// Trigger must also be specified if this field is specified.
-	// (Default: `/test <job name>`)
-	RerunCommand string `json:"rerun_command,omitempty"`
-
-	Brancher
-
-	RegexpChangeMatcher
-
-	Reporter
-
-	// We'll set these when we load it.
-	//re *regexp.Regexp // from Trigger.
-}
-
-// Postsubmit runs on push events.
-type Postsubmit struct {
-	JobBase
-
-	RegexpChangeMatcher
-
-	Brancher
-
-	// TODO(krzyzacy): Move existing `Report` into `Skip_Report` once this is deployed
-	Reporter
-}
-
-// Periodic runs on a timer.
-type Periodic struct {
-	JobBase
-
-	// (deprecated)Interval to wait between two runs of the job.
-	Interval string `json:"interval"`
-	// Cron representation of job trigger time
-	Cron string `json:"cron"`
-	// Tags for config entries
-	Tags []string `json:"tags,omitempty"`
-
-	interval time.Duration
-}
-
-// SetInterval updates interval, the frequency duration it runs.
-func (p *Periodic) SetInterval(d time.Duration) {
-	p.interval = d
-}
-
-// GetInterval returns interval, the frequency duration it runs.
-func (p *Periodic) GetInterval() time.Duration {
-	return p.interval
-}
-
-// Brancher is for shared code between jobs that only run against certain
-// branches. An empty brancher runs against all branches.
-type Brancher struct {
-	// Do not run against these branches. Default is no branches.
-	SkipBranches []string `json:"skip_branches,omitempty"`
-	// Only run against these branches. Default is all branches.
-	Branches []string `json:"branches,omitempty"`
-
-	// We'll set these when we load it.
-	re     *regexp.Regexp
-	reSkip *regexp.Regexp
-}
-
-// RegexpChangeMatcher is for code shared between jobs that run only when certain files are changed.
-type RegexpChangeMatcher struct {
-	// RunIfChanged defines a regex used to select which subset of file changes should trigger this job.
-	// If any file in the changeset matches this regex, the job will be triggered
-	RunIfChanged string         `json:"run_if_changed,omitempty"`
-	reChanges    *regexp.Regexp // from RunIfChanged
-}
-
-// Reporter keeps various details for status reporting
-type Reporter struct {
-	// Context is the name of the GitHub status context for the job.
-	// Defaults: the same as the name of the job.
-	Context string `json:"context,omitempty"`
-	// SkipReport skips commenting and setting status on GitHub.
-	SkipReport bool `json:"skip_report,omitempty"`
-}
-
-// RunsAgainstAllBranch returns true if there are both branches and skip_branches are unset
-func (br Brancher) RunsAgainstAllBranch() bool {
-	return len(br.SkipBranches) == 0 && len(br.Branches) == 0
-}
-
-// GetRESkip return the branch skip regexp
-func (br Brancher) GetRESkip() *regexp.Regexp {
-	if br.reSkip == nil {
-		br2, _ := setBrancherRegexes(br)
-		return br2.reSkip
-	}
-	return br.reSkip
-}
-
-// GetRE returns the branch regexp
-func (br Brancher) GetRE() *regexp.Regexp {
-	if br.re == nil {
-		br2, _ := setBrancherRegexes(br)
-		return br2.re
-	}
-	return br.re
-}
-
-// ShouldRun returns true if the input branch matches, given the includes/excludes.
-func (br Brancher) ShouldRun(branch string) bool {
-	if br.RunsAgainstAllBranch() {
-		return true
-	}
-
-	// Favor SkipBranches over Branches
-	if len(br.SkipBranches) != 0 && br.GetRESkip().MatchString(branch) {
-		return false
-	}
-	if len(br.Branches) == 0 || br.GetRE().MatchString(branch) {
-		return true
-	}
-	return false
-}
-
-// Intersects checks if other Brancher would trigger for the same branch.
-func (br Brancher) Intersects(other Brancher) bool {
-	if br.RunsAgainstAllBranch() || other.RunsAgainstAllBranch() {
-		return true
-	}
-	if len(br.Branches) > 0 {
-		baseBranches := sets.NewString(br.Branches...)
-		if len(other.Branches) > 0 {
-			otherBranches := sets.NewString(other.Branches...)
-			return baseBranches.Intersection(otherBranches).Len() > 0
-		}
-		if !baseBranches.Intersection(sets.NewString(other.SkipBranches...)).Equal(baseBranches) {
-			return true
-		}
-		return false
-	}
-	if len(other.Branches) == 0 {
-		// There can only be one Brancher with skip_branches.
-		return true
-	}
-	return other.Intersects(br)
-}
-
-// CouldRun determines if its possible for a set of changes to trigger this condition
-func (cm RegexpChangeMatcher) CouldRun() bool {
-	return cm.RunIfChanged != ""
-}
-
-// ShouldRun determines if we can know for certain that the job should run. We can either
-// know for certain that the job should or should not run based on the matcher, or we can
-// not be able to determine that fact at all.
-func (cm RegexpChangeMatcher) ShouldRun(changes ChangedFilesProvider) (determined bool, shouldRun bool, err error) {
-	if cm.CouldRun() {
-		changeList, err := changes()
-		if err != nil {
-			return true, false, err
-		}
-		return true, cm.RunsAgainstChanges(changeList), nil
-	}
-	return false, false, nil
-}
-
-// RunsAgainstChanges returns true if any of the changed input paths match the run_if_changed regex.
-func (cm RegexpChangeMatcher) RunsAgainstChanges(changes []string) bool {
-	for _, change := range changes {
-		if cm.reChanges.MatchString(change) {
-			return true
-		}
-	}
-	return false
-}
-
-// CouldRun determines if the postsubmit could run against a specific
-// base ref
-func (ps Postsubmit) CouldRun(baseRef string) bool {
-	return ps.Brancher.ShouldRun(baseRef)
-}
-
-// ShouldRun determines if the postsubmit should run in response to a
-// set of changes. This is evaluated lazily, if necessary.
-func (ps Postsubmit) ShouldRun(baseRef string, changes ChangedFilesProvider) (bool, error) {
-	if !ps.CouldRun(baseRef) {
-		return false, nil
-	}
-	if determined, shouldRun, err := ps.RegexpChangeMatcher.ShouldRun(changes); err != nil {
-		return false, err
-	} else if determined {
-		return shouldRun, nil
-	}
-	// Postsubmits default to always run
-	return true, nil
-}
-
-// CouldRun determines if the presubmit could run against a specific
-// base ref
-func (ps Presubmit) CouldRun(baseRef string) bool {
-	return ps.Brancher.ShouldRun(baseRef)
-}
-
-// ShouldRun determines if the presubmit should run against a specific
-// base ref, or in response to a set of changes. The latter mechanism
-// is evaluated lazily, if necessary.
-func (ps Presubmit) ShouldRun(baseRef string, changes ChangedFilesProvider, forced, defaults bool) (bool, error) {
-	if !ps.CouldRun(baseRef) {
-		return false, nil
-	}
-	if ps.AlwaysRun {
-		return true, nil
-	}
-	if forced {
-		return true, nil
-	}
-	if determined, shouldRun, err := ps.RegexpChangeMatcher.ShouldRun(changes); err != nil {
-		return false, err
-	} else if determined {
-		return shouldRun, nil
-	}
-	return defaults, nil
-}
-
-// TriggersConditionally determines if the presubmit triggers conditionally (if it may or may not trigger).
-func (ps Presubmit) TriggersConditionally() bool {
-	return ps.NeedsExplicitTrigger() || ps.RegexpChangeMatcher.CouldRun()
-}
-
-// NeedsExplicitTrigger determines if the presubmit requires a human action to trigger it or not.
-func (ps Presubmit) NeedsExplicitTrigger() bool {
-	return !ps.AlwaysRun && !ps.RegexpChangeMatcher.CouldRun()
-}
-
-// TriggerMatches returns true if the comment body should trigger this presubmit.
-//
-// This is usually a /test foo string.
-func (ps Presubmit) TriggerMatches(body string) bool {
-	re := ps.re
-	if ps.Trigger == "" {
-		return false
-	}
-	if re == nil {
-		var err error
-		re, err = regexp.Compile(ps.Trigger)
-		if err != nil {
-			return body == ps.Trigger
-		}
-	}
-	return ps.Trigger != "" && re != nil && re.MatchString(body)
-}
-
-// ContextRequired checks whether a context is required from github points of view (required check).
-func (ps Presubmit) ContextRequired() bool {
-	return !ps.Optional && !ps.SkipReport
-}
-
-// ChangedFilesProvider returns a slice of modified files.
-type ChangedFilesProvider func() ([]string, error)
-
-type scmClient interface {
-	GetPullRequestChanges(org, repo string, number int) ([]*scm.Change, error)
-}
-
-// NewGitHubDeferredChangedFilesProvider uses a closure to lazily retrieve the file changes only if they are needed.
-// We only have to fetch the changes if there is at least one RunIfChanged job that is not being force run (due to
-// a `/retest` after a failure or because it is explicitly triggered with `/test foo`).
-func NewGitHubDeferredChangedFilesProvider(client scmClient, org, repo string, num int) ChangedFilesProvider {
-	var changedFiles []string
-	return func() ([]string, error) {
-		// Fetch the changed files from github at most once.
-		if changedFiles == nil {
-			changes, err := client.GetPullRequestChanges(org, repo, num)
-			if err != nil {
-				return nil, fmt.Errorf("error getting pull request changes: %v", err)
-			}
-			for _, change := range changes {
-				changedFiles = append(changedFiles, change.Path)
-			}
-		}
-		return changedFiles, nil
-	}
-}
-
-// UtilityConfig holds decoration metadata, such as how to clone and additional containers/etc
-type UtilityConfig struct {
-	// Decorate determines if we decorate the PodSpec or not
-	Decorate bool `json:"decorate,omitempty"`
-
-	// PathAlias is the location under <root-dir>/src
-	// where the repository under test is cloned. If this
-	// is not set, <root-dir>/src/github.com/org/repo will
-	// be used as the default.
-	PathAlias string `json:"path_alias,omitempty"`
-	// CloneURI is the URI that is used to clone the
-	// repository. If unset, will default to
-	// `https://github.com/org/repo.git`.
-	CloneURI string `json:"clone_uri,omitempty"`
-	// SkipSubmodules determines if submodules should be
-	// cloned when the job is run. Defaults to true.
-	SkipSubmodules bool `json:"skip_submodules,omitempty"`
-	// CloneDepth is the depth of the clone that will be used.
-	// A depth of zero will do a full clone.
-	CloneDepth int `json:"clone_depth,omitempty"`
-}
-
-// RetestPresubmits returns all presubmits that should be run given a /retest command.
-// This is the set of all presubmits intersected with ((alwaysRun + runContexts) - skipContexts)
-func (c *JobConfig) RetestPresubmits(fullRepoName string, skipContexts, runContexts sets.String) []Presubmit {
-	var result []Presubmit
-	if jobs, ok := c.Presubmits[fullRepoName]; ok {
-		for _, job := range jobs {
-			if skipContexts.Has(job.Context) {
-				continue
-			}
-			if job.AlwaysRun || job.RunIfChanged != "" || runContexts.Has(job.Context) {
-				result = append(result, job)
-			}
-		}
-	}
-	return result
-}
-
-// GetPresubmit returns the presubmit job for the provided repo and job name.
-func (c *JobConfig) GetPresubmit(repo, jobName string) *Presubmit {
-	presubmits := c.AllPresubmits([]string{repo})
-	for i := range presubmits {
-		ps := presubmits[i]
-		if ps.Name == jobName {
-			return &ps
-		}
-	}
-	return nil
-}
-
-// SetPresubmits updates c.Presubmits to jobs, after compiling and validating their regexes.
-func (c *JobConfig) SetPresubmits(jobs map[string][]Presubmit) error {
-	nj := map[string][]Presubmit{}
-	for k, v := range jobs {
-		nj[k] = make([]Presubmit, len(v))
-		copy(nj[k], v)
-		if err := SetPresubmitRegexes(nj[k]); err != nil {
-			return err
-		}
-	}
-	c.Presubmits = nj
-	return nil
-}
-
-// SetPostsubmits updates c.Postsubmits to jobs, after compiling and validating their regexes.
-func (c *JobConfig) SetPostsubmits(jobs map[string][]Postsubmit) error {
-	nj := map[string][]Postsubmit{}
-	for k, v := range jobs {
-		nj[k] = make([]Postsubmit, len(v))
-		copy(nj[k], v)
-		if err := SetPostsubmitRegexes(nj[k]); err != nil {
-			return err
-		}
-	}
-	c.Postsubmits = nj
-	return nil
-}
-
-// AllPresubmits returns all prow presubmit jobs in repos.
-// if repos is empty, return all presubmits.
-func (c *JobConfig) AllPresubmits(repos []string) []Presubmit {
-	var res []Presubmit
-
-	for repo, v := range c.Presubmits {
-		if len(repos) == 0 {
-			res = append(res, v...)
-		} else {
-			for _, r := range repos {
-				if r == repo {
-					res = append(res, v...)
-					break
-				}
-			}
-		}
-	}
-
-	return res
-}
-
-// AllPostsubmits returns all prow postsubmit jobs in repos.
-// if repos is empty, return all postsubmits.
-func (c *JobConfig) AllPostsubmits(repos []string) []Postsubmit {
-	var res []Postsubmit
-
-	for repo, v := range c.Postsubmits {
-		if len(repos) == 0 {
-			res = append(res, v...)
-		} else {
-			for _, r := range repos {
-				if r == repo {
-					res = append(res, v...)
-					break
-				}
-			}
-		}
-	}
-
-	return res
-}
-
-// AllPeriodics returns all prow periodic jobs.
-func (c *JobConfig) AllPeriodics() []Periodic {
-	listPeriodic := func(ps []Periodic) []Periodic {
-		var res []Periodic
-		res = append(res, ps...)
-		return res
-	}
-
-	return listPeriodic(c.Periodics)
-}
-
-// ClearCompiledRegexes removes compiled regexes from the presubmits,
-// useful for testing when deep equality is needed between presubmits
-func ClearCompiledRegexes(presubmits []Presubmit) {
-	for i := range presubmits {
-		presubmits[i].re = nil
-		presubmits[i].Brancher.re = nil
-		presubmits[i].Brancher.reSkip = nil
-		presubmits[i].RegexpChangeMatcher.reChanges = nil
-	}
-}
diff --git a/pkg/config/util/util.go b/pkg/config/util/util.go
new file mode 100644
index 00000000..79035659
--- /dev/null
+++ b/pkg/config/util/util.go
@@ -0,0 +1,50 @@
+package util
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/jenkins-x/go-scm/scm"
+	"github.com/sirupsen/logrus"
+)
+
+// DefaultConfigPath will be used if a --config-path is unset
+const DefaultConfigPath = "/etc/config/config.yaml"
+
+// FullNames creates possible full names of a repository
+func FullNames(repository scm.Repository) []string {
+	owner := repository.Namespace
+	name := repository.Name
+	fullName := repository.FullName
+	if fullName == "" {
+		fullName = scm.Join(owner, name)
+	}
+	fullNames := []string{fullName}
+	lowerOwner := strings.ToLower(owner)
+	if lowerOwner != owner {
+		fullNames = append(fullNames, scm.Join(lowerOwner, name))
+	}
+	return fullNames
+}
+
+// PathOrDefault returns the value for the component's configPath if provided
+// explicitly or default otherwise.
+func PathOrDefault(value string) string {
+	if value != "" {
+		return value
+	}
+	logrus.Warningf("defaulting to %s until 15 July 2019, please migrate", DefaultConfigPath)
+	return DefaultConfigPath
+}
+
+// DefaultTriggerFor returns the default regexp string used to match comments
+// that should trigger the job with this name.
+func DefaultTriggerFor(name string) string {
+	return fmt.Sprintf(`(?m)^/test( | .* )%s,?($|\s.*)`, name)
+}
+
+// DefaultRerunCommandFor returns the default rerun command for the job with
+// this name.
+func DefaultRerunCommandFor(name string) string {
+	return fmt.Sprintf("/test %s", name)
+}
diff --git a/pkg/engines/tekton/controller.go b/pkg/engines/tekton/controller.go
index b6680b80..3bd3a0ff 100644
--- a/pkg/engines/tekton/controller.go
+++ b/pkg/engines/tekton/controller.go
@@ -5,7 +5,7 @@ import (
 	"fmt"
 
 	lighthousev1alpha1 "github.com/jenkins-x/lighthouse/pkg/apis/lighthouse/v1alpha1"
-	"github.com/jenkins-x/lighthouse/pkg/config"
+	configjob "github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/util"
 	"github.com/sirupsen/logrus"
 	pipelinev1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
@@ -78,7 +78,7 @@ func (r *LighthouseJobReconciler) Reconcile(req ctrl.Request) (ctrl.Result, erro
 	}
 
 	// filter on job agent
-	if job.Spec.Agent != config.TektonPipelineAgent {
+	if job.Spec.Agent != configjob.TektonPipelineAgent {
 		return ctrl.Result{}, nil
 	}
 
diff --git a/pkg/jobutil/filter.go b/pkg/jobutil/filter.go
index ebca39c6..fa0ef945 100644
--- a/pkg/jobutil/filter.go
+++ b/pkg/jobutil/filter.go
@@ -21,7 +21,7 @@ import (
 
 	"github.com/sirupsen/logrus"
 
-	"github.com/jenkins-x/lighthouse/pkg/config"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"k8s.io/apimachinery/pkg/util/sets"
 )
 
@@ -39,11 +39,11 @@ var OkToTestRe = regexp.MustCompile(`(?m)^/(?:lh-)?ok-to-test\s*$`)
 //  - we know that the presubmit is forced to run
 //  - what the default behavior should be if the presubmit
 //    runs conditionally and does not match trigger conditions
-type Filter func(p config.Presubmit) (shouldRun bool, forcedToRun bool, defaultBehavior bool)
+type Filter func(p job.Presubmit) (shouldRun bool, forcedToRun bool, defaultBehavior bool)
 
 // CommandFilter builds a filter for `/test foo`
 func CommandFilter(body string) Filter {
-	return func(p config.Presubmit) (bool, bool, bool) {
+	return func(p job.Presubmit) (bool, bool, bool) {
 		return p.TriggerMatches(body), p.TriggerMatches(body), true
 	}
 }
@@ -52,7 +52,7 @@ func CommandFilter(body string) Filter {
 // Pipelines that explicitly match `/test all` in their trigger regex will be
 // handled by a commandFilter for the comment in question.
 func TestAllFilter() Filter {
-	return func(p config.Presubmit) (bool, bool, bool) {
+	return func(p job.Presubmit) (bool, bool, bool) {
 		return !p.NeedsExplicitTrigger(), false, false
 	}
 }
@@ -60,7 +60,7 @@ func TestAllFilter() Filter {
 // AggregateFilter builds a filter that evaluates the child filters in order
 // and returns the first match
 func AggregateFilter(filters []Filter) Filter {
-	return func(presubmit config.Presubmit) (bool, bool, bool) {
+	return func(presubmit job.Presubmit) (bool, bool, bool) {
 		for _, filter := range filters {
 			if shouldRun, forced, defaults := filter(presubmit); shouldRun {
 				return shouldRun, forced, defaults
@@ -72,11 +72,11 @@ func AggregateFilter(filters []Filter) Filter {
 
 // FilterPresubmits determines which presubmits should run and which should be skipped
 // by evaluating the user-provided filter.
-func FilterPresubmits(filter Filter, changes config.ChangedFilesProvider, branch string, presubmits []config.Presubmit, logger *logrus.Entry) ([]config.Presubmit, []config.Presubmit, error) {
+func FilterPresubmits(filter Filter, changes job.ChangedFilesProvider, branch string, presubmits []job.Presubmit, logger *logrus.Entry) ([]job.Presubmit, []job.Presubmit, error) {
 
-	var toTrigger []config.Presubmit
+	var toTrigger []job.Presubmit
 	var namesToTrigger []string
-	var toSkipSuperset []config.Presubmit
+	var toSkipSuperset []job.Presubmit
 	for _, presubmit := range presubmits {
 		matches, forced, defaults := filter(presubmit)
 		if !matches {
@@ -108,12 +108,12 @@ func FilterPresubmits(filter Filter, changes config.ChangedFilesProvider, branch
 // post skipped contexts for, given a set of presubmits we're triggering. We don't
 // want to skip a job that posts a context that will be written to by a job we just
 // identified for triggering or the skipped context will override the triggered one
-func determineSkippedPresubmits(toTrigger, toSkipSuperset []config.Presubmit, logger *logrus.Entry) []config.Presubmit {
+func determineSkippedPresubmits(toTrigger, toSkipSuperset []job.Presubmit, logger *logrus.Entry) []job.Presubmit {
 	triggeredContexts := sets.NewString()
 	for _, presubmit := range toTrigger {
 		triggeredContexts.Insert(presubmit.Context)
 	}
-	var toSkip []config.Presubmit
+	var toSkip []job.Presubmit
 	for _, presubmit := range toSkipSuperset {
 		if triggeredContexts.Has(presubmit.Context) {
 			logger.WithFields(logrus.Fields{"context": presubmit.Context, "job": presubmit.Name}).Debug("Not skipping job as context will be created by a triggered job.")
@@ -126,7 +126,7 @@ func determineSkippedPresubmits(toTrigger, toSkipSuperset []config.Presubmit, lo
 
 // RetestFilter builds a filter for `/retest`
 func RetestFilter(failedContexts, allContexts sets.String) Filter {
-	return func(p config.Presubmit) (bool, bool, bool) {
+	return func(p job.Presubmit) (bool, bool, bool) {
 		return failedContexts.Has(p.Context) || (!p.NeedsExplicitTrigger() && !allContexts.Has(p.Context)), false, true
 	}
 }
diff --git a/pkg/jobutil/jobutil.go b/pkg/jobutil/jobutil.go
index d7edfcb1..0be551fd 100644
--- a/pkg/jobutil/jobutil.go
+++ b/pkg/jobutil/jobutil.go
@@ -26,6 +26,7 @@ import (
 	"github.com/jenkins-x/go-scm/scm"
 	"github.com/jenkins-x/lighthouse/pkg/apis/lighthouse/v1alpha1"
 	"github.com/jenkins-x/lighthouse/pkg/config"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/scmprovider"
 	"github.com/jenkins-x/lighthouse/pkg/util"
 	uuid "github.com/satori/go.uuid"
@@ -85,7 +86,7 @@ func createRefs(pr *scm.PullRequest, baseSHA string, prRefFmt string) v1alpha1.R
 // NewPresubmit converts a config.Presubmit into a builder.PipelineOptions.
 // The builder.Refs are configured correctly per the pr, baseSHA.
 // The eventGUID becomes a gitprovider.EventGUID label.
-func NewPresubmit(pr *scm.PullRequest, baseSHA string, job config.Presubmit, eventGUID string, prRefFmt string) v1alpha1.LighthouseJob {
+func NewPresubmit(pr *scm.PullRequest, baseSHA string, job job.Presubmit, eventGUID string, prRefFmt string) v1alpha1.LighthouseJob {
 	refs := createRefs(pr, baseSHA, prRefFmt)
 	labels := make(map[string]string)
 	for k, v := range job.Labels {
@@ -100,45 +101,45 @@ func NewPresubmit(pr *scm.PullRequest, baseSHA string, job config.Presubmit, eve
 }
 
 // PresubmitSpec initializes a PipelineOptionsSpec for a given presubmit job.
-func PresubmitSpec(p config.Presubmit, refs v1alpha1.Refs) v1alpha1.LighthouseJobSpec {
-	pjs := specFromJobBase(p.JobBase)
+func PresubmitSpec(p job.Presubmit, refs v1alpha1.Refs) v1alpha1.LighthouseJobSpec {
+	pjs := specFromJobBase(p.Base)
 	pjs.Type = config.PresubmitJob
 	pjs.Context = p.Context
 	pjs.RerunCommand = p.RerunCommand
-	pjs.Refs = completePrimaryRefs(refs, p.JobBase)
+	pjs.Refs = completePrimaryRefs(refs, p.Base)
 
 	return pjs
 }
 
 // PostsubmitSpec initializes a PipelineOptionsSpec for a given postsubmit job.
-func PostsubmitSpec(p config.Postsubmit, refs v1alpha1.Refs) v1alpha1.LighthouseJobSpec {
-	pjs := specFromJobBase(p.JobBase)
+func PostsubmitSpec(p job.Postsubmit, refs v1alpha1.Refs) v1alpha1.LighthouseJobSpec {
+	pjs := specFromJobBase(p.Base)
 	pjs.Type = config.PostsubmitJob
 	pjs.Context = p.Context
-	pjs.Refs = completePrimaryRefs(refs, p.JobBase)
+	pjs.Refs = completePrimaryRefs(refs, p.Base)
 
 	return pjs
 }
 
 // PeriodicSpec initializes a PipelineOptionsSpec for a given periodic job.
-func PeriodicSpec(p config.Periodic) v1alpha1.LighthouseJobSpec {
-	pjs := specFromJobBase(p.JobBase)
+func PeriodicSpec(p job.Periodic) v1alpha1.LighthouseJobSpec {
+	pjs := specFromJobBase(p.Base)
 	pjs.Type = config.PeriodicJob
 
 	return pjs
 }
 
 // BatchSpec initializes a PipelineOptionsSpec for a given batch job and ref spec.
-func BatchSpec(p config.Presubmit, refs v1alpha1.Refs) v1alpha1.LighthouseJobSpec {
-	pjs := specFromJobBase(p.JobBase)
+func BatchSpec(p job.Presubmit, refs v1alpha1.Refs) v1alpha1.LighthouseJobSpec {
+	pjs := specFromJobBase(p.Base)
 	pjs.Type = config.BatchJob
 	pjs.Context = p.Context
-	pjs.Refs = completePrimaryRefs(refs, p.JobBase)
+	pjs.Refs = completePrimaryRefs(refs, p.Base)
 
 	return pjs
 }
 
-func specFromJobBase(jb config.JobBase) v1alpha1.LighthouseJobSpec {
+func specFromJobBase(jb job.Base) v1alpha1.LighthouseJobSpec {
 	var namespace string
 	if jb.Namespace != nil {
 		namespace = *jb.Namespace
@@ -153,7 +154,7 @@ func specFromJobBase(jb config.JobBase) v1alpha1.LighthouseJobSpec {
 	}
 }
 
-func completePrimaryRefs(refs v1alpha1.Refs, jb config.JobBase) *v1alpha1.Refs {
+func completePrimaryRefs(refs v1alpha1.Refs, jb job.Base) *v1alpha1.Refs {
 	if jb.PathAlias != "" {
 		refs.PathAlias = jb.PathAlias
 	}
diff --git a/pkg/keeper/keeper.go b/pkg/keeper/keeper.go
index 395e770a..f79b5e1a 100644
--- a/pkg/keeper/keeper.go
+++ b/pkg/keeper/keeper.go
@@ -34,6 +34,7 @@ import (
 	"github.com/jenkins-x/lighthouse/pkg/apis/lighthouse/v1alpha1"
 	clientset "github.com/jenkins-x/lighthouse/pkg/client/clientset/versioned"
 	"github.com/jenkins-x/lighthouse/pkg/config"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/errorutil"
 	"github.com/jenkins-x/lighthouse/pkg/git"
 	"github.com/jenkins-x/lighthouse/pkg/jobutil"
@@ -671,7 +672,7 @@ func pickSmallestPassingNumber(log *logrus.Entry, spc scmProviderClient, prs []P
 // accumulateBatch returns a list of PRs that can be merged after passing batch
 // testing, if any exist. It also returns a list of PRs currently being batch
 // tested.
-func accumulateBatch(presubmits map[int][]config.Presubmit, prs []PullRequest, pjs []v1alpha1.LighthouseJob, log *logrus.Entry) ([]PullRequest, []PullRequest) {
+func accumulateBatch(presubmits map[int][]job.Presubmit, prs []PullRequest, pjs []v1alpha1.LighthouseJob, log *logrus.Entry) ([]PullRequest, []PullRequest) {
 	log.Debug("accumulating PRs for batch testing")
 	if len(presubmits) == 0 {
 		log.Debug("no presubmits configured, no batch can be triggered")
@@ -764,9 +765,9 @@ func accumulateBatch(presubmits map[int][]config.Presubmit, prs []PullRequest, p
 
 // accumulate returns the supplied PRs sorted into three buckets based on their
 // accumulated state across the presubmits.
-func accumulate(presubmits map[int][]config.Presubmit, prs []PullRequest, pjs []v1alpha1.LighthouseJob, log *logrus.Entry) (successes, pendings, missings []PullRequest, missingTests map[int][]config.Presubmit) {
+func accumulate(presubmits map[int][]job.Presubmit, prs []PullRequest, pjs []v1alpha1.LighthouseJob, log *logrus.Entry) (successes, pendings, missings []PullRequest, missingTests map[int][]job.Presubmit) {
 
-	missingTests = map[int][]config.Presubmit{}
+	missingTests = map[int][]job.Presubmit{}
 	for _, pr := range prs {
 		// Accumulate the best result for each job (Passing > Pending > Failing/Unknown)
 		// We can ignore the baseSHA here because the subPool only contains PipelineActivitys with the correct baseSHA
@@ -1099,7 +1100,7 @@ func tryMerge(mergeFunc func() error) (bool, error) {
 	return true, err
 }
 
-func (c *DefaultController) trigger(sp subpool, presubmits map[int][]config.Presubmit, prs []PullRequest) error {
+func (c *DefaultController) trigger(sp subpool, presubmits map[int][]job.Presubmit, prs []PullRequest) error {
 	refs := v1alpha1.Refs{
 		Org:      sp.org,
 		Repo:     sp.repo,
@@ -1161,7 +1162,7 @@ func (c *DefaultController) trigger(sp subpool, presubmits map[int][]config.Pres
 	return nil
 }
 
-func (c *DefaultController) takeAction(sp subpool, batchPending, successes, pendings, missings, batchMerges []PullRequest, missingSerialTests map[int][]config.Presubmit) (Action, []PullRequest, error) {
+func (c *DefaultController) takeAction(sp subpool, batchPending, successes, pendings, missings, batchMerges []PullRequest, missingSerialTests map[int][]job.Presubmit) (Action, []PullRequest, error) {
 	// Merge the batch!
 	if len(batchMerges) > 0 {
 		return MergeBatch, batchMerges, c.mergePRs(sp, batchMerges)
@@ -1215,7 +1216,7 @@ type changeCacheKey struct {
 
 // prChanges gets the files changed by the PR, either from the cache or by
 // querying GitHub.
-func (c *changedFilesAgent) prChanges(pr *PullRequest) config.ChangedFilesProvider {
+func (c *changedFilesAgent) prChanges(pr *PullRequest) job.ChangedFilesProvider {
 	return func() ([]string, error) {
 		cacheKey := changeCacheKey{
 			org:    string(pr.Repository.Owner.Login),
@@ -1268,13 +1269,13 @@ func (c *changedFilesAgent) prune() {
 	c.nextChangeCache = make(map[changeCacheKey][]string)
 }
 
-func (c *DefaultController) presubmitsByPull(sp *subpool) (map[int][]config.Presubmit, error) {
-	presubmits := make(map[int][]config.Presubmit, len(sp.prs))
-	record := func(num int, job config.Presubmit) {
+func (c *DefaultController) presubmitsByPull(sp *subpool) (map[int][]job.Presubmit, error) {
+	presubmits := make(map[int][]job.Presubmit, len(sp.prs))
+	record := func(num int, j job.Presubmit) {
 		if jobs, ok := presubmits[num]; ok {
-			presubmits[num] = append(jobs, job)
+			presubmits[num] = append(jobs, j)
 		} else {
-			presubmits[num] = []config.Presubmit{job}
+			presubmits[num] = []job.Presubmit{j}
 		}
 	}
 
@@ -1424,7 +1425,7 @@ type subpool struct {
 	cc contextChecker
 	// presubmit contains all required presubmits for each PR
 	// in this subpool
-	presubmits map[int][]config.Presubmit
+	presubmits map[int][]job.Presubmit
 }
 
 func poolKey(org, repo, branch string) string {
diff --git a/pkg/plugins/override/override.go b/pkg/plugins/override/override.go
index 861b3694..2ad5b837 100644
--- a/pkg/plugins/override/override.go
+++ b/pkg/plugins/override/override.go
@@ -25,6 +25,7 @@ import (
 	"github.com/jenkins-x/go-scm/scm"
 	"github.com/jenkins-x/lighthouse/pkg/apis/lighthouse/v1alpha1"
 	lighthouseclient "github.com/jenkins-x/lighthouse/pkg/client/clientset/versioned/typed/lighthouse/v1alpha1"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/jobutil"
 	"github.com/jenkins-x/lighthouse/pkg/scmprovider"
 	"github.com/jenkins-x/lighthouse/pkg/util"
@@ -32,7 +33,6 @@ import (
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"k8s.io/apimachinery/pkg/util/sets"
 
-	"github.com/jenkins-x/lighthouse/pkg/config"
 	"github.com/jenkins-x/lighthouse/pkg/pluginhelp"
 	"github.com/jenkins-x/lighthouse/pkg/plugins"
 )
@@ -58,13 +58,13 @@ type scmProviderClient interface {
 
 type overrideClient interface {
 	scmProviderClient
-	presubmitForContext(org, repo, context string) *config.Presubmit
+	presubmitForContext(org, repo, context string) *job.Presubmit
 	createOverrideJob(job *v1alpha1.LighthouseJob) (*v1alpha1.LighthouseJob, error)
 }
 
 type client struct {
 	spc      scmProviderClient
-	jc       config.JobConfig
+	jc       job.Config
 	lhClient lighthouseclient.LighthouseJobInterface
 }
 
@@ -117,7 +117,7 @@ func (c client) QuoteAuthorForComment(author string) string {
 	return c.spc.QuoteAuthorForComment(author)
 }
 
-func (c client) presubmitForContext(org, repo, context string) *config.Presubmit {
+func (c client) presubmitForContext(org, repo, context string) *job.Presubmit {
 	for _, p := range c.jc.AllPresubmits([]string{org + "/" + repo}) {
 		if p.Context == context {
 			return &p
diff --git a/pkg/plugins/skip/skip.go b/pkg/plugins/skip/skip.go
index 69e8573f..ad5c915f 100644
--- a/pkg/plugins/skip/skip.go
+++ b/pkg/plugins/skip/skip.go
@@ -23,7 +23,7 @@ import (
 	"regexp"
 
 	"github.com/jenkins-x/go-scm/scm"
-	"github.com/jenkins-x/lighthouse/pkg/config"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/pluginhelp"
 	"github.com/jenkins-x/lighthouse/pkg/plugins"
 	"github.com/jenkins-x/lighthouse/pkg/plugins/trigger"
@@ -69,7 +69,7 @@ func handleGenericComment(pc plugins.Agent, e scmprovider.GenericCommentEvent) e
 	return handle(pc.SCMProviderClient, pc.Logger, &e, pc.Config.GetPresubmits(e.Repo), honorOkToTest)
 }
 
-func handle(spc scmProviderClient, log *logrus.Entry, e *scmprovider.GenericCommentEvent, presubmits []config.Presubmit, honorOkToTest bool) error {
+func handle(spc scmProviderClient, log *logrus.Entry, e *scmprovider.GenericCommentEvent, presubmits []job.Presubmit, honorOkToTest bool) error {
 	if !e.IsPR || e.IssueState != "open" || e.Action != scm.ActionCreate {
 		return nil
 	}
@@ -106,7 +106,7 @@ func handle(spc scmProviderClient, log *logrus.Entry, e *scmprovider.GenericComm
 		log.Warn(resp)
 		return spc.CreateComment(org, repo, number, e.IsPR, plugins.FormatResponseRaw(e.Body, e.Link, spc.QuoteAuthorForComment(e.Author.Login), resp))
 	}
-	triggerWillHandle := func(p config.Presubmit) bool {
+	triggerWillHandle := func(p job.Presubmit) bool {
 		for _, presubmit := range filteredPresubmits {
 			if p.Name == presubmit.Name && p.Context == presubmit.Context {
 				return true
@@ -148,7 +148,7 @@ func handle(spc scmProviderClient, log *logrus.Entry, e *scmprovider.GenericComm
 	return nil
 }
 
-func statusExists(job config.Presubmit, statuses []*scm.Status) bool {
+func statusExists(job job.Presubmit, statuses []*scm.Status) bool {
 	for _, status := range statuses {
 		if status.Label == job.Context {
 			return true
@@ -157,7 +157,7 @@ func statusExists(job config.Presubmit, statuses []*scm.Status) bool {
 	return false
 }
 
-func isSuccess(job config.Presubmit, statuses []*scm.Status) bool {
+func isSuccess(job job.Presubmit, statuses []*scm.Status) bool {
 	for _, status := range statuses {
 		if status.Label == job.Context && status.State == scm.StateSuccess {
 			return true
diff --git a/pkg/plugins/trigger/generic-comment.go b/pkg/plugins/trigger/generic-comment.go
index d0cda1f3..cd6cb57a 100644
--- a/pkg/plugins/trigger/generic-comment.go
+++ b/pkg/plugins/trigger/generic-comment.go
@@ -20,10 +20,10 @@ import (
 	"fmt"
 
 	"github.com/jenkins-x/go-scm/scm"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/scmprovider"
 	"github.com/sirupsen/logrus"
 
-	"github.com/jenkins-x/lighthouse/pkg/config"
 	"github.com/jenkins-x/lighthouse/pkg/jobutil"
 	"github.com/jenkins-x/lighthouse/pkg/labels"
 	"github.com/jenkins-x/lighthouse/pkg/plugins"
@@ -144,7 +144,7 @@ type SCMProviderClient interface {
 // If a comment that we get matches more than one of the above patterns, we
 // consider the set of matching presubmits the union of the results from the
 // matching cases.
-func FilterPresubmits(honorOkToTest bool, scmClient SCMProviderClient, body string, pr *scm.PullRequest, presubmits []config.Presubmit, logger *logrus.Entry) ([]config.Presubmit, []config.Presubmit, error) {
+func FilterPresubmits(honorOkToTest bool, scmClient SCMProviderClient, body string, pr *scm.PullRequest, presubmits []job.Presubmit, logger *logrus.Entry) ([]job.Presubmit, []job.Presubmit, error) {
 	org, repo, sha := pr.Base.Repo.Namespace, pr.Base.Repo.Name, pr.Head.Sha
 
 	contextGetter := func() (sets.String, sets.String, error) {
@@ -162,7 +162,7 @@ func FilterPresubmits(honorOkToTest bool, scmClient SCMProviderClient, body stri
 	}
 
 	number, branch := pr.Number, pr.Base.Ref
-	changes := config.NewGitHubDeferredChangedFilesProvider(scmClient, org, repo, number)
+	changes := job.NewGitHubDeferredChangedFilesProvider(scmClient, org, repo, number)
 	return jobutil.FilterPresubmits(filter, changes, branch, presubmits, logger)
 }
 
diff --git a/pkg/plugins/trigger/pull-request.go b/pkg/plugins/trigger/pull-request.go
index 3179672c..0485695e 100644
--- a/pkg/plugins/trigger/pull-request.go
+++ b/pkg/plugins/trigger/pull-request.go
@@ -21,7 +21,7 @@ import (
 	"net/url"
 
 	"github.com/jenkins-x/go-scm/scm"
-	"github.com/jenkins-x/lighthouse/pkg/config"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/errorutil"
 	"github.com/jenkins-x/lighthouse/pkg/jobutil"
 	"github.com/jenkins-x/lighthouse/pkg/labels"
@@ -214,7 +214,7 @@ func TrustedPullRequest(spc scmProviderClient, trigger *plugins.Trigger, author,
 // buildAll ensures that all builds that should run and will be required are built
 func buildAll(c Client, pr *scm.PullRequest, eventGUID string, elideSkippedContexts bool) error {
 	org, repo, number, branch := pr.Base.Repo.Namespace, pr.Base.Repo.Name, pr.Number, pr.Base.Ref
-	changes := config.NewGitHubDeferredChangedFilesProvider(c.SCMProviderClient, org, repo, number)
+	changes := job.NewGitHubDeferredChangedFilesProvider(c.SCMProviderClient, org, repo, number)
 	toTest, toSkip, err := jobutil.FilterPresubmits(jobutil.TestAllFilter(), changes, branch, c.Config.GetPresubmits(pr.Base.Repo), c.Logger)
 	if err != nil {
 		return err
diff --git a/pkg/plugins/trigger/push.go b/pkg/plugins/trigger/push.go
index f7712647..fb947031 100644
--- a/pkg/plugins/trigger/push.go
+++ b/pkg/plugins/trigger/push.go
@@ -19,12 +19,12 @@ package trigger
 import (
 	"github.com/jenkins-x/go-scm/scm"
 	"github.com/jenkins-x/lighthouse/pkg/apis/lighthouse/v1alpha1"
-	"github.com/jenkins-x/lighthouse/pkg/config"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/jobutil"
 	"github.com/jenkins-x/lighthouse/pkg/scmprovider"
 )
 
-func listPushEventChanges(pe scm.PushHook) config.ChangedFilesProvider {
+func listPushEventChanges(pe scm.PushHook) job.ChangedFilesProvider {
 	return func() ([]string, error) {
 		changed := make(map[string]bool)
 		for _, commit := range pe.Commits {
diff --git a/pkg/plugins/trigger/trigger.go b/pkg/plugins/trigger/trigger.go
index cb130dc7..675b60bc 100644
--- a/pkg/plugins/trigger/trigger.go
+++ b/pkg/plugins/trigger/trigger.go
@@ -23,6 +23,7 @@ import (
 	"github.com/jenkins-x/go-scm/scm"
 	"github.com/jenkins-x/lighthouse/pkg/apis/lighthouse/v1alpha1"
 	"github.com/jenkins-x/lighthouse/pkg/config"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/errorutil"
 	"github.com/jenkins-x/lighthouse/pkg/jobutil"
 	"github.com/jenkins-x/lighthouse/pkg/pluginhelp"
@@ -215,7 +216,7 @@ func failedStatusForMetapipelineCreation(context string, err error) *scm.StatusI
 
 // RunAndSkipJobs executes the config.Presubmits that are requested and posts skipped statuses
 // for the reporting jobs that are skipped
-func RunAndSkipJobs(c Client, pr *scm.PullRequest, requestedJobs []config.Presubmit, skippedJobs []config.Presubmit, eventGUID string, elideSkippedContexts bool) error {
+func RunAndSkipJobs(c Client, pr *scm.PullRequest, requestedJobs []job.Presubmit, skippedJobs []job.Presubmit, eventGUID string, elideSkippedContexts bool) error {
 	if err := validateContextOverlap(requestedJobs, skippedJobs); err != nil {
 		c.Logger.WithError(err).Warn("Could not run or skip requested jobs, overlapping contexts.")
 		return err
@@ -230,7 +231,7 @@ func RunAndSkipJobs(c Client, pr *scm.PullRequest, requestedJobs []config.Presub
 }
 
 // validateContextOverlap ensures that there will be no overlap in contexts between a set of jobs running and a set to skip
-func validateContextOverlap(toRun, toSkip []config.Presubmit) error {
+func validateContextOverlap(toRun, toSkip []job.Presubmit) error {
 	requestedContexts := sets.NewString()
 	for _, job := range toRun {
 		requestedContexts.Insert(job.Context)
@@ -247,7 +248,7 @@ func validateContextOverlap(toRun, toSkip []config.Presubmit) error {
 }
 
 // runRequested executes the config.Presubmits that are requested
-func runRequested(c Client, pr *scm.PullRequest, requestedJobs []config.Presubmit, eventGUID string) error {
+func runRequested(c Client, pr *scm.PullRequest, requestedJobs []job.Presubmit, eventGUID string) error {
 	baseSHA, err := c.SCMProviderClient.GetRef(pr.Base.Repo.Namespace, pr.Base.Repo.Name, "heads/"+pr.Base.Ref)
 	if err != nil {
 		return err
@@ -270,7 +271,7 @@ func runRequested(c Client, pr *scm.PullRequest, requestedJobs []config.Presubmi
 }
 
 // skipRequested posts skipped statuses for the config.Presubmits that are requested
-func skipRequested(c Client, pr *scm.PullRequest, skippedJobs []config.Presubmit) error {
+func skipRequested(c Client, pr *scm.PullRequest, skippedJobs []job.Presubmit) error {
 	var errors []error
 	for _, job := range skippedJobs {
 		if job.SkipReport {
diff --git a/pkg/repoconfig/merge/converters.go b/pkg/repoconfig/merge/converters.go
index efb22c5f..647a3cd7 100644
--- a/pkg/repoconfig/merge/converters.go
+++ b/pkg/repoconfig/merge/converters.go
@@ -1,15 +1,15 @@
 package merge
 
 import (
-	"github.com/jenkins-x/lighthouse/pkg/config"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/plugins"
 	"github.com/jenkins-x/lighthouse/pkg/repoconfig"
 )
 
 // ToPresubmit converts the repo config to the lighthouse config resource
-func ToPresubmit(r repoconfig.Presubmit) config.Presubmit {
-	return config.Presubmit{
-		JobBase:             ToJobBase(r.JobBase),
+func ToPresubmit(r repoconfig.Presubmit) job.Presubmit {
+	return job.Presubmit{
+		Base:                ToJobBase(r.JobBase),
 		AlwaysRun:           r.AlwaysRun,
 		Optional:            r.Optional,
 		Trigger:             r.Trigger,
@@ -21,9 +21,9 @@ func ToPresubmit(r repoconfig.Presubmit) config.Presubmit {
 }
 
 // ToPostsubmit converts the repo config to the lighthouse config resource
-func ToPostsubmit(r repoconfig.Postsubmit) config.Postsubmit {
-	return config.Postsubmit{
-		JobBase:             ToJobBase(r.JobBase),
+func ToPostsubmit(r repoconfig.Postsubmit) job.Postsubmit {
+	return job.Postsubmit{
+		Base:                ToJobBase(r.JobBase),
 		RegexpChangeMatcher: ToRegexpChangeMatcher(r.RegexpChangeMatcher),
 		Brancher:            ToBrancher(r.Brancher),
 		Reporter:            ToReporter(r.Reporter),
@@ -31,8 +31,8 @@ func ToPostsubmit(r repoconfig.Postsubmit) config.Postsubmit {
 }
 
 // ToJobBase converts the repo config to the lighthouse config resource
-func ToJobBase(r repoconfig.JobBase) config.JobBase {
-	return config.JobBase{
+func ToJobBase(r repoconfig.JobBase) job.Base {
+	return job.Base{
 		Name:            r.Name,
 		Labels:          r.Labels,
 		Annotations:     r.Annotations,
@@ -49,29 +49,29 @@ func ToJobBase(r repoconfig.JobBase) config.JobBase {
 }
 
 // ToBrancher converts the repo config to the lighthouse config resource
-func ToBrancher(r repoconfig.Brancher) config.Brancher {
-	return config.Brancher{
+func ToBrancher(r repoconfig.Brancher) job.Brancher {
+	return job.Brancher{
 		SkipBranches: r.SkipBranches,
 		Branches:     r.Branches,
 	}
 }
 
 // ToReporter converts the repo config to the lighthouse config resource
-func ToReporter(r repoconfig.Reporter) config.Reporter {
-	return config.Reporter{
+func ToReporter(r repoconfig.Reporter) job.Reporter {
+	return job.Reporter{
 		Context:    r.Context,
 		SkipReport: r.SkipReport,
 	}
 }
 
 // ToRegexpChangeMatcher converts the repo config to the lighthouse config resource
-func ToRegexpChangeMatcher(r repoconfig.RegexpChangeMatcher) config.RegexpChangeMatcher {
-	return config.RegexpChangeMatcher{RunIfChanged: r.RunIfChanged}
+func ToRegexpChangeMatcher(r repoconfig.RegexpChangeMatcher) job.RegexpChangeMatcher {
+	return job.RegexpChangeMatcher{RunIfChanged: r.RunIfChanged}
 }
 
 // ToUtilityConfig converts the repo config to the lighthouse config resource
-func ToUtilityConfig(r repoconfig.UtilityConfig) config.UtilityConfig {
-	return config.UtilityConfig{
+func ToUtilityConfig(r repoconfig.UtilityConfig) job.UtilityConfig {
+	return job.UtilityConfig{
 		Decorate:       r.Decorate,
 		PathAlias:      r.PathAlias,
 		CloneURI:       r.CloneURI,
diff --git a/pkg/repoconfig/merge/merge.go b/pkg/repoconfig/merge/merge.go
index e026e8f1..8def7d8f 100644
--- a/pkg/repoconfig/merge/merge.go
+++ b/pkg/repoconfig/merge/merge.go
@@ -2,6 +2,7 @@ package merge
 
 import (
 	"github.com/jenkins-x/lighthouse/pkg/config"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/plugins"
 	"github.com/jenkins-x/lighthouse/pkg/repoconfig"
 )
@@ -11,10 +12,10 @@ func ConfigMerge(cfg *config.Config, pluginsCfg *plugins.Configuration, repoConf
 	repoKey := repoOwner + "/" + repoName
 	if len(repoConfig.Spec.Presubmits) > 0 {
 		if cfg.Presubmits == nil {
-			cfg.Presubmits = map[string][]config.Presubmit{}
+			cfg.Presubmits = map[string][]job.Presubmit{}
 		}
 
-		var ps []config.Presubmit
+		var ps []job.Presubmit
 		for _, p := range repoConfig.Spec.Presubmits {
 			ps = append(ps, ToPresubmit(p))
 		}
@@ -22,10 +23,10 @@ func ConfigMerge(cfg *config.Config, pluginsCfg *plugins.Configuration, repoConf
 	}
 	if len(repoConfig.Spec.Postsubmits) > 0 {
 		if cfg.Postsubmits == nil {
-			cfg.Postsubmits = map[string][]config.Postsubmit{}
+			cfg.Postsubmits = map[string][]job.Postsubmit{}
 		}
 
-		var ps []config.Postsubmit
+		var ps []job.Postsubmit
 		for _, p := range repoConfig.Spec.Postsubmits {
 			ps = append(ps, ToPostsubmit(p))
 		}
diff --git a/pkg/repoconfig/repoconfig_config_types.go b/pkg/repoconfig/repoconfig_config_types.go
index 6bdaa24f..85c885b2 100644
--- a/pkg/repoconfig/repoconfig_config_types.go
+++ b/pkg/repoconfig/repoconfig_config_types.go
@@ -20,7 +20,7 @@ import (
 	"regexp"
 	"time"
 
-	"github.com/jenkins-x/lighthouse/pkg/config"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	tektonv1beta1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1"
 	v1 "k8s.io/api/core/v1"
 )
@@ -61,7 +61,7 @@ type JobBase struct {
 	// PipelineRunSpec is the Tekton PipelineRun spec used if agent is tekton-pipeline
 	PipelineRunSpec *tektonv1beta1.PipelineRunSpec `json:"pipelineRunSpec,omitempty"`
 	// PipelineRunParams are the params used by the pipeline run
-	PipelineRunParams []config.PipelineRunParam `json:"pipeline_run_params,omitempty"`
+	PipelineRunParams []job.PipelineRunParam `json:"pipeline_run_params,omitempty"`
 
 	UtilityConfig
 }


Test patch:
diff --git a/pkg/config/branch_protection_test.go b/pkg/config/branch_protection_test.go
index 591fd197..5da51bb3 100644
--- a/pkg/config/branch_protection_test.go
+++ b/pkg/config/branch_protection_test.go
@@ -21,6 +21,7 @@ import (
 	"sort"
 	"testing"
 
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"k8s.io/apimachinery/pkg/util/diff"
 )
 
@@ -304,51 +305,51 @@ func TestApply(test *testing.T) {
 func TestBranchRequirements(t *testing.T) {
 	cases := []struct {
 		name                            string
-		config                          []Presubmit
+		config                          []job.Presubmit
 		masterExpected, otherExpected   []string
 		masterOptional, otherOptional   []string
 		masterIfPresent, otherIfPresent []string
 	}{
 		{
 			name: "basic",
-			config: []Presubmit{
+			config: []job.Presubmit{
 				{
 					AlwaysRun: true,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "always-run",
 						SkipReport: false,
 					},
 				},
 				{
-					RegexpChangeMatcher: RegexpChangeMatcher{
+					RegexpChangeMatcher: job.RegexpChangeMatcher{
 						RunIfChanged: "foo",
 					},
 					AlwaysRun: false,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "run-if-changed",
 						SkipReport: false,
 					},
 				},
 				{
 					AlwaysRun: false,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "not-always",
 						SkipReport: false,
 					},
 				},
 				{
 					AlwaysRun: true,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "skip-report",
 						SkipReport: true,
 					},
-					Brancher: Brancher{
+					Brancher: job.Brancher{
 						SkipBranches: []string{"master"},
 					},
 				},
 				{
 					AlwaysRun: true,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "optional",
 						SkipReport: false,
 					},
@@ -365,10 +366,10 @@ func TestBranchRequirements(t *testing.T) {
 	}
 
 	for _, tc := range cases {
-		if err := SetPresubmitRegexes(tc.config); err != nil {
+		if err := job.SetPresubmitRegexes(tc.config); err != nil {
 			t.Fatalf("could not set regexes: %v", err)
 		}
-		presubmits := map[string][]Presubmit{
+		presubmits := map[string][]job.Presubmit{
 			"o/r": tc.config,
 		}
 		masterActual, masterActualIfPresent, masterOptional := BranchRequirements("o", "r", "master", presubmits)
@@ -618,14 +619,14 @@ func TestConfig_GetBranchProtection(t *testing.T) {
 						},
 					},
 				},
-				JobConfig: JobConfig{
-					Presubmits: map[string][]Presubmit{
+				JobConfig: job.Config{
+					Presubmits: map[string][]job.Presubmit{
 						"org/repo": {
 							{
-								JobBase: JobBase{
+								Base: job.Base{
 									Name: "required presubmit",
 								},
-								Reporter: Reporter{
+								Reporter: job.Reporter{
 									Context: "required presubmit",
 								},
 								AlwaysRun: true,
@@ -652,14 +653,14 @@ func TestConfig_GetBranchProtection(t *testing.T) {
 						},
 					},
 				},
-				JobConfig: JobConfig{
-					Presubmits: map[string][]Presubmit{
+				JobConfig: job.Config{
+					Presubmits: map[string][]job.Presubmit{
 						"org/repo": {
 							{
-								JobBase: JobBase{
+								Base: job.Base{
 									Name: "required presubmit",
 								},
-								Reporter: Reporter{
+								Reporter: job.Reporter{
 									Context: "required presubmit",
 								},
 								AlwaysRun: true,
@@ -688,14 +689,14 @@ func TestConfig_GetBranchProtection(t *testing.T) {
 						},
 					},
 				},
-				JobConfig: JobConfig{
-					Presubmits: map[string][]Presubmit{
+				JobConfig: job.Config{
+					Presubmits: map[string][]job.Presubmit{
 						"org/repo": {
 							{
-								JobBase: JobBase{
+								Base: job.Base{
 									Name: "required presubmit",
 								},
-								Reporter: Reporter{
+								Reporter: job.Reporter{
 									Context: "required presubmit",
 								},
 								AlwaysRun: true,
@@ -717,14 +718,14 @@ func TestConfig_GetBranchProtection(t *testing.T) {
 						},
 					},
 				},
-				JobConfig: JobConfig{
-					Presubmits: map[string][]Presubmit{
+				JobConfig: job.Config{
+					Presubmits: map[string][]job.Presubmit{
 						"org/repo": {
 							{
-								JobBase: JobBase{
+								Base: job.Base{
 									Name: "optional presubmit",
 								},
-								Reporter: Reporter{
+								Reporter: job.Reporter{
 									Context: "optional presubmit",
 								},
 								AlwaysRun: true,
@@ -750,14 +751,14 @@ func TestConfig_GetBranchProtection(t *testing.T) {
 						},
 					},
 				},
-				JobConfig: JobConfig{
-					Presubmits: map[string][]Presubmit{
+				JobConfig: job.Config{
+					Presubmits: map[string][]job.Presubmit{
 						"org/repo": {
 							{
-								JobBase: JobBase{
+								Base: job.Base{
 									Name: "optional presubmit",
 								},
-								Reporter: Reporter{
+								Reporter: job.Reporter{
 									Context: "optional presubmit",
 								},
 								AlwaysRun: true,
@@ -789,14 +790,14 @@ func TestConfig_GetBranchProtection(t *testing.T) {
 						},
 					},
 				},
-				JobConfig: JobConfig{
-					Presubmits: map[string][]Presubmit{
+				JobConfig: job.Config{
+					Presubmits: map[string][]job.Presubmit{
 						"org/repo": {
 							{
-								JobBase: JobBase{
+								Base: job.Base{
 									Name: "required presubmit",
 								},
-								Reporter: Reporter{
+								Reporter: job.Reporter{
 									Context: "required presubmit",
 								},
 								AlwaysRun: true,
diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go
index cfc7197a..d29eb4f4 100644
--- a/pkg/config/config_test.go
+++ b/pkg/config/config_test.go
@@ -25,6 +25,7 @@ import (
 	"testing"
 	"time"
 
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/config/secret"
 	"github.com/stretchr/testify/assert"
 	v1 "k8s.io/api/core/v1"
@@ -32,7 +33,7 @@ import (
 
 func TestDefaultJobBase(t *testing.T) {
 	bar := "bar"
-	filled := JobBase{
+	filled := job.Base{
 		Agent:     "foo",
 		Namespace: &bar,
 		Cluster:   "build",
@@ -40,19 +41,19 @@ func TestDefaultJobBase(t *testing.T) {
 	cases := []struct {
 		name     string
 		config   ProwConfig
-		base     func(j *JobBase)
-		expected func(j *JobBase)
+		base     func(j *job.Base)
+		expected func(j *job.Base)
 	}{
 		{
 			name: "no changes when fields are already set",
 		},
 		{
 			name: "empty agent results in kubernetes",
-			base: func(j *JobBase) {
+			base: func(j *job.Base) {
 				j.Agent = ""
 			},
-			expected: func(j *JobBase) {
-				j.Agent = string(JenkinsXAgent)
+			expected: func(j *job.Base) {
+				j.Agent = string(job.JenkinsXAgent)
 			},
 		},
 		{
@@ -61,10 +62,10 @@ func TestDefaultJobBase(t *testing.T) {
 				PodNamespace:           "pod-namespace",
 				LighthouseJobNamespace: "wrong",
 			},
-			base: func(j *JobBase) {
+			base: func(j *job.Base) {
 				j.Namespace = nil
 			},
-			expected: func(j *JobBase) {
+			expected: func(j *job.Base) {
 				p := "pod-namespace"
 				j.Namespace = &p
 			},
@@ -75,21 +76,21 @@ func TestDefaultJobBase(t *testing.T) {
 				PodNamespace:           "new-pod-namespace",
 				LighthouseJobNamespace: "still-wrong",
 			},
-			base: func(j *JobBase) {
+			base: func(j *job.Base) {
 				var empty string
 				j.Namespace = &empty
 			},
-			expected: func(j *JobBase) {
+			expected: func(j *job.Base) {
 				p := "new-pod-namespace"
 				j.Namespace = &p
 			},
 		},
 		{
 			name: "empty cluster becomes DefaultClusterAlias",
-			base: func(j *JobBase) {
+			base: func(j *job.Base) {
 				j.Cluster = ""
 			},
-			expected: func(j *JobBase) {
+			expected: func(j *job.Base) {
 				j.Cluster = DefaultClusterAlias
 			},
 		},
@@ -105,7 +106,7 @@ func TestDefaultJobBase(t *testing.T) {
 			if tc.expected != nil {
 				tc.expected(&expected)
 			}
-			tc.config.defaultJobBase(&actual)
+			actual.SetDefaults(tc.config.PodNamespace)
 			if !reflect.DeepEqual(actual, expected) {
 				t.Errorf("expected %#v\n!=\nactual %#v", expected, actual)
 			}
@@ -114,9 +115,9 @@ func TestDefaultJobBase(t *testing.T) {
 }
 
 func TestValidateAgent(t *testing.T) {
-	k := string(JenkinsXAgent)
+	k := string(job.JenkinsXAgent)
 	ns := "default"
-	base := JobBase{
+	base := job.Base{
 		Agent:     k,
 		Namespace: &ns,
 		Spec:      &v1.PodSpec{},
@@ -124,12 +125,12 @@ func TestValidateAgent(t *testing.T) {
 
 	cases := []struct {
 		name string
-		base func(j *JobBase)
+		base func(j *job.Base)
 		pass bool
 	}{
 		{
 			name: "reject unknown agent",
-			base: func(j *JobBase) {
+			base: func(j *job.Base) {
 				j.Agent = "random-agent"
 			},
 		},
@@ -194,7 +195,7 @@ func TestValidateLabels(t *testing.T) {
 }
 
 func TestValidateJobBase(t *testing.T) {
-	ka := string(JenkinsXAgent)
+	ka := string(job.JenkinsXAgent)
 	goodSpec := v1.PodSpec{
 		Containers: []v1.Container{
 			{},
@@ -203,12 +204,12 @@ func TestValidateJobBase(t *testing.T) {
 	ns := "target-namespace"
 	cases := []struct {
 		name string
-		base JobBase
+		base job.Base
 		pass bool
 	}{
 		{
 			name: "valid kubernetes job",
-			base: JobBase{
+			base: job.Base{
 				Name:      "name",
 				Agent:     ka,
 				Spec:      &goodSpec,
@@ -218,7 +219,7 @@ func TestValidateJobBase(t *testing.T) {
 		},
 		{
 			name: "invalid concurrency",
-			base: JobBase{
+			base: job.Base{
 				Name:           "name",
 				MaxConcurrency: -1,
 				Agent:          ka,
@@ -972,75 +973,75 @@ presubmits:
 func TestBrancher_Intersects(t *testing.T) {
 	testCases := []struct {
 		name   string
-		a, b   Brancher
+		a, b   job.Brancher
 		result bool
 	}{
 		{
 			name: "TwodifferentBranches",
-			a: Brancher{
+			a: job.Brancher{
 				Branches: []string{"a"},
 			},
-			b: Brancher{
+			b: job.Brancher{
 				Branches: []string{"b"},
 			},
 		},
 		{
 			name: "Opposite",
-			a: Brancher{
+			a: job.Brancher{
 				SkipBranches: []string{"b"},
 			},
-			b: Brancher{
+			b: job.Brancher{
 				Branches: []string{"b"},
 			},
 		},
 		{
 			name:   "BothRunOnAllBranches",
-			a:      Brancher{},
-			b:      Brancher{},
+			a:      job.Brancher{},
+			b:      job.Brancher{},
 			result: true,
 		},
 		{
 			name: "RunsOnAllBranchesAndSpecified",
-			a:    Brancher{},
-			b: Brancher{
+			a:    job.Brancher{},
+			b: job.Brancher{
 				Branches: []string{"b"},
 			},
 			result: true,
 		},
 		{
 			name: "SkipBranchesAndSet",
-			a: Brancher{
+			a: job.Brancher{
 				SkipBranches: []string{"a", "b", "c"},
 			},
-			b: Brancher{
+			b: job.Brancher{
 				Branches: []string{"a"},
 			},
 		},
 		{
 			name: "SkipBranchesAndSet",
-			a: Brancher{
+			a: job.Brancher{
 				Branches: []string{"c"},
 			},
-			b: Brancher{
+			b: job.Brancher{
 				Branches: []string{"a"},
 			},
 		},
 		{
 			name: "BothSkipBranches",
-			a: Brancher{
+			a: job.Brancher{
 				SkipBranches: []string{"a", "b", "c"},
 			},
-			b: Brancher{
+			b: job.Brancher{
 				SkipBranches: []string{"d", "e", "f"},
 			},
 			result: true,
 		},
 		{
 			name: "BothSkipCommonBranches",
-			a: Brancher{
+			a: job.Brancher{
 				SkipBranches: []string{"a", "b", "c"},
 			},
-			b: Brancher{
+			b: job.Brancher{
 				SkipBranches: []string{"b", "e", "f"},
 			},
 			result: true,
diff --git a/pkg/config/keeper_test.go b/pkg/config/keeper_test.go
index a1670d4a..255b4e0f 100644
--- a/pkg/config/keeper_test.go
+++ b/pkg/config/keeper_test.go
@@ -3,6 +3,7 @@ package config
 import (
 	"testing"
 
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/stretchr/testify/assert"
 )
 
@@ -10,7 +11,7 @@ func TestConfigGetKeeperContextPolicy(t *testing.T) {
 	cases := []struct {
 		name                 string
 		bpOrgs               map[string]Org
-		presubmits           []Presubmit
+		presubmits           []job.Presubmit
 		skipUnknownContexts  bool
 		fromBranchProtection bool
 
@@ -20,44 +21,44 @@ func TestConfigGetKeeperContextPolicy(t *testing.T) {
 	}{
 		{
 			name: "basic",
-			presubmits: []Presubmit{
+			presubmits: []job.Presubmit{
 				{
 					AlwaysRun: true,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "always-run",
 						SkipReport: false,
 					},
 				},
 				{
-					RegexpChangeMatcher: RegexpChangeMatcher{
+					RegexpChangeMatcher: job.RegexpChangeMatcher{
 						RunIfChanged: "foo",
 					},
 					AlwaysRun: false,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "run-if-changed",
 						SkipReport: false,
 					},
 				},
 				{
 					AlwaysRun: false,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "not-always",
 						SkipReport: false,
 					},
 				},
 				{
 					AlwaysRun: true,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "skip-report",
 						SkipReport: true,
 					},
-					Brancher: Brancher{
+					Brancher: job.Brancher{
 						SkipBranches: []string{"master"},
 					},
 				},
 				{
 					AlwaysRun: true,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "optional",
 						SkipReport: false,
 					},
@@ -70,44 +71,44 @@ func TestConfigGetKeeperContextPolicy(t *testing.T) {
 		},
 		{
 			name: "from branch protection",
-			presubmits: []Presubmit{
+			presubmits: []job.Presubmit{
 				{
 					AlwaysRun: true,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "always-run",
 						SkipReport: false,
 					},
 				},
 				{
-					RegexpChangeMatcher: RegexpChangeMatcher{
+					RegexpChangeMatcher: job.RegexpChangeMatcher{
 						RunIfChanged: "foo",
 					},
 					AlwaysRun: false,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "run-if-changed",
 						SkipReport: false,
 					},
 				},
 				{
 					AlwaysRun: false,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "not-always",
 						SkipReport: false,
 					},
 				},
 				{
 					AlwaysRun: true,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "skip-report",
 						SkipReport: true,
 					},
-					Brancher: Brancher{
+					Brancher: job.Brancher{
 						SkipBranches: []string{"master"},
 					},
 				},
 				{
 					AlwaysRun: true,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "optional",
 						SkipReport: false,
 					},
@@ -138,44 +139,44 @@ func TestConfigGetKeeperContextPolicy(t *testing.T) {
 		},
 		{
 			name: "from branch protection with unknown context",
-			presubmits: []Presubmit{
+			presubmits: []job.Presubmit{
 				{
 					AlwaysRun: true,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "always-run",
 						SkipReport: false,
 					},
 				},
 				{
-					RegexpChangeMatcher: RegexpChangeMatcher{
+					RegexpChangeMatcher: job.RegexpChangeMatcher{
 						RunIfChanged: "foo",
 					},
 					AlwaysRun: false,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "run-if-changed",
 						SkipReport: false,
 					},
 				},
 				{
 					AlwaysRun: false,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "not-always",
 						SkipReport: false,
 					},
 				},
 				{
 					AlwaysRun: true,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "skip-report",
 						SkipReport: true,
 					},
-					Brancher: Brancher{
+					Brancher: job.Brancher{
 						SkipBranches: []string{"master"},
 					},
 				},
 				{
 					AlwaysRun: true,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "optional",
 						SkipReport: false,
 					},
@@ -207,44 +208,44 @@ func TestConfigGetKeeperContextPolicy(t *testing.T) {
 		},
 		{
 			name: "from branch protection skipping unknown context",
-			presubmits: []Presubmit{
+			presubmits: []job.Presubmit{
 				{
 					AlwaysRun: true,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "always-run",
 						SkipReport: false,
 					},
 				},
 				{
-					RegexpChangeMatcher: RegexpChangeMatcher{
+					RegexpChangeMatcher: job.RegexpChangeMatcher{
 						RunIfChanged: "foo",
 					},
 					AlwaysRun: false,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "run-if-changed",
 						SkipReport: false,
 					},
 				},
 				{
 					AlwaysRun: false,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "not-always",
 						SkipReport: false,
 					},
 				},
 				{
 					AlwaysRun: true,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "skip-report",
 						SkipReport: true,
 					},
-					Brancher: Brancher{
+					Brancher: job.Brancher{
 						SkipBranches: []string{"master"},
 					},
 				},
 				{
 					AlwaysRun: true,
-					Reporter: Reporter{
+					Reporter: job.Reporter{
 						Context:    "optional",
 						SkipReport: false,
 					},
@@ -280,14 +281,14 @@ func TestConfigGetKeeperContextPolicy(t *testing.T) {
 	for _, tc := range cases {
 		t.Run(tc.name, func(t *testing.T) {
 
-			if err := SetPresubmitRegexes(tc.presubmits); err != nil {
+			if err := job.SetPresubmitRegexes(tc.presubmits); err != nil {
 				t.Fatalf("could not set regexes: %v", err)
 			}
-			presubmits := map[string][]Presubmit{
+			presubmits := map[string][]job.Presubmit{
 				"o/r": tc.presubmits,
 			}
 			cfg := Config{
-				JobConfig: JobConfig{
+				JobConfig: job.Config{
 					Presubmits: presubmits,
 				},
 				ProwConfig: ProwConfig{
diff --git a/pkg/foghorn/controller_test.go b/pkg/foghorn/controller_test.go
index a182a7d4..4ec895c8 100644
--- a/pkg/foghorn/controller_test.go
+++ b/pkg/foghorn/controller_test.go
@@ -10,6 +10,7 @@ import (
 	"github.com/google/go-cmp/cmp"
 	lighthousev1alpha1 "github.com/jenkins-x/lighthouse/pkg/apis/lighthouse/v1alpha1"
 	"github.com/jenkins-x/lighthouse/pkg/config"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/plugins"
 	"github.com/jenkins-x/lighthouse/pkg/util"
 	"github.com/jenkins-x/lighthouse/pkg/watcher"
@@ -41,7 +42,7 @@ func TestReconcile(t *testing.T) {
 	}()
 	configAgent := &config.Agent{}
 	configAgent.Set(&config.Config{
-		JobConfig: config.JobConfig{},
+		JobConfig: job.Config{},
 		ProwConfig: config.ProwConfig{
 			Keeper:                 config.Keeper{},
 			Plank:                  config.Plank{},
diff --git a/pkg/jobutil/filter_test.go b/pkg/jobutil/filter_test.go
index eceb3b52..905c10fa 100644
--- a/pkg/jobutil/filter_test.go
+++ b/pkg/jobutil/filter_test.go
@@ -27,49 +27,49 @@ import (
 
 	"github.com/sirupsen/logrus"
 
-	"github.com/jenkins-x/lighthouse/pkg/config"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"k8s.io/apimachinery/pkg/util/diff"
 )
 
 func TestTestAllFilter(t *testing.T) {
 	var testCases = []struct {
 		name       string
-		presubmits []config.Presubmit
+		presubmits []job.Presubmit
 		expected   [][]bool
 	}{
 		{
 			name: "test all filter matches jobs which do not require human triggering",
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "always-runs",
 					},
 					AlwaysRun: true,
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "runs-if-changed",
 					},
 					AlwaysRun: false,
-					RegexpChangeMatcher: config.RegexpChangeMatcher{
+					RegexpChangeMatcher: job.RegexpChangeMatcher{
 						RunIfChanged: "sometimes",
 					},
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "runs-if-triggered",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "runs-if-triggered",
 					},
 					Trigger:      `(?m)^/test (?:.*? )?trigger(?: .*?)?$`,
 					RerunCommand: "/test trigger",
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "literal-test-all-trigger",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "runs-if-triggered",
 					},
 					Trigger:      `(?m)^/test (?:.*? )?all(?: .*?)?$`,
@@ -85,7 +85,7 @@ func TestTestAllFilter(t *testing.T) {
 			if len(testCase.presubmits) != len(testCase.expected) {
 				t.Fatalf("%s: have %d presubmits but only %d expected filter outputs", testCase.name, len(testCase.presubmits), len(testCase.expected))
 			}
-			if err := config.SetPresubmitRegexes(testCase.presubmits); err != nil {
+			if err := job.SetPresubmitRegexes(testCase.presubmits); err != nil {
 				t.Fatalf("%s: could not set presubmit regexes: %v", testCase.name, err)
 			}
 			filter := TestAllFilter()
@@ -110,22 +110,22 @@ func TestCommandFilter(t *testing.T) {
 	var testCases = []struct {
 		name       string
 		body       string
-		presubmits []config.Presubmit
+		presubmits []job.Presubmit
 		expected   [][]bool
 	}{
 		{
 			name: "command filter matches jobs whose triggers match the body",
 			body: "/test trigger",
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "trigger",
 					},
 					Trigger:      `(?m)^/test (?:.*? )?trigger(?: .*?)?$`,
 					RerunCommand: "/test trigger",
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "other-trigger",
 					},
 					Trigger:      `(?m)^/test (?:.*? )?other-trigger(?: .*?)?$`,
@@ -141,7 +141,7 @@ func TestCommandFilter(t *testing.T) {
 			if len(testCase.presubmits) != len(testCase.expected) {
 				t.Fatalf("%s: have %d presubmits but only %d expected filter outputs", testCase.name, len(testCase.presubmits), len(testCase.expected))
 			}
-			if err := config.SetPresubmitRegexes(testCase.presubmits); err != nil {
+			if err := job.SetPresubmitRegexes(testCase.presubmits); err != nil {
 				t.Fatalf("%s: could not set presubmit regexes: %v", testCase.name, err)
 			}
 			filter := CommandFilter(testCase.body)
@@ -162,7 +162,7 @@ func TestCommandFilter(t *testing.T) {
 	}
 }
 
-func fakeChangedFilesProvider(shouldError bool) config.ChangedFilesProvider {
+func fakeChangedFilesProvider(shouldError bool) job.ChangedFilesProvider {
 	return func() ([]string, error) {
 		if shouldError {
 			return nil, errors.New("error getting changes")
@@ -175,22 +175,22 @@ func TestFilterPresubmits(t *testing.T) {
 	var testCases = []struct {
 		name                              string
 		filter                            Filter
-		presubmits                        []config.Presubmit
+		presubmits                        []job.Presubmit
 		changesError                      bool
-		expectedToTrigger, expectedToSkip []config.Presubmit
+		expectedToTrigger, expectedToSkip []job.Presubmit
 		expectErr                         bool
 	}{
 		{
 			name: "nothing matches, nothing to run or skip",
-			filter: func(p config.Presubmit) (shouldRun bool, forcedToRun bool, defaultBehavior bool) {
+			filter: func(p job.Presubmit) (shouldRun bool, forcedToRun bool, defaultBehavior bool) {
 				return false, false, false
 			},
-			presubmits: []config.Presubmit{{
-				JobBase:  config.JobBase{Name: "ignored"},
-				Reporter: config.Reporter{Context: "first"},
+			presubmits: []job.Presubmit{{
+				Base:     job.Base{Name: "ignored"},
+				Reporter: job.Reporter{Context: "first"},
 			}, {
-				JobBase:  config.JobBase{Name: "ignored"},
-				Reporter: config.Reporter{Context: "second"},
+				Base:     job.Base{Name: "ignored"},
+				Reporter: job.Reporter{Context: "second"},
 			}},
 			changesError:      false,
 			expectedToTrigger: nil,
@@ -199,39 +199,39 @@ func TestFilterPresubmits(t *testing.T) {
 		},
 		{
 			name: "everything matches and is forced to run, nothing to skip",
-			filter: func(p config.Presubmit) (shouldRun bool, forcedToRun bool, defaultBehavior bool) {
+			filter: func(p job.Presubmit) (shouldRun bool, forcedToRun bool, defaultBehavior bool) {
 				return true, true, true
 			},
-			presubmits: []config.Presubmit{{
-				JobBase:  config.JobBase{Name: "should-trigger"},
-				Reporter: config.Reporter{Context: "first"},
+			presubmits: []job.Presubmit{{
+				Base:     job.Base{Name: "should-trigger"},
+				Reporter: job.Reporter{Context: "first"},
 			}, {
-				JobBase:  config.JobBase{Name: "should-trigger"},
-				Reporter: config.Reporter{Context: "second"},
+				Base:     job.Base{Name: "should-trigger"},
+				Reporter: job.Reporter{Context: "second"},
 			}},
 			changesError: false,
-			expectedToTrigger: []config.Presubmit{{
-				JobBase:  config.JobBase{Name: "should-trigger"},
-				Reporter: config.Reporter{Context: "first"},
+			expectedToTrigger: []job.Presubmit{{
+				Base:     job.Base{Name: "should-trigger"},
+				Reporter: job.Reporter{Context: "first"},
 			}, {
-				JobBase:  config.JobBase{Name: "should-trigger"},
-				Reporter: config.Reporter{Context: "second"},
+				Base:     job.Base{Name: "should-trigger"},
+				Reporter: job.Reporter{Context: "second"},
 			}},
 			expectedToSkip: nil,
 			expectErr:      false,
 		},
 		{
 			name: "error detecting if something should run, nothing to run or skip",
-			filter: func(p config.Presubmit) (shouldRun bool, forcedToRun bool, defaultBehavior bool) {
+			filter: func(p job.Presubmit) (shouldRun bool, forcedToRun bool, defaultBehavior bool) {
 				return true, false, false
 			},
-			presubmits: []config.Presubmit{{
-				JobBase:             config.JobBase{Name: "errors"},
-				Reporter:            config.Reporter{Context: "first"},
-				RegexpChangeMatcher: config.RegexpChangeMatcher{RunIfChanged: "oopsie"},
+			presubmits: []job.Presubmit{{
+				Base:                job.Base{Name: "errors"},
+				Reporter:            job.Reporter{Context: "first"},
+				RegexpChangeMatcher: job.RegexpChangeMatcher{RunIfChanged: "oopsie"},
 			}, {
-				JobBase:  config.JobBase{Name: "ignored"},
-				Reporter: config.Reporter{Context: "second"},
+				Base:     job.Base{Name: "ignored"},
+				Reporter: job.Reporter{Context: "second"},
 			}},
 			changesError:      true,
 			expectedToTrigger: nil,
@@ -240,88 +240,88 @@ func TestFilterPresubmits(t *testing.T) {
 		},
 		{
 			name: "some things match and are forced to run, nothing to skip",
-			filter: func(p config.Presubmit) (shouldRun bool, forcedToRun bool, defaultBehavior bool) {
+			filter: func(p job.Presubmit) (shouldRun bool, forcedToRun bool, defaultBehavior bool) {
 				return p.Name == "should-trigger", true, true
 			},
-			presubmits: []config.Presubmit{{
-				JobBase:  config.JobBase{Name: "should-trigger"},
-				Reporter: config.Reporter{Context: "first"},
+			presubmits: []job.Presubmit{{
+				Base:     job.Base{Name: "should-trigger"},
+				Reporter: job.Reporter{Context: "first"},
 			}, {
-				JobBase:  config.JobBase{Name: "ignored"},
-				Reporter: config.Reporter{Context: "second"},
+				Base:     job.Base{Name: "ignored"},
+				Reporter: job.Reporter{Context: "second"},
 			}},
 			changesError: false,
-			expectedToTrigger: []config.Presubmit{{
-				JobBase:  config.JobBase{Name: "should-trigger"},
-				Reporter: config.Reporter{Context: "first"},
+			expectedToTrigger: []job.Presubmit{{
+				Base:     job.Base{Name: "should-trigger"},
+				Reporter: job.Reporter{Context: "first"},
 			}},
 			expectedToSkip: nil,
 			expectErr:      false,
 		},
 		{
 			name: "everything matches and some things are forced to run, others should be skipped",
-			filter: func(p config.Presubmit) (shouldRun bool, forcedToRun bool, defaultBehavior bool) {
+			filter: func(p job.Presubmit) (shouldRun bool, forcedToRun bool, defaultBehavior bool) {
 				return true, p.Name == "should-trigger", p.Name == "should-trigger"
 			},
-			presubmits: []config.Presubmit{{
-				JobBase:  config.JobBase{Name: "should-trigger"},
-				Reporter: config.Reporter{Context: "first"},
+			presubmits: []job.Presubmit{{
+				Base:     job.Base{Name: "should-trigger"},
+				Reporter: job.Reporter{Context: "first"},
 			}, {
-				JobBase:  config.JobBase{Name: "should-trigger"},
-				Reporter: config.Reporter{Context: "second"},
+				Base:     job.Base{Name: "should-trigger"},
+				Reporter: job.Reporter{Context: "second"},
 			}, {
-				JobBase:  config.JobBase{Name: "should-skip"},
-				Reporter: config.Reporter{Context: "third"},
+				Base:     job.Base{Name: "should-skip"},
+				Reporter: job.Reporter{Context: "third"},
 			}, {
-				JobBase:  config.JobBase{Name: "should-skip2"},
-				Reporter: config.Reporter{Context: "fourth"},
+				Base:     job.Base{Name: "should-skip2"},
+				Reporter: job.Reporter{Context: "fourth"},
 			}},
 			changesError: false,
-			expectedToTrigger: []config.Presubmit{{
-				JobBase:  config.JobBase{Name: "should-trigger"},
-				Reporter: config.Reporter{Context: "first"},
+			expectedToTrigger: []job.Presubmit{{
+				Base:     job.Base{Name: "should-trigger"},
+				Reporter: job.Reporter{Context: "first"},
 			}, {
-				JobBase:  config.JobBase{Name: "should-trigger"},
-				Reporter: config.Reporter{Context: "second"},
+				Base:     job.Base{Name: "should-trigger"},
+				Reporter: job.Reporter{Context: "second"},
 			}},
-			expectedToSkip: []config.Presubmit{{
-				JobBase:  config.JobBase{Name: "should-skip"},
-				Reporter: config.Reporter{Context: "third"},
+			expectedToSkip: []job.Presubmit{{
+				Base:     job.Base{Name: "should-skip"},
+				Reporter: job.Reporter{Context: "third"},
 			}, {
-				JobBase:  config.JobBase{Name: "should-skip2"},
-				Reporter: config.Reporter{Context: "fourth"},
+				Base:     job.Base{Name: "should-skip2"},
+				Reporter: job.Reporter{Context: "fourth"},
 			}},
 			expectErr: false,
 		},
 		{
 			name: "everything matches and some that are forces to run supercede some that are skipped due to shared contexts",
-			filter: func(p config.Presubmit) (shouldRun bool, forcedToRun bool, defaultBehavior bool) {
+			filter: func(p job.Presubmit) (shouldRun bool, forcedToRun bool, defaultBehavior bool) {
 				return true, p.Name == "should-trigger", p.Name == "should-trigger"
 			},
-			presubmits: []config.Presubmit{{
-				JobBase:  config.JobBase{Name: "should-trigger"},
-				Reporter: config.Reporter{Context: "first"},
+			presubmits: []job.Presubmit{{
+				Base:     job.Base{Name: "should-trigger"},
+				Reporter: job.Reporter{Context: "first"},
 			}, {
-				JobBase:  config.JobBase{Name: "should-trigger"},
-				Reporter: config.Reporter{Context: "second"},
+				Base:     job.Base{Name: "should-trigger"},
+				Reporter: job.Reporter{Context: "second"},
 			}, {
-				JobBase:  config.JobBase{Name: "should-skip"},
-				Reporter: config.Reporter{Context: "third"},
+				Base:     job.Base{Name: "should-skip"},
+				Reporter: job.Reporter{Context: "third"},
 			}, {
-				JobBase:  config.JobBase{Name: "should-not-skip"},
-				Reporter: config.Reporter{Context: "second"},
+				Base:     job.Base{Name: "should-not-skip"},
+				Reporter: job.Reporter{Context: "second"},
 			}},
 			changesError: false,
-			expectedToTrigger: []config.Presubmit{{
-				JobBase:  config.JobBase{Name: "should-trigger"},
-				Reporter: config.Reporter{Context: "first"},
+			expectedToTrigger: []job.Presubmit{{
+				Base:     job.Base{Name: "should-trigger"},
+				Reporter: job.Reporter{Context: "first"},
 			}, {
-				JobBase:  config.JobBase{Name: "should-trigger"},
-				Reporter: config.Reporter{Context: "second"},
+				Base:     job.Base{Name: "should-trigger"},
+				Reporter: job.Reporter{Context: "second"},
 			}},
-			expectedToSkip: []config.Presubmit{{
-				JobBase:  config.JobBase{Name: "should-skip"},
-				Reporter: config.Reporter{Context: "third"},
+			expectedToSkip: []job.Presubmit{{
+				Base:     job.Base{Name: "should-skip"},
+				Reporter: job.Reporter{Context: "third"},
 			}},
 			expectErr: false,
 		},
@@ -351,37 +351,37 @@ func TestFilterPresubmits(t *testing.T) {
 func TestDetermineSkippedPresubmits(t *testing.T) {
 	var testCases = []struct {
 		name                      string
-		toTrigger, toSkipSuperset []config.Presubmit
-		expectedToSkip            []config.Presubmit
+		toTrigger, toSkipSuperset []job.Presubmit
+		expectedToSkip            []job.Presubmit
 	}{
 		{
 			name:           "no inputs leads to no output",
-			toTrigger:      []config.Presubmit{},
-			toSkipSuperset: []config.Presubmit{},
+			toTrigger:      []job.Presubmit{},
+			toSkipSuperset: []job.Presubmit{},
 			expectedToSkip: nil,
 		},
 		{
 			name:           "no superset of skips to choose from leads to no output",
-			toTrigger:      []config.Presubmit{{Reporter: config.Reporter{Context: "foo"}}},
-			toSkipSuperset: []config.Presubmit{},
+			toTrigger:      []job.Presubmit{{Reporter: job.Reporter{Context: "foo"}}},
+			toSkipSuperset: []job.Presubmit{},
 			expectedToSkip: nil,
 		},
 		{
 			name:           "disjoint sets of contexts leads to full skip set",
-			toTrigger:      []config.Presubmit{{Reporter: config.Reporter{Context: "foo"}}, {Reporter: config.Reporter{Context: "bar"}}},
-			toSkipSuperset: []config.Presubmit{{Reporter: config.Reporter{Context: "oof"}}, {Reporter: config.Reporter{Context: "rab"}}},
-			expectedToSkip: []config.Presubmit{{Reporter: config.Reporter{Context: "oof"}}, {Reporter: config.Reporter{Context: "rab"}}},
+			toTrigger:      []job.Presubmit{{Reporter: job.Reporter{Context: "foo"}}, {Reporter: job.Reporter{Context: "bar"}}},
+			toSkipSuperset: []job.Presubmit{{Reporter: job.Reporter{Context: "oof"}}, {Reporter: job.Reporter{Context: "rab"}}},
+			expectedToSkip: []job.Presubmit{{Reporter: job.Reporter{Context: "oof"}}, {Reporter: job.Reporter{Context: "rab"}}},
 		},
 		{
 			name:           "overlaps on context removes from skip set",
-			toTrigger:      []config.Presubmit{{Reporter: config.Reporter{Context: "foo"}}, {Reporter: config.Reporter{Context: "bar"}}},
-			toSkipSuperset: []config.Presubmit{{Reporter: config.Reporter{Context: "foo"}}, {Reporter: config.Reporter{Context: "rab"}}},
-			expectedToSkip: []config.Presubmit{{Reporter: config.Reporter{Context: "rab"}}},
+			toTrigger:      []job.Presubmit{{Reporter: job.Reporter{Context: "foo"}}, {Reporter: job.Reporter{Context: "bar"}}},
+			toSkipSuperset: []job.Presubmit{{Reporter: job.Reporter{Context: "foo"}}, {Reporter: job.Reporter{Context: "rab"}}},
+			expectedToSkip: []job.Presubmit{{Reporter: job.Reporter{Context: "rab"}}},
 		},
 		{
 			name:           "full set of overlaps on context removes everything from skip set",
-			toTrigger:      []config.Presubmit{{Reporter: config.Reporter{Context: "foo"}}, {Reporter: config.Reporter{Context: "bar"}}},
-			toSkipSuperset: []config.Presubmit{{Reporter: config.Reporter{Context: "foo"}}, {Reporter: config.Reporter{Context: "bar"}}},
+			toTrigger:      []job.Presubmit{{Reporter: job.Reporter{Context: "foo"}}, {Reporter: job.Reporter{Context: "bar"}}},
+			toSkipSuperset: []job.Presubmit{{Reporter: job.Reporter{Context: "foo"}}, {Reporter: job.Reporter{Context: "bar"}}},
 			expectedToSkip: nil,
 		},
 	}
@@ -445,7 +445,7 @@ func TestPresubmitFilter(t *testing.T) {
 		name                 string
 		honorOkToTest        bool
 		body, org, repo, ref string
-		presubmits           []config.Presubmit
+		presubmits           []job.Presubmit
 		expected             [][]bool
 		statusErr, expectErr bool
 	}{
@@ -455,32 +455,32 @@ func TestPresubmitFilter(t *testing.T) {
 			org:  "org",
 			repo: "repo",
 			ref:  "ref",
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "always-runs",
 					},
 					AlwaysRun: true,
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "always-runs",
 					},
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "runs-if-changed",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "runs-if-changed",
 					},
-					RegexpChangeMatcher: config.RegexpChangeMatcher{
+					RegexpChangeMatcher: job.RegexpChangeMatcher{
 						RunIfChanged: "sometimes",
 					},
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "runs-if-triggered",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "runs-if-triggered",
 					},
 					Trigger:      `(?m)^/test (?:.*? )?trigger(?: .*?)?$`,
@@ -496,32 +496,32 @@ func TestPresubmitFilter(t *testing.T) {
 			org:           "org",
 			repo:          "repo",
 			ref:           "ref",
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "always-runs",
 					},
 					AlwaysRun: true,
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "always-runs",
 					},
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "runs-if-changed",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "runs-if-changed",
 					},
-					RegexpChangeMatcher: config.RegexpChangeMatcher{
+					RegexpChangeMatcher: job.RegexpChangeMatcher{
 						RunIfChanged: "sometimes",
 					},
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "runs-if-triggered",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "runs-if-triggered",
 					},
 					Trigger:      `(?m)^/test (?:.*? )?trigger(?: .*?)?$`,
@@ -537,32 +537,32 @@ func TestPresubmitFilter(t *testing.T) {
 			org:           "org",
 			repo:          "repo",
 			ref:           "ref",
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "always-runs",
 					},
 					AlwaysRun: true,
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "always-runs",
 					},
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "runs-if-changed",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "runs-if-changed",
 					},
-					RegexpChangeMatcher: config.RegexpChangeMatcher{
+					RegexpChangeMatcher: job.RegexpChangeMatcher{
 						RunIfChanged: "sometimes",
 					},
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "runs-if-triggered",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "runs-if-triggered",
 					},
 					Trigger:      `(?m)^/test (?:.*? )?trigger(?: .*?)?$`,
@@ -577,7 +577,7 @@ func TestPresubmitFilter(t *testing.T) {
 			org:        "org",
 			repo:       "repo",
 			ref:        "ref",
-			presubmits: []config.Presubmit{},
+			presubmits: []job.Presubmit{},
 			expected:   [][]bool{},
 			statusErr:  true,
 			expectErr:  false,
@@ -588,7 +588,7 @@ func TestPresubmitFilter(t *testing.T) {
 			org:        "org",
 			repo:       "repo",
 			ref:        "ref",
-			presubmits: []config.Presubmit{},
+			presubmits: []job.Presubmit{},
 			expected:   [][]bool{},
 			statusErr:  true,
 			expectErr:  true,
@@ -599,44 +599,44 @@ func TestPresubmitFilter(t *testing.T) {
 			org:  "org",
 			repo: "repo",
 			ref:  "ref",
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "successful-job",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "existing-successful",
 					},
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "pending-job",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "existing-pending",
 					},
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "failure-job",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "existing-failure",
 					},
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "error-job",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "existing-error",
 					},
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "missing-always-runs",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "missing-always-runs",
 					},
 					AlwaysRun: true,
@@ -650,70 +650,70 @@ func TestPresubmitFilter(t *testing.T) {
 			org:  "org",
 			repo: "repo",
 			ref:  "ref",
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "always-runs",
 					},
 					AlwaysRun: true,
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "always-runs",
 					},
 					Trigger:      `(?m)^/test (?:.*? )?trigger(?: .*?)?$`,
 					RerunCommand: "/test trigger",
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "runs-if-changed",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "runs-if-changed",
 					},
-					RegexpChangeMatcher: config.RegexpChangeMatcher{
+					RegexpChangeMatcher: job.RegexpChangeMatcher{
 						RunIfChanged: "sometimes",
 					},
 					Trigger:      `(?m)^/test (?:.*? )?trigger(?: .*?)?$`,
 					RerunCommand: "/test trigger",
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "runs-if-triggered",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "runs-if-triggered",
 					},
 					Trigger:      `(?m)^/test (?:.*? )?trigger(?: .*?)?$`,
 					RerunCommand: "/test trigger",
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "always-runs",
 					},
 					AlwaysRun: true,
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "always-runs",
 					},
 					Trigger:      `(?m)^/test (?:.*? )?other-trigger(?: .*?)?$`,
 					RerunCommand: "/test other-trigger",
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "runs-if-changed",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "runs-if-changed",
 					},
-					RegexpChangeMatcher: config.RegexpChangeMatcher{
+					RegexpChangeMatcher: job.RegexpChangeMatcher{
 						RunIfChanged: "sometimes",
 					},
 					Trigger:      `(?m)^/test (?:.*? )?other-trigger(?: .*?)?$`,
 					RerunCommand: "/test other-trigger",
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "runs-if-triggered",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "runs-if-triggered",
 					},
 					Trigger:      `(?m)^/test (?:.*? )?other-trigger(?: .*?)?$`,
@@ -730,79 +730,79 @@ func TestPresubmitFilter(t *testing.T) {
 			org:  "org",
 			repo: "repo",
 			ref:  "ref",
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "always-runs",
 					},
 					AlwaysRun: true,
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "existing-successful",
 					},
 					Trigger:      `(?m)^/test (?:.*? )?other-trigger(?: .*?)?$`,
 					RerunCommand: "/test other-trigger",
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "runs-if-changed",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "existing-successful",
 					},
-					RegexpChangeMatcher: config.RegexpChangeMatcher{
+					RegexpChangeMatcher: job.RegexpChangeMatcher{
 						RunIfChanged: "sometimes",
 					},
 					Trigger:      `(?m)^/test (?:.*? )?other-trigger(?: .*?)?$`,
 					RerunCommand: "/test other-trigger",
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "runs-if-triggered",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "runs-if-triggered",
 					},
 					Trigger:      `(?m)^/test (?:.*? )?trigger(?: .*?)?$`,
 					RerunCommand: "/test trigger",
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "successful-job",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "existing-successful",
 					},
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "pending-job",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "existing-pending",
 					},
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "failure-job",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "existing-failure",
 					},
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "error-job",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "existing-error",
 					},
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "missing-always-runs",
 					},
 					AlwaysRun: true,
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "missing-always-runs",
 					},
 				},
@@ -816,7 +816,7 @@ func TestPresubmitFilter(t *testing.T) {
 			if len(testCase.presubmits) != len(testCase.expected) {
 				t.Fatalf("%s: have %d presubmits but only %d expected filter outputs", testCase.name, len(testCase.presubmits), len(testCase.expected))
 			}
-			if err := config.SetPresubmitRegexes(testCase.presubmits); err != nil {
+			if err := job.SetPresubmitRegexes(testCase.presubmits); err != nil {
 				t.Fatalf("%s: could not set presubmit regexes: %v", testCase.name, err)
 			}
 			fsg := &fakeContextGetter{
diff --git a/pkg/jobutil/jobutil_test.go b/pkg/jobutil/jobutil_test.go
index b8f75a8c..7bf40343 100644
--- a/pkg/jobutil/jobutil_test.go
+++ b/pkg/jobutil/jobutil_test.go
@@ -22,6 +22,7 @@ import (
 
 	"github.com/jenkins-x/go-scm/scm"
 	"github.com/jenkins-x/lighthouse/pkg/apis/lighthouse/v1alpha1"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/util"
 	"k8s.io/apimachinery/pkg/api/equality"
 	"k8s.io/apimachinery/pkg/util/diff"
@@ -32,15 +33,15 @@ import (
 func TestPostsubmitSpec(t *testing.T) {
 	tests := []struct {
 		name     string
-		p        config.Postsubmit
+		p        job.Postsubmit
 		refs     v1alpha1.Refs
 		expected v1alpha1.LighthouseJobSpec
 	}{
 		{
 			name: "can override path alias and cloneuri",
-			p: config.Postsubmit{
-				JobBase: config.JobBase{
-					UtilityConfig: config.UtilityConfig{
+			p: job.Postsubmit{
+				Base: job.Base{
+					UtilityConfig: job.UtilityConfig{
 						PathAlias: "foo",
 						CloneURI:  "bar",
 					},
@@ -70,9 +71,9 @@ func TestPostsubmitSpec(t *testing.T) {
 		},
 		{
 			name: "job overrides take precedence over controller defaults",
-			p: config.Postsubmit{
-				JobBase: config.JobBase{
-					UtilityConfig: config.UtilityConfig{
+			p: job.Postsubmit{
+				Base: job.Base{
+					UtilityConfig: job.UtilityConfig{
 						PathAlias: "foo",
 						CloneURI:  "bar",
 					},
@@ -103,15 +104,15 @@ func TestPostsubmitSpec(t *testing.T) {
 func TestPresubmitSpec(t *testing.T) {
 	tests := []struct {
 		name     string
-		p        config.Presubmit
+		p        job.Presubmit
 		refs     v1alpha1.Refs
 		expected v1alpha1.LighthouseJobSpec
 	}{
 		{
 			name: "can override path alias and cloneuri",
-			p: config.Presubmit{
-				JobBase: config.JobBase{
-					UtilityConfig: config.UtilityConfig{
+			p: job.Presubmit{
+				Base: job.Base{
+					UtilityConfig: job.UtilityConfig{
 						PathAlias: "foo",
 						CloneURI:  "bar",
 					},
@@ -141,9 +142,9 @@ func TestPresubmitSpec(t *testing.T) {
 		},
 		{
 			name: "job overrides take precedence over controller defaults",
-			p: config.Presubmit{
-				JobBase: config.JobBase{
-					UtilityConfig: config.UtilityConfig{
+			p: job.Presubmit{
+				Base: job.Base{
+					UtilityConfig: job.UtilityConfig{
 						PathAlias: "foo",
 						CloneURI:  "bar",
 					},
@@ -174,15 +175,15 @@ func TestPresubmitSpec(t *testing.T) {
 func TestBatchSpec(t *testing.T) {
 	tests := []struct {
 		name     string
-		p        config.Presubmit
+		p        job.Presubmit
 		refs     v1alpha1.Refs
 		expected v1alpha1.LighthouseJobSpec
 	}{
 		{
 			name: "can override path alias and cloneuri",
-			p: config.Presubmit{
-				JobBase: config.JobBase{
-					UtilityConfig: config.UtilityConfig{
+			p: job.Presubmit{
+				Base: job.Base{
+					UtilityConfig: job.UtilityConfig{
 						PathAlias: "foo",
 						CloneURI:  "bar",
 					},
@@ -212,9 +213,9 @@ func TestBatchSpec(t *testing.T) {
 		},
 		{
 			name: "job overrides take precedence over controller defaults",
-			p: config.Presubmit{
-				JobBase: config.JobBase{
-					UtilityConfig: config.UtilityConfig{
+			p: job.Presubmit{
+				Base: job.Base{
+					UtilityConfig: job.UtilityConfig{
 						PathAlias: "foo",
 						CloneURI:  "bar",
 					},
@@ -520,12 +521,12 @@ func TestCreateRefs(t *testing.T) {
 func TestSpecFromJobBase(t *testing.T) {
 	testCases := []struct {
 		name    string
-		jobBase config.JobBase
+		jobBase job.Base
 		verify  func(v1alpha1.LighthouseJobSpec) error
 	}{
 		{
 			name:    "Verify reporter config gets copied",
-			jobBase: config.JobBase{
+			jobBase: job.Base{
 				/*				ReporterConfig: &v1alpha1.ReporterConfig{
 									Slack: &v1alpha1.SlackReporterConfig{
 										Channel: "my-channel",
diff --git a/pkg/keeper/keeper_test.go b/pkg/keeper/keeper_test.go
index cf753cfb..489a1f08 100644
--- a/pkg/keeper/keeper_test.go
+++ b/pkg/keeper/keeper_test.go
@@ -32,6 +32,7 @@ import (
 	"github.com/jenkins-x/go-scm/scm"
 	"github.com/jenkins-x/lighthouse/pkg/apis/lighthouse/v1alpha1"
 	"github.com/jenkins-x/lighthouse/pkg/client/clientset/versioned/fake"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/scmprovider"
 	githubql "github.com/shurcooL/githubv4"
 	"github.com/sirupsen/logrus"
@@ -67,15 +68,15 @@ func testPullsMatchList(t *testing.T, test string, actual []PullRequest, expecte
 }
 
 func TestAccumulateBatch(t *testing.T) {
-	jobSet := []config.Presubmit{
+	jobSet := []job.Presubmit{
 		{
-			Reporter: config.Reporter{Context: "foo"},
+			Reporter: job.Reporter{Context: "foo"},
 		},
 		{
-			Reporter: config.Reporter{Context: "bar"},
+			Reporter: job.Reporter{Context: "bar"},
 		},
 		{
-			Reporter: config.Reporter{Context: "baz"},
+			Reporter: job.Reporter{Context: "baz"},
 		},
 	}
 	type pull struct {
@@ -89,7 +90,7 @@ func TestAccumulateBatch(t *testing.T) {
 	}
 	tests := []struct {
 		name       string
-		presubmits map[int][]config.Presubmit
+		presubmits map[int][]job.Presubmit
 		pulls      []pull
 		activities []activity
 
@@ -101,9 +102,9 @@ func TestAccumulateBatch(t *testing.T) {
 		},
 		{
 			name: "batch pending",
-			presubmits: map[int][]config.Presubmit{
-				1: {{Reporter: config.Reporter{Context: "foo"}}},
-				2: {{Reporter: config.Reporter{Context: "foo"}}},
+			presubmits: map[int][]job.Presubmit{
+				1: {{Reporter: job.Reporter{Context: "foo"}}},
+				2: {{Reporter: job.Reporter{Context: "foo"}}},
 			},
 			pulls:      []pull{{1, "a"}, {2, "b"}},
 			activities: []activity{{job: "foo", state: v1alpha1.PendingState, prs: []pull{{1, "a"}}}},
@@ -111,13 +112,13 @@ func TestAccumulateBatch(t *testing.T) {
 		},
 		{
 			name:       "pending batch missing presubmits is ignored",
-			presubmits: map[int][]config.Presubmit{1: jobSet},
+			presubmits: map[int][]job.Presubmit{1: jobSet},
 			pulls:      []pull{{1, "a"}, {2, "b"}},
 			activities: []activity{{job: "foo", state: v1alpha1.PendingState, prs: []pull{{1, "a"}}}},
 		},
 		{
 			name:       "batch pending, successful previous run",
-			presubmits: map[int][]config.Presubmit{1: jobSet, 2: jobSet},
+			presubmits: map[int][]job.Presubmit{1: jobSet, 2: jobSet},
 			pulls:      []pull{{1, "a"}, {2, "b"}},
 			activities: []activity{
 				{job: "foo", state: v1alpha1.PendingState, prs: []pull{{1, "a"}}},
@@ -132,7 +133,7 @@ func TestAccumulateBatch(t *testing.T) {
 		},
 		{
 			name:       "successful run",
-			presubmits: map[int][]config.Presubmit{1: jobSet, 2: jobSet},
+			presubmits: map[int][]job.Presubmit{1: jobSet, 2: jobSet},
 			pulls:      []pull{{1, "a"}, {2, "b"}},
 			activities: []activity{
 				{job: "foo", state: v1alpha1.SuccessState, prs: []pull{{2, "b"}}},
@@ -143,7 +144,7 @@ func TestAccumulateBatch(t *testing.T) {
 		},
 		{
 			name:       "successful run, multiple PRs",
-			presubmits: map[int][]config.Presubmit{1: jobSet, 2: jobSet},
+			presubmits: map[int][]job.Presubmit{1: jobSet, 2: jobSet},
 			pulls:      []pull{{1, "a"}, {2, "b"}},
 			activities: []activity{
 				{job: "foo", state: v1alpha1.SuccessState, prs: []pull{{1, "a"}, {2, "b"}}},
@@ -154,7 +155,7 @@ func TestAccumulateBatch(t *testing.T) {
 		},
 		{
 			name:       "successful run, failures in past",
-			presubmits: map[int][]config.Presubmit{1: jobSet, 2: jobSet},
+			presubmits: map[int][]job.Presubmit{1: jobSet, 2: jobSet},
 			pulls:      []pull{{1, "a"}, {2, "b"}},
 			activities: []activity{
 				{job: "foo", state: v1alpha1.SuccessState, prs: []pull{{1, "a"}, {2, "b"}}},
@@ -168,7 +169,7 @@ func TestAccumulateBatch(t *testing.T) {
 		},
 		{
 			name:       "failures",
-			presubmits: map[int][]config.Presubmit{1: jobSet, 2: jobSet},
+			presubmits: map[int][]job.Presubmit{1: jobSet, 2: jobSet},
 			pulls:      []pull{{1, "a"}, {2, "b"}},
 			activities: []activity{
 				{job: "foo", state: v1alpha1.FailureState, prs: []pull{{1, "a"}, {2, "b"}}},
@@ -179,7 +180,7 @@ func TestAccumulateBatch(t *testing.T) {
 		},
 		{
 			name:       "missing job required by one PR",
-			presubmits: map[int][]config.Presubmit{1: jobSet, 2: append(jobSet, config.Presubmit{Reporter: config.Reporter{Context: "boo"}})},
+			presubmits: map[int][]job.Presubmit{1: jobSet, 2: append(jobSet, job.Presubmit{Reporter: job.Reporter{Context: "boo"}})},
 			pulls:      []pull{{1, "a"}, {2, "b"}},
 			activities: []activity{
 				{job: "foo", state: v1alpha1.SuccessState, prs: []pull{{1, "a"}, {2, "b"}}},
@@ -189,7 +190,7 @@ func TestAccumulateBatch(t *testing.T) {
 		},
 		{
 			name:       "successful run with PR that requires additional job",
-			presubmits: map[int][]config.Presubmit{1: jobSet, 2: append(jobSet, config.Presubmit{Reporter: config.Reporter{Context: "boo"}})},
+			presubmits: map[int][]job.Presubmit{1: jobSet, 2: append(jobSet, job.Presubmit{Reporter: job.Reporter{Context: "boo"}})},
 			pulls:      []pull{{1, "a"}, {2, "b"}},
 			activities: []activity{
 				{job: "foo", state: v1alpha1.SuccessState, prs: []pull{{1, "a"}, {2, "b"}}},
@@ -206,7 +207,7 @@ func TestAccumulateBatch(t *testing.T) {
 		},
 		{
 			name:       "pending batch with PR that left pool, successful previous run",
-			presubmits: map[int][]config.Presubmit{2: jobSet},
+			presubmits: map[int][]job.Presubmit{2: jobSet},
 			pulls:      []pull{{2, "b"}},
 			activities: []activity{
 				{job: "foo", state: v1alpha1.PendingState, prs: []pull{{1, "a"}}},
@@ -257,14 +258,14 @@ func TestAccumulateBatch(t *testing.T) {
 }
 
 func TestAccumulate(t *testing.T) {
-	jobSet := []config.Presubmit{
+	jobSet := []job.Presubmit{
 		{
-			Reporter: config.Reporter{
+			Reporter: job.Reporter{
 				Context: "job1",
 			},
 		},
 		{
-			Reporter: config.Reporter{
+			Reporter: job.Reporter{
 				Context: "job2",
 			},
 		},
@@ -277,7 +278,7 @@ func TestAccumulate(t *testing.T) {
 	}
 	tests := []struct {
 		name         string
-		presubmits   map[int][]config.Presubmit
+		presubmits   map[int][]job.Presubmit
 		pullRequests map[int]string
 		activities   []activity
 
@@ -288,7 +289,7 @@ func TestAccumulate(t *testing.T) {
 		{
 			name:         "seven PRs, two jobs, with an overridden context and an unrelated success context",
 			pullRequests: map[int]string{1: "sha1", 2: "sha2", 3: "sha3", 4: "sha4", 5: "sha5", 6: "sha6", 7: "sha7"},
-			presubmits: map[int][]config.Presubmit{
+			presubmits: map[int][]job.Presubmit{
 				1: jobSet,
 				2: jobSet,
 				3: jobSet,
@@ -321,12 +322,12 @@ func TestAccumulate(t *testing.T) {
 		{
 			name:         "one PR, four jobs, mix of failures and success",
 			pullRequests: map[int]string{7: ""},
-			presubmits: map[int][]config.Presubmit{
+			presubmits: map[int][]job.Presubmit{
 				7: {
-					{Reporter: config.Reporter{Context: "job1"}},
-					{Reporter: config.Reporter{Context: "job2"}},
-					{Reporter: config.Reporter{Context: "job3"}},
-					{Reporter: config.Reporter{Context: "job4"}},
+					{Reporter: job.Reporter{Context: "job1"}},
+					{Reporter: job.Reporter{Context: "job2"}},
+					{Reporter: job.Reporter{Context: "job3"}},
+					{Reporter: job.Reporter{Context: "job4"}},
 				},
 			},
 			activities: []activity{
@@ -348,12 +349,12 @@ func TestAccumulate(t *testing.T) {
 		{
 			name:         "one PR, four jobs, all failure",
 			pullRequests: map[int]string{7: ""},
-			presubmits: map[int][]config.Presubmit{
+			presubmits: map[int][]job.Presubmit{
 				7: {
-					{Reporter: config.Reporter{Context: "job1"}},
-					{Reporter: config.Reporter{Context: "job2"}},
-					{Reporter: config.Reporter{Context: "job3"}},
-					{Reporter: config.Reporter{Context: "job4"}},
+					{Reporter: job.Reporter{Context: "job1"}},
+					{Reporter: job.Reporter{Context: "job2"}},
+					{Reporter: job.Reporter{Context: "job3"}},
+					{Reporter: job.Reporter{Context: "job4"}},
 				},
 			},
 			activities: []activity{
@@ -375,12 +376,12 @@ func TestAccumulate(t *testing.T) {
 		{
 			name:         "one PR, four jobs, latest all succeed",
 			pullRequests: map[int]string{7: ""},
-			presubmits: map[int][]config.Presubmit{
+			presubmits: map[int][]job.Presubmit{
 				7: {
-					{Reporter: config.Reporter{Context: "job1"}},
-					{Reporter: config.Reporter{Context: "job2"}},
-					{Reporter: config.Reporter{Context: "job3"}},
-					{Reporter: config.Reporter{Context: "job4"}},
+					{Reporter: job.Reporter{Context: "job1"}},
+					{Reporter: job.Reporter{Context: "job2"}},
+					{Reporter: job.Reporter{Context: "job3"}},
+					{Reporter: job.Reporter{Context: "job4"}},
 				},
 			},
 			activities: []activity{
@@ -403,12 +404,12 @@ func TestAccumulate(t *testing.T) {
 		{
 			name:         "one PR, four jobs, one is pending",
 			pullRequests: map[int]string{7: ""},
-			presubmits: map[int][]config.Presubmit{
+			presubmits: map[int][]job.Presubmit{
 				7: {
-					{Reporter: config.Reporter{Context: "job1"}},
-					{Reporter: config.Reporter{Context: "job2"}},
-					{Reporter: config.Reporter{Context: "job3"}},
-					{Reporter: config.Reporter{Context: "job4"}},
+					{Reporter: job.Reporter{Context: "job1"}},
+					{Reporter: job.Reporter{Context: "job2"}},
+					{Reporter: job.Reporter{Context: "job3"}},
+					{Reporter: job.Reporter{Context: "job4"}},
 				},
 			},
 			activities: []activity{
@@ -430,9 +431,9 @@ func TestAccumulate(t *testing.T) {
 		},
 		{
 			name: "two PRs, one job, one success and one failure",
-			presubmits: map[int][]config.Presubmit{
+			presubmits: map[int][]job.Presubmit{
 				7: {
-					{Reporter: config.Reporter{Context: "job1"}},
+					{Reporter: job.Reporter{Context: "job1"}},
 				},
 			},
 			pullRequests: map[int]string{7: "new", 8: "new"},
@@ -993,7 +994,7 @@ func TestTakeAction(t *testing.T) {
 		pendings     []int
 		nones        []int
 		batchMerges  []int
-		presubmits   map[int][]config.Presubmit
+		presubmits   map[int][]job.Presubmit
 		mergeErrs    map[int]error
 
 		merged           int
@@ -1010,10 +1011,10 @@ func TestTakeAction(t *testing.T) {
 			pendings:     []int{},
 			nones:        []int{},
 			batchMerges:  []int{},
-			presubmits: map[int][]config.Presubmit{
+			presubmits: map[int][]job.Presubmit{
 				100: {
-					{Reporter: config.Reporter{Context: "foo"}},
-					{Reporter: config.Reporter{Context: "if-changed"}},
+					{Reporter: job.Reporter{Context: "foo"}},
+					{Reporter: job.Reporter{Context: "if-changed"}},
 				},
 			},
 			merged:    0,
@@ -1028,10 +1029,10 @@ func TestTakeAction(t *testing.T) {
 			pendings:     []int{1},
 			nones:        []int{0, 2},
 			batchMerges:  []int{},
-			presubmits: map[int][]config.Presubmit{
+			presubmits: map[int][]job.Presubmit{
 				100: {
-					{Reporter: config.Reporter{Context: "foo"}},
-					{Reporter: config.Reporter{Context: "if-changed"}},
+					{Reporter: job.Reporter{Context: "foo"}},
+					{Reporter: job.Reporter{Context: "if-changed"}},
 				},
 			},
 			merged:    0,
@@ -1046,10 +1047,10 @@ func TestTakeAction(t *testing.T) {
 			pendings:     []int{},
 			nones:        []int{0, 2},
 			batchMerges:  []int{},
-			presubmits: map[int][]config.Presubmit{
+			presubmits: map[int][]job.Presubmit{
 				100: {
-					{Reporter: config.Reporter{Context: "foo"}},
-					{Reporter: config.Reporter{Context: "if-changed"}},
+					{Reporter: job.Reporter{Context: "foo"}},
+					{Reporter: job.Reporter{Context: "if-changed"}},
 				},
 			},
 			merged:    0,
@@ -1064,10 +1065,10 @@ func TestTakeAction(t *testing.T) {
 			pendings:     []int{},
 			nones:        []int{0, 1, 2},
 			batchMerges:  []int{},
-			presubmits: map[int][]config.Presubmit{
+			presubmits: map[int][]job.Presubmit{
 				100: {
-					{Reporter: config.Reporter{Context: "foo"}},
-					{Reporter: config.Reporter{Context: "if-changed"}},
+					{Reporter: job.Reporter{Context: "foo"}},
+					{Reporter: job.Reporter{Context: "if-changed"}},
 				},
 			},
 			merged:    0,
@@ -1082,10 +1083,10 @@ func TestTakeAction(t *testing.T) {
 			pendings:     []int{0},
 			nones:        []int{1, 2, 3},
 			batchMerges:  []int{},
-			presubmits: map[int][]config.Presubmit{
+			presubmits: map[int][]job.Presubmit{
 				100: {
-					{Reporter: config.Reporter{Context: "foo"}},
-					{Reporter: config.Reporter{Context: "if-changed"}},
+					{Reporter: job.Reporter{Context: "foo"}},
+					{Reporter: job.Reporter{Context: "if-changed"}},
 				},
 			},
 			merged:           0,
@@ -1101,10 +1102,10 @@ func TestTakeAction(t *testing.T) {
 			pendings:     []int{},
 			nones:        []int{0},
 			batchMerges:  []int{},
-			presubmits: map[int][]config.Presubmit{
+			presubmits: map[int][]job.Presubmit{
 				100: {
-					{Reporter: config.Reporter{Context: "foo"}},
-					{Reporter: config.Reporter{Context: "if-changed"}},
+					{Reporter: job.Reporter{Context: "foo"}},
+					{Reporter: job.Reporter{Context: "if-changed"}},
 				},
 			},
 			merged:    0,
@@ -1119,10 +1120,10 @@ func TestTakeAction(t *testing.T) {
 			pendings:     []int{},
 			nones:        []int{1, 2, 3},
 			batchMerges:  []int{},
-			presubmits: map[int][]config.Presubmit{
+			presubmits: map[int][]job.Presubmit{
 				100: {
-					{Reporter: config.Reporter{Context: "foo"}},
-					{Reporter: config.Reporter{Context: "if-changed"}},
+					{Reporter: job.Reporter{Context: "foo"}},
+					{Reporter: job.Reporter{Context: "if-changed"}},
 				},
 			},
 			merged:    1,
@@ -1137,10 +1138,10 @@ func TestTakeAction(t *testing.T) {
 			pendings:     []int{2, 3},
 			nones:        []int{4, 5},
 			batchMerges:  []int{6, 7, 8},
-			presubmits: map[int][]config.Presubmit{
+			presubmits: map[int][]job.Presubmit{
 				100: {
-					{Reporter: config.Reporter{Context: "foo"}},
-					{Reporter: config.Reporter{Context: "if-changed"}},
+					{Reporter: job.Reporter{Context: "foo"}},
+					{Reporter: job.Reporter{Context: "if-changed"}},
 				},
 			},
 			merged:    3,
@@ -1155,10 +1156,10 @@ func TestTakeAction(t *testing.T) {
 			pendings:     []int{},
 			nones:        []int{100},
 			batchMerges:  []int{},
-			presubmits: map[int][]config.Presubmit{
+			presubmits: map[int][]job.Presubmit{
 				100: {
-					{Reporter: config.Reporter{Context: "foo"}},
-					{Reporter: config.Reporter{Context: "if-changed"}},
+					{Reporter: job.Reporter{Context: "foo"}},
+					{Reporter: job.Reporter{Context: "if-changed"}},
 				},
 			},
 			merged:    0,
@@ -1199,10 +1200,10 @@ func TestTakeAction(t *testing.T) {
 			pendings:     []int{},
 			nones:        []int{1, 2, 3},
 			batchMerges:  []int{},
-			presubmits: map[int][]config.Presubmit{
+			presubmits: map[int][]job.Presubmit{
 				100: {
-					{Reporter: config.Reporter{Context: "foo"}},
-					{Reporter: config.Reporter{Context: "if-changed"}},
+					{Reporter: job.Reporter{Context: "foo"}},
+					{Reporter: job.Reporter{Context: "if-changed"}},
 				},
 			},
 			merged:           0,
@@ -1218,10 +1219,10 @@ func TestTakeAction(t *testing.T) {
 			pendings:     []int{},
 			nones:        []int{1, 2, 3},
 			batchMerges:  []int{},
-			presubmits: map[int][]config.Presubmit{
+			presubmits: map[int][]job.Presubmit{
 				100: {
-					{Reporter: config.Reporter{Context: "foo"}},
-					{Reporter: config.Reporter{Context: "if-changed"}},
+					{Reporter: job.Reporter{Context: "foo"}},
+					{Reporter: job.Reporter{Context: "if-changed"}},
 				},
 			},
 			merged:    0,
@@ -1289,19 +1290,19 @@ func TestTakeAction(t *testing.T) {
 			ca := &config.Agent{}
 			cfg := &config.Config{}
 			if err := cfg.SetPresubmits(
-				map[string][]config.Presubmit{
+				map[string][]job.Presubmit{
 					"o/r": {
 						{
-							Reporter:     config.Reporter{Context: "foo"},
+							Reporter:     job.Reporter{Context: "foo"},
 							Trigger:      "/test all",
 							RerunCommand: "/test all",
 							AlwaysRun:    true,
 						},
 						{
-							Reporter:     config.Reporter{Context: "if-changed"},
+							Reporter:     job.Reporter{Context: "if-changed"},
 							Trigger:      "/test if-changed",
 							RerunCommand: "/test if-changed",
-							RegexpChangeMatcher: config.RegexpChangeMatcher{
+							RegexpChangeMatcher: job.RegexpChangeMatcher{
 								RunIfChanged: "CHANGED",
 							},
 						},
@@ -1313,7 +1314,7 @@ func TestTakeAction(t *testing.T) {
 			ca.Set(cfg)
 			if len(tc.presubmits) > 0 {
 				for i := 0; i <= 8; i++ {
-					tc.presubmits[i] = []config.Presubmit{{Reporter: config.Reporter{Context: "foo"}}}
+					tc.presubmits[i] = []job.Presubmit{{Reporter: job.Reporter{Context: "foo"}}}
 				}
 			}
 			lg, gc, err := localgit.New()
@@ -1747,9 +1748,9 @@ func TestSync(t *testing.T) {
 }
 
 func TestFilterSubpool(t *testing.T) {
-	presubmits := map[int][]config.Presubmit{
-		1: {{Reporter: config.Reporter{Context: "pj-a"}}},
-		2: {{Reporter: config.Reporter{Context: "pj-a"}}, {Reporter: config.Reporter{Context: "pj-b"}}},
+	presubmits := map[int][]job.Presubmit{
+		1: {{Reporter: job.Reporter{Context: "pj-a"}}},
+		2: {{Reporter: job.Reporter{Context: "pj-a"}}, {Reporter: job.Reporter{Context: "pj-b"}}},
 	}
 
 	trueVar := true
@@ -2200,198 +2201,198 @@ func TestPresubmitsByPull(t *testing.T) {
 		name string
 
 		initialChangeCache map[changeCacheKey][]string
-		presubmits         []config.Presubmit
+		presubmits         []job.Presubmit
 
-		expectedPresubmits  map[int][]config.Presubmit
+		expectedPresubmits  map[int][]job.Presubmit
 		expectedChangeCache map[changeCacheKey][]string
 	}{
 		{
 			name: "no matching presubmits",
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
-					Reporter: config.Reporter{Context: "always"},
-					RegexpChangeMatcher: config.RegexpChangeMatcher{
+					Reporter: job.Reporter{Context: "always"},
+					RegexpChangeMatcher: job.RegexpChangeMatcher{
 						RunIfChanged: "foo",
 					},
 				},
 				{
-					Reporter: config.Reporter{Context: "never"},
+					Reporter: job.Reporter{Context: "never"},
 				},
 			},
 			expectedChangeCache: map[changeCacheKey][]string{{number: 100, sha: "sha"}: {"CHANGED"}},
-			expectedPresubmits:  map[int][]config.Presubmit{},
+			expectedPresubmits:  map[int][]job.Presubmit{},
 		},
 		{
 			name:               "no presubmits",
-			presubmits:         []config.Presubmit{},
-			expectedPresubmits: map[int][]config.Presubmit{},
+			presubmits:         []job.Presubmit{},
+			expectedPresubmits: map[int][]job.Presubmit{},
 		},
 		{
 			name: "no matching presubmits (check cache eviction)",
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
-					Reporter: config.Reporter{Context: "never"},
+					Reporter: job.Reporter{Context: "never"},
 				},
 			},
 			initialChangeCache: map[changeCacheKey][]string{{number: 100, sha: "sha"}: {"FILE"}},
-			expectedPresubmits: map[int][]config.Presubmit{},
+			expectedPresubmits: map[int][]job.Presubmit{},
 		},
 		{
 			name: "no matching presubmits (check cache retention)",
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
-					Reporter: config.Reporter{Context: "always"},
-					RegexpChangeMatcher: config.RegexpChangeMatcher{
+					Reporter: job.Reporter{Context: "always"},
+					RegexpChangeMatcher: job.RegexpChangeMatcher{
 						RunIfChanged: "foo",
 					},
 				},
 				{
-					Reporter: config.Reporter{Context: "never"},
+					Reporter: job.Reporter{Context: "never"},
 				},
 			},
 			initialChangeCache:  map[changeCacheKey][]string{{number: 100, sha: "sha"}: {"FILE"}},
 			expectedChangeCache: map[changeCacheKey][]string{{number: 100, sha: "sha"}: {"FILE"}},
-			expectedPresubmits:  map[int][]config.Presubmit{},
+			expectedPresubmits:  map[int][]job.Presubmit{},
 		},
 		{
 			name: "always_run",
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
-					Reporter:  config.Reporter{Context: "always"},
+					Reporter:  job.Reporter{Context: "always"},
 					AlwaysRun: true,
 				},
 				{
-					Reporter: config.Reporter{Context: "never"},
+					Reporter: job.Reporter{Context: "never"},
 				},
 			},
-			expectedPresubmits: map[int][]config.Presubmit{100: {{
-				Reporter:  config.Reporter{Context: "always"},
+			expectedPresubmits: map[int][]job.Presubmit{100: {{
+				Reporter:  job.Reporter{Context: "always"},
 				AlwaysRun: true,
 			}}},
 		},
 		{
 			name: "runs against branch",
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
-					Reporter:  config.Reporter{Context: "presubmit"},
+					Reporter:  job.Reporter{Context: "presubmit"},
 					AlwaysRun: true,
-					Brancher: config.Brancher{
+					Brancher: job.Brancher{
 						Branches: []string{"master", "dev"},
 					},
 				},
 				{
-					Reporter: config.Reporter{Context: "never"},
+					Reporter: job.Reporter{Context: "never"},
 				},
 			},
-			expectedPresubmits: map[int][]config.Presubmit{100: {{
-				Reporter:  config.Reporter{Context: "presubmit"},
+			expectedPresubmits: map[int][]job.Presubmit{100: {{
+				Reporter:  job.Reporter{Context: "presubmit"},
 				AlwaysRun: true,
-				Brancher: config.Brancher{
+				Brancher: job.Brancher{
 					Branches: []string{"master", "dev"},
 				},
 			}}},
 		},
 		{
 			name: "doesn't run against branch",
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
-					Reporter:  config.Reporter{Context: "presubmit"},
+					Reporter:  job.Reporter{Context: "presubmit"},
 					AlwaysRun: true,
-					Brancher: config.Brancher{
+					Brancher: job.Brancher{
 						Branches: []string{"release", "dev"},
 					},
 				},
 				{
-					Reporter:  config.Reporter{Context: "always"},
+					Reporter:  job.Reporter{Context: "always"},
 					AlwaysRun: true,
 				},
 				{
-					Reporter: config.Reporter{Context: "never"},
+					Reporter: job.Reporter{Context: "never"},
 				},
 			},
-			expectedPresubmits: map[int][]config.Presubmit{100: {{
-				Reporter:  config.Reporter{Context: "always"},
+			expectedPresubmits: map[int][]job.Presubmit{100: {{
+				Reporter:  job.Reporter{Context: "always"},
 				AlwaysRun: true,
 			}}},
 		},
 		{
 			name: "run_if_changed (uncached)",
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
-					Reporter: config.Reporter{Context: "presubmit"},
-					RegexpChangeMatcher: config.RegexpChangeMatcher{
+					Reporter: job.Reporter{Context: "presubmit"},
+					RegexpChangeMatcher: job.RegexpChangeMatcher{
 						RunIfChanged: "^CHANGE.$",
 					},
 				},
 				{
-					Reporter:  config.Reporter{Context: "always"},
+					Reporter:  job.Reporter{Context: "always"},
 					AlwaysRun: true,
 				},
 				{
-					Reporter: config.Reporter{Context: "never"},
+					Reporter: job.Reporter{Context: "never"},
 				},
 			},
-			expectedPresubmits: map[int][]config.Presubmit{100: {{
-				Reporter: config.Reporter{Context: "presubmit"},
-				RegexpChangeMatcher: config.RegexpChangeMatcher{
+			expectedPresubmits: map[int][]job.Presubmit{100: {{
+				Reporter: job.Reporter{Context: "presubmit"},
+				RegexpChangeMatcher: job.RegexpChangeMatcher{
 					RunIfChanged: "^CHANGE.$",
 				},
 			}, {
-				Reporter:  config.Reporter{Context: "always"},
+				Reporter:  job.Reporter{Context: "always"},
 				AlwaysRun: true,
 			}}},
 			expectedChangeCache: map[changeCacheKey][]string{{number: 100, sha: "sha"}: {"CHANGED"}},
 		},
 		{
 			name: "run_if_changed (cached)",
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
-					Reporter: config.Reporter{Context: "presubmit"},
-					RegexpChangeMatcher: config.RegexpChangeMatcher{
+					Reporter: job.Reporter{Context: "presubmit"},
+					RegexpChangeMatcher: job.RegexpChangeMatcher{
 						RunIfChanged: "^FIL.$",
 					},
 				},
 				{
-					Reporter:  config.Reporter{Context: "always"},
+					Reporter:  job.Reporter{Context: "always"},
 					AlwaysRun: true,
 				},
 				{
-					Reporter: config.Reporter{Context: "never"},
+					Reporter: job.Reporter{Context: "never"},
 				},
 			},
 			initialChangeCache: map[changeCacheKey][]string{{number: 100, sha: "sha"}: {"FILE"}},
-			expectedPresubmits: map[int][]config.Presubmit{100: {{
-				Reporter: config.Reporter{Context: "presubmit"},
-				RegexpChangeMatcher: config.RegexpChangeMatcher{
+			expectedPresubmits: map[int][]job.Presubmit{100: {{
+				Reporter: job.Reporter{Context: "presubmit"},
+				RegexpChangeMatcher: job.RegexpChangeMatcher{
 					RunIfChanged: "^FIL.$",
 				},
 			},
 				{
-					Reporter:  config.Reporter{Context: "always"},
+					Reporter:  job.Reporter{Context: "always"},
 					AlwaysRun: true,
 				}}},
 			expectedChangeCache: map[changeCacheKey][]string{{number: 100, sha: "sha"}: {"FILE"}},
 		},
 		{
 			name: "run_if_changed (cached) (skippable)",
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
-					Reporter: config.Reporter{Context: "presubmit"},
-					RegexpChangeMatcher: config.RegexpChangeMatcher{
+					Reporter: job.Reporter{Context: "presubmit"},
+					RegexpChangeMatcher: job.RegexpChangeMatcher{
 						RunIfChanged: "^CHANGE.$",
 					},
 				},
 				{
-					Reporter:  config.Reporter{Context: "always"},
+					Reporter:  job.Reporter{Context: "always"},
 					AlwaysRun: true,
 				},
 				{
-					Reporter: config.Reporter{Context: "never"},
+					Reporter: job.Reporter{Context: "never"},
 				},
 			},
 			initialChangeCache: map[changeCacheKey][]string{{number: 100, sha: "sha"}: {"FILE"}},
-			expectedPresubmits: map[int][]config.Presubmit{100: {{
-				Reporter:  config.Reporter{Context: "always"},
+			expectedPresubmits: map[int][]job.Presubmit{100: {{
+				Reporter:  job.Reporter{Context: "always"},
 				AlwaysRun: true,
 			}}},
 			expectedChangeCache: map[changeCacheKey][]string{{number: 100, sha: "sha"}: {"FILE"}},
@@ -2409,9 +2410,9 @@ func TestPresubmitsByPull(t *testing.T) {
 		}
 
 		cfg := &config.Config{}
-		cfg.SetPresubmits(map[string][]config.Presubmit{
+		cfg.SetPresubmits(map[string][]job.Presubmit{
 			"/":       tc.presubmits,
-			"foo/bar": {{Reporter: config.Reporter{Context: "wrong-repo"}, AlwaysRun: true}},
+			"foo/bar": {{Reporter: job.Reporter{Context: "wrong-repo"}, AlwaysRun: true}},
 		})
 		cfgAgent := &config.Agent{}
 		cfgAgent.Set(cfg)
@@ -2435,7 +2436,7 @@ func TestPresubmitsByPull(t *testing.T) {
 		c.changedFiles.prune()
 		// for equality we need to clear the compiled regexes
 		for _, jobs := range presubmits {
-			config.ClearCompiledRegexes(jobs)
+			job.ClearCompiledRegexes(jobs)
 		}
 		if !equality.Semantic.DeepEqual(presubmits, tc.expectedPresubmits) {
 			t.Errorf("got incorrect presubmit mapping: %v\n", diff.ObjectReflectDiff(tc.expectedPresubmits, presubmits))
@@ -2550,10 +2551,10 @@ func TestPrepareMergeDetails(t *testing.T) {
 func TestAccumulateReturnsCorrectMissingTests(t *testing.T) {
 	testCases := []struct {
 		name               string
-		presubmits         map[int][]config.Presubmit
+		presubmits         map[int][]job.Presubmit
 		prs                []PullRequest
 		pjs                []v1alpha1.LighthouseJob
-		expectedPresubmits map[int][]config.Presubmit
+		expectedPresubmits map[int][]job.Presubmit
 	}{
 		{
 			name: "All presubmits missing, no changes",
@@ -2561,13 +2562,13 @@ func TestAccumulateReturnsCorrectMissingTests(t *testing.T) {
 				Number:     githubql.Int(1),
 				HeadRefOID: githubql.String("sha"),
 			}},
-			presubmits: map[int][]config.Presubmit{1: {{
-				Reporter: config.Reporter{
+			presubmits: map[int][]job.Presubmit{1: {{
+				Reporter: job.Reporter{
 					Context: "my-presubmit",
 				},
 			}}},
-			expectedPresubmits: map[int][]config.Presubmit{
-				1: {{Reporter: config.Reporter{Context: "my-presubmit"}}},
+			expectedPresubmits: map[int][]job.Presubmit{
+				1: {{Reporter: job.Reporter{Context: "my-presubmit"}}},
 			},
 		},
 		{
@@ -2589,8 +2590,8 @@ func TestAccumulateReturnsCorrectMissingTests(t *testing.T) {
 				},
 				Status: v1alpha1.LighthouseJobStatus{State: v1alpha1.SuccessState},
 			}},
-			presubmits: map[int][]config.Presubmit{
-				1: {{Reporter: config.Reporter{Context: "my-presubmit"}}},
+			presubmits: map[int][]job.Presubmit{
+				1: {{Reporter: job.Reporter{Context: "my-presubmit"}}},
 			},
 		},
 		{
@@ -2612,8 +2613,8 @@ func TestAccumulateReturnsCorrectMissingTests(t *testing.T) {
 				},
 				Status: v1alpha1.LighthouseJobStatus{State: v1alpha1.PendingState},
 			}},
-			presubmits: map[int][]config.Presubmit{
-				1: {{Reporter: config.Reporter{Context: "my-presubmit"}}}},
+			presubmits: map[int][]job.Presubmit{
+				1: {{Reporter: job.Reporter{Context: "my-presubmit"}}}},
 		},
 		{
 			name: "One successful, one pending, one missing, one failing, only missing and failing remain",
@@ -2662,17 +2663,17 @@ func TestAccumulateReturnsCorrectMissingTests(t *testing.T) {
 					Status: v1alpha1.LighthouseJobStatus{State: v1alpha1.FailureState},
 				},
 			},
-			presubmits: map[int][]config.Presubmit{
+			presubmits: map[int][]job.Presubmit{
 				1: {
-					{Reporter: config.Reporter{Context: "my-successful-presubmit"}},
-					{Reporter: config.Reporter{Context: "my-pending-presubmit"}},
-					{Reporter: config.Reporter{Context: "my-failing-presubmit"}},
-					{Reporter: config.Reporter{Context: "my-missing-presubmit"}},
+					{Reporter: job.Reporter{Context: "my-successful-presubmit"}},
+					{Reporter: job.Reporter{Context: "my-pending-presubmit"}},
+					{Reporter: job.Reporter{Context: "my-failing-presubmit"}},
+					{Reporter: job.Reporter{Context: "my-missing-presubmit"}},
 				}},
-			expectedPresubmits: map[int][]config.Presubmit{
+			expectedPresubmits: map[int][]job.Presubmit{
 				1: {
-					{Reporter: config.Reporter{Context: "my-failing-presubmit"}},
-					{Reporter: config.Reporter{Context: "my-missing-presubmit"}},
+					{Reporter: job.Reporter{Context: "my-failing-presubmit"}},
+					{Reporter: job.Reporter{Context: "my-missing-presubmit"}},
 				}},
 		},
 		{
@@ -2767,28 +2768,28 @@ func TestAccumulateReturnsCorrectMissingTests(t *testing.T) {
 					Status: v1alpha1.LighthouseJobStatus{State: v1alpha1.FailureState},
 				},
 			},
-			presubmits: map[int][]config.Presubmit{
+			presubmits: map[int][]job.Presubmit{
 				1: {
-					{Reporter: config.Reporter{Context: "my-successful-presubmit"}},
-					{Reporter: config.Reporter{Context: "my-pending-presubmit"}},
-					{Reporter: config.Reporter{Context: "my-failing-presubmit"}},
-					{Reporter: config.Reporter{Context: "my-missing-presubmit"}},
+					{Reporter: job.Reporter{Context: "my-successful-presubmit"}},
+					{Reporter: job.Reporter{Context: "my-pending-presubmit"}},
+					{Reporter: job.Reporter{Context: "my-failing-presubmit"}},
+					{Reporter: job.Reporter{Context: "my-missing-presubmit"}},
 				},
 				2: {
-					{Reporter: config.Reporter{Context: "my-successful-presubmit"}},
-					{Reporter: config.Reporter{Context: "my-pending-presubmit"}},
-					{Reporter: config.Reporter{Context: "my-failing-presubmit"}},
-					{Reporter: config.Reporter{Context: "my-missing-presubmit"}},
+					{Reporter: job.Reporter{Context: "my-successful-presubmit"}},
+					{Reporter: job.Reporter{Context: "my-pending-presubmit"}},
+					{Reporter: job.Reporter{Context: "my-failing-presubmit"}},
+					{Reporter: job.Reporter{Context: "my-missing-presubmit"}},
 				},
 			},
-			expectedPresubmits: map[int][]config.Presubmit{
+			expectedPresubmits: map[int][]job.Presubmit{
 				1: {
-					{Reporter: config.Reporter{Context: "my-failing-presubmit"}},
-					{Reporter: config.Reporter{Context: "my-missing-presubmit"}},
+					{Reporter: job.Reporter{Context: "my-failing-presubmit"}},
+					{Reporter: job.Reporter{Context: "my-missing-presubmit"}},
 				},
 				2: {
-					{Reporter: config.Reporter{Context: "my-failing-presubmit"}},
-					{Reporter: config.Reporter{Context: "my-missing-presubmit"}},
+					{Reporter: job.Reporter{Context: "my-failing-presubmit"}},
+					{Reporter: job.Reporter{Context: "my-missing-presubmit"}},
 				},
 			},
 		},
diff --git a/pkg/plugins/override/override_test.go b/pkg/plugins/override/override_test.go
index 82e77f07..5e82832d 100644
--- a/pkg/plugins/override/override_test.go
+++ b/pkg/plugins/override/override_test.go
@@ -25,11 +25,10 @@ import (
 
 	"github.com/jenkins-x/go-scm/scm"
 	"github.com/jenkins-x/lighthouse/pkg/apis/lighthouse/v1alpha1"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/scmprovider"
 	"github.com/sirupsen/logrus"
 	"k8s.io/apimachinery/pkg/util/sets"
-
-	"github.com/jenkins-x/lighthouse/pkg/config"
 )
 
 const (
@@ -44,7 +43,7 @@ const (
 type fakeClient struct {
 	comments   []string
 	statuses   map[string]*scm.StatusInput
-	presubmits map[string]config.Presubmit
+	presubmits map[string]job.Presubmit
 	jobs       sets.String
 }
 
@@ -158,7 +157,7 @@ func (c *fakeClient) QuoteAuthorForComment(author string) string {
 	return author
 }
 
-func (c *fakeClient) presubmitForContext(org, repo, context string) *config.Presubmit {
+func (c *fakeClient) presubmitForContext(org, repo, context string) *job.Presubmit {
 	p, ok := c.presubmits[context]
 	if !ok {
 		return nil
@@ -216,7 +215,7 @@ func TestHandle(t *testing.T) {
 		state         string
 		comment       string
 		contexts      map[string]*scm.StatusInput
-		presubmits    map[string]config.Presubmit
+		presubmits    map[string]job.Presubmit
 		user          string
 		number        int
 		expected      map[string]*scm.StatusInput
@@ -491,9 +490,9 @@ func TestHandle(t *testing.T) {
 					State: scm.StateFailure,
 				},
 			},
-			presubmits: map[string]config.Presubmit{
+			presubmits: map[string]job.Presubmit{
 				"prow-job": {
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "prow-job",
 					},
 				},
diff --git a/pkg/plugins/skip/skip_test.go b/pkg/plugins/skip/skip_test.go
index 8c5c531a..ce1271e9 100644
--- a/pkg/plugins/skip/skip_test.go
+++ b/pkg/plugins/skip/skip_test.go
@@ -21,18 +21,17 @@ import (
 	"testing"
 
 	"github.com/jenkins-x/go-scm/scm"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/scmprovider"
 	"github.com/jenkins-x/lighthouse/pkg/scmprovider/fake"
 	"github.com/sirupsen/logrus"
-
-	"github.com/jenkins-x/lighthouse/pkg/config"
 )
 
 func TestSkipStatus(t *testing.T) {
 	tests := []struct {
 		name string
 
-		presubmits     []config.Presubmit
+		presubmits     []job.Presubmit
 		sha            string
 		event          *scmprovider.GenericCommentEvent
 		prChanges      map[int][]*scm.Change
@@ -43,19 +42,19 @@ func TestSkipStatus(t *testing.T) {
 		{
 			name: "required contexts should not be skipped regardless of their state",
 
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "passing-tests",
 					},
 				},
 				{
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "failed-tests",
 					},
 				},
 				{
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "pending-tests",
 					},
 				},
@@ -102,16 +101,16 @@ func TestSkipStatus(t *testing.T) {
 		{
 			name: "optional contexts that have failed or are pending should be skipped",
 
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
 					Optional: true,
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "failed-tests",
 					},
 				},
 				{
 					Optional: true,
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "pending-tests",
 					},
 				},
@@ -152,16 +151,16 @@ func TestSkipStatus(t *testing.T) {
 		{
 			name: "optional contexts that have failed or are pending should be skipped, with prefix",
 
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
 					Optional: true,
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "failed-tests",
 					},
 				},
 				{
 					Optional: true,
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "pending-tests",
 					},
 				},
@@ -202,10 +201,10 @@ func TestSkipStatus(t *testing.T) {
 		{
 			name: "optional contexts that have not posted a context should not be skipped",
 
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
 					Optional: true,
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "untriggered-tests",
 					},
 				},
@@ -226,10 +225,10 @@ func TestSkipStatus(t *testing.T) {
 		{
 			name: "optional contexts that have succeeded should not be skipped",
 
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
 					Optional: true,
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "succeeded-tests",
 					},
 				},
@@ -260,12 +259,12 @@ func TestSkipStatus(t *testing.T) {
 		{
 			name: "optional tests that have failed but will be handled by trigger should not be skipped",
 
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
 					Optional:     true,
 					Trigger:      `(?m)^/test (?:.*? )?job(?: .*?)?$`,
 					RerunCommand: "/test job",
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "failed-tests",
 					},
 				},
@@ -296,16 +295,16 @@ func TestSkipStatus(t *testing.T) {
 		{
 			name: "no contexts should be skipped if the combined status is success",
 
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
 					Optional: true,
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "failed-tests",
 					},
 				},
 				{
 					Optional: true,
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "pending-tests",
 					},
 				},
@@ -344,7 +343,7 @@ func TestSkipStatus(t *testing.T) {
 	}
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
-			if err := config.SetPresubmitRegexes(test.presubmits); err != nil {
+			if err := job.SetPresubmitRegexes(test.presubmits); err != nil {
 				t.Fatalf("%s: could not set presubmit regexes: %v", test.name, err)
 			}
 
diff --git a/pkg/plugins/trigger/generic-comment_test.go b/pkg/plugins/trigger/generic-comment_test.go
index 57b5a986..743a6066 100644
--- a/pkg/plugins/trigger/generic-comment_test.go
+++ b/pkg/plugins/trigger/generic-comment_test.go
@@ -24,6 +24,7 @@ import (
 
 	"github.com/jenkins-x/go-scm/scm"
 	"github.com/jenkins-x/lighthouse/pkg/config"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/jobutil"
 	"github.com/jenkins-x/lighthouse/pkg/labels"
 	"github.com/jenkins-x/lighthouse/pkg/launcher/fake"
@@ -56,7 +57,7 @@ type testcase struct {
 	AddedLabels          []string
 	RemovedLabels        []string
 	StartsExactly        string
-	Presubmits           map[string][]config.Presubmit
+	Presubmits           map[string][]job.Presubmit
 	IssueLabels          []string
 	IgnoreOkToTest       bool
 	ElideSkippedContexts bool
@@ -275,14 +276,14 @@ func TestHandleGenericComment(t *testing.T) {
 				Body:   "Nice weather outside, right?",
 				State:  "open",
 				IsPR:   true,
-				Presubmits: map[string][]config.Presubmit{
+				Presubmits: map[string][]job.Presubmit{
 					"org/repo": {
 						{
-							JobBase: config.JobBase{
+							Base: job.Base{
 								Name: "jab",
 							},
-							Brancher: config.Brancher{Branches: []string{"master"}},
-							Reporter: config.Reporter{
+							Brancher: job.Brancher{Branches: []string{"master"}},
+							Reporter: job.Reporter{
 								Context: "pull-jab",
 							},
 							Trigger:      "Nice weather outside, right?",
@@ -303,25 +304,25 @@ func TestHandleGenericComment(t *testing.T) {
 			State:       "open",
 			IsPR:        true,
 			ShouldBuild: false,
-			Presubmits: map[string][]config.Presubmit{
+			Presubmits: map[string][]job.Presubmit{
 				"org/repo": {
 					{
-						JobBase: config.JobBase{
+						Base: job.Base{
 							Name: "job",
 						},
 						AlwaysRun: false,
-						Reporter: config.Reporter{
+						Reporter: job.Reporter{
 							Context: "pull-job",
 						},
 						Trigger:      `(?m)^/test (?:.*? )?job(?: .*?)?$`,
 						RerunCommand: `/test job`,
 					},
 					{
-						JobBase: config.JobBase{
+						Base: job.Base{
 							Name: "jib",
 						},
 						AlwaysRun: false,
-						Reporter: config.Reporter{
+						Reporter: job.Reporter{
 							Context: "pull-jib",
 						},
 						Trigger:      `(?m)^/test (?:.*? )?jib(?: .*?)?$`,
@@ -340,20 +341,20 @@ func TestHandleGenericComment(t *testing.T) {
 			Branch: "other",
 			State:  "open",
 			IsPR:   true,
-			Presubmits: map[string][]config.Presubmit{
+			Presubmits: map[string][]job.Presubmit{
 				"org/repo": {
 					{
-						JobBase: config.JobBase{
+						Base: job.Base{
 							Name: "job",
 						},
 						AlwaysRun: true,
-						Reporter: config.Reporter{
+						Reporter: job.Reporter{
 							SkipReport: true,
 							Context:    "pull-job",
 						},
 						Trigger:      `(?m)^/test (?:.*? )?job(?: .*?)?$`,
 						RerunCommand: `/test job`,
-						Brancher:     config.Brancher{Branches: []string{"master"}},
+						Brancher:     job.Brancher{Branches: []string{"master"}},
 					},
 				},
 			},
@@ -364,16 +365,16 @@ func TestHandleGenericComment(t *testing.T) {
 			Body:   "/retest",
 			State:  "open",
 			IsPR:   true,
-			Presubmits: map[string][]config.Presubmit{
+			Presubmits: map[string][]job.Presubmit{
 				"org/repo": {
 					{
-						JobBase: config.JobBase{
+						Base: job.Base{
 							Name: "jab",
 						},
-						RegexpChangeMatcher: config.RegexpChangeMatcher{
+						RegexpChangeMatcher: job.RegexpChangeMatcher{
 							RunIfChanged: "CHANGED",
 						},
-						Reporter: config.Reporter{
+						Reporter: job.Reporter{
 							SkipReport: true,
 							Context:    "pull-jab",
 						},
@@ -391,16 +392,16 @@ func TestHandleGenericComment(t *testing.T) {
 			Body:   "/retest",
 			State:  "open",
 			IsPR:   true,
-			Presubmits: map[string][]config.Presubmit{
+			Presubmits: map[string][]job.Presubmit{
 				"org/repo": {
 					{
-						JobBase: config.JobBase{
+						Base: job.Base{
 							Name: "jib",
 						},
-						RegexpChangeMatcher: config.RegexpChangeMatcher{
+						RegexpChangeMatcher: job.RegexpChangeMatcher{
 							RunIfChanged: "CHANGED",
 						},
-						Reporter: config.Reporter{
+						Reporter: job.Reporter{
 							Context: "pull-jib",
 						},
 						Trigger:      `(?m)^/test (?:.*? )?jib(?: .*?)?$`,
@@ -417,16 +418,16 @@ func TestHandleGenericComment(t *testing.T) {
 			Body:   "/lh-retest",
 			State:  "open",
 			IsPR:   true,
-			Presubmits: map[string][]config.Presubmit{
+			Presubmits: map[string][]job.Presubmit{
 				"org/repo": {
 					{
-						JobBase: config.JobBase{
+						Base: job.Base{
 							Name: "jib",
 						},
-						RegexpChangeMatcher: config.RegexpChangeMatcher{
+						RegexpChangeMatcher: job.RegexpChangeMatcher{
 							RunIfChanged: "CHANGED",
 						},
-						Reporter: config.Reporter{
+						Reporter: job.Reporter{
 							Context: "pull-jib",
 						},
 						Trigger:      `(?m)^/test (?:.*? )?jib(?: .*?)?$`,
@@ -443,16 +444,16 @@ func TestHandleGenericComment(t *testing.T) {
 			Body:   "/test jub",
 			State:  "open",
 			IsPR:   true,
-			Presubmits: map[string][]config.Presubmit{
+			Presubmits: map[string][]job.Presubmit{
 				"org/repo": {
 					{
-						JobBase: config.JobBase{
+						Base: job.Base{
 							Name: "jub",
 						},
-						RegexpChangeMatcher: config.RegexpChangeMatcher{
+						RegexpChangeMatcher: job.RegexpChangeMatcher{
 							RunIfChanged: "CHANGED",
 						},
-						Reporter: config.Reporter{
+						Reporter: job.Reporter{
 							Context: "pull-jub",
 						},
 						Trigger:      `(?m)^/test (?:.*? )?jub(?: .*?)?$`,
@@ -469,16 +470,16 @@ func TestHandleGenericComment(t *testing.T) {
 			Body:   "/retest",
 			State:  "open",
 			IsPR:   true,
-			Presubmits: map[string][]config.Presubmit{
+			Presubmits: map[string][]job.Presubmit{
 				"org/repo": {
 					{
-						JobBase: config.JobBase{
+						Base: job.Base{
 							Name: "jib",
 						},
-						RegexpChangeMatcher: config.RegexpChangeMatcher{
+						RegexpChangeMatcher: job.RegexpChangeMatcher{
 							RunIfChanged: "CHANGED2",
 						},
-						Reporter: config.Reporter{
+						Reporter: job.Reporter{
 							Context: "pull-jib",
 						},
 						Trigger:      `(?m)^/test (?:.*? )?jib(?: .*?)?$`,
@@ -495,16 +496,16 @@ func TestHandleGenericComment(t *testing.T) {
 			Body:   "/retest",
 			State:  "open",
 			IsPR:   true,
-			Presubmits: map[string][]config.Presubmit{
+			Presubmits: map[string][]job.Presubmit{
 				"org/repo": {
 					{
-						JobBase: config.JobBase{
+						Base: job.Base{
 							Name: "jib",
 						},
-						RegexpChangeMatcher: config.RegexpChangeMatcher{
+						RegexpChangeMatcher: job.RegexpChangeMatcher{
 							RunIfChanged: "CHANGED2",
 						},
-						Reporter: config.Reporter{
+						Reporter: job.Reporter{
 							Context: "pull-jib",
 						},
 						Trigger:      `(?m)^/test (?:.*? )?jib(?: .*?)?$`,
@@ -522,16 +523,16 @@ func TestHandleGenericComment(t *testing.T) {
 			Body:   "/ok-to-test",
 			State:  "open",
 			IsPR:   true,
-			Presubmits: map[string][]config.Presubmit{
+			Presubmits: map[string][]job.Presubmit{
 				"org/repo": {
 					{
-						JobBase: config.JobBase{
+						Base: job.Base{
 							Name: "jab",
 						},
-						RegexpChangeMatcher: config.RegexpChangeMatcher{
+						RegexpChangeMatcher: job.RegexpChangeMatcher{
 							RunIfChanged: "CHANGED",
 						},
-						Reporter: config.Reporter{
+						Reporter: job.Reporter{
 							Context: "pull-jab",
 						},
 						Trigger:      `(?m)^/test (?:.*? )?jab(?: .*?)?$`,
@@ -552,25 +553,25 @@ func TestHandleGenericComment(t *testing.T) {
 			Body:   "/test jab",
 			State:  "open",
 			IsPR:   true,
-			Presubmits: map[string][]config.Presubmit{
+			Presubmits: map[string][]job.Presubmit{
 				"org/repo": {
 					{
-						JobBase: config.JobBase{
+						Base: job.Base{
 							Name: "jab",
 						},
-						Brancher: config.Brancher{Branches: []string{"master"}},
-						Reporter: config.Reporter{
+						Brancher: job.Brancher{Branches: []string{"master"}},
+						Reporter: job.Reporter{
 							Context: "pull-jab",
 						},
 						Trigger:      `(?m)^/test (?:.*? )?jab(?: .*?)?$`,
 						RerunCommand: `/test jab`,
 					},
 					{
-						JobBase: config.JobBase{
+						Base: job.Base{
 							Name: "jab",
 						},
-						Brancher: config.Brancher{Branches: []string{"release"}},
-						Reporter: config.Reporter{
+						Brancher: job.Brancher{Branches: []string{"release"}},
+						Reporter: job.Reporter{
 							Context: "pull-jab",
 						},
 						Trigger:      `(?m)^/test (?:.*? )?jab(?: .*?)?$`,
@@ -588,25 +589,25 @@ func TestHandleGenericComment(t *testing.T) {
 			Body:   "/test jab",
 			State:  "open",
 			IsPR:   true,
-			Presubmits: map[string][]config.Presubmit{
+			Presubmits: map[string][]job.Presubmit{
 				"org/repo": {
 					{
-						JobBase: config.JobBase{
+						Base: job.Base{
 							Name: "jab",
 						},
-						Brancher: config.Brancher{Branches: []string{"master"}},
-						Reporter: config.Reporter{
+						Brancher: job.Brancher{Branches: []string{"master"}},
+						Reporter: job.Reporter{
 							Context: "pull-jab",
 						},
 						Trigger:      `(?m)^/test (?:.*? )?jab(?: .*?)?$`,
 						RerunCommand: `/test jab`,
 					},
 					{
-						JobBase: config.JobBase{
+						Base: job.Base{
 							Name: "jab",
 						},
-						Brancher: config.Brancher{Branches: []string{"release"}},
-						Reporter: config.Reporter{
+						Brancher: job.Brancher{Branches: []string{"release"}},
+						Reporter: job.Reporter{
 							Context: "pull-jab",
 						},
 						Trigger:      `(?m)^/test (?:.*? )?jab(?: .*?)?$`,
@@ -624,25 +625,25 @@ func TestHandleGenericComment(t *testing.T) {
 			Body:   "/test jab",
 			State:  "open",
 			IsPR:   true,
-			Presubmits: map[string][]config.Presubmit{
+			Presubmits: map[string][]job.Presubmit{
 				"org/repo": {
 					{
-						JobBase: config.JobBase{
+						Base: job.Base{
 							Name: "jab",
 						},
-						Brancher: config.Brancher{Branches: []string{"master"}},
-						Reporter: config.Reporter{
+						Brancher: job.Brancher{Branches: []string{"master"}},
+						Reporter: job.Reporter{
 							Context: "pull-jab",
 						},
 						Trigger:      `(?m)^/test (?:.*? )?jab(?: .*?)?$`,
 						RerunCommand: `/test jab`,
 					},
 					{
-						JobBase: config.JobBase{
+						Base: job.Base{
 							Name: "jab",
 						},
-						Brancher: config.Brancher{Branches: []string{"release"}},
-						Reporter: config.Reporter{
+						Brancher: job.Brancher{Branches: []string{"release"}},
+						Reporter: job.Reporter{
 							Context: "pull-jab",
 						},
 						Trigger:      `(?m)^/test (?:.*? )?jab(?: .*?)?$`,
@@ -660,16 +661,16 @@ func TestHandleGenericComment(t *testing.T) {
 			Body:   "/retest",
 			State:  "open",
 			IsPR:   true,
-			Presubmits: map[string][]config.Presubmit{
+			Presubmits: map[string][]job.Presubmit{
 				"org/repo": {
 					{
-						JobBase: config.JobBase{
+						Base: job.Base{
 							Name: "jeb",
 						},
-						RegexpChangeMatcher: config.RegexpChangeMatcher{
+						RegexpChangeMatcher: job.RegexpChangeMatcher{
 							RunIfChanged: "CHANGED2",
 						},
-						Reporter: config.Reporter{
+						Reporter: job.Reporter{
 							Context: "pull-jeb",
 						},
 						Trigger:      `(?m)^/test (?:.*? )?jeb(?: .*?)?$`,
@@ -686,16 +687,16 @@ func TestHandleGenericComment(t *testing.T) {
 			Body:   "/retest",
 			State:  "open",
 			IsPR:   true,
-			Presubmits: map[string][]config.Presubmit{
+			Presubmits: map[string][]job.Presubmit{
 				"org/repo": {
 					{
-						JobBase: config.JobBase{
+						Base: job.Base{
 							Name: "jeb",
 						},
-						RegexpChangeMatcher: config.RegexpChangeMatcher{
+						RegexpChangeMatcher: job.RegexpChangeMatcher{
 							RunIfChanged: "CHANGED2",
 						},
-						Reporter: config.Reporter{
+						Reporter: job.Reporter{
 							Context: "pull-jeb",
 						},
 						Trigger:      `(?m)^/test (?:.*? )?jeb(?: .*?)?$`,
@@ -713,16 +714,16 @@ func TestHandleGenericComment(t *testing.T) {
 			Body:   "/test pull-jeb",
 			State:  "open",
 			IsPR:   true,
-			Presubmits: map[string][]config.Presubmit{
+			Presubmits: map[string][]job.Presubmit{
 				"org/repo": {
 					{
-						JobBase: config.JobBase{
+						Base: job.Base{
 							Name: "jeb",
 						},
-						RegexpChangeMatcher: config.RegexpChangeMatcher{
+						RegexpChangeMatcher: job.RegexpChangeMatcher{
 							RunIfChanged: "CHANGED2",
 						},
-						Reporter: config.Reporter{
+						Reporter: job.Reporter{
 							Context: "pull-jeb",
 						},
 						Trigger:      `(?m)^/test (?:.*? )?jeb(?: .*?)?$`,
@@ -738,16 +739,16 @@ func TestHandleGenericComment(t *testing.T) {
 			Body:   "/test all",
 			State:  "open",
 			IsPR:   true,
-			Presubmits: map[string][]config.Presubmit{
+			Presubmits: map[string][]job.Presubmit{
 				"org/repo": {
 					{
-						JobBase: config.JobBase{
+						Base: job.Base{
 							Name: "jub",
 						},
-						RegexpChangeMatcher: config.RegexpChangeMatcher{
+						RegexpChangeMatcher: job.RegexpChangeMatcher{
 							RunIfChanged: "CHANGED",
 						},
-						Reporter: config.Reporter{
+						Reporter: job.Reporter{
 							Context: "pull-jub",
 						},
 						Trigger:      `(?m)^/test (?:.*? )?jub(?: .*?)?$`,
@@ -764,16 +765,16 @@ func TestHandleGenericComment(t *testing.T) {
 			Body:   "/test all",
 			State:  "open",
 			IsPR:   true,
-			Presubmits: map[string][]config.Presubmit{
+			Presubmits: map[string][]job.Presubmit{
 				"org/repo": {
 					{
-						JobBase: config.JobBase{
+						Base: job.Base{
 							Name: "jub",
 						},
-						RegexpChangeMatcher: config.RegexpChangeMatcher{
+						RegexpChangeMatcher: job.RegexpChangeMatcher{
 							RunIfChanged: "CHANGED2",
 						},
-						Reporter: config.Reporter{
+						Reporter: job.Reporter{
 							Context: "pull-jub",
 						},
 						Trigger:      `(?m)^/test (?:.*? )?jub(?: .*?)?$`,
@@ -789,16 +790,16 @@ func TestHandleGenericComment(t *testing.T) {
 			Body:   "/test all",
 			State:  "open",
 			IsPR:   true,
-			Presubmits: map[string][]config.Presubmit{
+			Presubmits: map[string][]job.Presubmit{
 				"org/repo": {
 					{
-						JobBase: config.JobBase{
+						Base: job.Base{
 							Name: "jub",
 						},
-						RegexpChangeMatcher: config.RegexpChangeMatcher{
+						RegexpChangeMatcher: job.RegexpChangeMatcher{
 							RunIfChanged: "CHANGED2",
 						},
-						Reporter: config.Reporter{
+						Reporter: job.Reporter{
 							Context: "pull-jub",
 						},
 						Trigger:      `(?m)^/test (?:.*? )?jub(?: .*?)?$`,
@@ -881,26 +882,26 @@ func TestHandleGenericComment(t *testing.T) {
 			}
 			presubmits := tc.Presubmits
 			if presubmits == nil {
-				presubmits = map[string][]config.Presubmit{
+				presubmits = map[string][]job.Presubmit{
 					"org/repo": {
 						{
-							JobBase: config.JobBase{
+							Base: job.Base{
 								Name: "job",
 							},
 							AlwaysRun: true,
-							Reporter: config.Reporter{
+							Reporter: job.Reporter{
 								Context: "pull-job",
 							},
 							Trigger:      `(?m)^/test (?:.*? )?job(?: .*?)?$`,
 							RerunCommand: `/test job`,
-							Brancher:     config.Brancher{Branches: []string{"master"}},
+							Brancher:     job.Brancher{Branches: []string{"master"}},
 						},
 						{
-							JobBase: config.JobBase{
+							Base: job.Base{
 								Name: "jib",
 							},
 							AlwaysRun: false,
-							Reporter: config.Reporter{
+							Reporter: job.Reporter{
 								Context: "pull-jib",
 							},
 							Trigger:      `(?m)^/test (?:.*? )?jib(?: .*?)?$`,
@@ -988,27 +989,27 @@ func TestRetestFilter(t *testing.T) {
 		name           string
 		failedContexts sets.String
 		allContexts    sets.String
-		presubmits     []config.Presubmit
+		presubmits     []job.Presubmit
 		expected       [][]bool
 	}{
 		{
 			name:           "retest filter matches jobs that produce contexts which have failed",
 			failedContexts: sets.NewString("failed"),
 			allContexts:    sets.NewString("failed", "succeeded"),
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "failed",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "failed",
 					},
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "succeeded",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "succeeded",
 					},
 				},
@@ -1019,21 +1020,21 @@ func TestRetestFilter(t *testing.T) {
 			name:           "retest filter matches jobs that would run automatically and haven't yet ",
 			failedContexts: sets.NewString(),
 			allContexts:    sets.NewString("finished"),
-			presubmits: []config.Presubmit{
+			presubmits: []job.Presubmit{
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "finished",
 					},
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "finished",
 					},
 				},
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "not-yet-run",
 					},
 					AlwaysRun: true,
-					Reporter: config.Reporter{
+					Reporter: job.Reporter{
 						Context: "not-yet-run",
 					},
 				},
@@ -1047,7 +1048,7 @@ func TestRetestFilter(t *testing.T) {
 			if len(testCase.presubmits) != len(testCase.expected) {
 				t.Fatalf("%s: have %d presubmits but only %d expected filter outputs", testCase.name, len(testCase.presubmits), len(testCase.expected))
 			}
-			if err := config.SetPresubmitRegexes(testCase.presubmits); err != nil {
+			if err := job.SetPresubmitRegexes(testCase.presubmits); err != nil {
 				t.Fatalf("%s: could not set presubmit regexes: %v", testCase.name, err)
 			}
 			filter := jobutil.RetestFilter(testCase.failedContexts, testCase.allContexts)
diff --git a/pkg/plugins/trigger/pull-request_test.go b/pkg/plugins/trigger/pull-request_test.go
index 03d5b272..5373ff2c 100644
--- a/pkg/plugins/trigger/pull-request_test.go
+++ b/pkg/plugins/trigger/pull-request_test.go
@@ -21,6 +21,7 @@ import (
 
 	"github.com/jenkins-x/go-scm/scm"
 	"github.com/jenkins-x/lighthouse/pkg/config"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/labels"
 	"github.com/jenkins-x/lighthouse/pkg/launcher/fake"
 	"github.com/jenkins-x/lighthouse/pkg/plugins"
@@ -284,10 +285,10 @@ func TestHandlePullRequest(t *testing.T) {
 			Logger:            logrus.WithField("plugin", PluginName),
 		}
 
-		presubmits := map[string][]config.Presubmit{
+		presubmits := map[string][]job.Presubmit{
 			"org/repo": {
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "jib",
 					},
 					AlwaysRun: true,
diff --git a/pkg/plugins/trigger/push_test.go b/pkg/plugins/trigger/push_test.go
index e2b913dc..5f84e2b8 100644
--- a/pkg/plugins/trigger/push_test.go
+++ b/pkg/plugins/trigger/push_test.go
@@ -22,6 +22,7 @@ import (
 	"github.com/jenkins-x/go-scm/scm"
 	"github.com/jenkins-x/lighthouse/pkg/apis/lighthouse/v1alpha1"
 	"github.com/jenkins-x/lighthouse/pkg/config"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/launcher/fake"
 	fake2 "github.com/jenkins-x/lighthouse/pkg/scmprovider/fake"
 	"github.com/sirupsen/logrus"
@@ -139,30 +140,30 @@ func TestHandlePE(t *testing.T) {
 			Config:            &config.Config{ProwConfig: config.ProwConfig{LighthouseJobNamespace: "lighthouseJobs"}},
 			Logger:            logrus.WithField("plugin", PluginName),
 		}
-		postsubmits := map[string][]config.Postsubmit{
+		postsubmits := map[string][]job.Postsubmit{
 			"org/repo": {
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "pass-butter",
 					},
-					RegexpChangeMatcher: config.RegexpChangeMatcher{
+					RegexpChangeMatcher: job.RegexpChangeMatcher{
 						RunIfChanged: "\\.sh$",
 					},
 				},
 			},
 			"org2/repo2": {
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "pass-salt",
 					},
 				},
 			},
 			"org3/repo3": {
 				{
-					JobBase: config.JobBase{
+					Base: job.Base{
 						Name: "pass-pepper",
 					},
-					Brancher: config.Brancher{
+					Brancher: job.Brancher{
 						Branches: []string{"release/v1.14"},
 					},
 				},
diff --git a/pkg/plugins/trigger/trigger_test.go b/pkg/plugins/trigger/trigger_test.go
index 376acb85..64728ae1 100644
--- a/pkg/plugins/trigger/trigger_test.go
+++ b/pkg/plugins/trigger/trigger_test.go
@@ -21,7 +21,7 @@ import (
 	"testing"
 
 	"github.com/jenkins-x/go-scm/scm"
-	"github.com/jenkins-x/lighthouse/pkg/config"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/launcher/fake"
 	"github.com/jenkins-x/lighthouse/pkg/plugins"
 	fake2 "github.com/jenkins-x/lighthouse/pkg/scmprovider/fake"
@@ -83,8 +83,8 @@ func TestRunAndSkipJobs(t *testing.T) {
 	var testCases = []struct {
 		name string
 
-		requestedJobs        []config.Presubmit
-		skippedJobs          []config.Presubmit
+		requestedJobs        []job.Presubmit
+		skippedJobs          []job.Presubmit
 		elideSkippedContexts bool
 		jobCreationErrs      sets.String // job names which fail creation
 
@@ -97,31 +97,31 @@ func TestRunAndSkipJobs(t *testing.T) {
 		},
 		{
 			name: "all requested jobs get run",
-			requestedJobs: []config.Presubmit{{
-				JobBase: config.JobBase{
+			requestedJobs: []job.Presubmit{{
+				Base: job.Base{
 					Name: "first",
 				},
-				Reporter: config.Reporter{Context: "first-context"},
+				Reporter: job.Reporter{Context: "first-context"},
 			}, {
-				JobBase: config.JobBase{
+				Base: job.Base{
 					Name: "second",
 				},
-				Reporter: config.Reporter{Context: "second-context"},
+				Reporter: job.Reporter{Context: "second-context"},
 			}},
 			expectedJobs: sets.NewString("first", "second"),
 		},
 		{
 			name: "failure on job creation bubbles up but doesn't stop others from starting",
-			requestedJobs: []config.Presubmit{{
-				JobBase: config.JobBase{
+			requestedJobs: []job.Presubmit{{
+				Base: job.Base{
 					Name: "first",
 				},
-				Reporter: config.Reporter{Context: "first-context"},
+				Reporter: job.Reporter{Context: "first-context"},
 			}, {
-				JobBase: config.JobBase{
+				Base: job.Base{
 					Name: "second",
 				},
-				Reporter: config.Reporter{Context: "second-context"},
+				Reporter: job.Reporter{Context: "second-context"},
 			}},
 			jobCreationErrs: sets.NewString("first"),
 			expectedJobs:    sets.NewString("second"),
@@ -134,16 +134,16 @@ func TestRunAndSkipJobs(t *testing.T) {
 		},
 		{
 			name: "all skipped jobs get skipped",
-			skippedJobs: []config.Presubmit{{
-				JobBase: config.JobBase{
+			skippedJobs: []job.Presubmit{{
+				Base: job.Base{
 					Name: "first",
 				},
-				Reporter: config.Reporter{Context: "first-context"},
+				Reporter: job.Reporter{Context: "first-context"},
 			}, {
-				JobBase: config.JobBase{
+				Base: job.Base{
 					Name: "second",
 				},
-				Reporter: config.Reporter{Context: "second-context"},
+				Reporter: job.Reporter{Context: "second-context"},
 			}},
 			expectedStatuses: []*scm.StatusInput{{
 				State: scm.StateSuccess,
@@ -157,31 +157,31 @@ func TestRunAndSkipJobs(t *testing.T) {
 		},
 		{
 			name: "all skipped jobs get ignored if skipped statuses are elided",
-			skippedJobs: []config.Presubmit{{
-				JobBase: config.JobBase{
+			skippedJobs: []job.Presubmit{{
+				Base: job.Base{
 					Name: "first",
 				},
-				Reporter: config.Reporter{Context: "first-context"},
+				Reporter: job.Reporter{Context: "first-context"},
 			}, {
-				JobBase: config.JobBase{
+				Base: job.Base{
 					Name: "second",
 				},
-				Reporter: config.Reporter{Context: "second-context"},
+				Reporter: job.Reporter{Context: "second-context"},
 			}},
 			elideSkippedContexts: true,
 		},
 		{
 			name: "skipped jobs with skip report get ignored",
-			skippedJobs: []config.Presubmit{{
-				JobBase: config.JobBase{
+			skippedJobs: []job.Presubmit{{
+				Base: job.Base{
 					Name: "first",
 				},
-				Reporter: config.Reporter{Context: "first-context"},
+				Reporter: job.Reporter{Context: "first-context"},
 			}, {
-				JobBase: config.JobBase{
+				Base: job.Base{
 					Name: "second",
 				},
-				Reporter: config.Reporter{Context: "second-context", SkipReport: true},
+				Reporter: job.Reporter{Context: "second-context", SkipReport: true},
 			}},
 			expectedStatuses: []*scm.StatusInput{{
 				State: scm.StateSuccess,
@@ -191,48 +191,48 @@ func TestRunAndSkipJobs(t *testing.T) {
 		},
 		{
 			name: "overlap between jobs callErrors and has no external action",
-			requestedJobs: []config.Presubmit{{
-				JobBase: config.JobBase{
+			requestedJobs: []job.Presubmit{{
+				Base: job.Base{
 					Name: "first",
 				},
-				Reporter: config.Reporter{Context: "first-context"},
+				Reporter: job.Reporter{Context: "first-context"},
 			}, {
-				JobBase: config.JobBase{
+				Base: job.Base{
 					Name: "second",
 				},
-				Reporter: config.Reporter{Context: "second-context"},
+				Reporter: job.Reporter{Context: "second-context"},
 			}},
-			skippedJobs: []config.Presubmit{{
-				JobBase: config.JobBase{
+			skippedJobs: []job.Presubmit{{
+				Base: job.Base{
 					Name: "first",
 				},
-				Reporter: config.Reporter{Context: "first-context"},
+				Reporter: job.Reporter{Context: "first-context"},
 			}},
 			expectedErr: true,
 		},
 		{
 			name: "disjoint sets of jobs get triggered and skipped correctly",
-			requestedJobs: []config.Presubmit{{
-				JobBase: config.JobBase{
+			requestedJobs: []job.Presubmit{{
+				Base: job.Base{
 					Name: "first",
 				},
-				Reporter: config.Reporter{Context: "first-context"},
+				Reporter: job.Reporter{Context: "first-context"},
 			}, {
-				JobBase: config.JobBase{
+				Base: job.Base{
 					Name: "second",
 				},
-				Reporter: config.Reporter{Context: "second-context"},
+				Reporter: job.Reporter{Context: "second-context"},
 			}},
-			skippedJobs: []config.Presubmit{{
-				JobBase: config.JobBase{
+			skippedJobs: []job.Presubmit{{
+				Base: job.Base{
 					Name: "third",
 				},
-				Reporter: config.Reporter{Context: "third-context"},
+				Reporter: job.Reporter{Context: "third-context"},
 			}, {
-				JobBase: config.JobBase{
+				Base: job.Base{
 					Name: "fourth",
 				},
-				Reporter: config.Reporter{Context: "fourth-context"},
+				Reporter: job.Reporter{Context: "fourth-context"},
 			}},
 			expectedJobs: sets.NewString("first", "second"),
 			expectedStatuses: []*scm.StatusInput{{
@@ -247,27 +247,27 @@ func TestRunAndSkipJobs(t *testing.T) {
 		},
 		{
 			name: "disjoint sets of jobs get triggered and skipped correctly, even if one creation fails",
-			requestedJobs: []config.Presubmit{{
-				JobBase: config.JobBase{
+			requestedJobs: []job.Presubmit{{
+				Base: job.Base{
 					Name: "first",
 				},
-				Reporter: config.Reporter{Context: "first-context"},
+				Reporter: job.Reporter{Context: "first-context"},
 			}, {
-				JobBase: config.JobBase{
+				Base: job.Base{
 					Name: "second",
 				},
-				Reporter: config.Reporter{Context: "second-context"},
+				Reporter: job.Reporter{Context: "second-context"},
 			}},
-			skippedJobs: []config.Presubmit{{
-				JobBase: config.JobBase{
+			skippedJobs: []job.Presubmit{{
+				Base: job.Base{
 					Name: "third",
 				},
-				Reporter: config.Reporter{Context: "third-context"},
+				Reporter: job.Reporter{Context: "third-context"},
 			}, {
-				JobBase: config.JobBase{
+				Base: job.Base{
 					Name: "fourth",
 				},
-				Reporter: config.Reporter{Context: "fourth-context"},
+				Reporter: job.Reporter{Context: "fourth-context"},
 			}},
 			jobCreationErrs: sets.NewString("first"),
 			expectedJobs:    sets.NewString("second"),
@@ -288,16 +288,16 @@ func TestRunAndSkipJobs(t *testing.T) {
 		},
 		{
 			name: "jobs that fail to run have status",
-			requestedJobs: []config.Presubmit{{
-				JobBase: config.JobBase{
+			requestedJobs: []job.Presubmit{{
+				Base: job.Base{
 					Name: "first",
 				},
-				Reporter: config.Reporter{Context: "first-context"},
+				Reporter: job.Reporter{Context: "first-context"},
 			}, {
-				JobBase: config.JobBase{
+				Base: job.Base{
 					Name: "second",
 				},
-				Reporter: config.Reporter{Context: "second-context"},
+				Reporter: job.Reporter{Context: "second-context"},
 			}},
 			jobCreationErrs: sets.NewString("first", "second"),
 			expectedStatuses: []*scm.StatusInput{{
@@ -370,7 +370,7 @@ func TestRunRequested(t *testing.T) {
 	var testCases = []struct {
 		name string
 
-		requestedJobs   []config.Presubmit
+		requestedJobs   []job.Presubmit
 		jobCreationErrs sets.String // job names which fail creation
 
 		expectedJobs sets.String // by name
@@ -381,31 +381,31 @@ func TestRunRequested(t *testing.T) {
 		},
 		{
 			name: "all requested jobs get run",
-			requestedJobs: []config.Presubmit{{
-				JobBase: config.JobBase{
+			requestedJobs: []job.Presubmit{{
+				Base: job.Base{
 					Name: "first",
 				},
-				Reporter: config.Reporter{Context: "first-context"},
+				Reporter: job.Reporter{Context: "first-context"},
 			}, {
-				JobBase: config.JobBase{
+				Base: job.Base{
 					Name: "second",
 				},
-				Reporter: config.Reporter{Context: "second-context"},
+				Reporter: job.Reporter{Context: "second-context"},
 			}},
 			expectedJobs: sets.NewString("first", "second"),
 		},
 		{
 			name: "failure on job creation bubbles up but doesn't stop others from starting",
-			requestedJobs: []config.Presubmit{{
-				JobBase: config.JobBase{
+			requestedJobs: []job.Presubmit{{
+				Base: job.Base{
 					Name: "first",
 				},
-				Reporter: config.Reporter{Context: "first-context"},
+				Reporter: job.Reporter{Context: "first-context"},
 			}, {
-				JobBase: config.JobBase{
+				Base: job.Base{
 					Name: "second",
 				},
-				Reporter: config.Reporter{Context: "second-context"},
+				Reporter: job.Reporter{Context: "second-context"},
 			}},
 			jobCreationErrs: sets.NewString("first"),
 			expectedJobs:    sets.NewString("second"),
@@ -465,40 +465,40 @@ func TestRunRequested(t *testing.T) {
 func TestValidateContextOverlap(t *testing.T) {
 	var testCases = []struct {
 		name          string
-		toRun, toSkip []config.Presubmit
+		toRun, toSkip []job.Presubmit
 		expectedErr   bool
 	}{
 		{
 			name:   "empty inputs mean no error",
-			toRun:  []config.Presubmit{},
-			toSkip: []config.Presubmit{},
+			toRun:  []job.Presubmit{},
+			toSkip: []job.Presubmit{},
 		},
 		{
 			name:   "disjoint sets mean no error",
-			toRun:  []config.Presubmit{{Reporter: config.Reporter{Context: "foo"}}},
-			toSkip: []config.Presubmit{{Reporter: config.Reporter{Context: "bar"}}},
+			toRun:  []job.Presubmit{{Reporter: job.Reporter{Context: "foo"}}},
+			toSkip: []job.Presubmit{{Reporter: job.Reporter{Context: "bar"}}},
 		},
 		{
 			name:   "complex disjoint sets mean no error",
-			toRun:  []config.Presubmit{{Reporter: config.Reporter{Context: "foo"}}, {Reporter: config.Reporter{Context: "otherfoo"}}},
-			toSkip: []config.Presubmit{{Reporter: config.Reporter{Context: "bar"}}, {Reporter: config.Reporter{Context: "otherbar"}}},
+			toRun:  []job.Presubmit{{Reporter: job.Reporter{Context: "foo"}}, {Reporter: job.Reporter{Context: "otherfoo"}}},
+			toSkip: []job.Presubmit{{Reporter: job.Reporter{Context: "bar"}}, {Reporter: job.Reporter{Context: "otherbar"}}},
 		},
 		{
 			name:        "overlapping sets error",
-			toRun:       []config.Presubmit{{Reporter: config.Reporter{Context: "foo"}}, {Reporter: config.Reporter{Context: "otherfoo"}}},
-			toSkip:      []config.Presubmit{{Reporter: config.Reporter{Context: "bar"}}, {Reporter: config.Reporter{Context: "otherfoo"}}},
+			toRun:       []job.Presubmit{{Reporter: job.Reporter{Context: "foo"}}, {Reporter: job.Reporter{Context: "otherfoo"}}},
+			toSkip:      []job.Presubmit{{Reporter: job.Reporter{Context: "bar"}}, {Reporter: job.Reporter{Context: "otherfoo"}}},
 			expectedErr: true,
 		},
 		{
 			name:        "identical sets error",
-			toRun:       []config.Presubmit{{Reporter: config.Reporter{Context: "foo"}}, {Reporter: config.Reporter{Context: "otherfoo"}}},
-			toSkip:      []config.Presubmit{{Reporter: config.Reporter{Context: "foo"}}, {Reporter: config.Reporter{Context: "otherfoo"}}},
+			toRun:       []job.Presubmit{{Reporter: job.Reporter{Context: "foo"}}, {Reporter: job.Reporter{Context: "otherfoo"}}},
+			toSkip:      []job.Presubmit{{Reporter: job.Reporter{Context: "foo"}}, {Reporter: job.Reporter{Context: "otherfoo"}}},
 			expectedErr: true,
 		},
 		{
 			name:        "superset callErrors",
-			toRun:       []config.Presubmit{{Reporter: config.Reporter{Context: "foo"}}, {Reporter: config.Reporter{Context: "otherfoo"}}},
-			toSkip:      []config.Presubmit{{Reporter: config.Reporter{Context: "foo"}}, {Reporter: config.Reporter{Context: "otherfoo"}}, {Reporter: config.Reporter{Context: "thirdfoo"}}},
+			toRun:       []job.Presubmit{{Reporter: job.Reporter{Context: "foo"}}, {Reporter: job.Reporter{Context: "otherfoo"}}},
+			toSkip:      []job.Presubmit{{Reporter: job.Reporter{Context: "foo"}}, {Reporter: job.Reporter{Context: "otherfoo"}}, {Reporter: job.Reporter{Context: "thirdfoo"}}},
 			expectedErr: true,
 		},
 	}
diff --git a/test/e2e/tekton_test.go b/test/e2e/tekton_test.go
index a5c3d1f2..95b8fe35 100644
--- a/test/e2e/tekton_test.go
+++ b/test/e2e/tekton_test.go
@@ -15,7 +15,7 @@ import (
 
 	"github.com/cenkalti/backoff"
 	"github.com/jenkins-x/go-scm/scm"
-	"github.com/jenkins-x/lighthouse/pkg/config"
+	"github.com/jenkins-x/lighthouse/pkg/config/job"
 	"github.com/jenkins-x/lighthouse/pkg/git"
 	"github.com/jenkins-x/lighthouse/pkg/scmprovider"
 	. "github.com/onsi/ginkgo"
@@ -105,13 +105,13 @@ func ChatOpsTests() bool {
 				"https://raw.githubusercontent.com/tektoncd/catalog/master/task/git-batch-merge/0.2/git-batch-merge.yaml")
 
 			By(fmt.Sprintf("creating and populating Lighthouse config for %s", repo.Clone))
-			cfg, pluginCfg, err := ProcessConfigAndPlugins(repo.Namespace, repo.Name, ns, config.TektonPipelineAgent)
+			cfg, pluginCfg, err := ProcessConfigAndPlugins(repo.Namespace, repo.Name, ns, job.TektonPipelineAgent)
 			Expect(err).ShouldNot(HaveOccurred())
 			Expect(cfg).ShouldNot(BeNil())
 			Expect(pluginCfg).ShouldNot(BeNil())
 
 			cfg.Presubmits[repoFullName][0].PipelineRunSpec = generatePipelineRunSpec()
-			cfg.Presubmits[repoFullName][0].PipelineRunParams = []config.PipelineRunParam{
+			cfg.Presubmits[repoFullName][0].PipelineRunParams = []job.PipelineRunParam{
 				{
 					Name:          "batch-refs",
 					ValueTemplate: "{{ range $i, $v := .Refs.Pulls }}{{if $i}} {{end}}{{ $v.Ref }}{{ end }}",