name: Release
on:
push:
tags:
- 'v*'
env:
CARGO_TERM_COLOR: always
CARGO_TOOLCHAIN: stable
CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse
jobs:
validate:
runs-on: ubuntu-latest
timeout-minutes: 60
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@v1
with:
toolchain: ${{ env.CARGO_TOOLCHAIN }}
components: rustfmt, clippy
- name: Cache Cargo build files
uses: Swatinem/rust-cache@v2
- name: Install Protoc
uses: taiki-e/install-action@v2
with:
tool: protoc
- name: Check format
run: cargo fmt --all -- --check
- name: Run clippy
run: cargo clippy --workspace --all-targets --all-features -- -Dwarnings -A missing_docs
- name: Run clippy without default features
run: cargo clippy --workspace --all-targets --no-default-features -- -Dwarnings
- name: Run tests
run: cargo test --workspace --all-features
- name: Validate public examples
run: bash scripts/check-public-examples.sh
- name: Run cargo doc
run: cargo doc --workspace --no-deps --all-features --lib
env:
RUSTDOCFLAGS: "-D warnings"
github-release:
needs: validate
runs-on: ubuntu-latest
timeout-minutes: 30
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- name: Extract version from tag
id: extract_version
run: |
VERSION=${GITHUB_REF#refs/tags/v}
echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT
echo "Extracted version: ${VERSION}"
- name: Generate typed coverage summary
run: python3 tools/validate_apis.py --all-crates
- name: Enforce typed coverage release gate
run: python3 tools/check_typed_coverage_release.py
- name: Validate typed API endpoint contracts
run: python3 tools/validate_api_contracts.py --all-crates --strict endpoint
- name: Generate crate quality status summary
run: python3 tools/release_quality_status.py --output release_quality_status.md
- name: Detect prerelease flag
id: release_kind
run: |
VERSION="${{ steps.extract_version.outputs.VERSION }}"
if [[ "${VERSION}" == *-* ]]; then
echo "PRERELEASE=true" >> $GITHUB_OUTPUT
echo "Detected prerelease tag: ${VERSION}"
else
echo "PRERELEASE=false" >> $GITHUB_OUTPUT
echo "Detected stable tag: ${VERSION}"
fi
- name: Extract changelog entry
id: changelog
run: |
# 提取当前版本的 changelog 内容
awk '/^## \['"${{ steps.extract_version.outputs.VERSION }}"'\]/{flag=1; next} /^## \[/{flag=0} flag' CHANGELOG.md > release_notes.md
# 如果没有找到内容,使用默认说明
if [ ! -s release_notes.md ]; then
echo "Release version ${{ steps.extract_version.outputs.VERSION }}" > release_notes.md
echo "" >> release_notes.md
echo "See [CHANGELOG.md](CHANGELOG.md) for details." >> release_notes.md
fi
if [ -s release_quality_status.md ]; then
echo "" >> release_notes.md
cat release_quality_status.md >> release_notes.md
fi
echo "Release notes content:"
cat release_notes.md
- name: Create GitHub Release
uses: softprops/action-gh-release@v2
with:
name: Release v${{ steps.extract_version.outputs.VERSION }}
body_path: release_notes.md
draft: false
prerelease: ${{ steps.release_kind.outputs.PRERELEASE }}
token: ${{ secrets.GITHUB_TOKEN }}
crates-io-release:
needs: [validate, github-release]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@v1
with:
toolchain: ${{ env.CARGO_TOOLCHAIN }}
- name: Cache Cargo build files
uses: Swatinem/rust-cache@v2
- name: Install Protoc
uses: taiki-e/install-action@v2
with:
tool: protoc
- name: Extract version from tag
id: extract_version
run: |
VERSION=${GITHUB_REF#refs/tags/v}
echo "VERSION=${VERSION}" >> $GITHUB_OUTPUT
- name: Verify Cargo.toml version matches tag
run: |
set -euo pipefail
# workspace 使用 `version.workspace = true`,这里用 `cargo metadata` 获取实际发布包(openlark)版本
CARGO_VERSION=$(
cargo metadata --no-deps --format-version 1 \
| python3 -c 'import json,sys; d=json.load(sys.stdin); print(next((p["version"] for p in d.get("packages", []) if p.get("name")=="openlark"), ""))'
)
TAG_VERSION="${{ steps.extract_version.outputs.VERSION }}"
if [ -z "${CARGO_VERSION}" ]; then
echo "❌ Failed to detect openlark version from cargo metadata"
exit 1
fi
echo "Cargo (openlark) version: ${CARGO_VERSION}"
echo "Tag version: ${TAG_VERSION}"
if [ "${CARGO_VERSION}" != "${TAG_VERSION}" ]; then
echo "❌ Version mismatch: openlark is ${CARGO_VERSION}, but tag is v${TAG_VERSION}"
exit 1
fi
echo "✅ Version verification passed"
- name: Verify crates.io token
run: |
if [ -z "${{ secrets.CRATES_IO_TOKEN }}" ]; then
echo "❌ CRATES_IO_TOKEN not configured in repository secrets"
echo "Please add CRATES_IO_TOKEN to repository secrets"
exit 1
fi
echo "✅ CRATES_IO_TOKEN is configured"
- name: Publish workspace crates in order
run: bash scripts/publish-workspace.sh
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}