mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-09-20 18:13:49 +00:00
ci: require an open issue for first-time contributor PRs (#7169)
* ci: require an open issue for first-time contributor PRs Gate anyone who is not a returning contributor, and allow the PR only when a closing keyword points at an open issue in this repo. * ci: accept any open issue mention for first-timer PRs Drop the closing-keyword regex so #123, owner/repo#N, or an issue URL is enough when that issue is open. * ci: ignore foreign owner/repo#N in first-timer issue gate Bare #123 no longer matches the suffix of other/repo#123, so an open local issue cannot keep that PR open.
This commit is contained in:
4
.github/CONTRIBUTING.md
vendored
4
.github/CONTRIBUTING.md
vendored
@@ -103,8 +103,8 @@ chore(deps): bump pydantic to 2.11
|
||||
- Keep PRs focused — avoid bundling unrelated changes
|
||||
- PRs over 500 lines are labeled `size/XL` automatically
|
||||
- Title must follow the same conventional commit format
|
||||
- Link related issues where applicable (`Fixes #123`, `Closes #123`, or `Resolves #123`)
|
||||
- First-time contributors must open or pick an existing issue first, then include a closing keyword (`Fixes #N`, `Closes #N`, or `Resolves #N`) in the PR title or body. PRs without a linked issue are closed automatically.
|
||||
- Link related issues where applicable (`#123`, `Fixes #123`, or the issue URL)
|
||||
- First-time contributors must open or pick an existing **open** issue first, then mention it in the PR title or body (for example `#123`). PRs without a linked open issue are closed automatically.
|
||||
|
||||
## Testing
|
||||
|
||||
|
||||
5
.github/pull_request_template.md
vendored
5
.github/pull_request_template.md
vendored
@@ -3,9 +3,8 @@
|
||||
Fixes #
|
||||
|
||||
<!--
|
||||
First-time contributors must link an existing issue in this repo.
|
||||
Use a closing keyword: Fixes #123, Closes #123, or Resolves #123.
|
||||
PRs without a linked issue are closed automatically.
|
||||
First-time contributors must mention an existing open issue in this repo
|
||||
(for example #123). PRs without a linked open issue are closed automatically.
|
||||
-->
|
||||
|
||||
## Summary
|
||||
|
||||
37
.github/workflows/ftc-require-issue.yml
vendored
37
.github/workflows/ftc-require-issue.yml
vendored
@@ -14,17 +14,21 @@ concurrency:
|
||||
|
||||
jobs:
|
||||
require-issue:
|
||||
# Allow-list returning contributors. FIRST_TIMER / FIRST_TIME_CONTRIBUTOR
|
||||
# are often NONE on pull_request_target at opened time, which skipped the
|
||||
# previous deny-list and left first-timer PRs open.
|
||||
if: >
|
||||
github.event.pull_request.user.type != 'Bot' &&
|
||||
contains(fromJSON('["FIRST_TIME_CONTRIBUTOR","FIRST_TIMER"]'),
|
||||
github.event.pull_request.author_association)
|
||||
!contains(fromJSON('["MEMBER","OWNER","COLLABORATOR","CONTRIBUTOR"]'),
|
||||
github.event.pull_request.author_association)
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Require a closing-keyword issue
|
||||
- name: Require an open issue
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
REPO: ${{ github.repository }}
|
||||
AUTHOR_ASSOCIATION: ${{ github.event.pull_request.author_association }}
|
||||
run: |
|
||||
python3 << 'PY'
|
||||
import json
|
||||
@@ -36,13 +40,17 @@ jobs:
|
||||
repo = os.environ["REPO"]
|
||||
pr_number = os.environ["PR_NUMBER"]
|
||||
owner, name = repo.split("/", 1)
|
||||
print(
|
||||
"author_association=",
|
||||
os.environ.get("AUTHOR_ASSOCIATION", ""),
|
||||
sep="",
|
||||
)
|
||||
|
||||
keyword = r"(?:close[sd]?|fix(?:es|ed)?|resolve[sd]?)"
|
||||
patterns = (
|
||||
re.compile(rf"(?i)\b{keyword}\s+#(\d+)\b"),
|
||||
re.compile(rf"(?i)\b{keyword}\s+{re.escape(owner)}/{re.escape(name)}#(\d+)\b"),
|
||||
re.compile(r"(?<![\w./-])#(\d+)\b"),
|
||||
re.compile(rf"{re.escape(owner)}/{re.escape(name)}#(\d+)\b"),
|
||||
re.compile(
|
||||
rf"(?i)\b{keyword}\s+https://github\.com/{re.escape(owner)}/{re.escape(name)}/issues/(\d+)\b"
|
||||
rf"https://github\.com/{re.escape(owner)}/{re.escape(name)}/issues/(\d+)\b"
|
||||
),
|
||||
)
|
||||
|
||||
@@ -51,7 +59,7 @@ jobs:
|
||||
subprocess.check_output(["gh", *args], text=True)
|
||||
)
|
||||
|
||||
def is_repo_issue(number: int) -> bool:
|
||||
def is_open_repo_issue(number: int) -> bool:
|
||||
result = subprocess.run(
|
||||
["gh", "api", f"repos/{repo}/issues/{number}"],
|
||||
capture_output=True,
|
||||
@@ -64,7 +72,10 @@ jobs:
|
||||
raise RuntimeError(
|
||||
f"GitHub API error looking up #{number}: {stderr}"
|
||||
)
|
||||
return "pull_request" not in json.loads(result.stdout)
|
||||
payload = json.loads(result.stdout)
|
||||
if "pull_request" in payload:
|
||||
return False
|
||||
return (payload.get("state") or "").lower() == "open"
|
||||
|
||||
pr = gh_json(
|
||||
"pr", "view", pr_number, "--repo", repo, "--json", "title,body,state"
|
||||
@@ -75,7 +86,7 @@ jobs:
|
||||
for pattern in patterns
|
||||
for match in pattern.findall(text)
|
||||
}
|
||||
if any(is_repo_issue(number) for number in sorted(candidates)):
|
||||
if any(is_open_repo_issue(number) for number in sorted(candidates)):
|
||||
sys.exit(0)
|
||||
|
||||
if (pr.get("state") or "").upper() == "CLOSED":
|
||||
@@ -83,10 +94,10 @@ jobs:
|
||||
|
||||
comment = f"""Thanks for the pull request.
|
||||
|
||||
First-time contributors need an associated issue before we can review a PR.
|
||||
First-time contributors need an associated open issue before we can review a PR.
|
||||
|
||||
1. Open an issue with a [template](https://github.com/{repo}/issues/new/choose), or pick an existing one.
|
||||
2. Open a new PR (or reopen this one) whose title or body includes a closing keyword, for example `Fixes #123`.
|
||||
1. Open an issue with a [template](https://github.com/{repo}/issues/new/choose), or pick an existing open one.
|
||||
2. Open a new PR (or reopen this one) whose title or body mentions that issue, for example `#123`.
|
||||
|
||||
See the [contributing guide](https://github.com/{repo}/blob/main/.github/CONTRIBUTING.md).
|
||||
"""
|
||||
|
||||
Reference in New Issue
Block a user