Skip to content

🚀 Release main

🚀 Release main #88

Workflow file for this run

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