Skip to content

Commit 8ac846f

Browse files
committed
chore: add release runbook (RELEASING.md) and make release target
1 parent bb31c94 commit 8ac846f

2 files changed

Lines changed: 94 additions & 1 deletion

File tree

‎Makefile‎

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
.PHONY: clean-pyc clean-build test fmt
1+
.PHONY: clean-pyc clean-build test fmt release
2+
3+
part ?= patch
24

35
clean: clean-build clean-pyc
46

@@ -33,3 +35,16 @@ coverage:
3335

3436
coverage-html: coverage
3537
coverage html
38+
39+
# Cut a release: verify, bump version, commit and tag. See RELEASING.md.
40+
# Override the bump size with `make release part=minor` (default: patch).
41+
release:
42+
@test "$$(git rev-parse --abbrev-ref HEAD)" = "main" || { echo "Release from main only (currently on $$(git rev-parse --abbrev-ref HEAD))"; exit 1; }
43+
@git diff --quiet && git diff --cached --quiet || { echo "Working tree is dirty; commit the changelog first"; exit 1; }
44+
uv run ruff check .
45+
uv run pytest tests/
46+
uv run bumpversion $(part)
47+
@echo ""
48+
@echo "Tagged v$$(uv run python -c 'import dotenv.version as v; print(v.__version__)'). Next:"
49+
@echo " git push origin main --follow-tags"
50+
@echo " then create the GitHub Release (see RELEASING.md) to publish to PyPI"

‎RELEASING.md‎

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Releasing
2+
3+
python-dotenv follows [Semantic Versioning](https://semver.org/). Bug fixes are
4+
patch releases, backward-compatible features are minor releases, and breaking
5+
changes are major releases.
6+
7+
Publishing is automated: creating a GitHub **Release** triggers
8+
[`.github/workflows/release.yml`](.github/workflows/release.yml), which builds
9+
the package, publishes it to PyPI via Trusted Publishing (OIDC, no tokens), and
10+
deploys the docs to GitHub Pages. You never run `twine` by hand.
11+
12+
## Prerequisites
13+
14+
- Push access to `main` and permission to create releases.
15+
- A clean local checkout: `git switch main && git pull --ff-only`.
16+
- Dev tools installed: `uv pip install -r requirements.txt && uv pip install -e .`.
17+
18+
## Steps
19+
20+
1. **Write the changelog.** In `CHANGELOG.md`, rename the `## [Unreleased]`
21+
section to `## [X.Y.Z] - YYYY-MM-DD`, and add a fresh empty `## [Unreleased]`
22+
above it. Every entry credits the author and links the PR, for example:
23+
24+
```
25+
- Short description of the change by [@handle] in [#123]
26+
```
27+
28+
Add the matching link definitions at the bottom of the file (`[#123]: ...`
29+
and, for a first-time contributor, `[@handle]: https://github.com/handle`).
30+
31+
Every version header is a reference link, so also maintain the compare links
32+
at the bottom: point `[Unreleased]` at the new tag and add the new version:
33+
34+
```
35+
[Unreleased]: https://github.com/theskumar/python-dotenv/compare/vX.Y.Z...HEAD
36+
[X.Y.Z]: https://github.com/theskumar/python-dotenv/compare/vPREV...vX.Y.Z
37+
```
38+
39+
2. **Commit the notes** on `main`:
40+
41+
```
42+
git commit -am "docs: add X.Y.Z release notes"
43+
```
44+
45+
3. **Bump the version.** This runs the checks, updates `src/dotenv/version.py`
46+
and `.bumpversion.cfg`, commits `Bump version: ... → X.Y.Z`, and tags
47+
`vX.Y.Z`:
48+
49+
```
50+
make release # patch (default)
51+
make release part=minor
52+
make release part=major
53+
```
54+
55+
4. **Push** the release commit and tag:
56+
57+
```
58+
git push origin main --follow-tags
59+
```
60+
61+
5. **Publish.** Create the GitHub Release from the new tag. This starts the
62+
PyPI upload and docs deploy:
63+
64+
```
65+
VERSION=$(uv run python -c "import dotenv.version as v; print(v.__version__)")
66+
gh release create "v$VERSION" --title "v$VERSION" \
67+
--notes "$(awk "/^## \\[$VERSION\\]/{f=1;next} /^## \\[/{f=0} f" CHANGELOG.md)"
68+
```
69+
70+
6. **Verify.** Watch the workflow (`gh run watch`), then confirm the new version
71+
on [PyPI](https://pypi.org/project/python-dotenv/) and that the
72+
[docs](https://saurabh-kumar.com/python-dotenv/) rebuilt.
73+
74+
## Rollback
75+
76+
The version bump is a normal commit plus tag. Before you push, undo with
77+
`git reset --hard HEAD~1 && git tag -d vX.Y.Z`. After a bad publish, yank the
78+
release on PyPI and ship a follow-up patch; PyPI versions cannot be reused.

0 commit comments

Comments
 (0)