govgate 0.2.1 → 0.3.0

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.
Files changed (3) hide show
  1. package/README.md +16 -20
  2. package/dist/index.js +23 -13
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # govgate
2
2
 
3
- Pipeline-step CLI for the MT Testing Tool: parses standard test output (JUnit XML),
3
+ Pipeline-step CLI for Governance OS: parses standard test output (JUnit XML),
4
4
  maps tests to test cases, reports a run, and **gates the release** via its exit code.
5
5
  No SDK in application code — only the pipeline YAML changes.
6
6
 
@@ -19,9 +19,9 @@ standard reporter.
19
19
 
20
20
  | Flag | Default | Meaning |
21
21
  |---|---|---|
22
- | `--url <url>` | `MT_TESTING_TOOL_URL` | Tool deployment URL |
23
- | `--api-key <key>` | `MT_TESTING_TOOL_API_KEY` | API key (env var strongly preferred) |
24
- | `--config <path>` | `.mt-testing.json` searched upward | Config file |
22
+ | `--url <url>` | `GOVGATE_URL` | Tool deployment URL |
23
+ | `--api-key <key>` | `GOVGATE_API_KEY` | API key (env var strongly preferred) |
24
+ | `--config <path>` | `govgate/config.json` searched upward | Config file |
25
25
  | `--suite <slug>` | config `suite` | Target suite |
26
26
  | `--env <slug>` | config `defaultEnvironment` | Environment for the run |
27
27
  | `--name <name>` | derived from CI context | Run name |
@@ -61,7 +61,7 @@ Resolution per test (results are unioned):
61
61
  what .NET JUnit loggers emit), an underscore-delimited `Mt<n>` token maps the test:
62
62
  `Mt5_DuplicateEmail_Rejected`, `Profiles_Mt12_NotFound`, `Delete_Resolves_MT28`.
63
63
  Embedded substrings (`GMT5_…`, `Format2_…`) do not match.
64
- 3. **Config patterns** in `.mt-testing.json`:
64
+ 3. **Config patterns** in `govgate/config.json`:
65
65
 
66
66
  ```jsonc
67
67
  {
@@ -83,10 +83,9 @@ any passing → `pass`; all skipped → the case is not posted (stays pending
83
83
  test is a non-observation). Suite cases with no mapped tests stay pending and are
84
84
  listed as "uncovered" in the summary.
85
85
 
86
- Use the `map-tests` Claude Code skill (in the
87
- [Maersk-Training/mt-testing-tool](https://github.com/Maersk-Training/mt-testing-tool)
88
- repo under `skills/`) to generate the mapping semi-automatically, and `--dry-run` to
89
- validate it.
86
+ Use the `map-tests` Governance OS skill (served by your deployment at
87
+ `${GOVGATE_URL}/api/v1/skills`) to generate the mapping semi-automatically, and
88
+ `--dry-run` to validate it.
90
89
 
91
90
  ## .NET specifics (learned the hard way)
92
91
 
@@ -102,28 +101,25 @@ validate it.
102
101
  - **Classic Release has no source checkout**: `dotnet publish` the test project into
103
102
  the build artifact (`drop/tests/`) and run it with the ".NET Core" task using
104
103
  Command `custom` + `vstest` — the `run` command does NOT execute arbitrary commands.
105
- - The full ADO runbook (variable groups, stage scoping, exact task configs) lives in
106
- `skills/onboard-repo/reference.md` in the
107
- [Maersk-Training/mt-testing-tool](https://github.com/Maersk-Training/mt-testing-tool)
108
- repo — or run the `onboard-repo` skill.
104
+ - The full ADO runbook (variable groups, stage scoping, exact task configs) is the
105
+ `onboard-repo` Governance OS skill (served at `${GOVGATE_URL}/api/v1/skills`) run it,
106
+ or read its `reference.md`.
109
107
 
110
108
  ## Multi-job pipelines
111
109
 
112
110
  ```bash
113
111
  # job A — creates the run, leaves it open
114
- govgate report unit-results.xml --no-complete # emits MT_RUN_ID (GH output / ADO variable)
112
+ govgate report unit-results.xml --no-complete # emits GOVGATE_RUN_ID (GH output / ADO variable)
115
113
 
116
114
  # job B — appends to the same run
117
- govgate report e2e-results.xml --run-id $MT_RUN_ID --no-complete
115
+ govgate report e2e-results.xml --run-id $GOVGATE_RUN_ID --no-complete
118
116
 
119
117
  # final job — completes + gates over everything
