CLCI Gitlab CI v2.0.0 ΒΆ
Gitlab CI is the default CI solution for projects hosted on Gitlab. While in-depth knowledge of how Gitlab CI works is not needed to get very basic pipelines set up using this project, it can be useful when attempting to build more complicated pipelines. See https://docs.gitlab.com/ee/ci/ for more documentation. The repository for this project is located at https://gitlab.common-lisp.net/clci/gitlab-ci.
Gitlab CI ultimately requires one or more YAML files that describe the jobs to perform. This project is written using a single org file (this file) that is then tangled in order to produce the various YAML files consumed by Gitlab CI. This file is also exported to produce documentation.
In order to produce the YAML files, run org-babel-tangle
(typically bound to C-c C-v t
). Tangling produces the following files:
definitions.gitlab-ci.yml: Basic definitions that are used to build up more complicated jobs and pipelines.
linux-test-pipeline.gitlab-ci.yml: A pipeline that runs tests on Linux systems.
guarded-linux-test-pipeline.gitlab-ci.yml: A pipeline that includes
linux-test-pipeline.gitlab-ci.yml
if allowed by the value of$PIPELINE_TYPE
.clpm-dep-update-pipeline.gitlab-ci.yml: A pipeline that updates dependencies managed by CLPM.
guarded-clpm-dep-update-pipeline.gitlab-ci.yml: A pipeline that includes
clpm-dep-update-pipeline.gitlab-ci.yml
if allowed by the value of$PIPELINE_TYPE
.release-pipeline.gitlab-ci.yml: A pipeline that cuts releases when tags are pushed.
guarded-release-pipeline.gitlab-ci.yml: A pipeline that includes
release-pipeline.gitlab-ci.yml
if allowed by the value of$PIPELINE_TYPE
and the commit is a tag that looks like a release.
Currently, this project only works on Linux runners (and may Mac runners if you configure them correctly). However, first-class Windows and MacOS support is on the roadmap. This support is likely to arrive because this project is an offshoot of another (private) project that does have Windows and MacOS support. We mostly just need to get some runners for testing.
Quickstart
This section describes how to set up Gitlab CI for a CL-based project using these helpers. Gitlab CI has a dizzying amount of flexibility, so this quickstart will quickly get you something that works and will be sufficient for many use cases. But you may want to dive deeper into this project or Gitlab CI at some point to perform more advanced tasks.
Prep
This section describes setup that you must perform other than modifying your .gitlab-ci.yml
file.
Testing
In order to use the test pipeline, you must provide a method to run your tests (this project does not attempt to guess how they should be run). You must provide either a Makefile target to run your tests or write a script for the CI helpers to run.
Create a file called scripts/ci-test.lisp
(alternatively, set $CLCI_TEST_SCRIPT
to point to another file). This file will be loaded (with cl:load
) into a CL process that has ASDF available (and your chosen dependency manager, if applicable). This file must either enter the debugger (by signaling an uncaught error) or exit with a non-zero exit code ((uiop:quit 1)
) if your tests fail.
For most projects, the contents of this file should be as simple as:
(asdf:test-system "my-cool-system")
NOTE: If you have a Makefile
in your repo, the helpers will instead run make test
(after setting some environment variables). If you wish to disable this behavior, set $CLCI_TEST_USE_MAKEFILE
to no
.
Release
In order to use the release pipeline, you should create a CHANGELOG.md
file in your repo. The first level heading (line starting with a single #
) should be your project name. The second level headings (starting with ##
) should start with the version number and the contents should describe the changes to your project. See the CHANGELOG.md
file in this repo for an example.
Additionally, you must protect your release tags. Go to "Settings > Repository > Protected Tags" and protect v*
.
Then, when you're ready to make a release, push a tag of the form v$VERSION_NUMBER
.
Update CLPM bundle
If you are using CLPM for your dependency management, you can use these helpers to periodically update your lock file for you.
To do this, you should create a bot for your project that can open merge requests. Go to "Settings > Access Tokens" and create a token with write_repository
and api
permissions. Then create a CI variable ("Settings > CI/CD > Variables") called CLCI_MR_TOKEN
, whose value is the token you got from the first step.
Last, you should create a scheduled job to check for updates to your dependencies. Go to "CI/CD > Schedules". Create a new scheduled job for your default branch that sets PIPELINE_TYPE
to clpm-dep-update
.
.gitlab-ci.yml
Copy the following to .gitlab-ci.yml
in your repo. Be sure to read the comments, as they give some hints on customizations that may be appropriate for you.
include:
project: 'clci/gitlab-ci'
ref: v2-stable
file:
- definitions.gitlab-ci.yml
- guarded-linux-test-pipeline.gitlab-ci.yml
- guarded-release-pipeline.gitlab-ci.yml
# Uncomment if you are using CLPM and want to automatically update your
# bundle.
#
# - guarded-clpm-dep-update-pipeline.gitlab-ci.yml
variables:
# Uncomment if you want to use Quicklisp as your dependency manager during
# tests.
#
# CLCI_DEPENDENCY_MANAGER: "quicklisp"
#
# Uncomment if you have Git submodules that you want the runner to
# automatically init and update for you. Submodules are sometimes used by
# projects to bundle their test dependencies.
#
# GIT_SUBMODULE_STRATEGY: recursive
#
# Uncomment these lines if you want to test against Allegro, you have read
# the Allegro express license
# <https://franz.com/ftp/pub/legal/ACL-Express-20170301.pdf>, *and* your use
# of Allegro Express does not violate the license. Alternatively, uncomment
# and provide your own Docker image (or runner) that has Allegro installed
# with your actual license.
#
# CLCI_TEST_ALLEGRO: "yes"
# I_AGREE_TO_ALLEGRO_EXPRESS_LICENSE: "yes"
# This section is not strictly required, but prevents Gitlab CI from launching
# multiple redundent pipelines when a Merge Request is opened.
workflow:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
- if: '$CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS'
when: never
- if: '$CI_COMMIT_BRANCH'
- if: '$CI_COMMIT_TAG'
FAQs
This project is still very new, so I can't really say that these questions are frequently asked, but I imagine they would be :).
How do I install a non-CL dependency before running tests?
First, make sure your dependency isn't already installed. The default Linux Docker images are based on the buildpack-deps image, which includes a lot of commonly used libraries.
If you really need to install something before your tests run, add the following to your .gitlab-ci.yml
:
.common:test:clci:
before_script:
- apt-get update
- apt-get install -y foo bar baz
How do I use CLPM as my dependency manager?
Just commit your clpmfile.lock
(in the root of your repo) without setting $CLCI_DEPENDENCY_MANAGER
and the helpers will take care of the rest.
How do I test using dependencies from Ultralisp?
Set $CLCI_DEPENDENCY_MANAGER
to quicklisp
. Then set $CLCI_QL_DIST_NAME
to ultralisp
.
How do I test against both Quicklisp and Ultralisp?
Add the following to your .gitlab-ci.yml
:
.common:test:clci:
parallel:
matrix:
- CLCI_QL_DIST_NAME: [quicklisp, ultralisp]
How do I test against both the ASDF bundled with the implementation and the latest released ASDF?
Add the following to your .gitlab-ci.yml
:
.common:test:clci:
parallel:
matrix:
- CLCI_ASDF_VERSION: [REQUIRE, latest]
How do I generate documentation (or any other CL-based task)?
Create a CL file in your repo that does what you want and enters the debugger or exits with a non-zero status if it fails. Then add a job in your .gitlab-ci.yml
:
generate docs:
extends:
- .clci sbcl
- .clci DEPENDENCY_MANAGER script
variables:
CLCI_SCRIPT: path/to/script.lisp
artifacts:
paths:
- doc/
Where DEPENDENCY_MANAGER
is replaced with asdf
(no dependency manager), clpm
, or quicklisp
. In the future, a more flexible job may be added that choses the correct dependency manager based on the value of $CLCI_DEPENDENCY_MANAGER
, but that will require a non-trivial amount of refactoring to support.
Your script will then be loaded into a CL process that has ASDF and your dependency manager (if applicable) available.
Utilities
This section contains some definitions that are tangled into other definitions and, as such, are not directly accessible to users. However, they are included in the documentation for reference purposes.
Single Implementation Scripts
Each CL implementation has its own CLI, resulting in different ways to run scripts for each of them. It'd be great if we could use cl-launch for this purpose, but it doesn't work on Windows and is too opinionated when it comes to ASDF (it requires a minimum version of ASDF). Additionally, Roswell might be nice, but it's too heavyweight to bring in for just a unified CLI interface. It's also very opinionated in different areas than cl-launch.
Therefore, we end up with these helpers. When tangled into other source blocks, they provide the correct command to start a Lisp, disable init scripts, and load a file. The process exits with a non-zero code if the debugger is entered.
ABCL
abcl --noinit --nosystem --batch --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit :status 1)))) (load \"$_clci_script\"))"
Allegro
alisp --qq --batch --backtrace-on-error -L "$_clci_script"
CCL
ccl -n -b --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ccl:quit 1)))) (load \"$_clci_script\"))"
CLASP
clasp -N --norc --load "$_clci_script"
CLISP
clisp -ansi -norc -x "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit 1)))) (load \"$_clci_script\"))"
CMUCL
cmucl -noinit -eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (unix:unix-exit 1)))) (load \"$_clci_script\") (unix:unix-exit 0))"
ECL
ecl --norc --shell "$_clci_script"
SBCL
sbcl --disable-ldb --lose-on-corruption --no-sysinit --disable-debugger --script "$_clci_script"
Multi Implementation Scripts
This section contains snippets that can be expanded into other source blocks to run a CL script. It chooses the implementation to run based on the $LISP
environment variable.
Run CL script
case "$LISP" in
abcl)
abcl --noinit --nosystem --batch --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit :status 1)))) (load \"$_clci_script\"))" || exit 1
;;
allegro)
alisp --qq --batch --backtrace-on-error -L "$_clci_script" || exit 1
;;
ccl)
ccl -n -b --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ccl:quit 1)))) (load \"$_clci_script\"))" || exit 1
;;
clasp)
clasp -N --norc --load "$_clci_script" || exit 1
;;
clisp)
clisp -ansi -norc -x "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit 1)))) (load \"$_clci_script\"))" || exit 1
;;
cmucl)
cmucl -noinit -eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (unix:unix-exit 1)))) (load \"$_clci_script\") (unix:unix-exit 0))" || exit 1
;;
ecl)
ecl --norc --shell "$_clci_script" || exit 1
;;
sbcl)
sbcl --disable-ldb --lose-on-corruption --no-sysinit --disable-debugger --script "$_clci_script" || exit 1
;;
*)
echo "Unkown LISP: $LISP"
exit 1
;;
esac
CLPM Run CL script
Run a script using CLPM, using the $LISP
environment variable to determine which implementation to run.
case "$LISP" in
abcl)
$CLPM bundle exec -- abcl --noinit --nosystem --batch --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit :status 1)))) (load \"$_clci_script\"))" || exit 1
;;
allegro)
$CLPM bundle exec -- alisp --qq --batch --backtrace-on-error -L "$_clci_script" || exit 1
;;
ccl)
$CLPM bundle exec -- ccl -n -b --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ccl:quit 1)))) (load \"$_clci_script\"))" || exit 1
;;
clasp)
$CLPM bundle exec -- clasp -N --norc --load "$_clci_script" || exit 1
;;
clisp)
$CLPM bundle exec -- clisp -ansi -norc -x "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit 1)))) (load \"$_clci_script\"))" || exit 1
;;
cmucl)
$CLPM bundle exec -- cmucl -noinit -eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (unix:unix-exit 1)))) (load \"$_clci_script\") (unix:unix-exit 0))" || exit 1
;;
ecl)
$CLPM bundle exec -- ecl --norc --shell "$_clci_script" || exit 1
;;
sbcl)
$CLPM bundle exec -- sbcl --disable-ldb --lose-on-corruption --no-sysinit --disable-debugger --script "$_clci_script" || exit 1
;;
*)
echo "Unkown LISP: $LISP"
exit 1
;;
esac
Job Definitions
This section produces the definitions.gitlab-ci.yml
file.
All of these jobs are hidden by default, meaning that including this file will result in no jobs being added to your pipeline.
All jobs now and in the future will start with .clci
. If a job starts with ._clci
or an environment variable starts with a _
, then its continued existence and semantics are not guaranteed.
At the present time, we do not support any modifications to these jobs, other than overriding variable values that do not start with _
.
It is recommended that you extend, or !reference these jobs to include their functionality in other jobs.
ASDF
This section contains definitions to use ASDF.
Variables
These variables are set by default:
CLCI_ASDF_CACHE_KEY: $CI_JOB_NAME-clci-asdf
CLCI_ASDF_VERSION: latest
_CLCI_ASDF_CACHE_PATH: $CI_PROJECT_DIR/.clci-cache/asdf
Cache
Reference this in a cache list to get caching of ASDF files.
.clci asdf cache: &clci_asdf_cache
key: $CLCI_ASDF_CACHE_KEY
paths:
- .clci-cache/asdf/
Download ASDF
Download ASDF version $CLCI_ASDF_VERSION
and build asdf.lisp. Requires that make
and curl
are installed.
Downloads code directly from ASDF's git repo. Can download any tag (technically any reference, but if you are caching you should not use branch names). Will store the code in the CI cache.
If $CLCI_ASDF_VERSION
is not set, empty, or "REQUIRE", this does nothing.
Exports the following env vars:
ASDF_VERSION
: The version actually downloaded (in case CLCIASDFVERSION is "latest").ASDF_DIR
: The directory where ASDF is downloaded.ASDF_LISP
: The path to the asdf.lisp file.
.clci download asdf:
script: &clci_download_asdf_script
- |
if [ "z$CLCI_ASDF_VERSION" = "z" ]; then
echo "CLCI_ASDF_VERSION not set. Skipping downloading ASDF."
elif [ "$CLCI_ASDF_VERSION" = "REQUIRE" ]; then
echo "CLCI_ASDF_VERSION set to REQUIRE. Skipping downloading ASDF."
else
if [ "$CLCI_ASDF_VERSION" = "latest" ]; then
ASDF_VERSION=3.3.5
else
ASDF_VERSION="$CLCI_ASDF_VERSION"
fi
ASDF_DIR="$_CLCI_ASDF_CACHE_PATH/asdf-$ASDF_VERSION"
ASDF_LISP="$ASDF_DIR/build/asdf.lisp"
if [ -e "$ASDF_LISP" ]; then
echo "ASDF $ASDF_VERSION already downloaded."
else
echo "Downloading ASDF $ASDF_VERSION"
mkdir -p "$_CLCI_ASDF_CACHE_PATH"
_clci_asdf_loc="$(mktemp)"
curl -fsSL "https://gitlab.common-lisp.net/asdf/asdf/-/archive/$ASDF_VERSION/asdf-$ASDF_VERSION.tar.gz" > "$_clci_asdf_loc"
tar x -z -f "$_clci_asdf_loc" -C "$_CLCI_ASDF_CACHE_PATH"
( cd "$_CLCI_ASDF_CACHE_PATH/asdf-$ASDF_VERSION/" && make ) || exit 1
echo "ASDF $ASDF_VERSION downloaded"
fi
echo "(:source-registry-cache)" > "$_CLCI_ASDF_CACHE_PATH/.cl-source-registry.cache"
export ASDF_DIR
export ASDF_LISP
fi
Install ASDF
Make it so that ASDF can be found and self upgraded by itself. Adds $ASDF_DIR
to ASDF's search path by adding it to ~/.config/common-lisp/source-registry.conf.d/50-cici-asdf.conf
. Does nothing if $ASDF_DIR
is not set or empty.
.clci install asdf:
script: &clci_install_asdf_script
- |
if [ "z$ASDF_DIR" = "z" ]; then
echo "ASDF_DIR not set. Skipping installing ASDF."
else
mkdir -p ~/.config/common-lisp/source-registry.conf.d/
echo "(:tree \"$ASDF_DIR\")" > ~/.config/common-lisp/source-registry.conf.d/50-cici-asdf.conf
echo "$ASDF_DIR added to ASDF source registry."
fi
Compile ASDF
Compile the asdf.lisp file at $ASDF_LISP
into a fasl. If $ASDF_LISP
is not set, does nothing.
Exports $ASDF_FASL
, the path to the generated fasl.
Requires that $LISP
is set.
.clci compile asdf:
script: &clci_compile_asdf_script
- |
if [ "z$ASDF_LISP" = "z" ] || [ "z$LISP" = "z" ]; then
echo "ASDF_LISP or LISP not set. Skipping ASDF compilation."
else
_clci_asdf_fasl_file="$(mktemp)"
_clci_script="$(mktemp)"
cat > "$_clci_script" <<EOF
(require "asdf")
(let* ((fasl-type (pathname-type (compile-file-pathname "$ASDF_LISP")))
(output-pn (merge-pathnames (make-pathname
:directory (list :relative
(uiop:implementation-identifier))
:type fasl-type)
"$ASDF_LISP")))
(ensure-directories-exist output-pn)
(if (probe-file output-pn)
(with-open-file (s "$_clci_asdf_fasl_file" :direction :output
:if-exists :supersede)
(write-string (uiop:native-namestring output-pn) s))
(multiple-value-bind (output-truename warnings-p failure-p)
(compile-file "$ASDF_LISP" :output-file output-pn)
(if (probe-file output-pn)
(with-open-file (s "$_clci_asdf_fasl_file" :direction :output
:if-exists :supersede)
(write-string (uiop:native-namestring output-pn) s))
(uiop:quit 1)))))
(uiop:quit 0)
EOF
case "$LISP" in
abcl)
abcl --noinit --nosystem --batch --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit :status 1)))) (load \"$_clci_script\"))" || exit 1
;;
allegro)
alisp --qq --batch --backtrace-on-error -L "$_clci_script" || exit 1
;;
ccl)
ccl -n -b --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ccl:quit 1)))) (load \"$_clci_script\"))" || exit 1
;;
clasp)
clasp -N --norc --load "$_clci_script" || exit 1
;;
clisp)
clisp -ansi -norc -x "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit 1)))) (load \"$_clci_script\"))" || exit 1
;;
cmucl)
cmucl -noinit -eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (unix:unix-exit 1)))) (load \"$_clci_script\") (unix:unix-exit 0))" || exit 1
;;
ecl)
ecl --norc --shell "$_clci_script" || exit 1
;;
sbcl)
sbcl --disable-ldb --lose-on-corruption --no-sysinit --disable-debugger --script "$_clci_script" || exit 1
;;
*)
echo "Unkown LISP: $LISP"
exit 1
;;
esac
if [ -e "$_clci_asdf_fasl_file" ]; then
ASDF_FASL="$(cat "$_clci_asdf_fasl_file")"
export ASDF_FASL
else
echo "Unable to determine fasl location."
exit 1
fi
fi
ASDF Job
This job is meant to be extended. It provides a cache entry for ASDF, as well as downloading, installing, and compiling it in a before script.
.clci asdf job:
before_script:
- *clci_download_asdf_script
- *clci_install_asdf_script
- *clci_compile_asdf_script
cache:
- *clci_asdf_cache
ASDF Script
This job is meant to be extended. It provides cache entries for ASDF, as well as downloading, installing and compiling ASDF. You can add your own before_script
. You must define a variable CLCI_SCRIPT
containing the path to a script to be run as the last step of script
.
.clci asdf script:
script:
- *clci_download_asdf_script
- *clci_install_asdf_script
- *clci_compile_asdf_script
- _clci_script="$(mktemp)"
- |
if [ "z$ASDF_FASL" = "z" ]; then
if [ ! "z$ASDF_LISP" = "z" ]; then
echo "(load \"$ASDF_LISP\")" >> "$_clci_script"
fi
else
echo "(load \"$ASDF_FASL\")" >> "$_clci_script"
fi
- |
if [ "$CLCI_ASDF_VERSION" = "REQUIRE" ]; then
echo '(require "asdf")' >> "$_clci_script"
fi
- |
echo "(load \"$CLCI_SCRIPT\")" >> "$_clci_script"
- echo "Running script:"
- cat "$_clci_script"
- |
case "$LISP" in
abcl)
abcl --noinit --nosystem --batch --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit :status 1)))) (load \"$_clci_script\"))" || exit 1
;;
allegro)
alisp --qq --batch --backtrace-on-error -L "$_clci_script" || exit 1
;;
ccl)
ccl -n -b --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ccl:quit 1)))) (load \"$_clci_script\"))" || exit 1
;;
clasp)
clasp -N --norc --load "$_clci_script" || exit 1
;;
clisp)
clisp -ansi -norc -x "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit 1)))) (load \"$_clci_script\"))" || exit 1
;;
cmucl)
cmucl -noinit -eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (unix:unix-exit 1)))) (load \"$_clci_script\") (unix:unix-exit 0))" || exit 1
;;
ecl)
ecl --norc --shell "$_clci_script" || exit 1
;;
sbcl)
sbcl --disable-ldb --lose-on-corruption --no-sysinit --disable-debugger --script "$_clci_script" || exit 1
;;
*)
echo "Unkown LISP: $LISP"
exit 1
;;
esac
cache:
- *clci_asdf_cache
CLPM
This section contains definitions for using CLPM.
Variables
CLCI_CLPM_CACHE_KEY: clci-clpm-releases
CLCI_CLPM_VERSION: latest
_CLCI_CLPM_CACHE_PATH: $CI_PROJECT_DIR/.clci-cache/clpm
# Use Dexador as the default HTTP client for CLPM. There seems to
# occasionally be issues with Drakma and Gitlab.
CLPM_HTTP_CLIENT_TYPE: "dexador"
CLPM Cache
Include in jobs that use CLPM to cache the results.
The job .clci clpm cache variables
is meant to be extended. It sets some environment variables to ensure that CLPM stores things in the appropriate folders in the cache.
The jobs .clci clpm release cache
and .clci clpm cache
are meant to be included in cache lists via !reference
.
.clci clpm cache variables:
variables:
CLPM_CACHE_DIR: $CI_PROJECT_DIR/.clci-cache/clpm/cache
CLPM_DATA_DIR: $CI_PROJECT_DIR/.clci-cache/clpm/data
.clci clpm release cache: &clci_clpm_release_cache
key: $CLCI_CLPM_CACHE_KEY
paths:
- .clci-cache/clpm/releases
when: always
.clci clpm cache: &clci_clpm_cache
key:
files:
- clpmfile.lock
prefix: $CI_JOB_NAME
paths:
- .clci-cache/clpm/data
- .clci-cache/clpm/cache
Download CLPM
Download CLPM version $CLCI_CLPM_VERSION
for $CLCI_CLPM_OS
on $CLCI_CLPM_ARCH
. Requires that curl
is installed.
If $CLCI_CLPM_VERSION
is empty, this does nothing. If $CLCI_CLPM_OS
or $CLCI_CLPM_ARCH
are empty, they are guessed from the current system.
Exports the following env vars:
$CLPM_VERSION
: The actual version downloaded (in case CLCICLPMVERSION is "latest").$CLPM_ARCHIVE
: The path to the downloaded CLPM archive.
.clci download clpm:
script: &clci_download_clpm_script
- |
if [ "z$CLCI_CLPM_VERSION" = "z" ]; then
echo "CLCI_CLPM_VERSION not set. Skipping downloading CLPM."
else
if [ "$CLCI_CLPM_VERSION" = "latest" ]; then
CLPM_VERSION=0.4.1
else
CLPM_VERSION="$CLCI_CLPM_VERSION"
fi
if [ "z$CLCI_CLPM_ARCH" = "z" ]; then
case $(uname -m) in
x86_64)
CLCI_CLPM_ARCH="amd64"
;;
aarch64)
CLCI_CLPM_ARCH="arm64"
;;
*)
echo "Unknown platform" >&2
exit 1
;;
esac
export CLCI_CLPM_ARCH
fi
if [ "z$CLCI_CLPM_OS" = "z" ]; then
case $(uname -s) in
Linux)
CLCI_CLPM_OS="linux"
;;
Darwin)
CLCI_CLPM_OS="darwin"
;;
MINGW*)
CLCI_CLPM_OS="windows"
;;
*)
echo "Unknown platform" >&2
exit 1
;;
esac
export CLCI_CLPM_OS
fi
if [ "$CLCI_CLPM_OS" = "windows" ]; then
_CLCI_CLPM_ARCHIVE_TYPE="zip"
else
_CLCI_CLPM_ARCHIVE_TYPE="tar.gz"
fi
_CLCI_CLPM_ARCHIVE_NAME="clpm-$CLPM_VERSION-$CLCI_CLPM_OS-$CLCI_CLPM_ARCH.$_CLCI_CLPM_ARCHIVE_TYPE"
CLPM_ARCHIVE="$_CLCI_CLPM_CACHE_PATH/releases/$_CLCI_CLPM_ARCHIVE_NAME"
mkdir -p "$_CLCI_CLPM_CACHE_PATH/releases/"
if [ -e "$CLPM_ARCHIVE" ]; then
echo "$_CLCI_CLPM_ARCHIVE_NAME already downloaded. Skipping."
else
echo "Downloading $_CLCI_CLPM_ARCHIVE_NAME"
curl -fsSL "https://files.clpm.dev/clpm/$_CLCI_CLPM_ARCHIVE_NAME" > "$CLPM_ARCHIVE"
fi
export CLPM_ARCHIVE
export CLPM_VERSION
fi
install clpm
A job to install CLPM. It must already be downloaded. $CLPM_ARCHIVE
must point to the archive.
CLPM is installed to $CLCI_CLPM_PREFIX
which defaults to $HOME/.local
.
Exports $CLPM
which points to the CLPM executable.
.clci install clpm:
script: &clci_install_clpm_script
- |
if [ ! -f "$CLPM_ARCHIVE" ]; then
echo "$CLPM_ARCHIVE does not exist."
exit 1
fi
# Unpack it.
- mkdir -p "${CLCI_CLPM_PREFIX:-$HOME/.local}"
- |
if [ "${CLPM_ARCHIVE%zip}" = "$CLPM_ARCHIVE" ]; then
# tar.gz
tar -C "${CLCI_CLPM_PREFIX:-$HOME/.local}" -xf "$CLPM_ARCHIVE" --exclude=install.sh --strip-components=1
export CLPM="${CLCI_CLPM_PREFIX:-$HOME/.local}/bin/clpm"
else
unzip "$CLPM_ARCHIVE" -d "${CLCI_CLPM_PREFIX:-$HOME/.local}"
export CLPM="${CLCI_CLPM_PREFIX:-$HOME/.local}/bin/clpm.exe"
fi
CLPM Job
This job is meant to be extended. It provides cache entries for ASDF and CLPM, as well as downloading, installing, and compiling ASDF, and downloading and installing CLPM.
.clci clpm job:
extends:
- .clci clpm cache variables
before_script:
- *clci_download_asdf_script
- *clci_install_asdf_script
- *clci_compile_asdf_script
- *clci_download_clpm_script
- *clci_install_clpm_script
cache:
- *clci_asdf_cache
- *clci_clpm_release_cache
- *clci_clpm_cache
CLPM Script
This job is meant to be extended. It provides cache entries for ASDF and CLPM, as well as downloading, installing and compiling ASDF, and downloading and installing CLPM. You can add your own before_script
. You must define a variable CLCI_SCRIPT
containing the path to a script to be run as the last step of script
.
.clci clpm script:
extends:
- .clci clpm cache variables
script:
- *clci_download_asdf_script
- *clci_install_asdf_script
- *clci_compile_asdf_script
- *clci_download_clpm_script
- *clci_install_clpm_script
- _clci_script="$(mktemp)"
- |
if [ "z$ASDF_FASL" = "z" ]; then
if [ ! "z$ASDF_LISP" = "z" ]; then
echo "(load \"$ASDF_LISP\")" >> "$_clci_script"
fi
else
echo "(load \"$ASDF_FASL\")" >> "$_clci_script"
fi
- |
if [ "$CLCI_ASDF_VERSION" = "REQUIRE" ]; then
echo '(require "asdf")' >> "$_clci_script"
fi
- |
echo "(load \"$CLCI_SCRIPT\")" >> "$_clci_script"
- $CLPM bundle install --no-resolve
- echo "Running script:"
- cat "$_clci_script"
- |
case "$LISP" in
abcl)
$CLPM bundle exec -- abcl --noinit --nosystem --batch --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit :status 1)))) (load \"$_clci_script\"))" || exit 1
;;
allegro)
$CLPM bundle exec -- alisp --qq --batch --backtrace-on-error -L "$_clci_script" || exit 1
;;
ccl)
$CLPM bundle exec -- ccl -n -b --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ccl:quit 1)))) (load \"$_clci_script\"))" || exit 1
;;
clasp)
$CLPM bundle exec -- clasp -N --norc --load "$_clci_script" || exit 1
;;
clisp)
$CLPM bundle exec -- clisp -ansi -norc -x "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit 1)))) (load \"$_clci_script\"))" || exit 1
;;
cmucl)
$CLPM bundle exec -- cmucl -noinit -eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (unix:unix-exit 1)))) (load \"$_clci_script\") (unix:unix-exit 0))" || exit 1
;;
ecl)
$CLPM bundle exec -- ecl --norc --shell "$_clci_script" || exit 1
;;
sbcl)
$CLPM bundle exec -- sbcl --disable-ldb --lose-on-corruption --no-sysinit --disable-debugger --script "$_clci_script" || exit 1
;;
*)
echo "Unkown LISP: $LISP"
exit 1
;;
esac
cache:
- *clci_asdf_cache
- *clci_clpm_release_cache
- *clci_clpm_cache
Common Lisp
Jobs, meant to be extended, for running different Common Lisp jobs.
Variables
CLCI_ABCL_IMAGE: containers.common-lisp.net/cl-docker-images/abcl
CLCI_ABCL_TAG: latest
CLCI_ALLEGRO_IMAGE: containers.common-lisp.net/cl-docker-images/allegro
CLCI_ALLEGRO_TAG: latest
CLCI_CCL_IMAGE: containers.common-lisp.net/cl-docker-images/ccl
CLCI_CCL_TAG: latest
CLCI_CLASP_IMAGE: containers.common-lisp.net/cl-docker-images/clasp
CLCI_CLASP_TAG: latest
CLCI_CLISP_IMAGE: containers.common-lisp.net/cl-docker-images/clisp
CLCI_CLISP_TAG: latest
CLCI_CMUCL_IMAGE: containers.common-lisp.net/cl-docker-images/cmucl
CLCI_CMUCL_TAG: latest
CLCI_ECL_IMAGE: containers.common-lisp.net/cl-docker-images/ecl
CLCI_ECL_TAG: latest
CLCI_SBCL_IMAGE: containers.common-lisp.net/cl-docker-images/sbcl
CLCI_SBCL_TAG: latest
ABCL
Armed Bear Common Lisp
.clci abcl:
image: $CLCI_ABCL_IMAGE:$CLCI_ABCL_TAG
variables:
LISP: abcl
Allegro
Allegro Common Lisp
.clci allegro:
image: $CLCI_ALLEGRO_IMAGE:$CLCI_ALLEGRO_TAG
variables:
LISP: allegro
CCL
Clozure Common Lisp
.clci ccl:
image: $CLCI_CCL_IMAGE:$CLCI_CCL_TAG
variables:
LISP: ccl
CLASP
clasp
.clci clasp:
image: $CLCI_CLASP_IMAGE:$CLCI_CLASP_TAG
variables:
LISP: clasp
CLISP
clisp
.clci clisp:
image: $CLCI_CLISP_IMAGE:$CLCI_CLISP_TAG
variables:
LISP: clisp
CMUCL
CMU Common Lisp
.clci cmucl:
image: $CLCI_CMUCL_IMAGE:$CLCI_CMUCL_TAG
variables:
LISP: cmucl
ECL
Embeddable Common Lisp
.clci ecl:
image: $CLCI_ECL_IMAGE:$CLCI_ECL_TAG
variables:
LISP: ecl
SBCL
Steel Bank Common Lisp
.clci sbcl:
image: $CLCI_SBCL_IMAGE:$CLCI_SBCL_TAG
variables:
LISP: sbcl
Quicklisp
Variables
These variables are set by default:
CLCI_QL_CACHE_KEY: $CI_JOB_NAME-clci-ql
CLCI_QL_CLIENT_VERSION: latest
CLCI_QL_DIST_NAME: quicklisp
CLCI_QL_DIST_VERSION: latest
_CLCI_QL_CACHE_PATH: $CI_PROJECT_DIR/.clci-cache/ql
Cache
Reference this in a cache list to get caching of QL files.
.clci ql cache: &clci_ql_cache
key: $CLCI_QL_CACHE_KEY
paths:
- .clci-cache/ql/
Download Quicklisp Installer
Download the Quicklisp installer. Requires that curl
and sha256sum are installed.
Exports the following env vars:
$QUICKLISP_INSTALLER
: The path to the downloaded Quicklisp installer.
.clci download ql installer:
script: &clci_download_ql_installer_script
- QUICKLISP_INSTALLER="$_CLCI_QL_CACHE_PATH/installer/quicklisp.lisp"
- |
if [ -e "$QUICKLISP_INSTALLER" ]; then
echo "Quicklisp installer already downloaded."
else
echo "Downloading Quicklisp installer."
mkdir -p "$_CLCI_QL_CACHE_PATH/installer/"
curl -fsSL "https://beta.quicklisp.org/quicklisp.lisp" > "$QUICKLISP_INSTALLER"
if echo "4a7a5c2aebe0716417047854267397e24a44d0cce096127411e9ce9ccfeb2c17 $QUICKLISP_INSTALLER" | sha256sum -c - ; then
echo "SHA256 verified"
else
echo "SHA256 validation of Quicklisp installer failed!"
rm "$QUICKLISP_INSTALLER"
exit 1
fi
fi
- export QUICKLISP_INSTALLER
Install Quicklisp
Install Quicklisp using a previously downloaded installer. Installs Quicklisp using the installer located at $QUICKLISP_INSTALLER
using the CL implementation specified by $LISP
. Requires that curl
is installed if the latest client or dist versions are used. Requires that sha256sum
is installed.
Its behavior can be configured using the following environment variables:
$CLCI_QL_CLIENT_VERSION
: The version of the Quicklisp client to install. Defaults tolatest
.$CLCI_QL_DIST_URL
: The URL to the Quicklisp dist to install. Defaults to empty. If empty, it is computed from$CLCI_QL_DIST_VERSION
and$CLCI_QL_DIST_NAME
.$CLCI_QL_DIST_VERSION
: The version of the dist to install. Defaults tolatest
. Ignored if$CLCI_QL_DIST_URL
is set.$CLCI_QL_DIST_NAME
: The name of the dist to install. Defaults toquicklisp
(the canonical QL dist). Also recognizesultralisp
. Ignored if$CLCI_QL_DIST_URL
is set.
It installs Quicklisp in a cache friendly way, in folders corresponding to both the concrete client version and concrete dist version.
Exports the following env vars:
$QUICKLISP_SETUP_LISP
: The path to the installed setup.lisp file.$QUICKLISP_DIST_URL
: The concrete URL to the installed dist.$QUICKLISP_CLIENT_VERSION
: The concrete client version installed.
.clci installer ql:
script: &clci_install_ql_script
- |
if [ "$CLCI_QL_CLIENT_VERSION" == "latest" ]; then
echo "Computing the concrete client version."
_ql_client_sexp="$(mktemp)"
curl -fsSL "https://beta.quicklisp.org/client/quicklisp.sexp" > "$_ql_client_sexp"
_clci_script="$(mktemp)"
_ql_version_out="$(mktemp)"
cat > "$_clci_script" <<EOF
(with-open-file (info "$_ql_client_sexp" :direction :input)
(with-open-file (out "$_ql_version_out" :direction :output :if-exists :supersede)
(let* ((*read-eval* nil)
(sexp (read info)))
(write-line (getf sexp :version) out))))
EOF
echo "Running script:"
cat "$_clci_script"
case "$LISP" in
abcl)
abcl --noinit --nosystem --batch --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit :status 1)))) (load \"$_clci_script\"))" || exit 1
;;
allegro)
alisp --qq --batch --backtrace-on-error -L "$_clci_script" || exit 1
;;
ccl)
ccl -n -b --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ccl:quit 1)))) (load \"$_clci_script\"))" || exit 1
;;
clasp)
clasp -N --norc --load "$_clci_script" || exit 1
;;
clisp)
clisp -ansi -norc -x "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit 1)))) (load \"$_clci_script\"))" || exit 1
;;
cmucl)
cmucl -noinit -eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (unix:unix-exit 1)))) (load \"$_clci_script\") (unix:unix-exit 0))" || exit 1
;;
ecl)
ecl --norc --shell "$_clci_script" || exit 1
;;
sbcl)
sbcl --disable-ldb --lose-on-corruption --no-sysinit --disable-debugger --script "$_clci_script" || exit 1
;;
*)
echo "Unkown LISP: $LISP"
exit 1
;;
esac
QUICKLISP_CLIENT_VERSION="$(cat "$_ql_version_out")"
else
QUICKLISP_CLIENT_VERSION="$CLCI_QL_CLIENT_VERSION"
fi
- export QUICKLISP_CLIENT_VERSION
- |
if [ "z$CLCI_QL_DIST_URL" == "z" ]; then
case "$CLCI_QL_DIST_NAME" in
quicklisp)
if [ "$CLCI_QL_DIST_VERSION" == "latest" ]; then
echo "Computing the concrete dist version."
_ql_distinfo="$(mktemp)"
curl -fsSL "https://beta.quicklisp.org/dist/quicklisp.txt" > "$_ql_distinfo"
CLCI_QL_DIST_VERSION="$(cat "$_ql_distinfo" | grep "^version: " | cut -c10- )"
fi
QUICKLISP_DIST_URL="http://beta.quicklisp.org/dist/quicklisp/$CLCI_QL_DIST_VERSION/distinfo.txt"
;;
ultralisp)
if [ "$CLCI_QL_DIST_VERSION" == "latest" ]; then
echo "Computing the concrete dist version."
_ql_distinfo="$(mktemp)"
curl -fsSL "https://dist.ultralisp.org/" > "$_ql_distinfo"
CLCI_QL_DIST_VERSION="$(cat "$_ql_distinfo" | grep "^version: " | cut -c10- )"
fi
QUICKLISP_DIST_URL="http://dist.ultralisp.org/ultralisp/$CLCI_QL_DIST_VERSION/distinfo.txt"
;;
*)
echo "Unknown Quicklisp Dist $CLCI_QL_DIST_NAME"
exit 1
;;
esac
else
QUICKLISP_DIST_URL="$CLCI_QL_DIST_URL"
fi
- export QUICKLISP_DIST_URL
- |
_CLCI_QL_DIR="$_CLCI_QL_CACHE_PATH/dists/client-$QUICKLISP_CLIENT_VERSION/$(echo "$QUICKLISP_DIST_URL" | sha256sum - | cut -d' ' -f1 )"
- |
if [ -d "$_CLCI_QL_DIR" ]; then
echo "Quicklisp already installed."
else
echo "Installing Quicklisp $QUICKLISP_DIST_URL to $_CLCI_QL_DIR"
_clci_script="$(mktemp)"
cat > "$_clci_script" <<EOF
(load "$QUICKLISP_INSTALLER")
(quicklisp-quickstart:install :dist-url "$QUICKLISP_DIST_URL" :client-version "$QUICKLISP_CLIENT_VERSION" :path "$_CLCI_QL_DIR/")
EOF
echo "Running script:"
cat "$_clci_script"
case "$LISP" in
abcl)
abcl --noinit --nosystem --batch --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit :status 1)))) (load \"$_clci_script\"))" || exit 1
;;
allegro)
alisp --qq --batch --backtrace-on-error -L "$_clci_script" || exit 1
;;
ccl)
ccl -n -b --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ccl:quit 1)))) (load \"$_clci_script\"))" || exit 1
;;
clasp)
clasp -N --norc --load "$_clci_script" || exit 1
;;
clisp)
clisp -ansi -norc -x "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit 1)))) (load \"$_clci_script\"))" || exit 1
;;
cmucl)
cmucl -noinit -eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (unix:unix-exit 1)))) (load \"$_clci_script\") (unix:unix-exit 0))" || exit 1
;;
ecl)
ecl --norc --shell "$_clci_script" || exit 1
;;
sbcl)
sbcl --disable-ldb --lose-on-corruption --no-sysinit --disable-debugger --script "$_clci_script" || exit 1
;;
*)
echo "Unkown LISP: $LISP"
exit 1
;;
esac
fi
- QUICKLISP_SETUP_LISP="$_CLCI_QL_DIR/setup.lisp"
- export QUICKLISP_SETUP_LISP
- echo "(:source-registry-cache)" > "$_CLCI_QL_CACHE_PATH/.cl-source-registry.cache"
QL Job
This job is meant to be extended. It provides cache entries for ASDF and QL, as well as downloading, installing, and compiling ASDF, and downloading and installing QL.
.clci ql job:
before_script:
- *clci_download_asdf_script
- *clci_install_asdf_script
- *clci_compile_asdf_script
- *clci_download_ql_installer_script
- *clci_install_ql_script
cache:
- *clci_asdf_cache
- *clci_ql_cache
QL Script
This job is meant to be extended. It provides cache entries for ASDF and QL, as well as downloading, installing and compiling ASDF, and downloading and installing QL. You can add your own before_script
. You must define a variable CLCI_SCRIPT
containing the path to a script to be run as the last step of script
.
.clci ql script:
script:
- *clci_download_asdf_script
- *clci_install_asdf_script
- *clci_compile_asdf_script
- *clci_download_ql_installer_script
- *clci_install_ql_script
- _clci_script="$(mktemp)"
- |
if [ "z$ASDF_FASL" = "z" ]; then
if [ ! "z$ASDF_LISP" = "z" ]; then
echo "(load \"$ASDF_LISP\")" >> "$_clci_script"
fi
else
echo "(load \"$ASDF_FASL\")" >> "$_clci_script"
fi
- |
if [ "$CLCI_ASDF_VERSION" = "REQUIRE" ]; then
echo '(require "asdf")' >> "$_clci_script"
fi
- |
echo "(load \"$QUICKLISP_SETUP_LISP\")" >> "$_clci_script"
- |
echo "(load \"$CLCI_SCRIPT\")" >> "$_clci_script"
- echo "Running script:"
- cat "$_clci_script"
- |
case "$LISP" in
abcl)
abcl --noinit --nosystem --batch --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit :status 1)))) (load \"$_clci_script\"))" || exit 1
;;
allegro)
alisp --qq --batch --backtrace-on-error -L "$_clci_script" || exit 1
;;
ccl)
ccl -n -b --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ccl:quit 1)))) (load \"$_clci_script\"))" || exit 1
;;
clasp)
clasp -N --norc --load "$_clci_script" || exit 1
;;
clisp)
clisp -ansi -norc -x "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit 1)))) (load \"$_clci_script\"))" || exit 1
;;
cmucl)
cmucl -noinit -eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (unix:unix-exit 1)))) (load \"$_clci_script\") (unix:unix-exit 0))" || exit 1
;;
ecl)
ecl --norc --shell "$_clci_script" || exit 1
;;
sbcl)
sbcl --disable-ldb --lose-on-corruption --no-sysinit --disable-debugger --script "$_clci_script" || exit 1
;;
*)
echo "Unkown LISP: $LISP"
exit 1
;;
esac
cache:
- *clci_asdf_cache
- *clci_ql_cache
Releases
This section defines some helpers for creating releases.
tagged release rule
A rule that runs the job only if tagged and looks like a version string (starting with v).
.clci tagged release rule:
rules:
- if: '$CI_COMMIT_TAG =~ /^v[0-9]+(\.[0-9]+)*(-.*)?$/'
Linux test pipeline
This section produces the linux-test-pipeline.gitlab-ci.yml
file.
It currently supports the following implementations:
ABCL
Allegro (not enabled by default: public image requires acceptance of license). To accept the license of the default image, set
I_AGREE_TO_ALLEGRO_EXPRESS_LICENSE
toyes
.CCL
Clasp (not enabled by default: Docker image is a bit out of date due to upstream churn. Will be enabled by default after their next release.)
CLISP
CMUCL
ECL
SBCL
If a particular implementation is used for testing is controlled by the variable CLCI_TEST_$IMPL
. If set to the string yes
, the implementation is used for testing. Every implementation except Allegro and Clasp defaults to yes
. Once Clasp reaches 1.0.0, it will likely be enabled by default.
This pipeline supports the following dependency managers:
Quicklisp
CLPM
You can specify which one to use via the $CLCI_DEPENDENCY_MANAGER
variable. It defaults to empty. CLPM is used if the variable is set to clpm
or the file clpmfile.lock
exists in the root of your repository. If the variable is set to quicklisp
, then the Quicklisp client is installed, using the dist as specified by $CLCI_QL_DIST_URL
and/or $CLCI_QL_DIST_VERSION
/ $CLCI_QL_DIST_NAME
. If the variable is explicitly set to none
, no dependency manager is installed.
Each job first installs the ASDF version requested by $CLCI_ASDF_VERSION
. Then the relevant package manager is installed. Next, the implementation is fired up (under clpm bundle exec
if CLPM is used), ASDF loaded (if $CLCI_ASDF_VERSION
is specified), Quicklisp loaded (if Quicklisp is used), and the test script is run. The test script is specified by the CLCI_TEST_SCRIPT
variable, which defaults to scripts/ci-test.lisp
.
The test script is run with no rc files loaded and the debugger disabled. If the debugger is entered, the lisp is exited with a non-zero exit code.
Normally, this pipeline produces one job for every enabled implementation. That job is called either $LISP:clpm:test:clci
, $LISP:ql:test:clci
, or $LISP:test:clci
, depending on what library manager is used (if any).
However, if $NEW_IMPLEMENTATION_RELEASE
or $NEW_IMPLEMENTATION_RC
are set, only the implementation corresponding to the value of those variables is tested. Additionally, $CLCI_$IMPL_TAG
is overridden to the value of $NEW_IMPLMENTATION_RELEASE_TAG
or $NEW_IMPLEMENTATION_RC_TAG
.
Last, a job is added called finished:test:clci
. This job is a noop that simply waits for every other job in this pipeline to end. This can be used to help order jobs (look at the release pipeline for an example).
This pipeline can be customized by:
Overriding the value of any
CLCI_TEST_*
variable.Overriding the value of any
CLCI_*_IMAGE
orCLCI_*_TAG
variable.Adding a
before_script
to the job.common:test:clci
or any non hidden job.Adding
tags:
to the job.common:test:clci
or any non hidden job.Adding
parallel:
to the job.common:test:clci
or any non hidden job.Adding
stage:
to the job.common:test:clci
or any non hidden job.Adding
artifacts:
to the job.common:test:clci
or any non hidden job.
Variables
variables:
CLCI_TEST_ABCL: "yes"
CLCI_TEST_ALLEGRO: "no"
CLCI_TEST_CCL: "yes"
CLCI_TEST_CLASP: "no"
CLCI_TEST_CLISP: "yes"
CLCI_TEST_CMUCL: "yes"
CLCI_TEST_ECL: "yes"
CLCI_TEST_SBCL: "yes"
CLCI_TEST_SCRIPT: scripts/ci-test.lisp
Common
Every job in this pipeline extends this one. If you would like to install packages or do other common setup, put it in the beforescript of this job.
.common:test:clci:
before_script:
- "true"
._rules:test:clci:
rules: []
No manager
This section is the piece of the pipeline dedicated to non-CLPM or QL jobs.
Template
This provides the common template for non-CLPM based jobs. It downloads, installs, and compiles ASDF. Then installs Quicklisp if requested.
._template:none:test:clci:
script:
- !reference [.clci asdf job, before_script]
- _clci_script="$(mktemp)"
- |
if [ "z$ASDF_FASL" = "z" ]; then
if [ ! "z$ASDF_LISP" = "z" ]; then
echo "(load \"$ASDF_LISP\")" >> "$_clci_script"
fi
else
echo "(load \"$ASDF_FASL\")" >> "$_clci_script"
fi
- |
if [ "$CLCI_ASDF_VERSION" = "REQUIRE" ]; then
echo '(require "asdf")' >> "$_clci_script"
fi
- |
if [ "z$ASDF_DIR" != "z" ]; then
echo "(push #p\"$ASDF_DIR/\" asdf:*central-registry*)" >> "$_clci_script"
fi
- |
echo "(push #p\"$CI_PROJECT_DIR/\" asdf:*central-registry*)" >> "$_clci_script"
- |
echo "(load \"$CLCI_TEST_SCRIPT\")" >> "$_clci_script"
- |
if [ -e Makefile ] && [ "$CLCI_TEST_USE_MAKEFILE" != "no" ] ; then
make test
else
echo "Running script:"
cat "$_clci_script"
case "$LISP" in
abcl)
abcl --noinit --nosystem --batch --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit :status 1)))) (load \"$_clci_script\"))" || exit 1
;;
allegro)
alisp --qq --batch --backtrace-on-error -L "$_clci_script" || exit 1
;;
ccl)
ccl -n -b --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ccl:quit 1)))) (load \"$_clci_script\"))" || exit 1
;;
clasp)
clasp -N --norc --load "$_clci_script" || exit 1
;;
clisp)
clisp -ansi -norc -x "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit 1)))) (load \"$_clci_script\"))" || exit 1
;;
cmucl)
cmucl -noinit -eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (unix:unix-exit 1)))) (load \"$_clci_script\") (unix:unix-exit 0))" || exit 1
;;
ecl)
ecl --norc --shell "$_clci_script" || exit 1
;;
sbcl)
sbcl --disable-ldb --lose-on-corruption --no-sysinit --disable-debugger --script "$_clci_script" || exit 1
;;
*)
echo "Unkown LISP: $LISP"
exit 1
;;
esac
fi
.common:none:test:clci:
extends:
- ".common:test:clci"
cache:
- !reference [.clci asdf cache]
ABCL
Test on ABCL without a dependency manager.
abcl:test:clci:
extends:
- ".clci abcl"
- ".common:none:test:clci"
script:
- !reference ["._template:none:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- exists:
- clpmfile.lock
if: '$CLCI_DEPENDENCY_MANAGER != "none"'
when: never
- if: '$CLCI_DEPENDENCY_MANAGER && $CLCI_DEPENDENCY_MANAGER != "none"'
when: never
- if: '$CLCI_TEST_ABCL != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "abcl"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "abcl"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "abcl"'
variables:
CLCI_ABCL_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "abcl"'
variables:
CLCI_ABCL_TAG: $NEW_IMPLEMENTATION_RC_TAG
- when: on_success
Allegro
Test on Allegro without a dependency manager.
allegro:test:clci:
extends:
- ".clci allegro"
- ".common:none:test:clci"
script:
- !reference ["._template:none:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- exists:
- clpmfile.lock
if: '$CLCI_DEPENDENCY_MANAGER != "none"'
when: never
- if: '$CLCI_DEPENDENCY_MANAGER && $CLCI_DEPENDENCY_MANAGER != "none"'
when: never
- if: '$CLCI_TEST_ALLEGRO != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "allegro"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "allegro"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "allegro"'
variables:
CLCI_ALLEGRO_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "allegro"'
variables:
CLCI_ALLEGRO_TAG: $NEW_IMPLEMENTATION_RC_TAG
- when: on_success
CCL
Test on CCL without a dependency manager.
ccl:test:clci:
extends:
- ".clci ccl"
- ".common:none:test:clci"
script:
- !reference ["._template:none:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- exists:
- clpmfile.lock
if: '$CLCI_DEPENDENCY_MANAGER != "none"'
when: never
- if: '$CLCI_DEPENDENCY_MANAGER && $CLCI_DEPENDENCY_MANAGER != "none"'
when: never
- if: '$CLCI_TEST_CCL != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "ccl"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "ccl"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "ccl"'
variables:
CLCI_CCL_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "ccl"'
variables:
CLCI_CCL_TAG: $NEW_IMPLEMENTATION_RC_TAG
- when: on_success
Clasp
Test on Clasp without a dependency manager.
clasp:test:clci:
extends:
- ".clci clasp"
- ".common:none:test:clci"
script:
- !reference ["._template:none:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- exists:
- clpmfile.lock
if: '$CLCI_DEPENDENCY_MANAGER != "none"'
when: never
- if: '$CLCI_DEPENDENCY_MANAGER && $CLCI_DEPENDENCY_MANAGER != "none"'
when: never
- if: '$CLCI_TEST_CLASP != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "clasp"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "clasp"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "clasp"'
variables:
CLCI_CLASP_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "clasp"'
variables:
CLCI_CLASP_TAG: $NEW_IMPLEMENTATION_RC_TAG
- when: on_success
CLISP
Test on CLISP without a dependency manager.
clisp:test:clci:
extends:
- ".clci clisp"
- ".common:none:test:clci"
script:
- !reference ["._template:none:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- exists:
- clpmfile.lock
if: '$CLCI_DEPENDENCY_MANAGER != "none"'
when: never
- if: '$CLCI_DEPENDENCY_MANAGER && $CLCI_DEPENDENCY_MANAGER != "none"'
when: never
- if: '$CLCI_TEST_CLISP != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "clisp"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "clisp"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "clisp"'
variables:
CLCI_CLISP_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "clisp"'
variables:
CLCI_CLISP_TAG: $NEW_IMPLEMENTATION_RC_TAG
- when: on_success
CMUCL
Test on CMUCL without a dependency manager.
cmucl:test:clci:
extends:
- ".clci cmucl"
- ".common:none:test:clci"
script:
- !reference ["._template:none:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- exists:
- clpmfile.lock
if: '$CLCI_DEPENDENCY_MANAGER != "none"'
when: never
- if: '$CLCI_DEPENDENCY_MANAGER && $CLCI_DEPENDENCY_MANAGER != "none"'
when: never
- if: '$CLCI_TEST_CMUCL != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "cmucl"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "cmucl"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "cmucl"'
variables:
CLCI_CMUCL_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "cmucl"'
variables:
CLCI_CMUCL_TAG: $NEW_IMPLEMENTATION_RC_TAG
- when: on_success
ECL
Test on ECL without a dependency manager.
ecl:test:clci:
extends:
- ".clci ecl"
- ".common:none:test:clci"
script:
- !reference ["._template:none:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- exists:
- clpmfile.lock
if: '$CLCI_DEPENDENCY_MANAGER != "none"'
when: never
- if: '$CLCI_DEPENDENCY_MANAGER && $CLCI_DEPENDENCY_MANAGER != "none"'
when: never
- if: '$CLCI_TEST_ECL != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "ecl"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "ecl"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "ecl"'
variables:
CLCI_ECL_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "ecl"'
variables:
CLCI_ECL_TAG: $NEW_IMPLEMENTATION_RC_TAG
- when: on_success
SBCL
Test on SBCL without a dependency manager.
sbcl:test:clci:
extends:
- ".clci sbcl"
- ".common:none:test:clci"
script:
- !reference ["._template:none:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- exists:
- clpmfile.lock
if: '$CLCI_DEPENDENCY_MANAGER != "none"'
when: never
- if: '$CLCI_DEPENDENCY_MANAGER && $CLCI_DEPENDENCY_MANAGER != "none"'
when: never
- if: '$CLCI_TEST_SBCL != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "sbcl"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "sbcl"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "sbcl"'
variables:
CLCI_SBCL_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "sbcl"'
variables:
CLCI_SBCL_TAG: $NEW_IMPLEMENTATION_RC_TAG
- when: on_success
Quicklisp
This section is the piece of the pipeline dedicated to QL based jobs.
Template
This provides the common template for QL based jobs. It downloads, installs, and compiles ASDF. Then installs Quicklisp.
._template:ql:test:clci:
script:
- !reference [.clci ql job, before_script]
- _clci_script="$(mktemp)"
- |
if [ "z$ASDF_FASL" = "z" ]; then
if [ ! "z$ASDF_LISP" = "z" ]; then
echo "(load \"$ASDF_LISP\")" >> "$_clci_script"
fi
else
echo "(load \"$ASDF_FASL\")" >> "$_clci_script"
fi
- |
if [ "$CLCI_ASDF_VERSION" = "REQUIRE" ]; then
echo '(require "asdf")' >> "$_clci_script"
fi
- |
if [ "z$ASDF_DIR" != "z" ]; then
echo "(push #p\"$ASDF_DIR/\" asdf:*central-registry*)" >> "$_clci_script"
fi
- |
echo "(push #p\"$CI_PROJECT_DIR/\" asdf:*central-registry*)" >> "$_clci_script"
- |
echo "(load \"$QUICKLISP_SETUP_LISP\")" >> "$_clci_script"
- |
echo "(load \"$CLCI_TEST_SCRIPT\")" >> "$_clci_script"
- |
if [ -e Makefile ] && [ "$CLCI_TEST_USE_MAKEFILE" != "no" ] ; then
make test
else
echo "Running script:"
cat "$_clci_script"
case "$LISP" in
abcl)
abcl --noinit --nosystem --batch --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit :status 1)))) (load \"$_clci_script\"))" || exit 1
;;
allegro)
alisp --qq --batch --backtrace-on-error -L "$_clci_script" || exit 1
;;
ccl)
ccl -n -b --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ccl:quit 1)))) (load \"$_clci_script\"))" || exit 1
;;
clasp)
clasp -N --norc --load "$_clci_script" || exit 1
;;
clisp)
clisp -ansi -norc -x "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit 1)))) (load \"$_clci_script\"))" || exit 1
;;
cmucl)
cmucl -noinit -eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (unix:unix-exit 1)))) (load \"$_clci_script\") (unix:unix-exit 0))" || exit 1
;;
ecl)
ecl --norc --shell "$_clci_script" || exit 1
;;
sbcl)
sbcl --disable-ldb --lose-on-corruption --no-sysinit --disable-debugger --script "$_clci_script" || exit 1
;;
*)
echo "Unkown LISP: $LISP"
exit 1
;;
esac
fi
.common:ql:test:clci:
extends:
- ".common:test:clci"
cache:
- !reference [.clci asdf cache]
- !reference [.clci ql cache]
ABCL
Test on ABCL without CLPM.
abcl:ql:test:clci:
extends:
- ".clci abcl"
- ".common:ql:test:clci"
script:
- !reference ["._template:ql:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- if: '$CLCI_DEPENDENCY_MANAGER != "quicklisp"'
when: never
- if: '$CLCI_TEST_ABCL != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "abcl"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "abcl"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "abcl"'
variables:
CLCI_ABCL_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "abcl"'
variables:
CLCI_ABCL_TAG: $NEW_IMPLEMENTATION_RC_TAG
- when: on_success
Allegro
Test on Allegro without CLPM.
allegro:ql:test:clci:
extends:
- ".clci allegro"
- ".common:ql:test:clci"
script:
- !reference ["._template:ql:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- if: '$CLCI_DEPENDENCY_MANAGER != "quicklisp"'
when: never
- if: '$CLCI_TEST_ALLEGRO != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "allegro"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "allegro"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "allegro"'
variables:
CLCI_ALLEGRO_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "allegro"'
variables:
CLCI_ALLEGRO_TAG: $NEW_IMPLEMENTATION_RC_TAG
- when: on_success
CCL
Test on CCL without CLPM.
ccl:ql:test:clci:
extends:
- ".clci ccl"
- ".common:ql:test:clci"
script:
- !reference ["._template:ql:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- if: '$CLCI_DEPENDENCY_MANAGER != "quicklisp"'
when: never
- if: '$CLCI_TEST_CCL != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "ccl"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "ccl"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "ccl"'
variables:
CLCI_CCL_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "ccl"'
variables:
CLCI_CCL_TAG: $NEW_IMPLEMENTATION_RC_TAG
- when: on_success
Clasp
Test on Clasp without CLPM.
clasp:ql:test:clci:
extends:
- ".clci clasp"
- ".common:ql:test:clci"
script:
- !reference ["._template:ql:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- if: '$CLCI_DEPENDENCY_MANAGER != "quicklisp"'
when: never
- if: '$CLCI_TEST_CLASP != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "clasp"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "clasp"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "clasp"'
variables:
CLCI_CLASP_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "clasp"'
variables:
CLCI_CLASP_TAG: $NEW_IMPLEMENTATION_RC_TAG
- when: on_success
CLISP
Test on CLISP without CLPM.
clisp:ql:test:clci:
extends:
- ".clci clisp"
- ".common:ql:test:clci"
script:
- !reference ["._template:ql:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- if: '$CLCI_DEPENDENCY_MANAGER != "quicklisp"'
when: never
- if: '$CLCI_TEST_CLISP != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "clisp"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "clisp"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "clisp"'
variables:
CLCI_CLISP_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "clisp"'
variables:
CLCI_CLISP_TAG: $NEW_IMPLEMENTATION_RC_TAG
- when: on_success
CMUCL
Test on CMUCL without CLPM.
cmucl:ql:test:clci:
extends:
- ".clci cmucl"
- ".common:ql:test:clci"
script:
- !reference ["._template:ql:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- if: '$CLCI_DEPENDENCY_MANAGER != "quicklisp"'
when: never
- if: '$CLCI_TEST_CMUCL != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "cmucl"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "cmucl"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "cmucl"'
variables:
CLCI_CMUCL_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "cmucl"'
variables:
CLCI_CMUCL_TAG: $NEW_IMPLEMENTATION_RC_TAG
- when: on_success
ECL
Test on ECL without CLPM.
ecl:ql:test:clci:
extends:
- ".clci ecl"
- ".common:ql:test:clci"
script:
- !reference ["._template:ql:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- if: '$CLCI_DEPENDENCY_MANAGER != "quicklisp"'
when: never
- if: '$CLCI_TEST_ECL != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "ecl"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "ecl"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "ecl"'
variables:
CLCI_ECL_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "ecl"'
variables:
CLCI_ECL_TAG: $NEW_IMPLEMENTATION_RC_TAG
- when: on_success
SBCL
Test on SBCL without CLPM.
sbcl:ql:test:clci:
extends:
- ".clci sbcl"
- ".common:ql:test:clci"
script:
- !reference ["._template:ql:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- if: '$CLCI_DEPENDENCY_MANAGER != "quicklisp"'
when: never
- if: '$CLCI_TEST_SBCL != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "sbcl"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "sbcl"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "sbcl"'
variables:
CLCI_SBCL_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "sbcl"'
variables:
CLCI_SBCL_TAG: $NEW_IMPLEMENTATION_RC_TAG
- when: on_success
CLPM
This section is the piece of the pipeline dedicated to CLPM based jobs.
Template
This provides the common template. It downloads, installs, and compiles ASDF. Then downloads and installs CLPM. Next, it installs the bundle.
._template:clpm:test:clci:
script:
- !reference [.clci clpm job, before_script]
- _clci_script="$(mktemp)"
- |
if [ "z$ASDF_FASL" = "z" ]; then
if [ ! "z$ASDF_LISP" = "z" ]; then
echo "(load \"$ASDF_LISP\")" >> "$_clci_script"
fi
else
echo "(load \"$ASDF_FASL\")" >> "$_clci_script"
fi
- |
if [ "$CLCI_ASDF_VERSION" = "REQUIRE" ]; then
echo '(require "asdf")' >> "$_clci_script"
fi
- |
if [ "z$ASDF_DIR" != "z" ]; then
echo "(push #p\"$ASDF_DIR/\" asdf:*central-registry*)" >> "$_clci_script"
fi
- |
echo "(load \"$CLCI_TEST_SCRIPT\")" >> "$_clci_script"
- $CLPM bundle install --no-resolve
- echo "Running script:"
- cat "$_clci_script"
- |
if [ -e Makefile ] && [ "$CLCI_TEST_USE_MAKEFILE" != "no" ] ; then
make test
else
case "$LISP" in
abcl)
$CLPM bundle exec -- abcl --noinit --nosystem --batch --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit :status 1)))) (load \"$_clci_script\"))" || exit 1
;;
allegro)
$CLPM bundle exec -- alisp --qq --batch --backtrace-on-error -L "$_clci_script" || exit 1
;;
ccl)
$CLPM bundle exec -- ccl -n -b --eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ccl:quit 1)))) (load \"$_clci_script\"))" || exit 1
;;
clasp)
$CLPM bundle exec -- clasp -N --norc --load "$_clci_script" || exit 1
;;
clisp)
$CLPM bundle exec -- clisp -ansi -norc -x "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (ext:quit 1)))) (load \"$_clci_script\"))" || exit 1
;;
cmucl)
$CLPM bundle exec -- cmucl -noinit -eval "(let ((*debugger-hook* (lambda (c prev) (declare (ignore prev)) (format *error-output* \"Caught error: ~A~%\" c) (unix:unix-exit 1)))) (load \"$_clci_script\") (unix:unix-exit 0))" || exit 1
;;
ecl)
$CLPM bundle exec -- ecl --norc --shell "$_clci_script" || exit 1
;;
sbcl)
$CLPM bundle exec -- sbcl --disable-ldb --lose-on-corruption --no-sysinit --disable-debugger --script "$_clci_script" || exit 1
;;
*)
echo "Unkown LISP: $LISP"
exit 1
;;
esac
fi
.common:clpm:test:clci:
variables:
CLPM_CACHE_DIR: !reference [.clci clpm cache variables, variables, CLPM_CACHE_DIR]
CLPM_DATA_DIR: !reference [.clci clpm cache variables, variables, CLPM_DATA_DIR]
extends:
- ".common:test:clci"
cache:
- !reference [.clci asdf cache]
- !reference [.clci clpm cache]
- !reference [.clci clpm release cache]
ABCL
Test on ABCL.
abcl:clpm:test:clci:
extends:
- ".clci abcl"
- ".common:clpm:test:clci"
script:
- !reference ["._template:clpm:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- if: '$CLCI_DEPENDENCY_MANAGER && $CLCI_DEPENDENCY_MANAGER != "clpm"'
when: never
- if: '$CLCI_TEST_ABCL != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "abcl"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "abcl"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "abcl"'
exists:
- clpmfile.lock
variables:
CLCI_ABCL_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "abcl"'
exists:
- clpmfile.lock
variables:
CLCI_ABCL_TAG: $NEW_IMPLEMENTATION_RC_TAG
- exists:
- clpmfile.lock
Allegro
Test on Allegro
allegro:clpm:test:clci:
extends:
- ".clci allegro"
- ".common:clpm:test:clci"
script:
- !reference ["._template:clpm:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- if: '$CLCI_DEPENDENCY_MANAGER && $CLCI_DEPENDENCY_MANAGER != "clpm"'
when: never
- if: '$CLCI_TEST_ALLEGRO != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "allegro"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "allegro"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "allegro"'
exists:
- clpmfile.lock
variables:
CLCI_ALLEGRO_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "allegro"'
exists:
- clpmfile.lock
variables:
CLCI_ALLEGRO_TAG: $NEW_IMPLEMENTATION_RC_TAG
- exists:
- clpmfile.lock
CCL
Test on CCL.
ccl:clpm:test:clci:
extends:
- ".clci ccl"
- ".common:clpm:test:clci"
script:
- !reference ["._template:clpm:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- if: '$CLCI_DEPENDENCY_MANAGER && $CLCI_DEPENDENCY_MANAGER != "clpm"'
when: never
- if: '$CLCI_TEST_CCL != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "ccl"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "ccl"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "ccl"'
exists:
- clpmfile.lock
variables:
CLCI_CCL_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "ccl"'
exists:
- clpmfile.lock
variables:
CLCI_CCL_TAG: $NEW_IMPLEMENTATION_RC_TAG
- exists:
- clpmfile.lock
CLASP
Test on CLASP
clasp:clpm:test:clci:
extends:
- ".clci clasp"
- ".common:clpm:test:clci"
script:
- !reference ["._template:clpm:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- if: '$CLCI_DEPENDENCY_MANAGER && $CLCI_DEPENDENCY_MANAGER != "clpm"'
when: never
- if: '$CLCI_TEST_CLASP != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "clasp"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "clasp"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "clasp"'
exists:
- clpmfile.lock
variables:
CLCI_CLASP_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "clasp"'
exists:
- clpmfile.lock
variables:
CLCI_CLASP_TAG: $NEW_IMPLEMENTATION_RC_TAG
- exists:
- clpmfile.lock
CLISP
Test on CLISP
clisp:clpm:test:clci:
extends:
- ".clci clisp"
- ".common:clpm:test:clci"
script:
- !reference ["._template:clpm:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- if: '$CLCI_DEPENDENCY_MANAGER && $CLCI_DEPENDENCY_MANAGER != "clpm"'
when: never
- if: '$CLCI_TEST_CLISP != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "clisp"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "clisp"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "clisp"'
exists:
- clpmfile.lock
variables:
CLCI_CLISP_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "clisp"'
exists:
- clpmfile.lock
variables:
CLCI_CLISP_TAG: $NEW_IMPLEMENTATION_RC_TAG
- exists:
- clpmfile.lock
CMUCL
Test on CMUCL.
cmucl:clpm:test:clci:
extends:
- ".clci cmucl"
- ".common:clpm:test:clci"
script:
- !reference ["._template:clpm:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- if: '$CLCI_DEPENDENCY_MANAGER && $CLCI_DEPENDENCY_MANAGER != "clpm"'
when: never
- if: '$CLCI_TEST_CMUCL != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "cmucl"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "cmucl"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "cmucl"'
exists:
- clpmfile.lock
variables:
CLCI_CMUCL_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "cmucl"'
exists:
- clpmfile.lock
variables:
CLCI_CMUCL_TAG: $NEW_IMPLEMENTATION_RC_TAG
- exists:
- clpmfile.lock
ECL
Test on ECL.
ecl:clpm:test:clci:
extends:
- ".clci ecl"
- ".common:clpm:test:clci"
script:
- !reference ["._template:clpm:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- if: '$CLCI_DEPENDENCY_MANAGER && $CLCI_DEPENDENCY_MANAGER != "clpm"'
when: never
- if: '$CLCI_TEST_ECL != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "ecl"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "ecl"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "ecl"'
exists:
- clpmfile.lock
variables:
CLCI_ECL_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "ecl"'
exists:
- clpmfile.lock
variables:
CLCI_ECL_TAG: $NEW_IMPLEMENTATION_RC_TAG
- exists:
- clpmfile.lock
SBCL
Test on SBCL.
sbcl:clpm:test:clci:
extends:
- ".clci sbcl"
- ".common:clpm:test:clci"
script:
- !reference ["._template:clpm:test:clci", script]
rules:
- !reference ["._rules:test:clci", "rules"]
- if: '$CLCI_DEPENDENCY_MANAGER && $CLCI_DEPENDENCY_MANAGER != "clpm"'
when: never
- if: '$CLCI_TEST_SBCL != "yes"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE && $NEW_IMPLEMENTATION_RELEASE != "sbcl"'
when: never
- if: '$NEW_IMPLEMENTATION_RC && $NEW_IMPLEMENTATION_RC != "sbcl"'
when: never
- if: '$NEW_IMPLEMENTATION_RELEASE == "sbcl"'
exists:
- clpmfile.lock
variables:
CLCI_SBCL_TAG: $NEW_IMPLEMENTATION_RELEASE_TAG
- if: '$NEW_IMPLEMENTATION_RC == "sbcl"'
exists:
- clpmfile.lock
variables:
CLCI_SBCL_TAG: $NEW_IMPLEMENTATION_RC_TAG
- exists:
- clpmfile.lock
Finished
This job simply waits until every other job in the pipeline is finished.
finished:test:clci:
script:
- echo "All tests finished"
rules:
- !reference ["._rules:test:clci", "rules"]
- when: on_success
needs:
- job: "abcl:clpm:test:clci"
optional: true
artifacts: false
- job: "allegro:clpm:test:clci"
optional: true
artifacts: false
- job: "ccl:clpm:test:clci"
optional: true
artifacts: false
- job: "clasp:clpm:test:clci"
optional: true
artifacts: false
- job: "clisp:clpm:test:clci"
optional: true
artifacts: false
- job: "cmucl:clpm:test:clci"
optional: true
artifacts: false
- job: "ecl:clpm:test:clci"
optional: true
artifacts: false
- job: "sbcl:clpm:test:clci"
optional: true
artifacts: false
- job: "abcl:test:clci"
optional: true
artifacts: false
- job: "allegro:test:clci"
optional: true
artifacts: false
- job: "ccl:test:clci"
optional: true
artifacts: false
- job: "clasp:test:clci"
optional: true
artifacts: false
- job: "clisp:test:clci"
optional: true
artifacts: false
- job: "cmucl:test:clci"
optional: true
artifacts: false
- job: "ecl:test:clci"
optional: true
artifacts: false
- job: "sbcl:test:clci"
optional: true
artifacts: false
- job: "abcl:ql:test:clci"
optional: true
artifacts: false
- job: "allegro:ql:test:clci"
optional: true
artifacts: false
- job: "ccl:ql:test:clci"
optional: true
artifacts: false
- job: "clasp:ql:test:clci"
optional: true
artifacts: false
- job: "clisp:ql:test:clci"
optional: true
artifacts: false
- job: "cmucl:ql:test:clci"
optional: true
artifacts: false
- job: "ecl:ql:test:clci"
optional: true
artifacts: false
- job: "sbcl:ql:test:clci"
optional: true
artifacts: false
Guarded Test Pipeline
This section tangles to the file guarded-linux-test-pipeline.gitlab-ci.yml
. It conditionally includes linux-test-pipeline.gitlab-ci.yml
if the value of $PIPELINE_TYPE
allows it. This file is used by the suggested configuration in order to limit verbosity.
CLPM Dependency Update
This section tangles to the clpm-dep-update-pipeline.gitlab-ci.yml
file.
This pipeline is meant to be run on a schedule. Its purpose is to update your CLPM lock file and open an MR against the default branch if there are changes.
You must set $CLCI_MR_TOKEN
to a Gitlab token that has permissions to create merge requests on your project.
This pipeline cannot otherwise be customized.
Common
Defaults.
._rules:clpm dep update:clci:
rules: []
Sanity Check
Checks that CLCIMRTOKEN is set.
sanity-check:clpm dep update:clci:
image: !reference [.clci sbcl, image]
script:
- '[ -n "$CLCI_MR_TOKEN" ] || { echo "CLCI_MR_TOKEN needs to be set" >&2; exit 1; }'
rules:
- !reference ["._rules:clpm dep update:clci", "rules"]
- when: on_success
Update
Run clpm update, and open an MR if there's a change.
update:clpm dep update:clci:
image: !reference [.clci sbcl, image]
variables:
LISP: sbcl
script:
- BRANCH_NAME="update-deps-$(date +%Y-%m-%d)"
- git checkout -B "$BRANCH_NAME" "$CI_COMMIT_SHA"
- !reference [.clci download asdf, script]
- !reference [.clci install asdf, script]
- !reference [.clci compile asdf, script]
- !reference [.clci download clpm, script]
- !reference [.clci install clpm, script]
- '$CLPM bundle update -y -V'
- |
if [ -z "$(git status --untracked-files=no --porcelain)" ]; then
exit 0
fi
- git config user.email "$GITLAB_USER_EMAIL"
- git config user.name "$GITLAB_USER_NAME"
- git add clpmfile.lock
- git commit -m 'Update bundle dependencies'
- 'git push "https://git:$CLCI_MR_TOKEN@$CI_SERVER_HOST/$CI_PROJECT_PATH.git" "$BRANCH_NAME"'
- 'curl -X POST "$CI_API_V4_URL/projects/$CI_PROJECT_ID/merge_requests" -H "PRIVATE-TOKEN: $CLCI_MR_TOKEN" -d "labels=bot" -d "source_branch=$BRANCH_NAME" -d "target_branch=$CI_COMMIT_BRANCH" -d "title=Update clpmfile.lock" -d "description=Automated update of clpmfile.lock"'
needs:
- "sanity-check:clpm dep update:clci"
rules:
- !reference ["._rules:clpm dep update:clci", "rules"]
- when: on_success
Guarded CLPM Dependency Update
This section tangles to the file guarded-clpm-dep-update-pipeline.gitlab-ci.yml
. It conditionally includes clpm-dep-update-pipeline.gitlab-ci.yml
if the value of $PIPELINE_TYPE
allows it. This file is used by the suggested configuration in order to limit verbosity.
Release Pipeline
This section tangles to the file release-pipeline.gitlab-ci.yml. It contains jobs that run when tags are pushed to the repo. that look like releases (a v
followed by a version number).
In order to use this pipeline, you must protect the tags you use for releasing. To do this, go to "Settings > Repository > Protected Tags". Most projects will probably want to protect v*
.
Additionally, you must be able to create a changelog entry for the release. By default, the extract changelog:release:clci
job will look at the file CHANGELOG.md
and extract the entry corresponding to the second level heading that starts with $CI_COMMIT_TAG
(with anything after a -
stripped). The file location can be changed by changing the value of $CLCI_CHANGELOG
.
Changelog extraction can be customized by overriding the script of the extract changelog:release:clci
job. It must write the changelog entry to the file .clci-build/changelog-entry.md
.
Actually performing the release blocks on both sanity checks and any tests added by the test pipeline succeeded. If you would like to add additionally blockers, add needs:
to the job user blocker:release:clci
.
By default, this pipeline only releases to Gitlab. (Look at the "Deployments > Releases" tab).
However, you can also release to a CLPI server by setting the variables $CLCI_CLPI_SERVER
, $CLCI_CLPI_USERNAME
, and $CLCI_CLPI_PASSWORD
. This feature is in beta and stability is not guaranteed.
After all releases have been performed, the release is announced. Currently, the only announcement mechanism supported is via Slack Webhook. To enable this, set the variable $CLCI_SLACK_ANNOUNCE_WEBHOOK_URL
.
Beyond setting these environment variables, adding needs
to the job user blocker:release:clci
, and overriding the script
of extract changelog:release:clci
, no further customizations are currently supported.
Common
Defaults.
._rules:release:clci:
rules: []
Sanity Check
Checks that the current tag is protected.
check tag protected:release:clci:
script:
- '[ "$CI_COMMIT_REF_PROTECTED" == "true" ] || { echo "You must protect this tag" >&2; exit 1; }'
rules:
- !reference ["._rules:release:clci", "rules"]
- when: on_success
Extract Changelog Entry
extract changelog:release:clci:
script:
- mkdir -p .clci-build
- _CLCI_INTERMEDIATE="${CI_COMMIT_TAG%%-*}"
- |
awk "
/^## /{flag=0}
/^## ${_CLCI_INTERMEDIATE//./\\.}/{flag=1}
flag
" "$CLCI_CHANGELOG" > .clci-build/changelog-entry.md
- '[[ -s .clci-build/changelog-entry.md ]] || { echo "Unable to extract changelog entry" >&2; exit 1; }'
artifacts:
paths:
- .clci-build/changelog-entry.md
rules:
- !reference ["._rules:release:clci", "rules"]
- when: on_success
user blocker
This job is a noop job that simply waits for any jobs the user desires to finish before proceeding.
user blocker:release:clci:
script:
- echo "All user blockers for release finished"
rules:
- !reference ["._rules:release:clci", "rules"]
- when: on_success
test blocker
This job is a noop job that simply waits before all tests and sanity checks are complete before proceeding.
blocker:release:clci:
script:
- echo "All release blockers finished"
needs:
- job: "user blocker:release:clci"
artifacts: false
optional: true
- job: "check tag protected:release:clci"
artifacts: false
- job: "extract changelog:release:clci"
artifacts: false
- job: "finished:test:clci"
optional: true
artifacts: false
rules:
- !reference ["._rules:release:clci", "rules"]
- when: on_success
Release to Gitlab
This job uses Gitlab's release API to create a release from the tag name.
gitlab:release:clci:
image: registry.gitlab.com/gitlab-org/release-cli:latest
script:
- echo 'release job'
release:
tag_name: $CI_COMMIT_TAG
description: './.clci-build/changelog-entry.md'
needs:
- "extract changelog:release:clci"
- "blocker:release:clci"
rules:
- !reference ["._rules:release:clci", "rules"]
- when: on_success
Release to CLPI
clpi:release:clci:
extends:
- .clci sbcl
- .clci clpm job
script:
- apt-get update
- apt-get install -y --no-install-recommends jq
- $CLPM bundle install --no-resolve
- _clci_asd_args=""
- for asd in $(ls *.asd); do _clci_asd_args="$_clci_asd_args --asd $asd"; done
- mkdir -p .clci-build
- $CLPM clpi release $_clci_asd_args --deps-from-lockfile -VV "$CI_PROJECT_NAME" "${CI_COMMIT_TAG#v}" "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/repository/archive.tar.gz?sha=${CI_COMMIT_TAG}" | tee .clci-build/clpi-release.json
# First, make sure the project is present in CLPI, with the repo set.
- |
repo_desc="$(echo "{}" | jq --arg host "$CI_SERVER_HOST" --arg path "$CI_PROJECT_PATH" --arg type gitlab '. + {type: $type, host: $host, path: $path}')"
- echo "$repo_desc"
- |
curl -X PUT \
-f \
-d "$repo_desc" \
-H "Content-Type: application/json" \
"${CLCI_CLPI_SERVER}/api/v0.1/projects/$CI_PROJECT_NAME/repo" \
--user "${CLCI_CLPI_USERNAME}:${CLCI_CLPI_PASSWORD}"
- |
curl -f -X PUT \
-d @.clci-build/clpi-release.json \
-H "Content-Type: application/json" \
"${CLCI_CLPI_SERVER}/api/v0.1/projects/$CI_PROJECT_NAME/releases/${CI_COMMIT_TAG#v}" \
--user "${CLCI_CLPI_USERNAME}:${CLCI_CLPI_PASSWORD}"
rules:
- !reference ["._rules:release:clci", "rules"]
- if: '$CLCI_CLPI_SERVER == null || $CLCI_CLPI_SERVER == "" || $CLCI_CLPI_USERNAME == null || $CLCI_CLPI_USERNAME == "" || $CLCI_CLPI_PASSWORD == null || $CLCI_CLPI_PASSWORD == ""'
when: never
- when: on_success
needs:
- "extract changelog:release:clci"
- "blocker:release:clci"
Announce to Slack
slack announcement:release:clci:
image: alpine:latest
script:
- apk add curl jq
- |
curl -X POST \
--data-urlencode "payload=$(echo "{}" | jq --arg text "$CI_PROJECT_TITLE $CI_COMMIT_TAG has been released.
$(cat "./.clci-build/changelog-entry.md")" '. + {text: $text}')" \
"$CLCI_SLACK_ANNOUNCE_WEBHOOK_URL"
rules:
- !reference ["._rules:release:clci", "rules"]
- if: '$CLCI_SLACK_ANNOUNCE_WEBHOOK_URL == null || $CLCI_SLACK_ANNOUNCE_WEBHOOK_URL == ""'
when: never
- when: on_success
needs:
- "gitlab:release:clci"
- job: "clpi:release:clci"
optional: true
- "extract changelog:release:clci"
Guarded Release Pipeline
This section tangles to the file guarded-release-pipeline.gitlab-ci.yml
. It conditionally includes release-pipeline.gitlab-ci.yml
if the value of $PIPELINE_TYPE
allows it and if a tag is pushed that looks like a version number (v
followed by any number of dot separated integers and optionally a -
followed by anything). This file is used by the suggested configuration in order to limit verbosity.