Skip to content

ci: add automatic PR labeling from linked issues#67

Merged
panos-xyz merged 3 commits intomainfrom
panos/label-pr
Mar 31, 2026
Merged

ci: add automatic PR labeling from linked issues#67
panos-xyz merged 3 commits intomainfrom
panos/label-pr

Conversation

@panos-xyz
Copy link
Copy Markdown
Contributor

@panos-xyz panos-xyz commented Mar 26, 2026

Summary

Test plan

  • PR referencing an issue with labels gets those labels applied
  • PR without issue reference is handled gracefully (no error)

Summary by CodeRabbit

Release Notes

  • Chores
    • Automated pull request labeling: Pull requests now automatically inherit labels from their associated issues when opened, improving label consistency across the project.

When a PR references an issue (e.g., "fixes #42"), labels from that
issue are automatically copied to the PR. Status and difficulty
labels are excluded.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 26, 2026

Caution

Review failed

Failed to post review comments

📝 Walkthrough

Walkthrough

This PR adds a GitHub Actions workflow that automatically labels pull requests based on referenced issues. When a PR opens, a script extracts the issue number from the PR description, fetches the issue's labels, filters out certain label types, and applies the remaining labels to the PR.

Changes

Cohort / File(s) Summary
GitHub Actions PR Labeling
​.github/assets/label_pr.js, .github/workflows/label-pr.yml
Introduces a new workflow triggered on PR open events that reads PR descriptions to extract referenced issue numbers using regex pattern matching (close/fix/resolve keywords), fetches the issue's labels via GitHub API, filters out status (S-), stale-prevention (M-prevent-stale), and difficulty (D-) labels, then applies the remaining labels to the PR. Includes error handling and logging.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰 Wiggles nose with glee
Auto-labels hop so free,
Issues and PRs now agree!
Regex magic, filters wise,
GitHub API—what a prize! ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR changes implement automatic PR labeling functionality, which is unrelated to the linked issue #42 that requires documentation updates and file additions. The PR implements a GitHub Actions workflow for label automation but does not address any coding objectives from issue #42 (README updates, LICENSE files, CONTRIBUTING guide).
Out of Scope Changes check ⚠️ Warning The PR introduces a new GitHub Actions workflow and script for automatic PR labeling, which is out of scope relative to the linked issue #42 focused on documentation. The PR should either implement the documentation requirements from issue #42 or be linked to a different issue that covers automated PR labeling functionality.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'ci: add automatic PR labeling from linked issues' clearly summarizes the main change: adding CI/workflow automation for automatic PR labeling based on linked issues.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch panos/label-pr

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@panos-xyz panos-xyz requested review from anylots and chengwenxi March 26, 2026 08:03
Copy link
Copy Markdown
Contributor

@chengwenxi chengwenxi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Security posture is sound (pull_request not pull_request_target, scoped permissions). Label propagation logic is correct. Minor notes: only first issue link is processed, fetch-depth: 0 is unnecessary (shallow clone suffices).

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
.github/workflows/label-pr.yml (2)

15-16: Avoid full-history checkout for this workflow.

