Reputation: 1610
Let's suppose I have this hidden "base" job.
.base_job:
rules:
- if: "$CI_COMMIT_TAG"
when: never
- if: '$CI_PIPELINE_SOURCE == "web"'
I'd like to add these rules to a new job and be able to extend them too, e.g.:
job_1:
rules:
- <add .base_job here>
- if: "$CI_MERGE_REQUEST_IID"
job_2:
rules:
- <add .base_job here>
- if: "$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH"
Note that job_1
and job_2
have different rules, including the ones from .base_job
.
If I were to use extends
, the jobs would have only the custom rule because according to the docs:
You can use extends to merge hashes but not arrays.
My solution so far is to copy-paste the rules for both jobs but I'd like to keep it more DRY.
Any tips on how to do it?
Upvotes: 27
Views: 33016
Reputation: 1610
So I've found a very hacky official way of doing this. It is not ideal but at least I could get what I wanted working.
Warning: This is only available starting on GitLab 14.3, which as of Sep/21 is in a pre-release state.
I prepare a set of just the texts of the rules and inject them in a real rule if
using !reference
.
.rules_base:
rules:
RULE_A: "$CI_COMMIT_TAG"
RULE_B: "$CI_MERGE_REQUEST_IID"
job_a:
rules:
- if: !reference [.rules_base, rules, RULE_A]
- if: '$CI_PIPELINE_SOURCE == "web"'
job_b:
rules:
- if: !reference [.rules_base, rules, RULE_B]
This actually works and I can reuse the same rules on different jobs while also including new rules, if necessary.
Upvotes: 29
Reputation: 71
You can actually declare a set of rules as an array, and merged them in each job:
.base_rules:
- if: "$CI_COMMIT_TAG"
when: never
- if: '$CI_PIPELINE_SOURCE == "web"'
.base_job:
rules: !reference [.base_rules]
job_1:
rules:
- if: "$CI_MERGE_REQUEST_ID"
- !reference [.base_rules]
job_2:
rules:
- if: "$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH"
- !reference [.base_rules]
Upvotes: 7
Reputation: 14723
As pointed out in the question, the GitLab CI extends
construct does not allow one to merge inner arrays (and more generally the expected underlying feature in YAML is not(yet) available), so basically:
.base_job:
rules:
- if: "$CI_COMMIT_TAG"
when: never
- if: '$CI_PIPELINE_SOURCE == "web"'
job_1:
extends: .base_job
rules:
- if: "$CI_MERGE_REQUEST_IID"
would lead to:
job_1:
rules:
- if: "$CI_MERGE_REQUEST_IID"
# → overwritten
However, if you find that the first answer posted is too hacky and too verbose, it appears you could just use the native YAML anchors construct to do the same.
Namely, you might write a GitLab CI conf-file like this:
.base_job:
rules:
- &rule_a
if: "$CI_COMMIT_TAG"
when: never
- &rule_b
if: '$CI_PIPELINE_SOURCE == "web"'
job_a:
rules:
- *rule_a
- if: "$CI_MERGE_REQUEST_IID"
job_b:
rules:
- *rule_b
- if: "$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH"
Upvotes: 34