v0.1.0 #38
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| # One release pipeline, two phases. | |
| # | |
| # A push to the candidate ref builds every native target, attests | |
| # provenance, uploads everything to a DRAFT GitHub release, and | |
| # smoke-builds the container image. Publishing the draft is a separate, | |
| # human-approved step after the candidate binaries pass verification; a | |
| # failed candidate is deleted and main never moves. | |
| # | |
| # Publishing the release (release: published) triggers the container | |
| # phase: architecture images are built from the tagged commit, pushed to | |
| # GHCR, and stitched into a multi-architecture manifest with the same | |
| # provenance attestation as the binaries. | |
| on: | |
| push: | |
| branches: | |
| - candidate | |
| release: | |
| types: [published] | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: release-${{ github.event_name }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| env: | |
| RUST_VERSION: 1.97.1 | |
| IMAGE: ghcr.io/denoland/celld | |
| jobs: | |
| build-celld: | |
| name: Build celld ${{ matrix.target }} | |
| if: github.event_name != 'release' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - runner: ubuntu-22.04 | |
| target: x86_64-unknown-linux-gnu | |
| - runner: ubuntu-22.04-arm | |
| target: aarch64-unknown-linux-gnu | |
| - runner: macos-14 | |
| target: aarch64-apple-darwin | |
| runs-on: ${{ matrix.runner }} | |
| timeout-minutes: 90 | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Build | |
| run: | | |
| set -euo pipefail | |
| rustup toolchain install "$RUST_VERSION" --profile minimal | |
| rustup default "$RUST_VERSION" | |
| cargo build --release --locked | |
| version=$(sed -n 's/^version = "\(.*\)"$/\1/p' crates/celld/Cargo.toml | head -1) | |
| target/release/celld --version | grep -F "$version" | |
| - name: Package | |
| run: | | |
| set -euo pipefail | |
| mkdir -p out | |
| # -n omits name and timestamp so the envelope is reproducible | |
| # whenever the binary is. | |
| gzip -9 -n -c target/release/celld \ | |
| > "out/celld-${{ matrix.target }}.gz" | |
| - uses: actions/upload-artifact@v4 | |
| with: | |
| name: celld-${{ matrix.target }} | |
| path: out/celld-${{ matrix.target }}.gz | |
| if-no-files-found: error | |
| # The Dockerfile must build and its test stage pass before anything can | |
| # be published; nothing is pushed at candidate time. | |
| container-check: | |
| name: Container smoke build | |
| if: github.event_name != 'release' | |
| runs-on: ubuntu-22.04 | |
| timeout-minutes: 60 | |
| permissions: | |
| contents: read | |
| packages: read | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: docker/setup-buildx-action@v3 | |
| - name: Log in to GHCR | |
| env: | |
| GHCR_TOKEN: ${{ github.token }} | |
| run: | | |
| printf '%s' "$GHCR_TOKEN" | | |
| docker login ghcr.io --username "$GITHUB_ACTOR" --password-stdin | |
| - name: Build the test stage | |
| run: | | |
| set -euo pipefail | |
| version=$(sed -n 's/^version = "\(.*\)"$/\1/p' crates/celld/Cargo.toml | head -1) | |
| docker buildx build \ | |
| --platform linux/amd64 \ | |
| --target test \ | |
| --build-arg "CELLD_COMMIT=$GITHUB_SHA" \ | |
| --build-arg "CELLD_VERSION=$version" \ | |
| --cache-from "type=registry,ref=$IMAGE:buildcache-amd64" \ | |
| . | |
| draft-release: | |
| name: Attest and draft the release | |
| if: github.event_name != 'release' | |
| needs: | |
| - build-celld | |
| runs-on: ubuntu-22.04 | |
| timeout-minutes: 15 | |
| permissions: | |
| contents: write | |
| id-token: write | |
| attestations: write | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - uses: actions/download-artifact@v4 | |
| with: | |
| path: assets | |
| merge-multiple: true | |
| # Assets are minimal: the binaries, nothing else. Integrity is the | |
| # attestation plus GitHub's own immutable per-asset digests; gzip's | |
| # CRC catches corruption in transit. | |
| - name: Check assets | |
| run: | | |
| set -euo pipefail | |
| cd assets | |
| for target in \ | |
| x86_64-unknown-linux-gnu \ | |
| aarch64-unknown-linux-gnu \ | |
| aarch64-apple-darwin; do | |
| test -f "celld-$target.gz" | |
| done | |
| # Attestations require a public repository; until the visibility flip | |
| # this step is skipped and drafts carry checksums only. | |
| - name: Attest build provenance | |
| if: github.event.repository.visibility == 'public' | |
| uses: actions/attest-build-provenance@v2 | |
| with: | |
| subject-path: assets/*.gz | |
| - name: Create or refresh the draft release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| set -euo pipefail | |
| version=$(sed -n 's/^version = "\(.*\)"$/\1/p' crates/celld/Cargo.toml | head -1) | |
| tag="v$version" | |
| existing=$(gh release view "$tag" --json isDraft \ | |
| --jq .isDraft 2>/dev/null || echo "absent") | |
| if [ "$existing" = "false" ]; then | |
| echo "release $tag is already published; bump the version" >&2 | |
| exit 1 | |
| fi | |
| if [ "$existing" = "true" ]; then | |
| gh release delete "$tag" --yes | |
| fi | |
| # The release body is the release commit's message: subject | |
| # dropped (it is the title), trailers stripped, hard wraps | |
| # unfolded so paragraphs and bullets render without awkward | |
| # line breaks. | |
| git log -1 --format=%b "$GITHUB_SHA" | | |
| sed '/^[A-Za-z-]*-by:/d' | | |
| awk ' | |
| /^$/ { if (buf != "") print buf; buf = ""; print; next } | |
| /^- / { if (buf != "") print buf; buf = $0; next } | |
| { sub(/^[ \t]+/, "") | |
| buf = (buf == "" ? $0 : buf " " $0) } | |
| END { if (buf != "") print buf } | |
| ' | cat -s > /tmp/notes.md | |
| gh release create "$tag" \ | |
| --draft \ | |
| --target "$GITHUB_SHA" \ | |
| --title "$tag" \ | |
| --notes-file /tmp/notes.md \ | |
| assets/* | |
| build-container: | |
| # Static name so a skipped run shows "Build container" instead of the | |
| # unexpanded matrix expression; GitHub still appends the platform when | |
| # the job actually runs. | |
| name: Build container | |
| if: github.event_name == 'release' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - runner: ubuntu-22.04 | |
| platform: linux/amd64 | |
| suffix: amd64 | |
| - runner: ubuntu-22.04-arm | |
| platform: linux/arm64 | |
| suffix: arm64 | |
| runs-on: ${{ matrix.runner }} | |
| timeout-minutes: 60 | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ github.event.release.tag_name }} | |
| - name: Resolve and validate the release tag | |
| run: | | |
| set -euo pipefail | |
| version=$(sed -n 's/^version = "\(.*\)"$/\1/p' crates/celld/Cargo.toml | head -1) | |
| test "${{ github.event.release.tag_name }}" = "v$version" | |
| echo "TAG_SHA=$(git rev-parse HEAD)" >> "$GITHUB_ENV" | |
| echo "CELLD_VERSION=$version" >> "$GITHUB_ENV" | |
| # Registry cache export (--cache-to type=registry) needs the | |
| # docker-container driver; the default docker driver cannot export. | |
| - uses: docker/setup-buildx-action@v3 | |
| - name: Log in to GHCR | |
| env: | |
| GHCR_TOKEN: ${{ github.token }} | |
| run: | | |
| printf '%s' "$GHCR_TOKEN" | | |
| docker login ghcr.io --username "$GITHUB_ACTOR" --password-stdin | |
| - name: Test architecture image | |
| run: | | |
| set -euo pipefail | |
| cache="$IMAGE:buildcache-${{ matrix.suffix }}" | |
| docker buildx build \ | |
| --platform "${{ matrix.platform }}" \ | |
| --target test \ | |
| --build-arg "CELLD_COMMIT=$TAG_SHA" \ | |
| --build-arg "CELLD_VERSION=$CELLD_VERSION" \ | |
| --cache-from "type=registry,ref=$cache" \ | |
| --cache-to "type=registry,ref=$cache,mode=max" \ | |
| . | |
| - name: Build and push architecture image | |
| run: | | |
| set -euo pipefail | |
| tag="$IMAGE:$TAG_SHA-${{ matrix.suffix }}" | |
| cache="$IMAGE:buildcache-${{ matrix.suffix }}" | |
| docker buildx build \ | |
| --platform "${{ matrix.platform }}" \ | |
| --build-arg "CELLD_COMMIT=$TAG_SHA" \ | |
| --build-arg "CELLD_VERSION=$CELLD_VERSION" \ | |
| --cache-from "type=registry,ref=$cache" \ | |
| --cache-to "type=registry,ref=$cache,mode=max" \ | |
| --provenance=mode=max \ | |
| --sbom=true \ | |
| --tag "$tag" \ | |
| --push \ | |
| . | |
| publish-container: | |
| name: Publish multi-architecture image | |
| if: github.event_name == 'release' | |
| needs: build-container | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 15 | |
| permissions: | |
| contents: read | |
| packages: write | |
| id-token: write | |
| attestations: write | |
| steps: | |
| - uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ github.event.release.tag_name }} | |
| - name: Resolve and validate the release tag | |
| run: | | |
| set -euo pipefail | |
| version=$(sed -n 's/^version = "\(.*\)"$/\1/p' crates/celld/Cargo.toml | head -1) | |
| test "${{ github.event.release.tag_name }}" = "v$version" | |
| echo "TAG_SHA=$(git rev-parse HEAD)" >> "$GITHUB_ENV" | |
| echo "CELLD_VERSION=$version" >> "$GITHUB_ENV" | |
| - name: Log in to GHCR | |
| env: | |
| GHCR_TOKEN: ${{ github.token }} | |
| run: | | |
| printf '%s' "$GHCR_TOKEN" | | |
| docker login ghcr.io --username "$GITHUB_ACTOR" --password-stdin | |
| - name: Publish immutable and release tags | |
| run: | | |
| set -euo pipefail | |
| docker buildx imagetools create \ | |
| --tag "$IMAGE:sha-$TAG_SHA" \ | |
| --tag "$IMAGE:${{ github.event.release.tag_name }}" \ | |
| --tag "$IMAGE:$CELLD_VERSION" \ | |
| --tag "$IMAGE:latest" \ | |
| "$IMAGE:$TAG_SHA-amd64" \ | |
| "$IMAGE:$TAG_SHA-arm64" | |
| - name: Resolve manifest digest | |
| id: digest | |
| run: | | |
| set -euo pipefail | |
| digest=$(docker buildx imagetools inspect "$IMAGE:sha-$TAG_SHA" \ | |
| --format '{{json .Manifest.Digest}}' | tr -d '"') | |
| echo "digest=$digest" >> "$GITHUB_OUTPUT" | |
| # Attestations require a public repository; skipped until the | |
| # visibility flip. | |
| - name: Attest image provenance | |
| if: github.event.repository.visibility == 'public' | |
| uses: actions/attest-build-provenance@v2 | |
| with: | |
| subject-name: ghcr.io/denoland/celld | |
| subject-digest: ${{ steps.digest.outputs.digest }} | |
| push-to-registry: true | |
| # Meaningful only once the package is public; while the repository is | |
| # internal an anonymous pull can only 401, and a red-by-design run | |
| # teaches people to ignore red. Enforced automatically at launch. | |
| - name: Verify anonymous manifest access | |
| if: github.event.repository.visibility == 'public' | |
| run: | | |
| set -euo pipefail | |
| docker logout ghcr.io | |
| docker buildx imagetools inspect "$IMAGE:sha-$TAG_SHA" |