Merge develop into main for v0.1.19 release #9
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 | |
| on: | |
| push: | |
| tags: ["v*"] | |
| permissions: | |
| contents: read | |
| jobs: | |
| test: | |
| # Gate the entire release on `cargo test --workspace` passing on every | |
| # native platform we ship a binary for. Without this, a tag push could | |
| # produce release artifacts from a commit whose tests never ran (the | |
| # bump commit's CI workflow runs in parallel with this one, not before | |
| # it). Cross targets — aarch64 Linux / Android — can't run tests on | |
| # GitHub-hosted runners; we trust their native counterparts to surface | |
| # logic bugs. | |
| name: Test (${{ matrix.os }}) | |
| runs-on: ${{ matrix.os }} | |
| permissions: | |
| contents: read | |
| strategy: | |
| fail-fast: true | |
| matrix: | |
| os: [ubuntu-latest, windows-latest, macos-latest] | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable pinned 2026-04 | |
| - name: Test | |
| run: cargo test --workspace --locked | |
| build: | |
| name: Build (${{ matrix.target }}) | |
| needs: test | |
| runs-on: ${{ matrix.os }} | |
| permissions: | |
| contents: read | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - target: x86_64-pc-windows-msvc | |
| os: windows-latest | |
| archive: zip | |
| - target: x86_64-unknown-linux-gnu | |
| os: ubuntu-latest | |
| archive: tar.gz | |
| - target: aarch64-unknown-linux-gnu | |
| os: ubuntu-latest | |
| archive: tar.gz | |
| - target: x86_64-apple-darwin | |
| os: macos-latest | |
| archive: tar.gz | |
| - target: aarch64-apple-darwin | |
| os: macos-latest | |
| archive: tar.gz | |
| - target: aarch64-linux-android | |
| os: ubuntu-latest | |
| archive: tar.gz | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable pinned 2026-04 | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Install cross-compilation tools (Linux ARM) | |
| if: matrix.target == 'aarch64-unknown-linux-gnu' | |
| run: sudo apt-get install -y gcc-aarch64-linux-gnu | |
| - name: Install cross-compilation tools (Android) | |
| if: matrix.target == 'aarch64-linux-android' | |
| run: | | |
| # Use the NDK bundled with the runner | |
| NDK_HOME="${ANDROID_NDK_HOME:-$ANDROID_NDK_ROOT}" | |
| if [ -z "$NDK_HOME" ]; then | |
| NDK_HOME="$(ls -d "$ANDROID_HOME"/ndk/*/ 2>/dev/null | sort -V | tail -1)" | |
| fi | |
| echo "NDK_HOME=$NDK_HOME" >> "$GITHUB_ENV" | |
| TOOLCHAIN="$NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64" | |
| echo "CC_aarch64_linux_android=${TOOLCHAIN}/bin/aarch64-linux-android24-clang" >> "$GITHUB_ENV" | |
| echo "AR_aarch64_linux_android=${TOOLCHAIN}/bin/llvm-ar" >> "$GITHUB_ENV" | |
| echo "CARGO_TARGET_AARCH64_LINUX_ANDROID_LINKER=${TOOLCHAIN}/bin/aarch64-linux-android24-clang" >> "$GITHUB_ENV" | |
| - name: Build | |
| run: cargo build --release --target ${{ matrix.target }} -p runex | |
| env: | |
| RUNEX_GIT_COMMIT: ${{ github.sha }} | |
| CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc | |
| - name: Package (tar.gz) | |
| if: matrix.archive == 'tar.gz' | |
| run: | | |
| cd target/${{ matrix.target }}/release | |
| tar czf ../../../runex-${{ matrix.target }}.tar.gz runex | |
| - name: Package (zip) | |
| if: matrix.archive == 'zip' | |
| shell: pwsh | |
| run: | | |
| Compress-Archive -Path target/${{ matrix.target }}/release/runex.exe -DestinationPath runex-${{ matrix.target }}.zip | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: runex-${{ matrix.target }} | |
| path: runex-${{ matrix.target }}.* | |
| release: | |
| name: Create Release | |
| needs: build | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| # Required for actions/attest-build-provenance to mint a Sigstore | |
| # signing certificate via the GitHub OIDC provider. | |
| id-token: write | |
| attestations: write | |
| steps: | |
| - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| path: artifacts | |
| merge-multiple: true | |
| - name: Attest build provenance | |
| # Generates a signed SLSA provenance statement for every release | |
| # artifact and stores it on the GitHub attestations API. Lets a | |
| # downstream installer (or paranoid user) verify the binary was | |
| # built by *this* workflow on *this* commit, not slipped in by a | |
| # compromised maintainer account. Run before `gh release create` | |
| # so a failure here aborts the release entirely rather than | |
| # publishing unattested binaries. | |
| uses: actions/attest-build-provenance@ef244123eb79f2f7a7e75d99086184180e6d0018 # v1.4.4 | |
| with: | |
| subject-path: artifacts/* | |
| - name: Create release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| TAG: ${{ github.ref_name }} | |
| run: | | |
| gh release create "$TAG" \ | |
| --repo "$GITHUB_REPOSITORY" \ | |
| --title "$TAG" \ | |
| --generate-notes \ | |
| artifacts/* | |
| publish-crates: | |
| # Publish runex to crates.io via OIDC Trusted Publishing. No | |
| # long-lived CARGO_REGISTRY_TOKEN is stored anywhere — every run | |
| # exchanges a short-lived GitHub OIDC token for an equally short- | |
| # lived crates.io token via `rust-lang/crates-io-auth-action`. | |
| # | |
| # Phase C absorbed the previous `runex-core` crate into `runex`, | |
| # so this job now publishes a single crate. The Trusted Publisher | |
| # registration on crates.io for `runex-core` is left in place | |
| # (harmless; future republish would no-op since the crate now | |
| # builds nothing) — only the `runex` publish actually fires. | |
| # `runex-core 0.1.13` (the last version before absorption) stays | |
| # on crates.io un-yanked for any cargo lockfile that still pins | |
| # it; no new versions will appear. | |
| # | |
| # Set `[skip publish]` in the bump commit message to bypass this | |
| # job — useful for re-tagging after a release-process glitch where | |
| # the binaries are out of date but the crate already published. | |
| name: Publish to crates.io (OIDC) | |
| needs: [test, build, release] | |
| if: ${{ !contains(github.event.head_commit.message, '[skip publish]') }} | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: read | |
| id-token: write | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: false | |
| - uses: dtolnay/rust-toolchain@29eef336d9b2848a0b548edc03f92a220660cdb8 # stable pinned 2026-04 | |
| - name: Exchange OIDC token for crates.io token | |
| id: auth | |
| # v1.0.4 (2026-03-23) is the first release on Node 24, silencing | |
| # the "Node.js 20 actions are deprecated" warning. Re-evaluate | |
| # when v1.1 / v2 ships. | |
| uses: rust-lang/crates-io-auth-action@v1.0.4 | |
| - name: Dry-run publish (sanity check) | |
| # Catches packaging issues (missing files, dirty workdir, | |
| # manifest rejection) before we burn the OIDC token on a real | |
| # publish. Uses the same token the live publish step will | |
| # use, so any auth-side problem also surfaces here. Cheap | |
| # insurance — adds ~30 s to the job and saves a manual yank | |
| # when packaging breaks. | |
| env: | |
| CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} | |
| RUNEX_GIT_COMMIT: ${{ github.sha }} | |
| run: | | |
| set -euo pipefail | |
| version="${GITHUB_REF_NAME#v}" | |
| status=$(curl -fsS -o /dev/null -w '%{http_code}' \ | |
| "https://crates.io/api/v1/crates/runex/$version" || echo "000") | |
| if [ "$status" = "200" ]; then | |
| echo "runex $version already on crates.io — skipping dry-run" | |
| else | |
| cargo publish -p runex --dry-run | |
| fi | |
| - name: Publish runex | |
| # Skip when this version is already on crates.io. Reruns of a | |
| # partially-failed publish-crates job would otherwise abort | |
| # here with "crate already exists on crates.io index" — that | |
| # bit us on 0.1.13 (back when there were two crates) and the | |
| # guard pattern is worth keeping for the same reason. | |
| env: | |
| CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }} | |
| RUNEX_GIT_COMMIT: ${{ github.sha }} | |
| run: | | |
| set -euo pipefail | |
| version="${GITHUB_REF_NAME#v}" | |
| status=$(curl -fsS -o /dev/null -w '%{http_code}' \ | |
| "https://crates.io/api/v1/crates/runex/$version" || echo "000") | |
| if [ "$status" = "200" ]; then | |
| echo "runex $version already on crates.io — skipping publish" | |
| else | |
| cargo publish -p runex | |
| fi |