name: Release
on:
release:
types: [published]
permissions:
contents: write
env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: 1
jobs:
prepare:
name: Prepare Release
runs-on: ubuntu-latest
outputs:
version: ${{ steps.version.outputs.version }}
version_valid: ${{ steps.version.outputs.valid }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Extract version from tag
id: version
run: |
# Remove 'v' prefix if present (e.g., v0.2.0 -> 0.2.0)
VERSION="${GITHUB_REF_NAME#v}"
echo "version=$VERSION" >> $GITHUB_OUTPUT
# Validate semver format
if [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z0-9.]+)?$ ]]; then
echo "valid=true" >> $GITHUB_OUTPUT
echo "✅ Version: $VERSION (valid semver)"
else
echo "valid=false" >> $GITHUB_OUTPUT
echo "❌ Version: $VERSION (invalid semver)"
exit 1
fi
- name: Verify version matches all manifests
run: |
RELEASE_VERSION="${{ steps.version.outputs.version }}"
ERRORS=0
# Check Cargo.toml
CARGO_VERSION=$(grep '^version =' Cargo.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
if [ "$CARGO_VERSION" != "$RELEASE_VERSION" ]; then
echo "❌ Cargo.toml: $CARGO_VERSION (expected $RELEASE_VERSION)"
ERRORS=1
else
echo "✅ Cargo.toml: $CARGO_VERSION"
fi
# Check pyproject.toml
PYPROJECT_VERSION=$(grep '^version =' pyproject.toml | head -1 | sed 's/.*"\(.*\)".*/\1/')
if [ "$PYPROJECT_VERSION" != "$RELEASE_VERSION" ]; then
echo "❌ pyproject.toml: $PYPROJECT_VERSION (expected $RELEASE_VERSION)"
ERRORS=1
else
echo "✅ pyproject.toml: $PYPROJECT_VERSION"
fi
# Check bindings/wasm/package.json
NPM_VERSION=$(grep '"version":' bindings/wasm/package.json | head -1 | sed 's/.*: *"\([^"]*\)".*/\1/')
if [ "$NPM_VERSION" != "$RELEASE_VERSION" ]; then
echo "❌ bindings/wasm/package.json: $NPM_VERSION (expected $RELEASE_VERSION)"
ERRORS=1
else
echo "✅ bindings/wasm/package.json: $NPM_VERSION"
fi
# Check Cargo.lock
LOCK_VERSION=$(grep -A1 '^name = "kya-validator"$' Cargo.lock | grep '^version =' | head -1 | sed 's/.*"\(.*\)".*/\1/')
if [ "$LOCK_VERSION" != "$RELEASE_VERSION" ]; then
echo "❌ Cargo.lock: $LOCK_VERSION (expected $RELEASE_VERSION)"
ERRORS=1
else
echo "✅ Cargo.lock: $LOCK_VERSION"
fi
if [ $ERRORS -eq 1 ]; then
echo ""
echo "⚠️ Version mismatch detected!"
echo "Please update all manifest files before creating release:"
echo " - Cargo.toml"
echo " - pyproject.toml"
echo " - bindings/wasm/package.json"
echo " - Cargo.lock (run: cargo update -p kya-validator)"
exit 1
fi
echo ""
echo "✅ All versions match: $RELEASE_VERSION"
publish-crates:
name: Publish to crates.io
needs: prepare
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo
uses: Swatinem/rust-cache@v2
- name: Build
run: cargo build --release
- name: Publish to crates.io
run: cargo publish --token ${{ secrets.CRATES_IO_TOKEN }}
- name: Summary
run: |
echo "## crates.io Publish Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "✅ Published \`kya-validator\` v${{ needs.prepare.outputs.version }} to crates.io" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Package: https://crates.io/crates/kya-validator" >> $GITHUB_STEP_SUMMARY
publish-npm:
name: Publish WASM to npm
needs: prepare
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-unknown-unknown
- name: Cache Rust dependencies
uses: Swatinem/rust-cache@v2
with:
key: wasm-${{ hashFiles('**/Cargo.lock') }}
- name: Install wasm-pack
run: cargo install wasm-pack --locked
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Build WASM package
run: wasm-pack build --scope open-kya --release
- name: Update package.json version
working-directory: pkg
run: |
VERSION="${{ needs.prepare.outputs.version }}"
# Update version in package.json
jq --arg v "$VERSION" '.version = $v' package.json > package.json.tmp && mv package.json.tmp package.json
echo "✅ Updated pkg/package.json version to $VERSION"
- name: Publish to npm
working-directory: pkg
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npm publish --access public
- name: Summary
run: |
echo "## npm Publish Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "✅ Published \`@open-kya/kya-validator-wasm\` v${{ needs.prepare.outputs.version }} to npm" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Package: https://www.npmjs.com/package/@open-kya/kya-validator-wasm" >> $GITHUB_STEP_SUMMARY
publish-pypi:
name: Publish to PyPI (${{ matrix.os }})
needs: prepare
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install uv
uses: astral-sh/setup-uv@v4
with:
enable-cache: true
- name: Build wheel
run: |
uv sync --extra dev
uv run maturin build --release
- name: Publish to PyPI
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
run: |
uv pip install twine
uv run twine upload target/wheels/*.whl
- name: Summary
shell: bash
run: |
OS_NAME="${{ matrix.os }}"
if [ "$OS_NAME" == "ubuntu-latest" ]; then
PLATFORM="Linux x86_64"
else
PLATFORM="macOS ARM64"
fi
echo "## PyPI Publish Summary ($PLATFORM)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "✅ Published \`kya-validator\` v${{ needs.prepare.outputs.version }} ($PLATFORM wheel) to PyPI" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Package: https://pypi.org/project/kya-validator/${{ needs.prepare.outputs.version }}/#files" >> $GITHUB_STEP_SUMMARY
upload-assets:
name: Upload Release Assets
needs: [prepare, publish-pypi]
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install uv
uses: astral-sh/setup-uv@v4
- name: Build all wheels
run: |
uv sync --extra dev
uv run maturin build --release
- name: Upload wheels to release
uses: softprops/action-gh-release@v2
with:
files: target/wheels/*.whl
fail_on_unmatched_files: true
- name: Summary
run: |
echo "## Release Assets Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "✅ Uploaded wheels to GitHub Release v${{ needs.prepare.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Release: ${{ github.event.release.html_url }}" >> $GITHUB_STEP_SUMMARY