Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions .github/workflows/issue-self-assign.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Self-assign issues

# Lets community contributors and interns claim issues WITHOUT being granted
# write/triage: commenting "/assign" on an issue assigns the commenter,
# "/unassign" removes them. The workflow's GITHUB_TOKEN performs the
# assignment, so no per-person role hand-out is needed for self-service
# claiming. (Requested by Josh — pairs with the fork-and-PR contribution
# model.)
on:
issue_comment:
types: [created]

permissions:
issues: write

jobs:
assign:
# Only on issues (not PR comments), and only for the /assign|/unassign verbs.
if: >-
${{ !github.event.issue.pull_request &&
(startsWith(github.event.comment.body, '/assign') ||
startsWith(github.event.comment.body, '/unassign')) }}
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
with:
script: |
const { owner, repo } = context.repo;
const issue_number = context.issue.number;
const user = context.payload.comment.user.login;
const unassign = context.payload.comment.body.trim().startsWith('/unassign');
if (unassign) {
await github.rest.issues.removeAssignees({ owner, repo, issue_number, assignees: [user] });
} else {
await github.rest.issues.addAssignees({ owner, repo, issue_number, assignees: [user] });
}
Comment on lines +31 to +36
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use exact command matching instead of prefix matching.

startsWith('/assign') will also match comments like /assignment, which currently falls into the assign path. Parse the first token and require exact /assign or /unassign before mutating assignees.

Suggested fix
-            const unassign = context.payload.comment.body.trim().startsWith('/unassign');
-            if (unassign) {
+            const command = context.payload.comment.body.trim().split(/\s+/, 1)[0];
+            if (command === '/unassign') {
               await github.rest.issues.removeAssignees({ owner, repo, issue_number, assignees: [user] });
-            } else {
+            } else if (command === '/assign') {
               await github.rest.issues.addAssignees({ owner, repo, issue_number, assignees: [user] });
+            } else {
+              return;
             }
📝 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 unassign = context.payload.comment.body.trim().startsWith('/unassign');
if (unassign) {
await github.rest.issues.removeAssignees({ owner, repo, issue_number, assignees: [user] });
} else {
await github.rest.issues.addAssignees({ owner, repo, issue_number, assignees: [user] });
}
const command = context.payload.comment.body.trim().split(/\s+/, 1)[0];
if (command === '/unassign') {
await github.rest.issues.removeAssignees({ owner, repo, issue_number, assignees: [user] });
} else if (command === '/assign') {
await github.rest.issues.addAssignees({ owner, repo, issue_number, assignees: [user] });
} else {
return;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/issue-self-assign.yml around lines 31 - 36, The current
check uses startsWith('/unassign') which can misfire on longer tokens; instead
split the comment text into tokens (e.g., const cmd =
context.payload.comment.body.trim().split(/\s+/)[0]) and compare cmd ===
'/assign' or cmd === '/unassign' exactly before calling
github.rest.issues.addAssignees or github.rest.issues.removeAssignees; update
the variable (currently named unassign) to be set from this exact-match
comparison so only an exact first token triggers the assignee mutation.

await github.rest.reactions.createForIssueComment({
owner, repo, comment_id: context.payload.comment.id, content: 'eyes',
});
Comment on lines +32 to +39
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

GitHub REST API docs: what error codes can issues.addAssignees and issues.removeAssignees return, especially when a user is not assignable to a repository issue?

💡 Result:

For GitHub REST API “issue assignees” endpoints (issues.addAssignees and issues.removeAssignees), the docs only spell out these HTTP response status codes for the assignee-add/remove operations: 1) issues.addAssignees (POST /repos/{owner}/{repo}/issues/{issue_number}/assignees) - 201 Created when assignees are added successfully. [1] - 204 No Content when the assignee can be assigned to issue_number. [1] - 404 Not Found when the assignee cannot be assigned to issue_number. [1] 2) issues.removeAssignees (DELETE /repos/{owner}/{repo}/issues/{issue_number}/assignees) - 200 OK when the assignees are removed successfully. [2] When a user is not assignable to a repository issue (i.e., cannot be assigned to that specific issue_number), the REST docs describe the response as 404 Not Found. [1] Note: the removeAssignees operation page shown in the search results explicitly lists only 200 OK, and does not mention additional error status codes on that page. [2]

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE=".github/workflows/issue-self-assign.yml"

# Show the referenced region with some surrounding context
nl -ba "$FILE" | sed -n '1,120p' | cat

Repository: rocketride-org/rocketride-server

Length of output: 119


🏁 Script executed:

#!/bin/bash
set -euo pipefail

FILE=".github/workflows/issue-self-assign.yml"

if [ ! -f "$FILE" ]; then
  echo "Missing $FILE"
  exit 1
fi

awk 'NR>=1 && NR<=120 { printf "%4d: %s\n", NR, $0 }' "$FILE"

Repository: rocketride-org/rocketride-server

Length of output: 1912


Handle GitHub assignee REST failures so the workflow still provides deterministic feedback.

  • .github/workflows/issue-self-assign.yml currently calls github.rest.issues.removeAssignees(...) / github.rest.issues.addAssignees(...) without try/catch; if GitHub returns an error (e.g., 404 when the user can’t be assigned to that issue_number), the script exits before github.rest.reactions.createForIssueComment(..., 'eyes'), failing the job and skipping confirmation.
  • Wrap the mutation in try/catch and post a consistent reaction/comment for both success and failure (and log the error).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/issue-self-assign.yml around lines 32 - 39, Wrap the
assignee mutation calls (github.rest.issues.removeAssignees and
github.rest.issues.addAssignees) in a try/catch so failures do not abort the
workflow; inside the try perform the add/remove based on unassign, and in the
catch log the caught error (include owner, repo, issue_number and user for
context) so failure details are recorded. After the try/catch always call
github.rest.reactions.createForIssueComment with the same confirmation reaction
(and optionally post a brief failure comment) so the workflow gives
deterministic feedback regardless of assignment success.

Loading