name: Release and Publish
on:
push:
tags: ['v*']
workflow_dispatch:
inputs:
version:
description: 'Version to release (e.g., v0.1.0)'
required: true
type: string
env:
CARGO_TERM_COLOR: always
permissions:
contents: write
jobs:
test:
name: Test and Validate
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy
- name: Cache cargo dependencies
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-test-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-test-
${{ runner.os }}-cargo-
- name: Check code formatting
run: cargo fmt -- --check
- name: Run clippy
run: cargo clippy --all-targets --all-features -- -D warnings
- name: Run tests
run: cargo test --all-features
- name: Test documentation
run: cargo doc --no-deps --all-features
- name: Check for security vulnerabilities
run: |
cargo install cargo-audit
cargo audit
verify:
name: Verify Release
runs-on: ubuntu-latest
needs: test
outputs:
version: ${{ steps.version.outputs.version }}
cargo_version: ${{ steps.version.outputs.cargo_version }}
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Verify version consistency
id: version
run: |
chmod +x scripts/verify-version.sh
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
./scripts/verify-version.sh "${{ github.event.inputs.version }}"
else
./scripts/verify-version.sh
fi
# 输出版本信息供后续job使用
echo "version=${RELEASE_VERSION}" >> $GITHUB_OUTPUT
echo "cargo_version=${CARGO_VERSION}" >> $GITHUB_OUTPUT
- name: Verify package can be built
run: cargo build --release
- name: Verify package can be packaged
run: |
cargo package --allow-dirty
echo "Package verification successful"
- name: Check publish readiness (dry run)
run: |
cargo publish --dry-run --allow-dirty
echo "Publish dry run successful"
github-release:
name: Create GitHub Release
runs-on: ubuntu-latest
needs: verify
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo dependencies
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-release-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-release-
${{ runner.os }}-cargo-
- name: Generate changelog
id: changelog
run: |
echo "## Changes in ${{ needs.verify.outputs.version }}" > CHANGELOG.md
echo "" >> CHANGELOG.md
# 尝试从Git提交生成变更日志
if [ -n "$(git tag --list | tail -2 | head -1)" ]; then
PREV_TAG=$(git tag --list | tail -2 | head -1)
echo "### Commits since $PREV_TAG:" >> CHANGELOG.md
git log --oneline $PREV_TAG..HEAD >> CHANGELOG.md
else
echo "### Initial release" >> CHANGELOG.md
echo "- First release of wim-parser library" >> CHANGELOG.md
fi
echo "changelog<<EOF" >> $GITHUB_OUTPUT
cat CHANGELOG.md >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ needs.verify.outputs.version }}
name: Release ${{ needs.verify.outputs.version }}
body: ${{ steps.changelog.outputs.changelog }}
draft: false
prerelease: false
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
crates-publish:
name: Publish to crates.io
runs-on: ubuntu-latest
needs: [verify, github-release]
environment: crates-io
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo dependencies
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-publish-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-publish-
${{ runner.os }}-cargo-
- name: Publish to crates.io
run: |
echo "Publishing wim-parser version ${{ needs.verify.outputs.cargo_version }} to crates.io"
cargo publish --token ${{ secrets.CRATES_TOKEN }} --allow-dirty
echo "✅ Successfully published to crates.io!"
- name: Verify publication
run: |
echo "Waiting for crates.io to index the new version..."
sleep 30
# 验证发布是否成功
if cargo search wim-parser | grep -q "${{ needs.verify.outputs.cargo_version }}"; then
echo "✅ Version ${{ needs.verify.outputs.cargo_version }} is now available on crates.io"
else
echo "⚠️ Version may still be indexing on crates.io"
fi
notify:
name: Notify Release Complete
runs-on: ubuntu-latest
needs: [verify, github-release, crates-publish]
if: always()
steps:
- name: Release Summary
run: |
echo "## 🎉 Release Summary"
echo "- Version: ${{ needs.verify.outputs.version }}"
echo "- GitHub Release: ${{ needs.github-release.result }}"
echo "- Crates.io Publish: ${{ needs.crates-publish.result }}"
if [ "${{ needs.github-release.result }}" = "success" ] && [ "${{ needs.crates-publish.result }}" = "success" ]; then
echo "✅ Release completed successfully!"
echo "📦 Package is now available at: https://crates.io/crates/wim-parser"
echo "📋 Release notes: https://github.com/${{ github.repository }}/releases/tag/${{ needs.verify.outputs.version }}"
else
echo "❌ Release completed with issues. Please check the logs above."
fi