fix(ci): handle cross-repo refs and exempt org members from linked-issue check (#5113)

## Summary / motivation

Two independent gaps in the `check-linked-issue` workflow caused false
positives on valid PRs:

1. **Cross-repo references not recognised** — the regex only matched
bare `#NNN` but GitHub also accepts `owner/repo#NNN`. Any PR referencing
an issue from another repository (e.g. `Refs ankitects/ankimobile#10`)
was still flagged. Observed in #5111.

2. **Org members should be trusted contributors** — maintainers and core
team members already know the process; requiring them to link an issue
on every PR adds friction with no benefit. The check now calls the
GitHub membership API and skips the requirement for org members
entirely.

## Steps to reproduce

1. Open a PR with `Refs ankitects/ankimobile#10` as the linked issue →
bot flags it as missing.
2. Open a PR as an org member without a linked issue → bot should not
flag it.

## How to test

1. Open a draft PR from an external contributor with `Refs
owner/repo#NNN` → verify **no** `missing-issue` label.
2. Open a draft PR as an org member with no linked issue → verify **no**
label or comment.
3. Open a draft PR as an external contributor with no linked issue →
verify label and comment **are** applied.
This commit is contained in:
Fernando Lins
2026-07-06 17:40:32 -03:00
committed by GitHub
parent 4bb42b0f64
commit 257ea825b8
+8 -1
View File
@@ -10,6 +10,7 @@ jobs:
permissions:
pull-requests: write
issues: write
members: read
steps:
- name: Check for linked issue
@@ -22,7 +23,13 @@ jobs:
const author = pr.user.login;
const labels = pr.labels.map(l => l.name);
const isOrgMember = await github.rest.orgs.checkMembershipForUser({
org: owner,
username: author,
}).then(() => true).catch(() => false);
const isExempt =
isOrgMember ||
labels.includes('hotfix') ||
author === 'dependabot[bot]' ||
labels.includes('dependencies');
@@ -34,7 +41,7 @@ jobs:
}
core.setOutput('exempt', 'false');
const linkedIssuePattern = /\b(closes|close|fixes|fix|resolves|resolve|refs|ref|references)\s+#\d+/i;
const linkedIssuePattern = /\b(closes|close|fixes|fix|resolves|resolve|refs|ref|references)\s+(?:[a-zA-Z0-9_.-]+\/[a-zA-Z0-9_.-]+)?#\d+/i;
const hasLinkedIssue = linkedIssuePattern.test(body);
core.setOutput('has_linked_issue', hasLinkedIssue);