name: Release
on:
push:
branches: [main]
paths:
- "src/**"
- "Cargo.toml"
- "Cargo.lock"
- ".github/workflows/release.yml"
workflow_dispatch:
inputs:
version_bump:
description: "版本递增类型(手动触发时选择;push [publish] 触发时固定为 patch)"
type: choice
default: patch
options:
- patch
- minor
- major
publish_crates:
description: "发布 crates.io(需 secret CARGO_REGISTRY_TOKEN)"
type: boolean
default: true
publish_npm:
description: "npm stage publish(暂存;需 secret NPM_TOKEN,正式发布还需手动 promote)"
type: boolean
default: true
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-24.04
if: |
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'push' && contains(github.event.head_commit.message, '[publish]'))
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- name: Bump version
id: next_version
run: |
KIND="${{ github.event.inputs.version_bump || 'patch' }}"
[ -z "$KIND" ] && KIND=patch
VER="$(grep -m1 '^version' Cargo.toml | cut -d '"' -f2)"
IFS=. read -r MAJ MIN PAT <<< "$VER"
if [ "$KIND" = "major" ]; then MAJ=$((MAJ+1)); MIN=0; PAT=0
elif [ "$KIND" = "minor" ]; then MIN=$((MIN+1)); PAT=0
else PAT=$((PAT+1)); fi
NV="$MAJ.$MIN.$PAT"
sed -i "s/^version = .*/version = \"$NV\"/" Cargo.toml
# 同步 npm 包版本(单一来源:Cargo.toml)
if [ -f wasm/package.json ]; then
sed -i "s/\"version\": \"[^\"]*\"/\"version\": \"$NV\"/" wasm/package.json
fi
cargo metadata --no-deps --format-version 1 >/dev/null
echo "version=$NV" >> "$GITHUB_OUTPUT"
- name: Commit and tag
if: steps.next_version.outputs.version != ''
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add Cargo.toml
git add wasm/package.json 2>/dev/null || true
# Cargo.lock 被 .gitignore 忽略(库 crate 惯例,不随 checkout 存在):
# 存在才 add(cargo metadata 会在本地生成它),不存在则跳过
git add Cargo.lock 2>/dev/null || true
git commit -m "release: v${{ steps.next_version.outputs.version }} [skip ci]"
git tag "v${{ steps.next_version.outputs.version }}"
git push origin HEAD:main
git push origin "v${{ steps.next_version.outputs.version }}"
- name: Package verify
run: cargo package --allow-dirty
- name: Publish to crates.io
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
run: cargo publish --registry crates-io
if: |
env.CARGO_REGISTRY_TOKEN != '' &&
(
(github.event_name == 'workflow_dispatch' && github.event.inputs.publish_crates == 'true') ||
(github.event_name == 'push' && contains(github.event.head_commit.message, '[publish]'))
)
- name: Stage npm package
working-directory: wasm
env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
npm config set //registry.npmjs.org/:_authToken "${NPM_TOKEN}"
npx -y npm@12 stage publish --registry https://registry.npmjs.org
if: |
env.NPM_TOKEN != '' &&
(
(github.event_name == 'workflow_dispatch' && github.event.inputs.publish_npm == 'true') ||
(github.event_name == 'push' && contains(github.event.head_commit.message, '[publish]'))
)
- name: Build demo binary
run: cargo build --release --example demo
- name: Create GitHub Release
env:
GH_TOKEN: ${{ github.token }}
run: |
gh release create "v${{ steps.next_version.outputs.version }}" \
--repo "${{ github.repository }}" \
--title "v${{ steps.next_version.outputs.version }}" \
--generate-notes \
target/package/multiavatar-*.crate \
target/release/examples/demo