fix: 文件名截断问题 #55
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: 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" | |
# 验证 RELEASE_ID 不为空且为数字 | |
if [ -z "$RELEASE_ID" ] || [ "$RELEASE_ID" = "null" ] || ! echo "$RELEASE_ID" | grep -q '^[0-9]\+$'; then | |
echo "❌ Invalid release ID: '$RELEASE_ID'" | |
exit 1 | |
fi | |
# 获取 assets,添加超时和重试 | |
echo "📁 Getting release assets..." | |
for attempt in 1 2 3; do | |
echo " Attempt $attempt/3..." | |
ASSETS_RESPONSE=$(curl -s --connect-timeout 30 --max-time 60 \ | |
-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 "✅ Successfully retrieved $(echo "$ASSETS_RESPONSE" | jq length) assets" | |
break | |
else | |
echo "⚠️ Attempt $attempt failed. Response: $ASSETS_RESPONSE" | |
if [ $attempt -lt 3 ]; then | |
echo " Waiting 10 seconds before retry..." | |
sleep 10 | |
fi | |
fi | |
done | |
# 最终验证assets获取是否成功 | |
if ! echo "$ASSETS_RESPONSE" | jq -e '. | length' > /dev/null 2>&1; then | |
echo "❌ Failed to get assets after 3 attempts" | |
echo "Final 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 | |
# 检查并发布 draft release | |
RELEASE_DRAFT=$(echo "$RELEASE_RESPONSE" | jq -r '.draft') | |
if [ "$RELEASE_DRAFT" = "true" ]; then | |
echo "📤 Publishing draft release..." | |
PUBLISH_RESPONSE=$(curl -s -w "%{http_code}" -o /dev/null \ | |
-X PATCH \ | |
-H "Authorization: token $GITHUB_TOKEN" \ | |
-H "Content-Type: application/json" \ | |
-d '{"draft": false}' \ | |
https://api.github.com/repos/${{ github.repository }}/releases/$RELEASE_ID) | |
if [ "$PUBLISH_RESPONSE" = "200" ]; then | |
echo "✅ Successfully published release" | |
else | |
echo "⚠️ Failed to publish release (HTTP: $PUBLISH_RESPONSE)" | |
echo " This may affect subsequent download steps" | |
fi | |
else | |
echo "✅ Release is already published" | |
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 | |
run: | | |
set -e | |
echo "🔍 Getting release info for tag: ${{ github.ref_name }}" | |
# 验证环境变量 | |
if [ -z "$GITHUB_TOKEN" ]; then | |
echo "❌ GITHUB_TOKEN not set" | |
exit 1 | |
fi | |
# 等待确保 cleanup 完成 | |
echo "⏰ Waiting 15 seconds for cleanup to complete..." | |
sleep 15 | |
# 首先尝试通过标签获取 release(与 cleanup-release 相同的方法) | |
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') | |
TAG_NAME=$(echo "$RELEASE_RESPONSE" | jq -r '.tag_name') | |
ASSETS=$(echo "$RELEASE_RESPONSE" | jq -c '.assets') | |
echo "✅ Found release: $TAG_NAME (ID: $RELEASE_ID)" | |
echo "📦 Assets count: $(echo "$ASSETS" | jq length)" | |
# 检查是否是 untagged release | |
if echo "$ASSETS" | jq -r '.[0].browser_download_url' | grep -q "untagged"; then | |
echo "⚠️ WARNING: Found untagged release URLs!" | |
echo " This may indicate a draft release or tagging issue." | |
echo " Expected tag: ${{ github.ref_name }}" | |
echo " Found in URL: $(echo "$ASSETS" | jq -r '.[0].browser_download_url' | sed 's|.*/download/||' | sed 's|/.*||')" | |
fi | |
# 输出到 GitHub Actions outputs | |
echo "release_id=$RELEASE_ID" >> $GITHUB_OUTPUT | |
echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT | |
echo "assets<<EOF" >> $GITHUB_OUTPUT | |
echo "$ASSETS" >> $GITHUB_OUTPUT | |
echo "EOF" >> $GITHUB_OUTPUT | |
echo "✅ Release info prepared for COS upload" | |
env: | |
GITHUB_TOKEN: ${{ secrets.atriordsa }} | |
- 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 [ -z "$name" ] || [ "$name" = "null" ]; then | |
echo "❌ Invalid file name: '$name'" | |
continue | |
fi | |
# 下载文件,使用认证 | |
if curl -L -H "Authorization: token ${{ secrets.atriordsa }}" \ | |
-H "Accept: application/octet-stream" \ | |
--fail --show-error --silent \ | |
-o "$name" "$url"; then | |
# 验证下载的文件大小 | |
if [ -s "$name" ]; then | |
echo "✅ Downloaded: $name ($(du -h "$name" | cut -f1))" | |
else | |
echo "⚠️ Downloaded but file is empty: $name" | |
rm -f "$name" | |
fi | |
else | |
echo "❌ Failed to download: $name" | |
# 清理可能的空文件 | |
rm -f "$name" | |
fi | |
done | |
echo "📂 Downloaded files:" | |
ls -la | |
# 验证下载的文件 | |
echo "🔍 Verifying downloaded files..." | |
for file in *; do | |
if [ -f "$file" ] && [ "$file" != "assets.json" ]; then | |
echo "✅ $file: $(du -h "$file" | cut -f1) - $(file "$file" | cut -d: -f2-)" | |
fi | |
done | |
# 检查是否有文件名问题 | |
if ls -1 | grep -q "^[^S].*AppImage$\|^[^S].*\.deb$\|^[^S].*\.dmg$\|^[^S].*\.exe$"; then | |
echo "⚠️ WARNING: Found files with potentially truncated names:" | |
ls -1 | grep "^[^S].*AppImage$\|^[^S].*\.deb$\|^[^S].*\.dmg$\|^[^S].*\.exe$" || true | |
fi | |
- name: Pre-upload file verification | |
run: | | |
echo "🔍 Final file verification before COS upload..." | |
cd ./downloads | |
# 移除 assets.json 文件以避免上传 | |
rm -f assets.json | |
echo "Files to be uploaded:" | |
ls -la | |
echo "" | |
echo "File count: $(ls -1 | wc -l)" | |
echo "" | |
echo "Detailed file analysis:" | |
for file in *; do | |
if [ -f "$file" ]; then | |
echo "📄 $file:" | |
echo " Size: $(du -h "$file" | cut -f1)" | |
echo " Type: $(file "$file" | cut -d: -f2-)" | |
echo " Permissions: $(ls -l "$file" | cut -d' ' -f1)" | |
# 检查文件名是否包含特殊字符 | |
if echo "$file" | grep -q '[^a-zA-Z0-9._-]'; then | |
echo " ⚠️ Contains special characters" | |
fi | |
fi | |
done | |
# 修复可能被截断的文件名 | |
echo "" | |
echo "🔧 CRITICAL: Checking and fixing truncated filenames..." | |
fixed_count=0 | |
# 显示修复前的状态 | |
echo "Files before fixing:" | |
ls -1 | |
echo "" | |
for file in *; do | |
if [ -f "$file" ]; then | |
# 检查是否是被截断的文件名(缺少开头的S) | |
if echo "$file" | grep -q "^DUTOJCompetitionSideClient"; then | |
new_name="S$file" | |
echo "🔧 CRITICAL FIX: $file -> $new_name" | |
mv "$file" "$new_name" | |
fixed_count=$((fixed_count + 1)) | |
fi | |
fi | |
done | |
# 修复拼写错误(protable -> portable) | |
echo "" | |
echo "🔧 Checking for spelling errors..." | |
for file in *; do | |
if [ -f "$file" ]; then | |
if echo "$file" | grep -q "_protable_"; then | |
new_name=$(echo "$file" | sed 's/_protable_/_portable_/') | |
echo "🔧 Fixing spelling: $file -> $new_name" | |
mv "$file" "$new_name" | |
fixed_count=$((fixed_count + 1)) | |
fi | |
fi | |
done | |
if [ $fixed_count -gt 0 ]; then | |
echo "✅ Fixed $fixed_count filename(s)" | |
echo "" | |
echo "Files after fixing:" | |
ls -la | |
else | |
echo "✅ No filename issues found" | |
fi | |
- name: Prepare COS upload directory | |
run: | | |
echo "📁 Creating clean upload directory..." | |
mkdir -p ./cos-upload | |
cd ./downloads | |
echo "📋 Copying files to upload directory..." | |
for file in *; do | |
if [ -f "$file" ]; then | |
echo "📄 Copying: $file" | |
cp "$file" "../cos-upload/$file" | |
fi | |
done | |
cd ../cos-upload | |
echo "" | |
echo "🔧 CRITICAL: Comprehensive filename fixes in cos-upload directory..." | |
# 第一轮:修复截断的文件名(添加缺失的S) | |
echo "🔧 Round 1: Fixing truncated filenames (adding missing 'S')..." | |
fixed_count=0 | |
for file in *; do | |
if [ -f "$file" ]; then | |
if echo "$file" | grep -q "^DUTOJCompetitionSideClient"; then | |
new_name="S$file" | |
echo " 🔧 FIXING: $file -> $new_name" | |
mv "$file" "$new_name" | |
fixed_count=$((fixed_count + 1)) | |
fi | |
fi | |
done | |
# 第二轮:修复拼写错误(protable -> portable) | |
echo "🔧 Round 2: Fixing spelling errors..." | |
for file in *; do | |
if [ -f "$file" ]; then | |
if echo "$file" | grep -q "_protable_"; then | |
new_name=$(echo "$file" | sed 's/_protable_/_portable_/') | |
echo " 🔧 FIXING: $file -> $new_name" | |
mv "$file" "$new_name" | |
fixed_count=$((fixed_count + 1)) | |
fi | |
fi | |
done | |
# 第三轮:验证所有文件都有正确的前缀 | |
echo "🔧 Round 3: Final verification..." | |
problem_files=0 | |
for file in *; do | |
if [ -f "$file" ]; then | |
if ! echo "$file" | grep -q "^SDUTOJCompetitionSideClient_"; then | |
echo " ❌ PROBLEMATIC FILE: $file (doesn't start with SDUTOJCompetitionSideClient_)" | |
problem_files=$((problem_files + 1)) | |
else | |
echo " ✅ GOOD: $file" | |
fi | |
fi | |
done | |
echo "" | |
echo "📊 Fix summary:" | |
echo " Files fixed: $fixed_count" | |
echo " Problem files remaining: $problem_files" | |
if [ $problem_files -gt 0 ]; then | |
echo "❌ Still have problematic files - this may cause COS upload to fail" | |
echo "📋 All files after fixes:" | |
ls -la | |
# Don't exit, let it try to upload anyway | |
fi | |
echo "" | |
echo "✅ Files ready for COS upload:" | |
ls -la | |
echo "" | |
echo "📊 Upload summary:" | |
echo " Total files: $(ls -1 | wc -l)" | |
echo " Total size: $(du -sh . | cut -f1)" | |
- name: Final COS upload verification | |
run: | | |
echo "🔍 Final verification before COS upload..." | |
cd ./cos-upload | |
echo "📂 Files in cos-upload directory:" | |
ls -la | |
echo "" | |
echo "🔍 Analyzing actual file patterns..." | |
# 动态获取版本号(从任意文件名中提取) | |
VERSION=$(ls -1 | head -1 | grep -o '_[0-9]\+\.[0-9]\+\.[0-9]\+\.' | sed 's/_//g' | sed 's/\.$//g' || echo "unknown") | |
echo "📋 Detected version: $VERSION" | |
if [ "$VERSION" = "unknown" ]; then | |
echo "⚠️ Could not detect version from filenames" | |
VERSION="1.2.14" # 使用默认版本 | |
fi | |
found_count=0 | |
total_files=$(ls -1 | wc -l) | |
echo "" | |
echo "📋 File analysis:" | |
for file in *; do | |
if [ -f "$file" ]; then | |
echo "✅ Found: $file ($(du -h "$file" | cut -f1))" | |
found_count=$((found_count + 1)) | |
# 检查文件名格式 | |
if echo "$file" | grep -q "^SDUTOJCompetitionSideClient_"; then | |
echo " ✅ Correct filename prefix" | |
else | |
echo " ⚠️ Incorrect filename prefix" | |
fi | |
# 检查是否包含版本号 | |
if echo "$file" | grep -q "_${VERSION}\."; then | |
echo " ✅ Contains correct version: $VERSION" | |
else | |
echo " ⚠️ Version mismatch or missing in filename" | |
fi | |
fi | |
done | |
echo "" | |
echo "📊 Verification summary:" | |
echo " Version detected: $VERSION" | |
echo " Total files found: $found_count" | |
echo " Total files expected: ~12 (may vary based on build targets)" | |
# 检查关键文件类型是否存在 | |
echo "" | |
echo "🔍 Checking for key file types:" | |
windows_count=$(ls -1 | grep "_windows_" | wc -l) | |
macos_count=$(ls -1 | grep "_mac_" | wc -l) | |
linux_count=$(ls -1 | grep "_linux_" | wc -l) | |
echo " Windows files: $windows_count" | |
echo " macOS files: $macos_count" | |
echo " Linux files: $linux_count" | |
if [ $windows_count -gt 0 ] && [ $macos_count -gt 0 ] && [ $linux_count -gt 0 ]; then | |
echo "✅ All platforms represented - verification passed" | |
elif [ $found_count -gt 0 ]; then | |
echo "⚠️ Some platforms missing, but files exist - proceeding with upload" | |
else | |
echo "❌ No files found - this will cause COS upload to fail" | |
exit 1 | |
fi | |
- name: Emergency filename fix for COS action | |
run: | | |
echo "🚨 EMERGENCY: Final filename verification and fix before COS upload..." | |
cd ./cos-upload | |
echo "📋 Current files in cos-upload:" | |
ls -la | |
# 强制修复所有截断的文件名 | |
echo "" | |
echo "🔧 EMERGENCY FIX: Scanning for ANY truncated filenames..." | |
# 使用更强力的方法检查和修复 | |
emergency_fixes=0 | |
for file in *; do | |
if [ -f "$file" ]; then | |
echo "� Checking: $file" | |
# 检查文件是否以正确的前缀开始 | |
if echo "$file" | grep -q "^SDUTOJCompetitionSideClient_"; then | |
echo " ✅ $file - Correct prefix" | |
elif echo "$file" | grep -q "^DUTOJCompetitionSideClient"; then | |
new_name="S$file" | |
echo " � EMERGENCY FIX: $file -> $new_name" | |
mv "$file" "$new_name" | |
emergency_fixes=$((emergency_fixes + 1)) | |
else | |
echo " ⚠️ $file - Unexpected filename pattern" | |
fi | |
fi | |
done | |
# 再次扫描所有文件,确保没有遗漏 | |
echo "" | |
echo "� FINAL SCAN: Verifying all files have correct naming..." | |
all_correct=true | |
for file in *; do | |
if [ -f "$file" ]; then | |
if echo "$file" | grep -q "^SDUTOJCompetitionSideClient_"; then | |
echo "✅ VERIFIED: $file" | |
else | |
echo "❌ STILL WRONG: $file" | |
all_correct=false | |
fi | |
fi | |
done | |
echo "" | |
echo "� Emergency fix summary:" | |
echo " Emergency fixes applied: $emergency_fixes" | |
echo " All files correct: $all_correct" | |
if [ "$all_correct" = "false" ]; then | |
echo "" | |
echo "❌ CRITICAL: Some files still have incorrect names!" | |
echo "This WILL cause COS upload to fail!" | |
echo "" | |
echo "📋 Current file list:" | |
ls -la | |
# 显示具体哪些文件有问题 | |
echo "" | |
echo "🔍 Problem analysis:" | |
for file in *; do | |
if [ -f "$file" ]; then | |
if ! echo "$file" | grep -q "^SDUTOJCompetitionSideClient_"; then | |
echo "❌ PROBLEM: $file" | |
else | |
echo "✅ OK: $file" | |
fi | |
fi | |
done | |
echo "" | |
echo "⚠️ Proceeding anyway, but expect ENOENT errors..." | |
else | |
echo "✅ All files have correct naming - should upload successfully" | |
fi | |
echo "" | |
echo "🎯 Final upload manifest:" | |
echo " Total files: $(ls -1 | wc -l)" | |
echo " Total size: $(du -sh . | cut -f1)" | |
for file in *; do | |
if [ -f "$file" ]; then | |
echo " 📄 $file ($(du -h "$file" | cut -f1))" | |
fi | |
done | |
- name: Pre-COS-action diagnostic | |
run: | | |
echo "🔬 DIAGNOSTIC: Pre-COS-action file verification..." | |
cd ./cos-upload | |
echo "📋 Exact file list that COS action will see:" | |
ls -1 | |
echo "" | |
echo "🔍 Testing each file accessibility:" | |
for file in *; do | |
if [ -f "$file" ]; then | |
if [ -r "$file" ]; then | |
echo "✅ READABLE: $file ($(stat -c%s "$file") bytes)" | |
else | |
echo "❌ NOT READABLE: $file" | |
fi | |
else | |
echo "❌ NOT A FILE: $file" | |
fi | |
done | |
echo "" | |
echo "📊 Directory structure for COS action:" | |
echo "Current directory: $(pwd)" | |
echo "Directory permissions: $(ls -ld . | cut -d' ' -f1)" | |
echo "Files count: $(ls -1 | wc -l)" | |
echo "" | |
# 创建一个文件清单,供调试使用 | |
echo "Creating file manifest for debugging..." | |
ls -la > file_manifest.txt | |
echo "File manifest created:" | |
cat file_manifest.txt | |
- 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: ./cos-upload | |
remote_path: /releases/${{ steps.release.outputs.tag_name }} | |
clean: false | |
- name: Verify COS upload success | |
run: | | |
echo "🔍 Analyzing COS upload results..." | |
echo "📁 Upload target: /releases/${{ steps.release.outputs.tag_name }}" | |
echo "📂 Source directory: ./cos-upload" | |
# 检查源目录状态 | |
if [ -d "./cos-upload" ]; then | |
echo "✅ cos-upload directory exists" | |
cd ./cos-upload | |
echo "" | |
echo "📋 Files that should have been uploaded:" | |
for file in *; do | |
if [ -f "$file" ]; then | |
echo " ✅ $file ($(du -h "$file" | cut -f1))" | |
fi | |
done | |
echo "" | |
echo "📊 Upload summary:" | |
echo " Total files processed: $(ls -1 | wc -l)" | |
echo " Total size processed: $(du -sh . | cut -f1)" | |
# 检查是否有文件清单 | |
if [ -f "file_manifest.txt" ]; then | |
echo "" | |
echo "📄 File manifest from pre-upload:" | |
cat file_manifest.txt | |
fi | |
else | |
echo "❌ cos-upload directory not found" | |
fi | |
echo "" | |
echo "🎉 COS upload process completed!" | |
echo " If no errors appeared above, all files should be uploaded successfully." | |
- 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 uploadDir = './cos-upload'; | |
const files = []; | |
if (fs.existsSync(uploadDir)) { | |
const fileList = fs.readdirSync(uploadDir); | |
for (const fileName of fileList) { | |
const filePath = path.join(uploadDir, 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(uploadDir, '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: ./cos-upload/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" |