Previously the action used the PAT (SLASH_COMMANDS_TOKEN) for everything,
so comments and reviews showed as authored by whoever owns the PAT. This
is confusing — the PAT exists only because team-membership checks need
read:org, which GITHUB_TOKEN can never have.
New bot-token input (default ${{ github.token }}) is used for all
user-visible side effects. The PAT is now scoped to what actually needs
it: team membership, CODEOWNERS fetch, listFiles, pulls.get, and
workflow dispatch.
Side benefit: the PAT's required scopes shrink. It no longer needs
Pull requests:write or Issues:write — just Contents:read + Members:read
(+ Actions:write for /stageblog). README updated to reflect this.
103 lines
3.9 KiB
YAML
103 lines
3.9 KiB
YAML
name: PR Slash Commands
|
|
description: >-
|
|
Handles /lgtm, /hold, and /stageblog slash commands on PRs. Authorized
|
|
users (core maintainers or CODEOWNERS of the PR's changed files) can approve
|
|
via /lgtm (adds a label + bot APPROVE review), block via /hold, or trigger
|
|
a blog preview staging workflow via /stageblog. Approval is invalidated when
|
|
new commits are pushed.
|
|
|
|
inputs:
|
|
github-token:
|
|
description: >-
|
|
Token for org team-membership checks and workflow dispatch. MUST have
|
|
read:org scope — the default GITHUB_TOKEN cannot do this. Use a
|
|
fine-grained PAT with Organization Members:read (+ Actions:write if
|
|
using /stageblog), or a GitHub App installation token with equivalent
|
|
perms.
|
|
required: true
|
|
bot-token:
|
|
description: >-
|
|
Token used for user-visible side effects (comments, reactions, labels,
|
|
reviews). Defaults to the automatic GITHUB_TOKEN so these show as
|
|
authored by github-actions[bot]. The caller workflow must grant this
|
|
token the necessary repo permissions (pull-requests: write,
|
|
issues: write).
|
|
required: false
|
|
default: ${{ github.token }}
|
|
approved-label:
|
|
description: Label added by /lgtm and used by the status job as the merge gate
|
|
required: false
|
|
default: approved
|
|
hold-label:
|
|
description: Label added by /hold to block merging
|
|
required: false
|
|
default: do-not-merge/hold
|
|
always-allow-teams:
|
|
description: >-
|
|
Comma-separated team slugs (within the repo's org) whose members may
|
|
/lgtm or /hold any PR regardless of CODEOWNERS
|
|
required: false
|
|
default: core-maintainers
|
|
codeowners-path:
|
|
description: Path to the CODEOWNERS file (fetched from the PR base branch)
|
|
required: false
|
|
default: .github/CODEOWNERS
|
|
invalidate-on-push:
|
|
description: >-
|
|
Remove the approved label and dismiss the bot review when new commits
|
|
are pushed to the PR. Set to 'false' to keep approval across pushes.
|
|
required: false
|
|
default: 'true'
|
|
submit-review:
|
|
description: >-
|
|
Whether to submit a bot APPROVE review alongside the label on /lgtm.
|
|
Set to 'false' to rely on the label alone.
|
|
required: false
|
|
default: 'true'
|
|
stageblog-workflow:
|
|
description: >-
|
|
Workflow file name (e.g. stage-blog.yml) to dispatch when /stageblog is
|
|
invoked. Leave empty to disable the command. The workflow must accept
|
|
inputs 'pr_number' and 'head_sha'.
|
|
required: false
|
|
default: ''
|
|
stageblog-paths:
|
|
description: >-
|
|
Comma-separated glob patterns (CODEOWNERS-style: **, *, ?, leading /,
|
|
trailing /) matched against the PR's changed files. /stageblog is refused
|
|
if no file matches.
|
|
required: false
|
|
default: 'blog/**'
|
|
|
|
outputs:
|
|
result:
|
|
description: >-
|
|
One of: lgtm-added, lgtm-removed, hold-added, hold-removed, invalidated,
|
|
unauthorized, self-lgtm-blocked, stageblog-dispatched, stageblog-not-blog,
|
|
stageblog-disabled, noop
|
|
value: ${{ steps.handle.outputs.result }}
|
|
actor:
|
|
description: Login of the user who triggered the action (commenter)
|
|
value: ${{ steps.handle.outputs.actor }}
|
|
|
|
runs:
|
|
using: composite
|
|
steps:
|
|
- name: Handle slash command
|
|
id: handle
|
|
uses: actions/github-script@v8
|
|
env:
|
|
APPROVED_LABEL: ${{ inputs.approved-label }}
|
|
HOLD_LABEL: ${{ inputs.hold-label }}
|
|
ALWAYS_ALLOW_TEAMS: ${{ inputs.always-allow-teams }}
|
|
CODEOWNERS_PATH: ${{ inputs.codeowners-path }}
|
|
INVALIDATE_ON_PUSH: ${{ inputs.invalidate-on-push }}
|
|
SUBMIT_REVIEW: ${{ inputs.submit-review }}
|
|
STAGEBLOG_WORKFLOW: ${{ inputs.stageblog-workflow }}
|
|
STAGEBLOG_PATHS: ${{ inputs.stageblog-paths }}
|
|
BOT_TOKEN: ${{ inputs.bot-token }}
|
|
with:
|
|
github-token: ${{ inputs.github-token }}
|
|
script: |
|
|
const main = require(process.env.GITHUB_ACTION_PATH + '/main.js');
|
|
await main({ github, context, core });
|