Skip to content

fix: 修复 workflow 文件语法错误 #41

fix: 修复 workflow 文件语法错误

fix: 修复 workflow 文件语法错误 #41

name: Build and Publish Release
on:
push:
tags:
- 'v*'
permissions:
contents: write
jobs:
publish-linux:
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Debug environment
run: |
echo "GitHub ref: ${{ github.ref }}"
echo "Tag name: ${{ github.ref_name }}"
echo "Repository: ${{ github.repository }}"
echo "Is tag push: ${{ startsWith(github.ref, 'refs/tags/') }}"
echo "GITHUB_TOKEN exists: ${{ secrets.GITHUB_TOKEN != '' }}"
node --version
npm --version
- name: Publish Linux (AppImage and deb)
run: npm run publish:linux
env:
GH_TOKEN: ${{ secrets.atriordsa }}
DEBUG: electron-builder
publish-windows:
runs-on: windows-latest
timeout-minutes: 30
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Debug environment
run: |
echo "GitHub ref: ${{ github.ref }}"
echo "Tag name: ${{ github.ref_name }}"
echo "Repository: ${{ github.repository }}"
echo "Is tag push: ${{ startsWith(github.ref, 'refs/tags/') }}"
echo "GITHUB_TOKEN exists: ${{ secrets.GITHUB_TOKEN != '' }}"
node --version
npm --version
- name: Publish Windows
run: npm run publish:win
env:
GH_TOKEN: ${{ secrets.atriordsa }}
DEBUG: electron-builder
publish-macos:
runs-on: macos-latest
timeout-minutes: 30
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Debug environment
run: |
echo "GitHub ref: ${{ github.ref }}"
echo "Tag name: ${{ github.ref_name }}"
echo "Repository: ${{ github.repository }}"
echo "Is tag push: ${{ startsWith(github.ref, 'refs/tags/') }}"
echo "GITHUB_TOKEN exists: ${{ secrets.GITHUB_TOKEN != '' }}"
node --version
npm --version
- name: Publish macOS
run: npm run publish:mac
env:
GH_TOKEN: ${{ secrets.atriordsa }}
DEBUG: electron-builder
cleanup-release:
runs-on: ubuntu-latest
needs: [publish-linux, publish-windows, publish-macos]
if: always() && (needs.publish-linux.result == 'success' || needs.publish-windows.result == 'success' || needs.publish-macos.result == 'success')
permissions:
contents: write
actions: read
steps:
- name: Debug GitHub token and permissions
run: |
echo "🔍 Debugging GitHub environment..."
echo "Repository: ${{ github.repository }}"
echo "Actor: ${{ github.actor }}"
echo "Token exists: ${{ secrets.atriordsa != '' }}"
echo "Token length: ${#GITHUB_TOKEN}"
# 尝试不同的 API 调用
echo "🧪 Testing different API endpoints..."
# 测试基本用户信息
echo "Testing /user endpoint:"
curl -s -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/user | jq -r '.login // "Failed"' || echo "curl failed"
# 测试仓库信息
echo "Testing repository endpoint:"
curl -s -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/repos/${{ github.repository }} | jq -r '.name // "Failed"' || echo "curl failed"
env:
GITHUB_TOKEN: ${{ secrets.atriordsa }}
- name: Clean unwanted files from release
run: |
set -e # 启用错误时退出
echo "🧹 Starting release cleanup for tag: ${{ github.ref_name }}"
# 直接使用 curl 而不是 gh CLI,因为 gh CLI 可能有权限问题
echo "🔗 Testing GitHub API with curl..."
# 验证环境变量
if [ -z "$GITHUB_TOKEN" ]; then
echo "❌ GITHUB_TOKEN not set"
exit 1
fi
# 测试 API 连接
USER_RESPONSE=$(curl -s -H "Authorization: token $GITHUB_TOKEN" https://api.github.com/user)
if ! echo "$USER_RESPONSE" | jq -e '.login' > /dev/null 2>&1; then
echo "❌ Cannot authenticate with GitHub API"
echo "Response: $USER_RESPONSE"
exit 1
fi
echo "✅ GitHub API authentication successful"
# 等待确保所有上传完成
echo "⏰ Waiting 30 seconds for uploads to complete..."
sleep 30
echo "📡 Getting release for tag: ${{ github.ref_name }}"
# 首先尝试通过标签获取 release,如果失败则从所有 releases 中查找
RELEASE_RESPONSE=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
https://api.github.com/repos/${{ github.repository }}/releases/tags/${{ github.ref_name }})
# 如果直接通过标签获取失败,则从所有 releases 中查找
if ! echo "$RELEASE_RESPONSE" | jq -e '.id' > /dev/null 2>&1; then
echo "⚠️ Direct tag lookup failed, searching in all releases..."
echo "Direct response: $RELEASE_RESPONSE"
ALL_RELEASES=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
https://api.github.com/repos/${{ github.repository }}/releases)
RELEASE_RESPONSE=$(echo "$ALL_RELEASES" | jq ".[] | select(.tag_name == \"${{ github.ref_name }}\")")
if ! echo "$RELEASE_RESPONSE" | jq -e '.id' > /dev/null 2>&1; then
echo "❌ Could not find release for tag ${{ github.ref_name }}"
echo "Available releases:"
echo "$ALL_RELEASES" | jq -r '.[] | "- \(.tag_name) (ID: \(.id))"' | head -10
exit 1
fi
fi
RELEASE_ID=$(echo "$RELEASE_RESPONSE" | jq -r '.id')
echo "✅ Found release ID: $RELEASE_ID"
# 获取 assets
echo "📁 Getting release assets..."
ASSETS_RESPONSE=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
https://api.github.com/repos/${{ github.repository }}/releases/$RELEASE_ID/assets)
if ! echo "$ASSETS_RESPONSE" | jq -e '. | length' > /dev/null 2>&1; then
echo "❌ Failed to get assets"
echo "Response: $ASSETS_RESPONSE"
exit 1
fi
echo "📁 Current release assets:"
echo "$ASSETS_RESPONSE" | jq -r '.[] | "- \(.name) (ID: \(.id))"'
# 查找并删除不需要的文件
echo "🔍 Looking for unwanted assets..."
# 删除 .yml, .yaml, .blockmap 文件
echo "Finding .yml, .yaml, .blockmap files..."
YML_ASSETS=$(echo "$ASSETS_RESPONSE" | jq -r 'if type == "array" then .[] | select(.name | test("\\.(yml|yaml|blockmap)$")) | .id else empty end' 2>/dev/null || echo "")
# 删除不带架构标识的 Windows 文件
echo "Finding Windows files without architecture identifiers..."
WINDOWS_NO_ARCH_ASSETS=$(echo "$ASSETS_RESPONSE" | jq -r 'if type == "array" then .[] | select(.name | test("windows.*\\.(exe)$") and (.name | test("_(x64|arm64)_") | not)) | .id else empty end' 2>/dev/null || echo "")
# 合并所有要删除的 assets,过滤空行
ALL_UNWANTED_ASSETS=""
if [ -n "$YML_ASSETS" ]; then
ALL_UNWANTED_ASSETS="$YML_ASSETS"
fi
if [ -n "$WINDOWS_NO_ARCH_ASSETS" ]; then
if [ -n "$ALL_UNWANTED_ASSETS" ]; then
ALL_UNWANTED_ASSETS="$ALL_UNWANTED_ASSETS\n$WINDOWS_NO_ARCH_ASSETS"
else
ALL_UNWANTED_ASSETS="$WINDOWS_NO_ARCH_ASSETS"
fi
fi
if [ -n "$ALL_UNWANTED_ASSETS" ]; then
echo "🎯 Found unwanted assets to delete:"
# 显示要删除的文件列表
echo "$ASSETS_RESPONSE" | jq -r 'if type == "array" then .[] | select((.name | test("\\.(yml|yaml|blockmap)$")) or (.name | test("windows.*\\.(exe)$") and (.name | test("_(x64|arm64)_") | not))) | "- \(.name) (ID: \(.id))" else empty end' 2>/dev/null || echo "Error displaying file list"
echo -e "$ALL_UNWANTED_ASSETS" | while read -r asset_id; do
if [ -n "$asset_id" ] && [ "$asset_id" != "null" ] && [ "$asset_id" != "" ]; then
ASSET_NAME=$(echo "$ASSETS_RESPONSE" | jq -r "if type == \"array\" then .[] | select(.id == $asset_id) | .name else \"unknown\" end" 2>/dev/null)
echo "🗑️ Deleting: $ASSET_NAME (ID: $asset_id)"
DELETE_RESPONSE=$(curl -s -w "%{http_code}" -o /dev/null \
-X DELETE \
-H "Authorization: token $GITHUB_TOKEN" \
https://api.github.com/repos/${{ github.repository }}/releases/assets/$asset_id)
if [ "$DELETE_RESPONSE" = "204" ]; then
echo "✅ Successfully deleted: $ASSET_NAME"
else
echo "❌ Failed to delete: $ASSET_NAME (HTTP: $DELETE_RESPONSE)"
fi
fi
done
else
echo "🎉 No unwanted files found!"
fi
echo "🏁 Cleanup completed successfully!"
env:
GITHUB_TOKEN: ${{ secrets.atriordsa }}
upload-to-cos:
runs-on: ubuntu-latest
needs: [cleanup-release]
if: always() && needs.cleanup-release.result == 'success'
steps:
- name: Get release info
id: release
uses: actions/github-script@v7
with:
github-token: ${{ secrets.atriordsa }}
script: |
const tag = context.ref.replace('refs/tags/', '');
console.log(`� Looking for release with tag: ${tag}`);
// 等待 release 被创建的重试机制
let release = null;
const maxRetries = 3; // 减少重试次数
const retryDelay = 10000; // 减少等待时间到 10 秒
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
console.log(`🔄 Attempt ${attempt}/${maxRetries} to find release ${tag}...`);
const releaseResponse = await github.rest.repos.getReleaseByTag({
owner: context.repo.owner,
repo: context.repo.repo,
tag: tag
});
release = releaseResponse.data;
console.log(`✅ Found release: ${release.name} (ID: ${release.id})`);
console.log(` Published: ${release.published_at || 'Draft'}`);
console.log(` Assets: ${release.assets.length}`);
break;
} catch (error) {
console.log(`⚠️ Attempt ${attempt} failed: ${error.status} - ${error.message}`);
if (attempt < maxRetries) {
console.log(`⏰ Waiting ${retryDelay/1000} seconds before retry...`);
await new Promise(resolve => setTimeout(resolve, retryDelay));
}
}
}
if (!release) {
console.log(`❌ Release ${tag} not found after ${maxRetries} attempts`);
console.log(`💡 Please check if the release exists and is published`);
core.setFailed(`Release for tag ${tag} not found`);
return;
}
if (release.assets.length === 0) {
console.log(`⚠️ Release ${tag} has no assets`);
core.setFailed(`Release ${tag} has no assets to upload`);
return;
}
// 输出 release 信息和 assets 列表
core.setOutput('release_id', release.id);
core.setOutput('tag_name', release.tag_name);
core.setOutput('assets', JSON.stringify(release.assets));
console.log(`✅ Release info prepared for COS upload`);
return release;
- name: Download release assets
id: download
run: |
echo "📥 Starting download of release assets..."
# 创建下载目录
mkdir -p ./downloads
cd ./downloads
# 解析 assets JSON
echo '${{ steps.release.outputs.assets }}' > assets.json
# 使用 jq 处理每个 asset
jq -r '.[] | "\(.name)|\(.browser_download_url)"' assets.json | while IFS='|' read -r name url; do
echo "📥 Downloading: $name"
echo " URL: $url"
# 下载文件,使用认证
if curl -L -H "Authorization: token ${{ secrets.atriordsa }}" \
-H "Accept: application/octet-stream" \
--fail --show-error --silent \
-o "$name" "$url"; then
echo "✅ Downloaded: $name ($(du -h "$name" | cut -f1))"
else
echo "❌ Failed to download: $name"
fi
done
echo "� Downloaded files:"
ls -la
- name: Configure Tencent Cloud COS
uses: TencentCloud/cos-action@v1
with:
secret_id: ${{ secrets.COS_SECRET_ID }}
secret_key: ${{ secrets.COS_SECRET_KEY }}
cos_bucket: ${{ secrets.COS_BUCKET }}
cos_region: ${{ secrets.COS_REGION }}
local_path: ./downloads
remote_path: /releases/${{ steps.release.outputs.tag_name }}
clean: false
skip_src_check: true
- name: Create release index
uses: actions/github-script@v7
with:
github-token: ${{ secrets.atriordsa }}
script: |
const fs = require('fs');
const path = require('path');
const tagName = '${{ steps.release.outputs.tag_name }}';
const cdnUrl = '${{ secrets.CDN_URL }}';
const versionPath = `releases/${tagName}`;
console.log('📋 Creating release index...');
// 读取下载的文件信息
const downloadDir = './downloads';
const files = [];
if (fs.existsSync(downloadDir)) {
const fileList = fs.readdirSync(downloadDir);
for (const fileName of fileList) {
if (fileName !== 'assets.json') {
const filePath = path.join(downloadDir, fileName);
const stats = fs.statSync(filePath);
const safeKey = `${versionPath}/${fileName}`.replace(/ /g, '_');
const cdnFileUrl = `${cdnUrl.replace(/\/$/, '')}/${safeKey}`;
files.push({
name: fileName,
cos_key: safeKey,
cdn_url: cdnFileUrl,
size: stats.size
});
console.log(`📄 ${fileName} -> ${cdnFileUrl}`);
}
}
}
// 创建索引数据
const indexData = {
version: tagName,
upload_time: Math.floor(Date.now() / 1000),
files: files,
total_files: files.length,
repository: context.repo.owner + '/' + context.repo.repo
};
// 保存索引文件
const indexFile = path.join(downloadDir, 'index.json');
fs.writeFileSync(indexFile, JSON.stringify(indexData, null, 2));
console.log(`✅ Created index with ${files.length} files`);
console.log(`📁 Version directory: ${cdnUrl.replace(/\/$/, '')}/${versionPath}/`);
- name: Upload index to COS
uses: TencentCloud/cos-action@v1
with:
secret_id: ${{ secrets.COS_SECRET_ID }}
secret_key: ${{ secrets.COS_SECRET_KEY }}
cos_bucket: ${{ secrets.COS_BUCKET }}
cos_region: ${{ secrets.COS_REGION }}
local_path: ./downloads/index.json
remote_path: /releases/${{ steps.release.outputs.tag_name }}/index.json
clean: false
- name: Display upload summary
run: |
echo "🎉 COS upload completed successfully!"
echo "📁 Version: ${{ steps.release.outputs.tag_name }}"
echo "🌐 CDN Base URL: ${{ secrets.CDN_URL }}"
echo "📂 Release Directory: ${{ secrets.CDN_URL }}/releases/${{ steps.release.outputs.tag_name }}/"
echo "📋 Index File: ${{ secrets.CDN_URL }}/releases/${{ steps.release.outputs.tag_name }}/index.json"