Skip to content

ci: publish cross-platform portable differential updates - #2439

Open
xxynet wants to merge 20 commits into
Project-N-E-K-O:mainfrom
xxynet:ci/portable-update
Open

ci: publish cross-platform portable differential updates#2439
xxynet wants to merge 20 commits into
Project-N-E-K-O:mainfrom
xxynet:ci/portable-update

Conversation

@xxynet

@xxynet xxynet commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

改动概述 / Summary

  • 将桌面构建工作流改造成可复用 workflow,并新增 Windows-only 手动入口;版本、前端仓库/ref、差分基线及 fork 调试许可均由执行时传入,不在 workflow 中保留测试专用值。
  • 为 Windows、macOS x64/arm64、Linux x64 和 Linux AppImage 生成自管理 Portable 全量包、manifest 与差分更新资产,可基于最新稳定版或指定 Release 的 manifest 计算差分。
  • v* tag 构建后统一发布各平台 Portable 资产;Windows-only nightly 重跑只覆盖 Windows 资产,不删除其他平台文件。
  • 修复 macOS 重签名前 Playwright .links 元数据导致的签名识别问题,并调整 OpenAI ASR worker 的异步任务清理以避免 Nuitka 运行时崩溃。

回归报告 / Regression Report

  • 改动内容:main_logic/asr_client/workers/openai.py 的 worker 清理阶段改为显式收集实际存在的 sender/receiver task,取消未完成任务后统一 gather
  • 理由 / 必要性:原先的任务列表推导式在 Nuitka 构建环境的异常清理路径中可能崩溃,导致 OpenAI 实时 ASR worker 无法正常退出。
  • 改动前后:改动前先取消 task、再通过列表推导式重新收集;改动后跳过 None,逐个取消未完成 task 并加入列表,最后等待所有实际创建的 task 完成清理。
  • 潜在回归点:ASR sender/receiver task 的取消、WebSocket 关闭和 closed 事件发送。已运行完整 tests/unit/test_asr_workers.py 覆盖正常关闭、异常和取消路径。

不拆分理由 / Why Not Split

不适用。计入上限的既有文件不超过 20 个;新增 workflow 与测试文件不计入该上限。

测试 / Testing

  • .\.venv\Scripts\python.exe -m pytest -q tests/unit/test_asr_workers.py tests/unit/test_desktop_windows_workflow_contract.py -p no:cacheprovider:36 passed。
  • git diff --check:通过。

Summary by CodeRabbit

  • 新功能
    • 新增仅 Windows 的桌面构建工作流(手动触发),可按需产出便携版全量与差分更新资源。
    • 新增“稳定版发布校验”工作流:仅当各平台资产清单与签名齐全时才通过。
  • 改进
    • 扩展桌面构建与发布链路的参数化:支持跳过签名、Windows-only 夜间发布、便携版清单签名与夜间产物说明调整。
    • 本地发布与远端注册更严格:增加 SHA256 校验、不可覆盖检测与镜像同步重试。
  • 文档
    • 更新手动稳定版发布说明。
  • 测试
    • 更新并增强发布/夜间签名与合约断言覆盖范围。

@xxynet
xxynet requested a review from wehos as a code owner July 22, 2026 08:11
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

新增 Windows-only 手动桌面构建入口,并扩展可复用工作流以支持动态平台矩阵、签名控制、Portable 更新资产、Nightly/稳定版校验及本地发布脚本喵。

Changes

桌面构建与发布

Layer / File(s) Summary
工作流入口与运行参数
.github/workflows/build-desktop-windows.yml, .github/workflows/build-desktop.yml, tests/unit/test_desktop_windows_workflow_contract.py
新增 Windows 手动工作流和可复用输入,支持版本、Electron 来源、签名、Windows-only 与 fork 构建参数,并由契约测试校验调用关系喵。
平台矩阵与 Portable 构建
.github/workflows/build-desktop.yml, tests/unit/test_desktop_windows_workflow_contract.py
构建矩阵根据 windows_only 动态选择平台,生成签名、Portable 及差分更新资产,并收集与签名 Portable 清单喵。
Nightly 与稳定版校验
.github/workflows/build-desktop.yml, .github/workflows/sync-update-release.yml, tests/unit/test_desktop_windows_workflow_contract.py
Nightly 支持 Windows-only 创建或更新,稳定版流程校验发布资产并移除更新服务交互喵。
手动稳定版构建与发布工具
scripts/build-desktop-release.ps1, scripts/publish-desktop-release-assets.ps1, docs/deployment/manual-desktop-release.md, .gitignore, tests/unit/test_desktop_windows_workflow_contract.py
补充本地构建、差分打包、清单签名、资产暂存、哈希校验、OSS/CDN 发布、架构校验和操作说明喵。

Estimated code review effort: 4 (Complex) | ~60 minutes

Suggested labels: enhancement

Poem

Windows 小猫踏进构建喵
Portable 资产排成队喵
签名差分转圈圈喵
Nightly 稳定版发光喵
契约测试守门喵

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题概括了本次发布跨平台 Portable 差分更新的核心变更,和修改内容一致喵。
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Warning

Review ran into problems

🔥 Problems

Repository analysis: Couldn't refresh Project-N-E-K-O/N.E.K.O clone - clone failed: Clone operation failed: Stream initialization permanently failed: 14 UNAVAILABLE: Connection dropped


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

这个 PR 将桌面构建工作流改造为可复用的 workflow_call 形式,新增 Windows-only 手动入口,并为所有平台引入自管理 Portable 全量/差分更新包与 Ed25519 签名流水线喵。

  • 工作流参数化build-desktop.yml 新增 workflow_call 触发器,通过 fromJSON 表达式动态切换全平台矩阵与 Windows-only 矩阵;签名决策已从事件名判断迁移为 inputs.skip_signing 直接控制喵。
  • Portable 更新管道:在 build-electron 阶段为 Windows、macOS x64/arm64、Linux x64 及 Linux AppImage 生成全量包与差分包,nightly 阶段用 openssl pkeyutl -sign -rawin(Ed25519)对所有 manifest 签名喵。
  • 本地发布脚本build-desktop-release.ps1 在本地签名并暂存资产,publish-desktop-release-assets.ps1 验证 SHA-256 后上传 OSS 并注册 CDN 镜像;sync-update-release.yml 在 GitHub Release 发布后仅校验资产完整性,不调用 update service 喵。

Confidence Score: 4/5

The local build script will crash on first adoption if -PreviousReleaseTag references a release without portable manifests, while the CI workflow handles this gracefully.

The workflow restructuring and signing pipeline are well-covered by contract tests and the publish script CDN verification logic is solid. The one defect is Get-PreviousManifest in the local build script: it calls gh release download --pattern via Invoke-Checked, which aborts on zero matches, meaning the very first stable build will fail with a cryptic gh error whenever a maintainer passes -PreviousReleaseTag for a release that predates portable manifest support.

Files Needing Attention: scripts/build-desktop-release.ps1 — specifically the Get-PreviousManifest function and its handling of gh release download when the previous release has no matching manifest assets.

Important Files Changed

Filename Overview
.github/workflows/build-desktop-windows.yml New Windows-only workflow_dispatch entry point that delegates to build-desktop.yml with windows_only: true and secrets: inherit; straightforward and correct.
.github/workflows/build-desktop.yml Major refactor to a reusable workflow_call with parameterized matrix (via fromJSON toggle), portable update pipeline, and differential manifest signing; one inline ${{ github.sha }} remains in the Windows nightly step against the new env-var pattern.
.github/workflows/sync-update-release.yml New validation-only workflow triggered on stable release publication; checks all required portable assets and signatures without touching the update service or CDN.
scripts/build-desktop-release.ps1 New local stable-release build script; Get-PreviousManifest uses Invoke-Checked gh release download --pattern which throws when no asset matches, unlike the CI workflow's graceful "full package only" fallback; all other logic (env cleanup, signing, staged-output guard) is correct.
scripts/publish-desktop-release-assets.ps1 New CDN upload and mirror registration script; correctly validates local-vs-remote asset parity, enforces immutability on existing OSS objects via SHA-256 comparison, and verifies CDN bytes before mirror registration.
tests/unit/test_desktop_windows_workflow_contract.py New contract tests covering signing input handling, matrix selection, env-var injection pattern, Windows-only nightly branching, and stable release validation; all referenced job/step names align with the current workflow YAML.
.gitignore Adds !scripts/build-desktop-release.ps1 to un-ignore the new script whose basename matches the existing build* rule; publish-desktop-release-assets.ps1 is unaffected and correctly tracked without a negation.
docs/deployment/manual-desktop-release.md New deployment guide documenting the full manual stable-release flow; accurately reflects the two-script model and correctly notes that sync-update-release.yml only validates assets.

Sequence Diagram

sequenceDiagram
    participant WD as workflow_dispatch / schedule
    participant WW as build-desktop-windows.yml
    participant BD as build-desktop.yml
    participant NJ as nightly job
    participant GH as GitHub Release

    WD->>WW: trigger (windows_only)
    WW->>BD: "workflow_call (windows_only=true)"
    BD->>BD: version job
    BD->>BD: build-python (win only matrix)
    BD->>BD: build-electron (win only matrix)
    BD->>BD: Download previous manifests
    BD->>BD: create-portable-update.js
    BD->>NJ: artifact upload
    NJ->>NJ: Organize release files
    NJ->>NJ: Sign Portable manifests (Ed25519)
    NJ->>GH: gh release upload --clobber

    Note over BD,GH: Full cross-platform tag build
    WD->>BD: "push v* tag"
    BD->>BD: All platforms (4 matrix entries each)
    BD->>NJ: artifacts (all platforms)
    NJ->>NJ: Sign all manifests
    NJ->>GH: gh release create (full nightly)

    Note over GH: Stable release publishing
    GH->>GH: Maintainer publishes stable release
    GH->>GH: sync-update-release.yml validates assets
Loading

Comments Outside Diff (1)

  1. scripts/build-desktop-release.ps1, line 824-827 (link)

    P1 Get-PreviousManifest crashes instead of falling back on missing assets

    Invoke-Checked gh release download ... --pattern "..." exits non-zero when no assets match the pattern. This causes the entire script to throw a cryptic error and abort. The first time a maintainer runs this script with -PreviousReleaseTag pointing at a release that predates portable manifest support, the script will crash instead of gracefully producing a full package — exactly the scenario that will occur on first adoption.

    The CI workflow handles this correctly: it uses gh api to test for the URL first, and only downloads when the asset exists, otherwise printing "full package only". The local script has no equivalent guard in Get-PreviousManifest.

Reviews (15): Last reviewed commit: "fix: harden portable release publication" | Re-trigger Greptile

Comment thread .github/workflows/build-desktop.yml
Comment thread .github/workflows/build-desktop.yml Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3c53853b6e

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread .github/workflows/build-desktop.yml
@coderabbitai coderabbitai Bot added the enhancement New feature or request label Jul 22, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
.github/workflows/build-desktop.yml (1)

819-825: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

macOS/Linux 也走包装脚本喵 npx electron-builder 会跳过 scripts/build-electron-distribution.js 里的 Electron 版本、package-lock 和 Wayland 补丁清单校验;这里建议和 Windows/Portable 一样改用该脚本,避免产出不一致的分发包喵。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-desktop.yml around lines 819 - 825, Update the
“Build Electron app (macOS/Linux)” step to invoke
scripts/build-electron-distribution.js instead of npx electron-builder, while
preserving the existing matrix.electron_args, working directory, publish
behavior, and environment variables so all platforms use the same validation and
packaging flow.

Source: Linked repositories

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In @.github/workflows/build-desktop.yml:
- Around line 819-825: Update the “Build Electron app (macOS/Linux)” step to
invoke scripts/build-electron-distribution.js instead of npx electron-builder,
while preserving the existing matrix.electron_args, working directory, publish
behavior, and environment variables so all platforms use the same validation and
packaging flow.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 10168a2c-b25b-48c0-9ea8-b799b2e9b332

📥 Commits

Reviewing files that changed from the base of the PR and between 42c0c18 and 3c53853.

📒 Files selected for processing (4)
  • .github/workflows/build-desktop-windows.yml
  • .github/workflows/build-desktop.yml
  • main_logic/asr_client/workers/openai.py
  • tests/unit/test_desktop_windows_workflow_contract.py
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Project-N-E-K-O/N.E.K.O.-PC (manual)

@xxynet

