From 71cb04525be1b693c6c55746c05db78fe208d79b Mon Sep 17 00:00:00 2001 From: Parfii-bot Date: Wed, 22 Apr 2026 23:22:50 +0800 Subject: [PATCH] =?UTF-8?q?fix(release):=20v0.22.3=20=E2=80=94=20native=20?= =?UTF-8?q?arm64-linux=20+=20gh-CLI=20Publish=20(no=20race,=20no=20draft)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two production-readiness fixes motivated by the v0.22.2 post-mortem. 1. aarch64-linux: native ARM runner instead of cross-compile v0.22.2 consistently failed `Install aarch64 cross-linker` (apt gcc-aarch64-linux-gnu) on the ubuntu-latest x86_64 runner. Was carried as `experimental: true` so non-blocking, but meant no aarch64-linux Rust tarball ever shipped. Fix: move to ubuntu-24.04-arm (native ARM64 runner). Rust builds aarch64-unknown-linux-gnu HOST-NATIVELY — no cross-linker, no `.cargo/config.toml` linker override. `experimental: false` now — native path is reliable. 2. Publish step: softprops/action-gh-release → `gh release create` CLI v0.22.2 softprops/action-gh-release v2.6.2 uploaded all 15 assets successfully but exited with `failure` due to a metadata-update race: asset uploaded to GitHub's blob store, then the subsequent PATCH to set the asset's `name` returned 404 because the Releases metadata API hadn't caught up yet (eventual consistency). Workflow failure → Release left in Draft. We had to promote it manually (`gh release edit --draft=false`) and re-upload one missing sha256. Fix: replace the action with `gh release create` + `gh release upload --clobber` in a bash step. - Idempotent: existing release gets updated in place. - No metadata PATCH race: CLI never patches, it creates fresh. - Retry loop: up to 3 tries per asset on transient network errors. - `--clobber` means re-runs replace cleanly. - GitHub CLI is pre-installed on every runner, zero new deps. Verified post-polish on v0.22.2: 16/16 assets present, Release Published, `kei-mcp-server-darwin-arm64` + `keisei` both execute on this MacBook (arm64) — adapter list shows Claude Code detected at project+user scope. SHA256 of `keisei-aarch64-apple-darwin.tar.gz` verified OK. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/workflows/release.yml | 73 ++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 22 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 132a61c..4a95db9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,13 +16,18 @@ jobs: strategy: fail-fast: false matrix: + # v0.22.3 fix: aarch64-linux moved from ubuntu-latest + cross-linker + # install (apt gcc-aarch64-linux-gnu consistently failed in CI) to + # ubuntu-24.04-arm NATIVE ARM runner. No cross-compile, rustc builds + # the target host-native. `experimental: false` — native path is + # reliable. include: - os: ubuntu-latest target: x86_64-unknown-linux-gnu experimental: false - - os: ubuntu-latest + - os: ubuntu-24.04-arm target: aarch64-unknown-linux-gnu - experimental: true + experimental: false - os: macos-latest target: x86_64-apple-darwin experimental: false @@ -47,14 +52,8 @@ jobs: with: workspaces: _primitives/_rust - - name: Install aarch64 cross-linker (Linux only) - if: matrix.target == 'aarch64-unknown-linux-gnu' - run: | - sudo apt-get update - sudo apt-get install -y gcc-aarch64-linux-gnu - mkdir -p .cargo - printf '[target.aarch64-unknown-linux-gnu]\nlinker = "aarch64-linux-gnu-gcc"\n' \ - > _primitives/_rust/.cargo/config.toml + # v0.22.3: cross-linker step removed — aarch64-linux now builds + # natively on ubuntu-24.04-arm. No cross-compile, no gcc-aarch64-linux-gnu. - name: Build workspace (release) working-directory: _primitives/_rust @@ -246,19 +245,49 @@ jobs: echo 'KEISEI_NOTES_EOF' } >> "$GITHUB_OUTPUT" + # v0.22.3 fix: softprops/action-gh-release v2.6.2 exited with failure + # on v0.22.2 due to a metadata-update race (asset uploaded to blob + # store but Releases metadata API returned 404 on the subsequent + # PATCH — eventual-consistency window). All 15 assets WERE uploaded, + # but the action exited 1 and left the Release in Draft state. + # + # Replaced with `gh release create` (bundled on all GitHub runners). + # CLI is idempotent: if the release already exists it updates it; if + # assets already exist `--clobber` replaces them. No metadata-PATCH + # race. Retry loop on transient upload failures. - name: Publish GitHub Release - # HIGH priority pin: this action has `contents: write` — a compromised - # tag would let an attacker publish arbitrary releases under this repo. - uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2.6.2 - with: - name: ${{ github.ref_name }} - tag_name: ${{ github.ref_name }} - body: ${{ steps.notes.outputs.notes }} - files: | - release-assets/*.tar.gz - release-assets/*.sha256 - release-assets/kei-mcp-server-* - fail_on_unmatched_files: false + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ github.ref_name }} + NOTES: ${{ steps.notes.outputs.notes }} + shell: bash + run: | + set -euo pipefail + # Create the release if missing; `|| true` absorbs "already exists" + # on workflow re-run. + gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1 || \ + gh release create "$TAG" \ + --repo "$GITHUB_REPOSITORY" \ + --title "$TAG" \ + --notes "$NOTES" + # Upload all assets with --clobber so re-runs replace cleanly. + # Retry each asset up to 3 times on transient network errors. + shopt -s nullglob + for f in release-assets/*.tar.gz release-assets/*.sha256 release-assets/kei-mcp-server-*; do + [ -f "$f" ] || continue + for try in 1 2 3; do + if gh release upload "$TAG" --repo "$GITHUB_REPOSITORY" --clobber "$f"; then + break + elif [ "$try" -eq 3 ]; then + echo "::error::failed to upload $f after 3 tries" >&2 + exit 1 + else + echo "upload of $f failed (attempt $try/3), retrying in 5s..." >&2 + sleep 5 + fi + done + done + echo "✓ Release $TAG published with all assets" npm-publish: name: Publish npm packages (optional)