Skip to content

Commit 564d32c

Browse files
authored
Merge pull request DeusData#1536 from DeusData/fix/publish-registries-idempotent
fix(release): unwedge publish-registries — twine 7 for Metadata-Version 2.5, idempotent re-runs
2 parents f7d422d + 462b0d3 commit 564d32c

1 file changed

Lines changed: 22 additions & 3 deletions

File tree

‎.github/workflows/release.yml‎

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -335,8 +335,17 @@ jobs:
335335
# A prerelease must never become npm `latest` — plain `npm install`
336336
# would serve the RC to everyone. Publish prereleases under the
337337
# `next` dist-tag; testers opt in via `npm i codebase-memory-mcp@next`.
338+
#
339+
# Idempotency: npm versions are immutable, so a re-run of this job
340+
# after a partial success (v0.10.1: npm published, then the twine
341+
# step died) can never republish — it 403s on its own earlier
342+
# success and the release wedges in draft forever. If the exact
343+
# version already exists on the registry, publishing is DONE; skip.
338344
run: |
339-
if [[ "$RELEASE_VERSION" == *-* ]]; then
345+
V="${RELEASE_VERSION#v}"
346+
if npm view "codebase-memory-mcp@$V" version >/dev/null 2>&1; then
347+
echo "npm already has codebase-memory-mcp@$V — skipping publish (idempotent re-run)"
348+
elif [[ "$RELEASE_VERSION" == *-* ]]; then
340349
npm publish --access public --provenance --tag next
341350
else
342351
npm publish --access public --provenance
@@ -354,15 +363,25 @@ jobs:
354363
# Pin to specific versions (typosquatting / supply-chain mitigation).
355364
# OSSF scorecard prefers --require-hashes, but that needs full
356365
# transitive deps; version pinning is the practical compromise.
357-
python -m pip install --upgrade 'build==1.3.0' 'twine==6.2.0'
366+
#
367+
# twine >= 7 is required: `python -m build` resolves the UNPINNED
368+
# hatchling backend fresh in its isolated env, and current hatchling
369+
# emits Metadata-Version 2.5, which twine 6.2.0 rejects as invalid
370+
# ("'2.5' is not a valid metadata version" — the v0.10.1 failure).
371+
# Verified locally: identical artifacts, 6.2.0 rejects / 7.0.0 passes.
372+
python -m pip install --upgrade 'build==1.3.0' 'twine==7.0.0'
358373
python -m build
374+
twine check dist/*
359375
360376
- name: Publish to PyPI
361377
working-directory: pkg/pypi
362378
env:
363379
TWINE_USERNAME: __token__
364380
TWINE_PASSWORD: ${{ secrets.PYPI_TOKEN }}
365-
run: twine upload --non-interactive dist/*
381+
# --skip-existing: PyPI files are immutable like npm versions; a
382+
# re-run after partial success must treat already-uploaded files
383+
# as done, not as a fatal collision.
384+
run: twine upload --non-interactive --skip-existing dist/*
366385

367386
# ── 8b. Publish server.json to the official MCP Registry ──────
368387
# Runs after npm + PyPI so the registry can verify package ownership

0 commit comments

Comments
 (0)