xxynet commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the CodeRabbit macOS/Linux packaging nit in fb8034b: the normal distribution step now uses scripts/build-electron-distribution.js with the matrix platform and architecture arguments, so Electron/package-lock/Wayland manifest validation is shared with the Portable builds. Combined ASR + workflow contract tests: 36 passed.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/unit/test_desktop_windows_workflow_contract.py`:
- Around line 34-49: 更新
test_reusable_build_honors_signing_inputs_and_distribution_wrapper,使其解析 workflow
YAML,并按步骤名称提取对应的 mapping,而不是在完整文本中匹配字符串。将 Windows-only nightly 上传步骤的 if 与 run
联合断言,并将签名构建步骤的 if、run 和 env 中的 WIN_CSC_LINK、WIN_CSC_KEY_PASSWORD
联合断言,确保这些配置属于同一步骤且不会被注释或其它步骤中的字符串误通过。
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: c522809a-7704-41b9-9e1a-14401c51ca92

📥 Commits

Reviewing files that changed from the base of the PR and between 3c53853 and fb8034b.

📒 Files selected for processing (2)
  • .github/workflows/build-desktop.yml
  • tests/unit/test_desktop_windows_workflow_contract.py
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Project-N-E-K-O/N.E.K.O.-PC (manual)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/build-desktop.yml

Comment thread tests/unit/test_desktop_windows_workflow_contract.py Outdated
@xxynet
xxynet marked this pull request as draft July 22, 2026 09:06
@wehos
wehos marked this pull request as ready for review July 26, 2026 17:56
@wehos
wehos marked this pull request as draft July 26, 2026 18:58
@xxynet
xxynet marked this pull request as ready for review July 27, 2026 07:06

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0527ff020c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread .github/workflows/build-desktop.yml Outdated
# Stable tags publish every self-managed Portable update channel. If a release was
# created manually first, upload --clobber updates its assets in place.
publish-stable-portable:
if: (github.repository == 'Project-N-E-K-O/N.E.K.O' || inputs.allow_fork_build) && startsWith(github.ref, 'refs/tags/v') && needs.build-electron.result == 'success'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Exclude prerelease tags from the stable publication job

Restrict this condition to stable semantic versions before publishing: a tag such as the advertised v1.0.0-beta.1 also satisfies refs/tags/v*, so the job creates a non-prerelease GitHub release and then posts that beta version to /stable/sync. When the update service is configured, stable-channel users can therefore be offered a prerelease build.

Useful? React with 👍 / 👎.

Comment thread .github/workflows/build-desktop.yml Outdated
run: |
set -euo pipefail
mkdir -p previous-portable
RELEASE_ENDPOINT="repos/${GITHUB_REPOSITORY}/releases/latest"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Exclude the current tag from the delta baseline

Resolve the latest release preceding the tag rather than querying releases/latest unconditionally. If the tag's GitHub Release was created manually before this workflow—as the publication code explicitly supports—or this workflow is rerun after publishing, that endpoint can return the current release; the first case produces no delta and the second compares against the current manifest instead of the version users are upgrading from, defeating differential updates for that release.

Useful? React with 👍 / 👎.


jobs:
build-windows:
uses: ./.github/workflows/build-desktop.yml

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Grant release-write permission in the reusable caller

Grant contents: write to this calling job or workflow. When the repository uses a read-only default GITHUB_TOKEN, this wrapper passes only that permission to the reusable workflow, so its Windows-nightly release upload fails even though the called job requests write access; GitHub's reusable-workflow documentation states that permissions “can be only downgraded (not elevated) by the called workflow.”

Useful? React with 👍 / 👎.

@xxynet

xxynet commented Jul 29, 2026

Copy link
Copy Markdown
Contributor Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Bravo.

Reviewed commit: 0fbde6e2fe

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/build-desktop-release.ps1`:
- Around line 194-197: Update the build setup around $portableUpdateDirectory
and the later dist asset collection to clear the entire dist directory before
starting a new build, while retaining the existing existence check and
preservation guidance for dist/portable-update. Ensure stale artifacts cannot be
selected by the Where-Object asset-copy logic, and keep the cleanup scoped to
the pre-build phase.
- Around line 9-13: After determining buildPlatform in the release script,
validate Architecture against the platform’s actual build behavior: only allow
the supported architecture value for Windows/Linux, and reject unsupported
combinations before invoking build-electron-distribution.js or
create-portable-update.js. Ensure create-portable-update.js receives an
architecture value that matches the produced artifact, while preserving the
existing macOS architecture handling.
- Around line 186-192: 在 Linux 分支中更新对 `$package.build.linux` 的检查,改用
`$package.build.PSObject.Properties.Match('linux')` 等属性枚举方式判断属性是否存在,避免
StrictMode 下直接访问缺失属性抛出异常;保留现有缺失时添加 linux 配置及设置 maintainer 的行为。
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d3221761-4035-4199-b3eb-96e77ea07eb6

📥 Commits

Reviewing files that changed from the base of the PR and between 0fbde6e and 799f186.

📒 Files selected for processing (5)
  • .github/workflows/build-desktop.yml
  • .github/workflows/sync-update-release.yml
  • .gitignore
  • docs/deployment/manual-desktop-release.md
  • scripts/build-desktop-release.ps1
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Project-N-E-K-O/N.E.K.O.-PC (manual)
💤 Files with no reviewable changes (1)
  • .github/workflows/build-desktop.yml

