General guidelines
Based on experience, the guidelines below apply to all uses of GitLab CICD, regardless of whether in a library project.
Know the pipeline types
GitLab CICD runs three distinct types of pipelines:
- Branch pipelines, which run by default on any push that changes a branch, as well as most manual and scheduled pipeline runs
- Tag pipelines, which run by default on any push that changes a tag
- Merge Request pipelines which run under some conditions on pushes to a branch managed by a merge request, as well as manual pipeline runs from the merge request form
Without attention, a project can end up with multiple pipelines running on the same push, pipelines triggering other pipelines in a loop, or simple confusion. The patterns described under pipeline conditions help to simplify things.
Leverage stages for visual flow and dependency openness
Both needs:
and stage:
can be used to define the order in which jobs run. Some guidelines:
- Without
needs:
ordependencies:
a job runs when all the previous stages finish, and gets all the artifacts from all previous stages - If a job has any
needs:
at all, it will run when the needed jobs are done, potentially out of stage order - also then only gets artifacts from listed jobs - Use
dependencies:
to optimize artifact downloads (rarely necessary) needs:
can be used within a stage, but can look a little confusing in the web UI (where jobs are sorted alphabetically by default)stage:
allows control over how jobs are grouped together in both the pipeline page and the pipelines list- Define meaningful stages and let the artifacts flow to take advantage of the setenv/getenv pattern
Use base jobs to avoid global defaults
In CICD YAML, the globally-defined image:
keyword is deprecated in favour of the default:
keyword. Just keep in mind that the default:
will apply to every job in the pipeline that doesn't define it's own image (or control defaults). Once the use of GitLab CICD becomes more sophisticated, with imports:
and components, the global settings become confusing. Instead, use base jobs (called hidden jobs in the documentation) to reuse configuration. A simple example:
.maven:
image: maven:3.8.7-openjdk-18-slim
variables:
MAVEN_CLI_OPTS: >-
-Dmaven.repo.local=.m2/repository
cache:
paths:
- .m2/repository
key: maven
maven-build:
extends: [.maven]
script:
- mvn build ${MAVEN_CLI_OPTS}
maven-deploy:
extends: [.maven]
...
Avoid Git pushes in pipelines
I advise against performing Git operations (other than tagging) in a CICD pipeline, for several reasons:
- The Git protocol is designed for source code repositories; CICD operations happen strictly downstream
- GitLab's Job artifacts, Package registry, and Container registry capabilities provide managed, access-control mechanisms to store downstream information, avoiding the need to commit files such as build products back into a Git repository
- GitLab's Releases and Environments capabilities provide mechanisms to track, control, and roll back deployments, avoiding the need for a "release tracking branch"
- Without careful attention to detail, it's possible to accidentally set up CICD loops, where a Git push triggers a CICD run, which triggers another Git push, etc
In the event a Git push operation seems necessary, the operation would require either a deploy key with "Read-write" permission or an access token with write_repository
permission. Access tokens expire (maximum expiration period of a year) and must be rotated. Read the documentation in detail before selecting and implementing an approach.