repoman CI + binary release — design
Date: 2026-06-02
Status: Approved (design), pending implementation
Author: Chris Tusa chris.tusa@leafscale.com
Goal
Build, test, and release repoman binaries automatically via Isurus CI, using
the prebuilt reef-lang toolchain container as the build environment. On every
push/PR: build + test. On a version tag: also package a binary bundle and publish
it as an Isurus release asset.
Context
- repoman is a reef application (compiles to a single
build/repomanbinary via
reefc), not the reef compiler. It also shipsprofiles/*.ymland
recipes/{docker,claude}/*thatmake installlays under
/usr/local/share/repoman. - Isurus CI config is
.isurus-ci.ymlat the repo root, hg-native (hg push
triggers;hg tag vX && hg push→ tag event). Steps run indocker:images;
container-registry:authenticates private pulls; a top-levelrelease:block
attachesassets:globs to the release on tag using areleases:writetoken. - The build image
registry.sharkos.one/reef/reef-builder:latestalready contains
a pre-installed reef compiler (reefcon PATH, runtime + clang/lld baked in;
reefc doctorpasses). Noopam envsetup is needed — that is only for building
the compiler from OCaml source, which repoman does not do. - Reference pipelines:
~/repos/reef-lang/.isurus-ci.yml(canonical Isurus
example) and~/repos/zygaena-project/coral/.woodpecker.yml(a reef app release,
pre-Isurus). This design follows reef-lang's structure.
Decisions
- Release contents: binary bundle only (no source tarball).
- Installer: a standalone
install.shinside the bundle — end users need no
reefc and no Makefile to install. - Arch:
linux-amd64only (the reef-builder image and repoman's Incus-host
target are x86-64). arm64 deferred. - Build image tag:
:latest(floats with the toolchain, matching reef-lang),
not a pinned:0.6.5. - Triggers: build + test on
[push, pull_request, tag]; package + release on
[tag]only. Singlewhen:filter map, no top-levelbranch:gate (a branch
gate is incompatible with PR CI — per reef-lang's CLAUDE.md note). - Version source of truth: the
versionfield inreef.toml(currently
0.6.0). Packaging derives the version from it; the release fires off$CI_TAG.
Components
1. .isurus-ci.yml (repo root, new)
container-registry:
- url: registry.sharkos.one
secret: SHARKOS_REGISTRY_CREDS
when:
event: [push, pull_request, tag]
steps:
- name: build
docker: { image: registry.sharkos.one/reef/reef-builder:latest }
commands:
- reefc doctor
- make all
- ./build/repoman --version
timeout: 30m
- name: test
docker: { image: registry.sharkos.one/reef/reef-builder:latest }
commands:
- make test
timeout: 30m
- name: package
docker: { image: registry.sharkos.one/reef/reef-builder:latest }
when: { event: [tag] }
commands:
- ./scripts/package-binary.sh
- ls -la dist/
timeout: 30m
release:
tag: "$CI_TAG"
title: "repoman $CI_TAG"
assets:
- dist/*.tar.gz
- dist/*.sha256
secret: ISURUS_RELEASE_TOKEN
when:
event: [tag]
Notes:
make alllives only inbuild. Steps share the cloned workspace and run
sequentially (pipeline halts on first failure), sopackageonly runs after
build/testpass. Each target is also self-sufficient:make testcompiles
and runs the test files directly viareefc run(no dependency on
build/repoman), andpackage-binary.shcallsmake install, whose phony
buildprerequisite rebuilds the binary. No repeatedmake all.reefc doctorinbuildgives an early, legible failure if the toolchain image
is broken.
2. scripts/package-binary.sh (new, executable)
Produces dist/repoman-<version>-linux-amd64.tar.gz and a matching .sha256.
Behavior:
- Derive
VERSIONfromreef.toml(grep '^version' | sed), allow override via
$1. NAME=repoman-${VERSION}-linux-amd64,DIST=${REPOMAN_DIST:-dist}.- Stage the real install tree by reusing the Makefile:
make install DESTDIR="$STAGE/$NAME" PREFIX=/usr/local
→$STAGE/$NAME/usr/local/{bin/repoman, share/repoman/...}. - Add
README.md,LICENSE, and a generatedinstall.sh(see §3) to
$STAGE/$NAME/. tar -czf "$DIST/$NAME.tar.gz" -C "$STAGE" "$NAME".sha256sum "$DIST/$NAME.tar.gz" > "$DIST/$NAME.tar.gz.sha256".set -eu; clean up$STAGEon exit.
Rationale for reusing make install: the tarball's tree stays byte-identical to a
real install, so there is one definition of the install layout (DRY) — when a new
recipe/profile is added, the bundle picks it up automatically.
3. Bundled install.sh (inside the tarball)
Relocatable installer; needs no reefc, no make. Run from the unpacked bundle dir:
#!/bin/sh
set -eu
PREFIX="${PREFIX:-/usr/local}"
here="$(cd "$(dirname "$0")" && pwd)"
# Copy the staged usr/local tree into PREFIX.
cp -a "$here/usr/local/." "$PREFIX/"
echo "repoman installed under $PREFIX"
"$PREFIX/bin/repoman" --version
- Honors
PREFIX(default/usr/local); preserves perms (cp -a) so the
launcher recipe stays0755. - Mirrors what
make installdoes, minus the build dependency.
4. .hgignore (edit)
Add dist/ so packaging output is not accidentally committed.
Data flow
hg push (branch) -> build + test
hg push (PR) -> build + test
hg tag vX.Y.Z && hg push -> build + test + package -> dist/*.tar.gz(+.sha256)
-> release: attach assets to vX.Y.Z
Prerequisites (operator-side, outside this repo)
Two CI secrets must exist for the repoman repo (or its org) in Isurus
CI/CD > Secrets:
SHARKOS_REGISTRY_CREDS— Harbor robot creds JSON
{"username":"robot$ci","password":"<token>"}to pull the builder image.ISURUS_RELEASE_TOKEN— token withreleases:writescope.
reef-lang already uses both names; if they are org-scoped, repoman inherits them.
Testing / verification
- Local dry runs (no CI needed):
make all && make testinside the builder image (or locally) stays green../scripts/package-binary.shproduces a tarball; unpack to a temp dir, run its
install.shwithPREFIX=$(mktemp -d), and confirmbin/repoman --version
prints the bundle version and the claude launcher lands at0755.
- CI smoke: push a branch → build+test pipeline goes green. Then a throwaway
tag (or the next real release tag) exercises package + release end to end.
Out of scope
- Source tarball, multi-arch (arm64), signing/notarization, publishing to any
index beyond Isurus releases, and container-image publishing for repoman itself.
Files touched
| File | Change |
|---|---|
.isurus-ci.yml |
new — pipeline + release block |
scripts/package-binary.sh |
new, 0755 — binary bundle + sha256 |
.hgignore |
add dist/ |
Makefile |
(if needed) confirm install works with DESTDIR/PREFIX — already verified |
README.md |
brief "Releases / CI" note (optional) |