Eins Zwei DRY
Overview
Teaching: 5 min
Exercises: 10 minQuestions
How can we make job templates?
Objectives
Don’t Repeat Yourself (DRY)
Making reusable/flexible CI/CD jobs
Hidden (keys) Jobs
A fun feature about GitLab’s CI YAML is the ability to disable entire jobs simply by prefixing the job name with a period (.
). Naively, we could just comment it out
#hidden job:
# script:
# - make
but it’s much easier to simply write
.hidden job:
script:
- make
Why is this fun? We should be able to combine it with some other nice features of GitLab’s CI YAML to build…
Job Templates
From the previous lesson, our .gitlab-ci.yml
looks like
variables:
GIT_SUBMODULE_STRATEGY: recursive
hello world:
script:
- echo "Hello World"
- find . -path ./.git -prune -o -print
build:
image: atlas/analysisbase:21.2.85-centos7
before_script:
- source /home/atlas/release_setup.sh
script:
- mkdir build
- cd build
- cmake ../source
- cmake --build .
build_latest:
image: atlas/analysisbase:latest
before_script:
- source /home/atlas/release_setup.sh
script:
- mkdir build
- cd build
- cmake ../source
- cmake --build .
allow_failure: yes
We’ve already started to repeat ourselves. How can we combine the two into a single job template called .build_template
? Let’s refactor things a little bit.
Refactoring the code
Can you refactor the above code by adding a hidden job (named
.build_template
) containing parameters thatbuild
andbuild_latest
have in common?Solution
variables: GIT_SUBMODULE_STRATEGY: recursive hello world: script: - echo "Hello World" - find . -path ./.git -prune -o -print .build_template: before_script: - source /home/atlas/release_setup.sh script: - mkdir build - cd build - cmake ../source - cmake --build . build: image: atlas/analysisbase:21.2.85-centos7 before_script: - source /home/atlas/release_setup.sh script: - mkdir build - cd build - cmake ../source - cmake --build . build_latest: image: atlas/analysisbase:latest before_script: - source /home/atlas/release_setup.sh script: - mkdir build - cd build - cmake ../source - cmake --build . allow_failure: yes
The idea behind not repeating yourself is to merge multiple (job) definitions together, usually a hidden job and a non-hidden job. This is done through a concept of inheritance. Interestingly enough, GitLab CI/CD also allows for :job:extends
as an alternative to using YAML anchors. I tend to prefer this syntax as it appears to be “more readable and slightly more flexible” (according to GitLab - but I argue it’s simply just more readable and has identical functionality!!!).
.only-important:
only:
- master
- stable
tags:
- production
.in-docker:
tags:
- docker
image: alpine
rspec:
extends:
- .only-important
- .in-docker
script:
- rake rspec
will become
rspec:
only:
- master
- stable
tags:
- docker
image: alpine
script:
- rake rspec
Note how .in-docker
overrides :rspec:tags
because it’s “closest in scope”.
Anchors Away?
If we use
extends
to remove duplicate code, what do we get?Solution
variables: GIT_SUBMODULE_STRATEGY: recursive hello world: script: - echo "Hello World" - find . -path ./.git -prune -o -print .build_template: before_script: - source /home/atlas/release_setup.sh script: - mkdir build - cd build - cmake ../source - cmake --build . build: extends: .build_template image: atlas/analysisbase:21.2.85-centos7 build_latest: extends: .build_template image: atlas/analysisbase:latest allow_failure: yes
Look how much cleaner you’ve made the code. You should now see that it’s pretty easy to start adding more build jobs for other images in a relatively clean way, as you’ve now abstracted the actual building from the definitions.
Key Points
Hidden jobs can be used as templates with the
extends
parameter.Using job templates allows you to stay DRY!