Files
mcp-windbg/scripts
Sven Scharmentke 92f73c2494 ci: gate the release on every version and the CHANGELOG agreeing (#94)
Makes `check-version-consistency.ps1` a gate instead of a post-mortem.

It ran from the publish build - which is *after* release-please has
created the tag and the GitHub release. It reported problems that had
already shipped, and the only way to correct one was to cut a second
release. CLAUDE.md described this as "caught, but late".

It now runs as a `preflight` job that `release-please` depends on, so a
release that is not internally consistent never gets a tag.

## What is asserted

All seven version sources must carry the same version:

| Source | Kept in step by |
| :----- | :-------------- |
| `pyproject.toml` | release-please, natively |
| `server.json` top level and `packages[*]` | two `extra-files` entries
|
| `.release-please-manifest.json` | release-please, natively |
| `plugins/mcp-windbg/.claude-plugin/plugin.json` | `extra-files` |
| `.claude-plugin/marketplace.json` | `extra-files` |
| the `uvx` pin in the plugin `.mcp.json` | `extra-files` |

Plus: `CHANGELOG.md`s top heading names that version, **and has an entry
under it**.

## Two assertions added while promoting it

- **`.release-please-manifest.json`** was unchecked. It is the version
release-please computes the *next* release from, so drift there silently
misprices the following release rather than the current one.
- **A bare heading**. `## [1.2.0]` with nothing beneath it matched the
version comparison perfectly and published empty release notes. The
`release-notes` job could only emit a warning about it, after the
release existed.

## Why only release merges are checked

On an ordinary push `CHANGELOG.md` correctly carries `## [Unreleased]`,
which would fail the version comparison on every single commit. The job
therefore reads the head commit subject and only enforces on
`chore(develop): release ...`. Verified against real subjects:

```
CHECK  <- chore(develop): release 1.2.0 (#91)
SKIP   <- fix(plugin): stop the agent hard-coding (#92)
SKIP   <- chore(main): release 1.2.0 (#89)
```

## Verification

Three states, exit codes checked directly rather than through a pipe:

| State | Expected | Got |
| :---- | :------- | :-- |
| Today`s tree, `## [Unreleased]` on top | fail | exit 1, names the
mismatch |
| Simulated 1.2.0 release, all seven sources bumped | pass | exit 0 |
| 1.2.0 heading with an empty body | fail | exit 1, names the empty
section |

The script still runs from the publish build as well, which is what
guards a `publish-mcp.yml` started by hand.
2026-08-27 21:34:14 +02:00
..