@@ -48,6 +48,128 @@ uv run python -m unittest discover -s tests
4848- Keep module-level constants near the top of each module, after imports
4949- Prefer specific package/module names over broad ` helpers ` or ` utils ` modules
5050
51+ ## Release process
52+
53+ - The tagged source commit must already contain the package version it
54+ releases. Do not make the release workflow edit ` pyproject.toml ` .
55+ - The tag must be ` vMAJOR.MINOR.PATCH ` , and ` .github/workflows/release.yml `
56+ verifies that it matches ` project.version ` before building GitHub release
57+ assets and publishing to PyPI.
58+ - Prepare releases on a branch from current ` main ` . Set ` VERSION ` , then run:
59+
60+ ``` sh
61+ set -euo pipefail
62+
63+ VERSION=0.1.1
64+ BRANCH=" release-v${VERSION} "
65+
66+ git fetch origin --tags --prune
67+ git switch main
68+ git pull --ff-only
69+ git switch -c " ${BRANCH} "
70+
71+ uv run python - " ${VERSION} " << 'PY '
72+ from pathlib import Path
73+ import re
74+ import sys
75+
76+ version = sys.argv[1]
77+ path = Path("pyproject.toml")
78+ text = path.read_text()
79+ new_text = re.sub(
80+ r'(?m)^version = "[^"]+"$',
81+ f'version = "{version}"',
82+ text,
83+ count=1,
84+ )
85+ if new_text == text:
86+ raise SystemExit("pyproject.toml version was not updated")
87+ path.write_text(new_text)
88+ PY
89+
90+ uv lock
91+ ```
92+
93+ - Validate before opening the PR:
94+
95+ ``` sh
96+ set -euo pipefail
97+
98+ uv lock --check
99+ npx --yes markdownlint-cli2
100+ uv run ruff check .
101+ uv run ruff format --check .
102+ uv run pyright
103+ uv run python -m unittest discover -s tests
104+ uv build --wheel --sdist --out-dir /tmp/src-py-lib-release-check --no-create-gitignore
105+ rm -rf /tmp/src-py-lib-release-check
106+ ```
107+
108+ - Commit, push, open the PR, wait for checks, then merge it. If review is
109+ required, stop after ` gh pr checks ` and ask for review before merging.
110+
111+ ``` sh
112+ set -euo pipefail
113+
114+ VERSION=0.1.1
115+ BRANCH=" release-v${VERSION} "
116+ GH_REPO=" sourcegraph/src-py-lib"
117+
118+ git add pyproject.toml uv.lock
119+ git commit -m " Release v${VERSION} "
120+ git push -u origin " ${BRANCH} "
121+
122+ gh pr create \
123+ --repo " ${GH_REPO} " \
124+ --base main \
125+ --head " ${BRANCH} " \
126+ --title " Release v${VERSION} " \
127+ --body " Bump src-py-lib package metadata to ${VERSION} ."
128+
129+ gh pr checks " ${BRANCH} " --repo " ${GH_REPO} " --watch --fail-fast
130+ gh pr merge " ${BRANCH} " --repo " ${GH_REPO} " --squash --delete-branch
131+ ```
132+
133+ - Tag the merged ` main ` commit. Do not tag a branch commit.
134+
135+ ``` sh
136+ set -euo pipefail
137+
138+ VERSION=0.1.1
139+
140+ git fetch origin --tags --prune
141+ git switch main
142+ git pull --ff-only
143+ git tag " v${VERSION} "
144+ git push origin " v${VERSION} "
145+ ```
146+
147+ - Watch the release workflow and confirm the GitHub release and PyPI project.
148+
149+ ``` sh
150+ set -euo pipefail
151+
152+ VERSION=0.1.1
153+ GH_REPO=" sourcegraph/src-py-lib"
154+
155+ RUN_ID=" $(
156+ gh run list \
157+ --repo " ${GH_REPO} " \
158+ --workflow release.yml \
159+ --branch " v${VERSION} " \
160+ --limit 1 \
161+ --json databaseId \
162+ --jq ' .[0].databaseId // empty'
163+ ) "
164+ test -n " ${RUN_ID} "
165+ gh run watch " ${RUN_ID} " --repo " ${GH_REPO} " --exit-status
166+ gh release view " v${VERSION} " --repo " ${GH_REPO} "
167+ uvx --from pip pip index versions src-py-lib
168+ ```
169+
170+ - If a pushed tag points at the wrong commit, move it only after explicit
171+ human approval.
172+
51173## Before finishing changes
52174
53175- Re-read edited files for organization and stale comments
0 commit comments