【免费下载链接】stashbase
An open-source, local-first writing workspace where you can write with Claude Code and Codex, drawing on your own sources and past work.
StashBase 是一个开源、本地优先的 AI 写作工作台,让你调用 Claude Code 与 Codex,结合自己的资料与过往作品进行写作。它的桌面端要同时交付 macOS、Windows、Linux 三平台安装包,还牵涉 Apple Developer ID 签名、公证(Notarization)、Windows Authenticode 以及一套独立版本化的 PDF/OCR 组件。本文拆解 StashBase 的整套发布流水线:一次version bump提交之后,如何从 CI 门禁一路自动化跑到签名打包、完整性校验与上架,全程无需人工干预。
一、流水线全景:一次提交如何变成三份安装包
StashBase 把整套发布逻辑沉淀在一份"发布手册"里,见 code-review/release-pipeline.md。整体形状非常清晰:
main 上的 version bump 提交 → CI push 运行成功(门禁) → Release 工作流创建对应的 vX.Y.Z tag → 创建空的 Draft Release → 独立版本化的 PDF/OCR 组件集合就绪 → macOS / Linux / Windows 并行打包 + 冒烟测试 → 校验完整的「不可变更新集」 → Release 转为公开 → Homebrew cask 指向公开 DMG💡 核心设计原则:源校验(Source CI)与平台打包(Release Packaging)是两套完全独立的工作流。一个安装包只能从"其对应提交已经跑通
ci.ymlpush 运行"的 tag 构建而来,绝不复用分支、也不为一次纯版本号提交重跑整套源 CI。
这套机制保证了三件事:版本资产不可变(immutable)、更新元数据与安装包来自同一 tag、客户端永远不会先看到"新版号"却拿不到对应文件。
二、第一道门禁:Source CI 与"绿 CI"校验
一切从main的推送开始。.github/workflows/ci.yml 用fail-fast: false跑一个四平台矩阵(ubuntu-latest、windows-latest、macos-latest、macos-15-intel),并设置 30 分钟超时。Linux 这一路承担最重的pnpm check:web(含边界、体积、命名规范、覆盖率、结构可达性、类型检查、生产构建),其余平台复用行为测试与原生构建。
门禁的真正"闸门"由可复用工作流 .github/workflows/release-ci-gate.yml 执行,其实现是 scripts/require-green-ci.mjs:
- 把 release tag 解析成精确的 commit SHA(支持轻量 tag 与附注 tag,最多下钻 5 层);
- 轮询该 SHA 的
ci.ymlpush 运行,等到出现conclusion: success; - 若该 SHA 的运行是失败/取消/超时,或 15 分钟内等不到,直接失败关闭(fail closed)。
换句话说,任何"未跑绿 CI 的提交"都无法进入打包阶段,这从根上杜绝了"半成品 tag 流出"。
三、自动打 tag:只有 version bump 才会触发发布
scripts/select-release-tag.mjs 里的automaticReleaseTag是发布协调器的"触发器"。它非常克制——只有同时满足以下条件才返回 tag:
- 事件是
push、conclusion为success、分支是main; - 提交信息严格等于
chore: bump to <version>,且前后版本确实发生了变化。
这样"随手改一下package.json"或某个 PR 都不会误触发布。随后:
- 若已存在同名 tag,其指向的 SHA 必须与"跑绿 CI 的那个提交"完全一致,否则报错(绝不移动 tag);
- 否则通过 GitHub API 在精确的
head_sha上创建vX.Y.Z; - 还会比对线上
latestRelease,避免 CI 重跑把稳定更新通道往回拉。
手动重试同样走门禁:在 release.yml 的workflow_dispatch里填入一个已存在的 tag 即可,仍会被release-ci-gate拦截校验。
四、独立分发的 PDF/OCR 组件:一个"永不 latest"的 pre-release
StashBase 的本地 PDF 文本抽取与 OCR 组件独立于 App 版本。由 .github/workflows/extractor-components.yml 负责,版本号形如0.0.0-extractor.<input-sha256>——输入摘要覆盖组件源码、Python 约束、构建/签名配方与依赖解析结果。App 版本号或纯前端 lockfile 变化都不会使其失效,因此能跨多个 App 版本复用,显著省构建时间。
流程由 scripts/prepare-extractor-release.mjs 驱动:
- 命中(已有完整公开集)→ 直接复用,不重建、不重签、不重传;
- 未命中→ 在四平台矩阵构建、对 macOS 签名+公证、校验哈希后,只上传到草稿(draft),校验通过后转成一个永不为 latest 的 pre-release。
各平台 App 打包任务会按"应用钉住的 manifest"下载该组件、校验身份/大小/哈希并内嵌。这样一份"组件更新"就不会搅动整条桌面应用发布线。
五、三平台并行打包:签名、公证与可选 Authenticode
release.yml的macos、windows、linux三个 job 在extractor就绪后并行启动,各自调用一个可复用工作流。
macOS(release-macos.yml):矩阵区分 arm64(macos-15)与 x64(macos-15-intel)。用 Developer ID Application 身份 + Hardened Runtime + 安全时间戳签名,再走 Apple 公证并 stapler。两个架构各自产出latest-mac.yml,最后由 scripts/merge-macos-artifacts.mjs 校验双架构版本号、架构与载荷哈希后,合并成一份latest-mac.yml,避免相互覆盖更新通道。发布所需密钥:MAC_CSC_LINK、MAC_CSC_KEY_PASSWORD以及公证用的APPLE_API_KEY_P8 / _ID / _ISSUER。
Windows(release-windows.yml):产出 NSIS 安装器(*.exe)+blockmap+latest.yml。签名是可选但失败关闭的升级项:若配置了WIN_CSC_LINK与WIN_CSC_KEY_PASSWORD二者之一则要求二者齐全,并用Get-AuthenticodeSignature逐个校验每个 NSIS 可执行文件;未配置则发布未签名安装器,更新通道依旧可用。
Linux(release-linux.yml):在ubuntu-22.04(定义最老受支持原生 ABI)上构建.deb+.AppImage,并校验latest-linux.yml内嵌了 AppImage 的blockMapSize。
🛡️ 每个平台打包完成后都会跑"已打包冒烟测试" scripts/smoke-packaged-server.mjs:启动已打包应用的服务、加载 Electron 主进程依赖图、真实调用 PDF/OCR 与 DOCX 转换,确保"冻结后的运行"真的可用,而不仅是"能构建"。
六、最后的守门员:校验完整更新集并原子发布
所有平台 job 完成后,publish-release任务扮演最后一道守门员(见 release.yml#L129-L168)。它先确认 Release 仍是draft,然后逐一核对"不可变更新集"是否齐全:
| 平台 | 必须存在的资产 |
|---|---|
| macOS | latest-mac.yml+ arm64/x64 各自的.dmg与.zip |
| Windows | latest.yml+*-win-*.exe+ 对应.blockmap |
| Linux | latest-linux.yml+*-linux-*.AppImage+*.deb |
任何一项缺失即报错退出;全部通过后,才执行gh release edit --draft=false --latest原子地把 Release 转为公开。随后publish-homebrew下载已公开的 DMG 并更新 Homebrew cask(需要HOMEBREW_TAP_TOKEN)。
所有资产都经由 scripts/upload-release-assets.mjs 上传:单个资产 15 分钟卡死即中止、按名称重试、已存在且大小一致的资产保留(重跑不重建)、大小不一致则直接失败——因为版本资产是不可变的。
七、本地也能跑:验证流水线改动
如果你想验证发布管线本身的改动,手册建议跑这一组契约测试:
pnpm test:release-gate pnpm test:toolchain pnpm test:package-inputs pnpm test:macos-signing pnpm test:windows-signing pnpm test:updates pnpm typecheck前端工具链被精确钉在一个固定的 Vite+ 发行版本上,toolchain/vite-plus.json 记录它解析到的工具清单,pnpm test:toolchain会做深度比对,任何"悄悄换工具"都会让构建失败。
需要复现整套流程时,可以先克隆仓库(本地只读分析):
git clone https://gitcode.com/gh_mirrors/st/stashbase cd stashbase pnpm install八、发布后:残留的手动体检
自动化能覆盖构建、签名、公证、校验与上架,但仍有少量"需要真机"的接缝留给维护者:真实 Intel macOS 12–14 的进入/编辑体验、代表性 OCR 质量、N→N+1 的在应用内更新等。这些清单集中在 release-checklists/ui-sanity.md。此外,一旦发布触及检索排序、分块、嵌入模型或 Provider 集成,还应在上架前跑pnpm eval:semantic-retrieval保留语义质量报告作为发布证据。
小结
StashBase 的发布流水线把"信任"做成了可执行、可校验、可失败的工程约束:
- 门禁前置:没有绿 CI,就没有 tag;
- 触发克制:只有严格的 version bump 才会自动发布;
- 组件解耦:PDF/OCR 独立版本、跨版本复用,永不 latest;
- 平台并行:三平台独立打包、各自签名/公证/冒烟;
- 原子发布:完整更新集校验通过,才把 draft 一次性转为公开并联动 Homebrew;
- 资产不可变:版本资产绝不覆盖,重跑只重试、不篡改。
对使用者来说,这意味着你从 docs/installation.md 下载或brew install到的每一份安装包,背后都经过了一条"失败即停、绝不发半成品"的自动化流水线。
【免费下载链接】stashbase
An open-source, local-first writing workspace where you can write with Claude Code and Codex, drawing on your own sources and past work.
相关推荐
PhotoCraft 发布工程:从版本管理到多平台签名打包的完整发布流水线
PhotoCraft 发布工程:从版本管理到多平台签名打包的完整发布流水线 PhotoCraft(用纯 Rust 实现的 Photoshop 清洁室重实现)的发
图像处理桌面应用clicky 项目(makesomething)自动化 macOS 发布流水线:release.sh 从签名、DMG、公证到 Sparkle appcast 全流程解析
clicky 项目(makesomething)自动化 macOS 发布流水线:release.sh 从签名、DMG、公证到 Sparkle appcast 全
RustNet 发布流程全解:从 Changelog 维护到跨平台自动化发布流水线
RustNet 发布流程全解:从 Changelog 维护到跨平台自动化发布流水线 本篇基于 RustNet 仓库中的 RELEASE.md https://l
网络可观测性
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考