chore: 优化 release workflow - 自动同步版本号、动态生成 release notes #186
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release | |
| on: | |
| push: | |
| tags: | |
| - 'v*' | |
| paths-ignore: | |
| - 'docs/**' | |
| - '*.md' | |
| - '.github/workflows/deploy-docs.yml' | |
| - '.github/workflows/update-homebrew.yml' | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version to release (e.g., v0.1.0)' | |
| required: true | |
| default: 'v0.1.0' | |
| permissions: | |
| contents: write | |
| packages: write | |
| actions: read | |
| env: | |
| CARGO_NET_RETRY: 10 | |
| RUSTUP_MAX_RETRIES: 10 | |
| CARGO_TERM_COLOR: always | |
| jobs: | |
| build: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: macos-latest | |
| target: aarch64-apple-darwin | |
| name: macOS-arm64 | |
| - platform: macos-latest | |
| target: x86_64-apple-darwin | |
| name: macOS-x64 | |
| - platform: windows-latest | |
| target: x86_64-pc-windows-msvc | |
| name: Windows-x64 | |
| - platform: ubuntu-22.04 | |
| target: x86_64-unknown-linux-gnu | |
| name: Linux-x64 | |
| runs-on: ${{ matrix.platform }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v4 | |
| with: | |
| version: 9 | |
| - name: Install Linux dependencies | |
| if: matrix.platform == 'ubuntu-22.04' | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf libssl-dev pkg-config libasound2-dev libxdo-dev | |
| - name: Setup Rust | |
| uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - name: Setup sccache | |
| uses: mozilla-actions/[email protected] | |
| - name: Setup Rust cache | |
| uses: Swatinem/rust-cache@v2 | |
| with: | |
| workspaces: src-tauri | |
| shared-key: "rust-${{ matrix.target }}" | |
| cache-on-failure: true | |
| cache-all-crates: true | |
| save-if: ${{ github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/') }} | |
| - name: Sync version from tag to tauri.conf.json | |
| shell: bash | |
| run: | | |
| VERSION="${{ github.event.inputs.version || github.ref_name }}" | |
| VERSION="${VERSION#v}" | |
| echo "Syncing version to $VERSION" | |
| cd src-tauri | |
| node -e " | |
| const fs = require('fs'); | |
| const conf = JSON.parse(fs.readFileSync('tauri.conf.json', 'utf8')); | |
| conf.version = '$VERSION'; | |
| fs.writeFileSync('tauri.conf.json', JSON.stringify(conf, null, 2) + '\n'); | |
| " | |
| echo "tauri.conf.json version is now: $(node -e "console.log(JSON.parse(require('fs').readFileSync('tauri.conf.json','utf8')).version)")" | |
| - name: Load release notes | |
| shell: bash | |
| run: | | |
| if [ -f RELEASE_NOTES.md ]; then | |
| { | |
| echo "RELEASE_BODY<<RELEASE_BODY_EOF" | |
| cat RELEASE_NOTES.md | |
| echo "" | |
| echo "RELEASE_BODY_EOF" | |
| } >> "$GITHUB_ENV" | |
| else | |
| # fallback: 从 git log 生成简单 changelog | |
| TAG="${{ github.event.inputs.version || github.ref_name }}" | |
| PREV_TAG=$(git tag --sort=-v:refname | grep -v "^${TAG}$" | head -n 1) | |
| if [ -z "$PREV_TAG" ]; then | |
| CHANGELOG=$(git log --pretty=format:"- %s (%h)" ${TAG} 2>/dev/null || git log --pretty=format:"- %s (%h)") | |
| else | |
| CHANGELOG=$(git log --pretty=format:"- %s (%h)" ${PREV_TAG}..${TAG} 2>/dev/null || git log --pretty=format:"- %s (%h)" ${PREV_TAG}..HEAD) | |
| fi | |
| { | |
| echo "RELEASE_BODY<<RELEASE_BODY_EOF" | |
| echo "## ProxyCast ${TAG}" | |
| echo "" | |
| echo "### Changes" | |
| echo "${CHANGELOG}" | |
| echo "RELEASE_BODY_EOF" | |
| } >> "$GITHUB_ENV" | |
| fi | |
| - name: Install frontend dependencies | |
| run: pnpm install --no-frozen-lockfile | |
| # macOS 签名证书设置 | |
| - name: Import Apple Certificate | |
| if: matrix.platform == 'macos-latest' | |
| env: | |
| APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| run: | | |
| # 创建临时 keychain | |
| KEYCHAIN_PATH=$RUNNER_TEMP/app-signing.keychain-db | |
| KEYCHAIN_PASSWORD=${{ secrets.KEYCHAIN_PASSWORD }} | |
| # 解码证书 | |
| echo -n "$APPLE_CERTIFICATE" | base64 --decode > $RUNNER_TEMP/certificate.p12 | |
| # 创建 keychain | |
| security create-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | |
| security set-keychain-settings -lut 21600 $KEYCHAIN_PATH | |
| security unlock-keychain -p "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | |
| # 导入证书 | |
| security import $RUNNER_TEMP/certificate.p12 -P "$APPLE_CERTIFICATE_PASSWORD" -A -t cert -f pkcs12 -k $KEYCHAIN_PATH | |
| security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" $KEYCHAIN_PATH | |
| security list-keychain -d user -s $KEYCHAIN_PATH | |
| - name: Build Tauri app (Linux) | |
| if: matrix.platform == 'ubuntu-22.04' | |
| uses: tauri-apps/tauri-action@v0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # 禁用 LTO 加速编译(正式发布可改为 thin) | |
| CARGO_PROFILE_RELEASE_LTO: "off" | |
| # 增加并行编译单元 | |
| CARGO_PROFILE_RELEASE_CODEGEN_UNITS: 32 | |
| CARGO_INCREMENTAL: 0 | |
| SCCACHE_GHA_ENABLED: "true" | |
| RUSTC_WRAPPER: sccache | |
| OPENSSL_NO_VENDOR: "1" | |
| with: | |
| tauriScript: npx tauri | |
| tagName: ${{ github.event.inputs.version || github.ref_name }} | |
| releaseName: 'ProxyCast ${{ github.event.inputs.version || github.ref_name }}' | |
| releaseBody: ${{ env.RELEASE_BODY }} | |
| releaseDraft: false | |
| prerelease: false | |
| # 默认不启用 voice feature(包含 whisper-rs,编译很慢) | |
| args: --target ${{ matrix.target }} | |
| - name: Build Tauri app (Windows) | |
| if: matrix.platform == 'windows-latest' | |
| uses: tauri-apps/tauri-action@v0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # 禁用 LTO 加速编译(正式发布可改为 thin) | |
| CARGO_PROFILE_RELEASE_LTO: "off" | |
| # 增加并行编译单元 | |
| CARGO_PROFILE_RELEASE_CODEGEN_UNITS: 32 | |
| CARGO_INCREMENTAL: 0 | |
| SCCACHE_GHA_ENABLED: "true" | |
| RUSTC_WRAPPER: sccache | |
| with: | |
| tauriScript: npx tauri | |
| tagName: ${{ github.event.inputs.version || github.ref_name }} | |
| releaseName: 'ProxyCast ${{ github.event.inputs.version || github.ref_name }}' | |
| releaseBody: ${{ env.RELEASE_BODY }} | |
| releaseDraft: false | |
| prerelease: false | |
| # 默认不启用 voice feature(包含 whisper-rs,编译很慢) | |
| args: --target ${{ matrix.target }} | |
| - name: Build Tauri app (macOS with notarization, attempt 1) | |
| id: build_macos_primary | |
| if: matrix.platform == 'macos-latest' | |
| continue-on-error: true | |
| uses: tauri-apps/tauri-action@v0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # 禁用 LTO 加速编译(正式发布可改为 thin) | |
| CARGO_PROFILE_RELEASE_LTO: "off" | |
| # 增加并行编译单元 | |
| CARGO_PROFILE_RELEASE_CODEGEN_UNITS: 32 | |
| CARGO_INCREMENTAL: 0 | |
| SCCACHE_GHA_ENABLED: "true" | |
| RUSTC_WRAPPER: sccache | |
| # Apple 签名环境变量 | |
| APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} | |
| # Apple 公证环境变量(解决 Gatekeeper 警告) | |
| APPLE_ID: ${{ secrets.APPLE_ID }} | |
| APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} | |
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| with: | |
| tauriScript: npx tauri | |
| tagName: ${{ github.event.inputs.version || github.ref_name }} | |
| releaseName: 'ProxyCast ${{ github.event.inputs.version || github.ref_name }}' | |
| releaseBody: ${{ env.RELEASE_BODY }} | |
| releaseDraft: false | |
| prerelease: false | |
| # 默认不启用 voice feature(包含 whisper-rs,编译很慢) | |
| args: --target ${{ matrix.target }} | |
| - name: Build Tauri app (macOS with notarization, retry) | |
| id: build_macos_retry | |
| if: matrix.platform == 'macos-latest' && steps.build_macos_primary.outcome == 'failure' | |
| continue-on-error: true | |
| uses: tauri-apps/tauri-action@v0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| CARGO_PROFILE_RELEASE_LTO: "off" | |
| CARGO_PROFILE_RELEASE_CODEGEN_UNITS: 32 | |
| CARGO_INCREMENTAL: 0 | |
| SCCACHE_GHA_ENABLED: "true" | |
| RUSTC_WRAPPER: sccache | |
| APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} | |
| APPLE_ID: ${{ secrets.APPLE_ID }} | |
| APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }} | |
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| with: | |
| tauriScript: npx tauri | |
| tagName: ${{ github.event.inputs.version || github.ref_name }} | |
| releaseName: 'ProxyCast ${{ github.event.inputs.version || github.ref_name }}' | |
| releaseBody: ${{ env.RELEASE_BODY }} | |
| releaseDraft: false | |
| prerelease: false | |
| args: --target ${{ matrix.target }} | |
| - name: Build Tauri app (macOS fallback without notarization) | |
| if: matrix.platform == 'macos-latest' && steps.build_macos_primary.outcome == 'failure' && steps.build_macos_retry.outcome == 'failure' | |
| uses: tauri-apps/tauri-action@v0 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| CARGO_PROFILE_RELEASE_LTO: "off" | |
| CARGO_PROFILE_RELEASE_CODEGEN_UNITS: 32 | |
| CARGO_INCREMENTAL: 0 | |
| SCCACHE_GHA_ENABLED: "true" | |
| RUSTC_WRAPPER: sccache | |
| APPLE_CERTIFICATE: ${{ secrets.APPLE_CERTIFICATE }} | |
| APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} | |
| APPLE_SIGNING_IDENTITY: ${{ secrets.APPLE_SIGNING_IDENTITY }} | |
| with: | |
| tauriScript: npx tauri | |
| tagName: ${{ github.event.inputs.version || github.ref_name }} | |
| releaseName: 'ProxyCast ${{ github.event.inputs.version || github.ref_name }}' | |
| releaseBody: ${{ env.RELEASE_BODY }} | |
| releaseDraft: false | |
| prerelease: false | |
| args: --target ${{ matrix.target }} | |
| - name: Warn on macOS notarization fallback | |
| if: matrix.platform == 'macos-latest' && steps.build_macos_primary.outcome == 'failure' && steps.build_macos_retry.outcome == 'failure' | |
| run: | | |
| echo "::warning::macOS notarization failed twice; fallback build skipped notarization and produced a signed-only artifact." | |
| # 注意:移除了 Post-build cleanup 步骤 | |
| # 之前的清理会删除 deps/build/incremental 目录,导致缓存无法复用 | |
| # 保留这些文件可以让 rust-cache 更好地工作 | |
| - name: Show sccache stats | |
| run: sccache --show-stats | |
| # 清理 keychain | |
| - name: Cleanup Keychain | |
| if: matrix.platform == 'macos-latest' && always() | |
| run: | | |
| security delete-keychain $RUNNER_TEMP/app-signing.keychain-db || true |