pmbootstrap CI
Continuous Integration (CI) scripts run whenever sending a patch into one of the source trees of postmarketOS. These run various tests, to make sure that new patches don't introduce new bugs and to do various style checks (linting) so the code looks consistent. The command pmbootstrap ci
can be used to run the same CI scripts locally. If they fail, you can fix your patch and run them again - and once they pass you can be confident that they will also pass after you submitted them.
Usage
Change to the directory of the git repository of which you would like to run the CI scripts. Then run pmbootstrap ci
for an interactive selection of which scripts to run.
$ cd ~/code/pmbootstrap
$ pmbootstrap ci
[20:42:49] Available CI scripts (4):
[20:42:49] * ruff: lint all python scripts
[20:42:49] * shellcheck: lint all shell scripts
[20:42:49] * vermin: verify that we don't use too new python features
[20:42:49] * pytest: run pmbootstrap python testsuite (slow)
[20:42:49] Which script? [all]:
It is also possible to directly start one or more scripts without the interactive prompt. Just add the name of the scripts you want to run at the end, for example:
$ pmbootstrap ci ruff vermin
See pmbootstrap ci -h
for the full usage instructions.
Example CI script
Here is a minimal example for checking all shell scripts in the git repository with shellcheck.
Create the following file as .ci/shellcheck.sh
:
#!/bin/sh -e
# Description: lint all shell scripts
# https://postmarketos.org/pmb-ci
if [ "$(id -u)" = 0 ]; then
set -x
apk -q add shellcheck
exec su "${TESTUSER:-build}" -c "sh -e $0"
fi
find . -name '*.sh' |
while read -r file; do
echo "shellcheck: $file"
shellcheck "$file"
done
Make it executable:
$ chmod +x .ci/shellcheck.sh
If the git repository is on SourceHut, put the following in .build.yml
:
image: alpine/latest
packages:
- sudo
tasks:
- shellcheck: |
cd name-of-your-git-repository
sudo .ci/shellcheck.sh
If the git repository is on GitLab, put the following in .gitlab-ci.yml
:
image: alpine:latest
shellcheck:
before_script:
- adduser -D build
script:
- .ci/shellcheck.sh
Reference
CI script
The CI scripts need to have a specific format, so pmbootstrap ci
can use them. They must be named .ci/$scriptname.sh
in the root of the git repository.
The scripts must follow the following template:
#!/bin/sh -e
# Description: put your description here
# Options: slow
# https://postmarketos.org/pmb-ci
if [ "$(id -u)" = 0 ]; then
set -x
apk -q add \
replace-this-with-packages-to-install
exec su "${TESTUSER:-build}" -c "sh -e $0"
fi
replace-this-with-ci-commands-to-run
Metadata
The comments on the top hold some metadata:
# Description:
this is what gets displayed in the interactive prompt# Options:
a list of options to configure how pmbootstrap should handle this script. Omit this if no options are used.native
: this script should run natively instead of running it inside a pmbootstrap chroot. This makes sense when the CI script needs to run pmbootstrap itself, as pmbootstrap can't run inside pmbootstrap. Note that the block that usually installs dependencies will get skipped when running this withpmbootstrap ci
, so add checks for all dependencies before starting the tests and give the user a helpful message if something is missing. See.ci/pytest.sh
inpmbootstrap.git
as example.slow
: this script takes significant time to execute. Usually there are a few linter scripts that run rather fast, and a testsuite that takes longer. pmbootstrap will run scripts with theslow
option at the end.
# Artifacts:
path to a file or directory, which after the CI job is done will be copied into a "ci-artifacts" subdirectory on the host.# https://postmarketos.org/pmb-ci
: link to this wiki page, and a marker sopmbootstrap ci
knows that it may use this script
Installing dependencies
The block at if [ "$(id -u)" = 0 ]; then
is for installing dependencies with apk.
- Add
set -x
at the beginning, so theapk
andexec su
commands are printed to the terminal, it's useful to know what packages are installed and when the other block is entered. The output is well readable with these two commands printed. - At the end of the block, execute the CI script again but as testuser. The install dependencies block will get skipped then.
- When running on a CI server (e.g. SourceHut, GitLab), this block will run as root inside an Alpine edge container (even if the script has
native
set). - When running with
pmbootstrap ci
, this block will run as root user inside the pmbootstrap chroot. It has an apk cache set up (as always when using pmbootstrap's chroot). When this script has thenative
option set,pmbootstrap ci
just skips this block and runs the part below it. - Make sure everything that is needed to run the CI script is packaged in Alpine, consider packaging it yourself otherwise.
Running the test
- CI scripts runs with the git repository as working dir.
- Everything after the "Installing dependencies" block runs as testuser. "pmos" in case of pmbootstrap, or whatever the CI server uses.
- Make sure that its output is well readable, therefore it might be better to not use
set -x
and insteadecho
some messages about what it is doing
SourceHut config
For SourceHut, a build manifest needs to be written, typically into a .build.yml
file in the root of the git repository. See the example above.
This file just calls the CI scripts inside an alpine image. It uses sudo to elevate rights to root, so we can install dependencies at the beginning of the CI scripts (and do it only there, not repeat it in the manifest).
In theory it would be nice to use doas instead of sudo, but as of writing that didn't work out of the box.
GitLab config
For GitLab, a .gitlab-ci.yml file needs to be written. See the example above.
See also
- pmbootstrap and pmaports git repositories have plenty of CI scripts, all compatible with
pmbootstrap ci
- #2169: issue for implementing this feature