Gitlab CI: How to reuse your .yml code

When doing new studies on Gitlab Continuous Integration, I discovered two things that do not say much about it, and that can help a lot in the development of pipelines. They are: Hidden Keys and Anchors.

Hidden keys and anchors are great features when it comes to reusing code. With them it is possible to reference the same block of code countless times, without the traditional Ctrl + C / Ctrl + V.

Let’s start with a practical example:

stages:
- deploy
- production
.template: &template
stage: deploy
cache:
key: site-package
policy: push
paths:
- ./build/project
artifacts:
name: "$CI_JOB_NAME-$CI_COMMIT_REF_NAME"
expire_in: 2hr20m
paths:
- ./build/project/
script:
- npm install
- npm run build
- npm run start
deploy to develop: 
<<: *template
deploy to production:
<<: *template
stage: production
cache:
key: site-package
policy: pull
script:
- npm run start

There’s a lot going on, so let’s break it down part by piece:

Each job definition that begins with a period is ignored. Therefore, .template does not define active and executable tasks. This feature is called hidden keys.
YAML allows you to reference other parts of yourself to avoid copying and pasting, thereby reducing the code. This resource is called anchor. In short:

.template: &template 
Onde &template é um alias que demos para o job .template,que por sua vez não será executado.

Basically the &template is the “copy” and the *template is the “paste”. So:

deploy to develop: 
<<: *template
Onde <<: *template vai trazer tudo o que foi definido no hidden job .template.
O código ficaria assim:
deploy to develop:
stage: deploy
cache:
key: site-package
policy: push
paths:
- ./build/project
artifacts:
name: "$CI_JOB_NAME-$CI_COMMIT_REF_NAME"
expire_in: 2hr20m
paths:
- ./build/project/
script:
- npm install
- npm run build
- npm run start

When calling “<<: *template” we are saying “do everything the job template does”. And everything that is described again or is declared, without existing in the anchor, is overwritten. Be a script, before_script, after_script, variable …

So in Production’s case the code would look like this:

# Com anchor
deploy to production:
<<: *template
stage: production
cache:
key: site-package
policy: pull
script:
- npm run start
# Sem anchor
deploy to production:
stage: production
cache:
key: site-package
policy: pull
paths:
- ./build/project
artifacts:
name: "$CI_JOB_NAME-$CI_COMMIT_REF_NAME"
expire_in: 2hr20m
paths:
- ./build/project/
script:
- npm run start

Here is the CI Lint demonstrating what will be done:

Gitlab: CI Lint

Therefore, use and abuse hidden keys and anchors. Is all code required to have a hidden key? No. This is not a mandatory part, as it depends a lot on each case and on how your DevOps cycle is. But in almost every pipeline you can dock an anchor to help “wipe” your code, making it more legible and with less effort.