mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-08-28 05:27:41 +00:00
Some checks failed
Rust / Format (push) Waiting to run
Rust / Clippy (push) Waiting to run
Rust / Generated Docs (push) Waiting to run
Rust / Test (Linux) (push) Waiting to run
Rust / Test (macOS) (push) Waiting to run
TypeScript / Typecheck (push) Has been cancelled
TypeScript / Test (push) Has been cancelled
TypeScript / Build (push) Has been cancelled
## Summary
Enforce Cargo lockfile use across CI and release automation so jobs fail
on stale `Cargo.lock` state instead of resolving dependencies
implicitly. This adds `--locked` to Rust CI, release builds/tests,
nightly release tagging, the TypeScript workflow's embedded Rust build,
and helper-owned Cargo calls in `fabro-dev`.
This also fixes the Linux CI flake exposed by the PR: canceling a
durably blocked in-process run could take the abort path while the
workflow was still unwinding a human-input gate, causing
`run.failed(cancelled)` to be followed by `run.unblocked`. That invalid
event order broke projection rebuilds and made `GET /runs/{id}` return
404. Cancellation now uses the durable lifecycle status when selecting
the in-process blocked-run path, so the pending interview is cancelled
before the terminal event is emitted.
The release command's intentional `cargo update --workspace` step is
unchanged, because that step updates `Cargo.lock` after bumping the
workspace version.
## Testing
- `cargo nextest run --locked -p fabro-dev --features dev -E
'test(dry_run_computes_stable_version_from_date) |
test(dry_run_prints_equivalent_build_commands)'`
- `cargo --locked dev release --dry-run --skip-tests --release-date
2026-01-01`
- `cargo --locked dev docs check`
- `cargo nextest run --locked -p fabro-server --features test-support
cancel_durably_blocked_in_process_run_cancels_pending_interview_without_abort_signal
--status-level fail --final-status-level fail --show-progress none`
- `cargo nextest run --locked -p fabro-server --features test-support
--test it scenario::lifecycle --profile ci --status-level fail
--final-status-level fail --show-progress none --no-fail-fast`
- Linux Docker stress reproduction: `cargo nextest run --locked -p
fabro-server --features test-support --test it
scenario::lifecycle::full_http_lifecycle_cancel --profile ci
--stress-count 200 --status-level fail --final-status-level fail
--show-progress none`
- `cargo +nightly-2026-04-14 fmt --check --all`
- `cargo +nightly-2026-04-14 clippy --locked -p fabro-dev --features dev
--all-targets -- -D warnings`
- `cargo +nightly-2026-04-14 clippy --locked -p fabro-server --features
test-support --all-targets -- -D warnings`
- `git diff --check`
Full `cargo nextest run --locked -p fabro-dev --features dev` currently
has two unrelated policy-test failures:
`policy::catalog_builtin_references_stay_in_allowlist` and
`policy::workflow_template_rendering_call_sites_stay_in_allowlist`.
---
[](https://github.com/EveryInc/compound-engineering-plugin)
🤖 Generated with GPT-5 via [Codex](https://openai.com/codex)
---------
Co-authored-by: Release Repro <release-repro@example.com>
348 lines
13 KiB
YAML
348 lines
13 KiB
YAML
name: Release
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- "v*"
|
|
|
|
permissions: {}
|
|
|
|
env:
|
|
CARGO_TERM_COLOR: always
|
|
SEGMENT_BASE_URL: ${{ vars.SEGMENT_BASE_URL }}
|
|
SEGMENT_WRITE_KEY: ${{ secrets.SEGMENT_WRITE_KEY }}
|
|
|
|
jobs:
|
|
compile:
|
|
name: Compile (${{ matrix.target }})
|
|
runs-on: ${{ matrix.runner }}
|
|
permissions:
|
|
contents: read
|
|
id-token: write
|
|
attestations: write
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
include:
|
|
- target: aarch64-apple-darwin
|
|
runner: macos-15-xlarge
|
|
- target: x86_64-unknown-linux-gnu
|
|
runner: ubuntu-24.04-x86-32-cores
|
|
- target: aarch64-unknown-linux-gnu
|
|
runner: ubuntu-22.04-arm-32-cores
|
|
- target: x86_64-unknown-linux-musl
|
|
runner: ubuntu-24.04-x86-32-cores
|
|
musl: true
|
|
- target: aarch64-unknown-linux-musl
|
|
runner: ubuntu-24.04-arm-32-cores
|
|
musl: true
|
|
env:
|
|
LIBZ_SYS_STATIC: "1"
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- name: Install unzip (ARM Linux runner image lacks it; setup-bun needs it)
|
|
if: runner.os == 'Linux' && runner.arch == 'ARM64'
|
|
run: sudo apt-get update && sudo apt-get install -y unzip
|
|
|
|
- uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
|
|
with:
|
|
no-cache: true
|
|
|
|
- name: Install bun deps
|
|
run: bun install --frozen-lockfile
|
|
|
|
- name: Install Linux build tools
|
|
if: runner.os == 'Linux'
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y build-essential pkg-config libssl-dev
|
|
|
|
- name: Install musl toolchain for x86_64-musl tests
|
|
if: matrix.target == 'x86_64-unknown-linux-musl'
|
|
run: sudo apt-get install -y musl-tools
|
|
|
|
- name: Set up Rust
|
|
uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # stable
|
|
with:
|
|
targets: ${{ matrix.target }}
|
|
|
|
- name: Set up zig
|
|
if: matrix.musl
|
|
uses: mlugg/setup-zig@8d6198c65fb0feaa111df26e6b467fea8345e46f # v2.0.5
|
|
with:
|
|
version: 0.13.0
|
|
|
|
- name: Install cargo-zigbuild
|
|
if: matrix.musl
|
|
uses: taiki-e/install-action@773334c0e05d7e699e4d78234494308223f3a2cf # v2
|
|
with:
|
|
tool: cargo-zigbuild
|
|
|
|
- uses: taiki-e/install-action@773334c0e05d7e699e4d78234494308223f3a2cf # nextest
|
|
|
|
- name: Refresh embedded SPA
|
|
run: cargo --locked dev spa refresh
|
|
|
|
- name: Test (x86_64-musl)
|
|
# nextest still shells through cargo test for this target, so
|
|
# build.rs C code needs an explicit musl compiler/linker.
|
|
if: matrix.target == 'x86_64-unknown-linux-musl'
|
|
env:
|
|
CC_x86_64_unknown_linux_musl: musl-gcc
|
|
CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER: musl-gcc
|
|
run: cargo nextest run --locked --workspace --target ${{ matrix.target }} --release --status-level slow --profile ci
|
|
|
|
- name: Test
|
|
# aarch64-musl test runs have not been validated on the compile
|
|
# runner yet; shipping binary is exercised via Docker smoke tests.
|
|
# Re-enable after verifying the workspace passes on this target.
|
|
if: matrix.target != 'aarch64-unknown-linux-musl' && matrix.target != 'x86_64-unknown-linux-musl'
|
|
run: cargo nextest run --locked --workspace --target ${{ matrix.target }} --release --status-level slow --profile ci
|
|
|
|
- name: Build (musl via cargo-zigbuild)
|
|
if: matrix.musl
|
|
run: cargo zigbuild --locked --target ${{ matrix.target }} --release -p fabro-cli
|
|
|
|
- name: Build
|
|
if: ${{ !matrix.musl }}
|
|
run: cargo build --locked --target ${{ matrix.target }} --release -p fabro-cli
|
|
|
|
- name: Package
|
|
run: |
|
|
mkdir fabro-${{ matrix.target }}
|
|
cp target/${{ matrix.target }}/release/fabro fabro-${{ matrix.target }}/
|
|
tar czf fabro-${{ matrix.target }}.tar.gz fabro-${{ matrix.target }}
|
|
shasum -a 256 fabro-${{ matrix.target }}.tar.gz > fabro-${{ matrix.target }}.tar.gz.sha256
|
|
|
|
- name: Attest build provenance
|
|
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
|
|
with:
|
|
subject-path: fabro-${{ matrix.target }}.tar.gz
|
|
|
|
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
with:
|
|
name: artifacts-fabro-${{ matrix.target }}
|
|
path: |
|
|
fabro-${{ matrix.target }}.tar.gz
|
|
fabro-${{ matrix.target }}.tar.gz.sha256
|
|
|
|
release:
|
|
name: Release
|
|
needs: compile
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: write
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
with:
|
|
path: target/distrib
|
|
pattern: artifacts-fabro-*
|
|
merge-multiple: true
|
|
|
|
- name: Create GitHub Release
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
TAG_NAME: ${{ github.ref_name }}
|
|
run: |
|
|
PRERELEASE_FLAG=""
|
|
if [[ "$TAG_NAME" == *-* ]]; then
|
|
PRERELEASE_FLAG="--prerelease"
|
|
fi
|
|
gh release create "$TAG_NAME" target/distrib/* --generate-notes $PRERELEASE_FLAG
|
|
|
|
docker:
|
|
name: Docker image
|
|
needs: compile
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
id-token: write
|
|
attestations: write
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
with:
|
|
path: target/distrib
|
|
pattern: artifacts-fabro-*-linux-musl
|
|
merge-multiple: true
|
|
|
|
- name: Stage binaries for Docker build context
|
|
run: |
|
|
for target in x86_64-unknown-linux-musl aarch64-unknown-linux-musl; do
|
|
case "$target" in
|
|
x86_64-*) arch=amd64 ;;
|
|
aarch64-*) arch=arm64 ;;
|
|
esac
|
|
mkdir -p "tmp/docker-context/$arch"
|
|
tar -xzf "target/distrib/fabro-${target}.tar.gz" -C target/distrib
|
|
cp "target/distrib/fabro-${target}/fabro" "tmp/docker-context/$arch/fabro"
|
|
done
|
|
|
|
- uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
|
|
|
|
- uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
|
|
|
- uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- id: meta
|
|
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
|
|
with:
|
|
images: ghcr.io/fabro-sh/fabro
|
|
tags: |
|
|
type=match,pattern=v(.*),group=1
|
|
type=raw,value=latest,enable=${{ !contains(github.ref_name, '-') }}
|
|
type=raw,value=nightly,enable=${{ contains(github.ref_name, '-nightly.') }}
|
|
|
|
- name: Build amd64 image for smoke test
|
|
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
|
with:
|
|
context: .
|
|
file: Dockerfile
|
|
platforms: linux/amd64
|
|
load: true
|
|
tags: fabro-smoke:amd64
|
|
|
|
- name: Smoke-test amd64 image
|
|
run: docker run --rm --platform linux/amd64 fabro-smoke:amd64 fabro version
|
|
|
|
- name: Build arm64 image for smoke test
|
|
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
|
with:
|
|
context: .
|
|
file: Dockerfile
|
|
platforms: linux/arm64
|
|
load: true
|
|
tags: fabro-smoke:arm64
|
|
|
|
- name: Smoke-test arm64 image
|
|
run: docker run --rm --platform linux/arm64 fabro-smoke:arm64 fabro version
|
|
|
|
- id: build
|
|
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
|
with:
|
|
context: .
|
|
file: Dockerfile
|
|
platforms: linux/amd64,linux/arm64
|
|
push: true
|
|
tags: ${{ steps.meta.outputs.tags }}
|
|
labels: ${{ steps.meta.outputs.labels }}
|
|
|
|
- name: Attest image provenance
|
|
uses: actions/attest-build-provenance@a2bbfa25375fe432b6a289bc6b6cd05ecd0c4c32 # v4.1.0
|
|
with:
|
|
subject-name: ghcr.io/fabro-sh/fabro
|
|
subject-digest: ${{ steps.build.outputs.digest }}
|
|
push-to-registry: true
|
|
|
|
update-homebrew:
|
|
name: Update Homebrew Formula
|
|
needs: release
|
|
if: ${{ !contains(github.ref_name, '-') }}
|
|
runs-on: ubuntu-latest
|
|
environment: release
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
with:
|
|
path: target/distrib
|
|
pattern: artifacts-fabro-*
|
|
merge-multiple: true
|
|
|
|
- name: Generate and push formula
|
|
env:
|
|
GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
|
|
TAG_NAME: ${{ github.ref_name }}
|
|
run: |
|
|
VERSION="${TAG_NAME#v}"
|
|
|
|
SHA_AARCH64_DARWIN=$(awk '{print $1}' target/distrib/fabro-aarch64-apple-darwin.tar.gz.sha256)
|
|
SHA_X86_64_LINUX=$(awk '{print $1}' target/distrib/fabro-x86_64-unknown-linux-gnu.tar.gz.sha256)
|
|
SHA_AARCH64_LINUX=$(awk '{print $1}' target/distrib/fabro-aarch64-unknown-linux-gnu.tar.gz.sha256)
|
|
|
|
sed \
|
|
-e "s/{{VERSION}}/$VERSION/g" \
|
|
-e "s/{{SHA_AARCH64_DARWIN}}/$SHA_AARCH64_DARWIN/g" \
|
|
-e "s/{{SHA_X86_64_LINUX}}/$SHA_X86_64_LINUX/g" \
|
|
-e "s/{{SHA_AARCH64_LINUX}}/$SHA_AARCH64_LINUX/g" \
|
|
installer/fabro.rb.template > fabro.rb
|
|
|
|
git clone https://x-access-token:${GH_TOKEN}@github.com/fabro-sh/homebrew-tap.git tap
|
|
cp fabro.rb tap/Formula/fabro.rb
|
|
jq --arg version "$VERSION" --arg tag "$TAG_NAME" \
|
|
'.stable = {version: $version, tag: $tag}' \
|
|
tap/versions.json > tap/versions.json.tmp
|
|
mv tap/versions.json.tmp tap/versions.json
|
|
cd tap
|
|
git config user.name "github-actions[bot]"
|
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
git add Formula/fabro.rb versions.json
|
|
git diff --cached --quiet || (git commit -m "Update fabro to ${TAG_NAME}" && git push)
|
|
|
|
update-homebrew-nightly:
|
|
name: Update Homebrew Nightly Formula
|
|
needs: release
|
|
if: ${{ contains(github.ref_name, '-') }}
|
|
runs-on: ubuntu-latest
|
|
environment: release
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
persist-credentials: false
|
|
|
|
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
with:
|
|
path: target/distrib
|
|
pattern: artifacts-fabro-*
|
|
merge-multiple: true
|
|
|
|
- name: Generate and push nightly formula
|
|
env:
|
|
GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }}
|
|
TAG_NAME: ${{ github.ref_name }}
|
|
run: |
|
|
VERSION="${TAG_NAME#v}"
|
|
|
|
SHA_AARCH64_DARWIN=$(awk '{print $1}' target/distrib/fabro-aarch64-apple-darwin.tar.gz.sha256)
|
|
SHA_X86_64_LINUX=$(awk '{print $1}' target/distrib/fabro-x86_64-unknown-linux-gnu.tar.gz.sha256)
|
|
SHA_AARCH64_LINUX=$(awk '{print $1}' target/distrib/fabro-aarch64-unknown-linux-gnu.tar.gz.sha256)
|
|
|
|
sed \
|
|
-e "s/{{VERSION}}/$VERSION/g" \
|
|
-e "s/{{SHA_AARCH64_DARWIN}}/$SHA_AARCH64_DARWIN/g" \
|
|
-e "s/{{SHA_X86_64_LINUX}}/$SHA_X86_64_LINUX/g" \
|
|
-e "s/{{SHA_AARCH64_LINUX}}/$SHA_AARCH64_LINUX/g" \
|
|
installer/fabro-nightly.rb.template > fabro-nightly.rb
|
|
|
|
git clone https://x-access-token:${GH_TOKEN}@github.com/fabro-sh/homebrew-tap.git tap
|
|
cp fabro-nightly.rb tap/Formula/fabro-nightly.rb
|
|
jq --arg version "$VERSION" --arg tag "$TAG_NAME" \
|
|
'.nightly = {version: $version, tag: $tag}' \
|
|
tap/versions.json > tap/versions.json.tmp
|
|
mv tap/versions.json.tmp tap/versions.json
|
|
cd tap
|
|
git config user.name "github-actions[bot]"
|
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
git add Formula/fabro-nightly.rb versions.json
|
|
git diff --cached --quiet || (git commit -m "Update fabro-nightly to ${TAG_NAME}" && git push)
|