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: arduino/setup-protoc@v3
with:
version: 23.4
repo-token: ${{ secrets.GITHUB_TOKEN }}
- name: Check format
run: cargo fmt --all -- --check
- name: Run clippy
run: cargo clippy --workspace --all-targets --all-features
- name: Run tests
run: cargo test --lib --all-features
- name: Validate public examples
run: bash scripts/check-public-examples.sh
- name: Run cargo doc
run: cargo doc --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: 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
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: arduino/setup-protoc@v3
with:
version: 23.4
repo-token: ${{ secrets.GITHUB_TOKEN }}
- 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: |
# Layer 1: Protocol
echo "📦 Publishing openlark-protocol..."
cargo publish -p openlark-protocol || echo "⚠️ openlark-protocol may already exist"
sleep 30
# Layer 2: Core
echo "📦 Publishing openlark-core..."
cargo publish -p openlark-core || echo "⚠️ openlark-core may already exist"
sleep 30
# Layer 3: Business crates (with longer sleep to avoid rate limits)
for crate in openlark-auth openlark-security openlark-communication openlark-cardkit openlark-webhook openlark-docs openlark-hr openlark-ai openlark-application openlark-platform openlark-meeting openlark-helpdesk openlark-mail openlark-workflow openlark-analytics openlark-user; do
echo "📦 Publishing ${crate}..."
cargo publish -p "${crate}" || echo "⚠️ ${crate} may already exist or failed"
echo "⏳ Waiting 60s to avoid rate limits..."
sleep 60
done
# Layer 4: Client
echo "📦 Publishing openlark-client..."
cargo publish -p openlark-client || echo "⚠️ openlark-client may already exist"
sleep 30
# Layer 5: Root
echo "📦 Publishing openlark..."
cargo publish -p openlark || echo "⚠️ openlark may already exist"
echo "✅ Publish process completed"
env:
CARGO_REGISTRY_TOKEN: ${{ secrets.CRATES_IO_TOKEN }}