GitLab CI Examples¶
This page collects some example snippets of GitLab CI configurations used to build, package, and publish with Nitrile.
Linux builds¶
The following is a very simple example to build a package. When the pipeline is run for a tag, it publishes the package to the registry.
Because builds by default run on an x64 Linux system, this will create a package for this platform.
image: cleanlang/nitrile # it's a good idea to specify the version here
stages: [build, publish]
build-linux-x64:
stage: build
before_script:
- nitrile update
- nitrile fetch
script:
- nitrile build
- nitrile package
artifacts:
paths:
- *.tar.gz
publish:
stage: publish
rules:
- if: $CI_COMMIT_TAG
script:
- nitrile publish --targets=linux-x64
x86¶
To build for x86, specify --arch=x86
:
build-linux-x86:
stage: build
before_script:
- nitrile update
- nitrile --arch=x86 fetch
script:
- nitrile --arch=x86 build
- nitrile --arch=x86 package
artifacts:
paths:
- *.tar.gz
Windows builds¶
The following is a minimal example to build a package on Windows:
build-windows-x64:
tags: [saas-windows-medium-amd64]
before_script:
- $Env:NitrileVersion = '0.4.0' # Or some other version
- Set-ExecutionPolicy ByPass -Scope Process -Force
- (New-Object System.Net.WebClient).DownloadString('https://clean-lang.org/install.ps1') | powershell -Command -
- $Env:PATH += ";${Env:APPDATA}\Nitrile\bin"
- nitrile update
- nitrile fetch
script:
- nitrile build
- nitrile package
artifacts:
paths:
- *.tar.gz
Compiling C code¶
If you need to compile C code using the Microsoft C Compiler, you need to get
some environment variable settings from a script called vcvarsall.bat
. These
settings need to be imported into the PowerShell instance, which can be done by
adding the following at the top of your before_script
:
build-windows-x64:
before_script:
# We need to get the environment set by a batch script; see https://stackoverflow.com/a/41399983:
- >-
cmd /c '"C:\Program Files (x86)\Microsoft Visual Studio\2022\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" amd64 & set'
| select-string '^([^=]*)=(.*)$'
| foreach-object { [Environment]::SetEnvironmentVariable($_.Matches[0].Groups[1].Value, $_.Matches[0].Groups[2].Value) }
This adds programs like cl
to your PATH
.
Catching errors¶
Warning
By default, native commands (.exe
files) do not participate in the
PowerShell error stream. This means that non-zero exit codes of native
commands cannot be caught as errors by Nitrile, so that nitrile build
(and
other commands) may succeed even if there were errors.
To make the behaviour more intuitive, make sure that you are using PowerShell 7.3 or higher with the experimental feature PSNativeCommandErrorActionPreference enabled. This makes sure that non-zero exit codes end up in the error stream so that Nitrile can pick them up:
build-windows-x64:
before_script:
- pwsh -Command 'Enable-ExperimentalFeature PSNativeCommandErrorActionPreference'
This will become the default behaviour once
PSNativeCommandErrorActionPreference
becomes a stable feature; see
issue #24 for
tracking.
Generic builds¶
If you are packaging a library, it may be that the package is the same for
every platform. In this case you can specify any
as the platform and/or
architecture, using the global options
--arch
and
--platform
.
Warning
To use this feature you should be absolutely sure that your library works for
all the targets included by any
. For example, if you are distributing some
object or library files as part of your library, it is not fully generic.
If your library is fully generic, you could use something like the following.
Note that we specify --arch=any --platform=any
when packaging and any-any
as the target for nitrile publish
:
image: cleanlang/nitrile # it's a good idea to specify the version here
stages: [build]
build:
stage: build
script:
# probably no update, fetch, and build needed if you have a generic package
- nitrile --arch=any --platform=any package
- '[ "$CI_COMMIT_TAG" = "" ] || nitrile publish --targets=any-any'
artifacts:
paths:
- *.tar.gz
If you have a separate Linux and Windows version, but are not interested in
different architectures and bitwidths, you might use a configuration like the
one below. Note that we still specify --arch=any
and use linux-any
and
windows-any
as the targets for nitrile publish
.
Info
If you publish overlapping packages to the registry, the behaviour is
undefined. For instance, if you publish a linux-any
package and a
linux-x64
package, a Linux x64 user may get either when they have your
package as a dependency. As a package author you are responsible for making
sure that there is no overlap in the set of packages that you publish to the
registry.
stages: [build, publish]
build-linux:
stage: build
script:
# optionally update, fetch, build...
- nitrile --arch=any package
artifacts:
paths:
- *.tar.gz
build-windows-x64:
tags: [saas-windows-medium-amd64]
before_script:
- Set-ExecutionPolicy ByPass -Scope Process -Force
- (New-Object System.Net.WebClient).DownloadString('https://clean-lang.org/install.ps1') | powershell -Command -
- $Env:PATH += ";${Env:APPDATA}\Nitrile\bin"
script:
- nitrile --arch=any package
artifacts:
paths:
- *.tar.gz
publish:
stage: publish
rules:
- if: $CI_COMMIT_TAG
script:
- nitrile publish --targets=linux-any,windows-any
Avoiding duplicate builds on branches, merge requests, and tags¶
You probably want to run only one pipeline for a commit in a merge request. By default, two are created: one for the branch and one for the merge request. The same thing happens with tags.
The following snippet at the top-level of .gitlab-ci.yml
ensures that you
get:
- A detached merge request pipeline for commits in a merge request.
- A tag pipeline for tags.
- A branch pipeline for all other commits.
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS'
when: never
- if: '$CI_COMMIT_BRANCH && $CI_COMMIT_TAG'
when: never
- if: '$CI_COMMIT_TAG'
- if: '$CI_COMMIT_BRANCH'
No separate publish job when there is only one build¶
When you have only one build job, you could publish from that job instead of
using a separate publish
stage. Just be sure that you only publish tags.
For Linux, add the following at the end of the script
:
- '[ "$CI_COMMIT_TAG" = "" ] || nitrile publish'
For Windows you can use:
- If (Test-Path variable:CI_COMMIT_TAG) { nitrile publish }
Parallelizing tests¶
GitLab CI allows you to parallelize jobs with the
parallel
keyword. You can use
this to parallelize tests over multiple jobs:
test:
parallel: 5
script:
- nitrile test --test-runner-options=parallel:$CI_NODE_INDEX:$CI_NODE_TOTAL
To parallelize property tests, it can be useful to define a separate job to build the property tests. This avoids building the same tests in each instance of the parallelized job. You can then pass the executables to a second job which actually runs them:
build-tests:
script:
- nitrile test --property-tester-options=compile-only
artifacts:
paths:
- nitrile-tests
run-tests:
needs: [build-tests]
parallel: 5
script:
- nitrile test --property-tester-options=no-regenerate --test-runner-options=parallel:$CI_NODE_INDEX:$CI_NODE_TOTAL