* Claim bot: a PR referencing an issue claims it Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TPWBBSRPfPYWgrrhbznewR * Triage bot: label new issues and PRs, /triage, backfill Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TPWBBSRPfPYWgrrhbznewR * Docs: a draft PR is the claim; labels and triage Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TPWBBSRPfPYWgrrhbznewR * Triage bot: start a runner only for events it acts on Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TPWBBSRPfPYWgrrhbznewR --------- Co-authored-by: jyviko <2501648+jyviko@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
70 lines
3.1 KiB
YAML
70 lines
3.1 KiB
YAML
# Labels new issues and PRs from fixed rules, `/triage` for maintainers, and a manual backfill
|
|
# over everything still unlabelled (CONTRIBUTING.md, "Labels and triage"). The logic is in
|
|
# scripts/triage/triage.js (tested in ci.yml).
|
|
name: Triage
|
|
|
|
on:
|
|
issues:
|
|
types: [opened, labeled]
|
|
issue_comment:
|
|
types: [created]
|
|
# pull_request_target so PRs from forks can be labelled. It runs the base branch's
|
|
# scripts/triage and only lists the PR's changed paths; the PR's code is never checked out.
|
|
pull_request_target:
|
|
types: [opened]
|
|
workflow_dispatch:
|
|
inputs:
|
|
dry_run:
|
|
description: 'Only report what would be labelled'
|
|
type: boolean
|
|
default: true
|
|
|
|
permissions:
|
|
contents: read # to check out scripts/triage
|
|
issues: write
|
|
pull-requests: write
|
|
|
|
concurrency:
|
|
group: triage-${{ github.event.issue.number || github.event.pull_request.number || 'backfill' }}
|
|
cancel-in-progress: false
|
|
|
|
jobs:
|
|
triage:
|
|
name: Triage bot
|
|
runs-on: ubuntu-24.04
|
|
timeout-minutes: 30
|
|
# Filtered here so the common events (every comment, every label) start no runner.
|
|
if: >-
|
|
(github.event_name == 'issue_comment' &&
|
|
github.event.comment.user.type != 'Bot' && startsWith(github.event.comment.body, '/triage')) ||
|
|
(github.event.action == 'labeled' && startsWith(github.event.label.name, 'priority:') &&
|
|
contains(github.event.issue.labels.*.name, 'needs-triage')) ||
|
|
(github.event_name != 'issue_comment' && github.event.action != 'labeled')
|
|
steps:
|
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
with:
|
|
sparse-checkout: scripts/triage
|
|
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
env:
|
|
DRY_RUN: ${{ inputs.dry_run }}
|
|
with:
|
|
script: |
|
|
const triage = require('./scripts/triage/triage.js');
|
|
const event = context.eventName;
|
|
if (event === 'issue_comment') {
|
|
core.info(await triage.handleComment({ github, context }));
|
|
} else if (event === 'issues' && context.payload.action === 'labeled') {
|
|
await triage.handleLabeled({ github, context });
|
|
} else if (event === 'workflow_dispatch') {
|
|
const dryRun = process.env.DRY_RUN !== 'false';
|
|
const plan = await triage.backfill({ github, context, dryRun });
|
|
const esc = (t) => String(t).replace(/[&<>"]/g, (c) => ({ '&': '&', '<': '<', '>': '>', '"': '"' })[c]);
|
|
const rows = plan.map((p) => [`#${p.number}`, p.pull ? 'PR' : 'issue', esc(p.labels.join(', ') || '—'), esc(p.title)]);
|
|
await core.summary
|
|
.addHeading(dryRun ? `Backfill dry run: ${plan.length} unlabelled` : `Backfill: ${plan.length} labelled`)
|
|
.addTable([[{ data: 'Item', header: true }, { data: 'Kind', header: true }, { data: 'Labels', header: true }, { data: 'Title', header: true }], ...rows])
|
|
.write();
|
|
} else {
|
|
core.info(`Labelled: ${(await triage.handleOpened({ github, context })).join(', ') || 'nothing'}`);
|
|
}
|