This document describes how to cut a new release of python_maithili
to PyPI. The workflow is .github/workflows/publish.yml and uses
Trusted Publishing (OIDC) — no API tokens are stored in GitHub.
In the repo, go to Settings → Environments and create two environments — they give us a place to pin the OIDC trust and (for production) an optional manual-approval gate.
- No required reviewers.
- Deployment branches: all branches (we publish to TestPyPI from feature branches too).
- Required reviewers: add yourself. Every production publish will wait for explicit approval. This is the final safety gate.
- Deployment branches: protected tags matching
v*only (v[0-9]+.[0-9]+.[0-9]+andv[0-9]+.[0-9]+.[0-9]+-*).
Go to https://pypi.org/manage/project/python-maithili/settings/publishing/ (owner only) and add a new "Trusted publisher":
| Field | Value |
|---|---|
| Owner | alphacrack |
| Repository | python-maithili-dsl |
| Workflow filename | publish.yml |
| Environment name | pypi |
TestPyPI doesn't have the project yet, so use a pending publisher. Go to https://test.pypi.org/manage/account/publishing/ and under "Pending trusted publishers" add:
| Field | Value |
|---|---|
| PyPI Project Name | python-maithili |
| Owner | alphacrack |
| Repository | python-maithili-dsl |
| Workflow filename | publish.yml |
| Environment name | testpypi |
The pending publisher converts to a real one the first time a workflow run successfully creates the project on TestPyPI.
Push a PR or run Actions → Publish to PyPI → Run workflow → build-only.
This executes the full pipeline except the publish step:
- Build sdist + wheel.
twine check --strictmetadata validation.- Install the wheel in a clean venv.
- Run the full pytest suite against the installed wheel.
- Upload the
dist/artifact for inspection.
No credentials are required and nothing touches the network package indexes. Use this whenever you want to confirm the package will build.
Two ways to trigger:
- Manual: Actions → Publish to PyPI → Run workflow →
testpypi. - Automatic: create a GitHub pre-release (check "This is a
pre-release" when making the Release). Tag format:
v0.X.Y-rc1,v0.X.Y-dev1, etc.
Version numbers you publish to TestPyPI are separate from production PyPI — TestPyPI has its own index. Verify the install:
pip install \
--index-url https://test.pypi.org/simple/ \
--extra-index-url https://pypi.org/simple/ \
python-maithili==0.X.Y
python_maithili --versionAny version on TestPyPI cannot be re-used. If you need to iterate,
bump the version (0.3.0.dev0, 0.3.0.dev1, ...) in
maithili_dsl/__init__.py before re-triggering.
Pre-flight checklist:
-
CHANGELOG.mdhas a section for the new version with date filled in. -
maithili_dsl/__init__.pyhas__version__set to the new version. -
pyproject.tomlhas matchingversion = "...". -
pytestruns green onmainCI. - The same version was successfully published to TestPyPI and installed cleanly (step B).
Cut the release:
-
Ensure
mainhas the final release commit on it (all three version strings updated, CHANGELOG finalized). -
Create a new GitHub Release (not a pre-release):
- Tag:
v0.X.Y(must match__version__exactly; the workflow enforces this and refuses to publish on mismatch). - Target:
main. - Title:
v0.X.Y. - Body: the corresponding CHANGELOG section.
- Leave "This is a pre-release" unchecked.
- Tag:
-
Click Publish release. The workflow fires.
-
If the
pypienvironment has required reviewers, approve the deployment in the Actions run. -
After the run finishes, verify:
pip install python-maithili==0.X.Y python_maithili --version
This project uses Semantic Versioning:
| Change | Bump |
|---|---|
| Breaking API change (exit code semantics, etc) | MAJOR |
| New keyword / module / feature | MINOR |
| Bugfix, doc change, internal refactor | PATCH |
Version is tracked in three places that must stay in sync:
maithili_dsl/__init__.py—__version__(single source of truth).pyproject.toml—version.CHANGELOG.md— section header and date.
The publish workflow's "Verify release tag matches package version" step will fail the production publish if these drift.
PyPI does not allow re-uploading the same filename. If you published a broken release:
- Yank (do not delete) the broken version on PyPI:
https://pypi.org/manage/project/python-maithili/releases/ →
pick the version → "Yank release". This hides it from
pip installwithout breaking already-pinned consumers. - Bump PATCH and release the fix via the normal flow above.