## 上一版没修透 先只加 `pnpm --filter @nodeagent/protocol build`,CI 换了个错法: `apps/cli` 报 `Cannot find module '@nodeagent/client'`。 依赖链是 **`protocol → client → cli / mcp / agent`**,逐层都要 dist/*.d.ts。 逐个补依赖是打地鼠,下次加包还会漏 —> 直接用 `pnpm -r build` 把整条链建出来。 ## 顺带修掉一个顺序矛盾 原工作流是 `typecheck` 在前、`pnpm -r build` 在后,而后者注释写着 「单测 import 的是 dist/,必须先构建」。既然后面无论如何都要 build, 不如提前一次到位 —— 现在 build 在 typecheck 之前,只保留一份。 **注入验证(模拟 CI 全新检出)**:把 `packages/*/dist`、`apps/*/dist` 全部移走 → `pnpm -r build` → `pnpm typecheck` **零错误**;`pnpm test:unit` **357 项全绿**。
130 lines
4.7 KiB
YAML
130 lines
4.7 KiB
YAML
# 交付流水线左移门禁(见 docs/DELIVERY-PIPELINE.md §1 §2 §8)
|
||
#
|
||
# 本文件只做「快且能阻断」的检查:密钥、依赖漏洞、类型、覆盖率、提交规范。
|
||
# 真机链路(install.cmd / control.cmd 双击、Windows 能力)留在 windows-e2e.yml
|
||
# —— 那一环跑得慢但价值最高,不可被这条更快的流水线替代。
|
||
#
|
||
# ⚠️ 阈值说明(别照搬通用 80%):详见 docs/DELIVERY-PIPELINE.md §2。
|
||
# 全量覆盖率当前基线约 66.9%,故全量只观测;阻断只针对**变更文件**(≥70%)。
|
||
|
||
name: Quality Gate
|
||
|
||
on:
|
||
pull_request:
|
||
branches: [main]
|
||
push:
|
||
branches: [main]
|
||
|
||
permissions:
|
||
contents: read
|
||
|
||
jobs:
|
||
# ① 代码审计:密钥 + 依赖漏洞
|
||
audit:
|
||
name: 代码审计(密钥 + 依赖)
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v5
|
||
with:
|
||
# gitleaks 扫历史提交,需要完整历史
|
||
fetch-depth: 0
|
||
|
||
# 密钥扫描:nodeagent 的密钥面比一般项目大 ——
|
||
# PSK、Ed25519 私钥、TLS 自签证书、PSK.txt、agent.json
|
||
- name: 密钥与敏感信息扫描
|
||
uses: gitleaks/gitleaks-action@v2
|
||
env:
|
||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||
|
||
- uses: pnpm/action-setup@v4
|
||
with:
|
||
# 与本仓库其他工作流保持一致(console-windows.yml / rust.yml / windows-e2e.yml 均为 12)
|
||
version: 12
|
||
|
||
- uses: actions/setup-node@v4
|
||
with:
|
||
node-version: 22
|
||
|
||
- run: pnpm install --frozen-lockfile
|
||
|
||
# 依赖漏洞:High 及以上阻断
|
||
- name: 依赖漏洞扫描(SCA)
|
||
# ⚠️ 必须显式指定公共 registry(2026-10-17)
|
||
# 仓库 `.npmrc` 指向 registry.npmmirror.com(镜像加速),但**镜像不实现
|
||
# audit 接口**,`pnpm audit` 会直接报 ERR_PNPM_AUDIT_ENDPOINT_NOT_EXISTS。
|
||
# 结果就是这道门禁从加上那天起**一直是红的**,等于没有门禁。
|
||
run: pnpm audit --audit-level=high --registry=https://registry.npmjs.org
|
||
|
||
# ② 质量门禁:类型 + 覆盖率
|
||
gate:
|
||
name: 质量门禁(类型 + 覆盖率)
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v5
|
||
with:
|
||
# 覆盖率门禁要算「变更文件」,需与基线做 diff
|
||
fetch-depth: 0
|
||
|
||
- uses: pnpm/action-setup@v4
|
||
with:
|
||
# 与本仓库其他工作流保持一致(console-windows.yml / rust.yml / windows-e2e.yml 均为 12)
|
||
version: 12
|
||
|
||
- uses: actions/setup-node@v4
|
||
with:
|
||
node-version: 22
|
||
|
||
- run: pnpm install --frozen-lockfile
|
||
|
||
# ⚠️ 必须先全量构建,再查类型(2026-10-17)
|
||
#
|
||
# 各包 import 的是**同仓其它包的编译产物**(dist/*.d.ts),依赖链是
|
||
# `protocol → client → cli / mcp / agent`。CI 全新检出没有 dist,
|
||
# 直接 typecheck 会逐层报 `TS2307: Cannot find module '@nodeagent/xxx'`;
|
||
# 而本地因为 dist 还在,完全看不出来 —— 典型「本地绿 / CI 红」。
|
||
#
|
||
# 一开始只想「只构建 protocol 就够」,实测不够:cli 又报找不到 `@nodeagent/client`。
|
||
# 与其逐个补依赖(下次加包还会漏),不如直接用 `-r build` 把整条链建出来。
|
||
# 顺带:单测 import 的也是 dist/,这一步同时保证了覆盖率不为空(原步骤在 typecheck 之后,
|
||
# 顺序本就矛盾 —— 既然后面也要 build,不如提前一次到位)。
|
||
- name: 构建 workspace(typecheck 与单测都依赖 dist)
|
||
run: pnpm -r build
|
||
|
||
- run: pnpm typecheck
|
||
|
||
- name: 采集覆盖率
|
||
run: |
|
||
mkdir -p coverage
|
||
node --test --experimental-test-coverage \
|
||
--test-reporter=lcov \
|
||
--test-reporter-destination=coverage/lcov.info \
|
||
"tests/unit/**/*.test.mjs"
|
||
|
||
- name: 覆盖率门禁
|
||
run: node scripts/ci/check-coverage.mjs --lcov coverage/lcov.info --base origin/main --threshold 70
|
||
|
||
# coverage/ 已在 .gitignore 中,此处留档便于人工查看
|
||
- uses: actions/upload-artifact@v4
|
||
if: always()
|
||
with:
|
||
name: coverage
|
||
path: coverage/
|
||
retention-days: 7
|
||
|
||
# ③ 提交信息规范
|
||
commits:
|
||
name: 提交信息规范
|
||
runs-on: ubuntu-latest
|
||
if: github.event_name == 'pull_request'
|
||
steps:
|
||
- uses: actions/checkout@v5
|
||
with:
|
||
fetch-depth: 0
|
||
|
||
- uses: actions/setup-node@v4
|
||
with:
|
||
node-version: 22
|
||
|
||
- name: 校验 Conventional Commits
|
||
run: node scripts/ci/check-commit-msg.mjs --base ${{ github.event.pull_request.base.sha }}
|