Run your first CI workflow
Add a .ckgit/ci.yml workflow to a hosted project to build and test every push.
Results, logs, and artifacts appear in the dashboard and in ckgit ci.
The server administrator first configures the CI runner.
Enable CI for a project
Opt in per project with ckgit-admin on the server. It must run as the ckgit
service account, which owns the private state root (plain sudo runs it as
root, which the state root's ownership check refuses), and it needs the
configuration file to find that state root:
sudo -u ckgit ckgit-admin ci enable myproject --config /etc/ck-git-hosting/server.ini
sudo -u ckgit ckgit-admin ci status myproject --config /etc/ck-git-hosting/server.ini
ci status prints myproject: CI enabled or myproject: CI disabled. Use
ci disable to turn it off again; disabling stops new runs but keeps existing
run history. Removing the project also clears its CI opt-in and records.
Enabling and disabling CI are administrator actions: a paired device can see
whether CI is on (ckgit ci status) but cannot change it.
Write .ckgit/ci.yml
Commit the workflow at .ckgit/ci.yml in the repository. It is read from the
pushed commit, so a build always matches the commit that triggered it. This
section gets a first workflow running; the
.ckgit/ci.yml reference has every accepted and
rejected syntax construct, the complete schema and bounds, the trigger
matrix, and the exact sandbox and environment a step runs in.
version: 1
on: { branches: [main] }
env: { BUILD_ROOT: /tmp/ck }
jobs:
- name: build
steps:
- run: [make, all]
- name: tests
run: make check
- script: |
make docs
artifacts:
name: build
paths: [dist/, build/app.bin]
retention_days: 14
version:must be1.on: { branches: [...] }andon: { tags: [...] }choose which branches and tags trigger the workflow (a tag pattern is an exact name or a trailing*, such asv*). Omiton:entirely to build the default branch and cut a release on any tag. A non-triggering ref is recordedskipped, as is a commit with no.ckgit/ci.yml. The default branch is whatever the hosted repository'sHEADnames;ckgit default-branchshows it andckgit default-branch BRANCHchanges it. The change takes effect for the next push; it does not start a build by itself.env:is fixedkey: valuepairs; there is no$VARexpansion. A job'senv:is merged over the top-levelenv:.- A step's
run:written as a list is an exact command with no shell. Arun:scalar or ascript:block runs withsh -ecinside the sandbox. artifacts:(optional, per job) packs the namedpathsinto one bundle after the job's steps succeed.pathsare relative to the checkout and may not be absolute or contain..;namedefaults to the job name and may not berelease, which names the release record a tag build writes beside each asset's own sidecar;retention_daysoverrides the server default and is clamped to its maximum.sisters:lists other projects hosted on this server whose source the build needs. Each is materialised read-only beside the checkout — reachable as../<name>and exported asCKGIT_SISTER_<NAME>— from its default branch, or a branch, tag, or commit you pin. No network is used and only same-server projects are allowed. Write- namefor the default branch, or the two-line form below it to pin. The project may name itself only with a pinnedref, to read another of its own branches. See below.cache:lists persistent build caches (e.g. a ccache store) kept across runs. Each is a directory exported asCKGIT_CACHE_<NAME>, plus any variables bound withenv:. Persistence needsci_cache_rootset on the server; without it a declared cache still works, only per-run, so a workflow is portable. See below.
The format is a strict, bounded subset of YAML — not GitHub Actions. Unknown
keys, tabs for indentation, wrong types, or anything past the documented size
limits are rejected, and the run is recorded error with the reason. Keep a
workflow well under 64 KiB, 64 jobs, and 128 steps per job.
Check a workflow before pushing it: ckgit ci lint parses .ckgit/ci.yml
from the working tree (or a file, or a commit with --rev REV) with the
runner's own parser, and prints a summary of its triggers and jobs or the
first error with its line. It works offline, so it cannot know the server's
default branch, whether sister projects exist, or the server's limits.