120
- govgate complete --run-id $MT_RUN_ID --fail-on fail --min-executed 80
118
+ govgate complete --run-id $GOVGATE_RUN_ID --fail-on fail --min-executed 80
121
119
  ```
122
120
 
123
- See `docs/examples/github-actions-ci-report.yml` and
124
- `docs/examples/azure-devops-ci-report.yml` in the
125
- [Maersk-Training/mt-testing-tool](https://github.com/Maersk-Training/mt-testing-tool)
126
- repo for full pipelines.
121
+ Full pipeline examples for GitHub Actions and Azure DevOps ship with your Governance OS
122
+ deployment (served alongside the skills at `${GOVGATE_URL}/api/v1/skills`).
127
123
 
128
124
  ## Registry
129
125
 
package/dist/index.js CHANGED
@@ -104,12 +104,12 @@ function detectCiContext(env = process.env) {
104
104
  };
105
105
  }
106
106
  function emitRunIdVariable(runId, ctx, env = process.env) {
107
- console.log(`MT_RUN_ID=${runId}`);
107
+ console.log(`GOVGATE_RUN_ID=${runId}`);
108
108
  if (ctx.provider === "github" && env.GITHUB_OUTPUT) {
109
109
  appendFileSync(env.GITHUB_OUTPUT, `run-id=${runId}
110
110
  `);
111
111
  } else if (ctx.provider === "azure-devops") {
112
- console.log(`##vso[task.setvariable variable=MT_RUN_ID;isOutput=true]${runId}`);
112
+ console.log(`##vso[task.setvariable variable=GOVGATE_RUN_ID;isOutput=true]${runId}`);
113
113
  }
114
114
  }
115
115
 
@@ -126,7 +126,7 @@ function findConfigFile(startDir, explicitPath) {
126
126
  }
127
127
  let dir = resolve(startDir);
128
128
  for (; ; ) {
129
- const candidate = join(dir, ".mt-testing.json");
129
+ const candidate = join(dir, "govgate", "config.json");
130
130
  if (existsSync(candidate)) return candidate;
131
131
  const parent = dirname(dir);
132
132
  if (parent === dir) return void 0;
@@ -169,26 +169,36 @@ function loadFileConfig(path) {
169
169
  }
170
170
  return out;
171
171
  }
172
+ function loadFileMappings(flags, cwd = process.cwd()) {
173
+ const configPath = findConfigFile(cwd, flags.config);
174
+ const file = configPath ? loadFileConfig(configPath) : {};
175
+ return {
176
+ mappings: file.mappings ?? {},
177
+ suite: flags.suite ?? file.suite,
178
+ environment: flags.env ?? file.defaultEnvironment,
179
+ configPath
180
+ };
181
+ }
172
182
  function resolveConfig(flags, cwd = process.cwd()) {
173
183
  const configPath = findConfigFile(cwd, flags.config);
174
184
  const file = configPath ? loadFileConfig(configPath) : {};
175
- const url = flags.url ?? process.env.MT_TESTING_TOOL_URL;
176
- const apiKey = flags.apiKey ?? process.env.MT_TESTING_TOOL_API_KEY;
185
+ const url = flags.url ?? process.env.GOVGATE_URL;
186
+ const apiKey = flags.apiKey ?? process.env.GOVGATE_API_KEY;
177
187
  const suite = flags.suite ?? file.suite;
178
188
  const environment = flags.env ?? file.defaultEnvironment;
179
189
  if (!url) {
180
190
  throw new ConfigError(
181
- "Tool URL missing. Set MT_TESTING_TOOL_URL or pass --url https://<your-deployment>"
191
+ "Tool URL missing. Set GOVGATE_URL or pass --url https://<your-deployment>"
182
192
  );
183
193
  }
184
194
  if (!apiKey) {
185
195
  throw new ConfigError(
186
- "API key missing. Set MT_TESTING_TOOL_API_KEY (create one in the tool: Admin -> API keys, scoped to this application)."
196
+ "API key missing. Set GOVGATE_API_KEY (create one in the tool: Admin -> API keys, scoped to this application)."
187
197
  );
188
198
  }
189
199
  if (!suite) {
190
200
  throw new ConfigError(
191
- 'Suite missing. Pass --suite <slug> or add { "suite": "<slug>" } to .mt-testing.json in the repo root.'
201
+ 'Suite missing. Pass --suite <slug> or add { "suite": "<slug>" } to govgate/config.json in the repo root.'
192
202
  );
193
203
  }
194
204
  return {
@@ -392,7 +402,7 @@ function printMappingTable(outcome) {
392
402
  }
393
403
  if (outcome.unmappedTests.length) {
394
404
  console.log(`
395
- Unmapped tests (${outcome.unmappedTests.length}) \u2014 add @mt-<case> tags or .mt-testing.json mappings:`);
405
+ Unmapped tests (${outcome.unmappedTests.length}) \u2014 add @mt-<case> tags or govgate/config.json mappings:`);
396
406
  for (const t of outcome.unmappedTests.slice(0, 20)) console.log(` - ${t.id}`);
397
407
  if (outcome.unmappedTests.length > 20)
398
408
  console.log(` \u2026 and ${outcome.unmappedTests.length - 20} more`);
@@ -476,8 +486,8 @@ async function completeAndGate(api, url, runId, gate) {
476
486
  printRunUrl(url, runId);
477
487
  if (!verdict.passed) process.exit(EXIT_GATE_FAILED);
478
488
  }
479
- var program = new Command().name("govgate").description("Report CI test results to the MT Testing Tool and gate releases on the outcome.");
480
- program.command("report").description("Parse test result files (JUnit XML), map tests to cases, and report a run").argument("<files...>", "result files or globs, e.g. test-results/*.xml").option("--url <url>", "tool URL (or MT_TESTING_TOOL_URL)").option("--api-key <key>", "API key (prefer MT_TESTING_TOOL_API_KEY)").option("--config <path>", "path to .mt-testing.json (default: searched upward)").option("--suite <slug>", "suite slug (overrides config)").option("--env <slug>", "environment slug (overrides config)").option("--name <name>", "run name (default: derived from CI context)").option("--build-version <v>", "build version (default: short commit SHA from CI)").option("--external-url <url>", "link to the build/PR (default: from CI context)").option("--format <format>", "input format", "junit").option("--run-id <uuid>", "append results to an existing run instead of creating one").option("--no-complete", "leave the run in progress (multi-job pipelines); skips the gate").option("--fail-on <list>", "statuses that fail the gate: fail | fail,blocked", "fail").option("--min-executed <pct>", "minimum executed percentage required by the gate").option("--actor <label>", "tested-by label on results", "govgate").option("--dry-run", "parse and map only; post nothing").action(async (files, opts) => {
489
+ var program = new Command().name("govgate").description("Report CI test results to your testing tool and gate releases on the outcome.");
490
+ program.command("report").description("Parse test result files (JUnit XML), map tests to cases, and report a run").argument("<files...>", "result files or globs, e.g. test-results/*.xml").option("--url <url>", "tool URL (or GOVGATE_URL)").option("--api-key <key>", "API key (prefer GOVGATE_API_KEY)").option("--config <path>", "path to govgate/config.json (default: searched upward)").option("--suite <slug>", "suite slug (overrides config)").option("--env <slug>", "environment slug (overrides config)").option("--name <name>", "run name (default: derived from CI context)").option("--build-version <v>", "build version (default: short commit SHA from CI)").option("--external-url <url>", "link to the build/PR (default: from CI context)").option("--format <format>", "input format", "junit").option("--run-id <uuid>", "append results to an existing run instead of creating one").option("--no-complete", "leave the run in progress (multi-job pipelines); skips the gate").option("--fail-on <list>", "statuses that fail the gate: fail | fail,blocked", "fail").option("--min-executed <pct>", "minimum executed percentage required by the gate").option("--actor <label>", "tested-by label on results", "govgate").option("--dry-run", "parse and map only; post nothing").action(async (files, opts) => {
481
491
  try {
482
492
  const flags = {
483
493
  url: opts.url,
@@ -488,7 +498,7 @@ program.command("report").description("Parse test result files (JUnit XML), map
488
498
  };
489
499
  const tests = await parseFiles(files, opts.format);
490
500
  const config = opts.dryRun ? tryResolveConfig(flags) : resolveConfig(flags);
491
- const mappings = config?.mappings ?? {};
501
+ const mappings = config?.mappings ?? (opts.dryRun ? loadFileMappings(flags).mappings : {});
492
502
  const outcome = mapTestsToCases(tests, mappings);
493
503
  console.log(
494
504
  `Parsed ${tests.length} test(s) from ${files.join(", ")} \u2014 ${outcome.results.length} case(s) mapped, ${outcome.unmappedTests.length} unmapped test(s)`
@@ -554,7 +564,7 @@ function tryResolveConfig(flags) {
554
564
  return void 0;
555
565
  }
556
566
  }
557
- program.command("complete").description("Complete a run and evaluate the gate (final job of a multi-job pipeline)").requiredOption("--run-id <uuid>", "run to complete").option("--url <url>", "tool URL (or MT_TESTING_TOOL_URL)").option("--api-key <key>", "API key (prefer MT_TESTING_TOOL_API_KEY)").option("--config <path>", "path to .mt-testing.json").option("--suite <slug>", "suite slug (only used for config resolution)").option("--fail-on <list>", "statuses that fail the gate: fail | fail,blocked", "fail").option("--min-executed <pct>", "minimum executed percentage required by the gate").action(async (opts) => {
567
+ program.command("complete").description("Complete a run and evaluate the gate (final job of a multi-job pipeline)").requiredOption("--run-id <uuid>", "run to complete").option("--url <url>", "tool URL (or GOVGATE_URL)").option("--api-key <key>", "API key (prefer GOVGATE_API_KEY)").option("--config <path>", "path to govgate/config.json").option("--suite <slug>", "suite slug (only used for config resolution)").option("--fail-on <list>", "statuses that fail the gate: fail | fail,blocked", "fail").option("--min-executed <pct>", "minimum executed percentage required by the gate").action(async (opts) => {
558
568
  try {
559
569
  const config = resolveConfig({
560
570
  url: opts.url,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "govgate",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Governance gate for releases: report CI test results (JUnit XML) to your testing tool and gate promotion on the outcome.",
5
5
  "license": "MIT",
6
6
  "author": "HatStack",