Update GAM7 pin #31
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Update GAM7 pin | |
| on: | |
| schedule: | |
| - cron: "43 12 * * *" | |
| workflow_dispatch: {} | |
| permissions: | |
| actions: write | |
| contents: write | |
| issues: write | |
| pull-requests: write | |
| concurrency: | |
| group: district-maintenance | |
| cancel-in-progress: false | |
| jobs: | |
| bump: | |
| runs-on: macos-latest | |
| timeout-minutes: 35 | |
| steps: | |
| - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 | |
| with: | |
| ref: district-main | |
| fetch-depth: 0 | |
| - uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 | |
| with: | |
| python-version: "3.12" | |
| - uses: astral-sh/setup-uv@37802adc94f370d6bfd71619e3f0bf239e1f3b78 # v7 | |
| with: | |
| version: "0.11.7" | |
| - name: Compare releases | |
| id: release | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| PIN="$(python3 -c "from gamgui.core.gam.commands import EXPECTED_GAM_VERSION; print(EXPECTED_GAM_VERSION)")" | |
| LATEST="$(gh api repos/GAM-team/GAM/releases/latest --jq .tag_name)" | |
| echo "tag=$LATEST" >> "$GITHUB_OUTPUT" | |
| if [ "v$PIN" = "$LATEST" ]; then | |
| echo "needed=false" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "needed=true" >> "$GITHUB_OUTPUT" | |
| fi | |
| - name: Find retryable automation pull request | |
| if: steps.release.outputs.needed == 'true' | |
| id: branch | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| TAG: ${{ steps.release.outputs.tag }} | |
| run: | | |
| PRS="$(gh pr list --base district-main --state open \ | |
| --json url,headRefName,title --limit 100)" | |
| MATCH="$(printf '%s' "$PRS" | python3 -c \ | |
| 'import json, os, sys; wanted = "chore: bump GAM7 to " + os.environ["TAG"]; match = next((item for item in json.load(sys.stdin) if item["title"] == wanted), {}); print("{}\t{}".format(match.get("url", ""), match.get("headRefName", "")))')" | |
| PR="${MATCH%%$'\t'*}" | |
| BRANCH="${MATCH#*$'\t'}" | |
| DISTRICT_SHORT="$(git rev-parse --short=12 origin/district-main)" | |
| if [ -z "$PR" ]; then | |
| BRANCH="automation/gam-${TAG}-${DISTRICT_SHORT}" | |
| if gh api "repos/$GITHUB_REPOSITORY/git/ref/heads/$BRANCH" >/dev/null 2>&1; then | |
| BRANCH="${BRANCH}-run-${GITHUB_RUN_ID}" | |
| fi | |
| fi | |
| echo "name=$BRANCH" >> "$GITHUB_OUTPUT" | |
| echo "pr=$PR" >> "$GITHUB_OUTPUT" | |
| - name: Prepare retryable update branch | |
| if: steps.release.outputs.needed == 'true' | |
| env: | |
| BRANCH: ${{ steps.branch.outputs.name }} | |
| EXISTING_PR: ${{ steps.branch.outputs.pr }} | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| if [ -n "$EXISTING_PR" ]; then | |
| git fetch --no-tags origin "$BRANCH" | |
| git checkout -B "$BRANCH" "origin/$BRANCH" | |
| git merge --no-edit origin/district-main | |
| else | |
| git checkout -b "$BRANCH" origin/district-main | |
| fi | |
| - name: Refresh pin, checksum, catalog, tests, mock, and docs | |
| if: steps.release.outputs.needed == 'true' | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| TAG: ${{ steps.release.outputs.tag }} | |
| run: | | |
| uv sync --frozen --python "$(which python)" --extra dev | |
| .venv/bin/python scripts/bump_gam.py --tag "$TAG" | |
| .venv/bin/pytest -q tests/test_command_contract.py tests/test_bump_gam.py tests/test_acceptance_privacy.py | |
| - name: Open or refresh update pull request | |
| if: steps.release.outputs.needed == 'true' | |
| id: pull | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| TAG: ${{ steps.release.outputs.tag }} | |
| BRANCH: ${{ steps.branch.outputs.name }} | |
| EXISTING_PR: ${{ steps.branch.outputs.pr }} | |
| run: | | |
| PR="$EXISTING_PR" | |
| git add README.md scripts/fetch_gam.sh scripts/gam_checksums.txt \ | |
| scripts/bump_gam.py gamgui/core/gam/commands.py \ | |
| gamgui/resources/gam7/VERSION gamgui/resources/gam7/command_catalog.json \ | |
| tests/fixtures/mock_gam.sh tests/test_acceptance_privacy.py tests/test_bump_gam.py | |
| if ! git diff --cached --quiet; then | |
| git commit -m "chore: bump GAM7 to ${TAG}" | |
| fi | |
| git push origin "HEAD:refs/heads/$BRANCH" | |
| if [ -z "$PR" ]; then | |
| PR="$(gh pr create --base district-main --head "$BRANCH" \ | |
| --title "chore: bump GAM7 to ${TAG}" \ | |
| --body "Automated GAM7 pin, checksum, catalog, mock, tests, and documentation update. Expanded CI and exact-SHA post-merge validation remain mandatory.")" | |
| else | |
| echo "Refreshed existing automatic update pull request: $PR" | |
| fi | |
| echo "url=$PR" >> "$GITHUB_OUTPUT" | |
| echo "head_sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" | |
| - name: Require exact-SHA CI and protected merge | |
| if: steps.release.outputs.needed == 'true' | |
| id: merge | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| python3 scripts/merge_tested_automation_pr.py \ | |
| --repository "$GITHUB_REPOSITORY" \ | |
| --branch "${{ steps.branch.outputs.name }}" \ | |
| --head-sha "${{ steps.pull.outputs.head_sha }}" \ | |
| --pull-request "${{ steps.pull.outputs.url }}" | |
| - name: Start exact post-merge validation | |
| if: steps.release.outputs.needed == 'true' | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| MERGED_SHA: ${{ steps.merge.outputs.merge_sha }} | |
| run: gh workflow run post-merge-validation.yml --ref district-main -f sha="$MERGED_SHA" | |
| - name: Report failed automatic bump | |
| if: failure() | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| TAG: ${{ steps.release.outputs.tag }} | |
| RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | |
| run: | | |
| TITLE="GAM7 automatic update blocked" | |
| BODY="The automatic bump for \`$TAG\` failed. No update was merged. Run: $RUN_URL" | |
| NUMBER="$(gh issue list --state open --search "$TITLE in:title" --json number --jq '.[0].number // empty')" | |
| if [ -n "$NUMBER" ]; then | |
| gh issue comment "$NUMBER" --body "$BODY" | |
| else | |
| gh issue create --title "$TITLE" --body "$BODY" | |
| fi |