writeonce/.github/workflows/release.yml
shoney.arickathil cfe81cf8d0 ci: release workflow — no gh auth login, tag-triggered
- .github/workflows/release.yml: builds, verifies and publishes on a
  `v*` tag. `permissions: contents: write` on the injected
  GITHUB_TOKEN replaces `gh auth login`; no PAT, nothing to rotate
- runs-on ubuntu-22.04 DELIBERATELY: the build host's glibc caps which
  symbol versions the binaries import, and that cap is the floor every
  user needs. 22.04 (2.35) includes Ubuntu 22.04 / Debian 12 / RHEL 9;
  24.04 (2.39) would exclude them
- guards that fail instead of publishing: tag vs VERSION, produced
  asset name vs the filename /install links, sha256, and a smoke test
  that builds a hello project with the binaries INSIDE the tarball
- reports the shipped glibc floor so the claim on /install is checkable
  from a build log
- releasing.md: pipeline route up front, manual route kept; GH_TOKEN
  recipe for non-GitHub CI

Not run — this repo has no CI history and Actions cannot execute
locally. Every guard's shell was dry-run here against the real dist.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 04:58:40 +02:00

119 lines
4.6 KiB
YAML

# NOTE: this workflow has never run. Authored 2026-08-25 and not
# executable locally — the first real tag push is its first test.
# Expect to adjust the toolchain step if the pinned OCaml/dune version
# is not available on the runner image.
name: release
# Fires only on a version tag, so nothing is published by an ordinary
# push. `workflow_dispatch` is the manual escape hatch for a re-run.
on:
push:
tags:
- 'v*'
workflow_dispatch:
# The ONE line that replaces `gh auth login`: it widens the automatic
# GITHUB_TOKEN so this job may write releases. No PAT, no secret to
# rotate, and the token dies with the job.
permissions:
contents: write
jobs:
release:
# DELIBERATE, not a default. The release binaries link glibc
# dynamically, so the build host's glibc caps which symbol versions
# they can import — and that cap becomes the minimum glibc every
# user needs. Built on 24.04 (glibc 2.39) the floor is 2.39;
# built here on 22.04 (2.35) it is 2.35, which is the difference
# between excluding and including Ubuntu 22.04, Debian 12 and
# RHEL 9. Raise this image only with a reason, and update the
# supported-systems list in docs/examples/site/install/view.wo in
# the same change.
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
# The compiler is OCaml stdlib only — no opam packages — so this
# step exists purely to get a compiler and dune onto the runner.
- uses: ocaml/setup-ocaml@v3
with:
ocaml-compiler: '4.14'
# The tag is the release's identity; VERSION is what the binaries
# report. If they disagree the download URL would name a version
# nobody can install. mkdist.sh already guards VERSION against the
# binaries; this guards the tag against VERSION.
- name: Tag must match VERSION
run: |
tag="${GITHUB_REF_NAME#v}"
ver="$(cat VERSION)"
[ "$tag" = "$ver" ] || {
echo "tag $GITHUB_REF_NAME does not match VERSION $ver" >&2
exit 1
}
- name: Build the tarball
run: ./scripts/mkdist.sh
# The site links one exact filename. If mkdist ever changes its
# naming, the download button 404s for every visitor — so fail
# here instead.
- name: Asset name must match what the site links
run: |
ver="$(cat VERSION)"
asset="writeonce-${ver}-linux-amd64.tar.gz"
test -f "dist/$asset"
grep -q "$asset" docs/examples/site/install/view.wo || {
echo "$asset is not the filename /install links" >&2
exit 1
}
- name: Verify the digest
run: cd dist && sha256sum -c "writeonce-$(cat ../VERSION)-linux-amd64.tar.gz.sha256"
# Prove the ARTEFACT works, using the binaries inside it rather
# than the ones just built in the tree. This is what catches a
# tarball that packaged the wrong thing.
- name: Smoke-test the extracted toolchain
run: |
ver="$(cat VERSION)"
tmp="$(mktemp -d)"
tar -C "$tmp" -xzf "dist/writeonce-${ver}-linux-amd64.tar.gz"
export PATH="$tmp/writeonce/bin:$PATH"
woc version
wovm --version
mkdir -p "$tmp/hello"
cd "$tmp/hello"
printf 'name = "hello"\nversion = "0.1.0"\n\n[runtime]\nwo = ">= 0.1"\n' > wo.toml
printf 'fn main() -> Int {\n print("hello, writeonce");\n return 0;\n}\n' > main.wo
woc .
out="$(./target/hello)"
[ "$out" = "hello, writeonce" ] || { echo "got: $out" >&2; exit 1; }
# Record the real glibc floor of what is about to ship, so the
# claim on /install can be checked against a build log rather
# than trusted.
- name: Report the glibc floor
run: |
ver="$(cat VERSION)"
tmp="$(mktemp -d)"
tar -C "$tmp" -xzf "dist/writeonce-${ver}-linux-amd64.tar.gz"
for b in "$tmp"/writeonce/bin/*; do
printf '%s needs %s\n' "$(basename "$b")" \
"$(objdump -T "$b" | grep -oE 'GLIBC_[0-9.]+' | sort -uV | tail -1)"
done
# gh is preinstalled on GitHub runners and reads GH_TOKEN from the
# environment, so there is no `gh auth login` anywhere in this file.
- name: Publish
env:
GH_TOKEN: ${{ github.token }}
run: |
ver="$(cat VERSION)"
gh release create "$GITHUB_REF_NAME" \
"dist/writeonce-${ver}-linux-amd64.tar.gz" \
"dist/writeonce-${ver}-linux-amd64.tar.gz.sha256" \
--title "writeonce ${ver}" \
--generate-notes