Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
192 changes: 51 additions & 141 deletions .github/RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/<owner>/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/<owner>/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: `<your-github-username>`
- 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).
<one-line summary of what shipped>

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/<owner>/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 `<!-- PRE-PYPI:` to `<!-- /PRE-PYPI -->` (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/<!-- PRE-PYPI:.*?<!-- \/PRE-PYPI -->\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`