agilelabs-fx-docs main framework-standards/cicd.md

CI/CD 规范

本页定义 AgileLabs Framework 项目在前后端混合仓库中的默认 CI/CD 规则,包括前端依赖安装、后端发布、镜像构建、部署边界和多应用产物汇总约定。接口契约请继续阅读 前端对接规范WebAPI 规范;Drone 的 runner、结构模板和示例请继续阅读 Drone CI 配置专题

适用场景

  • 使用 Drone 作为持续集成与持续部署平台的项目。
  • 同一仓库中同时存在一个或多个前端应用、WebAPI、后台任务或需要统一发布目录的项目。
  • 需要把前端构建、后端发布、镜像和部署边界稳定写成团队默认规则的项目。

必须遵守

  • 前端 CI 默认使用 pnpm,不再以 npm ci 作为新项目和新流水线的默认方案。
  • 使用 pnpm 的前端项目必须提交 pnpm-lock.yaml,不得与 package-lock.json 长期混用为同一套默认锁文件。
  • 前端依赖安装默认使用 pnpm install --frozen-lockfile,确保 CI 可复现。
  • 当项目使用 node:latest 或其他会漂移的 Node 构建镜像,且依赖链包含需要 install/build script 的包时,项目级必须显式提交 pnpm-workspace.yaml 或等价 pnpm 策略配置,声明允许执行的依赖构建脚本。
  • 多前端仓库中,每个前端应用必须独立成一个构建步骤,不把多个应用串进同一个长命令步骤。
  • 前端构建步骤只负责安装依赖和生成 dist/ 等构建产物,产物同步必须放到独立汇总步骤。
  • 后端 CI 必须把 restoretestpublish 视为清晰边界;至少 dotnet publish 必须独立成正式步骤。
  • 后端 dotnet publish 只负责生成最终发布目录,不与镜像构建、推送或部署命令混写成一个大步骤。
  • 前端构建镜像、后端 SDK 发布镜像、后端运行时镜像必须分别记录镜像族与版本 tag,不能只写“用 Docker 构建”。
  • 后端 SDK 发布镜像只用于 dotnet restoredotnet testdotnet publish 等构建阶段;应用 Dockerfile 中的运行时镜像必须单独维护。
  • 镜像构建步骤只能消费已经准备好的 publish 目录或其他最终制品目录,不得在镜像步骤里重新编译源码。
  • 部署步骤只能消费镜像或最终制品,不得在部署步骤中再次执行源码构建。
  • 多步骤之间的依赖必须显式写出,不能依赖 YAML 书写顺序猜测执行边界。
  • 部署规则只定义步骤边界和制品来源,不在通用规范中写真实仓库地址、命名空间、凭据或内网环境细节。