fetch-depth: 0 is unnecessary here and slows runs. Default shallow checkout is enough for loading .github/assets/label_pr.js.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/label-pr.yml around lines 15 - 16, The workflow step
currently sets fetch-depth: 0 which forces a full-history checkout and slows the
run; remove the unnecessary "fetch-depth: 0" key (or change it to "fetch-depth:
1") from the checkout step so the default shallow checkout is used when loading
.github/assets/label_pr.js — locate the checkout step that contains the "with:"
block and update the fetch-depth setting accordingly.

5-5: Trigger coverage is too narrow for real PR editing flows.

With only opened, labels will not be applied if the issue reference is added later by editing the PR body. Consider including edited (and optionally reopened) to make behavior dependable.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/label-pr.yml at line 5, The GitHub Actions workflow
trigger only listens for the pull_request event with types: [opened], which
misses later edits to the PR body; update the pull_request trigger's types array
(the types field in .github/workflows/label-pr.yml) to include "edited" (and
optionally "reopened") alongside "opened" so label application runs when a PR is
modified after creation; locate the types: [opened] entry in label-pr.yml and
expand it to types: [opened, edited, reopened] (or at minimum add "edited") to
ensure labels are applied on PR edits.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/assets/label_pr.js:
- Around line 61-64: The catch block in label_pr.js currently only logs errors
in the catch (err) { console.error("Failed to label PR"); console.error(err); }
which swallows failures; modify that catch to propagate the failure so the
workflow fails — either rethrow the error or set process.exitCode = 1 (or call
process.exit(1)) after logging. Locate the try/catch around the PR labeling
logic (the catch handling the label API call) and change it to log the error
then rethrow or set a non-zero exit code to ensure CI/workflow reports failure.
- Around line 15-22: The current regexes urlPattern and issuePattern are fragile
because they use a literal space and inject repoUrl unescaped; update both to
accept flexible whitespace (use \s+), allow optional URL schemes and optional
surrounding angle brackets, and escape repoUrl before interpolation (add a
helper like escapeRegExp to sanitize repoUrl) so special characters don't break
the RegExp; also consider using a case-insensitive non-capturing group for verbs
(e.g. (?:close|closes|fixes|resolved)) and anchor or word-boundary the issue
number capture (?<issue_number>\d+) to avoid unintended matches.

In @.github/workflows/label-pr.yml:
- Around line 10-12: Update the workflow permissions block to follow
least-privilege: remove the unnecessary pull-requests: write permission, keep
issues: write for the labels API usage, and add contents: read so the
actions/checkout step has explicit read access to the repository; adjust the
permissions stanza that currently lists issues and pull-requests and ensure
actions/checkout can operate with contents: read instead of granting broader
pull-requests scope.

---

Nitpick comments:
In @.github/workflows/label-pr.yml:
- Around line 15-16: The workflow step currently sets fetch-depth: 0 which
forces a full-history checkout and slows the run; remove the unnecessary
"fetch-depth: 0" key (or change it to "fetch-depth: 1") from the checkout step
so the default shallow checkout is used when loading .github/assets/label_pr.js
— locate the checkout step that contains the "with:" block and update the
fetch-depth setting accordingly.
- Line 5: The GitHub Actions workflow trigger only listens for the pull_request
event with types: [opened], which misses later edits to the PR body; update the
pull_request trigger's types array (the types field in
.github/workflows/label-pr.yml) to include "edited" (and optionally "reopened")
alongside "opened" so label application runs when a PR is modified after
creation; locate the types: [opened] entry in label-pr.yml and expand it to
types: [opened, edited, reopened] (or at minimum add "edited") to ensure labels
are applied on PR edits.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a8f5ca5b-1e11-431b-8184-e2dcb5d79128

📥 Commits

Reviewing files that changed from the base of the PR and between cd54b81 and 84bc067.

📒 Files selected for processing (2)
  • .github/assets/label_pr.js
  • .github/workflows/label-pr.yml

