From aabd875bdfc12262645b399944ec539785369255 Mon Sep 17 00:00:00 2001 From: Max Date: Sun, 19 Apr 2026 18:48:06 +0800 Subject: [PATCH] fix(workflows): refine release and notarization processes for macOS and Linux - Updated the notarization workflow to correctly reference the "Release macOS" workflow. - Enhanced version and run ID resolution logic to ensure accurate detection from the latest release or inputs. - Improved asset verification process on R2 with a retry mechanism to handle potential delays in asset availability. - Removed the deprecated unified release workflow, streamlining the release process for macOS and Linux. - Adjusted CDN update prerequisites to reflect the new workflow structure. --- .github/workflows/notarize-macos.yml | 76 +++++------ .github/workflows/release-linux.yml | 73 +++++++++++ .github/workflows/release-macos.yml | 97 +++++++++++++++ .github/workflows/release.yml | 159 ------------------------ .github/workflows/update-cdn-latest.yml | 3 +- 5 files changed, 210 insertions(+), 198 deletions(-) delete mode 100644 .github/workflows/release.yml diff --git a/.github/workflows/notarize-macos.yml b/.github/workflows/notarize-macos.yml index 76d666d9..0927772b 100644 --- a/.github/workflows/notarize-macos.yml +++ b/.github/workflows/notarize-macos.yml @@ -2,7 +2,7 @@ name: Notarize macOS on: workflow_run: - workflows: ["Release"] + workflows: ["Release macOS"] types: [completed] workflow_dispatch: inputs: @@ -18,7 +18,7 @@ permissions: actions: write concurrency: - group: notarize-${{ github.run_id }} + group: notarize-${{ github.event.workflow_run.head_branch || github.run_id }} cancel-in-progress: true jobs: @@ -29,7 +29,8 @@ jobs: runs-on: ubuntu-latest if: > github.event_name == 'workflow_dispatch' || - github.event.workflow_run.conclusion == 'success' + (github.event.workflow_run.conclusion == 'success' && + startsWith(github.event.workflow_run.head_branch, 'v')) outputs: version: ${{ steps.resolve.outputs.version }} run_id: ${{ steps.resolve.outputs.run_id }} @@ -42,24 +43,19 @@ jobs: if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then VERSION="${{ github.event.inputs.version }}" RUN_ID="${{ github.event.inputs.run_id }}" - fi - - # Auto-detect version from latest GitHub Release - if [ -z "$VERSION" ]; then - TAG=$(gh release view --repo "$GITHUB_REPOSITORY" --json tagName -q '.tagName') + if [ -z "$VERSION" ]; then + TAG=$(gh release view --repo "$GITHUB_REPOSITORY" --json tagName -q '.tagName') + VERSION="${TAG#v}" + fi + if [ -z "$RUN_ID" ]; then + RUN_ID=$(gh run list --repo "$GITHUB_REPOSITORY" \ + --workflow="Release macOS" --branch="v${VERSION}" --limit=1 \ + --json databaseId,conclusion --jq '.[] | select(.conclusion=="success") | .databaseId') + fi + else + TAG="${{ github.event.workflow_run.head_branch }}" VERSION="${TAG#v}" - fi - - if [ -z "$VERSION" ]; then - echo "::error::Could not determine version from latest release" - exit 1 - fi - - # Auto-detect macOS build run_id - if [ -z "$RUN_ID" ]; then - RUN_ID=$(gh run list --repo "$GITHUB_REPOSITORY" \ - --workflow="Release macOS" --branch="v${VERSION}" --limit=1 \ - --json databaseId,conclusion --jq '.[] | select(.conclusion=="success") | .databaseId') + RUN_ID="${{ github.event.workflow_run.id }}" fi if [ -z "$VERSION" ] || [ -z "$RUN_ID" ]; then @@ -146,7 +142,7 @@ jobs: echo "Yao ${{ matrix.arch }} notarization accepted." # =================================================================== - # After both architectures finish: verify R2 assets + trigger CDN + # After both architectures finish: wait for Linux R2, then trigger CDN # =================================================================== finalize: needs: [resolve, notarize] @@ -168,7 +164,7 @@ jobs: aws configure set default.region us-east-1 aws configure set default.s3.signature_version s3v4 - - name: Verify all platform assets on R2 + - name: Wait for all platform assets on R2 run: | VERSION="${{ needs.resolve.outputs.version }}" PREFIX="yao/${VERSION}" @@ -180,25 +176,29 @@ jobs: "linux-arm64" ) - MISSING=0 - for P in "${PLATFORMS[@]}"; do - KEY="${PREFIX}/yao-${VERSION}-${P}" - if ! aws s3 ls "s3://${R2_BUCKET}/${KEY}" --endpoint-url "$R2_ENDPOINTS" >/dev/null 2>&1; then - echo "::warning::Missing asset: ${KEY}" - MISSING=$((MISSING+1)) - fi - if ! aws s3 ls "s3://${R2_BUCKET}/${KEY}.sha256" --endpoint-url "$R2_ENDPOINTS" >/dev/null 2>&1; then - echo "::warning::Missing sha256: ${KEY}.sha256" - MISSING=$((MISSING+1)) + for ATTEMPT in $(seq 1 30); do + MISSING=0 + for P in "${PLATFORMS[@]}"; do + KEY="${PREFIX}/yao-${VERSION}-${P}" + if ! aws s3 ls "s3://${R2_BUCKET}/${KEY}" --endpoint-url "$R2_ENDPOINTS" >/dev/null 2>&1; then + MISSING=$((MISSING+1)) + fi + if ! aws s3 ls "s3://${R2_BUCKET}/${KEY}.sha256" --endpoint-url "$R2_ENDPOINTS" >/dev/null 2>&1; then + MISSING=$((MISSING+1)) + fi + done + + if [ "$MISSING" -eq 0 ]; then + echo "All 4 platform assets verified on R2." + exit 0 fi + + echo "Attempt $ATTEMPT: $MISSING asset(s) still missing, waiting 30s..." + sleep 30 done - if [ "$MISSING" -gt 0 ]; then - echo "::error::$MISSING required asset(s) missing on R2." - echo "Ensure release.yml has completed successfully before running notarize." - exit 1 - fi - echo "All 4 platform assets verified on R2." + echo "::error::Timed out waiting for all platform assets on R2." + exit 1 - name: Trigger CDN latest.json update env: diff --git a/.github/workflows/release-linux.yml b/.github/workflows/release-linux.yml index 9039ed20..6c868e7f 100644 --- a/.github/workflows/release-linux.yml +++ b/.github/workflows/release-linux.yml @@ -138,3 +138,76 @@ jobs: tags: | ${{ env.IMAGE_NAME }}:${{ steps.version.outputs.version }} ${{ env.IMAGE_NAME }}:latest + + # =================================================================== + # GitHub Release + R2 Upload (Linux binaries) + # =================================================================== + release: + needs: build + if: startsWith(github.ref, 'refs/tags/v') + runs-on: ubuntu-latest + steps: + - name: Get Version + id: version + run: | + if [[ "$GITHUB_REF" != refs/tags/v* ]]; then + echo "::error::This workflow requires a tag. Got: $GITHUB_REF" + exit 1 + fi + VERSION="${GITHUB_REF#refs/tags/v}" + TAG="${GITHUB_REF#refs/tags/}" + echo "version=${VERSION}" >> $GITHUB_OUTPUT + echo "tag=${TAG}" >> $GITHUB_OUTPUT + + - name: Download Linux Artifacts + uses: actions/download-artifact@v4 + with: + name: yao-linux + path: artifacts + + - name: Prepare Release Files + run: | + VERSION="${{ steps.version.outputs.version }}" + mkdir -p release + cp "artifacts/yao-${VERSION}-linux-amd64-prod" "release/yao-${VERSION}-linux-amd64" + cp "artifacts/yao-${VERSION}-linux-arm64-prod" "release/yao-${VERSION}-linux-arm64" + cp "artifacts/yao-${VERSION}-linux-amd64" "release/yao-${VERSION}-linux-amd64-dev" + cp "artifacts/yao-${VERSION}-linux-arm64" "release/yao-${VERSION}-linux-arm64-dev" + chmod +x release/yao-* + ls -lh release/ + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ steps.version.outputs.tag }} + name: Yao v${{ steps.version.outputs.version }} + files: release/* + generate_release_notes: true + make_latest: false + + - name: Upload Linux binaries to R2 + env: + AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }} + R2_ENDPOINTS: ${{ secrets.R2_ENDPOINTS }} + R2_BUCKET: ${{ secrets.R2_BUCKET || 'releases' }} + run: | + aws configure set default.region us-east-1 + aws configure set default.s3.signature_version s3v4 + + VERSION="${{ steps.version.outputs.version }}" + PREFIX="yao/${VERSION}" + + for PLATFORM in linux-amd64 linux-arm64; do + FILE="release/yao-${VERSION}-${PLATFORM}" + NAME="yao-${VERSION}-${PLATFORM}" + sha256sum "$FILE" | awk '{print $1}' > "/tmp/${NAME}.sha256" + + aws s3 cp "$FILE" "s3://${R2_BUCKET}/${PREFIX}/${NAME}" \ + --endpoint-url "$R2_ENDPOINTS" \ + --content-type "application/octet-stream" + aws s3 cp "/tmp/${NAME}.sha256" "s3://${R2_BUCKET}/${PREFIX}/${NAME}.sha256" \ + --endpoint-url "$R2_ENDPOINTS" \ + --content-type "text/plain" + echo "Uploaded: ${NAME} + ${NAME}.sha256" + done diff --git a/.github/workflows/release-macos.yml b/.github/workflows/release-macos.yml index a6846134..c7843705 100644 --- a/.github/workflows/release-macos.yml +++ b/.github/workflows/release-macos.yml @@ -217,3 +217,100 @@ jobs: with: name: yao-darwin-checksums path: /tmp/checksums/*.sha256 + + # =================================================================== + # GitHub Release + R2 Upload (macOS binaries) + # =================================================================== + release: + needs: build + if: startsWith(github.ref, 'refs/tags/v') + runs-on: ubuntu-latest + steps: + - name: Get Version + id: version + run: | + if [[ "$GITHUB_REF" != refs/tags/v* ]]; then + echo "::error::This workflow requires a tag. Got: $GITHUB_REF" + exit 1 + fi + VERSION="${GITHUB_REF#refs/tags/v}" + TAG="${GITHUB_REF#refs/tags/}" + echo "version=${VERSION}" >> $GITHUB_OUTPUT + echo "tag=${TAG}" >> $GITHUB_OUTPUT + + - name: Download macOS Artifacts + uses: actions/download-artifact@v4 + with: + name: yao-darwin-arm64 + path: artifacts/arm64-prod + + - name: Download arm64 Dev + uses: actions/download-artifact@v4 + with: + name: yao-darwin-arm64-dev + path: artifacts/arm64-dev + + - name: Download amd64 Prod + uses: actions/download-artifact@v4 + with: + name: yao-darwin-amd64 + path: artifacts/amd64-prod + + - name: Download amd64 Dev + uses: actions/download-artifact@v4 + with: + name: yao-darwin-amd64-dev + path: artifacts/amd64-dev + + - name: Download Checksums + uses: actions/download-artifact@v4 + with: + name: yao-darwin-checksums + path: artifacts/checksums + + - name: Prepare Release Files + run: | + VERSION="${{ steps.version.outputs.version }}" + mkdir -p release + cp artifacts/arm64-prod/yao "release/yao-${VERSION}-darwin-arm64" + cp artifacts/amd64-prod/yao "release/yao-${VERSION}-darwin-amd64" + cp artifacts/arm64-dev/yao "release/yao-${VERSION}-darwin-arm64-dev" + cp artifacts/amd64-dev/yao "release/yao-${VERSION}-darwin-amd64-dev" + cp artifacts/checksums/*.sha256 release/ 2>/dev/null || true + chmod +x release/yao-* + ls -lh release/ + + - name: Create GitHub Release + uses: softprops/action-gh-release@v2 + with: + tag_name: ${{ steps.version.outputs.tag }} + name: Yao v${{ steps.version.outputs.version }} + files: release/* + generate_release_notes: true + + - name: Upload macOS binaries to R2 + env: + AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }} + R2_ENDPOINTS: ${{ secrets.R2_ENDPOINTS }} + R2_BUCKET: ${{ secrets.R2_BUCKET || 'releases' }} + run: | + aws configure set default.region us-east-1 + aws configure set default.s3.signature_version s3v4 + + VERSION="${{ steps.version.outputs.version }}" + PREFIX="yao/${VERSION}" + + for PLATFORM in darwin-arm64 darwin-amd64; do + FILE="release/yao-${VERSION}-${PLATFORM}" + NAME="yao-${VERSION}-${PLATFORM}" + sha256sum "$FILE" | awk '{print $1}' > "/tmp/${NAME}.sha256" + + aws s3 cp "$FILE" "s3://${R2_BUCKET}/${PREFIX}/${NAME}" \ + --endpoint-url "$R2_ENDPOINTS" \ + --content-type "application/octet-stream" + aws s3 cp "/tmp/${NAME}.sha256" "s3://${R2_BUCKET}/${PREFIX}/${NAME}.sha256" \ + --endpoint-url "$R2_ENDPOINTS" \ + --content-type "text/plain" + echo "Uploaded: ${NAME} + ${NAME}.sha256" + done diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 0bd5504c..00000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,159 +0,0 @@ -name: Release - -on: - workflow_run: - workflows: ["Release Linux", "Release macOS"] - types: - - completed - -permissions: - contents: write - -jobs: - # =================================================================== - # Wait for both workflows to succeed, then create a unified release - # =================================================================== - release: - runs-on: ubuntu-latest - if: > - github.event.workflow_run.conclusion == 'success' && - startsWith(github.event.workflow_run.head_branch, 'v') - steps: - - name: Checkout Code - uses: actions/checkout@v4 - - - name: Get Version - id: version - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - # Prefer head_branch from upstream (works for first-level workflow_run) - TAG="${{ github.event.workflow_run.head_branch }}" - if [[ "$TAG" =~ ^v ]]; then - VERSION="${TAG#v}" - else - # Fallback: get from latest GitHub Release - TAG=$(gh release view --repo "$GITHUB_REPOSITORY" --json tagName -q '.tagName') - VERSION="${TAG#v}" - fi - echo "version=${VERSION}" >> $GITHUB_OUTPUT - echo "tag=${TAG}" >> $GITHUB_OUTPUT - echo "TAG=${TAG} VERSION=${VERSION}" - - - name: Wait for Both Workflows - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - TAG="${{ steps.version.outputs.tag }}" - echo "Waiting for both Release Linux and Release macOS to complete for $TAG..." - - for i in $(seq 1 60); do - LINUX_STATUS=$(gh run list --workflow="Release Linux" --branch="$TAG" --limit=1 --json conclusion --jq '.[0].conclusion // "pending"') - MACOS_STATUS=$(gh run list --workflow="Release macOS" --branch="$TAG" --limit=1 --json conclusion --jq '.[0].conclusion // "pending"') - - echo "Attempt $i: Linux=$LINUX_STATUS macOS=$MACOS_STATUS" - - if [ "$LINUX_STATUS" = "success" ] && [ "$MACOS_STATUS" = "success" ]; then - echo "Both workflows completed successfully." - exit 0 - fi - - if [ "$LINUX_STATUS" = "failure" ] || [ "$MACOS_STATUS" = "failure" ]; then - echo "::error::One or both workflows failed (Linux=$LINUX_STATUS macOS=$MACOS_STATUS)" - exit 1 - fi - - sleep 60 - done - - echo "::error::Timed out waiting for workflows" - exit 1 - - - name: Download Linux Artifacts - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - TAG="${{ steps.version.outputs.tag }}" - LINUX_RUN_ID=$(gh run list --workflow="Release Linux" --branch="$TAG" --limit=1 --json databaseId --jq '.[0].databaseId') - mkdir -p dist/linux - gh run download "$LINUX_RUN_ID" --name yao-linux --dir dist/linux - - - name: Download macOS Artifacts - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - TAG="${{ steps.version.outputs.tag }}" - MACOS_RUN_ID=$(gh run list --workflow="Release macOS" --branch="$TAG" --limit=1 --json databaseId --jq '.[0].databaseId') - mkdir -p dist/macos - gh run download "$MACOS_RUN_ID" --name yao-darwin-arm64 --dir dist/macos/arm64-prod - gh run download "$MACOS_RUN_ID" --name yao-darwin-arm64-dev --dir dist/macos/arm64-dev - gh run download "$MACOS_RUN_ID" --name yao-darwin-amd64 --dir dist/macos/amd64-prod - gh run download "$MACOS_RUN_ID" --name yao-darwin-amd64-dev --dir dist/macos/amd64-dev - gh run download "$MACOS_RUN_ID" --name yao-darwin-checksums --dir dist/macos/checksums - - - name: Prepare Release Files - run: | - VERSION="${{ steps.version.outputs.version }}" - mkdir -p release - - # Linux prod binaries (canonical name = prod/stripped) - cp "dist/linux/yao-${VERSION}-linux-amd64-prod" "release/yao-${VERSION}-linux-amd64" - cp "dist/linux/yao-${VERSION}-linux-arm64-prod" "release/yao-${VERSION}-linux-arm64" - - # Linux dev binaries - cp "dist/linux/yao-${VERSION}-linux-amd64" "release/yao-${VERSION}-linux-amd64-dev" - cp "dist/linux/yao-${VERSION}-linux-arm64" "release/yao-${VERSION}-linux-arm64-dev" - - # macOS prod binaries - cp dist/macos/arm64-prod/yao "release/yao-${VERSION}-darwin-arm64" - cp dist/macos/amd64-prod/yao "release/yao-${VERSION}-darwin-amd64" - - # macOS dev binaries - cp dist/macos/arm64-dev/yao "release/yao-${VERSION}-darwin-arm64-dev" - cp dist/macos/amd64-dev/yao "release/yao-${VERSION}-darwin-amd64-dev" - - # Checksums - cp dist/macos/checksums/*.sha256 release/ 2>/dev/null || true - - chmod +x release/yao-* 2>/dev/null || true - echo "=== Release files ===" - ls -lh release/ - - - name: Create GitHub Release - uses: softprops/action-gh-release@v2 - with: - tag_name: ${{ steps.version.outputs.tag }} - name: Yao v${{ steps.version.outputs.version }} - files: release/* - generate_release_notes: true - - - name: Upload all binaries to R2 - env: - AWS_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }} - AWS_SECRET_ACCESS_KEY: ${{ secrets.R2_SECRET_ACCESS_KEY }} - R2_ENDPOINTS: ${{ secrets.R2_ENDPOINTS }} - R2_BUCKET: ${{ secrets.R2_BUCKET || 'releases' }} - run: | - aws configure set default.region us-east-1 - aws configure set default.s3.signature_version s3v4 - - VERSION="${{ steps.version.outputs.version }}" - PREFIX="yao/${VERSION}" - - echo "Uploading release binaries to R2: ${PREFIX}" - - for file in release/yao-${VERSION}-*; do - name=$(basename "$file") - case "$name" in *-dev|*-prod|*.sha256) continue ;; esac - - sha256sum "$file" | awk '{print $1}' > "/tmp/${name}.sha256" - - aws s3 cp "$file" "s3://${R2_BUCKET}/${PREFIX}/${name}" \ - --endpoint-url "$R2_ENDPOINTS" \ - --content-type "application/octet-stream" - aws s3 cp "/tmp/${name}.sha256" "s3://${R2_BUCKET}/${PREFIX}/${name}.sha256" \ - --endpoint-url "$R2_ENDPOINTS" \ - --content-type "text/plain" - - echo "Uploaded: ${name} + ${name}.sha256" - done diff --git a/.github/workflows/update-cdn-latest.yml b/.github/workflows/update-cdn-latest.yml index 31ece8ba..a68d2302 100644 --- a/.github/workflows/update-cdn-latest.yml +++ b/.github/workflows/update-cdn-latest.yml @@ -5,7 +5,8 @@ name: Update CDN latest.json # Normally triggered automatically by notarize-macos.yml's finalize job after # notarization completes. Can also be triggered manually as a fallback. # -# Prerequisites: release.yml must have uploaded all 4 platform binaries to R2. +# Prerequisites: release-linux.yml and release-macos.yml must have uploaded +# all 4 platform binaries to R2. on: workflow_dispatch: