Shared CI contracts vendored by all repos
Find a file
2026-10-08 15:03:59 +02:00
ci feat: initial shared CI templates (justfile.ci, ci helpers, workflow models) 2026-10-08 14:54:00 +02:00
ci.yml.maps fix: vendor via local clone archive, git archive --remote 404s on Forgejo 2026-10-08 15:03:59 +02:00
ci.yml.rust fix: vendor via local clone archive, git archive --remote 404s on Forgejo 2026-10-08 15:03:59 +02:00
ci.yml.wasm fix: vendor via local clone archive, git archive --remote 404s on Forgejo 2026-10-08 15:03:59 +02:00
justfile.ci feat: initial shared CI templates (justfile.ci, ci helpers, workflow models) 2026-10-08 14:54:00 +02:00
README.md fix: vendor via local clone archive, git archive --remote 404s on Forgejo 2026-10-08 15:03:59 +02:00

alysia-ci-templates

Shared CI contracts vendored by all repos. One canonical justfile.ci (lint/test/build/push/wasm recipes), three POSIX-sh helpers (ci/), and one workflow model per repo type (ci.yml.*).

Context: the Forgejo runner (alysia-ci, host-shell, no node) has no actions/checkout — every job starts with the same ~15-line git bootstrap (frozen, the only accepted duplication), then calls just recipes. Copying that foundation into every repo by hand guarantees drift; this repo is the single source of it.

Layout

File Role
justfile.ci Canonical recipes: ci-lint (fmt + clippy + machete + deny), ci-test (test_args selects the subset), ci-build / ci-push (OCI via ci/registry.sh), ci-wasm (component + size floor). Variables, no repo names.
ci/checkout.sh Materializes the ref under test (never the default branch by accident) + repo-local credential helper. From the monorepo, CI_REPO_URL genericized.
ci/registry.sh Job-scoped registry authfile + tag/push. From the monorepo, unchanged.
ci/stack.sh wait_for_stack compose health waits (date +%s, never $SECONDS). From the monorepo, unchanged.
ci.yml.rust Model for a Rust service/library repo: freshness + lint/test/build/push.
ci.yml.wasm Model for a WASM plugin repo (own lockfile): freshness + lint/native tests/ci-wasm.
ci.yml.maps Model for a data/maps repo (digest-only): freshness + sha256sum -c of the committed digest.

Vendoring into a consumer repo

tpl="https://git.zeto.fr/alysia/alysia-ci-templates.git"
rev="tpl-v0.1.1"  # latest tag
tmp="$(mktemp -d)"
# NOTE: `git archive --remote` is not served by this Forgejo instance
# (HTTP 404), so archive from a throwaway local clone at the tag instead.
git clone --quiet --depth 1 --branch "$rev" "$tpl" "$tmp/tpl"
git -C "$tmp/tpl" archive HEAD justfile.ci ci | tar -x
mkdir -p .github/workflows
cp "$tmp/tpl/ci.yml.rust" .github/workflows/ci.yml  # pick the model
rm -rf "$tmp"

Then in the workflow: set CI_REPO_URL, the concurrency group, and keep TEMPLATE_REV=<tag you vendored>. Renovate bumps it afterwards.

Policy

  • Never patch vendored files locally. The ci-freshness job (first in every model) diffs justfile.ci + ci/ against $TEMPLATE_REV and fails with "re-vendor" on any local edit. Fix the template repo, tag, re-vendor.
  • Versioning: tags tpl-vX.Y.Z. Breaking = new major + note here.
  • All shell is POSIX sh (shellcheck -s sh + dash -n before commit).
  • Docs and code in English. Commits follow Conventional Commits.

Freshness job

Each model declares ci-freshness first: checkout via the frozen bootstrap, fetch the template repo at $TEMPLATE_REV, git archive it to a temp dir, cmp the four vendored files. Under a minute, no toolchain needed.