covgate 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -80,7 +80,7 @@ covgate run
80
80
 
81
81
  ### 从 npm registry 安装(推荐)
82
82
 
83
- 包已发布到 npm:[covgate](https://www.npmjs.com/package/covgate),当前 latest 为 **0.3.1**。
83
+ 包已发布到 npm:[covgate](https://www.npmjs.com/package/covgate),当前 latest 为 **0.3.2**。
84
84
 
85
85
  ```bash
86
86
  npm install --save-dev covgate
@@ -132,6 +132,8 @@ setup 会:
132
132
 
133
133
  **CovGate 不生成测试,也不补测试。** 行为变更的测试必须由项目自己补;没有测试时 `test:coverage` 会直接失败,不会生成空覆盖率来蒙混过关。
134
134
 
135
+ 如果 setup 找不到覆盖率命令,不会静默跳过:会打印具体的 `test:coverage` 建议、`--test-command` 用法和 GUI 命令。已有 `covgate.config.json` 会保留,并在输出中说明现有 scopes。
136
+
135
137
  `postinstall` 也会尝试同样的流程,但 **npm 11.19+ 默认不执行依赖安装脚本**。如果安装时没有弹出询问,直接运行 `npx covgate setup` 即可;详细说明见 [安装与自动配置](docs/setup.md)。
136
138
 
137
139
  ### 在 CovGate 仓库中开发
@@ -509,7 +511,7 @@ macOS 用 `open .covgate/report.html`,Linux 用 `xdg-open .covgate/report.html
509
511
  文本输出示例:
510
512
 
511
513
  ```text
512
- CovGate · 覆盖率门禁 v0.3.1
514
+ CovGate · 覆盖率门禁 v0.3.2
513
515
  模式 执行测试并检查 · 配置 covgate.config.json · 用时 12.4s
514
516
 
515
517
  ✗ 客户端 [client/client] 未通过
package/docs/setup.md CHANGED
@@ -9,7 +9,7 @@ npm install --save-dev covgate
9
9
  npx --no-install covgate setup
10
10
  ```
11
11
 
12
- 包页面:[covgate](https://www.npmjs.com/package/covgate)。当前 latest 是 **0.3.1**。
12
+ 包页面:[covgate](https://www.npmjs.com/package/covgate)。当前 latest 是 **0.3.2**。
13
13
 
14
14
  > `0.0.0-stage` 是 npm 暂存发布产生的占位版本,不会被 `npm install covgate` 选中,可以忽略。
15
15
 
@@ -38,7 +38,7 @@ npm 11.19+ 默认不执行依赖的 `postinstall`,会显示类似:
38
38
 
39
39
  ```text
40
40
  npm warn install-scripts 1 package has install scripts not yet covered by allowScripts
41
- npm warn install-scripts covgate@0.3.1 (postinstall: node bin/covgate-postinstall.js)
41
+ npm warn install-scripts covgate@0.3.2 (postinstall: node bin/covgate-postinstall.js)
42
42
  ```
43
43
 
44
44
  因此:
@@ -82,7 +82,9 @@ npm warn install-scripts covgate@0.3.1 (postinstall: node bin/covgate-postinst
82
82
  - `.github/workflows/covgate.yml`(如果存在 `.github/`)
83
83
  - `.gitignore` 加入 `.covgate/`、`coverage/`
84
84
  - 若已有 `CLAUDE.md`、`.cursor`、`.github/copilot-instructions.md`,同步写入对应说明。
85
- 6. 输出下一步命令。
85
+ 6. 输出下一步命令,包括可视化工作台:`npx --no-install covgate ui`。
86
+
87
+ > 找不到覆盖率测试命令时,setup 不会静默跳过:会给出 `test:coverage` 建议、`--test-command` 示例和 GUI 命令。如果项目已有 `covgate.config.json`,会保留并列出其中 scopes,不会因为缺少通用命令而覆盖或误报。
86
88
 
87
89
  > **CovGate 不生成测试,也不补测试。** setup 只配置测试框架和门禁;本次行为变更的测试必须由项目自己补。没有测试时 `test:coverage` 会直接失败(已移除 `--passWithNoTests`),不会产生可蒙混过关的空覆盖率。
88
90
 
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "covgate",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "覆盖率门禁:客户端 100%,服务端至少 95%,安装时自动检测/配置测试框架与 AI 编码代理接入。",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,5 +1,5 @@
1
1
  import { existsSync } from "node:fs";
2
- import { mkdir, writeFile } from "node:fs/promises";
2
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import {
5
5
  SetupError,
@@ -20,6 +20,33 @@ import { scaffoldAgent } from "./agent.js";
20
20
  import { askYesNo, canPrompt } from "./prompt.js";
21
21
 
22
22
  const DEFAULT_COVERAGE_PATH = "coverage/coverage-final.json";
23
+ const UI_COMMAND = "npx --no-install covgate ui";
24
+
25
+ async function existingScopeNames(configPath) {
26
+ try {
27
+ const data = JSON.parse(await readFile(configPath, "utf8"));
28
+ return Object.keys(data.scopes || {});
29
+ } catch {
30
+ return [];
31
+ }
32
+ }
33
+
34
+ function printConfigGuidance(log, framework) {
35
+ log("[covgate] 未生成 covgate.config.json:缺少可用的覆盖率测试命令。");
36
+ if (framework.id === "vitest") {
37
+ log('[covgate] 在 package.json 添加 "test:coverage": "vitest run --coverage --coverage.reporter=json --coverage.reporter=lcov",然后重新运行 setup。');
38
+ } else if (framework.id === "jest") {
39
+ log('[covgate] 在 package.json 添加 "test:coverage": "jest --coverage --coverageReporters=json --coverageReporters=lcov",然后重新运行 setup。');
40
+ } else if (framework.id === "node-test") {
41
+ log("[covgate] 检测到 Node.js 内置 test runner。安装 c8 后添加覆盖率命令:");
42
+ log(' "test:coverage": "c8 --reporter=json --reporter=lcov node --test"');
43
+ } else {
44
+ log("[covgate] 先安装/配置测试框架,并在 package.json 添加 test:coverage。");
45
+ }
46
+ log('[covgate] 也可以直接指定命令:npx --no-install covgate setup --test-command "<覆盖率命令>"');
47
+ log("[covgate] 然后运行 npx --no-install covgate validate 检查配置。");
48
+ log("[covgate] 可视化配置工作台:" + UI_COMMAND);
49
+ }
23
50
 
24
51
  /**
25
52
  * @param {string} root
@@ -134,12 +161,22 @@ export async function runSetup(options = {}) {
134
161
  }
135
162
  const coveragePath = normalizeGlob(root, options.coverage || DEFAULT_COVERAGE_PATH);
136
163
  const configPath = path.join(root, "covgate.config.json");
164
+ const configExists = existsSync(configPath);
137
165
  let configWritten = false;
166
+ let configPreserved = false;
138
167
 
139
- if (options.noConfig !== true && testCommand && scopeSpecs.length > 0) {
140
- if (existsSync(configPath) && options.force !== true) {
141
- log("[covgate] " + displayPath(root, configPath) + " 已存在,保留现有配置");
142
- } else {
168
+ if (options.noConfig !== true) {
169
+ if (configExists && options.force !== true) {
170
+ configPreserved = true;
171
+ const names = await existingScopeNames(configPath);
172
+ log(
173
+ "[covgate] " +
174
+ displayPath(root, configPath) +
175
+ " 已存在" +
176
+ (names.length ? "(scopes: " + names.join(", ") + ")" : "") +
177
+ ",保留现有配置,不因缺少通用覆盖率命令而覆盖或跳过。"
178
+ );
179
+ } else if (testCommand && scopeSpecs.length > 0) {
143
180
  const config = await buildStarterConfig({
144
181
  root,
145
182
  scopes: scopeSpecs,
@@ -163,13 +200,16 @@ export async function runSetup(options = {}) {
163
200
  if (framework.id && !coverageScriptFor(framework.id) && !options.testCommand) {
164
201
  log("[covgate] 注意:该测试框架的覆盖率命令需要你确认报告路径。");
165
202
  }
166
- }
167
- } else if (options.noConfig !== true) {
168
- if (!testCommand) {
169
- log("[covgate] 未找到可用的覆盖率测试命令,跳过 covgate.config.json。");
170
- }
171
- if (scopeSpecs.length === 0) {
172
- log("[covgate] 未找到源码目录,跳过 covgate.config.json;请用 --source 指定。");
203
+ } else if (configExists) {
204
+ configPreserved = true;
205
+ log("[covgate] " + displayPath(root, configPath) + " 无法重新生成,保留现有配置。");
206
+ if (!testCommand) {
207
+ log("[covgate] 现有配置仍可使用;如需重新生成,请先补覆盖率命令。");
208
+ }
209
+ } else if (!testCommand) {
210
+ printConfigGuidance(log, framework);
211
+ } else if (scopeSpecs.length === 0) {
212
+ log("[covgate] 未找到源码目录,未生成 covgate.config.json;请用 --source 指定。");
173
213
  }
174
214
  }
175
215
 
@@ -195,6 +235,8 @@ export async function runSetup(options = {}) {
195
235
  testCommand: testCommand || null,
196
236
  coveragePath,
197
237
  configPath: configWritten ? configPath : existsSync(configPath) ? configPath : null,
238
+ configPreserved,
239
+ uiCommand: UI_COMMAND,
198
240
  packageChanged,
199
241
  packageScripts: scriptChanges,
200
242
  agentChanges,
@@ -219,6 +261,7 @@ export async function runSetup(options = {}) {
219
261
  );
220
262
  }
221
263
  log("[covgate] 运行门禁: " + (summary.dryRun ? "npx covgate run" : "npx --no-install covgate run"));
264
+ log("[covgate] 可视化工作台: " + UI_COMMAND);
222
265
  log("[covgate] 注意:CovGate 不会生成或补写测试;项目必须为行为变更补真实测试后才能通过门禁。");
223
266
  if (!options.noAgent) {
224
267
  log("[covgate] AI 接入: AGENTS.md 与 scripts/covgate-agent-gate.*");