11#! /usr/bin/env bash
22#
3- # Check whether PolicyEngine .py has a newer release on PyPI. If so, update the
4- # policyengine[models] pin, refresh uv.lock, derive bundled package versions,
5- # create a changelog fragment, and open a PR.
3+ # Update the policyengine[models] pin to a released PolicyEngine .py version,
4+ # refresh uv.lock, derive bundled package versions, create a changelog
5+ # fragment, and open a single-version PR on branch
6+ # auto/update-policyengine-bundle-<version>.
67#
78# Environment:
89# GH_TOKEN must be set for gh.
9- # LATEST_OVERRIDE may be set for testing a specific version.
10+ # LATEST_OVERRIDE may be set to target an exact version (the
11+ # repository_dispatch trigger passes the just-released version here);
12+ # otherwise the latest version on PyPI is used.
13+ # FORCE=1 allows targeting a version that is not newer than the current pin.
1014set -euo pipefail
1115
1216DRY_RUN=0
1317if [[ " ${1:- } " == " --dry-run" ]]; then
1418 DRY_RUN=1
1519fi
1620
21+ create_pr_body () {
22+ cat << EOF
23+ ## Summary
24+
25+ Update PolicyEngine .py bundle from ${CURRENT} to ${LATEST} .
26+
27+ ## Bundled versions
28+
29+ - policyengine: ${POLICYENGINE_VERSION:- resolved during update}
30+ - policyengine-core: ${POLICYENGINE_CORE_VERSION:- resolved during update}
31+ - policyengine-us: ${US_VERSION:- resolved during update}
32+ - policyengine-uk: ${UK_VERSION:- resolved during update}
33+
34+ ---
35+ Generated automatically by GitHub Actions
36+ EOF
37+ }
38+
1739CURRENT=$( python3 -c '
1840import re
1941from pathlib import Path
@@ -45,18 +67,44 @@ if [[ "$CURRENT" == "$LATEST" ]]; then
4567 exit 0
4668fi
4769
48- BRANCH=" auto/update-policyengine-bundle-${LATEST} "
49- if git ls-remote --exit-code --heads origin " $BRANCH " & > /dev/null; then
50- echo " Branch '${BRANCH} ' already exists on remote. Skipping."
70+ if [[ " $( printf ' %s\n%s\n' " $CURRENT " " $LATEST " | sort -V | tail -n1) " != " $LATEST " && " ${FORCE:- 0} " != " 1" ]]; then
71+ echo " Requested ${LATEST} is not newer than current ${CURRENT} . Skipping (set FORCE=1 to override)."
5172 exit 0
5273fi
5374
75+ BRANCH=" auto/update-policyengine-bundle-${LATEST} "
76+
5477if [[ " $DRY_RUN " == " 1" ]]; then
78+ if git ls-remote --exit-code --heads origin " $BRANCH " & > /dev/null; then
79+ echo " Dry run: remote branch '${BRANCH} ' already exists; would ensure a PR exists for it."
80+ exit 0
81+ fi
5582 echo " Dry run complete. Would update PolicyEngine .py bundle from ${CURRENT} to ${LATEST} ."
5683 echo " Would update pyproject.toml, refresh uv.lock, create a changelog fragment, and open branch '${BRANCH} '."
5784 exit 0
5885fi
5986
87+ EXISTING_PR=$( gh pr list \
88+ --head " $BRANCH " \
89+ --state open \
90+ --json number \
91+ --jq ' .[0].number' 2> /dev/null || true)
92+ if [[ -n " $EXISTING_PR " ]]; then
93+ echo " PR #${EXISTING_PR} already exists for ${BRANCH} . Skipping."
94+ exit 0
95+ fi
96+
97+ if git ls-remote --exit-code --heads origin " $BRANCH " & > /dev/null; then
98+ echo " Remote branch '${BRANCH} ' already exists without an open PR. Creating PR."
99+ gh pr create \
100+ --base master \
101+ --head " $BRANCH " \
102+ --title " Update PolicyEngine bundle to ${LATEST} " \
103+ --body " $( create_pr_body) "
104+ echo " PR created for existing branch ${BRANCH} "
105+ exit 0
106+ fi
107+
60108python3 -c '
61109import re
62110import sys
@@ -76,28 +124,26 @@ if updated == text:
76124path.write_text(updated)
77125' " $CURRENT " " $LATEST "
78126
79- uv lock --upgrade-package policyengine
127+ # The PyPI Simple index (which uv resolves from) can lag the JSON API right
128+ # after a release, so retry the lock a few times.
129+ for attempt in 1 2 3; do
130+ if uv lock --upgrade-package policyengine; then
131+ break
132+ fi
133+ if [[ " $attempt " == " 3" ]]; then
134+ echo " ERROR: uv lock failed after ${attempt} attempts." >&2
135+ exit 1
136+ fi
137+ echo " uv lock attempt ${attempt} failed; retrying in 30s..."
138+ sleep 30
139+ done
80140
81141VERSIONS_OUTPUT=$( uv run python .github/find-api-model-versions.py --shell)
82142eval " $VERSIONS_OUTPUT "
83143
84144FRAGMENT=" changelog.d/update-policyengine-bundle-${LATEST} .changed.md"
85145echo " Update the PolicyEngine bundle to ${LATEST} ." > " $FRAGMENT "
86146
87- PR_BODY=" ## Summary
88-
89- Update PolicyEngine .py bundle from ${CURRENT} to ${LATEST} .
90-
91- ## Bundled versions
92-
93- - policyengine: ${POLICYENGINE_VERSION}
94- - policyengine-core: ${POLICYENGINE_CORE_VERSION}
95- - policyengine-us: ${US_VERSION}
96- - policyengine-uk: ${UK_VERSION}
97-
98- ---
99- Generated automatically by GitHub Actions"
100-
101147git config user.name " github-actions[bot]"
102148git config user.email " github-actions[bot]@users.noreply.github.com"
103149
@@ -110,6 +156,6 @@ git push -u origin "$BRANCH"
110156gh pr create \
111157 --base master \
112158 --title " Update PolicyEngine bundle to ${LATEST} " \
113- --body " $PR_BODY "
159+ --body " $( create_pr_body ) "
114160
115161echo " PR created: PolicyEngine bundle ${CURRENT} -> ${LATEST} "
0 commit comments