Comment thread scripts/build-desktop-release.ps1
Comment thread scripts/build-desktop-release.ps1
Comment thread scripts/build-desktop-release.ps1

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/unit/test_desktop_windows_workflow_contract.py`:
- Around line 135-145: Strengthen
test_published_stable_release_is_the_only_update_service_sync_trigger by
asserting the workflow condition explicitly requires draft and prerelease to be
false, not merely that those fields are referenced. Extend the “Validate stable
release assets” assertions to cover the complete release matrix: Windows, Linux
x64 AppImage, ordinary Linux, macOS x64, and macOS arm64 manifest .sig
filenames.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 171f2e34-303c-4919-9035-2dcd7f7b55a9

📥 Commits

Reviewing files that changed from the base of the PR and between 799f186 and e12803c.

📒 Files selected for processing (3)
  • .github/workflows/build-desktop.yml
  • scripts/build-desktop-release.ps1
  • tests/unit/test_desktop_windows_workflow_contract.py
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Project-N-E-K-O/N.E.K.O.-PC (manual)

Comment thread tests/unit/test_desktop_windows_workflow_contract.py Outdated
Comment thread .github/workflows/build-desktop.yml
@xxynet
xxynet force-pushed the ci/portable-update branch from 198caf8 to a72c78e Compare July 30, 2026 03:37

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (1)
.github/workflows/build-desktop.yml (1)

1038-1057: 🩺 Stability & Availability | 🔵 Trivial

签名密钥缺失就直接炸掉整条 Nightly,记得提前把 secret 配好喵。

PORTABLE_UPDATE_MANIFEST_ED25519_PRIVATE_KEY 现在是硬性必需项,没配就 exit 1,会让 Nightly(含 windows_only 重跑)整体失败,不只是跳过签名这一步喵。这符合 linked repo 文档"客户端强制要求签名 manifest"的约定,只是提醒一下:合并前请确认这个仓库 secret 已经配置好,否则第一次跑 Nightly 就会全军覆没喵。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build-desktop.yml around lines 1038 - 1057, Configure the
PORTABLE_UPDATE_MANIFEST_ED25519_PRIVATE_KEY repository secret before merging so
the “Sign Portable manifests” workflow step can run successfully. Keep the
existing required-secret validation and failure behavior unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build-desktop.yml:
- Around line 820-838: Update the downstream Nightly release configuration to
match the Windows --dir build output: replace the N.E.K.O.exe (Portable) release
text with the generated N.E.K.O_<version>_win.zip Portable package name, and
remove obsolete *.exe upload patterns. Locate the relevant release description
and artifact upload configuration near the existing Windows build steps,
preserving other platform artifacts and messaging.
- Around line 1117-1133: Update the “Create or update Windows nightly release”
step to derive the release notes from inputs.skip_signing instead of hardcoding
“Unsigned.” When creating a new nightly release, use wording that accurately
identifies signed versus unsigned builds while preserving the existing version
and release flow.
- Around line 104-105: Update the version handling in the workflow step
containing the VERSION assignment so inputs.version is passed through the step’s
env configuration and referenced via a shell environment variable, rather than
interpolated directly into the run script. Preserve the existing empty-value
check and VERSION assignment behavior while preventing input contents from being
parsed as shell syntax.

---

Nitpick comments:
In @.github/workflows/build-desktop.yml:
- Around line 1038-1057: Configure the
PORTABLE_UPDATE_MANIFEST_ED25519_PRIVATE_KEY repository secret before merging so
the “Sign Portable manifests” workflow step can run successfully. Keep the
existing required-secret validation and failure behavior unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 667d98e6-a05c-41bf-9985-9315aa967a8f

📥 Commits

Reviewing files that changed from the base of the PR and between 198caf8 and a72c78e.

📒 Files selected for processing (6)
  • .github/workflows/build-desktop-windows.yml
  • .github/workflows/build-desktop.yml
  • .github/workflows/sync-update-release.yml
  • .gitignore
  • docs/deployment/manual-desktop-release.md
  • scripts/build-desktop-release.ps1
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Project-N-E-K-O/N.E.K.O.-PC (manual)
🚧 Files skipped from review as they are similar to previous changes (2)
  • .gitignore
  • docs/deployment/manual-desktop-release.md

Comment thread .github/workflows/build-desktop.yml Outdated
Comment thread .github/workflows/build-desktop.yml
Comment thread .github/workflows/build-desktop.yml

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/unit/test_desktop_windows_workflow_contract.py`:
- Around line 105-112: 补强 windows_nightly["run"] 的断言,验证 SIGNING_NOTE 会根据
REQUESTED_SKIP_SIGNING 的值分支设置为 Signed 或
Unsigned,而不是仅检查两段赋值文本同时存在。确保断言覆盖跳过签名和正常签名两种路径,并保留现有发布说明使用 SIGNING_NOTE 的校验。
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3067faca-5c71-4bae-8486-14763c1baccd

📥 Commits

Reviewing files that changed from the base of the PR and between a72c78e and 5747d9e.

📒 Files selected for processing (2)
  • .github/workflows/build-desktop.yml
  • tests/unit/test_desktop_windows_workflow_contract.py
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Project-N-E-K-O/N.E.K.O.-PC (manual)
🚧 Files skipped from review as they are similar to previous changes (1)
  • .github/workflows/build-desktop.yml

Comment thread tests/unit/test_desktop_windows_workflow_contract.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/sync-update-release.yml (1)

35-51: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

稳定版校验也必须要求 Portable 差分资产喵

