name: 构建发布 on: push: tags: - 'v*' # 推送 tag 时触发发布 workflow_dispatch: # 支持手动触发 inputs: publish-to-pypi: description: '发布至 PyPI (true/false)' required: false default: 'false' env: CARGO_TERM_COLOR: always jobs: # ============================================================ # 1. 发布 chanlun 核心库至 crates.io # ============================================================ publish-crates: runs-on: ubuntu-latest outputs: version: ${{ steps.version.outputs.version }} exists: ${{ steps.check.outputs.exists }} steps: - uses: actions/checkout@v4 - name: 安装 Rust 工具链 uses: dtolnay/rust-toolchain@stable with: components: rustfmt, clippy - name: 缓存依赖 uses: actions/cache@v4 with: path: | ~/.cargo/registry ~/.cargo/git target key: ${{ runner.os }}-cargo-${{ hashFiles('chanlun/Cargo.lock') }} - name: 提取版本号 id: version working-directory: chanlun run: | VER=$(cargo metadata --format-version 1 --no-deps 2>/dev/null \ | jq -r '.packages[] | select(.name == "chanlun") | .version') echo "version=$VER" >> $GITHUB_OUTPUT echo "当前版本: $VER" - name: 检查版本是否已存在 id: check run: | VER="${{ steps.version.outputs.version }}" EXISTS=$(curl -sS "https://crates.io/api/v1/crates/chanlun" \ | jq -r --arg v "$VER" '.versions[]?.num // empty | select(. == $v)') if [ -n "$EXISTS" ]; then echo "版本 $VER 已存在于 crates.io,跳过发布" echo "exists=true" >> $GITHUB_OUTPUT else echo "版本 $VER 未发布,继续" echo "exists=false" >> $GITHUB_OUTPUT fi - name: 格式检查 if: steps.check.outputs.exists == 'false' working-directory: chanlun run: cargo fmt --check - name: Lint 检查 if: steps.check.outputs.exists == 'false' working-directory: chanlun run: cargo clippy - name: 运行测试 if: steps.check.outputs.exists == 'false' working-directory: chanlun run: cargo test - name: 验证打包 if: steps.check.outputs.exists == 'false' working-directory: chanlun run: cargo publish --dry-run --allow-dirty - name: 登录 crates.io if: steps.check.outputs.exists == 'false' run: cargo login ${{ secrets.CARGO_TOKEN }} - name: 发布 chanlun 至 crates.io if: steps.check.outputs.exists == 'false' working-directory: chanlun run: cargo publish --allow-dirty # ============================================================ # 2. 构建 wheel — Linux x86_64 (manylinux) # ============================================================ linux-x86_64: needs: [publish-crates] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: 安装 Python uses: actions/setup-python@v5 with: python-version: '3.12' - name: 安装 Rust 工具链 uses: dtolnay/rust-toolchain@stable - name: 更新 cargo 索引(确保新版本可见) run: cargo update working-directory: chanlun-py - name: 构建 wheel (manylinux) uses: PyO3/maturin-action@v1 with: target: x86_64 working-directory: chanlun-py args: --release --out dist manylinux: auto - name: 上传 wheel 产物 uses: actions/upload-artifact@v4 with: name: wheels-linux-x86_64 path: chanlun-py/dist/ # ============================================================ # 3. 构建 wheel — macOS (x86_64 + arm64) # ============================================================ macos: needs: [publish-crates] runs-on: macos-latest strategy: matrix: target: [x86_64, aarch64] steps: - uses: actions/checkout@v4 - name: 安装 Rust 工具链 uses: dtolnay/rust-toolchain@stable - name: 安装 Python uses: actions/setup-python@v5 with: python-version: '3.12' - name: 更新 cargo 索引 run: cargo update working-directory: chanlun-py - name: 构建 wheel uses: PyO3/maturin-action@v1 with: target: ${{ matrix.target }} working-directory: chanlun-py args: --release --out dist - name: 上传 wheel 产物 uses: actions/upload-artifact@v4 with: name: wheels-macos-${{ matrix.target }} path: chanlun-py/dist/ # ============================================================ # 4. 构建 wheel — Windows x86_64 # ============================================================ windows: needs: [publish-crates] runs-on: windows-latest strategy: matrix: target: [x64] steps: - uses: actions/checkout@v4 - name: 安装 Rust 工具链 uses: dtolnay/rust-toolchain@stable - name: 安装 Python uses: actions/setup-python@v5 with: python-version: '3.12' - name: 更新 cargo 索引 run: cargo update working-directory: chanlun-py - name: 构建 wheel uses: PyO3/maturin-action@v1 with: target: ${{ matrix.target }} working-directory: chanlun-py args: --release --out dist - name: 上传 wheel 产物 uses: actions/upload-artifact@v4 with: name: wheels-windows-${{ matrix.target }} path: chanlun-py/dist/ # ============================================================ # 5. 源码分发包 (sdist) # ============================================================ sdist: needs: [publish-crates] runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: 安装 Python uses: actions/setup-python@v5 with: python-version: '3.12' - name: 构建 sdist uses: PyO3/maturin-action@v1 with: command: sdist working-directory: chanlun-py args: --out dist - name: 上传 sdist 产物 uses: actions/upload-artifact@v4 with: name: wheels-sdist path: chanlun-py/dist/ # ============================================================ # 6. 发布至 PyPI # ============================================================ publish: needs: [publish-crates, linux-x86_64, macos, windows, sdist] runs-on: ubuntu-latest if: startsWith(github.ref, 'refs/tags/v') || github.event.inputs.publish-to-pypi == 'true' permissions: id-token: write steps: - name: 下载所有产物 uses: actions/download-artifact@v4 with: path: dist/ pattern: wheels-* merge-multiple: true - name: 列出产物 run: ls -la dist/ - name: 发布至 PyPI uses: pypa/gh-action-pypi-publish@release/v1 with: packages-dir: dist/