Files
ConformalLabpp/doc/architecture/ci-cd.md
Tarik Moussa a2464af8b1 ci: add Codeberg CI (Woodpecker + Forgejo) and document CI/CD topology
Add a lightweight test-fast pipeline for the public Codeberg mirror so it
shows a build status, defined for both CI systems Codeberg offers:
- .woodpecker.yml            (Woodpecker, debian:bookworm)
- .forgejo/workflows/        (Forgejo Actions, node:20-bookworm, runner label docker)

Both run the pure-math suite only (Eigen vendored, GTest via FetchContent;
no CGAL/Boost), using public images and the docker runner label since the
private eulernest ci-cpp image and Pi runner are unreachable from Codeberg.

Docs:
- new doc/architecture/ci-cd.md: two-forge topology, runners, trigger
  keywords, mirror mechanism.
- fix stale "codeberg/main ... no CI" claim in contributing.md and bring
  the CI table up to date.
- link the new doc from the README doc index.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 23:26:46 +02:00

5.2 KiB
Raw Blame History

CI / CD

Single source of truth for how continuous integration is wired across the two forges this project lives on. If you add, move or rename a workflow, update this page.

TL;DR

Forge Remote Role CI system Config Runner
eulernest Gitea origin Authoritative gate (full test + quality suite) Gitea Actions .gitea/workflows/ self-hosted Raspberry Pi (ARM64), label eulernest
Codeberg codeberg Public mirror + public build badge Woodpecker and Forgejo Actions .woodpecker.yml, .forgejo/workflows/ Codeberg shared runners, label docker

The two forges are connected by a one-way mirror: every push to main on eulernest is force-mirrored to Codeberg (see Mirror below). Codeberg never pushes back.

Why two CI systems on Codeberg? They are independent and either may be enabled per-repo; providing both means the public build status is green regardless of which one the repo has switched on. They run the same test-fast build.


eulernest Gitea (origin) — the real gate

Self-hosted Gitea with a single self-hosted runner: a Raspberry Pi (ARM64, 34 GB RAM). Because the runner is RAM-constrained, the heavy jobs are keyword-gated (opt-in per commit) rather than run on every push.

All C++ jobs use the private image git.eulernest.eu/conformallab/ci-cpp:latest (built from .gitea/docker/Dockerfile.ci-cpp — Ubuntu 22.04 + Node 20 + cmake + build-essential + libboost-dev + doxygen).

.gitea/workflows/cpp-tests.yml

Job Trigger Memory cap What it does
test-fast every push to main / claude/** / feature/** / review/** + every PR 800 MB Pure-math suite (Clausen, ImLi₂, hyper-ideal). Serial build (-j1) to avoid OOM. Eigen vendored, GTest via FetchContent.
test-cgal commit message contains /test-cgal 2000 MB Full CGAL suite via LOW_MEMORY_BUILD (-O0, no PCH, unity batch 1, --no-keep-memory). Then check-test-counts.sh + try_it.sh smoke test.
quality-gates commit message contains /quality-gates 600 MB License headers, CGAL conventions, codespell, shellcheck, coverage (gate currently in report-only mode, SKIP_COVERAGE_GATE=1).

One keyword per commit — the Pi cannot sustain multiple Docker containers at once (/ci-all was removed for this reason). Example: git commit -m "fix: correct angle formula /test-cgal".

Other eulernest workflows

File Trigger Purpose Blocks merge?
doc-build.yaml push to main branches + manual Doxygen HTML + warning stats No (continue-on-error)
markdown-links.yml push + weekly cron (Mon 05:00 UTC) + manual Link-rot check across docs Yes on push
doxygen-pages.yml manual only Publish Doxygen HTML to Codeberg Pages (tmoussa.codeberg.page/ConformalLabpp/) n/a
perf-compile-time.yml manual only Compile-time benchmark n/a
mirror-to-codeberg.yml push to main Mirror all branches to Codeberg (see below) n/a

Codeberg (codeberg) — public mirror CI

Codeberg's shared runners cannot pull the private ci-cpp image and are not the eulernest Pi, so the Codeberg configs differ from Gitea in exactly two ways:

  1. Runner label docker (Codeberg shared runners), not eulernest.
  2. Public base image, with build tools apt-installed at run time:
    • Woodpecker: debian:bookworm
    • Forgejo Actions: node:20-bookworm (Node is needed by actions/checkout@v4; cmake/g++/make are installed in the first step).

Both run only test-fast — the pure-math suite. No CGAL/Boost/Wayland, so they are fast (< 2 min) and headless. Eigen is vendored, GoogleTest is fetched at configure time (Codeberg runners have network). A failing build or any failing ctest turns the public CI badge red.

File CI system Enable via
.woodpecker.yml Woodpecker https://ci.codeberg.org → enable repo
.forgejo/workflows/cpp-tests.yml Forgejo Actions repo Settings → Actions (shared runner label docker)

These configs are committed in the repo and reach Codeberg through the mirror — they are not maintained separately on Codeberg.


Mirror (eulernest → Codeberg)

.gitea/workflows/mirror-to-codeberg.yml runs on every push to main and does a git push --mirror from eulernest to codeberg.org/TMoussa/ConformalLabpp.git. It uses two secrets:

  • MIRROR_TOKEN — read access to the eulernest source repo.
  • CODEBERG_TOKEN — push access to the Codeberg mirror.

The mirror is one-way and authoritative-from-eulernest: do not commit directly on Codeberg, it will be overwritten on the next mirror run.


The one rule

eulernest is the gate, Codeberg is the shop window. Merge decisions are made on eulernest CI (full suite). Codeberg CI exists so the public repo also shows a green/red build status to outside readers.

See also