name: Release
on:
workflow_dispatch:
permissions:
contents: write
jobs:
create-release:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.parse.outputs.version }}
steps:
- name: checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- name: verify Cargo.toml version matches changelog
run: |
CHANGELOG_VERSION=$(python release.py version)
CARGO_VERSION=$(grep '^version = ' Cargo.toml | head -n1 | sed 's/version = "\(.*\)"/\1/')
echo "CHANGELOG.xml version: $CHANGELOG_VERSION"
echo "Cargo.toml version: $CARGO_VERSION"
if [ "$CHANGELOG_VERSION" != "$CARGO_VERSION" ]; then
echo "❌ Version mismatch!"
echo "Update Cargo.toml to version $CHANGELOG_VERSION before releasing"
exit 1
fi
echo "✅ Versions match"
- name: parse release version from CHANGELOG.xml
id: parse
run: |
VERSION=$(python release.py version)
echo "Found version: $VERSION"
echo "version=$VERSION" >> $GITHUB_OUTPUT
- name: parse release notes from CHANGELOG.xml
run: |
python release.py markdown > release-notes.md
- name: check if tag exists
run: |
if git rev-parse "v${{ steps.parse.outputs.version }}" >/dev/null 2>&1; then
echo "Tag v${{ steps.parse.outputs.version }} already exists!"
exit 1
fi
- name: check if release exists
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
VERSION="v${{ steps.parse.outputs.version }}"
# Check if GitHub release exists (including drafts)
if gh release view "$VERSION" >/dev/null 2>&1; then
echo "❌ GitHub release $VERSION already exists!"
echo "Delete it first: gh release delete $VERSION"
exit 1
fi
echo "✅ No conflicts found"
- name: create release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release create "v${{ steps.parse.outputs.version }}" \
--title "v${{ steps.parse.outputs.version }}" \
--notes-file release-notes.md \
--draft
build:
needs: create-release
strategy:
matrix:
include:
- name: linux-amd64
os: ubuntu-latest
target: x86_64-unknown-linux-gnu
- name: macos-arm64
os: macos-latest
target: aarch64-apple-darwin
- name: windows-amd64
os: windows-latest
target: x86_64-pc-windows-msvc
runs-on: ${{ matrix.os }}
steps:
- name: checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- name: use rust nightly
uses: dtolnay/rust-toolchain@55d80eb3c5a4228eec5390a083c092095115c6f1 with:
toolchain: nightly
targets: ${{ matrix.target }}
- name: install cross-compilation tools
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y musl-tools
if [ "${{ matrix.target }}" = "aarch64-unknown-linux-gnu" ]; then
sudo apt-get install -y gcc-aarch64-linux-gnu
fi
- name: cargo fetch
run: cargo fetch --target ${{ matrix.target }}
- name: download katex fonts
run: make
- name: cargo build
run: cargo build --release --target ${{ matrix.target }}
- name: package
shell: bash
run: |
ARCHIVE_NAME="hashcards-v${{ needs.create-release.outputs.version }}-${{ matrix.name }}"
# Determine binary name based on OS
if [ "${{ matrix.os }}" = "windows-latest" ]; then
BINARY_NAME="hashcards.exe"
ARCHIVE_EXT=".zip"
else
BINARY_NAME="hashcards"
ARCHIVE_EXT=".tar.gz"
fi
BINARY_PATH="target/${{ matrix.target }}/release/${BINARY_NAME}"
# Check: does the binary exist?
if [ ! -f "${BINARY_PATH}" ]; then
echo "❌ Binary not found at ${BINARY_PATH}"
exit 1
fi
mkdir -p "${ARCHIVE_NAME}"
cp "${BINARY_PATH}" "${ARCHIVE_NAME}/${BINARY_NAME}"
# Package based on platform
if [ "${{ matrix.os }}" = "windows-latest" ]; then
powershell Compress-Archive -Path "${ARCHIVE_NAME}" -DestinationPath "${ARCHIVE_NAME}.zip"
else
tar czf "${ARCHIVE_NAME}.tar.gz" "${ARCHIVE_NAME}"
fi
rm -rf "${ARCHIVE_NAME}"
echo "asset=${ARCHIVE_NAME}${ARCHIVE_EXT}" >> $GITHUB_ENV
- name: upload to release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release upload "v${{ needs.create-release.outputs.version }}" "${{ env.asset }}"
publish:
needs:
- create-release
- build
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8
- name: publish release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh release edit "v${{ needs.create-release.outputs.version }}" --draft=false
echo "✅ Release v${{ needs.create-release.outputs.version }} published!"