🚀 Release main #88
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 | |
| run-name: 🚀 Release ${{ github.ref_name }} | |
| on: | |
| workflow_dispatch: | |
| push: | |
| branches: | |
| - main | |
| - alpha | |
| - beta | |
| permissions: | |
| contents: write | |
| pull-requests: read | |
| jobs: | |
| version-analysis: | |
| runs-on: ubuntu-latest | |
| outputs: | |
| next_version: ${{ steps.semantic.outputs.next_version }} | |
| version_type: ${{ steps.branch.outputs.version_type }} | |
| is_prerelease: ${{ steps.branch.outputs.is_prerelease }} | |
| channel: ${{ steps.branch.outputs.channel }} | |
| should_release: ${{ steps.semantic.outputs.should_release }} | |
| steps: | |
| - name: Checkout repository | |
| 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@v3 | |
| with: | |
| version: 8 | |
| - name: Install dependencies | |
| run: pnpm install | |
| - name: Detect branch type and channel | |
| id: branch | |
| shell: bash | |
| run: | | |
| # 根据分支名确定版本类型和更新渠道 | |
| if [[ "${{ github.ref_name }}" == "main" ]]; then | |
| VERSION_TYPE="stable" | |
| IS_PRERELEASE="false" | |
| CHANNEL="latest" | |
| elif [[ "${{ github.ref_name }}" == "beta" ]]; then | |
| VERSION_TYPE="beta" | |
| IS_PRERELEASE="true" | |
| CHANNEL="beta" | |
| elif [[ "${{ github.ref_name }}" == "alpha" ]]; then | |
| VERSION_TYPE="alpha" | |
| IS_PRERELEASE="true" | |
| CHANNEL="alpha" | |
| else | |
| echo "❌ Unsupported branch: ${{ github.ref_name }}" | |
| exit 1 | |
| fi | |
| echo "version_type=$VERSION_TYPE" >> $GITHUB_OUTPUT | |
| echo "is_prerelease=$IS_PRERELEASE" >> $GITHUB_OUTPUT | |
| echo "channel=$CHANNEL" >> $GITHUB_OUTPUT | |
| echo "📦 Version Type: $VERSION_TYPE" | |
| echo "🚀 Is Prerelease: $IS_PRERELEASE" | |
| echo "📺 Channel: $CHANNEL" | |
| - name: Run semantic-release for version analysis | |
| id: semantic | |
| shell: bash | |
| run: | | |
| echo "🔍 Analyzing commits to determine next version..." | |
| # 创建临时的分析配置文件 | |
| cat > .releaserc.temp.js << 'EOF' | |
| module.exports = { | |
| branches: [ | |
| 'main', | |
| { name: 'beta', prerelease: true }, | |
| { name: 'alpha', prerelease: true } | |
| ], | |
| plugins: [ | |
| '@semantic-release/commit-analyzer', | |
| '@semantic-release/release-notes-generator' | |
| ] | |
| } | |
| EOF | |
| # 使用临时配置进行版本分析,输出到临时文件 | |
| pnpm semantic-release --dry-run -c .releaserc.temp.js > semantic_output.txt 2>&1 | |
| # 显示输出内容以便调试 | |
| echo "=== Semantic Release Output ===" | |
| cat semantic_output.txt | |
| echo "=== End of Output ===" | |
| # 清理临时文件 | |
| rm -f .releaserc.temp.js | |
| # 检查是否有新版本需要发布(从文件中搜索,避免变量长度限制) | |
| if grep -q "next release version is" semantic_output.txt; then | |
| NEXT_VERSION=$(grep "next release version is" semantic_output.txt | sed 's/.*next release version is \([0-9.a-z-]*\).*/\1/' | head -1) | |
| echo "✅ Next version: $NEXT_VERSION" | |
| echo "next_version=$NEXT_VERSION" >> $GITHUB_OUTPUT | |
| echo "should_release=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "ℹ️ No new version to release" | |
| echo "should_release=false" >> $GITHUB_OUTPUT | |
| fi | |
| # 清理临时输出文件 | |
| rm -f semantic_output.txt | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| release: | |
| needs: version-analysis | |
| runs-on: ${{ matrix.os }} | |
| if: needs.version-analysis.outputs.should_release == 'true' | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # Windows builds - 支持 x64 和 ARM64 架构 | |
| - os: windows-latest | |
| platform: win | |
| target: --win | |
| # macOS builds - 支持 Intel 和 Apple Silicon 架构 | |
| - os: macos-latest | |
| platform: mac | |
| target: --mac | |
| # Linux builds - 支持 x64 和 ARM64 架构 | |
| - os: ubuntu-latest | |
| platform: linux | |
| target: --linux | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v3 | |
| with: | |
| version: 8 | |
| - name: Get pnpm store directory | |
| shell: bash | |
| run: | | |
| echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV | |
| - name: Setup pnpm cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: ${{ env.STORE_PATH }} | |
| key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pnpm-store- | |
| - name: Install dependencies | |
| run: pnpm install | |
| - name: Update package.json version | |
| shell: bash | |
| run: | | |
| echo "📋 Current package.json version: $(node -p "require('./package.json').version")" | |
| echo "🔄 Target version: ${{ needs.version-analysis.outputs.next_version }}" | |
| echo "🌿 Branch: ${{ github.ref_name }}" | |
| echo "📦 Version type: ${{ needs.version-analysis.outputs.version_type }}" | |
| echo "🚀 Is prerelease: ${{ needs.version-analysis.outputs.is_prerelease }}" | |
| echo "📺 Channel: ${{ needs.version-analysis.outputs.channel }}" | |
| # 更新 package.json 中的版本号 | |
| node -e " | |
| const fs = require('fs'); | |
| const package = JSON.parse(fs.readFileSync('package.json', 'utf8')); | |
| package.version = '${{ needs.version-analysis.outputs.next_version }}'; | |
| fs.writeFileSync('package.json', JSON.stringify(package, null, 2) + '\n'); | |
| console.log('✅ Updated package.json version to:', package.version); | |
| " | |
| echo "📋 Updated package.json version: $(node -p "require('./package.json').version")" | |
| - name: Build for ${{ matrix.platform }} | |
| shell: bash | |
| run: | | |
| echo "🏗️ Building for ${{ matrix.platform }}" | |
| echo "📦 版本号: ${{ needs.version-analysis.outputs.next_version }}" | |
| echo "📦 版本类型: ${{ needs.version-analysis.outputs.version_type }}" | |
| echo "🔄 更新渠道: ${{ needs.version-analysis.outputs.channel }}" | |
| pnpm build | |
| # 构建产物但不发布,版本号已经正确 | |
| echo "🏗️ Building artifacts with correct version number" | |
| echo "📦 Artifacts will be uploaded by final release job" | |
| pnpm exec electron-builder ${{ matrix.target }} --publish never | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| APPLE_ID: ${{ secrets.APPLE_ID }} | |
| APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} | |
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| CSC_LINK: ${{ secrets.CSC_LINK }} | |
| CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} | |
| # 根据分支设置更新渠道 | |
| ELECTRON_BUILDER_CHANNEL: ${{ needs.version-analysis.outputs.channel }} | |
| - name: List build artifacts | |
| shell: bash | |
| run: | | |
| echo "📦 Build artifacts in dist directory:" | |
| if [ -d "dist" ]; then | |
| if command -v ls >/dev/null 2>&1; then | |
| ls -la dist/ | |
| else | |
| # Windows fallback | |
| dir dist /a | |
| fi | |
| else | |
| echo "No dist directory found" | |
| fi | |
| echo "📁 Current directory contents:" | |
| if command -v ls >/dev/null 2>&1; then | |
| ls -la | |
| else | |
| # Windows fallback | |
| dir /a | |
| fi | |
| - name: Upload artifacts | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: ${{ matrix.platform }}-artifacts | |
| path: | | |
| dist/*.exe | |
| dist/*.dmg | |
| dist/*.zip | |
| dist/*.AppImage | |
| dist/*.deb | |
| dist/*.yml | |
| dist/*.yaml | |
| dist/*.blockmap | |
| retention-days: 30 | |
| if-no-files-found: warn | |
| semantic-release: | |
| needs: [version-analysis, release] | |
| runs-on: ubuntu-latest | |
| if: needs.version-analysis.outputs.should_release == 'true' | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # semantic-release 需要完整的 git 历史 | |
| - name: Setup Node.js | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: '20' | |
| - name: Setup pnpm | |
| uses: pnpm/action-setup@v3 | |
| with: | |
| version: 8 | |
| - name: Get pnpm store directory | |
| shell: bash | |
| run: | | |
| echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV | |
| - name: Setup pnpm cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: ${{ env.STORE_PATH }} | |
| key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} | |
| restore-keys: | | |
| ${{ runner.os }}-pnpm-store- | |
| - name: Install dependencies | |
| run: pnpm install | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - name: Update package.json version for release | |
| shell: bash | |
| run: | | |
| echo "🔄 Updating package.json version for semantic-release" | |
| echo "Target version: ${{ needs.version-analysis.outputs.next_version }}" | |
| # 更新 package.json 中的版本号,确保与分析阶段一致 | |
| node -e " | |
| const fs = require('fs'); | |
| const package = JSON.parse(fs.readFileSync('package.json', 'utf8')); | |
| package.version = '${{ needs.version-analysis.outputs.next_version }}'; | |
| fs.writeFileSync('package.json', JSON.stringify(package, null, 2) + '\n'); | |
| console.log('✅ Updated package.json version to:', package.version); | |
| " | |
| - name: Prepare artifacts for release | |
| run: | | |
| echo "📦 Preparing artifacts for GitHub Release" | |
| mkdir -p dist | |
| # 复制所有构建产物到 dist 目录 | |
| find artifacts -name "*.exe" -o -name "*.dmg" -o -name "*.zip" -o -name "*.AppImage" -o -name "*.deb" -o -name "*.yml" -o -name "*.yaml" -o -name "*.blockmap" | while read file; do | |
| cp "$file" dist/ | |
| echo "📁 Copied: $(basename "$file")" | |
| done | |
| ls -la dist/ | |
| - name: Run Semantic Release | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| echo "🚀 Creating GitHub Release with semantic-release" | |
| echo "📦 Version: ${{ needs.version-analysis.outputs.next_version }}" | |
| pnpm semantic-release | |
| upload-to-cos: | |
| needs: [version-analysis, release, semantic-release] | |
| runs-on: ubuntu-latest | |
| if: needs.version-analysis.outputs.should_release == 'true' && needs.semantic-release.result == 'success' | |
| strategy: | |
| matrix: | |
| retry: [1, 2, 3] | |
| max-parallel: 1 | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@v4 | |
| - name: Download all artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| path: artifacts | |
| - name: Prepare artifacts for COS upload | |
| run: | | |
| echo "📦 Preparing artifacts for COS upload" | |
| mkdir -p dist | |
| # 复制所有构建产物到 dist 目录 | |
| find artifacts -name "*.exe" -o -name "*.dmg" -o -name "*.zip" -o -name "*.AppImage" -o -name "*.deb" -o -name "*.yml" -o -name "*.yaml" -o -name "*.blockmap" | while read file; do | |
| cp "$file" dist/ | |
| echo "📁 Copied: $(basename "$file")" | |
| done | |
| ls -la dist/ | |
| - name: Install coscmd for Tencent Cloud COS | |
| run: | | |
| echo "📦 Installing coscmd for Tencent Cloud COS upload (Attempt ${{ matrix.retry }})" | |
| pip install coscmd | |
| - name: Configure coscmd | |
| env: | |
| COS_SECRET_ID: ${{ secrets.COS_SECRET_ID }} | |
| COS_SECRET_KEY: ${{ secrets.COS_SECRET_KEY }} | |
| COS_BUCKET: ${{ secrets.COS_BUCKET }} | |
| COS_REGION: ${{ secrets.COS_REGION }} | |
| run: | | |
| echo "🔧 Configuring coscmd (Attempt ${{ matrix.retry }})" | |
| coscmd config -a $COS_SECRET_ID -s $COS_SECRET_KEY -b $COS_BUCKET -r $COS_REGION | |
| - name: Upload artifacts to Tencent Cloud COS | |
| env: | |
| VERSION: ${{ needs.version-analysis.outputs.next_version }} | |
| CHANNEL: ${{ needs.version-analysis.outputs.channel }} | |
| run: | | |
| echo "☁️ Uploading artifacts to Tencent Cloud COS (Attempt ${{ matrix.retry }})" | |
| echo "📦 Version: $VERSION" | |
| echo "📺 Channel: $CHANNEL" | |
| # 创建版本目录路径 | |
| COS_PATH="releases/$CHANNEL/$VERSION" | |
| echo "📁 COS path: $COS_PATH" | |
| # 上传所有构建产物 | |
| echo "📤 Uploading build artifacts..." | |
| for file in dist/*; do | |
| if [ -f "$file" ]; then | |
| filename=$(basename "$file") | |
| echo " 📄 Uploading: $filename" | |
| coscmd upload "$file" "$COS_PATH/$filename" | |
| fi | |
| done | |
| echo "✅ All artifacts uploaded successfully" | |
| echo "🔗 Artifacts are available at: $COS_PATH" | |
| notify: | |
| needs: [version-analysis, release, semantic-release, upload-to-cos] | |
| runs-on: ubuntu-latest | |
| if: always() | |
| steps: | |
| - name: Build Status Summary | |
| run: | | |
| echo "🏗️ Build Summary" | |
| echo "===============" | |
| echo "Branch: ${{ github.ref_name }}" | |
| echo "Next Version: ${{ needs.version-analysis.outputs.next_version }}" | |
| echo "Type: ${{ needs.version-analysis.outputs.version_type }}" | |
| echo "Channel: ${{ needs.version-analysis.outputs.channel }}" | |
| echo "Prerelease: ${{ needs.version-analysis.outputs.is_prerelease }}" | |
| echo "Should Release: ${{ needs.version-analysis.outputs.should_release }}" | |
| echo "Build Status: ${{ needs.release.result }}" | |
| echo "Release Status: ${{ needs.semantic-release.result }}" | |
| echo "COS Upload Status: ${{ needs.upload-to-cos.result }}" | |
| echo "Trigger: ${{ github.event_name }}" | |
| echo "" | |
| if [ "${{ needs.version-analysis.outputs.should_release }}" == "false" ]; then | |
| echo "ℹ️ No new version to release - no commits since last release" | |
| elif [ "${{ needs.release.result }}" == "success" ]; then | |
| if [ "${{ needs.semantic-release.result }}" == "success" ]; then | |
| echo "🎉 Release ${{ needs.version-analysis.outputs.next_version }} created successfully!" | |
| echo "📍 Check: https://github.com/${{ github.repository }}/releases" | |
| echo "🔄 Version was automatically determined based on commit messages" | |
| echo "📦 Artifacts have correct version numbers in filenames" | |
| if [ "${{ needs.upload-to-cos.result }}" == "success" ]; then | |
| echo "☁️ Artifacts uploaded to Tencent Cloud COS successfully" | |
| elif [ "${{ needs.upload-to-cos.result }}" == "failure" ]; then | |
| echo "❌ COS upload failed - artifacts may not be available for auto-update" | |
| echo "💡 Check upload-to-cos job logs for details" | |
| else | |
| echo "⏳ COS upload status: ${{ needs.upload-to-cos.result }}" | |
| fi | |
| echo "" | |
| if [ "${{ needs.version-analysis.outputs.is_prerelease }}" == "true" ]; then | |
| echo "🧪 This is a prerelease version:" | |
| echo "- Alpha/Beta versions are marked as prerelease" | |
| echo "- Auto-update is enabled for prerelease users" | |
| else | |
| echo "🚀 This is a stable release" | |
| fi | |
| else | |
| echo "📦 Build completed but semantic-release failed" | |
| echo "💡 Check semantic-release logs for details" | |
| fi | |
| else | |
| echo "❌ Build failed - check logs for details" | |
| fi |