当前缺少 N.E.K.O_${VERSION}_linux_x64_appimage_delta.bin 仍会通过校验,但 AppImage 更新通道依赖该 .bin 差分包喵。

  • .github/workflows/sync-update-release.yml#L35-L51: 将 AppImage .bin delta(以及该发布契约要求的其余差分资产)加入 required 喵。
  • tests/unit/test_desktop_windows_workflow_contract.py#L188-L195: 为同一组差分资产增加断言,防止校验清单再次缩减喵。
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/sync-update-release.yml around lines 35 - 51, Extend the
required asset list in .github/workflows/sync-update-release.yml at lines 35-51
to include the AppImage .bin delta and all other Portable delta assets required
by the release contract. Update
tests/unit/test_desktop_windows_workflow_contract.py at lines 188-195 to assert
the same complete delta-asset set, including
N.E.K.O_${VERSION}_linux_x64_appimage_delta.bin, so the validation list cannot
regress.

Source: Linked repositories

🧹 Nitpick comments (1)
scripts/publish-desktop-release-assets.ps1 (1)

106-106: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

改用命名参数调用 Invoke-Checked

PSScriptAnalyzer 已标记这两处定位参数调用喵。请显式使用 -FilePath-Arguments,避免辅助函数签名调整后出现参数绑定歧义喵

Also applies to: 112-113

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/publish-desktop-release-assets.ps1` at line 106, Update both
Invoke-Checked calls in the asset upload flow to use explicit -FilePath and
-Arguments named parameters instead of positional arguments, preserving the
existing ossutil command, asset path, object URL, and metadata arguments.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/publish-desktop-release-assets.ps1`:
- Around line 86-114: 在发布校验流程中补充每个资产的 SHA-256(或等价远端摘要)内容比对,不能只比较名称和 CDN
首字节可达性;同时调整 `Invoke-Checked ossutil 'cp'` 的强制覆盖行为,禁止覆盖已有 immutable
对象,或在确需覆盖时显式执行缓存失效并确认 CDN 返回的新内容,确保同版本资产修正不会继续提供旧字节后仍注册元数据。
- Around line 74-94: 在发布资产校验流程中补充 manifest 与 Ed25519 .sig 的配对验证:对每个 manifest
要求存在对应签名文件,并拒绝没有对应 manifest 的孤立 .sig 文件;将此校验放在上传前、现有 $assets 与 $remoteAssetNames
集合比较之前,并沿用现有 throw 方式报告缺失或孤立资产。
- Line 121: 为发布脚本中的 Invoke-RestMethod 管理 API 注册请求设置有限的超时时间(例如 30
秒),并增加幂等重试机制;确保请求失败或超时后按既定次数重试,避免上传完成后的注册步骤无限阻塞。
- Around line 24-25: 修正发布脚本中 $Channel 与 latest 校验逻辑的不一致:在负责比较 $Tag 与 GitHub
/releases/latest 的校验流程中按 $Channel 分支处理,nightly 不应执行 stable 的 latest 比较;如果脚本仅支持
stable,则同步移除 ValidateSet、默认值及预发布标签相关输入契约中的 nightly 支持。

---

Outside diff comments:
In @.github/workflows/sync-update-release.yml:
- Around line 35-51: Extend the required asset list in
.github/workflows/sync-update-release.yml at lines 35-51 to include the AppImage
.bin delta and all other Portable delta assets required by the release contract.
Update tests/unit/test_desktop_windows_workflow_contract.py at lines 188-195 to
assert the same complete delta-asset set, including
N.E.K.O_${VERSION}_linux_x64_appimage_delta.bin, so the validation list cannot
regress.

---

Nitpick comments:
In `@scripts/publish-desktop-release-assets.ps1`:
- Line 106: Update both Invoke-Checked calls in the asset upload flow to use
explicit -FilePath and -Arguments named parameters instead of positional
arguments, preserving the existing ossutil command, asset path, object URL, and
metadata arguments.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 41810e2d-b18f-4900-a812-d3e7b40dff8b

📥 Commits

Reviewing files that changed from the base of the PR and between 2caf605 and d582551.

📒 Files selected for processing (4)
  • .github/workflows/sync-update-release.yml
  • docs/deployment/manual-desktop-release.md
  • scripts/publish-desktop-release-assets.ps1
  • tests/unit/test_desktop_windows_workflow_contract.py
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Project-N-E-K-O/N.E.K.O.-PC (manual)
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/deployment/manual-desktop-release.md

