mirror of
https://github.com/svnscha/mcp-windbg.git
synced 2026-10-16 20:32:50 +08:00
ci: regenerate uv.lock on the release PR (#95)
Fixes the release PR failure at [run 33109222328](https://github.com/svnscha/mcp-windbg/actions/runs/33109222328/job/98647266760): ``` error: The lockfile at `uv.lock` needs to be updated, but `--check` was provided. ``` ## Not a false alarm `uv.lock` records the **project`s own version**, so release-please bumping `pyproject.toml` to 1.2.0 leaves the lockfile behind. This is exactly the drift that stranded `uv.lock` at 1.0.1 through the entire 1.1.0 release - the check added in #93 is doing its job, it just surfaced that nothing maintains the lockfile across a release. ## Why not an `extra-files` entry That was my first instinct and it is the wrong tool. release-please`s updaters **parse and re-serialise** the file they edit rather than patching it in place - which is exactly why `plugin.json`s inline `keywords` array reflowed to one entry per line in the current release PR. Harmless for a small hand-written manifest. Applying it to a 900-line generated lockfile, with a tool that does not own the format, is not a trade worth making, and the TOML updater would additionally need a filter expression (`$.package[?(@.name=="mcp-windbg")].version`) whose support release-please`s docs do not confirm - a naive `$.package[*].version` would rewrite the version of all 67 packages. ## What this does instead A `sync-lockfile` job runs `uv lock` against the open release PR and commits the result only if it moved. uv owns the file, so uv regenerates it. The PR branch comes from release-please`s `pr` output. It is a JSON string, so the expression short-circuits rather than handing `fromJson` an empty value: ```yaml pr_branch: ${{ steps.release.outputs.pr && fromJson(steps.release.outputs.pr).headBranchName }} ``` ## Verified The bump is a single field and needs no dependency re-resolution - setting the `mcp-windbg` entry in `uv.lock` to 1.2.0 by hand makes the check pass: ``` Resolved 67 packages in 1ms exit: 0 ``` I deliberately did **not** hand-fix `uv.lock` on the release branch, so that merging this exercises the new job for real against #91 rather than leaving it untested.
This commit is contained in:
@@ -75,6 +75,9 @@ jobs:
|
||||
tag_name: ${{ steps.release.outputs.tag_name }}
|
||||
# The release commit on develop. main is fast-forwarded onto exactly this.
|
||||
sha: ${{ steps.release.outputs.sha }}
|
||||
# Branch of the open release PR, empty when there is none. `pr` is a JSON
|
||||
# string, so the && short-circuits rather than handing fromJson nothing.
|
||||
pr_branch: ${{ steps.release.outputs.pr && fromJson(steps.release.outputs.pr).headBranchName }}
|
||||
steps:
|
||||
- uses: googleapis/release-please-action@v5
|
||||
id: release
|
||||
@@ -90,6 +93,39 @@ jobs:
|
||||
# token here if you want the PR gated by the test matrix before merge.
|
||||
# token: ${{ secrets.RELEASE_PLEASE_TOKEN }}
|
||||
|
||||
# uv.lock records the project's own version, so every version bump leaves it a
|
||||
# release behind and fails `uv lock --check`. release-please cannot fix that:
|
||||
# its updaters re-serialise the file they edit, which is safe for a small hand
|
||||
# written manifest and emphatically not for a generated 900-line lockfile. So
|
||||
# uv regenerates it, on the release PR, before anyone merges it.
|
||||
sync-lockfile:
|
||||
needs: release-please
|
||||
if: ${{ needs.release-please.outputs.pr_branch != '' }}
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
ref: ${{ needs.release-please.outputs.pr_branch }}
|
||||
|
||||
- uses: astral-sh/setup-uv@v7
|
||||
with:
|
||||
version: "latest"
|
||||
|
||||
- name: Regenerate uv.lock and commit it if it moved
|
||||
run: |
|
||||
uv lock
|
||||
if git diff --quiet -- uv.lock; then
|
||||
echo "uv.lock is already in step with pyproject.toml."
|
||||
exit 0
|
||||
fi
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
||||
git commit -m "chore: sync uv.lock with the release version" -- uv.lock
|
||||
git push
|
||||
echo "uv.lock synced onto the release PR."
|
||||
|
||||
# release-please is configured with skip-changelog, so CHANGELOG.md stays
|
||||
# hand-written - but it still creates the GitHub release with its own notes,
|
||||
# generated from commit subjects. Those are thinner than the entry a human
|
||||
|
||||
@@ -181,7 +181,18 @@ started by hand.
|
||||
release type updates `pyproject.toml`'s `[project] version` natively. `server.json` is not
|
||||
something it knows about, so it is handled by two `extra-files` JSONPath entries (`$.version` and
|
||||
`$.packages[*].version`) - the top-level and per-package versions are separate fields, and one
|
||||
entry carries one JSONPath.
|
||||
entry carries one JSONPath. The plugin manifest, the marketplace entry and the `uvx` pin in the
|
||||
plugin's `.mcp.json` are three more `extra-files` entries.
|
||||
|
||||
Expect an `extra-files` target to come back **re-serialised**, not patched in place: the updater
|
||||
parses the file and writes it out again, which is why `plugin.json`'s inline `keywords` array
|
||||
reflowed to one entry per line on the first release that touched it. Harmless for a small
|
||||
hand-written manifest; the reason `uv.lock` is not an `extra-files` target.
|
||||
|
||||
`uv.lock` is instead regenerated by the `sync-lockfile` job, which runs `uv lock` on the release
|
||||
PR and commits the result. It records the project's own version, so every bump leaves it a
|
||||
release behind - which is what `uv lock --check` in the build now fails on. Left to `extra-files`
|
||||
a 900-line generated lockfile would be re-serialised by a tool that does not own its format.
|
||||
|
||||
**Two setup requirements**, easy to lose track of:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user