name: Release Binaries
on:
push:
tags:
- "v*"
permissions:
contents: write
jobs:
checks:
name: Pre-release checks
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Verify tag matches Cargo.toml version
shell: bash
run: |
TAG_VERSION="${GITHUB_REF_NAME#v}"
CARGO_VERSION=$(cargo metadata --no-deps --format-version 1 | jq -r '.packages[0].version')
echo "Tag version: $TAG_VERSION"
echo "Cargo.toml version: $CARGO_VERSION"
if [ "$TAG_VERSION" != "$CARGO_VERSION" ]; then
echo "❌ Version mismatch: tag ($TAG_VERSION) != Cargo.toml ($CARGO_VERSION)"
exit 1
fi
echo "✅ Tag and Cargo.toml version match."
build:
name: Build for ${{ matrix.os }}/${{ matrix.arch }}
runs-on: ${{ matrix.os }}
needs: checks
strategy:
matrix:
include:
- os: ubuntu-latest
arch: x86_64
target: x86_64-unknown-linux-gnu
ext: ""
- os: windows-latest
arch: x86_64
target: x86_64-pc-windows-msvc
ext: ".exe"
- os: macos-latest
arch: aarch64
target: aarch64-apple-darwin
ext: ""
- os: macos-latest
arch: x86_64
target: x86_64-apple-darwin
ext: ""
- os: ubuntu-latest
arch: aarch64
target: aarch64-unknown-linux-gnu
ext: ""
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}
- name: Add target
run: rustup target add ${{ matrix.target }}
- name: Install ARM toolchain and et up Cargo config for cross-compilation
if: matrix.target == 'aarch64-unknown-linux-gnu'
run: |
sudo apt update && sudo apt install -y gcc-aarch64-linux-gnu
mkdir -p .cargo
echo '[target.aarch64-unknown-linux-gnu]' > .cargo/config.toml
echo 'linker = "aarch64-linux-gnu-gcc"' >> .cargo/config.toml
rustup target add aarch64-unknown-linux-gnu
- name: Install Deps to build linux packages
if: matrix.os == 'ubuntu-latest'
run: |
cargo install cargo-deb cargo-generate-rpm
- name: Build binary
run: cargo build --release --target ${{ matrix.target }}
- name: Prepare artifact (all OS)
shell: bash
run: |
mkdir -p artifacts
BIN_DIR="target/${{ matrix.target }}/release"
BIN_LIST=$(find "$BIN_DIR" -maxdepth 1 -type f -perm -111 | xargs -n1 basename)
echo "Found binaries: $BIN_LIST"
case "${{ matrix.os }}" in
windows-latest)
ARCHIVE_NAME="coretilus-${{ github.ref_name }}-windows_${{ matrix.arch }}.zip"
BIN_ARRAY=""
for bin in $BIN_LIST; do
BIN_ARRAY+="'$BIN_DIR/$bin',"
done
BIN_ARRAY=${BIN_ARRAY%,}
pwsh -Command "Compress-Archive -Path @($BIN_ARRAY) -DestinationPath 'artifacts/$ARCHIVE_NAME' -Force"
;;
ubuntu-latest)
ARCHIVE_NAME="coretilus-${{ github.ref_name }}-linux_${{ matrix.arch }}.tar.gz"
tar -czf "artifacts/$ARCHIVE_NAME" -C "$BIN_DIR" $BIN_LIST
cargo deb --target ${{ matrix.target }}
cp -v target/debian/*.deb artifacts/
cargo generate-rpm --target ${{ matrix.target }}
cp -v target/${{ matrix.target }}/generate-rpm/*.rpm artifacts/
;;
macos-latest)
ARCHIVE_NAME="coretilus-${{ github.ref_name }}-macos_${{ matrix.arch }}.tar.gz"
tar -czf "artifacts/$ARCHIVE_NAME" -C "$BIN_DIR" $BIN_LIST
;;
*)
echo "Unsupported OS: ${{ matrix.os }}"
exit 1
;;
esac
echo "Created artifact: artifacts/$ARCHIVE_NAME"
- name: Upload artifact
uses: actions/upload-artifact@v7
with:
name: ${{ matrix.target }}
path: artifacts/
release:
name: Create GitHub Release
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Download all artifacts
uses: actions/download-artifact@v7
with:
path: artifacts/
- name: Create GitHub Release
uses: softprops/action-gh-release@v3
with:
files: artifacts/**/*
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
publish-crates:
name: Publish to crates.io
runs-on: ubuntu-latest
needs: release
permissions:
id-token: write
contents: read
environment:
name: crates-io
url: https://crates.io/crates/coretilus
steps:
- name: Checkout repository
uses: actions/checkout@v7
- name: Setup Rust toolchain
uses: dtolnay/rust-toolchain@stable
- uses: rust-lang/crates-io-auth-action@v1
id: auth
- name: Publish to crates.io
uses: katyo/publish-crates@v2
with:
registry-token: ${{ steps.auth.outputs.token }}
publish-homebrew:
name: Publish/Update Homebrew formula
runs-on: ubuntu-latest
needs: release
steps:
- name: Extract version from branch/tag
id: version
run: |
TAG="${GITHUB_REF_NAME}"
VERSION="${TAG#v}"
echo "version=${VERSION}" >> $GITHUB_OUTPUT
echo "tag=${TAG}" >> $GITHUB_OUTPUT
echo "Version: ${VERSION}, Tag: ${TAG}"
- name: Download and extract release assets
id: assets
run: |
set -x
VERSION="${{ steps.version.outputs.version }}"
TAG="${{ steps.version.outputs.tag }}"
BASE_URL="https://github.com/${{ github.repository }}/releases/download/${TAG}"
download_and_extract() {
local file=$1
local arch=$2
echo "Downloading ${BASE_URL}/${file}..."
if curl -fsSL "${BASE_URL}/${file}" -o "${file}"; then
SHA=$(sha256sum "${file}" | cut -d' ' -f1)
echo "✅ SHA256 ${arch}: ${SHA}"
mkdir -p "temp_${arch}"
tar -xzf "${file}" -C "temp_${arch}"
BINS=$(find "temp_${arch}" -maxdepth 1 -type f -perm -111 -exec basename {} \; | tr "\n" " ")
echo "✅ Binaires trouvés (${arch}): ${BINS}"
echo "${SHA}|${BINS}"
else
echo "ERROR: Failed to download ${file}"
exit 1
fi
}
ARM64_DATA=$(download_and_extract "coretilus-${TAG}-macos_aarch64.tar.gz" "arm64")
echo $ARM64_DATA
SHA_ARM64=$(echo "$ARM64_DATA" | tail -1 | cut -d'|' -f1)
BINS_ARM64=$(echo "$ARM64_DATA" | tail -1 | cut -d'|' -f2)
X86_64_DATA=$(download_and_extract "coretilus-${TAG}-macos_x86_64.tar.gz" "x86_64")
echo $X86_64_DATA
SHA_X86_64=$(echo "$X86_64_DATA" | tail -1 | cut -d'|' -f1)
BINS_X86_64=$(echo "$X86_64_DATA" | tail -1 | cut -d'|' -f2)
echo "sha_arm64=${SHA_ARM64}" >> $GITHUB_OUTPUT
echo "sha_x86_64=${SHA_X86_64}" >> $GITHUB_OUTPUT
echo "binaries=${BINS_ARM64}" >> $GITHUB_OUTPUT
- name: Checkout tap repository
uses: actions/checkout@v7
with:
repository: titilambert/homebrew-tap
ssh-key: ${{ secrets.TAP_DEPLOY_KEY }}
path: tap
- name: Generate formula from template
run: |
set -x
VERSION="${{ steps.version.outputs.version }}"
TAG="${{ steps.version.outputs.tag }}"
TEMPLATE="tap/templates/coretilus.rb.template"
FORMULA="tap/Formula/coretilus.rb"
BINARIES=$(echo '${{ steps.assets.outputs.binaries }}' | tr " " "\n")
if [ ! -f "$TEMPLATE" ]; then
echo "❌ Error: Template not found at $TEMPLATE"
exit 1
fi
mkdir -p "tap/Formula"
BINARIES_INSTALL=""
BINARIES_TEST=""
for binary in $BINARIES; do
BINARIES_INSTALL="${BINARIES_INSTALL} bin.install \"${binary}\"\n"
BINARIES_TEST="${BINARIES_TEST} assert_match \"${binary}\", shell_output(\"#{bin}/${binary} --version 2>&1\", 0)\n"
done
cp "$TEMPLATE" "$FORMULA"
sed -i "s/{{VERSION}}/${VERSION}/g" "$FORMULA"
sed -i "s/{{SHA256_ARM64}}/${{ steps.assets.outputs.sha_arm64 }}/g" "$FORMULA"
sed -i "s/{{SHA256_X86_64}}/${{ steps.assets.outputs.sha_x86_64 }}/g" "$FORMULA"
awk -v version="$VERSION" \
-v sha_arm64="${{ steps.assets.outputs.sha_arm64 }}" \
-v sha_x86_64="${{ steps.assets.outputs.sha_x86_64 }}" \
-v bins_install="$BINARIES_INSTALL" \
-v bins_test="$BINARIES_TEST" '
{
gsub(/\{\{VERSION\}\}/, version)
gsub(/\{\{SHA256_ARM64\}\}/, sha_arm64)
gsub(/\{\{SHA256_X86_64\}\}/, sha_x86_64)
gsub(/\{\{BINARIES_INSTALL\}\}/, bins_install)
gsub(/\{\{BINARIES_TEST\}\}/, bins_test)
print
}' "$TEMPLATE" > "$FORMULA"
echo "✅ Formula generated:"
cat "$FORMULA"
- name: Commit and push to tap repository
run: |
cd tap
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add Formula/coretilus.rb
git commit -m "chore: bump coretilus to ${{ steps.version.outputs.tag }}"
git tag -a "coretilus-${{ steps.version.outputs.tag }}" -m "Coretilus ${{ steps.version.outputs.tag }}"
git push origin main
git push origin "coretilus-${{ steps.version.outputs.tag }}"