diff --git a/.github/workflows/sync-marketplace-versions.yml b/.github/workflows/sync-marketplace-versions.yml index 469ede2..78e1dce 100644 --- a/.github/workflows/sync-marketplace-versions.yml +++ b/.github/workflows/sync-marketplace-versions.yml @@ -39,9 +39,28 @@ jobs: contents: write pull-requests: write steps: + # Open the eventual drift PR as the dispatcher App, not GITHUB_TOKEN: a + # GITHUB_TOKEN-authored PR doesn't trigger ci.yml (anti-recursion), so + # it can't satisfy main's required checks and would sit open. Skipped on + # pull_request (validation-only, no push) and when App creds are absent + # (falls back to GITHUB_TOKEN -- PR opens, lands via human review). + - name: Mint plugins-dispatcher app token + id: app-token + if: vars.PLUGINS_DISPATCH_CLIENT_ID != '' && github.event_name != 'pull_request' + continue-on-error: true + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 + with: + client-id: ${{ vars.PLUGINS_DISPATCH_CLIENT_ID }} + private-key: ${{ secrets.PLUGINS_DISPATCH_APP_PRIVATE_KEY }} + owner: TracineHQ + repositories: plugins + permission-contents: write + permission-pull-requests: write + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: - persist-credentials: false + token: ${{ steps.app-token.outputs.token || github.token }} + persist-credentials: true - name: Run sync script id: sync @@ -89,7 +108,8 @@ jobs: && inputs.dry_run != 'true' && github.event_name != 'pull_request' env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ steps.app-token.outputs.token || github.token }} + APP_SLUG: ${{ steps.app-token.outputs.app-slug }} run: | set -eu title="chore: sync marketplace.json versions to latest releases" @@ -105,16 +125,30 @@ jobs: # Run-ID suffix avoids same-day branch collisions across cron + # manual dispatch overlap. branch="bot/sync-marketplace-versions-$(date -u +%Y%m%d)-${GITHUB_RUN_ID}" - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - # checkout step ran with persist-credentials:false; wire gh's token - # into git so the push below authenticates. - gh auth setup-git + # Commit as the App when its token was minted (a non-GITHUB_TOKEN + # author is what makes ci.yml run on the PR); fall back to + # github-actions[bot] otherwise. checkout persisted the same token, + # so the push below authenticates without `gh auth setup-git`. + if [ -n "${APP_SLUG:-}" ]; then + app_user_id=$(gh api "/users/${APP_SLUG}[bot]" --jq .id) + git config user.name "${APP_SLUG}[bot]" + git config user.email "${app_user_id}+${APP_SLUG}[bot]@users.noreply.github.com" + else + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + fi git checkout -b "$branch" git add .claude-plugin/marketplace.json git commit -m "$title" git push -u origin "$branch" - gh pr create \ + pr_url=$(gh pr create \ --title "$title" \ - --body "Daily auto-sync from the source repos' latest GitHub release tags. See workflow run logs for the specific bumps." + --body "Daily auto-sync from the source repos' latest GitHub release tags. See workflow run logs for the specific bumps.") + + echo "Opened $pr_url" + # Land automatically once main's required checks pass. Non-fatal if + # auto-merge can't be enabled (App creds absent -> GITHUB_TOKEN PR -> + # no CI reports) -- a human can still merge. + gh pr merge "$pr_url" --auto --squash || \ + echo "WARN: could not enable auto-merge on $pr_url (continuing)" diff --git a/.github/workflows/sync-on-release.yml b/.github/workflows/sync-on-release.yml index c58048a..aafe345 100644 --- a/.github/workflows/sync-on-release.yml +++ b/.github/workflows/sync-on-release.yml @@ -54,8 +54,29 @@ jobs: exit 1 fi + # Open the PR as the dispatcher App, not GITHUB_TOKEN. Events made with + # GITHUB_TOKEN don't trigger workflows (GitHub anti-recursion), so a + # GITHUB_TOKEN-opened PR never runs ci.yml and can never satisfy main's + # required checks -- it just sits open. Minting an App token makes the + # push + PR a real actor, so CI fires and auto-merge can land it. + # Falls back to GITHUB_TOKEN when the App creds are absent: the PR still + # opens (no CI, no auto-merge), exactly the prior behavior. + - name: Mint plugins-dispatcher app token + id: app-token + if: vars.PLUGINS_DISPATCH_CLIENT_ID != '' + continue-on-error: true + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 + with: + client-id: ${{ vars.PLUGINS_DISPATCH_CLIENT_ID }} + private-key: ${{ secrets.PLUGINS_DISPATCH_APP_PRIVATE_KEY }} + owner: TracineHQ + repositories: plugins + permission-contents: write + permission-pull-requests: write + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: + token: ${{ steps.app-token.outputs.token || github.token }} persist-credentials: true - name: Bump plugin version in marketplace.json @@ -128,7 +149,8 @@ jobs: - name: Open auto-merge PR if: steps.bump.outputs.changed == 'true' env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ steps.app-token.outputs.token || github.token }} + APP_SLUG: ${{ steps.app-token.outputs.app-slug }} PLUGIN: ${{ github.event.client_payload.plugin }} VERSION: ${{ github.event.client_payload.version }} shell: bash @@ -145,8 +167,17 @@ jobs: exit 0 fi - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + # Commit as the App when its token was minted (a non-GITHUB_TOKEN + # author is what makes ci.yml run on the PR); fall back to + # github-actions[bot] otherwise. + if [ -n "${APP_SLUG:-}" ]; then + app_user_id=$(gh api "/users/${APP_SLUG}[bot]" --jq .id) + git config user.name "${APP_SLUG}[bot]" + git config user.email "${app_user_id}+${APP_SLUG}[bot]@users.noreply.github.com" + else + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + fi git checkout -b "$branch" git add .claude-plugin/marketplace.json