Comment thread scripts/publish-desktop-release-assets.ps1 Outdated
Comment thread scripts/publish-desktop-release-assets.ps1
Comment thread scripts/publish-desktop-release-assets.ps1 Outdated
Comment thread scripts/publish-desktop-release-assets.ps1 Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/publish-desktop-release-assets.ps1`:
- Around line 78-83: Update the catch block’s response detection in the retry
logic to inspect $_.Exception.PSObject.Properties['Response'] before accessing
the response value, avoiding direct $_.Exception.Response access under
StrictMode. Preserve the existing status-code extraction and retryable
conditions when the Response property exists.

In `@tests/unit/test_desktop_windows_workflow_contract.py`:
- Around line 216-226: Strengthen the assertions in the desktop Windows workflow
contract test to verify the publish path actually invokes the hash validation,
OSS object-existence check, and timeout configuration, in the required execution
order, rather than merely containing their definitions or command text. Replace
the narrow single-quote ValidateSet exclusion with a check that rejects the
equivalent validation in either quote style, or use PowerShell AST/Pester
assertions for these behavioral contracts.
- Around line 119-123: Strengthen the nightly asset assertions in the
full_nightly contract test so excluding the portable executable is validated in
the actual staging directory or upload manifest, not merely by checking that the
literal filename is absent from full_nightly["run"]. Preserve the existing
REQUESTED_SKIP_SIGNING and SIGNING_NOTE checks, and retain the allow-list
assertion for N.E.K.O_*_win.zip while ensuring N.E.K.O.exe cannot be selected
through wildcards or variables.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1bdf80ab-7a6a-4846-ac02-7fe4a1baf921

📥 Commits

Reviewing files that changed from the base of the PR and between d582551 and d629e5e.

📒 Files selected for processing (4)
  • .github/workflows/build-desktop.yml
  • docs/deployment/manual-desktop-release.md
  • scripts/publish-desktop-release-assets.ps1
  • tests/unit/test_desktop_windows_workflow_contract.py
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Project-N-E-K-O/N.E.K.O.-PC (manual)
🚧 Files skipped from review as they are similar to previous changes (2)
  • docs/deployment/manual-desktop-release.md
  • .github/workflows/build-desktop.yml

Comment on lines +78 to +83
catch {
$statusCode = $null
if ($_.Exception.Response) {
$statusCode = [int]$_.Exception.Response.StatusCode
}
$retryable = $null -eq $statusCode -or $statusCode -eq 408 -or $statusCode -eq 429 -or $statusCode -ge 500

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file outline/size =="
wc -l scripts/publish-desktop-release-assets.ps1 || true
rg -n "Set-StrictMode|function Invoke-UpdateMirrorSync|Invoke-UpdateMirrorSync|\.Response|TaskCanceled|catch" scripts/publish-desktop-release-assets.ps1 || true

echo
echo "== relevant section =="
sed -n '30,115p' scripts/publish-desktop-release-assets.ps1 | cat -n

Repository: Project-N-E-K-O/N.E.K.O

Length of output: 1925


🏁 Script executed (no clone):

#!/bin/bash
set -euo pipefail

echo "== PowerShell strict property access probe =="
if command -v pwsh >/dev/null 2>&1; then
  pwsh -NoProfile -Command '
    Set-StrictMode -Version Latest
    try {
      $value = $null
      try {
        $null = (new-object Object).Response
      } catch {
        $value = $_.Exception.GetType().FullName
      }
      $value
    } catch {
      "Outer: $($_.Exception.GetType().FullName): $($_.Exception.Message)"
    }
  '
else
  echo "pwsh not available"
fi

Length of output: 327


🌐 Web query:

PowerShell StrictMode PropertyNotFoundException accessing non-existent property returns null throws only StrictMode

💡 Result:

In PowerShell, the behavior when accessing a non-existent property depends on whether Set-StrictMode is enabled and the version configured [1][2]. Standard Behavior When Set-StrictMode is off (or set to version 1.0), attempting to access a non-existent property on an object returns $null without raising an error [3][2]. This is the default behavior in PowerShell, intended to allow for flexible, ad-hoc scripting [2]. Strict Mode Behavior When Set-StrictMode is set to version 2.0 or higher (including 'Latest'), PowerShell prohibits references to non-existent properties [1][4]. In this state, attempting to access a non-existent property causes a terminating error, typically manifesting as a PropertyNotFoundException [3][5][6]. Key details: - Version 1.0: Only restricts uninitialized variables (excluding those in strings) [1][2]. Accessing a non-existent property still returns $null [3][2]. - Version 2.0 and above: Prohibits references to uninitialized variables and non-existent properties, and enforces strict function call syntax [1][2][4]. - Scope: Set-StrictMode affects only the current scope (and its children) where it is defined, not the entire engine [2][6]. If you encounter this exception in your scripts, it indicates that StrictMode has been enabled (likely via Set-StrictMode -Version 2.0 or higher) in that scope [5][7]. If the goal is to safely check for a property's existence, you can use cmdlets like Get-Member to verify the property before access, rather than relying on the default $null return value [7]. [1][7]

Citations:


🌐 Web query:

PowerShell PSObject Properties indexer accessing missing property StrictMode

💡 Result:

In PowerShell, accessing a non-existent property on an object normally returns $null [1][2][3]. However, when StrictMode (version 2.0 or higher) is enabled, referencing a non-existent property generates a terminating PropertyNotFoundException [2][3][4]. To safely access properties or check for their existence while StrictMode is enabled, you can use the PSObject.Properties collection [1][5]. Recommended Approaches: 1. Using PSObject.Properties for Existence Checks The PSObject.Properties collection provides a safe way to check if a property exists without triggering a StrictMode error [1][5]. Example: if ($myObject.PSObject.Properties['PropertyName']) { Write-Host "Property exists and is not null" } 2. Using Member Access with Null-Coalescing or Null-Conditional Operators If you are using PowerShell 7+, you can use the null-conditional operator (?.) to safely access properties [6]. This allows you to attempt to access a property and return $null if the object or the property does not exist, avoiding the StrictMode error. Example: $value = $myObject?.PropertyName 3. Checking via Get-Member You can also use Get-Member to verify a property's existence before accessing it [1][5]. Example: if ($myObject | Get-Member -Name 'PropertyName' -MemberType Properties) { $value = $myObject.PropertyName } Why StrictMode affects this: Set-StrictMode is designed to enforce best practices by prohibiting references to uninitialized variables and non-existent object properties [2][7]. When version 2.0 or higher (including 'Latest') is active, the engine explicitly converts what would otherwise be a silent $null return into a terminating error to help developers catch typos and logic errors early [3][8][4].

Citations:


PSObject.Properties['Response'] 避开严格模式下的属性访问爆炸喵。

脚本开启了 Set-StrictMode -Version Latest,当异常没有 Response 属性时,$_ .Exception.Response 会先抛 PropertyNotFoundException,导致重试判断逻辑跳过喵。像建议的用法那样先通过属性集合探测是否存在再取值,可避免在 catch 里二次抛异常喵。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/publish-desktop-release-assets.ps1` around lines 78 - 83, Update the
catch block’s response detection in the retry logic to inspect
$_.Exception.PSObject.Properties['Response'] before accessing the response
value, avoiding direct $_.Exception.Response access under StrictMode. Preserve
the existing status-code extraction and retryable conditions when the Response
property exists.

