Skip to content

新增:支持 macOS 桌面打包并接入发布流程 - #203

Open
laohuan12138 wants to merge 1 commit into
ExplosiveCoderflome:betafrom
laohuan12138:macos-packaging
Open

laohuan12138 wants to merge 1 commit into
ExplosiveCoderflome:betafrom
laohuan12138:macos-packaging

Conversation

@laohuan12138

Copy link
Copy Markdown

背景

桌面端打包链路原先只面向 Windows(NSIS + portable),macOS 用户只能用源码 + 终端启动。本 PR 在同一套 Electron 宿主上补齐 macOS 打包,并让发布流程自动产出 macOS 安装包。

改动

1. macOS 打包能力

  • desktop/electron-builder.config.cjs:新增 mac(dmg + zip,默认 arm64)与 dmg 目标,新增 .icns 图标、entitlements.mac.plist;签名材料按平台隔离,正式发布缺签名/公证材料时直接报错。
  • desktop/scripts/generate-desktop-icons.py:随 PNG/ICO 一并生成 app-icon.icns。
  • desktop/src/runtime/paths.ts:窗口图标按平台选择 .icns / .ico。
  • desktop/src/runtime/updater.ts:macOS 应用内更新默认关闭(Squirrel.Mac 需要签名 zip 源),可用 AI_NOVEL_DESKTOP_MAC_UPDATER=true 打开。

2. 校验能力

  • desktop/scripts/verify-desktop-package.cjs:支持 macOS 产物结构校验(bundle 标识、bundle 图标、app.asar、SQLite 迁移、Prisma 运行时、arm64 原生模块),并修正 asar 路径分隔符的平台差异。
  • desktop/scripts/verify-desktop-mac-app.cjs:新增,真实启动打包产物并校验本地服务健康检查与数据库创建。

3. 发布流程

  • desktop/scripts/publish-desktop-target.cjs:新增,发布参数解析(--platform win|mac)。
  • desktop/scripts/publish-desktop-release.cjs / publish-desktop-beta.cjs:改为支持 --platform,Windows 默认行为不变。
  • scripts/check-desktop-release-tag.cjs:新增,发布 tag 与 desktop/package.json 版本一致性校验。

⚠️ 需要仓库所有者补的一步

由于本 PR 作者账号只有 Read 权限,且使用的 token 没有 workflow scope,本 PR 不包含两个 workflow 文件的改动。以下改动需要仓库所有者在本仓库内直接落地(内容见 PR 评论):

  • .github/workflows/desktop-release.yml:新增 verify-release-tag job 与 publish-release-macos job(runs-on: macos-latest,needs: publish-release)。
  • .github/workflows/desktop-beta-release.yml:同上,对应 beta 通道。

没有这两个 job 时,pnpm stage:desktop && pnpm dist:desktop:mac 仍可在任意 Mac 上本地打包,只是不会自动出现在 Releases。

验证

在 macOS 15.7.9 (Apple Silicon, Node 25) 上已完成:

  • pnpm run build:desktop:all、pnpm --filter @ai-novel/desktop typecheck 通过。
  • pnpm stage:desktop + pnpm dist:desktop:mac 产出 dmg/zip,ad-hoc 签名,codesign --verify --deep --strict 通过。
  • pnpm verify:desktop-package:mac 包体校验通过。
  • pnpm verify:desktop:mac-app 真实启动校验通过(/api/health 正常、SQLite 数据库创建成功)。
  • DMG 挂载校验通过(含 .app 与 /Applications 链接)。
  • 发布门禁与 tag 校验脚本的单测式验证通过(拒绝 linux 平台、拒绝 tag 与版本不匹配)。

UI 验收由维护者按项目惯例自行进行。

- 新增 macOS dmg/zip 打包目标、icns 图标与按平台隔离的签名门禁
- 新增 macOS 包体结构校验与打包产物真实启动冒烟校验
- 发布脚本支持 --platform win|mac,Windows 默认行为保持不变
- 新增发布 tag 与 desktop 版本一致性校验
- 补充 macOS 安装说明、桌面打包边界文档与发布说明
@laohuan12138

Copy link
Copy Markdown
Author

需要仓库所有者落地的 workflow 改动

PR 作者账号只有 Read 权限,且所用 token 没有 workflow scope,因此 .github/workflows/ 下的改动无法从 fork 推送。请在本仓库内直接应用下面的补丁(或按同样结构手动添加)。

注意:没有这两个 job,macOS 安装包仍可在任意 Mac 上本地打包,只是不会自动出现在 Releases 页面。

应用方式

git checkout beta
git pull
# 保存下方补丁为 workflow-macos.patch,然后:
git apply workflow-macos.patch
git add .github/workflows
git commit -m "新增:发布流程自动产出 macOS 安装包"
git push origin beta
workflow-macos.patch(点击展开)
diff --git a/.github/workflows/desktop-beta-release.yml b/.github/workflows/desktop-beta-release.yml
index 05a6d8d4..aa2003b7 100644
--- a/.github/workflows/desktop-beta-release.yml
+++ b/.github/workflows/desktop-beta-release.yml
@@ -10,7 +10,22 @@ permissions:
   contents: write
 
 jobs:
+  verify-release-tag:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v6
+
+      - name: Setup Node.js
+        uses: actions/setup-node@v6
+        with:
+          node-version: 24
+
+      - name: Verify release tag matches desktop version
+        run: node scripts/check-desktop-release-tag.cjs --tag "${{ github.ref_name }}"
+
   publish-beta:
+    needs: verify-release-tag
     runs-on: windows-latest
     env:
       AI_NOVEL_RELEASE_CHANNEL: beta
@@ -68,3 +83,61 @@ jobs:
 
       - name: Update GitHub release notes
         run: node scripts/update-desktop-release-notes.cjs
+
+  publish-beta-macos:
+    needs: publish-beta
+    runs-on: macos-latest
+    env:
+      AI_NOVEL_RELEASE_CHANNEL: beta
+      AI_NOVEL_GITHUB_OWNER: ExplosiveCoderflome
+      AI_NOVEL_GITHUB_REPO: AI-Novel-Writing-Assistant
+      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+      MAC_CSC_LINK: ${{ secrets.MAC_CSC_LINK }}
+      MAC_CSC_KEY_PASSWORD: ${{ secrets.MAC_CSC_KEY_PASSWORD }}
+      APPLE_ID: ${{ secrets.APPLE_ID }}
+      APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
+      APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v6
+
+      - name: Setup pnpm
+        uses: pnpm/action-setup@v6
+        with:
+          version: 10.6.0
+
+      - name: Setup Node.js
+        uses: actions/setup-node@v6
+        with:
+          node-version: 24
+          cache: pnpm
+
+      - name: Setup Python
+        uses: actions/setup-python@v6
+        with:
+          python-version: "3.11"
+
+      - name: Install dependencies
+        run: pnpm install --frozen-lockfile
+
+      - name: Install desktop icon tooling
+        run: python -m pip install --disable-pip-version-check pillow
+
+      - name: Regenerate desktop icon assets
+        run: python desktop/scripts/generate-desktop-icons.py
+
+      - name: Typecheck
+        run: pnpm typecheck
+
+      - name: Build and stage desktop app
+        run: pnpm stage:desktop
+
+      - name: Verify packaged macOS layout
+        run: pnpm verify:desktop-package:mac:reuse-stage
+
+      - name: Smoke check packaged macOS app (non-blocking)
+        continue-on-error: true
+        run: pnpm verify:desktop:mac-app
+
+      - name: Publish macOS beta to GitHub Releases
+        run: node desktop/scripts/publish-desktop-beta.cjs --platform mac
diff --git a/.github/workflows/desktop-release.yml b/.github/workflows/desktop-release.yml
index a103acad..2354ed20 100644
--- a/.github/workflows/desktop-release.yml
+++ b/.github/workflows/desktop-release.yml
@@ -11,7 +11,22 @@ permissions:
   contents: write
 
 jobs:
