This project contains gitlab-ci config snippets and associated script to help in building an OpenEmbedded-based project.
This includes:
-
support for building for several platforms
-
support for building images or SDK
-
publication of package feeds
-
publication of shared-state for reuse by developpers
-
offload of build artifacts through rsync servers, as gitlab does not support large-enough artifacts
-
support for platform-specific branches using a branch prefix (eg.
board1/master
) -
persistence of downloads and shared-state directories
-
different downloads directories between major poky versions
-
different shared-state directories when you decide it (typically on toolchain change)
-
cascading inheritance of shared-state for use in dev branches to limit cache polution and inflation (eg.
BUILD_GEN: 1.2+next+mytest
) -
(optional) protection from shared-state polution by forcing non-official branches to use copy-on-write shared-state
-
optional usage of buildhistory repo and PR server
-
buildhistory stored in seprate branches for each platform and each source branch
-
archiving of interesting task logs as build artifacts (filtering out setscene and rm_work), even when bitbake ultimately fails
-
archiving of cooker log as build artifact, as the log of a full builds can exceed gitlab’s job-log size limit
-
hosted by gitlab 12.0 or higher (for multiple
extends
) -
this repository is included in your project repo as
/ci
(eg. using git submodule or subtree) -
yocto project’s Poky repository is available in your project repo as
/poky
-
all other layers are available under your project repo after
git checkout
andsubmodule update --init
-
if specified,
$BUILDHISTREPO
must be writable from your gitlab-ci user -
you have set up a PR server, accessible from your runner (which assumes both are located inside of a trusted network)
-
local.conf sets
RM_WORK_EXCLUDE = ""
for maximal reuse of shared-state
This has been only used with a submodule-based setup, other setups may
work too (eg. using git subtrees or Android’s repo
), examples and
patches welcomed.
-
assumes a single shell runner containing all tools required to build your project
-
the shared-state and download dirs are kept in the runner
-
to have the CI build for a given target plaform from a given branch of your source repository where it was never CI-built before, you must first push the
$BRANCHPREFIX_ARCH/$BASEBRANCHNAME
first -
lots of
siginfo
files in the shared-state get just their timestamp modified, resulting in much more rsync work than really needed -
usage through a submodule hits a limitation of current gitlab, where we must refer to the same submodule sha1 in the
gitlab-ci.yml’s `include:file
statement -
using
after_script
does not cause the job to fail if one of the deploying commands fail -
canceling a job from Gitlab does not fully cancel it (may be linked to the double-interrupt idiom designed for interractive use)
-
the deploy scripts have to hijack the whole
artifacts:paths
definition; to mitigate this, we create a directory namedartifacts
in which your own scripts can add other files you want saved as artifacts -
cleanup of copy-on-write shared-state currently has to be done manually
-
buildhistory push is not robust about any change done concurently during the build (limits the single shell runner to one job at a time - but anyway there’s no job control in place today to make running several of them concurently on the same runner)
-
buildhistory usage relies on external creation of new buildhistory branches, effectively limiting the build to externally-defined branches, which is a problem to run build jobs on tags
planned evolutions:
-
support docker-based runners (investigate CROPS and Pyrex)
-
get gitlab-ci to support submodules natively
-
add a safety net to avoid sha1 discrepancy between
/ci
and/.gitlab-ci.yml
-
check reachability of deploy servers before starting the build
-
auto-management of buildhistory branches, mirroring source history
- NOTE
-
this section is far from exhaustive, please refer to the "example use" and read
oe.yml
to use. Most notably, variables required by the various job templates are defined insideoe.yml
.
Aside from gitlab-ci variables, the configuration can be further adjusted for the project’s need using hook scripts:
ci-mkconf-hook.sh
-
a bash snippet to be sourced after creation of the build tree, suitable for appending project-specific variables to
conf/local.conf
. It is sourced bymkconf
after sourcingpoky/oe-init-build-env
(or a user-provided alternate env-setting script) and thus runs from within the build tree, and can use any of the local variables set inmkconf
, including OE envvars.
A file named permissions
can be created in the sstate-cache dir, to
specify which repositories, branches, and tag patterns will be allowed
to contribute to this particular shared-state. It is expected to
contain one line per allowed repository, with fields separated by a
|
character.
Currently defined fields are:
<repo_url>|<branch_list>|<tag_pattern_list>
<branch_list>
is interpreted as a space-separated list of branch
names. <tag_pattern_list>
is interpreted as a space-separated list
shell glob patterns against which tags are checked.
If <branch_list>
or <tag_pattern_list>
is not specified or empty,
all branches (resp. all tags) are allowed. If no line matches the
repo to which the job belongs, or if the branch or tag does not match
the declaration for this repo, the build is aborted.
If the permissions
file does not exist, no restriction is enforced.
If it is empty, the rules described above imply no job can contribute
to this shared-state any more.
To avoid older settings from breaking, the build will also be aborted
if a legacy BASEGEN_ALLOWED_BRANCHES
variable is defined, to give
the opportunity to migrate to permissions
files, rather than just
ignoring the requested safeguard (as low-tech as it was).
You may run mkconf
from your own working copy to see if the
generated build configuration meets your expectations. It will
emulate being running by gitlab-ci from your current branch.
-
update the scripts (eg.
git add
the newer version of submodule) -
update
include
sha1 in [.gitlab-ci.yl] -
check what changed in [NEWS.adoc] since the previous version
include: - remote: "https://raw.githubusercontent.com/BladeGroup/gitlab-oe/161fd388350fb263a35f1ec598d1911ab3926035/oe.yml"
variables: GIT_SUBMODULE_STRATEGY: recursive BUILD_GEN: "1.2" POKY_BASE: "warrior" B: "build" BUILDHISTREPO: "ssh://[email protected]/oe/buildhistory.git" PRSERV: "prserv.company.net:8585"
.template_variables_board1: &variables_board1 YOCTO_ARCH: "x86_64" UPDATE_ARCH: "board1" BRANCHPREFIX_ARCH: "board1"
.board1_exceptions: except: - /^board2\/.*$/
cache: paths: - $B/cache
stages: - build
.my_oe_setup: extends: .oe_setup tags: - oe when: manual only: - branches
board1-image: variables: <<: *variables_board1 extends: - .my_oe_setup - .oe_deploy - .oe_buildlogs_artifacts - .board1_exceptions allow_failure: false stage: build script: - ./ci/run-bitbake --dir "${B}" -- -k core-image-x11 my-packagegroup # save/deploy artifacts - ./ci-my-images-deploy ...
board1-sdk: variables: <<: *variables_board1 IMGROOT: core-image-x11 extends: - .my_oe_setup - .oe_buildlogs_artifacts - .board1_exceptions stage: afterbuild script: - ./ci/run-bitbake --dir ${B} -- ${IMGROOT} -c populate_sdk - tar -C $B/tmp/deploy/sdk/ -cvf - . --xform=s,^.,${YOCTO_ARCH}/${BASEBRANCHNAME}, | ssh -p ${SSH_SDK_PORT} ${SSH_SDK_SRV} tar -C ${SSH_SDK_DIR} -xf -
The rsync-sstate
script will mirror the shared-state uploaded to a
server after the build. The rsync URL for the shared-state repo can
be specified in a .gitlab-oe.conf
at the toplevel of your git
repository, alongside .gitlab-ci.yml
. It can be overriden by the
--repo
flag if needed.
The shared-state generation will be read from .gitlab-ci.yml
, and
can be overriden by the --gen
flag.
If your BUILD_GEN
is set to 1.2+next+mytest
, you must set
SSTATE_MIRRORS
to make use or 1.2+next
and 1.2
, or the artifacts
provided by those base shared-states won’t be visible and will be
rebuilt. For example:
SSTATE_MIRRORS ?= "\ file://.* file://${HOME}/sstates/sstate-cache-1.2/PATH \n \ file://.* file://${HOME}/sstates/sstate-cache-1.2+next/PATH \n \ " SSTATE_DIR = "${HOME}/sstates/sstate-cache-3+dev"
Those base sstates are fetched automatically by rsync-sstate
.