Gate external PRs on an assigned, linked issue (#3291)
Signed-off-by: Max Isbey <224885523+maxisbey@users.noreply.github.com>
This commit is contained in:
parent
e473cca6a1
commit
2a1cc94493
2 changed files with 874 additions and 35 deletions
85
.github/workflows/require-linked-issue.yml
vendored
Normal file
85
.github/workflows/require-linked-issue.yml
vendored
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
# PR intake gate — see CONTRIBUTING.md ("How pull requests get in") for the
|
||||
# policy and .github/scripts/pr_intake_gate.js for the rules as applied.
|
||||
#
|
||||
# In short: a PR from someone without triage rights stays open only if it links
|
||||
# an open issue here that is assigned to them (or labeled `help wanted`);
|
||||
# otherwise it is labeled `missing-issue-link`, gets one comment, and is closed,
|
||||
# and it reopens automatically once the author is assigned. Bots and drafts are
|
||||
# skipped. A triage+ user reopening the PR, removing the label, or adding
|
||||
# `bypass-issue-check` overrides.
|
||||
#
|
||||
# Operating it:
|
||||
# - Live by default. To pause it without a revert, set the repository
|
||||
# variable PR_GATE_ENFORCE to "false": runs then only log their verdicts.
|
||||
# - PRs below the number in the job `if:` predate the gate and are ignored
|
||||
# unless evaluated by hand: `gh workflow run require-linked-issue.yml -f pr_number=N`.
|
||||
#
|
||||
# Security: pull_request_target runs with a write token in the base repo's
|
||||
# context, and GitHub takes both this file and the checkout from the default
|
||||
# branch whatever the PR targets (so PRs against v1.x are covered too). The
|
||||
# job checks out only that, for the script, and never fetches, builds, or runs
|
||||
# anything from the pull request.
|
||||
#
|
||||
# Adapted from PrefectHQ/fastmcp's require-issue-link.yml (Apache-2.0), itself
|
||||
# from langchain-ai/langchain (MIT).
|
||||
|
||||
name: Require Linked Issue
|
||||
|
||||
on:
|
||||
pull_request_target: # zizmor: ignore[dangerous-triggers] checks out the default branch only and never runs PR code — see header
|
||||
types: [opened, edited, reopened, ready_for_review, labeled, unlabeled]
|
||||
issues:
|
||||
types: [assigned]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
pr_number:
|
||||
description: PR number to evaluate
|
||||
required: true
|
||||
type: number
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
gate:
|
||||
name: Evaluate
|
||||
# Routing only; the rules are in the script. PR events run at or above the
|
||||
# grandfathering floor, or for PRs the gate has already labeled; label
|
||||
# events only for the two labels the gate cares about.
|
||||
if: >-
|
||||
github.event_name == 'workflow_dispatch' ||
|
||||
(github.event_name == 'issues' && !github.event.issue.pull_request && github.event.issue.state == 'open') ||
|
||||
(
|
||||
github.event_name == 'pull_request_target' &&
|
||||
(
|
||||
github.event.pull_request.number >= 3200 ||
|
||||
contains(github.event.pull_request.labels.*.name, 'missing-issue-link') ||
|
||||
github.event.action == 'unlabeled'
|
||||
) &&
|
||||
(github.event.action != 'unlabeled' || github.event.label.name == 'missing-issue-link') &&
|
||||
(github.event.action != 'labeled' || github.event.label.name == 'bypass-issue-check')
|
||||
)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
concurrency:
|
||||
group: require-linked-issue-${{ github.event.pull_request.number || inputs.pr_number || format('issue-{0}-{1}', github.event.issue.number, github.event.assignee.login) }}
|
||||
cancel-in-progress: false
|
||||
permissions:
|
||||
contents: read # check out the gate script from the default branch
|
||||
issues: write # read linked issues; label and comment on the PR
|
||||
pull-requests: write # close and reopen the PR
|
||||
env:
|
||||
ENFORCE: ${{ vars.PR_GATE_ENFORCE != 'false' && 'true' || 'false' }} # kill switch: set the variable to "false" to go log-only
|
||||
PR_NUMBER_INPUT: ${{ inputs.pr_number }}
|
||||
steps:
|
||||
- name: Check out the gate script (default branch)
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
||||
with:
|
||||
persist-credentials: false
|
||||
sparse-checkout: .github/scripts
|
||||
|
||||
- name: Evaluate
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
with:
|
||||
script: |
|
||||
const run = require('./.github/scripts/pr_intake_gate.js');
|
||||
await run({ github, context, core });
|
||||
6
.github/workflows/shared.yml
vendored
6
.github/workflows/shared.yml
vendored
|
|
@ -41,6 +41,12 @@ jobs:
|
|||
with:
|
||||
extra_args: --all-files --verbose
|
||||
|
||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
node-version: 24 # match the runtime actions/github-script@v8 uses
|
||||
- name: PR intake gate scenarios
|
||||
run: node --test .github/scripts/pr_intake_gate.test.js
|
||||
|
||||
- name: Surface types match vendored schema
|
||||
run: |
|
||||
uv sync --group codegen --frozen
|
||||
|
|
|
|||
Loading…
Reference in a new issue