+  verify-release-tag:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v6
+
+      - name: Setup Node.js
+        uses: actions/setup-node@v6
+        with:
+          node-version: 24
+
+      - name: Verify release tag matches desktop version
+        run: node scripts/check-desktop-release-tag.cjs --tag "${{ github.ref_name }}"
+
   publish-release:
+    needs: verify-release-tag
     if: ${{ startsWith(github.ref_name, 'desktop-v') || !contains(github.ref_name, '-') }}
     runs-on: windows-latest
     env:
@@ -71,3 +86,62 @@ jobs:
 
       - name: Update GitHub release notes
         run: node scripts/update-desktop-release-notes.cjs
+
+  publish-release-macos:
+    needs: publish-release
+    runs-on: macos-latest
+    env:
+      AI_NOVEL_RELEASE_CHANNEL: release
+      AI_NOVEL_ALLOW_UNSIGNED_MAC_RELEASE: ${{ vars.AI_NOVEL_ALLOW_UNSIGNED_MAC_RELEASE || 'true' }}
+      AI_NOVEL_GITHUB_OWNER: ExplosiveCoderflome
+      AI_NOVEL_GITHUB_REPO: AI-Novel-Writing-Assistant
+      GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+      MAC_CSC_LINK: ${{ secrets.MAC_CSC_LINK }}
+      MAC_CSC_KEY_PASSWORD: ${{ secrets.MAC_CSC_KEY_PASSWORD }}
+      APPLE_ID: ${{ secrets.APPLE_ID }}
+      APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
+      APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v6
+
+      - name: Setup pnpm
+        uses: pnpm/action-setup@v6
+        with:
+          version: 10.6.0
+
+      - name: Setup Node.js
+        uses: actions/setup-node@v6
+        with:
+          node-version: 24
+          cache: pnpm
+
+      - name: Setup Python
+        uses: actions/setup-python@v6
+        with:
+          python-version: "3.11"
+
+      - name: Install dependencies
+        run: pnpm install --frozen-lockfile
+
+      - name: Install desktop icon tooling
+        run: python -m pip install --disable-pip-version-check pillow
+
+      - name: Regenerate desktop icon assets
+        run: python desktop/scripts/generate-desktop-icons.py
+
+      - name: Typecheck
+        run: pnpm typecheck
+
+      - name: Build and stage desktop app
+        run: pnpm stage:desktop
+
+      - name: Verify packaged macOS layout
+        run: pnpm verify:desktop-package:mac:reuse-stage
+
+      - name: Smoke check packaged macOS app (non-blocking)
+        continue-on-error: true
+        run: pnpm verify:desktop:mac-app
+
+      - name: Publish macOS release to GitHub Releases
+        run: node desktop/scripts/publish-desktop-release.cjs --platform mac

关键设计点

  • macOS job 用 needs 排在 Windows job 之后:Windows job 负责创建 Release,macOS job 只向已存在的 Release 追加 dmg/zip 与 latest-mac.yml,避免并发创建同一个 Release 冲突。
  • verify-release-tag job 校验 tag 与 desktop/package.json 版本一致,不匹配则整个发布中止(对应仓库既有的 vX.Y.Z 发布标识规则)。
  • verify:desktop-package:mac 是阻塞校验;verify:desktop:mac-app 用 continue-on-error,因为 GitHub 的 macOS runner 没有真实用户会话,GUI 启动冒烟会偶发失败。
  • 签名走 secrets:MAC_CSC_LINK / MAC_CSC_KEY_PASSWORD / APPLE_ID / APPLE_APP_SPECIFIC_PASSWORD / APPLE_TEAM_ID。未配置时由仓库变量 AI_NOVEL_ALLOW_UNSIGNED_MAC_RELEASE(默认 true)允许未签名构建。

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant