From d327b64ad68905884f0df9d11647ab19c0aa3515 Mon Sep 17 00:00:00 2001 From: Niels Laute Date: Thu, 25 Jun 2026 17:41:24 +0200 Subject: [PATCH 1/5] ci: add scheduled workflow to regenerate extensions.json Runs daily (and on demand) to regenerate extensions.json from the extension manifests and opens a PR when the gallery content changes. Skips when only the generatedAt timestamp would change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/regenerate-gallery.yml | 70 ++++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 .github/workflows/regenerate-gallery.yml diff --git a/.github/workflows/regenerate-gallery.yml b/.github/workflows/regenerate-gallery.yml new file mode 100644 index 0000000..3355feb --- /dev/null +++ b/.github/workflows/regenerate-gallery.yml @@ -0,0 +1,70 @@ +name: Regenerate Gallery + +on: + # Run every 24 hours at 04:00 UTC. + schedule: + - cron: "0 4 * * *" + # Allow manual runs from the Actions tab. + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +# Prevent overlapping runs from racing on the PR branch. +concurrency: + group: regenerate-gallery + cancel-in-progress: false + +jobs: + regenerate: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup Python + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Regenerate extensions.json + run: python .github/scripts/generate.py + + - name: Detect meaningful changes + id: diff + run: | + if git diff --quiet -- extensions.json; then + echo "changed=false" >> "$GITHUB_OUTPUT" + echo "No changes to extensions.json." + exit 0 + fi + + # extensions.json changed, but the generatedAt timestamp updates on + # every run. Only commit when something other than generatedAt differs. + old=$(git show HEAD:extensions.json | jq -S 'del(.generatedAt)') + new=$(jq -S 'del(.generatedAt)' extensions.json) + if [ "$old" = "$new" ]; then + echo "changed=false" >> "$GITHUB_OUTPUT" + echo "Only generatedAt changed; skipping commit." + git checkout -- extensions.json + else + echo "changed=true" >> "$GITHUB_OUTPUT" + echo "Gallery content changed; will commit." + fi + + - name: Open pull request + if: steps.diff.outputs.changed == 'true' + uses: peter-evans/create-pull-request@v6 + with: + add-paths: extensions.json + branch: chore/regenerate-gallery + commit-message: "chore: regenerate extensions.json" + title: "chore: regenerate extensions.json" + body: | + Automated regeneration of `extensions.json` from the extension + manifests under `extensions/`. + + This PR was opened by the scheduled **Regenerate Gallery** workflow + because the gallery content changed. Review and merge to publish. + labels: automated From c95836f822fbc08ddabbd6b80c8dca35e39b37f6 Mon Sep 17 00:00:00 2001 From: Niels Laute Date: Thu, 25 Jun 2026 17:48:32 +0200 Subject: [PATCH 2/5] ci: auto-merge regeneration PR on approval Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/regenerate-gallery.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/regenerate-gallery.yml b/.github/workflows/regenerate-gallery.yml index 3355feb..72d3431 100644 --- a/.github/workflows/regenerate-gallery.yml +++ b/.github/workflows/regenerate-gallery.yml @@ -54,6 +54,7 @@ jobs: fi - name: Open pull request + id: cpr if: steps.diff.outputs.changed == 'true' uses: peter-evans/create-pull-request@v6 with: @@ -68,3 +69,9 @@ jobs: This PR was opened by the scheduled **Regenerate Gallery** workflow because the gallery content changed. Review and merge to publish. labels: automated + + - name: Enable auto-merge + if: steps.diff.outputs.changed == 'true' && steps.cpr.outputs.pull-request-number + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: gh pr merge --squash --auto "${{ steps.cpr.outputs.pull-request-number }}" From 8d10e540fb997fe1ca645cf3bc4c32d9b9e9e057 Mon Sep 17 00:00:00 2001 From: Niels Laute Date: Thu, 25 Jun 2026 17:51:40 +0200 Subject: [PATCH 3/5] ci: use GitHub App token to open regeneration PR The org disables 'Allow GitHub Actions to create and approve pull requests', so GITHUB_TOKEN cannot open PRs. Authenticate via a GitHub App installation token instead. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/regenerate-gallery.yml | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/.github/workflows/regenerate-gallery.yml b/.github/workflows/regenerate-gallery.yml index 72d3431..06c8508 100644 --- a/.github/workflows/regenerate-gallery.yml +++ b/.github/workflows/regenerate-gallery.yml @@ -20,8 +20,17 @@ jobs: regenerate: runs-on: ubuntu-latest steps: + - name: Generate app token + id: app-token + uses: actions/create-github-app-token@v1 + with: + app-id: ${{ secrets.GALLERY_BOT_APP_ID }} + private-key: ${{ secrets.GALLERY_BOT_PRIVATE_KEY }} + - name: Checkout repository uses: actions/checkout@v4 + with: + token: ${{ steps.app-token.outputs.token }} - name: Setup Python uses: actions/setup-python@v5 @@ -58,6 +67,7 @@ jobs: if: steps.diff.outputs.changed == 'true' uses: peter-evans/create-pull-request@v6 with: + token: ${{ steps.app-token.outputs.token }} add-paths: extensions.json branch: chore/regenerate-gallery commit-message: "chore: regenerate extensions.json" @@ -73,5 +83,5 @@ jobs: - name: Enable auto-merge if: steps.diff.outputs.changed == 'true' && steps.cpr.outputs.pull-request-number env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ steps.app-token.outputs.token }} run: gh pr merge --squash --auto "${{ steps.cpr.outputs.pull-request-number }}" From 61ace987ee225fc5b95f166ceca5e0d72a4093a2 Mon Sep 17 00:00:00 2001 From: Niels Laute Date: Thu, 25 Jun 2026 17:53:18 +0200 Subject: [PATCH 4/5] ci: store app id as a repo variable per org convention Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/regenerate-gallery.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/regenerate-gallery.yml b/.github/workflows/regenerate-gallery.yml index 06c8508..1fae2e8 100644 --- a/.github/workflows/regenerate-gallery.yml +++ b/.github/workflows/regenerate-gallery.yml @@ -24,7 +24,7 @@ jobs: id: app-token uses: actions/create-github-app-token@v1 with: - app-id: ${{ secrets.GALLERY_BOT_APP_ID }} + app-id: ${{ vars.GALLERY_BOT_APP_ID }} private-key: ${{ secrets.GALLERY_BOT_PRIVATE_KEY }} - name: Checkout repository From 970931557403af456f5fdff41fe39cb61f83feaf Mon Sep 17 00:00:00 2001 From: Niels Laute Date: Sat, 11 Jul 2026 18:29:16 +0200 Subject: [PATCH 5/5] ci: auto-approve the regeneration PR for a hands-off cycle The org ruleset requires an approving review (with require_last_push_approval), so a second bot identity approves the app-authored PR before auto-merge completes it. This makes the scheduled regeneration fully automated while contributor PRs still require human moderator review. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/regenerate-gallery.yml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/regenerate-gallery.yml b/.github/workflows/regenerate-gallery.yml index 1fae2e8..80f33f2 100644 --- a/.github/workflows/regenerate-gallery.yml +++ b/.github/workflows/regenerate-gallery.yml @@ -77,9 +77,18 @@ jobs: manifests under `extensions/`. This PR was opened by the scheduled **Regenerate Gallery** workflow - because the gallery content changed. Review and merge to publish. + because the gallery content changed. It is auto-approved and + auto-merged; no manual action is required. labels: automated + - name: Auto-approve pull request + if: steps.diff.outputs.changed == 'true' && steps.cpr.outputs.pull-request-number + env: + # A DIFFERENT identity than the app token that pushed the commit, + # because the org ruleset requires require_last_push_approval. + GH_TOKEN: ${{ secrets.GALLERY_APPROVE_TOKEN }} + run: gh pr review --approve "${{ steps.cpr.outputs.pull-request-number }}" + - name: Enable auto-merge if: steps.diff.outputs.changed == 'true' && steps.cpr.outputs.pull-request-number env: