From 6876ea8b7c82bf2c4f9b28aa3a8c052aebaccd94 Mon Sep 17 00:00:00 2001 From: Aymen Hammouda Date: Thu, 14 May 2026 23:04:56 +0200 Subject: [PATCH] docs(release): generalize RELEASE.md to be version-agnostic + drop one-time scaffolding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cleans up RELEASE.md after the v0.1.5/v0.1.6 release wave. Three structural fixes that together cut the file from 205 to 114 lines: 1. Collapse the duplicate "Creating a Release" + "v0.1.1 Release Checklist" sections into one canonical "Release Checklist" using an X.Y.Z placeholder. Maintainers replace X.Y.Z with the version they are releasing. 2. Replace hardcoded versions (0.1.1, 0.1.2) and `` template URLs with X.Y.Z placeholders and the actual repo URL. The two surviving numeric references (0.1.7 as the example version; v0.1.5 → v0.1.6 as historical context for the mcp-publisher-validate step) are intentional. 3. Drop the "Post-PyPI Launch Pack Cleanup" section entirely. That work (PRE-PYPI fence strip, docs/launch/ submission paths, manual MCP Registry submission) was a one-time scaffolding for the PyPI debut. PRE-PYPI fences are gone from README; MCP Registry publish is now automated by the release workflow; docs/launch/ is not tracked. Preserves from earlier work: - The mcp-publisher validate check added in PR #35. - The Trusted Publishing one-time setup steps. - Coverage notes (Python 3.13 release matrix; docs 3.10–3.14). Adds: - Lockstep version check across all four files (pyproject.toml + server.json:11 + server.json:17 + uv.lock). - Cache-bust step in fresh-install verification (lesson from v0.1.6 where uvx returned stale 0.1.5 until --refresh-package). - MCP Registry isLatest check via JSON API. --- .github/RELEASE.md | 192 ++++++++++++--------------------------------- 1 file changed, 51 insertions(+), 141 deletions(-) diff --git a/.github/RELEASE.md b/.github/RELEASE.md index 62a9102..1ad8096 100644 --- a/.github/RELEASE.md +++ b/.github/RELEASE.md @@ -2,203 +2,113 @@ ## One-Time Setup: PyPI Trusted Publishing -Before the first release, configure PyPI Trusted Publishing: +Already configured for this project — these steps are kept for reference when forking or recovering the publisher state. 1. Go to https://pypi.org/manage/account/publishing/ -2. Add a new pending publisher: +2. Add a publisher (pending or active): - **PyPI project name**: `python-docs-mcp-server` - - **Owner**: your GitHub username or org + - **Owner**: your GitHub username or org (this repo: `ayhammouda`) - **Repository**: `python-docs-mcp-server` - **Workflow name**: `release.yml` - **Environment name**: `pypi` 3. In the GitHub repo, go to Settings > Environments 4. Create an environment named `pypi` 5. (Optional) Add environment protection rules: - - Required reviewers (recommended for first release) + - Required reviewers (recommended) - Deployment branches: only `main` tags -## Notes +## Coverage notes -**Runtime coverage:** The release workflow builds and tests against Python 3.13 only. -Python 3.12 is covered by the CI workflow (`ci.yml`) which runs a 2x2 matrix -(3.12/3.13 x ubuntu/macos) on every push to `main`. Since tags are created -from commits that have already passed CI, 3.12 compatibility is verified before -the release workflow runs. This is an accepted trade-off to keep the release -artifact pipeline simple (single Python version produces the wheel). +**Runtime coverage:** the release workflow builds and tests against Python 3.13 only. Python 3.12 is covered by the CI workflow (`ci.yml`), which runs a 2×2 matrix (3.12/3.13 × ubuntu/macos) on every push to `main`. Since tags are created from commits that have already passed CI, 3.12 compatibility is verified before the release workflow runs. This is an accepted trade-off to keep the release artifact pipeline simple (single Python version produces the wheel). -**Documentation coverage:** The full docs index target is Python documentation -versions 3.10 through 3.14. +**Documentation coverage:** the full docs index target is Python documentation versions 3.10 through 3.14. -## Creating a Release +--- -1. Ensure all tests pass on main: - ```bash - uv run pytest --tb=short -q - uv run ruff check src/ tests/ - uv run pyright src/ - ``` +## Release Checklist -2. Verify the version in `pyproject.toml` is correct: - ```bash - grep '^version' pyproject.toml - # Should show: version = "0.1.2" - ``` - -3. Create and push the tag: - ```bash - git tag -a v0.1.2 -m "Release v0.1.2" - git push origin v0.1.2 - ``` - -4. Monitor the release workflow at: - https://github.com//python-docs-mcp-server/actions/workflows/release.yml - -5. Verify the package on PyPI: - https://pypi.org/project/python-docs-mcp-server/0.1.2/ - -## Post-Release Verification - -After the package is published: - -```bash -# In a fresh environment: -uvx python-docs-mcp-server --version -# Should print: 0.1.1 - -# Or via pipx: -pipx run python-docs-mcp-server --version -# Should print: 0.1.1 -``` - -## v0.1.1 Release Checklist - -Complete these steps in order. Each step has a checkbox -- do not skip ahead. +Replace `X.Y.Z` below with the version you are releasing (e.g. `0.1.7`). Complete each step in order; do not skip ahead. The release workflow at `.github/workflows/release.yml` runs four jobs in sequence on every `v*` tag push: `build` → `publish` (PyPI) → `publish-mcp-registry` → `github-release`. ### Pre-Release Verification -- [ ] All CI tests green on main: check https://github.com//python-docs-mcp-server/actions/workflows/ci.yml +- [ ] All CI tests green on `main`: https://github.com/ayhammouda/python-docs-mcp-server/actions/workflows/ci.yml - [ ] Local test suite passes: ```bash uv run pytest --tb=short -q + uv run ruff check src/ tests/ + uv run pyright src/ ``` -- [ ] Version in `pyproject.toml` is `0.1.1`: +- [ ] All four version-bearing files agree on `X.Y.Z` (the release workflow's `Verify tag matches package version` step enforces this; matching here saves a CI round-trip): ```bash grep '^version' pyproject.toml + python3 -c 'import json; d = json.load(open("server.json")); print("server.json:", d["version"], "/ packages[0]:", d["packages"][0]["version"])' + grep '^name = "python-docs-mcp-server"' -A1 uv.lock | head -2 ``` - [ ] `server.json` validates against the live MCP Registry schema. MCP Registry enforces stricter limits than PyPI (e.g. `description ≤ 100 chars`); validating before the tag prevents a half-published release (PyPI succeeds while MCP Registry rejects, as happened on v0.1.5 → recovered in v0.1.6): ```bash curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher ./mcp-publisher validate server.json ``` - Must report `✅ server.json is valid`. If validation fails, shorten the `server.json` `description` on `main` before tagging (the `pyproject.toml` description is unbounded by this constraint and can stay longer). + Must report `✅ server.json is valid`. If validation fails, shorten `server.json` `description` on `main` before tagging (the `pyproject.toml` description is unbounded by this constraint and can stay longer). - [ ] Integration tests from `.github/INTEGRATION-TEST.md` are complete and signed off -- [ ] Doctor subcommand passes: +- [ ] `Doctor` subcommand passes: ```bash uv run python-docs-mcp-server doctor ``` - -### PyPI Trusted Publishing Setup (one-time) - -- [ ] PyPI pending publisher configured at https://pypi.org/manage/account/publishing/: - - PyPI project name: `python-docs-mcp-server` - - Owner: `` - - Repository: `python-docs-mcp-server` - - Workflow name: `release.yml` - - Environment name: `pypi` -- [ ] GitHub environment `pypi` created in repo Settings > Environments +- [ ] `CHANGELOG.md` has a dated entry for `[X.Y.Z]` ### Tag and Release -- [ ] Create the annotated tag: +- [ ] Create the annotated tag (replace `X.Y.Z` everywhere): ```bash - git tag -a v0.1.1 -m "Release v0.1.1 - - First public release of python-docs-mcp-server. + git tag -a vX.Y.Z -m "Release vX.Y.Z - A read-only, version-aware MCP retrieval server over Python - standard library documentation (3.10 through 3.14). + - Installable via: uvx python-docs-mcp-server" + See CHANGELOG.md for the full entry." ``` - [ ] Push the tag to trigger the release workflow: ```bash - git push origin v0.1.1 + git push origin vX.Y.Z + ``` +- [ ] Watch the workflow run to completion: + ```bash + gh run watch $(gh run list --workflow=release.yml --limit 1 --json databaseId -q '.[0].databaseId') --exit-status ``` -- [ ] Monitor the workflow run: https://github.com//python-docs-mcp-server/actions/workflows/release.yml -- [ ] Verify all three jobs pass: `build` -> `publish` -> `github-release` +- [ ] All four jobs green: `build` → `publish` → `publish-mcp-registry` → `github-release` -### Post-Release Verification (SHIP-06) +### Post-Release Verification -- [ ] Package visible on PyPI: https://pypi.org/project/python-docs-mcp-server/0.1.2/ -- [ ] Attestation visible on PyPI package page (look for "Provenance" badge) -- [ ] Fresh install test: +- [ ] PyPI listing exists with attestation badge: `https://pypi.org/project/python-docs-mcp-server/X.Y.Z/` +- [ ] Fresh install test from a clean shell (cache-busted so the new version actually resolves): ```bash - # Clear any cached version uv cache clean python-docs-mcp-server 2>/dev/null || true - - # Install and verify version - uvx python-docs-mcp-server --version - # Expected output: 0.1.1 + uvx --refresh python-docs-mcp-server@X.Y.Z --version + # Expected: python-docs-mcp-server X.Y.Z ``` -- [ ] Full README flow test (from a clean environment): +- [ ] Full install flow: ```bash - # Step 1: Install - uvx python-docs-mcp-server --version - # Should print 0.1.1 - - # Step 2: Build index uvx python-docs-mcp-server build-index --versions 3.10,3.11,3.12,3.13,3.14 - # Should complete successfully - - # Step 3: Doctor check uvx python-docs-mcp-server doctor - # All checks should PASS ``` -- [ ] Slow E2E workflow passes: - - Run GitHub Actions workflow `Slow E2E` - - Confirm Python 3.13 and Python 3.14 jobs both pass - - Confirm each job installs the built wheel, runs - `build-index --versions 3.10,3.11,3.12,3.13,3.14`, `doctor`, and - `validate-corpus` - -### Post-PyPI Launch Pack Cleanup - -- [ ] Remove every temporary PyPI pre-release block from `README.md`: - - Mechanical pass: delete every region from `` (inclusive). Each block now encloses its surrounding heading + lead-in sentence + code, so a single pass produces a clean README. - - Reference command: - `perl -0777 -i -pe 's/\n*//gs' README.md` - - Make the published package commands (`uvx python-docs-mcp-server ...`) the - primary install, build-index, MCP client, `doctor`, and `validate-corpus` - examples -- [ ] Verify `README.md` has no temporary pre-release install artifacts: + Both must complete successfully. +- [ ] MCP Registry shows `X.Y.Z` as the `isLatest` entry: ```bash - rg -n 'PRE[-]PYPI|Before PyPI publishing|Until the first PyPI|After PyPI publishing|git\\+https://github.com/.*/python-docs-mcp-server' README.md + curl -s 'https://registry.modelcontextprotocol.io/v0.1/servers?search=python-docs-mcp-server' | \ + python3 -c "import json,sys; d=json.load(sys.stdin); print(next((e['server']['version'] for e in d['servers'] if e['_meta']['io.modelcontextprotocol.registry/official']['isLatest']), 'no latest'))" ``` - The command should return no output. -- [ ] Review `docs/launch/` so no public launch copy still asks users to install - from GitHub source after the PyPI package is available. Intentional historical - pre-release drafts may remain, but they must stay clearly labeled as - pre-PyPI-only. -- [ ] Submit `server.json` to https://registry.modelcontextprotocol.io/ via the - `mcp-publisher` CLI after the PyPI smoke test passes; verify the registry - listing appears and points at version 0.1.1 -- [ ] Use the post-PyPI draft in `docs/launch/show-hn.md` for the HN submission -- [ ] Use `docs/launch/reddit-posts.md` for the r/Python and r/LocalLLaMA - submissions after the PyPI release smoke test passes -- [ ] Commit and push the README cleanup before public launch posts go out - -- [ ] Claude Desktop test with published package: - Configure `mcpServers` with `uvx python-docs-mcp-server` and verify - "what is asyncio.TaskGroup" returns a correct hit +- [ ] GitHub Release exists at `https://github.com/ayhammouda/python-docs-mcp-server/releases/tag/vX.Y.Z` with wheel + sdist attached and auto-generated notes +- [ ] **Slow E2E workflow** passes (manually triggered after publish): + - Run GitHub Actions workflow `Slow E2E` (`.github/workflows/e2e.yml`) + - Python 3.13 and 3.14 jobs both pass + - Each job installs the built wheel and runs `build-index --versions 3.10,3.11,3.12,3.13,3.14`, `doctor`, and `validate-corpus` +- [ ] Claude Desktop manual smoke test: + Configure `mcpServers` with `uvx python-docs-mcp-server` and verify a known query (e.g. "what is asyncio.TaskGroup") returns a correct hit. ### Release Complete -- [ ] GitHub Release exists with attached artifacts -- [ ] PyPI page shows 0.1.1 with attestation -- [ ] README install instructions verified end-to-end -- [ ] README no longer contains temporary pre-PyPI GitHub-source install blocks -- [ ] Slow E2E workflow passed for the release candidate -- [ ] Tag v0.1.1 exists in git - -**Release date**: _______________ -**Released by**: _______________ +- [ ] All four `release.yml` jobs green for `vX.Y.Z` +- [ ] PyPI page shows `X.Y.Z` with the "Provenance" attestation badge +- [ ] MCP Registry `isLatest` entry points at `X.Y.Z` +- [ ] GitHub Release `vX.Y.Z` exists with both dist artifacts attached +- [ ] `CHANGELOG.md` `[X.Y.Z]` entry is committed on `main`