Repository navigation
Publish nightlies to GHCR #412
Replies: 3 comments
ponyup is live — a model for the other toolsponyup now dual-publishes its nightlies to GHCR alongside Cloudsmith. The work landed in #433, and the first scheduled nightly after it merged confirmed the whole thing in production: all six platforms published, the prune job ran clean, and the artifacts pull anonymously with their hashes intact. I'm writing the shape down so corral, ponyc, and changelog-tool can be cut from the same pattern. The whole change is additive. Cloudsmith publishing is untouched. Every platform's nightly build, right after its existing Cloudsmith push, ships the same archive a second time to The pieces to copyA stdlib-only push script, one per tool. Same posture as the Call it from the existing nightly script, after the Cloudsmith push. It reuses the date and the archive the Cloudsmith step already produced, so both destinations get the same bytes under the same date string. Ordering is deliberate: GHCR runs second. If GHCR ever falls over, it can't take the primary download source down with it. Workflow plumbing. Bump the workflow to A prune job. Ages out GHCR tags older than 90 days with What the experiment settled, and the first nightly confirmedBefore touching the real pipeline I proved the whole thing out on a throwaway
Check these per tool before cutting the PR
Rolling each one outProve it once in isolation if a tool's matrix makes you nervous, then integrate and let the next scheduled nightly exercise the platforms you can't run by hand. Because GHCR sits behind Cloudsmith, a per-platform stumble surfaces in the usual Zulip alert without costing anyone a nightly. Fix forward from there. Validating after the first nightlyA green board is necessary but not sufficient — confirm the packages are actually there, public, and intact. This is the same pass I ran for ponyup; repeat it per tool, swapping in the tool name, a triple, and the date.
Reading the result:
The exact diff to copy is in #433. |
|
corral and changelog-tool have been implemented. |
|
ponyc has been implemented as well. |
Uh oh!
There was an error while loading. Please reload this page.
Today, nightly tool binaries go to our Cloudsmith nightlies repository and nowhere else. We're adding GHCR as a second destination, storing nightlies as ORAS artifacts under a
nightly/path segment, and trimming the GHCR copy at 90 days. Cloudsmith publishing stays as it is.Unlike the release-channel migration, nightlies don't land in per-tool GitHub Releases — that would clutter each tool's release list with daily noise. GHCR is already where each tool stores its container images and CI builder images. Nightlies fit there too.
Divergences from today
Settled
nightly/path segment. Tag matches theYYYYMMDDdate string each tool's nightly CI already passes to its Cloudsmith push. ponyc's x86-64 alpine3.23 nightly for 2026-04-12 lives atghcr.io/ponylang/nightly/ponyc-x86-64-unknown-linux-alpine3.23:20260412.nightly/path segment is deliberate. It mirrors the Cloudsmith split betweenponylang/nightliesandponylang/releases, and it reserves room for releases to move to GHCR-as-ORAS later (underghcr.io/ponylang/release/...) as a purely additive change. No rename of existing image names ever required.YYYYMMDDdate string is computed once per platform job and passed to both the Cloudsmith and GHCR push steps, so a midnight-UTC rollover can't split the two destinations across different dates.github_release.pyscript releases use. Python3 availability in ponyup's builder image was verified during the releases work; other tools' builder images need the same probe before their PR lands (see pre-implementation verification). The script uploads the archive blob, uploads a config blob declaring the artifact type, PUTs the manifest, and sets the GHCR package to public. Every HTTP call checks for 2xx; non-2xx prints status and response body to stderr and exits non-zero. The visibility call is idempotent, and any failure — visibility or otherwise — fails the push. There is no code path that produces a private nightly. Authenticates against GHCR withGITHUB_TOKENandpackages: writeon the job..ci-scripts/, per-tool copy. Matches thegithub_release.pyprecedent.application/vnd.ponylang.nightly.v1.application/vnd.ponylang.nightly.config.v1+json, body carries{tool, platform, version, sha512, built_at}. Ponyup can read metadata straight off the manifest response without fetching the archive.application/vnd.ponylang.nightly.archive.v1.tar+gzipfor Linux/Darwin,application/vnd.ponylang.nightly.archive.v1.zipfor Windows.sha256:-prefixed digests on manifests and blobs in practice, so the OCI manifest carries the SHA-256 digest of the archive as registry-enforced integrity. SHA-512 of the archive goes in the config blob, continuing the "SHA-512 everywhere" convention from the releases plan for any ponyup code path that wants to cross-check.snok/container-retention-policy(pinned to a commit SHA, matching the pinning convention ponyc already uses for this action) withtag-selection: taggedand a 90-day cutoff — ninety days covers the tail of users who lag on picking up nightlies; older than that is debugging archaeology and can fall back to Cloudsmith.image-nameseither enumerates the per-(tool, platform) names or uses a glob against thenightly/path segment, depending on what the action accepts (see pre-implementation verification). A YAML comment on the prune job names the invariant: every platform publish job must appear in the prune job'sneeds:list before any artifact is eligible for deletion. That comment lives on the prune job, not on each platform job — the prune job's behavior is what breaks if someone adds a platform without updatingneeds:.General shape, per tool
Each tool's
nightlies.ymlhas its own platform matrix — ponyc has the most (roughly a dozen jobs across Linux distros, macOS, and Windows); ponyup and corral have six apiece; changelog-tool fewer. The shape of the change is the same regardless of how the matrix is structured:cloudsmith push rawstep, reusing the archive the Cloudsmith push already produced. Same version string. Pushes toghcr.io/ponylang/nightly/<tool>-<triple>:<date>. Workflow gainspackages: write.snok/container-retention-policyusage inponyc/.github/workflows/build-nightly-image.yml, adapted to thenightly/<tool>-<triple>image names and a 90-day cutoff instead of 1 day.Details — how auth is set up, the exact config-blob field set, exactly how the prune job names its images — may vary per tool.
Pre-implementation verification
Before the first implementing PR lands, verify on an experimental image name:
snok/container-retention-policyaccepts multi-segment image names (nightly/<name>). Ponyc's current usage is on single-segment names, so this is new ground. Confirmcut-off: 90dis syntactically valid (the existing usage is1d) and determine whetherimage-namessupports a glob across path segments or requires enumeration.If any of these fail in ways we can't work around, fall back to channel-in-package-name (
ghcr.io/ponylang/nightly-<tool>-<triple>). The path segment is a preference, not load-bearing.Out of scope
All reactions