Files
NotesAgentic/docs/guides/CI-CD细则-团队开发版.md

167 lines
9.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CI/CD 细则(团队开发版)
> 本文档规定 NotesAgent 在 Gitea 上的持续集成、构建产物、发布和回滚要求。当前仓库尚未提交 Gitea Actions 工作流,因此本文首先作为落地流水线时的统一规范;流水线启用前,Pull Request 仍须人工执行同等检查。
> 更新日期:2026-09-01。当前阶段的 CD 指“生成可验证的候选构建与发布产物”,不包含把后端自动部署到公网环境。
## 1. 目标与原则
CI/CD 用于尽早发现依赖锁文件失效、类型错误、测试回归、前后端契约不一致和生产构建失败。流水线应遵守以下原则:
- 以 Gitea 为唯一远程和流水线入口;
- `main` 始终保持可安装、可测试、可构建;
- 安装依赖时使用锁文件,避免流水线与开发机解析出不同版本;
- 未通过必需检查的提交不得合入 `main`
- 外部模型、真实 API Key 和用户本地数据不得成为基础 CI 的前置条件;
- 缓存只用于加速,不得影响构建结果;删除缓存后流水线仍应成功;
- 测试、构建和发布步骤使用最小权限,敏感信息不得写入日志或产物。
## 2. 运行环境基线
| 组件 | CI 要求 | 说明 |
| --- | --- | --- |
| Python | 3.12 | 项目最低支持 3.11,CI 使用团队推荐版本 |
| uv | 当前稳定版,并在日志中输出版本 | 按 `backend/uv.lock` 安装后端依赖 |
| Node.js | 22 LTS | 满足前端环境要求并保持 Runner 兼容性 |
| pnpm | 10 | 按 `frontend/pnpm-lock.yaml` 安装前端依赖 |
| 操作系统 | Linux Runner 为基础门禁 | 桌面端启用后再增加 Windows、macOS 构建矩阵 |
Runner 镜像或 Action 的大版本必须固定。升级 Python、Node.js、uv、pnpm 或基础 Action 时,应使用独立的 `chore/` 分支,并完整运行前后端检查。
## 3. 触发规则
| 事件 | 必须执行 | 用途 |
| --- | --- | --- |
| Pull Request 指向 `main` | 文档检查、后端测试、前端测试、类型检查、生产构建 | 合并门禁 |
| 推送到 `main` | 全量检查、集成冒烟、保存候选构建 | 验证合并结果 |
| 推送功能分支 | 至少执行受影响模块的检查 | 尽早反馈;不得替代 PR 全量门禁 |
| 推送 `v*` 标签 | 全量检查、构建、校验和、发布候选产物 | 正式发布入口 |
| 手动触发 | 可选择全量回归或重新生成候选产物 | 发布前复核和故障恢复 |
纯文档变更可以跳过前后端耗时任务,但必须执行文档链接检查和 `git diff --check`。只有可靠的路径检测结果才能判定为纯文档变更;锁文件、工作流、构建配置和接口契约变更一律按代码变更处理。
## 4. Pull Request 必需检查
建议将以下 Job 名称固定为 Gitea 分支保护所要求的状态检查:
| Job | 必需命令或行为 | 通过标准 |
| --- | --- | --- |
| `docs-check` | `git diff --check`,检查仓库内 Markdown 相对链接 | 无空白错误、无失效本地链接 |
| `backend-test` | `uv sync --frozen`、编译检查、`uv run pytest` | 依赖锁有效且测试全部通过 |
| `frontend-test` | `pnpm install --frozen-lockfile``pnpm test` | 依赖锁有效且测试全部通过 |
| `frontend-typecheck` | `pnpm type-check` | 无 TypeScript/Vue 类型错误 |
| `frontend-build` | `pnpm build` | Vite 生产构建成功 |
| `integration-smoke` | 启动 FastAPI,验证健康检查和关键本地链路 | 服务可启动,响应与契约符合预期 |
后端 Job 的基准命令:
```bash
cd backend
uv sync --frozen
uv run python -m compileall -q app
uv run pytest
```
前端 Job 的基准命令:
```bash
cd frontend
pnpm install --frozen-lockfile
pnpm test
pnpm type-check
pnpm build
```
`integration-smoke` 应使用 Mock Provider、临时数据库和临时附件目录,不访问 OpenAI、DeepSeek 或其他外部服务。测试结束后必须关闭服务并清理临时数据。
## 5. 路径与模块检查规则
- 修改 `backend/**``backend/uv.lock` 或后端配置时,必须运行 `backend-test``integration-smoke`
- 修改 `frontend/**``frontend/pnpm-lock.yaml` 或前端配置时,必须运行全部前端 Job。
- 修改 `docs/contracts/**`、FastAPI 路由、DTO、SSE 事件或前端 Service 类型时,必须同时运行前后端全量检查。
- 修改 `.gitea/**`、根目录工程配置或依赖版本时,必须运行所有 Job。
- 修改 `docs/**` 以外且无法明确归类的文件时,默认运行所有 Job。
路径过滤只用于减少无关重复任务,不得造成关键检查缺失。若无法可靠判断影响范围,应执行全量流水线。
## 6. 凭据与敏感信息
- 基础 CI 不配置真实模型 API Key,Provider 相关测试统一使用 Mock 或请求桩。
- 确需发布签名或访问受保护服务时,凭据只保存在 Gitea Actions Secrets 中,不写入仓库、工作流参数、缓存或构建产物。
- 来自外部分支或不受信任 Pull Request 的任务不得读取发布凭据。
- Secret 名称表达用途和环境,例如 `RELEASE_SIGNING_KEY`;禁止使用含义模糊的 `KEY1``TOKEN2`
- 日志中禁止输出请求头、完整 Token、API Key、用户笔记内容和本地凭据存储内容。
- 生产凭据与测试凭据分离,并遵循最小权限、定期轮换和可撤销原则。
前端构建时注入的变量会进入静态资源,不能用于保存秘密。只有明确可公开的配置才允许使用 Vite 客户端环境变量。
## 7. 缓存与产物
可以缓存 uv 下载缓存和 pnpm Store,缓存键至少包含操作系统、运行时版本和对应锁文件哈希。不得缓存:
- `backend/.venv/`
- `frontend/node_modules/`
- `backend/data/`、测试数据库和用户附件;
- `.env`、API Key、本地凭据库或签名材料。
普通 PR 不上传可执行发布包,只保留必要的测试报告和前端构建日志。`main` 或版本标签的候选产物应记录提交 SHA,生成 SHA-256 校验和,并设置明确的保留期限;非正式候选产物建议保留 14 天。
## 8. 分支保护与合并门禁
Gitea 中的 `main` 应启用以下保护:
- 禁止普通成员直接推送和强制推送;
- 要求 Pull Request 审阅通过;
- 要求第 4 节列出的适用状态检查成功;
- Head 更新后使旧审阅和旧检查失效,必须针对最新提交重新检查;
- 对话和审阅意见处理完成后才允许合并;
- 优先使用 squash 或 rebase 保持主线清晰,具体方式遵循 [Git 使用细则](Git使用细则-团队开发版.md)。
临时绕过门禁只允许用于明确的仓库级故障。绕过者需要记录原因、影响、补验计划,并在恢复后立即补跑全部检查。
## 9. 发布流程
当前阶段按以下顺序生成发布候选:
1. 从已通过全部检查的 `main` 提交确定发布 SHA
2. 更新版本号、变更说明和必要文档;
3. 创建形如 `v0.2.0` 的语义化版本标签;
4. 标签流水线重新执行全部测试和生产构建;
5. 对产物执行本地启动或安装冒烟测试;
6. 生成校验和,并把版本、提交 SHA、构建环境和已知限制写入发布说明;
7. 人工确认后在 Gitea 发布页面公开产物。
Tauri 桌面端接入后,发布流水线再增加 Windows、macOS 和 Linux 构建矩阵、平台签名及安装包验证。在签名、更新通道和回滚方案准备完成前,不启用面向用户的自动更新。
## 10. 回滚与热修复
- 尚未公开的候选产物直接标记为失败,不覆盖同一版本的已有产物;修复后递增预发布编号或版本号。
- 已发布版本出现问题时,优先停止分发并回退到最近一个已验证版本。
- 代码修复从 `main` 创建 `hotfix/<模块>-<问题>` 分支,通过完整门禁后合并并发布补丁版本。
- 禁止重写已公开版本标签或用新文件替换旧版本同名产物。
- 回滚或热修复完成后,在 `docs/retrospectives/` 记录原因、影响、处置过程和防复发措施。
## 11. 流水线失败处理
1. 先确认失败是否可在本地使用相同锁文件和命令复现;
2. 判断是代码、测试、依赖、Runner 还是外部基础设施问题;
3. 代码或测试问题由当前 PR 修复,不通过重跑掩盖不稳定测试;
4. Runner 或 Gitea 故障应记录日志和时间,恢复后针对同一 Head 重新执行;
5. 连续出现的偶发失败必须作为缺陷处理,明确负责人并增加稳定性修复;
6. 修复流水线本身时,不得顺便降低测试范围或绕过既有门禁。
## 12. 落地清单
首次创建 `.gitea/workflows/` 时,应逐项确认:
- [ ] 工作流只使用 Gitea Runner 支持且来源可信的 Action
- [ ] Python、Node.js、uv 和 pnpm 版本符合本规范;
- [ ] 后端和前端依赖均以 frozen 模式安装;
- [ ] 必需 Job 名称与 `main` 分支保护一致;
- [ ] Mock 测试不依赖外部模型服务和真实凭据;
- [ ] 缓存键包含锁文件哈希,缓存内容不含用户数据或秘密;
- [ ] PR、`main`、版本标签和手动触发行为分别验证;
- [ ] 失败任务能返回非零退出码,后续发布步骤不会继续;
- [ ] 候选产物包含提交 SHA、校验和和保留期限;
- [ ] 团队成员能够按本文档在本地复现全部门禁。