sdforge 0.5.0-rc.2

Multi-protocol SDK framework with unified macro configuration
name: Release

on:
  push:
    tags:
      - 'v*.*.*'

permissions:
  contents: write

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: false

env:
  CARGO_TERM_COLOR: always

jobs:
  verify:
    name: Verify Release
    runs-on: ubuntu-latest
    timeout-minutes: 45
    steps:
      - uses: actions/checkout@v7
      - uses: dtolnay/rust-toolchain@1.97.1

      - name: Install protoc (for grpc feature)
        run: sudo apt-get update && sudo apt-get install -y protobuf-compiler

      - name: Verify build (full features)
        run: cargo build --release --features full --workspace

      - name: Verify tests pass
        run: cargo test --features full --workspace --no-fail-fast

  publish-crates:
    name: Publish to crates.io (conditional)
    needs: verify
    runs-on: ubuntu-latest
    timeout-minutes: 20
    steps:
      - uses: actions/checkout@v7
      - uses: dtolnay/rust-toolchain@1.97.1

      - name: Install protoc (for grpc feature)
        run: sudo apt-get update && sudo apt-get install -y protobuf-compiler

      - name: Check CARGO_REGISTRY_TOKEN
        id: check_token
        env:
          TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
        run: |
          if [ -z "$TOKEN" ]; then
            echo "has_token=false" >> $GITHUB_OUTPUT
            echo "No CARGO_REGISTRY_TOKEN secret set, skipping publish."
          else
            echo "has_token=true" >> $GITHUB_OUTPUT
          fi

      - name: Resolve version from tag
        id: ver
        run: echo "version=${GITHUB_REF_NAME#v}" >> $GITHUB_OUTPUT

      # 幂等守卫:crates.io 已存在该版本则跳过发布(本地 publish 后推 tag 的场景)
      - name: Check already published
        id: published
        run: |
          CODE=$(curl -s -o /dev/null -w "%{http_code}" https://crates.io/api/v1/crates/sdforge/${{ steps.ver.outputs.version }})
          CODE_M=$(curl -s -o /dev/null -w "%{http_code}" https://crates.io/api/v1/crates/sdforge-macros/${{ steps.ver.outputs.version }})
          echo "crates.io: sdforge=$CODE sdforge-macros=$CODE_M for ${{ steps.ver.outputs.version }}"
          echo "main_exists=$([[ "$CODE" == "200" ]] && echo true || echo false)" >> $GITHUB_OUTPUT
          echo "macros_exists=$([[ "$CODE_M" == "200" ]] && echo true || echo false)" >> $GITHUB_OUTPUT

      # macros 必须先发布,sdforge 主 crate 才能 cargo package / cargo publish
      - name: Publish sdforge-macros
        if: steps.check_token.outputs.has_token == 'true' && steps.published.outputs.macros_exists == 'false'
        run: cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }} --manifest-path macros/Cargo.toml

      - name: Wait for crates.io index update
        if: steps.check_token.outputs.has_token == 'true' && steps.published.outputs.main_exists == 'false'
        run: sleep 30

      - name: Publish sdforge
        if: steps.check_token.outputs.has_token == 'true' && steps.published.outputs.main_exists == 'false'
        run: cargo publish --token ${{ secrets.CARGO_REGISTRY_TOKEN }} --features full

  github-release:
    name: Create GitHub Release
    needs: [verify, publish-crates]
    if: ${{ !cancelled() && !failure() }}
    runs-on: ubuntu-latest
    timeout-minutes: 15
    steps:
      - uses: actions/checkout@v7

      - name: Get version from tag
        id: version
        run: |
          TAG_NAME="${GITHUB_REF#refs/tags/}"
          VERSION="${TAG_NAME#v}"
          echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT
          echo "version=$VERSION" >> $GITHUB_OUTPUT

      - name: Install protoc (for grpc feature)
        run: sudo apt-get update && sudo apt-get install -y protobuf-compiler

      # sdforge-macros 可独立打包(无外部依赖问题)
      - name: Package sdforge-macros
        run: cargo package --no-verify --manifest-path macros/Cargo.toml

      # sdforge 主 crate 需要 sdforge-macros 已发布到 crates.io 才能 cargo package
      # 若未配置 CARGO_REGISTRY_TOKEN,此步骤会失败但允许继续(macros.crate 仍上传)
      - name: Package sdforge (may fail if macros not yet on crates.io)
        continue-on-error: true
        run: cargo package --no-verify --features full

      - name: Collect crate packages
        run: |
          mkdir -p release-assets
          cp target/package/sdforge-macros-*.crate release-assets/ 2>/dev/null || true
          cp target/package/sdforge-*.crate release-assets/ 2>/dev/null || true
          ls -la release-assets/

      - name: Create Release
        uses: softprops/action-gh-release@v3
        with:
          tag_name: ${{ steps.version.outputs.tag_name }}
          name: Release ${{ steps.version.outputs.tag_name }}
          generate_release_notes: true
          files: |
            release-assets/*.crate
          draft: false
          prerelease: ${{ contains(github.ref, '-rc') || contains(github.ref, '-beta') || contains(github.ref, '-alpha') }}
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}