From ca9fcff1873bac54f3ced85f8ce46e3db1220f97 Mon Sep 17 00:00:00 2001 From: Craig Colegrove Date: Thu, 14 May 2026 13:01:44 -0700 Subject: [PATCH 1/2] Adjust auto-promote criteria --- .github/workflows/bump-version.yaml | 47 ++++++++++++++++++++--------- .github/workflows/deploy.yaml | 28 +++++++++++------ 2 files changed, 51 insertions(+), 24 deletions(-) diff --git a/.github/workflows/bump-version.yaml b/.github/workflows/bump-version.yaml index b2190a5..6e96c0c 100644 --- a/.github/workflows/bump-version.yaml +++ b/.github/workflows/bump-version.yaml @@ -169,26 +169,45 @@ jobs: echo "Failed to push bumped versions; tried $TRY times." exit 1 working-directory: self + # Stamp metadata into the GitHub release body so downstream workflows (docker.yaml, deploy.yaml) + # can recover context that would otherwise be lost. Once this workflow creates the release using + # WORKFLOW_PAT, every subsequent event (release:created, release:released) is triggered + # by leeroy-travis (the PAT owner), washing out information like who actually clicked the button + # and which PR produced this commit. We encode it here so it survives the handoff. + # + # Output format is a single space-separated string of `key:value` pairs, e.g.: + # triggered_by:leeroy-travis latest_pr:1234 - name: Generate release text id: release-body run: | set -x - # Get the most recent commit. Hopefully it was a PR merge. + + # --- triggered_by: who actually kicked off this run --- + # Always recorded. deploy.yaml reads this to decide whether to apply the auto-promote label: + # scheduled rebuilds dispatch bump-version via rebuild.yaml's PAT (leeroy-travis), while + # humans clicking workflow_dispatch in the UI show up as themselves. + BODY="triggered_by:${{ github.triggering_actor }}" + + # --- latest_pr: the PR that produced the commit we're about to release --- + # Best-effort. deploy.yaml uses it to comment back on the original PR and assign reviewers. + # May be absent when: + # - Triggered by workflow_dispatch (the `push` event payload's `.after` field doesn't exist). + # - The commit landed on main without a PR (direct push, admin override of branch protection). COMMIT=$(jq -r '.after' ${{ github.event_path }}) - if [ "${COMMIT}" = "null" ] || [ -z "${COMMIT}" ] ; then - exit 0 - fi - # Get the most recent PRs; hopefully ours is one of them. - curl -fSs -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer ${{ secrets.WORKFLOW_PAT }}" \ - https://api.github.com/repos/${{ github.repository }}/pulls?state=all\&base=${{ github.ref }}\&sort=updated\&direction=desc > /tmp/prs.json - # Find a PR that resulted in our commit. - PR=$(jq -r ".[] | select(.merge_commit_sha == \"${COMMIT}\") | .number" /tmp/prs.json) - if [ "${PR}" = "null" ] || [ -z "${PR}" ] ; then - exit 0 + if [ "${COMMIT}" != "null" ] && [ -n "${COMMIT}" ] ; then + # GitHub's PRs API has no "find by merge commit" endpoint, so we list the most recently + # updated PRs against this branch and look for one whose merge_commit_sha matches ours. + # If the merge happened long enough ago that it's fallen off the first page, we miss it. + curl -fSs -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer ${{ secrets.WORKFLOW_PAT }}" \ + https://api.github.com/repos/${{ github.repository }}/pulls?state=all\&base=${{ github.ref }}\&sort=updated\&direction=desc > /tmp/prs.json + PR=$(jq -r ".[] | select(.merge_commit_sha == \"${COMMIT}\") | .number" /tmp/prs.json) + if [ "${PR}" != "null" ] && [ -n "${PR}" ] ; then + BODY="${BODY} latest_pr:${PR}" + fi fi - # Build the string we'll use as the description of the release. - echo "body=latest_pr:${PR}" >> "$GITHUB_OUTPUT" + + echo "body=${BODY}" >> "$GITHUB_OUTPUT" working-directory: self # This triggers the Docker workflow's `release: created` - name: Create GitHub Release diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index fddc8e0..ee23df4 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -61,16 +61,21 @@ jobs: with: ref: ${{ inputs.tag }} path: software - # Find the original PR to the software repo. The git tag should correspond to a GitHub release, which should have a - # description pointing to the PR number. - - name: Get original PR + # Pull metadata out of the GitHub release body. bump-version stamps `triggered_by:` and + # (when discoverable) `latest_pr:` so downstream workflows can recover context that the + # WORKFLOW_PAT-driven release event would otherwise lose. + - name: Get release metadata id: software-pr working-directory: software run: | set -x - gh release view ${{ inputs.tag }} --json body --jq '.body' | sed 's/.*latest_pr:\([0-9]*\).*/\1/' > /tmp/pr - PR=$(cat /tmp/pr) - if [ -z "${PR}" ] || [ "${PR}" = "null" ] ; then + BODY=$(gh release view ${{ inputs.tag }} --json body --jq '.body') + TRIGGERED_BY=$(echo "$BODY" | grep -oE 'triggered_by:[^ ]+' | cut -d: -f2 || true) + if [ -n "$TRIGGERED_BY" ] ; then + echo "triggered_by=$TRIGGERED_BY" >> "$GITHUB_OUTPUT" + fi + PR=$(echo "$BODY" | grep -oE 'latest_pr:[0-9]+' | cut -d: -f2 || true) + if [ -z "${PR}" ] ; then exit 0 fi echo "pr=$PR" >> "$GITHUB_OUTPUT" @@ -136,10 +141,13 @@ jobs: git commit -m "${COMMIT_MSG}" git push -u origin "${NEW_BRANCH}" - # If we can't find the originating PR, it must mean the change came from automation, and we should auto-promote. - if [ -z "${{ steps.software-pr.outputs.pr }}" ] ; then - LABELS="--label auto-promote" - fi + # Auto-promote only when bump-version was triggered by a known automation actor (e.g., + # leeroy-travis from rebuild.yaml). Manual workflow_dispatch by a human is intentionally excluded. + case "${{ steps.software-pr.outputs.triggered_by }}" in + leeroy-travis) + LABELS="--label auto-promote" + ;; + esac AUTHOR="${{ steps.software-pr.outputs.author }}" if [ -n "$AUTHOR" ] && [ "$AUTHOR" != "app/dependabot" ]; then ASSIGNEE="--assignee $AUTHOR --reviewer $AUTHOR" From 9bd5f37edfaf9779ec1ce3047688cefba7b73f79 Mon Sep 17 00:00:00 2001 From: Craig Colegrove Date: Thu, 14 May 2026 15:00:10 -0700 Subject: [PATCH 2/2] Switch to JSON data passing --- .github/workflows/bump-version.yaml | 11 ++++++----- .github/workflows/deploy.yaml | 14 +++++++++----- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/.github/workflows/bump-version.yaml b/.github/workflows/bump-version.yaml index 6e96c0c..693fac3 100644 --- a/.github/workflows/bump-version.yaml +++ b/.github/workflows/bump-version.yaml @@ -175,8 +175,8 @@ jobs: # by leeroy-travis (the PAT owner), washing out information like who actually clicked the button # and which PR produced this commit. We encode it here so it survives the handoff. # - # Output format is a single space-separated string of `key:value` pairs, e.g.: - # triggered_by:leeroy-travis latest_pr:1234 + # Output is a compact JSON object, e.g.: + # {"triggered_by":"leeroy-travis","latest_pr":1234} - name: Generate release text id: release-body run: | @@ -186,7 +186,8 @@ jobs: # Always recorded. deploy.yaml reads this to decide whether to apply the auto-promote label: # scheduled rebuilds dispatch bump-version via rebuild.yaml's PAT (leeroy-travis), while # humans clicking workflow_dispatch in the UI show up as themselves. - BODY="triggered_by:${{ github.triggering_actor }}" + METADATA=$(jq -cn --arg triggered_by "${{ github.triggering_actor }}" \ + '{triggered_by: $triggered_by}') # --- latest_pr: the PR that produced the commit we're about to release --- # Best-effort. deploy.yaml uses it to comment back on the original PR and assign reviewers. @@ -203,11 +204,11 @@ jobs: https://api.github.com/repos/${{ github.repository }}/pulls?state=all\&base=${{ github.ref }}\&sort=updated\&direction=desc > /tmp/prs.json PR=$(jq -r ".[] | select(.merge_commit_sha == \"${COMMIT}\") | .number" /tmp/prs.json) if [ "${PR}" != "null" ] && [ -n "${PR}" ] ; then - BODY="${BODY} latest_pr:${PR}" + METADATA=$(echo "$METADATA" | jq -c --argjson pr "$PR" '. + {latest_pr: $pr}') fi fi - echo "body=${BODY}" >> "$GITHUB_OUTPUT" + echo "body=${METADATA}" >> "$GITHUB_OUTPUT" working-directory: self # This triggers the Docker workflow's `release: created` - name: Create GitHub Release diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index ee23df4..f3a2a1f 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -61,20 +61,24 @@ jobs: with: ref: ${{ inputs.tag }} path: software - # Pull metadata out of the GitHub release body. bump-version stamps `triggered_by:` and - # (when discoverable) `latest_pr:` so downstream workflows can recover context that the - # WORKFLOW_PAT-driven release event would otherwise lose. + # Pull metadata out of the GitHub release body. bump-version stamps a JSON object containing + # `triggered_by` and (when discoverable) `latest_pr` so downstream workflows can recover context + # that the WORKFLOW_PAT-driven release event would otherwise lose. - name: Get release metadata id: software-pr working-directory: software run: | set -x BODY=$(gh release view ${{ inputs.tag }} --json body --jq '.body') - TRIGGERED_BY=$(echo "$BODY" | grep -oE 'triggered_by:[^ ]+' | cut -d: -f2 || true) + # Releases predating the JSON format have plain-text bodies; treat them as having no metadata. + if ! echo "$BODY" | jq -e . >/dev/null 2>&1 ; then + exit 0 + fi + TRIGGERED_BY=$(echo "$BODY" | jq -r '.triggered_by // empty') if [ -n "$TRIGGERED_BY" ] ; then echo "triggered_by=$TRIGGERED_BY" >> "$GITHUB_OUTPUT" fi - PR=$(echo "$BODY" | grep -oE 'latest_pr:[0-9]+' | cut -d: -f2 || true) + PR=$(echo "$BODY" | jq -r '.latest_pr // empty') if [ -z "${PR}" ] ; then exit 0 fi