@@ -151,3 +151,158 @@ jobs:
151151 --title "${GITHUB_REF_NAME}" \
152152 --generate-notes
153153 fi
154+
155+ post-release-bump :
156+ name : Open post-release bump PR
157+ needs :
158+ - build
159+ - publish-to-pypi
160+ - create-github-release
161+ runs-on : ubuntu-latest
162+ permissions :
163+ contents : write
164+ pull-requests : write
165+
166+ steps :
167+ - name : Checkout main
168+ uses : actions/checkout@v7
169+ with :
170+ ref : main
171+ fetch-depth : 0
172+
173+ - name : Compute next dev version
174+ id : next
175+ env :
176+ RELEASED_VERSION : ${{ needs.build.outputs.version }}
177+ run : |
178+ if [[ ! "$RELEASED_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
179+ echo "ERROR: release version must be stable and match X.Y.Z"
180+ exit 1
181+ fi
182+
183+ MAJOR=$(echo "$RELEASED_VERSION" | cut -d. -f1)
184+ MINOR=$(echo "$RELEASED_VERSION" | cut -d. -f2)
185+ PATCH=$(echo "$RELEASED_VERSION" | cut -d. -f3)
186+ NEXT_PATCH=$((PATCH + 1))
187+ NEXT_DEV="${MAJOR}.${MINOR}.${NEXT_PATCH}.dev0"
188+ echo "dev_version=$NEXT_DEV" >> "$GITHUB_OUTPUT"
189+ echo "branch=bump/${NEXT_DEV}" >> "$GITHUB_OUTPUT"
190+
191+ - name : Verify pyproject.toml shows the released version
192+ env :
193+ RELEASED_VERSION : ${{ needs.build.outputs.version }}
194+ run : |
195+ CURRENT=$(python3 -c "
196+ import tomllib
197+ with open('pyproject.toml', 'rb') as f:
198+ d = tomllib.load(f)
199+ print(d['project']['version'])
200+ ")
201+ if [ "$CURRENT" != "$RELEASED_VERSION" ]; then
202+ echo "ERROR: pyproject.toml is '$CURRENT' but release tag is '$RELEASED_VERSION'"
203+ exit 1
204+ fi
205+
206+ - name : Verify release exists on PyPI
207+ env :
208+ VERSION : ${{ needs.build.outputs.version }}
209+ run : |
210+ for attempt in 1 2 3 4 5; do
211+ if python3 - <<'PY'
212+ import os
213+ import urllib.error
214+ import urllib.request
215+
216+ version = os.environ["VERSION"]
217+ url = f"https://pypi.org/pypi/openenv/{version}/json"
218+ try:
219+ with urllib.request.urlopen(url, timeout=30) as response:
220+ if response.status == 200:
221+ raise SystemExit(0)
222+ except urllib.error.HTTPError as exc:
223+ if exc.code != 404:
224+ raise
225+ raise SystemExit(1)
226+ PY
227+ then
228+ echo "openenv ${VERSION} is available on PyPI"
229+ exit 0
230+ fi
231+ echo "openenv ${VERSION} is not visible on PyPI yet; retrying..."
232+ sleep 30
233+ done
234+
235+ echo "ERROR: openenv ${VERSION} is not available on PyPI; refusing post-release bump"
236+ exit 1
237+
238+ - name : Create bump branch and edit pyproject.toml
239+ env :
240+ DEV_VERSION : ${{ steps.next.outputs.dev_version }}
241+ BRANCH : ${{ steps.next.outputs.branch }}
242+ run : |
243+ git config user.name "github-actions[bot]"
244+ git config user.email "github-actions[bot]@users.noreply.github.com"
245+
246+ if git ls-remote --exit-code --heads origin "$BRANCH" >/dev/null 2>&1; then
247+ echo "Branch $BRANCH already exists; reusing it"
248+ git fetch origin "$BRANCH"
249+ git checkout -B "$BRANCH" FETCH_HEAD
250+ else
251+ git checkout -b "$BRANCH"
252+ fi
253+
254+ python3 - <<'PYEOF'
255+ import os
256+ import pathlib
257+ import re
258+
259+ dev_version = os.environ["DEV_VERSION"]
260+ pyproject = pathlib.Path("pyproject.toml")
261+ text = pyproject.read_text()
262+ text = re.sub(
263+ r'^version = ".*"',
264+ f'version = "{dev_version}"',
265+ text,
266+ count=1,
267+ flags=re.MULTILINE,
268+ )
269+ pyproject.write_text(text)
270+ PYEOF
271+
272+ if git diff --quiet; then
273+ echo "pyproject.toml already contains ${DEV_VERSION}"
274+ else
275+ git add pyproject.toml
276+ git commit -m "chore: bump version to ${DEV_VERSION} (post-release)"
277+ git push origin "$BRANCH"
278+ fi
279+
280+ - name : Create pull request
281+ env :
282+ GH_TOKEN : ${{ github.token }}
283+ DEV_VERSION : ${{ steps.next.outputs.dev_version }}
284+ RELEASED_VERSION : ${{ needs.build.outputs.version }}
285+ BRANCH : ${{ steps.next.outputs.branch }}
286+ run : |
287+ EXISTING_PR=$(gh pr list \
288+ --repo "$GITHUB_REPOSITORY" \
289+ --head "$BRANCH" \
290+ --state open \
291+ --json number \
292+ --jq '.[0].number // empty')
293+
294+ if [ -n "$EXISTING_PR" ]; then
295+ echo "Post-release bump PR already exists: #${EXISTING_PR}"
296+ exit 0
297+ fi
298+
299+ gh pr create \
300+ --repo "$GITHUB_REPOSITORY" \
301+ --base main \
302+ --head "$BRANCH" \
303+ --title "chore: bump version to ${DEV_VERSION} (post-release)" \
304+ --body "Automatic post-release bump after ${RELEASED_VERSION} was published.
305+
306+ **Change**: \`pyproject.toml\` version \`${RELEASED_VERSION}\` → \`${DEV_VERSION}\`
307+
308+ _Generated by \`.github/workflows/publish-pypi.yml\`_"
0 commit comments