This post provides some guidelines on how to set up a .gitlab-ci.yml definition file.

Tools

We assume that the reader already has some knowledge of the following tools:

  • gitlab/ci interactions via gitlab-runner
  • gitlab-ci.yml concepts and syntax
  • gitlab.inria.fr UI (CI initialization, pipelines, jobs, artifacts, gitlab-pages, etc.)
  • pixi usage

Using the include/extend directives of gitlab-ci.yml

In order to simplify the .gitlab-ci.yml content and ease its debugging, we use the following techniques:

  • Use include in the .gitlab-ci.yml file: this allows you to share instructions between different git/gitlab projects or different jobs. You can think of these as “macros”. Example:
include:
  - ".gitlab-ci/pages.yml"
  - ".gitlab-ci/build_conda.yml"
  - ".gitlab-ci/memcheck.yml"

These instructions will include the jobs/instructions from the files in the current git repository.

  • Of course, you can also include files defined in another repository. The given repository should be accessible from the current repository, e.g., by being in the same group or being public:
include:
  - project: 'dtk/dtk-ci'
    file: 'pixi-common.yaml'
    ref: main

This block will include all job definitions available in the file pixi-common.yaml from the git@gitlab.inria.fr:dtk/dtk-ci repository. All repositories in the dtk group will have access to this file.

  • Use the extend directive: this allows you to use a job defined previously, potentially modifying it if necessary:

Example: let’s suppose that pixi-common.yaml contains the following definition:

.build_unix:
  script:
    - echo "=== Running on $HOSTNAME"
    - mkdir build
    - cd build
    - pixi run cmake ..
    - pixi run cmake --build . --config Release --parallel
    - pixi run cmake --build . --config Release --parallel --target install

You can extend it this way:

include:
  - project: 'dtk/dtk-ci'
    file: 'pixi-common.yaml'
    ref: main

build-unix:
  extends: .build_unix
  needs: []
  parallel:
    matrix:
      - os_version: [osx-x86_64, osx-arm64, linux-x86_64, linux-aarch64]
  tags:
     - ${os_version}

For all 4 OS/architectures, the same commands will be used to build/install the software. And this will be the full content of your .gitlab-ci.yml file !!!

Remarks:

  • By (our) convention, macro names start with .
  • You can cascade extends, but you cannot cascade scripts in an extends chain (a workaround is to use before-script, but it also has its limits. See the pixi-common.yaml file if you want an example).

Using pixi tasks

Defining pixi tasks in the pixi.toml provides several improvements:

  • You can define dependencies between tasks (task build must run before task test, task install must run before build, etc.)
  • You (when developing) and gitlab-runner will use the same commands (e.g., pixi run build)
  • It will simplify the content of the .gitlab-ci.yml file: only pixi run something instead of a list of commands
  • It may also simplify the README.md and documentation

Example:

[tasks]
configure = "cmake -G Ninja -S . -B build -DCMAKE_BUILD_TYPE=Release"
build = { cmd = "cmake --build ./build --target install", depends-on = ["configure"] }

The pixi version of .gitlab-ci.yml will contain:

script:
  - pixi run build

In a “previous” conda version, the file would have been:

script:
  - source /Users/ci/Miniconda3/etc/profile.d/conda.sh
  - conda create -y -n $CI_PROJECT_NAME
  - mamba env update -f pkg/env/$CI_PROJECT_NAME.yaml
  - conda activate $CI_PROJECT_NAME
  - mkdir build
  - cd build
  - cmake .. -DCMAKE_BUILD_TYPE=Release
  - make