Comment on lines +119 to +123
full_nightly = nightly_steps["Create nightly release"]
assert full_nightly["env"]["REQUESTED_SKIP_SIGNING"] == "${{ inputs.skip_signing }}"
assert 'SIGNING_NOTE="unsigned"' in full_nightly["run"]
assert "N.E.K.O_*_win.zip" in full_nightly["run"]
assert "N.E.K.O.exe" not in full_nightly["run"]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

补强 nightly 资产排除断言,避免通配符绕过喵

Line 123 只验证 N.E.K.O.exe 这个字面量不在脚本文本中;如果发布命令通过 release/* 或变量上传,单文件 Portable 可执行文件仍可能被上传,而测试照样通过喵。请断言实际暂存目录或上传清单明确排除该文件,并保留对 N.E.K.O_*_win.zip 的允许列表校验喵。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/test_desktop_windows_workflow_contract.py` around lines 119 - 123,
Strengthen the nightly asset assertions in the full_nightly contract test so
excluding the portable executable is validated in the actual staging directory
or upload manifest, not merely by checking that the literal filename is absent
from full_nightly["run"]. Preserve the existing REQUESTED_SKIP_SIGNING and
SIGNING_NOTE checks, and retain the allow-list assertion for N.E.K.O_*_win.zip
while ensuring N.E.K.O.exe cannot be selected through wildcards or variables.

Source: Linked repositories

Comment on lines +216 to +226
assert "function Test-OssObjectExists" in script
assert "function Get-Sha256" in script
assert "Get-FileHash -LiteralPath $Path -Algorithm SHA256" in script
assert "Portable manifest is missing its signature asset" in script
assert "Portable signature has no matching manifest" in script
assert "Refusing to overwrite immutable OSS object" in script
assert "--max-time', '1800'" in script
assert "Invoke-UpdateMirrorSync" in script
assert "-TimeoutSec 30" in script
assert "ValidateSet('stable', 'nightly')" not in script
assert "/stable/sync" in script

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

验证发布脚本的真实调用关系,而不是只搜字符串喵

Lines 216-224 只检查函数名和命令片段存在,无法证明哈希校验、对象存在性检查及超时参数实际被发布路径调用;Line 225 也只排除一种特定引号写法,等价的双引号写法仍会误通过喵。请改为校验调用点、参数和执行顺序,或使用 PowerShell AST/Pester 做行为级契约断言喵。Based on learnings:测试断言应至少与所声明验证的不变量同等强度喵。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/unit/test_desktop_windows_workflow_contract.py` around lines 216 - 226,
Strengthen the assertions in the desktop Windows workflow contract test to
verify the publish path actually invokes the hash validation, OSS
object-existence check, and timeout configuration, in the required execution
order, rather than merely containing their definitions or command text. Replace
the narrow single-quote ValidateSet exclusion with a check that rejects the
equivalent validation in either quote style, or use PowerShell AST/Pester
assertions for these behavioral contracts.

Source: Learnings

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

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants