SIGN IN SIGN UP

INTPYTHON-1069 Avoid using TestPyPI in the release process (#436)

[INTPYTHON-1069](https://jira.mongodb.org/browse/INTPYTHON-1069)

## Summary

Removes TestPyPI from the release process, following [PYTHON-5971 /
winkerberos#161](https://github.com/mongodb/winkerberos/pull/161) and
PYTHON-5970 (PyMongo). PyPI admins are deprecating TestPyPI and have
already de-prioritized it; local validation replaces the round-trip.

Two reasons specific to this repo:

- **TestPyPI is a hard blocker for the first
`langchain-mongodb-deepagents-vfs` release.** Trusted publishing needs a
pending publisher on every index used, and the maintainer's TestPyPI
account name/email doesn't match their PyPI one — recoverable only by
emailing PyPI support.
- `_test_release.yml` passed `skip-existing: true`, which its own
comment describes as *"only for CI use and extremely dangerous
otherwise"*.

## Changes in this PR

| File | Change |
|---|---|
| `.github/workflows/_test_release.yml` | deleted (96 lines) |
| `.github/workflows/_release.yml` | `test-pypi-publish` job removed; 3
`needs:` entries dropped; `validate-pyproject` + `twine check --strict`
added to `build`; `pre-release-checks` reworked |

`RELEASE.md` needed no change — it never referenced TestPyPI.

### The non-obvious part: `pre-release-checks`

The coupling here is deeper than in winkerberos, which only had a
publish step to delete. This job installed the package **from TestPyPI**
to validate the built artifact the way a consumer receives it:

```
uv run pip install --extra-index-url https://test.pypi.org/simple/ "$PKG_NAME==$VERSION" || \
  ( sleep 5 && uv run pip install --extra-index-url ... )
```

TestPyPI was only the delivery mechanism for that check, so it now
installs the wheel directly from the `dist` artifact the `build` job
already uploads. A `download-artifact` step is added, since that job
didn't previously fetch it. The sleep-and-retry loops are gone — they
existed solely for TestPyPI propagation delay.

### ⚠️ twine must be pinned — the house recipe fails verbatim here

```
$ uvx twine check --strict dist/*
ERROR  InvalidDistribution: Invalid distribution metadata: '2.5' is not a valid metadata version
```

Not stale tooling: `uvx` resolves twine 6.2.0, and **twine <7 cannot
parse `Metadata-Version: 2.5`**, which current hatchling emits. With the
floor:

```
$ uvx --from 'twine>=7' twine check --strict dist/*
Checking dist/langchain_mongodb-0.12.0-py3-none-any.whl: PASSED
Checking dist/langchain_mongodb-0.12.0.tar.gz: PASSED
```

PyPI itself accepts Metadata 2.5 — `hatchling` 1.32.0 and `langsmith`
0.11.1 are published with it — so twine was simply behind. This also
retroactively explains the `test_distribution.py` failure removed in
#427; that was the same root cause, not vaguely "outdated local twine".

## Trade-off

**Lost:** a genuine round-trip through a warehouse instance, which
implicitly proved PyPI would accept the artifact's metadata *before* the
real upload. That now surfaces in `publish` instead. `twine check
--strict` in the `build` job is the intended mitigation and covers the
same class of problem locally.

**Gained:** `pre-release-checks` now resolves dependencies from **real**
PyPI rather than a TestPyPI/PyPI hybrid, making it a more faithful
consumer simulation than before; one fewer OIDC publisher per new
package; `skip-existing` gone; shorter pipeline.

## Test Plan

- `validate-pyproject` passes for **all four** libs
(`langchain-mongodb`, `langchain-mongodb-deepagents-vfs`,
`langgraph-checkpoint-mongodb`, `langgraph-store-mongodb`).
- `twine check --strict` with `twine>=7` passes for the
`langchain-mongodb` and `langchain-mongodb-deepagents-vfs` builds; fails
with the default (6.2.0), which is why the floor is pinned.
- `check-yaml` and `Validate GitHub Workflows` pre-commit hooks pass on
the changed workflow.
- Job dependency graph parsed and confirmed: `build → pre-release-checks
→ publish → mark-release`.
- No TestPyPI references remain anywhere under `.github/`.

Not exercised end-to-end: `_release.yml` only runs on `main` via
`workflow_dispatch`, so the reworked `pre-release-checks` job cannot run
on a PR. Reviewers may want a dry run before the next release — the
deepagents-vfs first release is the natural candidate, since it is
blocked on TestPyPI today either way.

## Checklist

### Checklist for Author

- [ ] Did you update the changelog (if necessary)?
- [ ] Is the intention of the code captured in relevant tests?
- [ ] If there are new TODOs, has a related JIRA ticket been created?
- [ ] Has a MongoDB Employee run [the patch build of this
PR](https://github.com/mongodb-labs/ai-ml-pipeline-testing?tab=readme-ov-file#running-a-patch-build-of-a-given-pr)?

### Checklist for Reviewer

- [ ] Does the title of the PR reference a JIRA Ticket?
- [ ] Do you fully understand the implementation? (Would you be
comfortable explaining how this code works to someone else?)
- [ ] Is all relevant documentation (README or docstring) updated?

Signed-off-by: Casey Clements <casey.clements@mongodb.com>
C
Casey Clements committed
091694c04b7669813724a88d6c8cc9e7aa6b4b9a
Parent: 006027e
Committed by GitHub <noreply@github.com> on 8/24/2026, 4:45:12 PM