From ea819a3421da54d96b2bb91fc0f6862143f9573f Mon Sep 17 00:00:00 2001 From: YuTengjing Date: Mon, 8 Sep 2025 23:46:57 +0800 Subject: [PATCH] feat: support mac intel desktop (#9136) --- .github/scripts/pr-comment.js | 13 +- .github/workflows/auto-i18n.yml | 2 +- .github/workflows/desktop-pr-build.yml | 126 +++++++++--- .github/workflows/docker-database.yml | 5 +- .github/workflows/release-desktop-beta.yml | 127 ++++++++++--- .github/workflows/release.yml | 5 +- .github/workflows/test.yml | 21 +- apps/desktop/electron-builder.js | 12 +- .../electronWorkflow/mergeMacReleaseFiles.js | 179 ++++++++++++++++++ 9 files changed, 420 insertions(+), 70 deletions(-) create mode 100644 scripts/electronWorkflow/mergeMacReleaseFiles.js diff --git a/.github/scripts/pr-comment.js b/.github/scripts/pr-comment.js index bb0c1a77d1..0775d7070d 100644 --- a/.github/scripts/pr-comment.js +++ b/.github/scripts/pr-comment.js @@ -36,10 +36,19 @@ module.exports = async ({ github, context, releaseUrl, version, tag }) => { // Generate combined download table let assetTable = '| Platform | File | Size |\n| --- | --- | --- |\n'; - // Add macOS assets + // Add macOS assets with architecture detection macAssets.forEach((asset) => { const sizeInMB = (asset.size / (1024 * 1024)).toFixed(2); - assetTable += `| macOS | [${asset.name}](${asset.browser_download_url}) | ${sizeInMB} MB |\n`; + + // Detect architecture from filename + let architecture = ''; + if (asset.name.includes('arm64')) { + architecture = ' (Apple Silicon)'; + } else if (asset.name.includes('x64') || asset.name.includes('-mac.')) { + architecture = ' (Intel)'; + } + + assetTable += `| macOS${architecture} | [${asset.name}](${asset.browser_download_url}) | ${sizeInMB} MB |\n`; }); // Add Windows assets diff --git a/.github/workflows/auto-i18n.yml b/.github/workflows/auto-i18n.yml index 0b7af2d175..b000281f73 100644 --- a/.github/workflows/auto-i18n.yml +++ b/.github/workflows/auto-i18n.yml @@ -26,7 +26,7 @@ jobs: ref: ${{ github.event.pull_request.head.ref }} - name: Install bun - uses: oven-sh/setup-bun@v1 + uses: oven-sh/setup-bun@v2 with: bun-version: ${{ secrets.BUN_VERSION }} diff --git a/.github/workflows/desktop-pr-build.yml b/.github/workflows/desktop-pr-build.yml index 1989b430f7..437868e90c 100644 --- a/.github/workflows/desktop-pr-build.yml +++ b/.github/workflows/desktop-pr-build.yml @@ -28,22 +28,23 @@ jobs: fetch-depth: 0 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: 22 + package-manager-cache: false - - name: Setup pnpm - uses: pnpm/action-setup@v2 + - name: Install bun + uses: oven-sh/setup-bun@v2 with: - version: 10 + bun-version: ${{ secrets.BUN_VERSION }} - name: Install deps - run: pnpm install + run: bun i env: NODE_OPTIONS: --max-old-space-size=6144 - name: Lint - run: pnpm run lint + run: bun run lint env: NODE_OPTIONS: --max-old-space-size=6144 @@ -61,9 +62,10 @@ jobs: fetch-depth: 0 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: 22 + package-manager-cache: false # 主要逻辑:确定构建版本号 - name: Set version @@ -93,24 +95,25 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [macos-latest, windows-2025, ubuntu-latest] + os: [macos-latest, macos-13, windows-2025, ubuntu-latest] steps: - uses: actions/checkout@v5 with: fetch-depth: 0 + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + run_install: false + - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: 22 - - - name: Setup pnpm - uses: pnpm/action-setup@v2 - with: - version: 10 + package-manager-cache: false # node-linker=hoisted 模式将可以确保 asar 压缩可用 - - name: Install deps + - name: Install dependencies run: pnpm install --node-linker=hoisted - name: Install deps on Desktop @@ -172,6 +175,28 @@ jobs: NEXT_PUBLIC_DESKTOP_PROJECT_ID: ${{ secrets.UMAMI_NIGHTLY_DESKTOP_PROJECT_ID }} NEXT_PUBLIC_DESKTOP_UMAMI_BASE_URL: ${{ secrets.UMAMI_NIGHTLY_DESKTOP_BASE_URL }} + # 处理 macOS latest-mac.yml 重命名 (避免多架构覆盖) + - name: Rename macOS latest-mac.yml for multi-architecture support + if: runner.os == 'macOS' + run: | + cd apps/desktop/release + if [ -f "latest-mac.yml" ]; then + # 使用系统架构检测,与 electron-builder 输出保持一致 + SYSTEM_ARCH=$(uname -m) + if [[ "$SYSTEM_ARCH" == "arm64" ]]; then + ARCH_SUFFIX="arm64" + else + ARCH_SUFFIX="x64" + fi + + mv latest-mac.yml "latest-mac-${ARCH_SUFFIX}.yml" + echo "✅ Renamed latest-mac.yml to latest-mac-${ARCH_SUFFIX}.yml (detected: $SYSTEM_ARCH)" + ls -la latest-mac-*.yml + else + echo "⚠️ latest-mac.yml not found, skipping rename" + ls -la latest*.yml || echo "No latest*.yml files found" + fi + # 上传构建产物 - name: Upload artifact uses: actions/upload-artifact@v4 @@ -189,8 +214,64 @@ jobs: apps/desktop/release/*.tar.gz* retention-days: 5 - publish-pr: + # 合并 macOS 多架构 latest-mac.yml 文件 + merge-mac-files: needs: [build, version] + name: Merge macOS Release Files for PR + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout repository + uses: actions/checkout@v5 + + - name: Setup Node.js + uses: actions/setup-node@v5 + with: + node-version: 22 + package-manager-cache: false + + - name: Install bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: ${{ secrets.BUN_VERSION }} + + # 下载所有平台的构建产物 + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + path: release + pattern: release-* + merge-multiple: true + + # 列出下载的构建产物 + - name: List downloaded artifacts + run: ls -R release + + # 仅为该步骤在脚本目录安装 yaml 单包,避免安装整个 monorepo 依赖 + - name: Install yaml only for merge step + run: | + cd scripts/electronWorkflow + # 在脚本目录创建最小 package.json,防止 bun 向上寻找根 package.json + if [ ! -f package.json ]; then + echo '{"name":"merge-mac-release","private":true}' > package.json + fi + bun add --no-save yaml@2.8.1 + + # 合并 macOS YAML 文件 (使用 bun 运行 JavaScript) + - name: Merge latest-mac.yml files + run: bun run scripts/electronWorkflow/mergeMacReleaseFiles.js + + # 上传合并后的构建产物 + - name: Upload artifacts with merged macOS files + uses: actions/upload-artifact@v4 + with: + name: merged-release-pr + path: release/ + retention-days: 1 + + publish-pr: + needs: [merge-mac-files, version] name: Publish PR Build runs-on: ubuntu-latest # Grant write permissions for creating release and commenting on PR @@ -204,22 +285,21 @@ jobs: with: fetch-depth: 0 - # 下载所有平台的构建产物 - - name: Download artifacts + # 下载合并后的构建产物 + - name: Download merged artifacts uses: actions/download-artifact@v4 with: + name: merged-release-pr path: release - pattern: release-* - merge-multiple: true # 列出所有构建产物 - - name: List artifacts + - name: List final artifacts run: ls -R release # 生成PR发布描述 - name: Generate PR Release Body id: pr_release_body - uses: actions/github-script@v7 + uses: actions/github-script@v8 with: result-encoding: string script: | @@ -258,7 +338,7 @@ jobs: # 在 PR 上添加评论,包含构建信息和下载链接 - name: Comment on PR - uses: actions/github-script@v7 + uses: actions/github-script@v8 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/docker-database.yml b/.github/workflows/docker-database.yml index 02089192d0..16f41958d3 100644 --- a/.github/workflows/docker-database.yml +++ b/.github/workflows/docker-database.yml @@ -160,10 +160,9 @@ jobs: run: | docker buildx imagetools inspect ${{ env.REGISTRY_IMAGE }}:${{ steps.meta.outputs.version }} - - name: Comment on PR with Docker build info if: github.event_name == 'pull_request' - uses: actions/github-script@v7 + uses: actions/github-script@v8 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | @@ -178,5 +177,3 @@ jobs: platforms: "linux/amd64, linux/arm64", }); core.info(`Status: ${result.updated ? 'Updated' : 'Created'}, ID: ${result.id}`); - - diff --git a/.github/workflows/release-desktop-beta.yml b/.github/workflows/release-desktop-beta.yml index 3cdc5a6dfb..f27e455a03 100644 --- a/.github/workflows/release-desktop-beta.yml +++ b/.github/workflows/release-desktop-beta.yml @@ -24,20 +24,21 @@ jobs: fetch-depth: 0 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: 22 + package-manager-cache: false - - name: Setup pnpm - uses: pnpm/action-setup@v2 + - name: Install bun + uses: oven-sh/setup-bun@v2 with: - version: 10 + bun-version: ${{ secrets.BUN_VERSION }} - name: Install deps - run: pnpm install + run: bun i - name: Lint - run: pnpm run lint + run: bun run lint version: name: Determine version @@ -52,9 +53,10 @@ jobs: fetch-depth: 0 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: 22 + package-manager-cache: false # 主要逻辑:确定构建版本号 - name: Set version @@ -80,24 +82,25 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [macos-latest, windows-2025, ubuntu-latest] + os: [macos-latest, macos-13, windows-2025, ubuntu-latest] steps: - uses: actions/checkout@v5 with: fetch-depth: 0 + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + run_install: false + - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: 22 - - - name: Setup pnpm - uses: pnpm/action-setup@v2 - with: - version: 10 + package-manager-cache: false # node-linker=hoisted 模式将可以确保 asar 压缩可用 - - name: Install deps + - name: Install dependencies run: pnpm install --node-linker=hoisted - name: Install deps on Desktop @@ -154,7 +157,29 @@ jobs: NEXT_PUBLIC_DESKTOP_PROJECT_ID: ${{ secrets.UMAMI_BETA_DESKTOP_PROJECT_ID }} NEXT_PUBLIC_DESKTOP_UMAMI_BASE_URL: ${{ secrets.UMAMI_BETA_DESKTOP_BASE_URL }} - # 上传构建产物,移除了 zip 相关部分 + # 处理 macOS latest-mac.yml 重命名 (避免多架构覆盖) + - name: Rename macOS latest-mac.yml for multi-architecture support + if: runner.os == 'macOS' + run: | + cd apps/desktop/release + if [ -f "latest-mac.yml" ]; then + # 使用系统架构检测,与 electron-builder 输出保持一致 + SYSTEM_ARCH=$(uname -m) + if [[ "$SYSTEM_ARCH" == "arm64" ]]; then + ARCH_SUFFIX="arm64" + else + ARCH_SUFFIX="x64" + fi + + mv latest-mac.yml "latest-mac-${ARCH_SUFFIX}.yml" + echo "✅ Renamed latest-mac.yml to latest-mac-${ARCH_SUFFIX}.yml (detected: $SYSTEM_ARCH)" + ls -la latest-mac-*.yml + else + echo "⚠️ latest-mac.yml not found, skipping rename" + ls -la latest*.yml || echo "No latest*.yml files found" + fi + + # 上传构建产物 (工作流处理重命名,不依赖 electron-builder 钩子) - name: Upload artifact uses: actions/upload-artifact@v4 with: @@ -171,17 +196,28 @@ jobs: apps/desktop/release/*.tar.gz* retention-days: 5 - # 正式版发布 job - publish-release: + # 合并 macOS 多架构 latest-mac.yml 文件 + merge-mac-files: needs: [build, version] - name: Publish Beta Release + name: Merge macOS Release Files runs-on: ubuntu-latest - # Grant write permission to contents for uploading release assets permissions: contents: write - outputs: - artifact_path: ${{ steps.set_path.outputs.path }} steps: + - name: Checkout repository + uses: actions/checkout@v5 + + - name: Setup Node.js + uses: actions/setup-node@v5 + with: + node-version: 22 + package-manager-cache: false + + - name: Install bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: ${{ secrets.BUN_VERSION }} + # 下载所有平台的构建产物 - name: Download artifacts uses: actions/download-artifact@v4 @@ -190,11 +226,52 @@ jobs: pattern: release-* merge-multiple: true - # 列出所有构建产物 - - name: List artifacts + # 列出下载的构建产物 + - name: List downloaded artifacts run: ls -R release - # 将构建产物上传到现有 release + # 仅为该步骤在脚本目录安装 yaml 单包,避免安装整个 monorepo 依赖 + - name: Install yaml only for merge step + run: | + cd scripts/electronWorkflow + # 在脚本目录创建最小 package.json,防止 bun 向上寻找根 package.json + if [ ! -f package.json ]; then + echo '{"name":"merge-mac-release","private":true}' > package.json + fi + bun add --no-save yaml@2.8.1 + + # 合并 macOS YAML 文件 (使用 bun 运行 JavaScript) + - name: Merge latest-mac.yml files + run: bun run scripts/electronWorkflow/mergeMacReleaseFiles.js + + # 上传合并后的构建产物 + - name: Upload artifacts with merged macOS files + uses: actions/upload-artifact@v4 + with: + name: merged-release + path: release/ + retention-days: 1 + + # 发布所有平台构建产物 + publish-release: + needs: [merge-mac-files] + name: Publish Beta Release + runs-on: ubuntu-latest + permissions: + contents: write + steps: + # 下载合并后的构建产物 + - name: Download merged artifacts + uses: actions/download-artifact@v4 + with: + name: merged-release + path: release + + # 列出所有构建产物 + - name: List final artifacts + run: ls -R release + + # 将构建产物上传到现有 release (现在包含合并后的 latest-mac.yml) - name: Upload to Release uses: softprops/action-gh-release@v1 with: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0d6322e803..c31b414c18 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -27,12 +27,13 @@ jobs: token: ${{ secrets.GH_TOKEN }} - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: 22 + package-manager-cache: false - name: Install bun - uses: oven-sh/setup-bun@v1 + uses: oven-sh/setup-bun@v2 with: bun-version: ${{ secrets.BUN_VERSION }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index ea316cf4fa..439ba473cc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,12 +19,13 @@ jobs: - uses: actions/checkout@v5 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: 22 + package-manager-cache: false - name: Install bun - uses: oven-sh/setup-bun@v1 + uses: oven-sh/setup-bun@v2 with: bun-version: ${{ secrets.BUN_VERSION }} @@ -53,12 +54,13 @@ jobs: - uses: actions/checkout@v5 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: 22 + package-manager-cache: false - name: Install bun - uses: oven-sh/setup-bun@v1 + uses: oven-sh/setup-bun@v2 with: bun-version: ${{ secrets.BUN_VERSION }} @@ -75,7 +77,6 @@ jobs: files: ./packages/${{ matrix.package }}/coverage/lcov.info flags: packages/${{ matrix.package }} - # App tests test-website: name: Test Website @@ -86,12 +87,13 @@ jobs: - uses: actions/checkout@v5 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: 22 + package-manager-cache: false - name: Install bun - uses: oven-sh/setup-bun@v1 + uses: oven-sh/setup-bun@v2 with: bun-version: ${{ secrets.BUN_VERSION }} @@ -129,12 +131,13 @@ jobs: - uses: actions/checkout@v5 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: 22 + package-manager-cache: false - name: Install bun - uses: oven-sh/setup-bun@v1 + uses: oven-sh/setup-bun@v2 with: bun-version: ${{ secrets.BUN_VERSION }} diff --git a/apps/desktop/electron-builder.js b/apps/desktop/electron-builder.js index 9d1cf582a0..202e9c2e95 100644 --- a/apps/desktop/electron-builder.js +++ b/apps/desktop/electron-builder.js @@ -1,12 +1,15 @@ const dotenv = require('dotenv'); +const os = require('node:os'); dotenv.config(); const packageJSON = require('./package.json'); const channel = process.env.UPDATE_CHANNEL; +const arch = os.arch(); console.log(`🚄 Build Version ${packageJSON.version}, Channel: ${channel}`); +console.log(`🏗️ Building for architecture: ${arch}`); const isNightly = channel === 'nightly'; const isBeta = packageJSON.name.includes('beta'); @@ -87,12 +90,13 @@ const config = { hardenedRuntime: true, notarize: true, target: - // 降低构建时间,nightly 只打 arm64 + // 降低构建时间,nightly 只打 dmg + // 根据当前机器架构只构建对应架构的包 isNightly - ? [{ arch: ['arm64'], target: 'dmg' }] + ? [{ arch: [arch === 'arm64' ? 'arm64' : 'x64'], target: 'dmg' }] : [ - { arch: ['x64', 'arm64'], target: 'dmg' }, - { arch: ['x64', 'arm64'], target: 'zip' }, + { arch: [arch === 'arm64' ? 'arm64' : 'x64'], target: 'dmg' }, + { arch: [arch === 'arm64' ? 'arm64' : 'x64'], target: 'zip' }, ], }, npmRebuild: true, diff --git a/scripts/electronWorkflow/mergeMacReleaseFiles.js b/scripts/electronWorkflow/mergeMacReleaseFiles.js new file mode 100644 index 0000000000..7ce3b11cf7 --- /dev/null +++ b/scripts/electronWorkflow/mergeMacReleaseFiles.js @@ -0,0 +1,179 @@ +/* eslint-disable unicorn/no-process-exit, unicorn/prefer-top-level-await */ +import fs from 'node:fs'; +import path from 'node:path'; +import YAML from 'yaml'; + +// 配置 +const FILE_NAME = 'latest-mac.yml'; +const RELEASE_DIR = path.resolve('release'); + +/** + * 检测 latest-mac.yml 文件的平台类型 + * @param {Object} yamlContent - YAML 文件内容 + * @returns {'x64' | 'arm64' | 'both' | 'none'} + */ +function detectPlatform(yamlContent) { + const hasX64 = yamlContent.files.some((file) => file.url.includes('-x64.dmg')); + const hasArm64 = yamlContent.files.some((file) => file.url.includes('-arm64.dmg')); + + if (hasX64 && hasArm64) return 'both'; + if (hasX64 && !hasArm64) return 'x64'; + if (!hasX64 && hasArm64) return 'arm64'; + return 'none'; +} + +/** + * 合并两个 latest-mac.yml 文件 + * @param {Object} x64Content - x64 平台的 YAML 内容 + * @param {Object} arm64Content - ARM64 平台的 YAML 内容 + * @returns {string} 合并后的 YAML 字符串 + */ +function mergeYamlFiles(x64Content, arm64Content) { + // 以 ARM64 为基础(Apple Silicon 优先) + const merged = { + ...arm64Content, + files: [...arm64Content.files, ...x64Content.files], + }; + + return YAML.stringify(merged); +} + +/** + * 读取本地文件 + * @param {string} filePath - 文件路径 + * @returns {string | null} 文件内容或 null + */ +function readLocalFile(filePath) { + try { + if (fs.existsSync(filePath)) { + const content = fs.readFileSync(filePath, 'utf8'); + console.log(`✅ Read local file: ${filePath} (${content.length} chars)`); + return content; + } + console.log(`⚠️ Local file not found: ${filePath}`); + return null; + } catch (error) { + console.error(`❌ Error reading local file ${filePath}:`, error); + return null; + } +} + +/** + * 写入本地文件 + * @param {string} filePath - 文件路径 + * @param {string} content - 文件内容 + */ +function writeLocalFile(filePath, content) { + try { + fs.writeFileSync(filePath, content, 'utf8'); + console.log(`✅ Written local file: ${filePath} (${content.length} chars)`); + } catch (error) { + console.error(`❌ Error writing local file ${filePath}:`, error); + throw error; + } +} + +/** + * 主函数 + */ +async function main() { + try { + console.log('🚀 Starting macOS Release file merge'); + console.log(`📁 Working directory: ${RELEASE_DIR}`); + + // 1. 检查 release 目录下的所有文件 + const releaseFiles = fs.readdirSync(RELEASE_DIR); + console.log(`📂 Files in release directory: ${releaseFiles.join(', ')}`); + + // 2. 查找所有 latest-mac*.yml 文件 + const macYmlFiles = releaseFiles.filter( + (f) => f.startsWith('latest-mac') && f.endsWith('.yml'), + ); + console.log(`🔍 Found macOS YAML files: ${macYmlFiles.join(', ')}`); + + if (macYmlFiles.length === 0) { + console.log('⚠️ No macOS YAML files found, skipping merge'); + return; + } + + // 3. 处理找到的文件,识别平台 + const macFiles = []; + + for (const fileName of macYmlFiles) { + const filePath = path.join(RELEASE_DIR, fileName); + const content = readLocalFile(filePath); + + if (!content) continue; + + try { + const yamlContent = YAML.parse(content); + const platform = detectPlatform(yamlContent); + + if (platform === 'x64' || platform === 'arm64') { + macFiles.push({ content, filename: fileName, platform, yaml: yamlContent }); + console.log(`🔍 Detected ${platform} platform in ${fileName}`); + } else if (platform === 'both') { + console.log(`✅ Found already merged file: ${fileName}`); + // 如果已经是合并后的文件,直接复制为最终文件 + writeLocalFile(path.join(RELEASE_DIR, FILE_NAME), content); + return; + } else { + console.log(`⚠️ Unknown platform type: ${platform} in ${fileName}`); + } + } catch (error) { + console.warn(`⚠️ Failed to parse ${fileName}:`, error); + } + } + + // 4. 检查是否有两个不同平台的文件 + const x64Files = macFiles.filter((f) => f.platform === 'x64'); + const arm64Files = macFiles.filter((f) => f.platform === 'arm64'); + + if (x64Files.length === 0 && arm64Files.length === 0) { + console.log('⚠️ No valid platform files found'); + return; + } + + if (x64Files.length === 0) { + console.log('⚠️ No x64 files found, using ARM64 only'); + writeLocalFile(path.join(RELEASE_DIR, FILE_NAME), arm64Files[0].content); + return; + } + + if (arm64Files.length === 0) { + console.log('⚠️ No ARM64 files found, using x64 only'); + writeLocalFile(path.join(RELEASE_DIR, FILE_NAME), x64Files[0].content); + return; + } + + // 5. 合并 x64 和 ARM64 文件 + const x64File = x64Files[0]; + const arm64File = arm64Files[0]; + + console.log(`🔄 Merging ${x64File.filename} (x64) and ${arm64File.filename} (ARM64)...`); + const mergedContent = mergeYamlFiles(x64File.yaml, arm64File.yaml); + + // 6. 保存合并后的文件 + const mergedFilePath = path.join(RELEASE_DIR, FILE_NAME); + writeLocalFile(mergedFilePath, mergedContent); + + // 7. 验证合并结果 + const mergedYaml = YAML.parse(mergedContent); + const finalPlatform = detectPlatform(mergedYaml); + + if (finalPlatform === 'both') { + console.log('✅ Successfully merged both x64 and ARM64 platforms'); + console.log(`📊 Final file contains ${mergedYaml.files.length} files`); + } else { + console.warn(`⚠️ Merge result unexpected: ${finalPlatform}`); + } + + console.log('🎉 Merge complete!'); + } catch (error) { + console.error('❌ Error during merge:', error); + process.exit(1); + } +} + +// 运行主函数 +await main();