发布阶段 A
issue #97 的阶段 A 负责把发布链路的基础设施落地:tag 白名单、本地发布命令、.env.production、外置硬盘存储根、7131 下载服务、7132 docs 静态服务,以及统一的 release metadata。当前默认发布路径是在当前电脑本地执行命令,不依赖 GitLab CI、pipeline、runner 或 GitLab Release。
Tag 白名单
阶段 A 只接受以下 tag 前缀:| 发布单元 | tag 格式 | 版本来源 |
|---|---|---|
workflow-code-core | workflow-code-core/vX.Y.Z | 根目录 package.json |
workflow-code-cli | workflow-code-cli/vX.Y.Z | server/cli/package.json |
server | server/vX.Y.Z | server/package.json |
server-web | server-web/vX.Y.Z | server/web/package.json |
docs | docs/vX.Y.Z | tag 本身 |
app | app/vX.Y.Z | app/package.json |
docs,其余发布单元都会通过本地 node scripts/release.mjs assert-tag --tag <unit>/vX.Y.Z 校验 tag 版本和对应 package.json.version 一致。不一致时本地发布命令直接失败。
生产 env 与外置硬盘
发布态必须使用.env.production。真实生产配置默认只保存在当前电脑,由 loadProductionEnv() 按 server/.env.production、仓库根目录 .env.production、server/.env、仓库根目录 .env 的顺序补充缺失变量;不需要 GitLab File Variable 参与。shell 中已有的变量优先级最高,.env 只作为缺省回退,不能覆盖生产值。
生产态新增的关键变量:
| 变量 | 用途 |
|---|---|
WORKFLOW_RELEASE_STORAGE_ROOT | 发布态外置硬盘根目录,阶段 A 的 server / download / release metadata 全都从这里派生。 |
WORKFLOW_SERVER_DATA_DIR | 可选;显式覆盖 server 数据目录。未设置时,生产态会自动落到 ${WORKFLOW_RELEASE_STORAGE_ROOT}/server-data。 |
WORKFLOW_DOWNLOAD_ROOT | 可选;显式覆盖下载根目录。未设置时,默认使用 ${WORKFLOW_RELEASE_STORAGE_ROOT}/downloads/workflow-code。 |
WORKFLOW_DOWNLOAD_PORT | 下载服务端口,默认 7131。 |
WORKFLOW_DOWNLOAD_HOST | 下载服务监听地址,默认 127.0.0.1。 |
WORKFLOW_DOCS_ROOT | 可选;显式覆盖 docs 静态目录。未设置时,默认使用 ${WORKFLOW_RELEASE_STORAGE_ROOT}/published/docs/stable。 |
WORKFLOW_DOCS_PORT | docs 静态服务端口,默认 7132。 |
WORKFLOW_DOCS_HOST | docs 静态服务监听地址,默认 127.0.0.1。 |
WORKFLOW_PUBLIC_BASE_URL | 发行版 workflow 管理端公开入口,默认 https://wf.yuhe.space。 |
WORKFLOW_API_PUBLIC_BASE_URL | 发行版 API 公开入口,默认 https://wfapi.yuhe.space。 |
WORKFLOW_HOOKS_PUBLIC_BASE_URL | 发行版 webhook 公开入口,默认 https://wfhooks.yuhe.space。 |
WORKFLOW_EMBED_PUBLIC_BASE_URL | 发行版 embed 公开入口,默认 https://wfembed.yuhe.space。 |
WORKFLOW_DOWNLOAD_PUBLIC_BASE_URL | 手动下载公开入口,默认 https://wfdownload.yuhe.space。 |
WORKFLOW_UPDATES_PUBLIC_BASE_URL | 自动更新 feed 公开入口,默认 https://wfupdates.yuhe.space。 |
WORKFLOW_DOCS_PUBLIC_BASE_URL | docs 站点公开入口,默认 https://wfdocs.yuhe.space。 |
WORKFLOW_DOCS_API_PUBLIC_BASE_URL | docs 发行版 OpenAPI playground 的公开 API 根地址,默认 https://wfapi.yuhe.space;开发预览仍使用源码 OpenAPI 里的 http://localhost:7125。 |
WORKFLOW_RELEASE_STORAGE_ROOT 缺失、未挂载或不可写时,生产服务、下载服务和 docs 服务都必须启动失败,不能回退到仓库里的 server/.data 或系统盘临时目录。
Supabase 发布存储
开发态仍可用pnpm run deploy:supabase 启动 docker/supabase/docker-compose.yml 和 Docker named volumes。发布态必须改用 pnpm run deploy:supabase:release 或完整 pnpm deploy,它会先加载 .env.production,确认 WORKFLOW_RELEASE_STORAGE_ROOT 可写,并创建以下 bind mount 目录:
${WORKFLOW_RELEASE_STORAGE_ROOT}/supabase/postgres-data${WORKFLOW_RELEASE_STORAGE_ROOT}/supabase/db-config${WORKFLOW_RELEASE_STORAGE_ROOT}/supabase/storage${WORKFLOW_RELEASE_STORAGE_ROOT}/supabase/deno-cache
docker/supabase/docker-compose.release.yml 会把 Postgres、Storage、imgproxy 和 Edge Functions cache 的持久数据固定到这些外置硬盘目录;如果缺少 WORKFLOW_RELEASE_STORAGE_ROOT,Docker Compose 会拒绝解析发布 override,避免生产数据落回系统盘 named volume。
下载服务
7131 下载服务负责托管 app 安装包、latest-mac.yml 和 blockmap 等 updater 静态文件。当前有两种启动方式,静态根目录都指向 WORKFLOW_DOWNLOAD_ROOT,通常是 ${WORKFLOW_RELEASE_STORAGE_ROOT}/downloads/workflow-code。
长期或可复现部署优先使用 docker/download:
/health 探活;它不会生成、复制或修改发布产物。停止服务:
server/scripts/download-server.mjs 启动 Node/Express 后台服务,默认监听 127.0.0.1:7131:
WORKFLOW_DOWNLOAD_ROOT 当作静态目录,提供:
/health/app/v<ver>/*/app/stable/*
server/scripts/download-launchd.mjs 生成 launchd plist:
Docs 服务
docs/vX.Y.Z 发布会先把 Mintlify 导出的静态文件 stage 到 ${WORKFLOW_RELEASE_STORAGE_ROOT}/published/docs/v<ver> 和 stable/,然后通过 server/scripts/docs-server.mjs 启动 127.0.0.1:7132 静态服务:
.release/docs-source 执行 Mintlify 导出。这个 staging 目录会复制仓库内 docs/,并把 docs/openapi/workflow-code.openapi.yaml 的默认 server 改成 WORKFLOW_DOCS_API_PUBLIC_BASE_URL。源码 docs/ 不会被改动,所以 pnpm doc:dev 仍默认连 http://localhost:7125。由于 OpenAPI paths 本身包含 /api/...,默认 https://wfapi.yuhe.space 会在 API 页面拼成 https://wfapi.yuhe.space/api/...。
发行域名
当前发行默认域名使用yuhe.space 子域,旧的 hookcode.win 域名只作为兼容入口继续指向同一组服务:
| 用途 | 默认域名 | 本机服务 | 兼容域名 |
|---|---|---|---|
| Workflow 管理端 | wf.yuhe.space | 127.0.0.1:7130 | workflow.hookcode.win |
| Workflow API | wfapi.yuhe.space | 127.0.0.1:7130 | api.hookcode.win |
| Webhooks | wfhooks.yuhe.space | 127.0.0.1:7130 | hooks.hookcode.win |
| Embed | wfembed.yuhe.space | 127.0.0.1:7130 | embed.hookcode.win |
| App 手动下载 | wfdownload.yuhe.space | 127.0.0.1:7131 | download.hookcode.win |
| App 自动更新 | wfupdates.yuhe.space | 127.0.0.1:7131 | updates.hookcode.win |
| Docs | wfdocs.yuhe.space | 127.0.0.1:7132 | docs.hookcode.win |
WORKFLOW_DOCS_ROOT 当作静态目录,提供:
/health/*静态站点内容
server/scripts/docs-launchd.mjs 生成 launchd plist:
Release Metadata
阶段 A 引入统一的结构化发布元数据,默认 schema 版本为1。核心字段包括:
unittagversionpackageNamereleaseTargetchannelpublishedAtcommitShaartifacts[]
scripts/release.mjs:
write-metadata 会写单次发布的 release.json,publish-metadata 会把它持久化到 ${WORKFLOW_RELEASE_STORAGE_ROOT}/releases:单次 metadata 落在 <unit>/v<ver>/release.json 和 <unit>/stable/release.json,聚合索引落在 releases/index.json。阶段 B 的 docs 版本页、下载页和发布记录页会继续消费这份聚合数据,并在 docs 发布前通过 scripts/generate-release-docs.mjs 写成静态 MDX 页面;同时 workflow server 的 /health 也会对外补充当前上线中的 server / server-web 部署版本与发布时间,避免 docs 把“稳定版”误写成“已部署版本”。
本地发布命令
阶段 A/C 的发布动作通过本地命令完成。常用路径如下:workflow-code-core/vX.Y.Z:本地执行pnpm build:core、必要测试和npm publish,再用release.mjs write-metadata/publish-metadata写入发布记录。workflow-code-cli/vX.Y.Z:本地执行pnpm -C server/cli build、必要测试和npm publish,再写入发布记录。server/vX.Y.Z:本地构建 server 和 server-web,把产物 stage 到${WORKFLOW_RELEASE_STORAGE_ROOT}/published/server/v<ver>,再promote-stable并启动或重启7130服务。docs/vX.Y.Z:本地执行node scripts/generate-release-docs.mjs、pnpm release:prepare-docs-source与 Mintlify 静态导出,把.release/docs-source的导出结果 stage 到${WORKFLOW_RELEASE_STORAGE_ROOT}/published/docs/v<ver>,再promote-stable并启动或重启7132docs 服务。app/vX.Y.Z:本地执行pnpm -C app build:mac,再运行pnpm release:finalize-app --version X.Y.Z --source-dir app/release。finalize 会校验latest-mac.yml、dmg、zip和*.blockmap齐全,且latest-mac.yml的files[].url必须同时引用arm64与x64zip,每个 zip 必须有同名.blockmap。随后挂载 DMG 检查.app图标、codesign --verify --deep --strict与spctl。只有 Apple Developer ID Application 签名和 notarize 后的包才能切换到downloads/workflow-code/app/stable/;没有证书时只能留作本地测试,避免浏览器下载后被 Gatekeeper 报“已损坏,无法打开”。公开 HTTPS 入口的反代证书还必须覆盖wfdownload.yuhe.space/wfupdates.yuhe.space。