-
-
Notifications
You must be signed in to change notification settings - Fork 89
[feature/releaser] Automate assigning/unassigning issues #571 #572
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
[feature/releaser] Automate assigning/unassigning issues #571 #572
Conversation
📝 WalkthroughWalkthroughFour new GitHub Actions workflows are added to automate issue and PR lifecycle tasks: an "Issue Assignment Bot" that replies to assignment-request comments with contribution guidance; a PR-linked-issue assigner that parses PR bodies and assigns linked issues to the PR author when opened; a reopen-and-activity handler that reassigns linked issues and removes a "stale" label when PR authors return or reopen PRs; and a Stale PR Management workflow that posts warnings, labels, unassigns, or closes inactive PRs based on 7/14/60-day thresholds. Sequence Diagram(s)sequenceDiagram
participant Commenter
participant GitHub as GitHub Events
participant Action as Issue Assignment Workflow
participant API as GitHub API (Issues)
Commenter->>GitHub: posts issue comment with "I'll take this" phrase
GitHub->>Action: triggers on issue_comment.created (non-PR)
Action->>API: read comment & issue details
alt comment matches assignment phrases
Action->>API: post guided reply comment with contribution steps
end
sequenceDiagram
participant Author
participant GitHub as GitHub Events
participant Action as PR Workflows (pr-issue-link / pr-reopen-reassign / stale-pr-management)
participant API as GitHub API (PRs & Issues)
participant Repo as Repository State (Issues, PRs, Labels)
Author->>GitHub: open/reopen PR or comment on PR
GitHub->>Action: trigger appropriate workflow (open/reopen/comment/schedule)
Action->>API: parse PR body for linked issues
loop for each linked issue
Action->>API: fetch issue
alt no assignees or assigned to PR author
Action->>API: add PR author as assignee
Action->>API: post comment on issue about automatic assignment
else if assigned to others
Action->>API: log/skips
end
end
alt stale-management path
Action->>API: check last author activity, comments, reviews
Action->>Repo: add label / post warnings / unassign from issues / close PR based on thresholds
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR introduces GitHub Actions workflows to automate issue assignment/unassignment based on PR linking and contributor activity, and to manage stale PRs after changes are requested.
Changes:
- Adds an “assign me” responder that directs contributors to the guidelines and encourages opening a linked PR.
- Auto-assigns linked issues to PR authors when PRs are opened/reopened.
- Introduces stale PR management that warns, marks stale/unassigns, and closes PRs after defined inactivity windows.
- Reassigns linked issues and removes stale status when PRs are reopened or when the PR author comments on a stale PR.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 10 comments.
| File | Description |
|---|---|
| .github/workflows/issue-assignment.yml | Responds to “assign me” issue comments with contribution guidance and PR-linking instructions. |
| .github/workflows/pr-issue-link.yml | Auto-assigns linked issues to PR authors on PR open/reopen. |
| .github/workflows/stale-pr-management.yml | Daily job to warn, mark stale/unassign, and close PRs after inactivity post “changes requested”. |
| .github/workflows/pr-reopen-reassign.yml | Reassigns issues / removes stale label on PR reopen and on PR-author follow-up comments. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const prBody = pr.body || ''; | ||
| const issuePattern = /(?:fix(?:es)?|close[sd]?|resolve[sd]?)\s+#(\d+)/gi; | ||
| const matches = [...prBody.matchAll(issuePattern)]; | ||
| for (const match of matches) { | ||
| const issueNumber = parseInt(match[1], 10); | ||
| try { | ||
| await github.rest.issues.removeAssignees({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: issueNumber, | ||
| assignees: [prAuthor] | ||
| }); | ||
| console.log(`Unassigned ${prAuthor} from issue #${issueNumber}`); |
Copilot
AI
Jan 31, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When extracting linked issues from the PR body, duplicates aren’t deduplicated and PR references aren’t filtered out. This can lead to repeated API calls (and possible rate limiting) and may attempt to unassign from referenced pull requests. Consider tracking processedIssues (as done in other workflows) and fetching the item to skip issue.data.pull_request before unassigning.
|
|
||
| permissions: | ||
| issues: write | ||
| pull-requests: write |
Copilot
AI
Jan 31, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The workflow is granting pull-requests: write, but it only reads PR data (and modifies issues/labels). Reducing this to pull-requests: read limits token scope and avoids unnecessary write privileges.
| pull-requests: write | |
| pull-requests: read |
| name: 'stale' | ||
| }); | ||
| } catch (e) { | ||
|
|
Copilot
AI
Jan 31, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This empty catch block swallows failures when removing the stale label, which makes debugging harder (e.g., permission changes, API errors). Consider at least logging the error or explicitly handling the expected 404 case.
| const status = e?.status ?? e?.response?.status; | |
| if (status === 404) { | |
| console.log(`'stale' label not found on PR #${prNumber}, nothing to remove.`); | |
| } else { | |
| console.error(`Failed to remove 'stale' label from PR #${prNumber}:`, e); | |
| } |
| const issuePattern = /(?:fix(?:es)?|close[sd]?|resolve[sd]?)\s+#(\d+)/gi; | ||
| const matches = [...prBody.matchAll(issuePattern)]; | ||
| if (matches.length === 0) { | ||
| console.log('No linked issues found in PR body'); | ||
| return; | ||
| } | ||
| const processedIssues = new Set(); | ||
| for (const match of matches) { | ||
| const issueNumber = parseInt(match[1], 10); | ||
| if (processedIssues.has(issueNumber)) { | ||
| continue; | ||
| } | ||
| processedIssues.add(issueNumber); | ||
| try { |
Copilot
AI
Jan 31, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The linked-issue parsing loop has no upper bound; a PR body referencing many issues could cause a large number of API calls and spam comments/assignments, potentially hitting rate limits. Consider limiting how many issue references are processed (e.g., first N unique matches) and logging when the limit is exceeded.
| with: | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||
| script: | | ||
| const contributingUrl = 'http://openwisp.io/docs/developer/contributing.html'; |
Copilot
AI
Jan 31, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The contributing URL is using plain HTTP. Prefer HTTPS to avoid mixed-content/security issues and ensure users are sent to the secure version of the docs.
| const contributingUrl = 'http://openwisp.io/docs/developer/contributing.html'; | |
| const contributingUrl = 'https://openwisp.io/docs/developer/contributing.html'; |
| contains(github.event.comment.body, 'assign this issue to me') || | ||
| contains(github.event.comment.body, 'assign me') || | ||
| contains(github.event.comment.body, 'can I work on this') || | ||
| contains(github.event.comment.body, 'I would like to work on this') || | ||
| contains(github.event.comment.body, 'I want to work on this') |
Copilot
AI
Jan 31, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The trigger conditions use case-sensitive contains(...) checks, so common variants like "Assign me" / "assign me!" / different capitalization won’t match. Consider normalizing github.event.comment.body (e.g., toLowerCase()) and matching more robustly to avoid missed requests.
| contains(github.event.comment.body, 'assign this issue to me') || | |
| contains(github.event.comment.body, 'assign me') || | |
| contains(github.event.comment.body, 'can I work on this') || | |
| contains(github.event.comment.body, 'I would like to work on this') || | |
| contains(github.event.comment.body, 'I want to work on this') | |
| contains(toLower(github.event.comment.body), 'assign this issue to me') || | |
| contains(toLower(github.event.comment.body), 'assign me') || | |
| contains(toLower(github.event.comment.body), 'can i work on this') || | |
| contains(toLower(github.event.comment.body), 'i would like to work on this') || | |
| contains(toLower(github.event.comment.body), 'i want to work on this') |
| const { data: pullRequests } = await github.rest.pulls.list({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| state: 'open', | ||
| per_page: 100 | ||
| }); |
Copilot
AI
Jan 31, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The workflow only fetches the first page of open PRs (per_page: 100) and does not paginate, so repos with >100 open PRs will silently skip the rest. Consider using github.paginate(...) (or manual page looping) to process all open PRs reliably.
| const { data: pullRequests } = await github.rest.pulls.list({ | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| state: 'open', | |
| per_page: 100 | |
| }); | |
| const pullRequests = await github.paginate( | |
| github.rest.pulls.list, | |
| { | |
| owner: context.repo.owner, | |
| repo: context.repo.repo, | |
| state: 'open', | |
| per_page: 100 | |
| } | |
| ); |
| const { data: reviews } = await github.rest.pulls.listReviews({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| pull_number: prNumber | ||
| }); | ||
| const changesRequestedReviews = reviews | ||
| .filter(r => r.state === 'CHANGES_REQUESTED') | ||
| .sort((a, b) => new Date(b.submitted_at) - new Date(a.submitted_at)); | ||
| if (changesRequestedReviews.length === 0) { | ||
| continue; | ||
| } | ||
| const lastChangesRequested = new Date(changesRequestedReviews[0].submitted_at); | ||
| const { data: commits } = await github.rest.pulls.listCommits({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| pull_number: prNumber, | ||
| per_page: 100 | ||
| }); | ||
| const { data: comments } = await github.rest.issues.listComments({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: prNumber, | ||
| per_page: 100 | ||
| }); |
Copilot
AI
Jan 31, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
listReviews, listCommits and issues.listComments are called without pagination (and listReviews doesn’t even set per_page). For long-running PRs with many commits/comments/reviews, activity and the latest CHANGES_REQUESTED timestamp can be missed, which can incorrectly mark/close PRs. Use github.paginate(...) for these endpoints (and/or increase per_page + loop).
| issue_comment: | ||
| types: [created] | ||
| push: | ||
|
|
Copilot
AI
Jan 31, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
on: push is configured, but both jobs are gated to pull_request_target or issue_comment, so push events will trigger workflow runs that immediately skip all jobs. Removing the push trigger avoids noisy/empty runs and reduces Actions usage.
| @@ -0,0 +1,77 @@ | |||
| name: PR Issue Auto-Assignment | |||
Copilot
AI
Jan 31, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR description ends with “Fixes #541”, but #541 appears to be an unrelated (already-merged) UI PR in this repository’s history. If the intent is to close an issue for this automation feature, the reference likely needs to point to the correct issue number (or be removed to avoid auto-closing the wrong item).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🤖 Fix all issues with AI agents
In @.github/workflows/issue-assignment.yml:
- Line 28: The contributingUrl constant is using an insecure HTTP URL; update
the value of contributingUrl to use the HTTPS scheme (i.e., replace
'http://openwisp.io/docs/developer/contributing.html' with
'https://openwisp.io/docs/developer/contributing.html') so the link is served
over TLS and avoids mixed-content/MITM risks.
In @.github/workflows/stale-pr-management.yml:
- Around line 26-59: The list calls (pulls.list, pulls.listReviews,
pulls.listCommits, issues.listComments) currently use per_page: 100 and will
miss results beyond the first page; replace each call with github.paginate(...)
using the corresponding endpoint.merge({...}) parameters (keep owner, repo,
pull_number/issue_number and state where applicable) to populate pullRequests,
reviews, commits, and comments with the full arrays; remove reliance on
single-page responses and ensure downstream code (e.g., filtering
changesRequestedReviews and accessing commits/comments) works with the full
arrays returned by paginate.
🧹 Nitpick comments (1)
.github/workflows/pr-reopen-reassign.yml (1)
3-9: Drop the unusedpushtrigger to avoid empty workflow runs.No job is enabled for
push, so these runs will always be skipped.🧹 Minimal cleanup
on: pull_request_target: types: [reopened] issue_comment: types: [created] - push:
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
.github/workflows/issue-assignment.yml.github/workflows/pr-issue-link.yml.github/workflows/pr-reopen-reassign.yml.github/workflows/stale-pr-management.yml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
- GitHub Check: Python==3.12 | django~=4.2.0
- GitHub Check: Python==3.13 | django~=5.2.0
- GitHub Check: Python==3.13 | django~=5.1.0
- GitHub Check: Python==3.10 | django~=5.1.0
- GitHub Check: Python==3.12 | django~=5.0.0
- GitHub Check: Python==3.12 | django~=5.2.0
- GitHub Check: Python==3.10 | django~=5.2.0
- GitHub Check: Python==3.12 | django~=5.1.0
- GitHub Check: Python==3.11 | django~=5.0.0
- GitHub Check: Python==3.11 | django~=5.2.0
- GitHub Check: Python==3.10 | django~=4.2.0
- GitHub Check: Python==3.11 | django~=4.2.0
- GitHub Check: Python==3.11 | django~=5.1.0
- GitHub Check: Python==3.10 | django~=5.0.0
- GitHub Check: Agent
🔇 Additional comments (1)
.github/workflows/pr-issue-link.yml (1)
20-75: Solid auto-assignment flow — looks safe and well-guarded.Nice dedupe + PR/assignee checks with clear logging.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| const { data: pullRequests } = await github.rest.pulls.list({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| state: 'open', | ||
| per_page: 100 | ||
| }); | ||
| for (const pr of pullRequests) { | ||
| const prAuthor = pr.user.login; | ||
| const prNumber = pr.number; | ||
| try { | ||
| const { data: reviews } = await github.rest.pulls.listReviews({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| pull_number: prNumber | ||
| }); | ||
| const changesRequestedReviews = reviews | ||
| .filter(r => r.state === 'CHANGES_REQUESTED') | ||
| .sort((a, b) => new Date(b.submitted_at) - new Date(a.submitted_at)); | ||
| if (changesRequestedReviews.length === 0) { | ||
| continue; | ||
| } | ||
| const lastChangesRequested = new Date(changesRequestedReviews[0].submitted_at); | ||
| const { data: commits } = await github.rest.pulls.listCommits({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| pull_number: prNumber, | ||
| per_page: 100 | ||
| }); | ||
| const { data: comments } = await github.rest.issues.listComments({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: prNumber, | ||
| per_page: 100 | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
# First, let's locate and examine the workflow file
find . -name "stale-pr-management.yml" -type fRepository: openwisp/openwisp-utils
Length of output: 110
🏁 Script executed:
# Once located, read the file to verify the pagination concern
cat -n .github/workflows/stale-pr-management.ymlRepository: openwisp/openwisp-utils
Length of output: 11967
🏁 Script executed:
# Also search for any usage of github.paginate in the repo
rg "github\.paginate" --type yaml --type javascript --type jsonRepository: openwisp/openwisp-utils
Length of output: 101
🏁 Script executed:
# Search for any pagination usage in the repo
rg "paginate" --no-filename -iRepository: openwisp/openwisp-utils
Length of output: 49
🏁 Script executed:
# Check if there are any other GitHub script workflows that might show pagination patterns
fd "\.yml$" -o "\.yaml$" .github/workflows/ -x grep -l "github-script"Repository: openwisp/openwisp-utils
Length of output: 200
🏁 Script executed:
# Let's also check the version of actions/github-script to understand what's available
grep -r "actions/github-script" .github/workflows/Repository: openwisp/openwisp-utils
Length of output: 460
🏁 Script executed:
# Check one of the other github-script workflows to see if they use pagination
cat -n .github/workflows/issue-assignment.yml | head -100Repository: openwisp/openwisp-utils
Length of output: 2754
🏁 Script executed:
# Let's check if there's a package.json or any docs about octokit versions
find . -name "package.json" -o -name "package-lock.json" | head -5Repository: openwisp/openwisp-utils
Length of output: 49
🌐 Web query:
github.paginate actions/github-script v7 octokit
💡 Result:
In actions/github-script@v7, the github object you get in script: is an authenticated Octokit client, and github.paginate is available (pagination behavior is the standard Octokit paginate() helper). Also, since v5+, REST endpoints are under github.rest.* (but github.paginate is unchanged). [1]
Pattern 1: paginate an endpoint “options” object (common in github-script)
const opts = github.rest.issues.listForRepo.endpoint.merge({
owner: context.repo.owner,
repo: context.repo.repo,
state: "all",
per_page: 100,
});
const issues = await github.paginate(opts);
console.log(issues.length);This is the same pattern shown in the actions/github-script docs/examples. [1]
Pattern 2: paginate by route + parameters (Octokit style)
const issues = await github.paginate("GET /repos/{owner}/{repo}/issues", {
owner: context.repo.owner,
repo: context.repo.repo,
per_page: 100,
});octokit.paginate() (and therefore github.paginate() here) keeps fetching pages until the last page and returns a single flattened array. [2]
Sources:
[1] actions/github-script README (breaking changes + paginate example) (github.com)
[2] GitHub Docs: “Using pagination in the REST API” (Octokit paginate behavior + example) (docs.github.com)
Citations:
- 1: https://github.com/actions/github-script?utm_source=openai
- 2: https://docs.github.com/rest/using-the-rest-api/using-pagination-in-the-rest-api?utm_source=openai
Pagination required: list calls will miss data beyond 100 items.
All four list calls use per_page: 100 without pagination logic, which means the script will skip remaining results in repositories with more than 100 open PRs or PRs with more than 100 reviews/commits/comments. This can cause the stale PR detection to run on incomplete data and trigger incorrect unassign/close actions.
Use github.paginate() to fetch all pages. For example:
const pullRequests = await github.paginate(
github.rest.pulls.list.endpoint.merge({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
per_page: 100
})
);Apply the same pattern to listReviews(), listCommits(), and listComments().
🤖 Prompt for AI Agents
In @.github/workflows/stale-pr-management.yml around lines 26 - 59, The list
calls (pulls.list, pulls.listReviews, pulls.listCommits, issues.listComments)
currently use per_page: 100 and will miss results beyond the first page; replace
each call with github.paginate(...) using the corresponding
endpoint.merge({...}) parameters (keep owner, repo, pull_number/issue_number and
state where applicable) to populate pullRequests, reviews, commits, and comments
with the full arrays; remove reliance on single-page responses and ensure
downstream code (e.g., filtering changesRequestedReviews and accessing
commits/comments) works with the full arrays returned by paginate.
c5d42ba to
a34efd6
Compare
I've created four GitHub Actions workflow files to automate issue assignment/unassignment. Created Workflows: 1. issue-assignment.yml – Auto-response to 'assign me' requests 2. pr-issue-link.yml – Auto-assign on PR 3. stale-pr-management.yml – Stale PR management (tracks contributor inactivity only) 4. pr-reopen-reassign.yml – Handle contributor follow-up Fixes openwisp#571
a34efd6 to
a116660
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @.github/workflows/issue-assignment.yml:
- Around line 13-57: The job 'if' condition uses unsupported toLower() calls
around github.event.comment.body; update the conditional to remove the toLower()
wrappers and call contains() directly on github.event.comment.body (e.g.,
replace contains(toLower(github.event.comment.body), 'assign me') with
contains(github.event.comment.body, 'assign me')) so the expressions use the
built-in case-insensitive contains() correctly.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
.github/workflows/issue-assignment.yml.github/workflows/pr-issue-link.yml.github/workflows/pr-reopen-reassign.yml.github/workflows/stale-pr-management.yml
🚧 Files skipped from review as they are similar to previous changes (1)
- .github/workflows/pr-reopen-reassign.yml
🧰 Additional context used
🪛 actionlint (1.7.10)
.github/workflows/issue-assignment.yml
[error] 15-15: undefined function "toLower". available functions are "always", "cancelled", "contains", "endswith", "failure", "format", "fromjson", "hashfiles", "join", "startswith", "success", "tojson"
(expression)
[error] 16-16: undefined function "toLower". available functions are "always", "cancelled", "contains", "endswith", "failure", "format", "fromjson", "hashfiles", "join", "startswith", "success", "tojson"
(expression)
[error] 17-17: undefined function "toLower". available functions are "always", "cancelled", "contains", "endswith", "failure", "format", "fromjson", "hashfiles", "join", "startswith", "success", "tojson"
(expression)
[error] 18-18: undefined function "toLower". available functions are "always", "cancelled", "contains", "endswith", "failure", "format", "fromjson", "hashfiles", "join", "startswith", "success", "tojson"
(expression)
[error] 19-19: undefined function "toLower". available functions are "always", "cancelled", "contains", "endswith", "failure", "format", "fromjson", "hashfiles", "join", "startswith", "success", "tojson"
(expression)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
- GitHub Check: Python==3.10 | django~=5.1.0
- GitHub Check: Python==3.12 | django~=4.2.0
- GitHub Check: Python==3.13 | django~=5.2.0
- GitHub Check: Python==3.12 | django~=5.2.0
- GitHub Check: Python==3.13 | django~=5.1.0
- GitHub Check: Python==3.10 | django~=5.2.0
- GitHub Check: Python==3.11 | django~=5.2.0
- GitHub Check: Python==3.11 | django~=5.0.0
- GitHub Check: Python==3.12 | django~=5.0.0
- GitHub Check: Python==3.12 | django~=5.1.0
- GitHub Check: Python==3.11 | django~=5.1.0
- GitHub Check: Python==3.10 | django~=5.0.0
- GitHub Check: Python==3.10 | django~=4.2.0
- GitHub Check: Python==3.11 | django~=4.2.0
🔇 Additional comments (7)
.github/workflows/pr-issue-link.yml (2)
3-10: Workflow trigger and permissions look good.Clear event scope and minimal permissions for the task.
20-85: Solid issue-link parsing and assignment flow.Dedupe + max cap reduce rate‑limit risk; skip logic for PRs/assigned issues is sensible.
.github/workflows/stale-pr-management.yml (5)
3-10: Schedule and permissions are appropriate.Daily cadence and write permissions align with automation responsibilities.
81-94: Bot-comment detection for stale actions is clear and consistent.The
botComments+ flags avoid duplicate warnings.
95-155: Closure flow is clear and user-friendly.Closes after the threshold and unassigns linked issues as expected.
156-219: Unassign + stale labeling branch looks solid.The messaging and unassign behavior align with the workflow intent.
220-244: Stale warning messaging is concise and actionable.Good guidance for contributors before escalation.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| if: | | ||
| github.event.issue.pull_request == null && | ||
| ( | ||
| contains(toLower(github.event.comment.body), 'assign this issue to me') || | ||
| contains(toLower(github.event.comment.body), 'assign me') || | ||
| contains(toLower(github.event.comment.body), 'can i work on this') || | ||
| contains(toLower(github.event.comment.body), 'i would like to work on this') || | ||
| contains(toLower(github.event.comment.body), 'i want to work on this') | ||
| ) | ||
| steps: | ||
| - name: Respond to assignment request | ||
| uses: actions/github-script@v7 | ||
| with: | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||
| script: | | ||
| const contributingUrl = 'https://openwisp.io/docs/developer/contributing.html'; | ||
| const commenter = context.payload.comment.user.login; | ||
|
|
||
| const message = `Hi @${commenter} 👋, | ||
|
|
||
| Thank you for your interest in contributing to OpenWISP! 🎉 | ||
|
|
||
| According to our [contributing guidelines](${contributingUrl}), **you don't need to wait to be assigned** to start working on an issue. We encourage you to: | ||
|
|
||
| 1. **Fork the repository** and start working on your solution | ||
| 2. **Open a Pull Request (PR) as soon as possible** - even as a draft if it's still in progress | ||
| 3. **Link your PR to this issue** by including \`Fixes #${context.payload.issue.number}\` in the PR description | ||
|
|
||
| Once you open a PR that references this issue, you will be automatically assigned to it. | ||
|
|
||
| This approach helps us: | ||
| - See your progress and provide early feedback | ||
| - Avoid multiple contributors working on the same issue unknowingly | ||
| - Keep the contribution process moving smoothly | ||
|
|
||
| We look forward to your contribution! If you have any questions, feel free to ask in the PR or check our [documentation](${contributingUrl}). | ||
|
|
||
| Happy coding! 🚀`; | ||
|
|
||
| await github.rest.issues.createComment({ | ||
| owner: context.repo.owner, | ||
| repo: context.repo.repo, | ||
| issue_number: context.payload.issue.number, | ||
| body: message | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
GitHub Actions expression language toLower function documentation
💡 Result:
GitHub Actions’ expression language does not have a toLower() / toLowerCase() function. The official “Evaluate expressions” docs list the built-in functions (e.g., contains, startsWith, endsWith, format, join, toJSON, fromJSON, hashFiles, case), and toLower is not among them. Comparisons and some functions are already case-insensitive (for example, contains, startsWith, and endsWith). [1]
If you need an actual lowercase transformation, you must do it in a step (shell) or script (e.g., JavaScript via actions/github-script, where expressions are evaluated before being passed into the script). [2]
Sources:
[1] GitHub Docs — “Evaluate expressions in workflows and actions” (Functions section) (docs.github.com)
[2] actions/github-script README (expressions evaluated before script) (github.com)
Citations:
- 1: https://docs.github.com/en/actions/reference/evaluate-expressions-in-workflows-and-actions
- 2: https://github.com/actions/github-script?utm_source=openai
Remove invalid toLower() calls from the job if condition.
GitHub Actions expressions don't support toLower(), but the built-in contains() function is already case-insensitive. Simply remove the toLower() wrapping:
Suggested fix
- if: |
- github.event.issue.pull_request == null &&
- (
- contains(toLower(github.event.comment.body), 'assign this issue to me') ||
- contains(toLower(github.event.comment.body), 'assign me') ||
- contains(toLower(github.event.comment.body), 'can i work on this') ||
- contains(toLower(github.event.comment.body), 'i would like to work on this') ||
- contains(toLower(github.event.comment.body), 'i want to work on this')
+ if: |
+ github.event.issue.pull_request == null &&
+ (
+ contains(github.event.comment.body, 'assign this issue to me') ||
+ contains(github.event.comment.body, 'assign me') ||
+ contains(github.event.comment.body, 'can i work on this') ||
+ contains(github.event.comment.body, 'i would like to work on this') ||
+ contains(github.event.comment.body, 'i want to work on this')
)🧰 Tools
🪛 actionlint (1.7.10)
[error] 15-15: undefined function "toLower". available functions are "always", "cancelled", "contains", "endswith", "failure", "format", "fromjson", "hashfiles", "join", "startswith", "success", "tojson"
(expression)
[error] 16-16: undefined function "toLower". available functions are "always", "cancelled", "contains", "endswith", "failure", "format", "fromjson", "hashfiles", "join", "startswith", "success", "tojson"
(expression)
[error] 17-17: undefined function "toLower". available functions are "always", "cancelled", "contains", "endswith", "failure", "format", "fromjson", "hashfiles", "join", "startswith", "success", "tojson"
(expression)
[error] 18-18: undefined function "toLower". available functions are "always", "cancelled", "contains", "endswith", "failure", "format", "fromjson", "hashfiles", "join", "startswith", "success", "tojson"
(expression)
[error] 19-19: undefined function "toLower". available functions are "always", "cancelled", "contains", "endswith", "failure", "format", "fromjson", "hashfiles", "join", "startswith", "success", "tojson"
(expression)
🤖 Prompt for AI Agents
In @.github/workflows/issue-assignment.yml around lines 13 - 57, The job 'if'
condition uses unsupported toLower() calls around github.event.comment.body;
update the conditional to remove the toLower() wrappers and call contains()
directly on github.event.comment.body (e.g., replace
contains(toLower(github.event.comment.body), 'assign me') with
contains(github.event.comment.body, 'assign me')) so the expressions use the
built-in case-insensitive contains() correctly.
nemesifier
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Eeshu-Yadav look at the work we're doing here:
#562
The same recommendations I've been giving there apply here, we should make something consistent:
- reusable actions that we can enable in all repos
- automated tests to give us confidence when maintaining/changing/iterating
- documentation for usage
- enable this in a test repo where we can test it and link to it in the PR description
- use Python
Checklist
Created Workflows
1.
issue-assignment.ymlAuto-response to "assign me" requests
2.
pr-issue-link.ymlAuto-assign on PR
Fixes #123,Closes #123, etc.)3.
stale-pr-management.ymlStale PR management (tracks contributor inactivity only)
stalelabel, unassigns linked issues4.
pr-reopen-reassign.ymlHandle contributor follow-up
stalelabelFixes #571