[CI] Define a global variable for including files from a branch
<!--IssueSummary start-->
<details>
<summary>
Everyone can contribute. [Help move this issue forward](https://handbook.gitlab.com/handbook/marketing/developer-relations/contributor-success/community-contributors-workflows/#contributor-links) while earning points, leveling up and collecting rewards.
</summary>
- [Close this issue](https://contributors.gitlab.com/manage-issue?action=close&projectId=278964&issueIid=345805)
</details>
<!--IssueSummary end-->
## Introduction
First of all, I hope that, despite the long description, the answer will be "You are doing it wrong. Here is how you should do it".
However, since I don't know better, I'll explain here with as many details I can provide.
Testing changes in the CI when using included files, especially on more than one nesting level, is by far the most complicated and time-consuming process.
It requires providing branch names almost everywhere, committing these changes, and removing them once I complete my changes.
### Scenario
Below are a couple of YAML files taken from an actual project (just slightly sanitized).
`my-group/my-front-end-project/.gitlab-ci.yml`:
```yaml
---
include:
- project: 'my-group/my-cd-project'
file:
- '/gitlab-ci/front-end.yml'
```
`my-group/my-cd-project/gitlab-ci/front-end.yml`:
```yaml
---
image: some-image
workflow:
rules:
- if: '$CI_COMMIT_MESSAGE =~ /-wip$/ || $CI_PIPELINE_SOURCE == "merge_request_event"'
when: never
- when: always
stages:
- development
- prepare
- quality
- tests
- qa
- staging
- production
- documentation
include:
- project: 'my-group/my-cd-project'
file:
- '/gitlab-ci/global.yml'
- '/gitlab-ci/before-script.yml'
- '/gitlab-ci/after-script.yml'
- '/gitlab-ci/prepare-cache.yml'
- '/gitlab-ci/qa/duplication.yml'
- '/gitlab-ci/integrations/build-succeeded.yml'
pages:
extends: .cache-pull
stage: documentation
script:
- rm -rf public
- npm run doc:generate -- --output public
- echo "Pages URL $CI_PAGES_URL"
artifacts:
paths:
- public
rules:
- if: '$CI_COMMIT_REF_SLUG == "master"'
```
I want to make some changes in the CI (on several of the included files) and test them without pushing them to the production branch.
What I usually do is the following [^thruth-to-be-told]:
1. Create a new branch called `my-new-feature` in `my-group/my-front-end-project`
2. Create a new branch called `my-new-feature` in `my-group/my-cd-project`
3. In `my-group/my-front-end-project/.gitlab-ci.yml`, add a `ref: my-new-feature` to the `include` keyword
4. Do the same in `my-group/my-cd-project/gitlab-ci/front-end.yml`
5. Do the same in all the files included in `my-group/my-cd-project/gitlab-ci/front-end.yml` if they also include files.
6. Repeat as long as there are nested included files (and as long as I need to modify them).
7. Cry if the included files spread across other projects (this is the last step because, when it happens, I usually realize it after dealing with all the previous steps).
[^thruth-to-be-told]: Frustration often leads me to skip all of this and push my changes to the main branch, which I hate to do.
### Proposal
Define "root" variables that tell the runner to include files from a branch with a given name but fall back to another one, should that branch not exist.
E.g.:
```
---
variables:
INCLUDE_FROM_REF: $CI_COMMIT_REF_SLUG
INCLUDE_FROM_REF_FALLBACK: $CI_DEFAULT_BRANCH
```
On every include, the runner will first try to include the file from `INCLUDE_FROM_REF` and:
1. Try to include the file from `INCLUDE_FROM_REF`.
2. Fail with an error if there is no branch with this name and no provided `INCLUDE_FROM_REF_FALLBACK`.
3. If the previous step didn't fail, try to include the file from `INCLUDE_FROM_REF_FALLBACK`.
4. Fail with an error if there is no `INCLUDE_FROM_REF_FALLBACK` branch.
I imagine that the CI Linter could handle the failure, as the required branches are meant to exist before starting any pipeline.
issue