Release #450
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: | |
| schedule: | |
| - cron: '0 */6 * * *' | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: 'Tag to build (e.g. aptos-cli-v9.0.0)' | |
| required: false | |
| type: string | |
| backfill: | |
| description: 'Backfill: build Windows artifacts for an existing release without recreating it' | |
| required: false | |
| type: boolean | |
| default: false | |
| permissions: | |
| contents: read | |
| env: | |
| CARGO_INCREMENTAL: 0 | |
| CARGO_NET_RETRY: 10 | |
| CARGO_TERM_COLOR: always | |
| jobs: | |
| # ──────────────────────────────────────────────────────────────────── | |
| # Job 1: Resolve the tag, decide whether to build, and emit the matrix | |
| # ──────────────────────────────────────────────────────────────────── | |
| check: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| tag: ${{ steps.resolve.outputs.tag }} | |
| version: ${{ steps.resolve.outputs.version }} | |
| should_build: ${{ steps.resolve.outputs.should_build }} | |
| backfill: ${{ steps.resolve.outputs.backfill }} | |
| matrix: ${{ steps.resolve.outputs.matrix }} | |
| steps: | |
| - name: Resolve tag, mode, and matrix | |
| id: resolve | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| INPUT_TAG: ${{ inputs.tag }} | |
| INPUT_BACKFILL: ${{ inputs.backfill }} | |
| GH_REPO: ${{ github.repository }} | |
| run: | | |
| set -euo pipefail | |
| BACKFILL="${INPUT_BACKFILL:-false}" | |
| if [ -n "$INPUT_TAG" ]; then | |
| TAG="$INPUT_TAG" | |
| else | |
| # Find the latest aptos-cli-v* release from aptos-core | |
| TAG=$(gh api repos/aptos-labs/aptos-core/releases \ | |
| --jq '[.[] | select(.tag_name | startswith("aptos-cli-v"))][0].tag_name') | |
| if [ -z "$TAG" ] || [ "$TAG" = "null" ]; then | |
| echo "No aptos-cli release found upstream" | |
| echo "should_build=false" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| fi | |
| VERSION="${TAG#aptos-cli-v}" | |
| echo "tag=$TAG" >> "$GITHUB_OUTPUT" | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| echo "backfill=$BACKFILL" >> "$GITHUB_OUTPUT" | |
| # Full matrix used for fresh releases. | |
| FULL_MATRIX=$(cat <<'JSON' | |
| [ | |
| {"name":"macOS x86", "runner":"macos-15-intel", "target":"x86_64-apple-darwin"}, | |
| {"name":"macOS ARM", "runner":"macos-latest", "target":"aarch64-apple-darwin"}, | |
| {"name":"Linux x86", "runner":"ubuntu-24.04", "target":"x86_64-unknown-linux-gnu"}, | |
| {"name":"Linux ARM", "runner":"ubuntu-24.04-arm", "target":"aarch64-unknown-linux-gnu"}, | |
| {"name":"Linux x86 compat", "runner":"ubuntu-latest", "target":"x86_64-unknown-linux-gnu", "compat":true, "container":"ubuntu:20.04"}, | |
| {"name":"Linux ARM compat", "runner":"ubuntu-24.04-arm", "target":"aarch64-unknown-linux-gnu", "compat":true, "container":"ubuntu:20.04"}, | |
| {"name":"Windows x86", "runner":"windows-2025", "target":"x86_64-pc-windows-msvc"} | |
| ] | |
| JSON | |
| ) | |
| # Backfill matrix: only Windows targets. | |
| BACKFILL_MATRIX=$(cat <<'JSON' | |
| [ | |
| {"name":"Windows x86", "runner":"windows-2025", "target":"x86_64-pc-windows-msvc"} | |
| ] | |
| JSON | |
| ) | |
| if [ "$BACKFILL" = "true" ]; then | |
| # Verify the release exists; backfill only makes sense for an existing release. | |
| if ! gh release view "$TAG" --repo "$GH_REPO" &>/dev/null; then | |
| echo "::error::Backfill requested but release $TAG does not exist" | |
| exit 1 | |
| fi | |
| echo "Backfilling Windows artifacts for $TAG" | |
| MATRIX=$(echo "$BACKFILL_MATRIX" | jq -c .) | |
| echo "matrix=$MATRIX" >> "$GITHUB_OUTPUT" | |
| echo "should_build=true" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| # Skip if we already published this release | |
| if gh release view "$TAG" --repo "$GH_REPO" &>/dev/null; then | |
| echo "Release $TAG already exists, skipping (use backfill=true to add Windows artifacts)" | |
| echo "should_build=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "Will build $TAG (version $VERSION)" | |
| MATRIX=$(echo "$FULL_MATRIX" | jq -c .) | |
| echo "matrix=$MATRIX" >> "$GITHUB_OUTPUT" | |
| echo "should_build=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| # ──────────────────────────────────────────────────────────────────── | |
| # Job 2: Build the CLI for every selected platform | |
| # ──────────────────────────────────────────────────────────────────── | |
| build: | |
| needs: check | |
| if: needs.check.outputs.should_build == 'true' | |
| timeout-minutes: 120 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: ${{ fromJSON(needs.check.outputs.matrix) }} | |
| name: ${{ matrix.name }} | |
| runs-on: ${{ matrix.runner }} | |
| container: ${{ matrix.container || '' }} | |
| env: | |
| TAG: ${{ needs.check.outputs.tag }} | |
| VERSION: ${{ needs.check.outputs.version }} | |
| steps: | |
| # ── Container prerequisites (compat builds only) ────────────── | |
| - name: Install container prerequisites | |
| if: matrix.container | |
| run: | | |
| export DEBIAN_FRONTEND=noninteractive | |
| apt-get update | |
| apt-get install -y curl ca-certificates git sudo | |
| git config --global --add safe.directory "$GITHUB_WORKSPACE" | |
| # ── Windows long-path support (aptos-core has very deep paths) ─ | |
| - name: Enable Windows long paths | |
| if: runner.os == 'Windows' | |
| shell: bash | |
| run: git config --global core.longpaths true | |
| # ── Checkout ────────────────────────────────────────────────── | |
| - name: Checkout release repo | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Checkout aptos-core | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| repository: aptos-labs/aptos-core | |
| ref: ${{ needs.check.outputs.tag }} | |
| path: aptos-core | |
| fetch-depth: 1 | |
| # ── System dependencies ─────────────────────────────────────── | |
| - name: Install Linux build deps | |
| if: runner.os == 'Linux' | |
| run: bash .github/workflows/build-scripts/setup-linux.sh | |
| - name: Install macOS build deps | |
| if: runner.os == 'macOS' | |
| run: | | |
| brew install pkg-config openssl cmake llvm lld | |
| OPENSSL_PREFIX="$(brew --prefix openssl)" | |
| echo "OPENSSL_DIR=${OPENSSL_PREFIX}" >> "$GITHUB_ENV" | |
| echo "PKG_CONFIG_PATH=${OPENSSL_PREFIX}/lib/pkgconfig" >> "$GITHUB_ENV" | |
| - name: Install Windows build deps | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| run: | | |
| # vcpkg is preinstalled on GitHub-hosted Windows runners at C:\vcpkg. | |
| # Match aptos-core's own Windows release script. | |
| $env:VCPKG_ROOT = 'C:\vcpkg\' | |
| vcpkg install openssl:x64-windows-static-md --clean-after-build | |
| "VCPKG_ROOT=C:\vcpkg\" | Out-File -FilePath $env:GITHUB_ENV -Append | |
| "OPENSSL_DIR=C:\vcpkg\installed\x64-windows-static-md" | Out-File -FilePath $env:GITHUB_ENV -Append | |
| "OPENSSL_STATIC=1" | Out-File -FilePath $env:GITHUB_ENV -Append | |
| # ── Rust toolchain ──────────────────────────────────────────── | |
| - name: Read Rust toolchain version | |
| id: rust-version | |
| shell: bash | |
| run: | | |
| CHANNEL=$(grep '^channel' aptos-core/rust-toolchain.toml | sed 's/.*"\(.*\)"/\1/') | |
| echo "channel=$CHANNEL" >> "$GITHUB_OUTPUT" | |
| echo "Using Rust toolchain: $CHANNEL" | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 # master | |
| with: | |
| toolchain: ${{ steps.rust-version.outputs.channel }} | |
| targets: ${{ matrix.target }} | |
| - name: Rust cache | |
| uses: Swatinem/rust-cache@c19371144df3bb44fab255c43d04cbc2ab54d1c4 # v2.9.1 | |
| with: | |
| workspaces: aptos-core -> target | |
| key: ${{ matrix.target }}${{ matrix.compat && '-compat' || '' }} | |
| # ── Compat build configuration ──────────────────────────────── | |
| - name: Patch .cargo/config.toml for compat (x86) | |
| if: matrix.compat && matrix.target == 'x86_64-unknown-linux-gnu' | |
| run: | | |
| cd aptos-core | |
| # Rust target-cpu: v3 → v2 (rustc supports this on all versions) | |
| sed -i 's/target-cpu=x86-64-v3/target-cpu=x86-64-v2/g' .cargo/config.toml | |
| # C compiler -march: v3 → baseline (Clang 10 in ubuntu:20.04 doesn't know v2 syntax) | |
| sed -i 's/-march=x86-64-v3/-march=x86-64/g' .cargo/config.toml | |
| echo "Patched .cargo/config.toml for x86-64-v2 compat" | |
| # ── Build ───────────────────────────────────────────────────── | |
| - name: Build | |
| working-directory: aptos-core | |
| run: cargo build -p aptos --profile cli | |
| # ── Package ─────────────────────────────────────────────────── | |
| - name: Package binary (Unix) | |
| if: runner.os != 'Windows' | |
| env: | |
| COMPAT: ${{ matrix.compat }} | |
| TARGET: ${{ matrix.target }} | |
| run: | | |
| SUFFIX="" | |
| if [ "$COMPAT" = "true" ]; then | |
| SUFFIX="-compat" | |
| fi | |
| ARCHIVE="aptos-cli-${VERSION}-${TARGET}${SUFFIX}.zip" | |
| cd aptos-core/target/cli | |
| zip "${GITHUB_WORKSPACE}/${ARCHIVE}" aptos | |
| echo "Packaged: ${ARCHIVE}" | |
| - name: Package binary (Windows) | |
| if: runner.os == 'Windows' | |
| shell: pwsh | |
| env: | |
| TARGET: ${{ matrix.target }} | |
| run: | | |
| $Archive = "aptos-cli-${env:VERSION}-${env:TARGET}.zip" | |
| Compress-Archive -Path "aptos-core\target\cli\aptos.exe" -DestinationPath $Archive | |
| Write-Output "Packaged: ${Archive}" | |
| # ── Upload artifact ─────────────────────────────────────────── | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | |
| with: | |
| name: aptos-cli-${{ matrix.target }}${{ matrix.compat && '-compat' || '' }} | |
| path: '*.zip' | |
| # ──────────────────────────────────────────────────────────────────── | |
| # Job 3: Create the GitHub Release with all artifacts (fresh releases) | |
| # ──────────────────────────────────────────────────────────────────── | |
| release: | |
| needs: [check, build] | |
| if: needs.check.outputs.should_build == 'true' && needs.check.outputs.backfill != 'true' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| env: | |
| TAG: ${{ needs.check.outputs.tag }} | |
| VERSION: ${{ needs.check.outputs.version }} | |
| steps: | |
| - name: Checkout release repo | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| path: artifacts | |
| merge-multiple: true | |
| - name: Generate checksums | |
| working-directory: artifacts | |
| run: sha256sum aptos-cli-*.zip > SHA256SUMS | |
| - name: Fetch changelog from aptos-core | |
| run: | | |
| # Download the CHANGELOG from the tagged version of aptos-core | |
| curl -fsSL "https://raw.githubusercontent.com/aptos-labs/aptos-core/${TAG}/crates/aptos/CHANGELOG.md" \ | |
| -o CHANGELOG.md | |
| # Extract the section for this version (between ## [VERSION] and the next ## [) | |
| awk -v ver="$VERSION" ' | |
| /^## \[/ { | |
| if (found) exit | |
| if (index($0, "[" ver "]")) found=1 | |
| } | |
| found { print } | |
| ' CHANGELOG.md > release_notes_section.md | |
| # If we found a section, use it; otherwise note it was not found | |
| if [ -s release_notes_section.md ]; then | |
| echo "Extracted changelog for version $VERSION" | |
| else | |
| echo "No changelog section found for version $VERSION" | |
| echo "_No changelog entry found for this version._" > release_notes_section.md | |
| fi | |
| - name: Build release body | |
| run: | | |
| cat > release_body.md << 'HEADER' | |
| ## Aptos CLI ${{ needs.check.outputs.version }} | |
| Built from [aptos-core `${{ needs.check.outputs.tag }}`](https://github.com/aptos-labs/aptos-core/releases/tag/${{ needs.check.outputs.tag }}). | |
| ### What's Changed | |
| HEADER | |
| cat release_notes_section.md >> release_body.md | |
| # Add checksums table | |
| cat >> release_body.md << 'TABLE_HEADER' | |
| ### Downloads | |
| | Platform | Archive | SHA-256 | | |
| |----------|---------|---------| | |
| TABLE_HEADER | |
| # Generate table rows with checksums | |
| cd artifacts | |
| for zip in aptos-cli-*.zip; do | |
| HASH=$(sha256sum "$zip" | cut -d' ' -f1) | |
| SHORT_HASH="${HASH:0:16}..." | |
| case "$zip" in | |
| *x86_64-apple-darwin*) PLATFORM="macOS x86_64" ;; | |
| *aarch64-apple-darwin*) PLATFORM="macOS ARM64" ;; | |
| *x86_64*linux*compat*) PLATFORM="Linux x86_64 (compat, GLIBC 2.31+)" ;; | |
| *aarch64*linux*compat*) PLATFORM="Linux ARM64 (compat, GLIBC 2.31+)" ;; | |
| *x86_64*linux*) PLATFORM="Linux x86_64" ;; | |
| *aarch64*linux*) PLATFORM="Linux ARM64" ;; | |
| *x86_64*windows*) PLATFORM="Windows x86_64" ;; | |
| *) PLATFORM="$zip" ;; | |
| esac | |
| echo "| $PLATFORM | \`$zip\` | \`$SHORT_HASH\` |" >> ../release_body.md | |
| done | |
| cat >> ../release_body.md << 'FOOTER' | |
| ### Verification | |
| ```bash | |
| sha256sum -c SHA256SUMS | |
| ``` | |
| FOOTER | |
| - name: Determine pre-release status | |
| id: prerelease | |
| run: | | |
| if echo "$TAG" | grep -qE '-(rc|beta|alpha)'; then | |
| echo "prerelease=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "prerelease=false" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@b4309332981a82ec1c5618f44dd2e27cc8bfbfda # v3.0.0 | |
| with: | |
| tag_name: ${{ needs.check.outputs.tag }} | |
| name: Aptos CLI ${{ needs.check.outputs.version }} | |
| prerelease: ${{ steps.prerelease.outputs.prerelease == 'true' }} | |
| body_path: release_body.md | |
| files: | | |
| artifacts/aptos-cli-*.zip | |
| artifacts/SHA256SUMS | |
| - name: Update CHANGELOG in this repo | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git add CHANGELOG.md | |
| if ! git diff --cached --quiet; then | |
| git commit -m "Update CHANGELOG from aptos-core ${TAG}" | |
| git push | |
| else | |
| echo "CHANGELOG.md unchanged, skipping commit" | |
| fi | |
| # ──────────────────────────────────────────────────────────────────── | |
| # Job 4: Backfill — upload new artifacts to an existing release and | |
| # merge their checksums into SHA256SUMS without touching anything else. | |
| # ──────────────────────────────────────────────────────────────────── | |
| backfill: | |
| needs: [check, build] | |
| if: needs.check.outputs.should_build == 'true' && needs.check.outputs.backfill == 'true' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| contents: write | |
| env: | |
| TAG: ${{ needs.check.outputs.tag }} | |
| VERSION: ${{ needs.check.outputs.version }} | |
| GH_TOKEN: ${{ github.token }} | |
| GH_REPO: ${{ github.repository }} | |
| steps: | |
| - name: Download newly built artifacts | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | |
| with: | |
| path: new-artifacts | |
| merge-multiple: true | |
| - name: List new artifacts | |
| run: ls -la new-artifacts/ | |
| - name: Download existing SHA256SUMS from release | |
| run: | | |
| mkdir -p existing | |
| if gh release download "$TAG" --repo "$GH_REPO" --pattern "SHA256SUMS" --dir existing; then | |
| echo "Found existing SHA256SUMS" | |
| else | |
| echo "No existing SHA256SUMS in release; will create one" | |
| : > existing/SHA256SUMS | |
| fi | |
| - name: Merge checksums | |
| run: | | |
| set -euo pipefail | |
| cd new-artifacts | |
| # Generate checksums for the new (Windows) zips. | |
| sha256sum aptos-cli-*.zip > new.sums | |
| # Start with the existing checksums... | |
| cp ../existing/SHA256SUMS merged.sums || : > merged.sums | |
| # ...and replace any rows for files we are about to upload, then | |
| # append the new ones. (`grep -v` removes existing entries with the | |
| # same filename so we don't end up with duplicates.) | |
| for f in aptos-cli-*.zip; do | |
| grep -v " $f\$" merged.sums > merged.sums.tmp || true | |
| mv merged.sums.tmp merged.sums | |
| done | |
| cat new.sums >> merged.sums | |
| # Stable, predictable ordering. | |
| sort -k2 merged.sums -o merged.sums | |
| mv merged.sums SHA256SUMS | |
| echo "Merged SHA256SUMS:" | |
| cat SHA256SUMS | |
| - name: Upload artifacts to existing release | |
| working-directory: new-artifacts | |
| run: | | |
| gh release upload "$TAG" \ | |
| --repo "$GH_REPO" \ | |
| --clobber \ | |
| aptos-cli-*.zip SHA256SUMS | |
| - name: Summary | |
| run: | | |
| echo "Backfilled the following assets to $TAG:" | |
| ls -1 new-artifacts/aptos-cli-*.zip | |
| echo "Updated SHA256SUMS in the release." |