Skip to content

fix: add checkout to upload-binaries, update Cargo.lock, reorder crat… #224

fix: add checkout to upload-binaries, update Cargo.lock, reorder crat…

fix: add checkout to upload-binaries, update Cargo.lock, reorder crat… #224

Workflow file for this run

name: Release
on:
push:
branches:
- main
workflow_dispatch: {}
permissions:
contents: write
packages: write
env:
CARGO_TERM_COLOR: always
IMAGE_NAME: ${{ github.repository }}
jobs:
# ------------------------------------------------------------------
# 0. Detect whether this is a release run
# ------------------------------------------------------------------
check-release:
name: Check release
runs-on: ubuntu-latest
outputs:
is_release: ${{ steps.check.outputs.is_release }}
version: ${{ steps.check.outputs.version }}
version_major: ${{ steps.check.outputs.version_major }}
version_minor: ${{ steps.check.outputs.version_minor }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6.0.2
with:
fetch-depth: 1
fetch-tags: true
- name: Detect release
id: check
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
VERSION="v$(grep '^version' Cargo.toml | head -1 | sed 's/.*"\(.*\)"/\1/')"
RAW="${VERSION#v}"
MAJOR=$(echo "$RAW" | cut -d. -f1)
MINOR="${MAJOR}.$(echo "$RAW" | cut -d. -f2)"
echo "is_release=true" >> "$GITHUB_OUTPUT"
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
echo "version_major=$MAJOR" >> "$GITHUB_OUTPUT"
echo "version_minor=$MINOR" >> "$GITHUB_OUTPUT"
if git tag -l "$VERSION" | grep -q .; then
echo "::error::Tag $VERSION already exists"
exit 1
fi
echo "Detected release: $VERSION"
else
echo "is_release=false" >> "$GITHUB_OUTPUT"
echo "version=" >> "$GITHUB_OUTPUT"
echo "Not a release run"
fi
# ------------------------------------------------------------------
# 1. Build binaries for each target (always)
# ------------------------------------------------------------------
build-binaries:
name: Build ${{ matrix.name }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
# Linux x86_64 (baseline)
- name: linux-x86_64
os: ubuntu-latest
target: x86_64-unknown-linux-gnu
# Linux x86_64 with AVX2 (x86-64-v3)
- name: linux-x86_64-v3
os: ubuntu-latest
target: x86_64-unknown-linux-gnu
target_cpu: x86-64-v3
# Linux x86_64 with AVX-512 (x86-64-v4)
- name: linux-x86_64-v4
os: ubuntu-latest
target: x86_64-unknown-linux-gnu
target_cpu: x86-64-v4
# Linux aarch64 (native arm64 runner, baseline)
- name: linux-aarch64
os: ubuntu-24.04-arm
target: aarch64-unknown-linux-gnu
# Linux aarch64 with SVE (Graviton 3+, Axion, Grace)
- name: linux-aarch64-neoverse-v1
os: ubuntu-24.04-arm
target: aarch64-unknown-linux-gnu
target_cpu: neoverse-v1
# macOS x86_64 (cross-compiled on Apple Silicon runner)
- name: macos-x86_64
os: macos-latest
target: x86_64-apple-darwin
# macOS aarch64 (Apple Silicon, baseline)
- name: macos-aarch64
os: macos-latest
target: aarch64-apple-darwin
# macOS aarch64 (Apple M1 optimized)
- name: macos-aarch64-apple-m1
os: macos-latest
target: aarch64-apple-darwin
target_cpu: apple-m1
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6.0.2
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 # ratchet:dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
# Linux build dependencies
- name: Install Linux build deps
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y cmake zlib1g-dev libbz2-dev liblzma-dev \
libcurl4-openssl-dev libssl-dev libfontconfig1-dev pkg-config clang
# macOS build dependencies
- name: Install macOS build deps
if: runner.os == 'macOS'
run: brew install bzip2 xz
- name: Build
run: >
cargo build --release --target ${{ matrix.target }}
${TARGET_CPU:+--config "target.'${{ matrix.target }}'.rustflags=['-C', 'target-cpu=$TARGET_CPU']"}
env:
TARGET_CPU: ${{ matrix.target_cpu || '' }}
- name: Package
id: package
run: |
BIN="rustqc"
ARCHIVE="${BIN}-${{ matrix.name }}"
mkdir -p "staging/${ARCHIVE}"
cp "target/${{ matrix.target }}/release/${BIN}" "staging/${ARCHIVE}/"
cp README.md LICENSE "staging/${ARCHIVE}/" 2>/dev/null || true
cd staging
tar czf "../${ARCHIVE}.tar.gz" "${ARCHIVE}"
cd ..
# SHA256 checksum
shasum -a 256 "${ARCHIVE}.tar.gz" > "${ARCHIVE}.tar.gz.sha256"
echo "archive=${ARCHIVE}.tar.gz" >> "$GITHUB_OUTPUT"
echo "checksum=${ARCHIVE}.tar.gz.sha256" >> "$GITHUB_OUTPUT"
- name: Upload build artifact
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # ratchet:actions/upload-artifact@v7.0.0
with:
name: binary-${{ matrix.name }}
path: |
${{ steps.package.outputs.archive }}
${{ steps.package.outputs.checksum }}
retention-days: 1
# ------------------------------------------------------------------
# 2. Build per-platform Docker images on native runners
# ------------------------------------------------------------------
docker-build:
name: Docker ${{ matrix.platform }}
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- platform: linux/amd64
runner: ubuntu-latest
- platform: linux/arm64
runner: ubuntu-24.04-arm
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6.0.2
- name: Lowercase image name
run: echo "IMAGE_NAME=${IMAGE_NAME,,}" >> "$GITHUB_ENV"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # ratchet:docker/setup-buildx-action@v4.0.0
- name: Log in to GHCR
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # ratchet:docker/login-action@v4.1.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Get short commit hash
id: git-hash
run: echo "short_hash=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
- name: Build and push by digest
id: build
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # ratchet:docker/build-push-action@v7.0.0
with:
context: .
platforms: ${{ matrix.platform }}
build-args: |
GIT_SHORT_HASH=${{ steps.git-hash.outputs.short_hash }}
outputs: type=image,name=ghcr.io/${{ env.IMAGE_NAME }},push-by-digest=true,name-canonical=true,push=true
cache-from: type=gha,scope=${{ matrix.platform }}
cache-to: type=gha,scope=${{ matrix.platform }},mode=max
- name: Export digest
run: |
mkdir -p /tmp/digests
digest="${{ steps.build.outputs.digest }}"
touch "/tmp/digests/${digest#sha256:}"
- name: Upload digest
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # ratchet:actions/upload-artifact@v7.0.0
with:
name: digests-${{ matrix.runner }}
path: /tmp/digests/*
if-no-files-found: error
retention-days: 1
# ------------------------------------------------------------------
# 2a. Build SIMD-optimized Docker images (single-arch each)
# ------------------------------------------------------------------
docker-build-simd:
name: Docker ${{ matrix.name }}
needs: [check-release]
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- name: amd64-avx2
runner: ubuntu-latest
platform: linux/amd64
cpu_target: x86-64-v3
tag_suffix: avx2
- name: amd64-avx512
runner: ubuntu-latest
platform: linux/amd64
cpu_target: x86-64-v4
tag_suffix: avx512
- name: arm64-sve
runner: ubuntu-24.04-arm
platform: linux/arm64
cpu_target: neoverse-v1
tag_suffix: sve
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6.0.2
- name: Prepare build metadata
id: prep
run: |
echo "IMAGE_NAME=${IMAGE_NAME,,}" >> "$GITHUB_ENV"
echo "short_hash=$(git rev-parse --short HEAD)" >> "$GITHUB_OUTPUT"
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # ratchet:docker/setup-buildx-action@v4.0.0
- name: Log in to GHCR
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # ratchet:docker/login-action@v4.1.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker meta
id: meta
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # ratchet:docker/metadata-action@v6.0.0
with:
images: ghcr.io/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=${{ needs.check-release.outputs.version }}-${{ matrix.tag_suffix }},enable=${{ needs.check-release.outputs.is_release == 'true' }}
type=raw,value=latest-${{ matrix.tag_suffix }},enable=${{ needs.check-release.outputs.is_release == 'true' }}
type=raw,value=dev-${{ matrix.tag_suffix }}
- name: Build and push
uses: docker/build-push-action@d08e5c354a6adb9ed34480a06d141179aa583294 # ratchet:docker/build-push-action@v7.0.0
with:
context: .
platforms: ${{ matrix.platform }}
push: true
tags: ${{ steps.meta.outputs.tags }}
build-args: |
GIT_SHORT_HASH=${{ steps.prep.outputs.short_hash }}
CPU_TARGET=${{ matrix.cpu_target }}
cache-from: type=gha,scope=${{ matrix.name }}
cache-to: type=gha,scope=${{ matrix.name }},mode=max
# ------------------------------------------------------------------
# 2b. Merge per-platform images into a multi-arch manifest
# ------------------------------------------------------------------
docker-merge:
name: Docker merge
needs: [check-release, docker-build]
runs-on: ubuntu-latest
steps:
- name: Lowercase image name
run: echo "IMAGE_NAME=${IMAGE_NAME,,}" >> "$GITHUB_ENV"
- name: Download digests
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # ratchet:actions/download-artifact@v8.0.1
with:
pattern: digests-*
path: /tmp/digests
merge-multiple: true
- name: Docker meta
id: meta
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # ratchet:docker/metadata-action@v6.0.0
with:
images: ghcr.io/${{ env.IMAGE_NAME }}
tags: |
type=raw,value=${{ needs.check-release.outputs.version }},enable=${{ needs.check-release.outputs.is_release == 'true' }}
type=raw,value=${{ needs.check-release.outputs.version_minor }},enable=${{ needs.check-release.outputs.is_release == 'true' }}
type=raw,value=${{ needs.check-release.outputs.version_major }},enable=${{ needs.check-release.outputs.is_release == 'true' }}
type=raw,value=latest,enable=${{ needs.check-release.outputs.is_release == 'true' }}
type=raw,value=dev
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # ratchet:docker/setup-buildx-action@v4.0.0
- name: Log in to GHCR
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # ratchet:docker/login-action@v4.1.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Create manifest list and push
working-directory: /tmp/digests
run: |
docker buildx imagetools create \
$(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
$(printf 'ghcr.io/${{ env.IMAGE_NAME }}@sha256:%s ' *)
# ------------------------------------------------------------------
# 3. Create tag and draft release (release only, after all builds)
# ------------------------------------------------------------------
create-tag-and-release:
name: Create tag and release
if: needs.check-release.outputs.is_release == 'true'
needs: [check-release, build-binaries, docker-merge, docker-build-simd]
runs-on: ubuntu-latest
outputs:
tag: ${{ needs.check-release.outputs.version }}
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6.0.2
- name: Create tag
run: |
git tag "${{ needs.check-release.outputs.version }}"
git push origin "${{ needs.check-release.outputs.version }}"
- name: Extract changelog
run: |
RAW="${{ needs.check-release.outputs.version }}"
RAW="${RAW#v}"
awk '/^## \[Version '"$RAW"'\]/{found=1; next} /^## \[/{if(found) exit} found' CHANGELOG.md > /tmp/release-notes.md
- name: Create release
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release create "${{ needs.check-release.outputs.version }}" \
--target "${{ github.sha }}" \
--title "RustQC ${{ needs.check-release.outputs.version }}" \
--notes-file /tmp/release-notes.md
# ------------------------------------------------------------------
# 4. Upload binaries to the release
# ------------------------------------------------------------------
upload-binaries:
name: Upload binaries
if: needs.check-release.outputs.is_release == 'true'
needs: [check-release, create-tag-and-release, build-binaries]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6.0.2
- name: Download all binary artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # ratchet:actions/download-artifact@v8.0.1
with:
pattern: binary-*
path: /tmp/binaries
merge-multiple: true
- name: Upload to release
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release upload "${{ needs.create-tag-and-release.outputs.tag }}" \
/tmp/binaries/*.tar.gz \
/tmp/binaries/*.sha256
# ------------------------------------------------------------------
# 5. Publish to crates.io (release only, last step)
# ------------------------------------------------------------------
publish-crate:
name: Publish to crates.io
if: needs.check-release.outputs.is_release == 'true'
needs: [check-release, upload-binaries]
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # ratchet:actions/checkout@v6.0.2
- name: Authenticate with crates.io
id: auth
uses: rust-lang/crates-io-auth-action@bbd81622f20ce9e2dd9622e3218b975523e45bbe # ratchet:rust-lang/crates-io-auth-action@v1.0.4
- name: Publish to crates.io
run: cargo publish --no-verify
env:
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}