Comment on lines +15 to +22
const urlPattern = new RegExp(
`(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved) ${repoUrl}/issues/(?<issue_number>\\d+)`,
"i"
);
const issuePattern = new RegExp(
`(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved) #(?<issue_number>\\d+)`,
"i"
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Make issue-link regex more robust to formatting and URL matching.

Current patterns are fragile (single literal space) and repoUrl is injected unescaped into a regex. This can miss references in common PR body formatting and allow unintended matches.

💡 Proposed hardening
 function getIssueLink(repoUrl, body) {
   if (!body) return undefined;

+  const escapedRepoUrl = repoUrl.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
   const urlPattern = new RegExp(
-    `(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved) ${repoUrl}/issues/(?<issue_number>\\d+)`,
+    `\\b(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved)\\b\\s+${escapedRepoUrl}/issues/(?<issue_number>\\d+)\\b`,
     "i"
   );
   const issuePattern = new RegExp(
-    `(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved) #(?<issue_number>\\d+)`,
+    `\\b(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved)\\b\\s+#(?<issue_number>\\d+)\\b`,
     "i"
   );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const urlPattern = new RegExp(
`(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved) ${repoUrl}/issues/(?<issue_number>\\d+)`,
"i"
);
const issuePattern = new RegExp(
`(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved) #(?<issue_number>\\d+)`,
"i"
);
const escapedRepoUrl = repoUrl.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
const urlPattern = new RegExp(
`\\b(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved)\\b\\s+${escapedRepoUrl}/issues/(?<issue_number>\\d+)\\b`,
"i"
);
const issuePattern = new RegExp(
`\\b(close|closes|closed|fix|fixes|fixed|resolve|resolves|resolved)\\b\\s+#(?<issue_number>\\d+)\\b`,
"i"
);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/assets/label_pr.js around lines 15 - 22, The current regexes
urlPattern and issuePattern are fragile because they use a literal space and
inject repoUrl unescaped; update both to accept flexible whitespace (use \s+),
allow optional URL schemes and optional surrounding angle brackets, and escape
repoUrl before interpolation (add a helper like escapeRegExp to sanitize
repoUrl) so special characters don't break the RegExp; also consider using a
case-insensitive non-capturing group for verbs (e.g.
(?:close|closes|fixes|resolved)) and anchor or word-boundary the issue number
capture (?<issue_number>\d+) to avoid unintended matches.

Comment on lines +61 to +64
} catch (err) {
console.error("Failed to label PR");
console.error(err);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Do not swallow labeling failures silently.

Line 61-Line 64 only logs errors. If GitHub API calls fail, the workflow still appears successful and masking this breaks reliability of auto-labeling.

✅ Suggested fix
   } catch (err) {
     console.error("Failed to label PR");
     console.error(err);
+    throw err;
   }
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (err) {
console.error("Failed to label PR");
console.error(err);
}
} catch (err) {
console.error("Failed to label PR");
console.error(err);
throw err;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/assets/label_pr.js around lines 61 - 64, The catch block in
label_pr.js currently only logs errors in the catch (err) {
console.error("Failed to label PR"); console.error(err); } which swallows
failures; modify that catch to propagate the failure so the workflow fails —
either rethrow the error or set process.exitCode = 1 (or call process.exit(1))
after logging. Locate the try/catch around the PR labeling logic (the catch
handling the label API call) and change it to log the error then rethrow or set
a non-zero exit code to ensure CI/workflow reports failure.

Comment on lines +10 to +12
permissions:
issues: write
pull-requests: write
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find .github/workflows -name "*label-pr*" -type f

Repository: morph-l2/morph-reth

Length of output: 93


🏁 Script executed:

cat -n .github/workflows/label-pr.yml

Repository: morph-l2/morph-reth

Length of output: 688


🏁 Script executed:

cat -n .github/assets/label_pr.js

Repository: morph-l2/morph-reth

Length of output: 2433


🌐 Web query:

GitHub Actions pull-requests write permission required addLabels

💡 Result:

Yes, GitHub Actions workflows require pull-requests: write permission to add labels to pull requests using the GITHUB_TOKEN. To add labels to a pull request (via the Issues API endpoint POST /repos/{owner}/{repo}/issues/{issue_number}/labels, since PRs are issues), declare the permission in your workflow YAML: permissions: pull-requests: write Example workflow step using gh pr edit or REST API: - name: Add label to PR run: gh pr edit ${{ github.event.pull_request.number }} --add-label "your-label" env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} This grants the GITHUB_TOKEN write access for pull requests. For labeler actions or creating new labels (if they don't exist), issues: write may also be needed alongside pull-requests: write, as PRs leverage the Issues API internally. Official examples in GitHub Docs use issues: write for issue labeling (applicable to PRs), but pull-requests: write is standard and sufficient for adding existing labels to PRs per actions/labeler documentation and community usage. For forked PRs, use pull_request_target trigger with explicit permissions for write access.

Citations:


🌐 Web query:

GitHub API issues.addLabels pull request permission requirements

💡 Result:

The GitHub REST API endpoint for adding labels to issues or pull requests is POST /repos/{owner}/{repo}/issues/{issue_number}/labels. Pull requests use the issues endpoints since every pull request is an issue. Permissions required: - For fine-grained personal access tokens (PATs): issues:write or pull-requests:write permission. - For GitHub Apps: issues:write or pull-requests:write permission. - For classic PATs: repo scope (provides push access to the repository). - Users must have write (push) access to the repository. Without sufficient permissions, label changes are silently dropped or the request fails with 403/404. In GitHub Actions, use permissions: { issues: write } or { pull-requests: write }.

Citations:


Tighten job token scope to least privilege.

This job labels pull requests via the Issues API; pull-requests: write is redundant since the label operation uses issues.addLabels(). Keep issues: write and add explicit contents: read for the checkout action.

🔐 Suggested permissions block
     permissions:
+      contents: read
       issues: write
-      pull-requests: write
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
permissions:
issues: write
pull-requests: write
permissions:
contents: read
issues: write
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/label-pr.yml around lines 10 - 12, Update the workflow
permissions block to follow least-privilege: remove the unnecessary
pull-requests: write permission, keep issues: write for the labels API usage,
and add contents: read so the actions/checkout step has explicit read access to
the repository; adjust the permissions stanza that currently lists issues and
pull-requests and ensure actions/checkout can operate with contents: read
instead of granting broader pull-requests scope.

@panos-xyz panos-xyz merged commit 4959844 into main Mar 31, 2026
13 checks passed
@panos-xyz panos-xyz deleted the panos/label-pr branch March 31, 2026 15:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants