name: PR Checks & Release (Crates.io & GitHub)
on:
pull_request:
branches:
- main
types:
- opened
- synchronize
- reopened
- ready_for_review
push:
branches:
- main
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ ubuntu-latest, macos-latest, windows-latest ]
arch: [ x86_64, aarch64, i686, armv7, ppc64le, riscv64 ]
exclude:
- os: windows-latest
arch: aarch64
- os: windows-latest
arch: armv7
- os: windows-latest
arch: ppc64le
- os: windows-latest
arch: riscv64
- os: macos-latest
arch: i686
- os: macos-latest
arch: armv7
- os: macos-latest
arch: ppc64le
- os: macos-latest
arch: riscv64
include:
- os: ubuntu-latest
arch: x86_64
target: x86_64-unknown-linux-gnu
- os: macos-latest
arch: x86_64
target: x86_64-apple-darwin
- os: windows-latest
arch: x86_64
target: x86_64-pc-windows-msvc
- os: ubuntu-latest
arch: aarch64
target: aarch64-unknown-linux-gnu
- os: macos-latest
arch: aarch64
target: aarch64-apple-darwin
- os: ubuntu-latest
arch: i686
target: i686-unknown-linux-gnu
- os: windows-latest
arch: i686
target: i686-pc-windows-msvc
- os: ubuntu-latest
arch: armv7
target: armv7-unknown-linux-gnueabihf
- os: ubuntu-latest
arch: ppc64le
target: powerpc64le-unknown-linux-gnu
- os: ubuntu-latest
arch: riscv64
target: riscv64gc-unknown-linux-gnu
fail-fast: false
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
targets: ${{ matrix.target }}
components: clippy
- name: Cache cargo registry
uses: actions/cache@v3
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-${{ matrix.target }}-cargo-
- name: Install cross
if: matrix.os == 'ubuntu-latest' && matrix.arch != 'x86_64'
run: |
cargo install cross --git https://github.com/cross-rs/cross
- name: Run Clippy (native)
if: (matrix.os == 'ubuntu-latest' && matrix.arch == 'x86_64') || (matrix.os == 'macos-latest' && matrix.arch == 'x86_64') || (matrix.os == 'windows-latest' && matrix.arch == 'x86_64')
run: cargo clippy --target ${{ matrix.target }}
- name: Run Clippy (Linux cross-compilation)
if: matrix.os == 'ubuntu-latest' && matrix.arch != 'x86_64'
run: cross clippy --target ${{ matrix.target }}
- name: Build (native)
if: (matrix.os == 'ubuntu-latest' && matrix.arch == 'x86_64') || (matrix.os == 'macos-latest') || (matrix.os == 'windows-latest')
run: cargo build --verbose --target ${{ matrix.target }}
- name: Test (native)
if: (matrix.os == 'ubuntu-latest' && matrix.arch == 'x86_64') || (matrix.os == 'macos-latest' && matrix.arch == 'x86_64') || (matrix.os == 'windows-latest' && matrix.arch == 'x86_64')
run: cargo test --verbose --target ${{ matrix.target }}
- name: Build (Linux cross-compilation)
if: matrix.os == 'ubuntu-latest' && matrix.arch != 'x86_64'
run: cross build --verbose --target ${{ matrix.target }}
- name: Test (Linux cross-compilation)
if: matrix.os == 'ubuntu-latest' && matrix.arch != 'x86_64'
run: cross test --verbose --target ${{ matrix.target }}
- name: Build and Test (Windows i686)
if: matrix.os == 'windows-latest' && matrix.arch == 'i686'
run: |
cargo build --verbose --target ${{ matrix.target }}
cargo test --verbose --target ${{ matrix.target }}
- name: Build and Test (macOS aarch64)
if: matrix.os == 'macos-latest' && matrix.arch == 'aarch64'
run: |
cargo build --verbose --target ${{ matrix.target }}
cargo test --verbose --target ${{ matrix.target }}
release:
name: Release on successful tests and merge
needs: test
if: github.event_name == 'push' runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
ssh-key: ${{ secrets.DEPLOY_KEY }}
fetch-depth: 0
- name: Set up Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: stable
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y build-essential
cargo install cargo-edit
- name: Build
run: cargo build --release --verbose
- name: Check package version
id: check_version
run: echo "VERSION=$(cargo metadata --format-version 1 --no-deps | jq -r '.packages[0].version')" >> $GITHUB_ENV
- name: Extract PR Number from Merge Commit
run: |
PR_NUMBER=$(git log -1 --pretty=%B | grep -oE 'Merge pull request #[0-9]+' | awk '{print $4}' | tr -d '#')
if [ -z "$PR_NUMBER" ]; then
echo "❌ Error: Could not determine PR number!"
exit 1
fi
echo "✅ Extracted PR Number: $PR_NUMBER"
echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV
- name: Fetch PR Labels Using GitHub API
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
run: |
PR_NUMBER="${{ env.PR_NUMBER }}"
LABELS_JSON=$(curl -s -H "Authorization: token $RELEASE_TOKEN" \
"https://api.github.com/repos/${{ github.repository }}/issues/${PR_NUMBER}/labels")
echo "✅ PR Labels JSON: $LABELS_JSON"
# Extract labels into a space-separated string
LABELS=$(echo "$LABELS_JSON" | jq -r 'map(.name) | join(" ")')
echo "✅ PR Labels: $LABELS"
# Determine version bump priority: major > minor > patch
VERSION_PART="patch" # Default to patch
if echo "$LABELS" | grep -iq "major"; then
VERSION_PART="major"
elif echo "$LABELS" | grep -iq "minor"; then
VERSION_PART="minor"
fi
echo "✅ Selected Version Bump: $VERSION_PART"
echo "VERSION_PART=$VERSION_PART" >> $GITHUB_ENV
- name: Determine Version Bump
run: |
if [[ "${{ env.VERSION_PART }}" == "major" ]]; then
NEW_VERSION=$(echo "${{ env.VERSION }}" | awk -F. -v OFS=. '{$1 += 1 ; $2=0; $3=0; print}')
elif [[ "${{ env.VERSION_PART }}" == "minor" ]]; then
NEW_VERSION=$(echo "${{ env.VERSION }}" | awk -F. -v OFS=. '{$2 += 1 ; $3=0; print}')
else
NEW_VERSION=$(echo "${{ env.VERSION }}" | awk -F. -v OFS=. '{$NF += 1 ; print}')
fi
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_ENV
- name: Update Cargo.toml with new version
run: cargo set-version ${{ env.NEW_VERSION }}
- name: Commit and push new version (Bypass Branch Protection)
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
run: |
git config --global user.name "GitHub Actions"
git config --global user.email "actions@github.com"
git add Cargo.toml
git commit -m "Bumping version to ${{ env.NEW_VERSION }} for release 🚀 [skip ci]"
git push origin main
- name: Tag version and push
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
run: |
git tag "v${{ env.NEW_VERSION }}"
git push origin "v${{ env.NEW_VERSION }}"
- name: Publish to Crates.io
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}
run: cargo publish --token $CARGO_REGISTRY_TOKEN
- name: Create GitHub Release
uses: softprops/action-gh-release@v2.2.1
with:
token: ${{ secrets.RELEASE_TOKEN }}
tag_name: v${{ env.NEW_VERSION }}
name: Release v${{ env.NEW_VERSION }}
body: "🚀 Automated release triggered by successful tests on main.\n\n📦 **[View on Crates.io](https://crates.io/crates/memsafe/${{ env.NEW_VERSION }})**"
draft: false
prerelease: false