推荐做法

  • 将复杂构建逻辑收敛到 scripts/ci/*,让 .drone.yml 主要表达步骤边界和依赖关系。
  • 为每个前端应用单独维护 package.jsonpnpm-lock.yaml,在没有 workspace 需求时保持独立 importer 即可。
  • 在前端步骤中统一使用团队认可的 Node 构建镜像,并固定安装命令、锁文件策略和产物目录约定。
  • 当依赖链包含原生模块、文件监听器或其他需要 install/build script 的包时,优先使用项目级 allow 配置显式声明允许列表,而不是关闭 pnpm 的整套安全检查。
  • 在后端步骤中先执行测试或必要检查,再执行 dotnet publish,把最终发布目录作为镜像步骤唯一输入,并记录实际使用的 SDK 镜像 tag。
  • 用单独的汇总步骤将多个前端 dist/、后端 publish/ 和附加静态资源同步到最终发布目录。
  • 在镜像推送成功后再进入部署步骤,并将版本写入、部署命令和回滚点信息视为部署阶段的一部分,而不是构建阶段的副作用。

运作机制

  • 本页负责定义正式默认规则,Drone CI 配置专题 负责说明 runner、模板和组织方式,两者不要混写成一页。
  • 前端依赖安装统一收敛到 pnpmpnpm-lock.yaml,目的是让本地开发、CI 构建和文档口径建立在同一套可复现前提上。
  • pnpm install --frozen-lockfile 只能保证锁文件解析一致,不能覆盖包管理器新版本引入的安全策略变化;当 pnpm 升级后,CI 是否可复现还取决于项目是否显式声明构建脚本策略。
  • node:latest 会隐式带来 Node、corepack 和 pnpm 行为漂移,因此前端 CI 的可复现性不只依赖 lockfile,也依赖项目级 pnpm 配置是否完整。
  • 多前端仓库将每个应用拆成独立步骤,是为了并行执行、缩小失败定位范围,并避免多个应用共享同一发布目录时互相覆盖。
  • 后端 dotnet publish 是源码编译边界,镜像构建是制品打包边界,部署步骤是环境变更边界;三者分开后,问题定位、缓存复用和重试策略都更清晰。
  • 构建镜像和运行时镜像不是同一件事:前者决定 CI 中能否完成依赖安装和源码发布,后者决定容器启动后的系统库、时区、端口和运行时版本。
  • 多前端 + WebAPI 仓库的推荐顺序固定为:前端各自构建、后端发布、统一汇总静态资源、构建镜像、推送镜像、执行部署。
  • 部署动作可以是 Kubernetes 更新、版本写入、脚本发布或其他环境发布方式,但它们都必须消费已经完成的最终制品,而不是继续回头处理源码。

标准 CI 镜像记录

项目级 CI 文档或 .drone.yml 附近应能快速查到以下信息:

类别 典型示例 记录位置 说明
前端构建镜像 hub.feinian.net/build/node:latesthub.feinian.net/library/node:25-alpinehub.feinian.net/feinian/node:20-alpine .drone.yml 的前端构建步骤、前端 package.jsonpnpm-lock.yaml 记录 Node 镜像族和 tag,避免 latest 漂移后无法追踪构建环境。
后端发布镜像 hub.feinian.net/dotnet/sdk:10.0hub.feinian.net/dotnet/sdk:8.0 .drone.ymldotnet publish 步骤 只负责 restore、test、publish,不应出现在应用运行时 Dockerfile 中。
后端运行时镜像 hub.feinian.net/build/dotnet/aspnet:10.0hub.feinian.net/dotnet/aspnet:10.0hub.feinian.net/dotnet/aspnet:8.0 WebAPI、WebHost、JobHost 等项目 Dockerfile 决定容器运行环境,应与发布目标框架和端口、时区等运行配置一起检查。
发布与部署配置 Dockerfile、version.txtkubectl set image 或部署脚本 镜像打包步骤和部署步骤 只消费最终发布目录与镜像 tag,不回头编译源码。

多后端制品项目可以分别发布 WebAPI、JobHost 等目录,再分别构建镜像;如果这些制品属于同一次发布,应共享同一份版本号来源,并分别把 version.txt 写入各自最终发布目录。

pnpm 11 build-script 审核的默认处理方式

  • 当 Drone 或其他 CI 在安装阶段报 ERR_PNPM_IGNORED_BUILDS 时,先确认是否因为 node:latest 或镜像升级引入了新的 pnpm 行为。
  • 如果项目目录本身就是独立前端入口,即使仓库根没有 workspace,也可以在该目录放置 pnpm-workspace.yaml
  • 默认修复方式是显式声明允许执行的依赖构建脚本,不把“关闭整套 pnpm 安全检查”作为团队默认规则。
  • 最小示例:
allowBuilds:
  "@parcel/watcher": true

常见问题

  • “现有项目还在用 npm ci,必须立刻切掉吗?” 不要求一次性重写全部存量流水线,但不得继续把 npm ci 当作新前端项目的默认 CI 方案。存量兼容应写明偏差范围和迁移计划。
  • “用了 pnpm 以后,还能顺手保留 package-lock.json 吗?” 不建议。这样会让本地与 CI 可能解析出两套依赖树,破坏可复现性。
  • “后端镜像里顺便执行 dotnet publish 不是更省步骤吗?” 不建议作为默认规则。这样会把源码编译、发布目录和镜像打包边界混在一起,难以复用制品,也不利于排查失败点。
  • “部署步骤里顺便再跑一遍构建,能保证最新吗?” 不能作为默认规则。部署应消费已经验证过的最终制品,否则会让部署结果与前面通过的构建产物脱节。
  • “项目没有根 pnpm-workspace.yaml,是不是就不适合多个前端应用?” 不是。多个前端应用可以保持独立包目录和独立锁文件,只要 CI 步骤边界、产物目录和汇总顺序写清楚即可。
  • pnpm install --frozen-lockfile 本地能过,为什么 Drone 里会报 ERR_PNPM_IGNORED_BUILDS?” 先看 CI 镜像是否切到了新的 Node / pnpm 版本,尤其是 node:latest。这类问题通常不是 lockfile 损坏,而是新 pnpm 开始要求项目显式声明允许执行的依赖构建脚本。
  • “没有根 pnpm-workspace.yaml 的独立前端目录,也可以放项目级 pnpm-workspace.yaml 吗?” 可以。只要该目录本身是独立前端入口,就可以在该目录放置项目级 pnpm-workspace.yaml,不要求仓库根一定存在 workspace。
  • “遇到被忽略的 build scripts,默认做法是关闭限制还是显式 allow?” 默认做法是显式 allow。优先把允许列表收敛到项目级配置,而不是直接关闭整套 pnpm 安全检查。
  • “本地复现 pnpm 11 的 CI 行为时,为什么有时还会看到无 TTY 或 CI=true 相关提示?” 这是本地模拟 CI 时的排查细节,不是团队正式规则。正式规范关注的是显式声明 pnpm build-script 策略,而不是要求所有项目在文档里固定写本地调试技巧。

相关检查

示例项目对照