Skip to content

[CI] 添加自动 Pre-release 工作流 #166

@wjllance

Description

@wjllance

背景

当前发布 Pre-release 版本需要手动创建 GitHub Release,流程繁琐。建议实现推送 tag 时自动发布 Pre-release。

修改内容

1. 触发条件更新

on.push 下添加 tag 触发:

on:
  push:
    branches: [main, develop]
    tags:
      - 'v*'  # 推送 v 开头的 tag 时触发自动发布

2. 新增 auto-prerelease Job

  • 触发条件: 推送 tag 且 tag 包含 -(如 -rc, -beta, -alpha
  • 功能:
    • 自动构建多平台二进制文件
    • 读取 RELEASE_NOTES_{VERSION}.md 作为 release notes
    • 自动创建 GitHub Pre-release
    • 上传构建产物和 checksums

3. Homebrew 更新优化

  • 仅稳定版触发 Homebrew 更新(tag 不包含 -
  • Pre-release 不会自动更新 Homebrew

使用方式

推送 tag 即可自动发布 Pre-release:

git tag v0.7.0-rc.2
git push origin v0.7.0-rc.2

GitHub Actions 会自动:

  1. 运行测试和构建
  2. 创建 Pre-release
  3. 上传二进制文件

完整文件内容

name: CI

on:
  push:
    branches: [main, develop]
    tags:
      - 'v*'  # 推送 v 开头的 tag 时触发自动发布
  pull_request:
    branches: [main]
  release:
    types: [published]

env:
  CARGO_TERM_COLOR: always

permissions:
  contents: write

jobs:
  # 基础检查 (Linux x86_64)
  check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install Rust
        uses: dtolnay/rust-toolchain@stable

      - name: Cache cargo
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}

      - name: Build
        run: cargo build --verbose

      - name: Run tests
        run: cargo test --verbose

      - name: Check formatting
        run: cargo fmt -- --check

      - name: Run clippy
        run: cargo clippy -- -D warnings

  # 多平台构建矩阵
  build-matrix:
    strategy:
      matrix:
        include:
          # macOS Apple Silicon (ARM64)
          - os: macos-latest
            target: aarch64-apple-darwin
            cross: false
          # Linux x86_64
          - os: ubuntu-latest
            target: x86_64-unknown-linux-gnu
            cross: false
          # Linux ARM64 (交叉编译)
          - os: ubuntu-latest
            target: aarch64-unknown-linux-gnu
            cross: true

    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@v4

      - name: Install Rust
        uses: dtolnay/rust-toolchain@stable
        with:
          targets: ${{ matrix.target }}

      - name: Install cross (for ARM64 Linux)
        if: matrix.cross
        run: cargo install cross --git https://github.com/cross-rs/cross

      - name: Cache cargo
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-${{ matrix.target }}-cargo-${{ hashFiles('**/Cargo.lock') }}

      - name: Build (native)
        if: '!matrix.cross'
        run: cargo build --release --target ${{ matrix.target }}

      - name: Build (cross)
        if: matrix.cross
        env:
          RUSTFLAGS: "-C linker=aarch64-linux-gnu-gcc"
          CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
        run: cross build --release --target ${{ matrix.target }}

      - name: Upload binary
        uses: actions/upload-artifact@v4
        with:
          name: standx-${{ matrix.target }}
          path: target/${{ matrix.target }}/release/standx

  # 发布 Release (手动创建 release 时触发)
  release:
    needs: [check, build-matrix]
    runs-on: ubuntu-latest
    if: github.event_name == 'release'
    steps:
      - uses: actions/checkout@v4

      - name: Download all binaries
        uses: actions/download-artifact@v4
        with:
          path: ./binaries

      - name: Package binaries
        run: |
          VERSION="${{ github.event.release.tag_name }}"
          mkdir -p ./packages

          for target in aarch64-apple-darwin x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu; do
            if [ -f "./binaries/standx-${target}/standx" ]; then
              chmod +x "./binaries/standx-${target}/standx"
              tar -czf "./packages/standx-${VERSION}-${target}.tar.gz" -C "./binaries/standx-${target}" standx
              echo "Packaged: standx-${VERSION}-${target}.tar.gz"
            fi
          done

      - name: Generate checksums
        run: |
          cd ./packages
          sha256sum *.tar.gz > checksums.txt
          cat checksums.txt

      - name: Upload install.sh to release
        run: |
          cp install.sh ./packages/

      - name: Upload to release
        uses: softprops/action-gh-release@v1
        with:
          files: |
            ./packages/*.tar.gz
            ./packages/checksums.txt
            ./packages/install.sh
          token: ${{ secrets.GITHUB_TOKEN }}

  # 自动发布 Pre-release (推送 tag 时触发)
  auto-prerelease:
    needs: [check, build-matrix]
    runs-on: ubuntu-latest
    if: startsWith(github.ref, 'refs/tags/v') && contains(github.ref, '-')
    steps:
      - uses: actions/checkout@v4

      - name: Download all binaries
        uses: actions/download-artifact@v4
        with:
          path: ./binaries

      - name: Package binaries
        run: |
          VERSION="${GITHUB_REF#refs/tags/}"
          mkdir -p ./packages

          for target in aarch64-apple-darwin x86_64-unknown-linux-gnu aarch64-unknown-linux-gnu; do
            if [ -f "./binaries/standx-${target}/standx" ]; then
              chmod +x "./binaries/standx-${target}/standx"
              tar -czf "./packages/standx-${VERSION}-${target}.tar.gz" -C "./binaries/standx-${target}" standx
              echo "Packaged: standx-${VERSION}-${target}.tar.gz"
            fi
          done

      - name: Generate checksums
        run: |
          cd ./packages
          sha256sum *.tar.gz > checksums.txt
          cat checksums.txt

      - name: Read release notes
        id: notes
        run: |
          VERSION="${GITHUB_REF#refs/tags/}"
          if [ -f "RELEASE_NOTES_${VERSION}.md" ]; then
            echo "body<<EOF" >> $GITHUB_OUTPUT
            cat "RELEASE_NOTES_${VERSION}.md" >> $GITHUB_OUTPUT
            echo "EOF" >> $GITHUB_OUTPUT
          fi

      - name: Create/Update Pre-release
        uses: softprops/action-gh-release@v1
        with:
          tag_name: ${{ github.ref_name }}
          name: ${{ github.ref_name }}
          body: ${{ steps.notes.outputs.body }}
          prerelease: true
          files: |
            ./packages/*.tar.gz
            ./packages/checksums.txt

  # 更新 Homebrew (稳定版发布时触发)
  update-homebrew:
    needs: release
    runs-on: ubuntu-latest
    if: github.event_name == 'release' && !contains(github.event.release.tag_name, '-')
    steps:
      - name: Checkout homebrew tap
        uses: actions/checkout@v4
        with:
          repository: wjllance/homebrew-standx-cli
          token: ${{ secrets.HOMEBREW_TAP_TOKEN || secrets.GITHUB_TOKEN }}
          path: homebrew-tap

      - name: Download source tarball
        run: |
          curl -L -o standx-cli.tar.gz "https://github.com/wjllance/standx-cli/archive/refs/tags/${{ github.event.release.tag_name }}.tar.gz"
          SHA256=$(sha256sum standx-cli.tar.gz | cut -d' ' -f1)
          echo "SHA256=$SHA256" >> $GITHUB_ENV
          echo "VERSION=${{ github.event.release.tag_name }}" >> $GITHUB_ENV

      - name: Update Homebrew formula
        run: |
          cd homebrew-tap
          sed -i "s|url \"https://github.com/wjllance/standx-cli/archive/refs/tags/v.*.tar.gz\"|url \"https://github.com/wjllance/standx-cli/archive/refs/tags/${{ env.VERSION }}.tar.gz\"|" Formula/standx-cli.rb
          sed -i "s|sha256 \"[^\"]*\"|sha256 \"${{ env.SHA256 }}\"|" Formula/standx-cli.rb

      - name: Commit and push to tap
        run: |
          cd homebrew-tap
          git config user.name "GitHub Actions"
          git config user.email "actions@github.com"
          git add Formula/standx-cli.rb
          git commit -m "Update standx-cli to ${{ env.VERSION }}"
          git push

注意: 需要 GitHub Token 有 workflow scope 才能推送 workflow 文件修改。

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions