Launch Runbook — PyPI + npm¶
How kew reaches its two registries in one motion: what is automatic, the
one-time manual steps, and the single-flag launch.
Distribution names: kew-cli on PyPI (pip install kew-cli; the
installed command is kew — the PyPI name kew is an unrelated project) and
create-kew on npm (npx create-kew, the recommended onboarding path).
The release pipeline lives in .github/workflows/release.yml; a single publish
gate — the repository variable PUBLISH_RELEASE — governs both the PyPI and
npm publishes, so they flip together.
One-time setup (now, alongside the packaging PR)¶
1. Create the GitHub environments¶
gh api --method PUT repos/thossullivan/kew/environments/pypi
gh api --method PUT repos/thossullivan/kew/environments/testpypi
gh api --method PUT repos/thossullivan/kew/environments/npm
2. Register the pending publishers (web UI — the only manual steps)¶
On pypi.org: log in → Account settings → Publishing (https://pypi.org/manage/account/publishing/) → "Add a new pending publisher" → GitHub tab:
| Field | Value |
|---|---|
| PyPI Project Name | kew-cli |
| Owner | thossullivan |
| Repository name | kew |
| Workflow name | release.yml |
| Environment name | pypi |
On test.pypi.org: same form at https://test.pypi.org/manage/account/publishing/:
| Field | Value |
|---|---|
| PyPI Project Name | kew-cli |
| Owner | thossullivan |
| Repository name | kew |
| Workflow name | release.yml |
| Environment name | testpypi |
On npmjs.com: no access token is used — trusted publishing is OIDC. Log in →
the create-kew package's Settings → Trusted Publishing (Account → Publishing
before the package exists) → add a GitHub Actions publisher:
| Field | Value |
|---|---|
| Package name | create-kew |
| Organization/User | thossullivan |
| Repository | kew |
| Workflow filename | release.yml |
| Environment | npm |
3. Claim the names (stub publish — PyPI + npm in one dispatch)¶
A single dispatch claims both names and exercises both OIDC auth paths
(the only real pre-launch test of the npm auth round-trip — the standing
npm publish --dry-run cannot check auth):
Verify PyPI: https://pypi.org/project/kew-cli/ exists and shows only
0.0.1.dev0, and a plain install still fails for the public (pip ignores
dev releases without --pre):
Verify npm:
The create-kew@0.0.1 stub is a functional-but-old wizard (npm has no
dev-release equivalent to hide it). Optionally deprecate it so it never
resolves as @latest at launch — needs an interactive npm login, so it is not
run in CI:
Standing rehearsal (automatic)¶
Every release on main publishes kew-cli to TestPyPI (skip-existing: true
absorbs workflow re-runs) and attaches the sdist + wheel to the GitHub release,
and runs npm publish --dry-run for create-kew (proving the tarball packs;
it does not check npm auth — that is what the §3 stub claim is for).
Spot-check monthly, and once more just before launch:
pipx install --index-url https://test.pypi.org/simple/ \
--pip-args="--extra-index-url https://pypi.org/simple/" kew-cli
kew --version
pipx uninstall kew-cli
Launch day¶
One flag flips both registries:
Then produce a release. Re-running an old workflow run will not publish —
semantic-release finds no new commits and releases nothing. Either merge any
pending fix:/feat: PR, or:
That single release run publishes kew-cli to PyPI, then (ordered after it)
create-kew to npm at the same version.
Verify:
- Both the
publish-pypiandpublish-npmjobs ran (not skipped) in the release workflow. - https://pypi.org/project/kew-cli/ renders the landing page and https://www.npmjs.com/package/create-kew shows the new version; all links and badges resolve.
- On a clean machine:
pipx install kew-cli && kew --version && kew --help, andnpx create-kew@latestscaffolds cleanly.
Rollback¶
- Stop future publishes:
gh variable set PUBLISH_RELEASE --body false(TestPyPI + npm dry-run rehearsals continue; nothing already published is affected). - Bad PyPI release: yank it, never delete it. There is no official CLI for
yanking — use the web UI: https://pypi.org/manage/project/kew-cli/releases/
→ the release → Options → Yank. Yanked versions remain installable for
users who pin
kew-cli==X.Y.Zexactly, but resolvers skip them otherwise. - Bad npm release:
npm deprecate create-kew@X.Y.Z "reason"(warns on install but keeps it resolvable).npm unpublish create-kew@X.Y.Zonly within 72h and only if nothing depends on it — never rely on unpublish for a version users may already have pinned.