mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-09 15:19:10 +02:00
Add 'prs welcome' label to waive the PR assignment gate (#4557)
* Add 'prs welcome' label to waive the PR assignment gate Also documents contributor accountability, maintainer edit access, and branch targeting in CONTRIBUTING. * Protect 'prs welcome' from prompt-injected triage labeling
This commit is contained in:
parent
3213776b25
commit
a3163bc275
3 changed files with 50 additions and 10 deletions
17
.github/scripts/triage-label.sh
vendored
17
.github/scripts/triage-label.sh
vendored
|
|
@ -48,17 +48,24 @@ done
|
|||
|
||||
# Never let triage add or remove the Require Issue Link control labels. Those
|
||||
# govern PR enforcement (bypass-issue-check / trusted-contributor are sticky
|
||||
# exemptions) and reopening (missing-issue-link is how closed PRs are found),
|
||||
# so a prompt-injected triage run must not be able to grant an exemption or
|
||||
# break recovery. Enforced here — in code — not merely in the prompt.
|
||||
protected=" missing-issue-link bypass-issue-check trusted-contributor "
|
||||
# exemptions, "prs welcome" waives the assignment requirement) and reopening
|
||||
# (missing-issue-link is how closed PRs are found), so a prompt-injected triage
|
||||
# run must not be able to grant an exemption or break recovery. Enforced here —
|
||||
# in code — not merely in the prompt.
|
||||
#
|
||||
# Exact match against array entries, not a substring scan of a joined string:
|
||||
# label names may contain spaces ("prs welcome"), which in a space-delimited
|
||||
# string would also make bare "prs" and "welcome" match.
|
||||
protected=(missing-issue-link bypass-issue-check trusted-contributor "prs welcome")
|
||||
for label in "$@"; do
|
||||
lower="${label,,}"
|
||||
if [[ "$protected" == *" $lower "* ]]; then
|
||||
for p in "${protected[@]}"; do
|
||||
if [[ "$lower" == "$p" ]]; then
|
||||
echo "refusing to touch protected control label: $label" >&2
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
if [[ "$method" == POST ]]; then
|
||||
args=()
|
||||
|
|
|
|||
27
.github/workflows/require-issue-link.yml
vendored
27
.github/workflows/require-issue-link.yml
vendored
|
|
@ -1,5 +1,8 @@
|
|||
# Require external PRs to reference an issue with an auto-close keyword
|
||||
# (e.g. "Fixes #123") AND have the PR author assigned to that issue.
|
||||
# (e.g. "Fixes #123") AND have the PR author assigned to that issue —
|
||||
# unless the referenced issue is labeled "prs welcome", which waives the
|
||||
# assignment requirement for everyone (the link itself is still required,
|
||||
# since that's how the check finds the issue to read the label from).
|
||||
# Otherwise the PR is labeled "missing-issue-link", commented on, and
|
||||
# closed. CONTRIBUTING.md requires external contributors to be assigned to
|
||||
# an issue before opening a PR; this enforces that.
|
||||
|
|
@ -96,6 +99,8 @@ jobs:
|
|||
const enforce = process.env.ENFORCE_ISSUE_LINK === 'true';
|
||||
const LABEL = 'missing-issue-link';
|
||||
const MARKER = '<!-- require-issue-link -->';
|
||||
// Issue-level label that waives the assignment requirement.
|
||||
const OPEN_LABEL = 'prs welcome';
|
||||
|
||||
// Dry-run guard: every mutating call goes through this so that
|
||||
// ENFORCE_ISSUE_LINK=false means strictly read-only.
|
||||
|
|
@ -300,6 +305,13 @@ jobs:
|
|||
// CONTRIBUTING.md requires external contributors to be assigned
|
||||
// before opening a PR (so maintainers can deconflict / steer
|
||||
// approach first).
|
||||
//
|
||||
// Exception: an issue labeled OPEN_LABEL waives that requirement
|
||||
// for everyone. It's how maintainers advertise "the reporter
|
||||
// isn't implementing this, we'd take a PR from anyone" without
|
||||
// having to assign a specific person up front. Unlike the
|
||||
// PR-level `trusted-contributor` / `bypass-issue-check` escapes,
|
||||
// this one lives on the *issue* and is set ahead of time.
|
||||
const MAX_ISSUES = 5;
|
||||
const allNumbers = [...new Set(matches.map(m => parseInt(m[1], 10)))];
|
||||
const numbers = allNumbers.slice(0, MAX_ISSUES);
|
||||
|
|
@ -326,6 +338,19 @@ jobs:
|
|||
throw new Error(`Cannot fetch issue #${num} (HTTP ${e.status ?? 'unknown'}): ${e.message}`);
|
||||
}
|
||||
sawRealIssue = true;
|
||||
|
||||
// GitHub returns labels as objects here, but the REST schema
|
||||
// permits bare strings — normalize both rather than assume.
|
||||
const labelNames = (issue.labels || [])
|
||||
.map(l => (typeof l === 'string' ? l : l && l.name))
|
||||
.filter(Boolean)
|
||||
.map(n => n.toLowerCase());
|
||||
if (labelNames.includes(OPEN_LABEL)) {
|
||||
console.log(`#${num} is labeled "${OPEN_LABEL}" — assignment not required`);
|
||||
assignedToAny = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const assignees = (issue.assignees || []).map(a => a.login.toLowerCase());
|
||||
if (assignees.includes(prAuthor)) {
|
||||
console.log(`PR author ${pr.user.login} is assigned to #${num}`);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
FastMCP is an actively maintained, high-traffic project. We welcome contributions — but the most impactful way to contribute might not be what you expect.
|
||||
|
||||
Participation is governed by our [Code of Conduct](CODE_OF_CONDUCT.md), and contributions are licensed under [Apache 2.0](LICENSE).
|
||||
|
||||
## The best contribution is a great issue
|
||||
|
||||
FastMCP is an opinionated framework, and its maintainers use AI-assisted tooling that is deeply tuned to those opinions — the design philosophy, the API patterns, the way the framework is meant to evolve. A well-written issue with a clear problem description is often more valuable than a pull request, because it lets maintainers produce a solution that isn't just correct, but consistent with how the framework wants to work. That matters more than speed, though it's faster too.
|
||||
|
|
@ -26,6 +28,10 @@ An open issue is not an invitation to submit a PR, and it is not a queue you joi
|
|||
|
||||
**Don't post drive-by comments claiming an issue** — "can I work on this?", "please assign me", "I'll take this." They don't affect who gets assigned, they're the most common form of noise we get, and automated versions are ignored. Whoever opens the issue has first claim on it; if that's you, a maintainer will assign you. If you want to implement something someone else reported, just open a PR — you don't need permission to try, and competing PRs are fine — but it's reviewed only if a maintainer assigns you to the issue, which usually won't happen if the reporter intends to handle it. The one comment worth posting is a genuinely different approach worth discussing; a substantive design proposal is welcome, a bare claim on the task is not.
|
||||
|
||||
**Issues labeled `prs welcome` skip the assignment gate.** When we apply that label, we're saying the reporter isn't implementing it and we'd take a PR from anyone. Open one directly — no assignment needed, and it won't be auto-closed. Still reference the issue (`Fixes #123`), since that's how the check knows which issue to look at.
|
||||
|
||||
**What assignment means.** Being assigned is a commitment on both sides: we'll review your work seriously, and you'll see it through. That means responding to review feedback yourself and being able to explain any part of your change and why you made it that way. Use whatever tooling you like to get there — but if you can't answer a question about your own diff, we'll unassign the issue so someone else can pick it up.
|
||||
|
||||
**Bug fixes** — PRs are welcome for simple, well-scoped bug fixes where the problem and solution are both straightforward. "The function raises `TypeError` when passed `None` because of a missing guard" is a good candidate. If the fix requires design decisions or touches multiple subsystems, open an issue with a design proposal instead.
|
||||
|
||||
**Documentation** — Typo fixes, clarifications, and improvements to examples are always welcome as PRs.
|
||||
|
|
@ -38,7 +44,9 @@ An open issue is not an invitation to submit a PR, and it is not a queue you joi
|
|||
|
||||
If you do open a PR:
|
||||
|
||||
- **Reference an issue you're assigned to.** Every PR must reference a tracked issue using an auto-close keyword (`Fixes #123`, `Closes #123`, or `Resolves #123`), and the referenced issue must be assigned to you. If there isn't an issue, open one. This lets us deconflict effort and steer the approach before you invest time in code. External PRs that don't meet both conditions are automatically labeled `missing-issue-link` and closed; they reopen automatically once the link is present and you're assigned.
|
||||
- **Reference an issue you're assigned to.** Every PR must reference a tracked issue using an auto-close keyword (`Fixes #123`, `Closes #123`, or `Resolves #123`), and the referenced issue must be assigned to you — unless it's labeled `prs welcome`, which waives the assignment requirement. If there isn't an issue, open one. This lets us deconflict effort and steer the approach before you invest time in code. External PRs that don't meet these conditions are automatically labeled `missing-issue-link` and closed; they reopen automatically once the link is present and you're assigned.
|
||||
- **Leave "Allow edits by maintainers" enabled.** We frequently take a PR the last few steps ourselves rather than block on another round trip — tightening a test, adjusting naming, rebasing. It's enabled by default on PRs from personal forks; leave it that way. GitHub doesn't allow it at all for forks owned by an organization, so if you're contributing from one, expect us to land the final changes separately.
|
||||
- **Target the right branch.** Open against `main` unless you're fixing something specific to a maintenance line, in which case target that branch directly (`release/3.x`, `release/2.x`).
|
||||
- **If your PR was auto-closed, don't open a new one.** Edit the *existing* PR to add the issue link, get assigned to that issue, and it reopens on its own — the branch and history are preserved. A duplicate PR just starts you over and adds to the triage pile.
|
||||
- **Keep it focused.** One logical change per PR. Don't bundle unrelated fixes or refactors.
|
||||
- **Match existing patterns.** Follow the code style, type annotation conventions, and test patterns you see in the codebase. Run `uv run prek run --all-files` before submitting.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue