- 桌面应用
【免费下载链接】Vortex
Vortex Development
适用对象:Vortex 的发布经理(release manager)及所有需要手动干预发布流程的维护者。核心主题:当 Vortex 的稳定版(stable release)发布时,CI 自动化完成了哪些步骤、哪些操作仍必须由人工完成,以及每一步背后的安全护栏与故障排查手段。读完收获:掌握 Vortex 的"构建打包 → 创建草稿发布 → 上传 R2 → 取消草稿(go-live)→ Nexus Mods 自动上传"的完整发布链路,理解
released/prereleased事件语义、预发布与稳定版的通道隔离机制,并能独立处理发布中遇到的最常见问题。
一、发布流程总览:自动化做了什么,人工还剩什么
Vortex 的发布流程被刻意设计为**"自动打包 + 手动 go-live"**两段式。整个流程围绕三个 GitHub Actions 工作流文件展开,全部位于 .github/workflows/ 目录:
| 工作流 | 文件 | 触发方式 | 职责 |
|---|---|---|---|
| Package | package.yml | workflow_dispatch(手动) | 构建并签名安装包、创建 GitHub 草稿发布、上传安装包到 R2 |
| Manual Upload Release to R2 | upload-release-to-r2.yml | workflow_dispatch(手动,兜底) | 按 release tag 重新上传安装包到 R2 |
| Nexus Mods 上传 | 由 GitHubreleased事件驱动的发布脚本 | 事件触发(不可手动触发) | 把安装包发布到 Nexus Mods 文件页 |
官方文档 publishing-releases.md 将整体节奏概括为两大步:
第 1 步:Package(自动化)package.yml负责构建、签名安装包,并在 GitHub 仓库与Vortex-Staging仓库各创建一个draft release(草稿发布),同时把安装包上传到 R2(Cloudflare R2 对象存储)。这一步之后,安装包已经"暂存"在 R2 中,但还不是对外可用的下载链接。每个动作都是一个独立的 dispatch 输入参数(release、staging-release、upload-to-r2),且默认全部开启。
第 2 步:Undraft(人工 go-live)发布经理在 GitHub 上手动取消草稿状态(undraft)。这是唯一的"上线动作":
- 对稳定版而言,取消草稿会立即触发
released事件,进而触发Nexus Mods 上传; - 同时让该发布对自动更新器的stable 通道可见。
发布后没有第二步人工操作——但R2 下载与Nexus Mods 上传是两条彼此独立的发布路径(详见下文"两条独立的公开路径")。
1.1 Package 工作流的三个独立开关
package.yml 的workflow_dispatch输入定义清楚地展示了每个动作的独立性与默认值:
on: workflow_dispatch: inputs: version: description: "The version to release (eg: 'v1.0.0')." required: true type: string create-artifacts: description: "Create artifacts?" required: true type: boolean default: true use-codesigning: description: "Use codesigning?" required: false type: boolean default: true release: description: "Create a draft release?" required: false type: boolean default: true staging-release: description: "Create a draft staging release?" required: false type: boolean default: true upload-to-r2: description: "Upload the installer to R2?" required: false type: boolean default: true参数说明:
version(必填):要发布的版本,格式如v1.0.0。该版本号贯穿整个打包过程——rawVersion(去掉前导v的版本,如2.4.0)会同时写入@vortex/main与@nexusmods/vortex-api的package.json(见 .github/actions/package/action.yml 的pnpm version调用)。create-artifacts(默认true):是否生成未打包目录(win-unpacked)工件。use-codesigning(默认true):是否使用代码签名。从源码看,若请求签名但ES_USERNAME等签名密钥不可用,工作流会打印警告并降级为无签名构建(见 package action 的package:nosign分支),而不会中断流程。release/staging-release(默认true):是否在 GitHub 主仓库 /Nexus-Mods/Vortex-Staging仓库创建草稿发布。upload-to-r2(默认true):是否把安装包上传到 R2。
1.2 预发布标记由版本号自动推导,不要手动改
Package 工作流创建发布时,prerelease标志完全由版本号自动推导,发布经理不应手工修改:
prerelease: ${{ contains(needs.build.outputs.raw-version, '-') }} draft: true规则(见 package.yml):
- 版本号含连字符后缀(如
2.5.0-beta.1)→ 标记为pre-release; - 版本号无后缀(如
2.5.0)→ 标记为stable。
这一推导规则是整个发布体系的分水岭:预发布标志决定了 GitHub 触发的是released还是prereleased事件,进而决定 Nexus Mods 上传是否发生(见下文)。同样的"-即预发布"约定也贯穿其他配套工作流,例如 winget-release.yml 用!contains(..., '-')拒绝预发布进入 WinGet、fingerprint-released.yml 用contains(inputs.tag, '-')判断预发布指纹。
二、发布产物:只有安装包去 Nexus,latest.yml留在 GitHub
2.1 产物清单
一次 Package 运行产生的产物由 package.yml 的 Installer Artifact 步骤定义:
path: | ./dist/vortex-setup-*.*.*.exe ./dist/vortex-setup-*.*.*.exe.blockmap ./dist/latest.yml if-no-files-found: errorvortex-setup-<version>.exe:NSIS 安装包,命名如vortex-setup-2.4.0.exe。这是唯一被上传到 Nexus Mods 的产物。vortex-setup-<version>.exe.blockmap:差分下载元数据。如 package.yml 中的注释所述,blockmap 使自动更新器能够只下载安装包中发生变化的块(差分更新),前提是上一版本的 blockmap 也已发布。docs/updater.md 中进一步提到,一次补丁更新通常只需传输安装包约10%的体积。latest.yml:electron-builder 生成的自动更新元数据文件,服务于 Vortex 自动更新器,始终留在 GitHub Releases,不会上传 Nexus。
2.2 为什么不存在alpha.yml/beta.yml
一个值得注意的细节:整个构建体系只产出latest.yml这一个元数据文件。发布文档明确强调——没有按通道区分的alpha.yml/beta.yml;无论 beta 还是 stable,每个发布都携带同一份latest.yml。
这与自动更新器的实现方式直接相关:Vortex 不再依赖 electron-updater 自带的 GitHub provider 去"按发布日期挑最新版本",而是自行实现了一个发布解析器(src/main/src/extensions/autoupdater/releaseResolver.ts),通过 GitHub Releases API 按通道语义 + semver 规则选择最高合格版本(详见 docs/updater.md)。因此元数据文件无需按通道区分——通道逻辑完全由发布解析器在运行时决定。
三、两条独立的公开路径:R2 下载与 Nexus Mods 上传
取消草稿之后,Vortex 的发布通过两条互不依赖的路径对公众可见:
3.1 路径 A:R2 下载(网站直链)
安装包在第 1 步就已被上传到 R2 的s3://nexusmodsapp/存储桶(Cloudflare R2,兼容 S3 API)。上传逻辑见 package.yml:
- name: Upload to R2 run: | installer=$(ls installer/vortex-setup-*.exe) echo "Uploading $installer" aws s3 cp "$installer" s3://nexusmodsapp/ --endpoint-url "${{ secrets.NEXUSMODS_R2_ENDPOINT }}" env: AWS_ACCESS_KEY_ID: ${{ secrets.NEXUSMODSAPP_R2_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.NEXUSMODSAPP_R2_SECRET_ACCESS_KEY }} AWS_DEFAULT_REGION: auto但上传 ≠ 上线。安装包真正对外可见,要等到网站仓库(website repo)中的下载标签(download tag)指向新版本那一刻。也就是说:R2 中的对象始终存在(且被新版本覆盖),但 Nexus Mods 官网的"下载 Vortex"按钮链接到哪个版本,由网站仓库侧的标签控制——这一步是独立于 GitHub 发布流程的。
3.2 路径 B:Nexus Mods 文件页上传
取消草稿触发 GitHub 的released事件后,发布脚本将安装包上传到 Nexus Mods 的文件页。两条路径互不依赖:即使 R2 标签尚未更新,Nexus 上传也会照常发生,反之亦然。
3.3 重要限定:仅稳定版
- Beta / Alpha 版本只通过 GitHub Releases 与 Vortex 自动更新通道分发,永远不会上传到 Nexus Mods。
- 原因在于事件语义:取消预发布的草稿触发的是
prereleased事件而非released,因此 beta 发布永远到达不了 Nexus Upload API。
仓库中多个事件驱动的工作流都体现了同样的语义约定:
| 工作流 | 监听事件 | 预发布处理 |
|---|---|---|
| Nexus Mods 上传脚本 | released | 预发布不触发 |
| winget-release.yml(WinGet 发布) | released | 额外用!contains(tag, '-')双重保险拒绝误标为完整发布的 beta |
| fingerprint-released.yml(指纹标记) | published | 兼容预发布(prerelease标志显式传入) |
| linear-release.yml(Linear 同步) | published | 兼容预发布 |
| annotate-mixpanel-release.yml(Mixpanel 注解) | published | stable 与 beta 使用不同 annotation tag |
注意released与published的差异:published在发布被发布时触发(含草稿首次发布),而released仅在发布从草稿/预发布变为正式发布时触发——这正是 Nexus 上传选择released的原因。
四、多发布日的发布顺序:按发布日期选版本,不是按版本号
发布文档给出了一个必须遵守的现场纪律,它源于自动更新器当前实现的行为:
Vortex 安装在现场(field)选择更新时,在 beta 通道上按发布日期选取最新发布,而不是按版本号。
这意味着:如果同一天既发布了 beta、又发布了稳定版热修复(hotfix),那么"用户最终应该停留的版本"必须最后取消草稿。否则 beta 用户会被提供一个更旧(但发布日期更新)的版本。
例如某天计划同日发布2.6.0-beta.2与稳定热修复2.5.1:若先取消2.5.1的草稿、后取消2.6.0-beta.2的草稿,beta 通道按发布日期排序会选中2.5.1——尽管2.6.0-beta.2版本号更高,beta 用户却被回退到旧版。因此必须先取消 beta 草稿,最后再取消稳定版草稿。
这一"按发布日期而非版本号"的根因,在 docs/updater.md 中有明确交代:这是旧版 electron-updater GitHub provider 的默认行为,也是当年"把降级当升级推荐"(offers a downgrade that's really an upgrade)Bug 的根源。Vortex 现已用自研解析器(releaseResolver.ts)重写了选版逻辑,其中 beta/next 通道的规则是"取全局最高版本,新稳定版可以压过旧 beta"——但文档明确指出,在更新器重构(updater rework)覆盖大多数安装之前,发布经理仍需遵守"最后发布用户应停留的版本"的顺序纪律。
五、安全护栏(Safety Guardrails)
发布脚本内置了多层安全护栏,防止误操作把不该发布的内容发布出去。官方文档以表格形式列出,全部规则如下:
| 护栏 | 说明 |
|---|---|
| Stable releases only(仅稳定版) | released事件不会为预发布触发。 |
| Draft/prerelease rejection(草稿/预发布拒绝) | 脚本会重新检查该发布,拒绝草稿与预发布状态。 |
| Changelog required(必须存在更新日志) | 若CHANGELOG.md中没有该版本的条目,发布直接失败。 |
| Identifiers required(必须存在标识符) | 若 Nexus 的 file ID / mod ID 变量未设置,发布直接失败。 |
| Paired overrides(覆盖项必须成对) | file-id / mod-id 覆盖必须同时设置两者,保证它们停留在同一个 mod 页面。 |
| Concurrency control(并发控制) | 同一时刻只允许一个发布运行(publish-nexusconcurrency group)。 |
| Dry-run default(默认试运行) | 手动触发运行默认跳过实际上传,除非把dry-run设为false。 |
结合仓库代码可以更深入地理解其中几条的实现依据:
- 版本号与标志的一致性:
prerelease标志由版本号自动推导(contains(raw-version, '-')),配合脚本的"重新检查并拒绝草稿/预发布",从源头杜绝"误把 beta 当 stable 上传"。 - Changelog 检查:仓库根目录的 CHANGELOG.md 遵循Keep a Changelog格式与Semantic Versioning规范(见文件头注释)。发布脚本校验该文件必须包含目标版本的条目——这保证了 Nexus 文件页的更新说明与 GitHub 发布说明一致。
- Dry-run 默认值:这与仓库中其他发布类工作流的惯例一致。例如 fingerprint-released.yml 与 linear-release.yml 的
workflow_dispatch输入中,dry-run都默认true,把"手动触发默认不动真格"确立为全仓库的通用安全约定。
六、故障排查(Troubleshooting)
发布文档针对最常见的四类失败场景给出了明确处置方法:
6.1 "Release X is a draft"(发布仍是草稿)
原因:发布尚未取消草稿状态。处置:先去 GitHub 上取消草稿(undraft),再重试发布脚本。
6.2 "Release X is marked as a prerelease"(发布被标记为预发布)
原因:beta 版本永远不会被发布到 Nexus Mods——这是设计行为,不是故障。处置:检查该发布的 tag。若确实需要发布稳定版,确认 tag 是否为无-后缀的裸版本号(如2.5.0),并按规范重新打包。
6.3 "No .exe installer asset found"(找不到 .exe 安装包资源)
原因:GitHub Release 上没有安装包资源。处置:检查Package工作流是否成功完成、并确实把安装包附加到了发布上。可对照 package.yml 的 Installer Artifact 步骤(vortex-setup-*.*.*.exe+.blockmap+latest.yml,if-no-files-found: error)确认产物是否齐全。
6.4 安装包在 R2 中缺失
原因:第 1 步的 R2 上传环节失败或未执行。处置:使用Manual Upload Release to R2工作流(upload-release-to-r2.yml)按发布 tag 手动重新上传。该工作流正是为此保留的兜底方案,其流程为:安装 gh 与 AWS CLI →gh release download <tag> --pattern "vortex-setup-*.exe"拉取安装包 →aws s3 cp上传到s3://nexusmodsapp/。它只需要一个tag输入(如v2.1.1),非常适合修复漏传场景。
七、与相邻发布组件的协作关系
理解 Nexus 发布流程,还需要把它放到 Vortex 更宽的发布生态中看。取消草稿这一动作,同时驱动着多个下游系统(各自监听不同的事件类型):
- 自动更新器(Auto-Updater):稳定版上线后进入 stable 通道候选。Vortex 的更新解析器(releaseResolver.ts)通过 GitHub Releases API 选版,稳定通道取最高非预发布版本,并排除"预发布标志与版本后缀不一致"的错误发布;草稿、非 semver tag、缺少安装包或
latest.yml的发布一律不可选(见 docs/updater.md)。下载环节由 electron-updater 基于latest.yml+ blockmap 执行差分下载并校验 sha512 与 Authenticode 签名。 - WinGet(winget-release.yml):稳定版发布时向
microsoft/winget-pkgs提交清单,使用 komac 生成并叠加 .github/winget/ 下的 overlay 字段。 - 指纹统计(fingerprint-released.yml):发布后把该版本的指纹行写入 ClickHouse。
- Linear 项目同步(linear-release.yml):发布后把对应 issue 同步到 Linear release 并标记为已发布。
- Mixpanel 注解(annotate-mixpanel-release.yml):为 stable 与 beta 分别创建分析注解,便于仪表盘分别开关。
这些工作流的共同点再次印证了发布文档的核心结论:稳定版与预发布的区分(-后缀 → prerelease)是贯穿所有下游系统的唯一事实来源,而 Nexus Mods 上传是其中唯一"严格拒绝预发布"的环节。
八、给发布经理的操作清单
综合以上分析,一次标准的 Vortex 稳定版发布流程如下:
- 触发 Package:在 Actions 页面手动运行
Package工作流,填写version(如v2.5.0),其余开关保持默认(release/staging-release/upload-to-r2均为true),等待构建、签名、草稿发布与 R2 上传完成。 - 验证产物:确认 GitHub(含
Vortex-Staging)上的草稿发布携带vortex-setup-<version>.exe、.blockmap与latest.yml;确认CHANGELOG.md已包含该版本的条目(这是 Nexus 上传的前置条件)。 - 排定发布顺序:若同日有多个版本要上线,先取消 beta/预发布的草稿,最后取消用户最终应停留版本的草稿。
- 取消草稿(go-live):在 GitHub 上取消稳定版发布的草稿状态。
released事件随即触发 Nexus Mods 上传。 - 更新网站下载标签:将网站仓库的 download tag 指向新版本,使 R2 中的安装包成为官网直链的下载对象。
- 按需跟进下游:确认 WinGet PR、指纹写入、Linear 同步与 Mixpanel 注解按各自事件正常触发;若 R2 漏传,运行Manual Upload Release to R2兜底。
整个过程的核心设计思想值得提炼:打包全自动、上线半自动(一个 undraft 动作)、通道靠版本号自动推导、Nexus 上传只认稳定版——四者共同把"发布事故"的可能面压缩到最小,同时保留了发布经理在任何环节手动兜底的能力。
- 桌面应用
【免费下载链接】Vortex
Vortex Development
相关推荐
IPTVnator Release Cut 发布流程实战:从变更笔记到草稿 Release 的完整契约
IPTVnator Release Cut 发布流程实战:从变更笔记到草稿 Release 的完整契约 导读 本文基于 IPTVnator 仓库中的 relea
音视频视频桌面应用前端3步快速上手:Ryujinx任天堂Switch模拟器终极使用指南
3步快速上手:Ryujinx任天堂Switch模拟器终极使用指南 Ryujinx是一款用C 编写的开源Nintendo Switch模拟器,致力于为玩家提供出色
硬件仿真图形学quiche GitHub Draft Release 自动化指南:从版本提交哈希到草稿发布
quiche GitHub Draft Release 自动化指南:从版本提交哈希到草稿发布 本篇指南讲解 quiche 仓库中如何通过 .opencode/s
网络通信后端
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考