Skip to content

Commit 101de6d

Browse files
Merge branch 'main' into test-streak-week-start
2 parents a900549 + 6a3d87e commit 101de6d

212 files changed

Lines changed: 33956 additions & 4743 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* text=auto eol=lf

.github/scripts/issue-management/claim-handler.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ async function handleClaim({ github, context }) {
3030

3131
const issueAuthor = context.payload.issue.user.login;
3232

33-
if (commenter.toLowerCase() !== issueAuthor.toLowerCase()) {
33+
const MAINTAINERS = ['jhasourav07', 'aamod007', 'souravjhahind'];
34+
const isOpenedByMaintainer = MAINTAINERS.includes(issueAuthor.toLowerCase());
35+
36+
if (!isOpenedByMaintainer && commenter.toLowerCase() !== issueAuthor.toLowerCase()) {
3437
await github.rest.issues.createComment({
3538
owner,
3639
repo,
@@ -71,7 +74,7 @@ async function handleClaim({ github, context }) {
7174
owner,
7275
repo,
7376
issue_number: issueNumber,
74-
body: `❌ You already have **${existingIssues.length}/${MAX_ASSIGNED_ISSUES}** active assigned issues (the maximum allowed).\nPlease complete or unassign one of your current issues before claiming another.\n\n${issueList}`,
77+
body: `❌ You already have **${existingIssues.length}/${MAX_ASSIGNED_ISSUES}** active assigned issues (the maximum allowed).\nPlease complete or \`/unclaim\` one of your current issues before claiming another.\n\n${issueList}`,
7578
});
7679
return;
7780
}
@@ -87,7 +90,7 @@ async function handleClaim({ github, context }) {
8790
owner,
8891
repo,
8992
issue_number: issueNumber,
90-
body: `✅ Successfully assigned issue to @${commenter}\n\n> 💡 Please read [CONTRIBUTING.md](../blob/main/CONTRIBUTING.md) if you haven't already. Good luck! 🚀`,
93+
body: `🎉 **Assigned!** Welcome to the project, @${commenter}.\n\n⏳ **Reminder:** You have **2 days** to submit a Pull Request. After 2 days of inactivity, you will be automatically unassigned to give others a chance (as per our GSSoC anti-hoarding policy).\n\n> 💡 Please read [CONTRIBUTING.md](../blob/main/CONTRIBUTING.md) if you haven't already.\n\nHappy coding! 🚀`,
9194
});
9295
}
9396

.github/scripts/issue-management/main.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const { handleAssign } = require('./assign-handler');
44
const { handleUnassign } = require('./unassign-handler');
55
const { handleAddLabel } = require('./addlabel-handler');
66
const { handleClaim } = require('./claim-handler');
7+
const { handleUnclaim } = require('./unclaim-handler');
78

89
module.exports = async ({ github, context, core }) => {
910
const commentBody = context.payload.comment?.body;
@@ -48,6 +49,9 @@ module.exports = async ({ github, context, core }) => {
4849
case 'claim':
4950
await handleClaim({ github, context });
5051
break;
52+
case 'unclaim':
53+
await handleUnclaim({ github, context });
54+
break;
5155
case 'ping':
5256
await github.rest.issues.createComment({
5357
owner,

.github/scripts/issue-management/parse-command.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ function parseCommand(commentBody) {
1515
const claimMatch = line.match(/^\/claim\s*$/i);
1616
if (claimMatch) return { command: 'claim' };
1717

18+
const unclaimMatch = line.match(/^\/unclaim\s*$/i);
19+
if (unclaimMatch) return { command: 'unclaim' };
20+
1821
const pingMatch = line.match(/^\/ping\s*$/i);
1922
if (pingMatch) return { command: 'ping' };
2023

.github/scripts/issue-management/stale-assignment.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
async function handleStaleAssignments({ github, context, core }) {
22
const { owner, repo } = context.repo;
3-
const THREE_DAYS_MS = 3 * 24 * 60 * 60 * 1000;
3+
const TWO_DAYS_MS = 2 * 24 * 60 * 60 * 1000;
44
const now = new Date();
55

66
console.log(`Starting stale assignment check for ${owner}/${repo}`);
@@ -27,7 +27,7 @@ async function handleStaleAssignments({ github, context, core }) {
2727
const updatedAt = new Date(issue.updated_at);
2828
const timeSinceUpdate = now.getTime() - updatedAt.getTime();
2929

30-
if (timeSinceUpdate > THREE_DAYS_MS) {
30+
if (timeSinceUpdate > TWO_DAYS_MS) {
3131
console.log(
3232
`Issue #${issue.number} has been inactive since ${issue.updated_at}. Removing assignees.`
3333
);
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
async function handleUnclaim({ github, context }) {
2+
const { owner, repo } = context.repo;
3+
const issueNumber = context.payload.issue.number;
4+
const commenter = context.payload.comment.user.login;
5+
const issueState = context.payload.issue.state;
6+
7+
if (issueState === 'closed') {
8+
await github.rest.issues.createComment({
9+
owner,
10+
repo,
11+
issue_number: issueNumber,
12+
body: `❌ Commands cannot be used on closed issues.`,
13+
});
14+
return;
15+
}
16+
17+
const currentAssignees = context.payload.issue.assignees.map((a) => a.login.toLowerCase());
18+
19+
if (!currentAssignees.includes(commenter.toLowerCase())) {
20+
await github.rest.issues.createComment({
21+
owner,
22+
repo,
23+
issue_number: issueNumber,
24+
body: `ℹ️ @${commenter}, you are not currently assigned to this issue, so there's nothing to unclaim.`,
25+
});
26+
return;
27+
}
28+
29+
await github.rest.issues.removeAssignees({
30+
owner,
31+
repo,
32+
issue_number: issueNumber,
33+
assignees: [commenter],
34+
});
35+
36+
await github.rest.issues.createComment({
37+
owner,
38+
repo,
39+
issue_number: issueNumber,
40+
body: `✅ Successfully unclaimed this issue for @${commenter}.\n\n> 🔓 The issue is now open for others to claim.`,
41+
});
42+
}
43+
44+
module.exports = { handleUnclaim };
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
name: Assign Request Reminder
2+
3+
on:
4+
issue_comment:
5+
types: [created]
6+
7+
concurrency:
8+
group: assign-reminder-${{ github.event.issue.number }}-${{ github.event.comment.id }}
9+
cancel-in-progress: false
10+
11+
permissions:
12+
issues: write
13+
contents: read
14+
15+
jobs:
16+
remind-claim:
17+
name: Remind About /claim Command
18+
runs-on: ubuntu-latest
19+
if: >-
20+
!github.event.issue.pull_request &&
21+
github.event.comment.user.type != 'Bot' &&
22+
!contains(github.event.comment.body, '/claim') &&
23+
!contains(github.event.comment.body, '/assign') &&
24+
!contains(github.event.comment.body, '/unassign') &&
25+
!contains(github.event.comment.body, '/addlabel') &&
26+
!contains(github.event.comment.body, '/ping') &&
27+
(
28+
contains(github.event.comment.body, 'assign this issue to me') ||
29+
contains(github.event.comment.body, 'assign this to me') ||
30+
contains(github.event.comment.body, 'please assign me') ||
31+
contains(github.event.comment.body, 'can i work on this') ||
32+
contains(github.event.comment.body, 'can i take this') ||
33+
contains(github.event.comment.body, 'i would like to work on this') ||
34+
contains(github.event.comment.body, 'i want to work on this') ||
35+
contains(github.event.comment.body, 'i''d like to work on this') ||
36+
contains(github.event.comment.body, 'id like to work on this') ||
37+
contains(github.event.comment.body, 'i want to take this issue') ||
38+
contains(github.event.comment.body, 'i want to fix this') ||
39+
contains(github.event.comment.body, 'i want to contribute') ||
40+
contains(github.event.comment.body, 'let me work on this') ||
41+
contains(github.event.comment.body, 'let me take this') ||
42+
contains(github.event.comment.body, 'can i be assigned') ||
43+
contains(github.event.comment.body, 'assign me to this') ||
44+
contains(github.event.comment.body, 'assign me this') ||
45+
contains(github.event.comment.body, 'work on this') ||
46+
contains(github.event.comment.body, 'i''ll work on this') ||
47+
contains(github.event.comment.body, 'ill work on this') ||
48+
contains(github.event.comment.body, 'i can work on this') ||
49+
contains(github.event.comment.body, 'i am interested in this') ||
50+
contains(github.event.comment.body, 'assign') ||
51+
contains(github.event.comment.body, 'i''m interested in this')
52+
)
53+
54+
steps:
55+
- name: Post /claim Reminder
56+
uses: actions/github-script@v7
57+
with:
58+
github-token: ${{ secrets.GITHUB_TOKEN }}
59+
script: |
60+
const commenter = context.payload.comment.user.login;
61+
const issueAuthor = context.payload.issue.user.login;
62+
const { owner, repo } = context.repo;
63+
const issueNumber = context.payload.issue.number;
64+
65+
// Check if the issue is closed — no point reminding on closed issues.
66+
if (context.payload.issue.state === 'closed') return;
67+
68+
// Check if commenter is already assigned — no point reminding them.
69+
const assignees = context.payload.issue.assignees.map(a => a.login.toLowerCase());
70+
if (assignees.includes(commenter.toLowerCase())) return;
71+
72+
const isOpenForAnyone = issueAuthor.toLowerCase() === 'jhasourav07';
73+
const isAuthor = commenter.toLowerCase() === issueAuthor.toLowerCase();
74+
75+
let claimEligibilityNote = '';
76+
if (!isOpenForAnyone && !isAuthor) {
77+
claimEligibilityNote = `\n> ⚠️ **Note:** Only the issue author (@${issueAuthor}) can \`/claim\` this issue. If you'd like to contribute, consider opening a new issue for a bug or feature you've found, then claim that one!`;
78+
}
79+
80+
const bodyLines = [
81+
`👋 Hey @${commenter}! Looks like you want to work on this issue — awesome! 🎉`,
82+
``,
83+
`We don't assign issues through comments like this. Here's how our system works:`,
84+
``,
85+
`## 🤖 How to Claim an Issue`,
86+
``,
87+
`Comment \`/claim\` on this issue and our bot will automatically assign it to you (if you're eligible).`,
88+
``,
89+
`\`\`\``,
90+
`/claim`,
91+
`\`\`\``,
92+
claimEligibilityNote,
93+
``,
94+
`## 📋 A Few Things to Know`,
95+
``,
96+
`- You can hold a **maximum of 3 open issues** at a time.`,
97+
`- If there's **no activity for 3 days**, the assignment will automatically expire so others can pick it up.`,
98+
`- Make sure to read our **[CONTRIBUTING.md](https://github.com/${owner}/${repo}/blob/main/CONTRIBUTING.md)** before you start — it covers code style, commit conventions, and the PR checklist.`,
99+
``,
100+
`## 💬 Join Our Discord`,
101+
``,
102+
`Get faster help, collaborate with other contributors, and stay updated with project news:`,
103+
``,
104+
`[![Join CommitPulse Discord](https://img.shields.io/badge/Join-CommitPulse%20Discord-5865F2?style=flat-square&logo=discord&logoColor=white)](https://discord.gg/Cb73bS79j)`,
105+
``,
106+
`Happy contributing! 🚀`,
107+
];
108+
await github.rest.issues.createComment({
109+
owner,
110+
repo,
111+
issue_number: issueNumber,
112+
body: bodyLines.join('\n'),
113+
});

.github/workflows/conflict-notifier.yml

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,12 @@ name: Merge Conflict Notifier
22

33
on:
44
schedule:
5-
- cron: '0 * * * *'
5+
- cron: '*/30 * * * *' # Hourly/half-hourly fallback
6+
push:
7+
branches:
8+
- main
9+
pull_request_target:
10+
types: [synchronize, reopened, edited]
611
workflow_dispatch:
712

813
permissions:
@@ -76,20 +81,33 @@ jobs:
7681
});
7782
}
7883
79-
// Check if we've already posted a conflict comment to avoid spam
84+
// Check existing comments to enforce a 2-hour notification gap
8085
const { data: comments } = await github.rest.issues.listComments({
8186
owner: context.repo.owner,
8287
repo: context.repo.repo,
8388
issue_number: pr.number,
8489
per_page: 100,
8590
});
8691
87-
const alreadyCommented = comments.some(c =>
92+
const conflictComments = comments.filter(c =>
8893
c.user?.login === 'github-actions[bot]' &&
8994
c.body?.includes('merge conflicts with the main branch')
9095
);
9196
92-
if (!alreadyCommented) {
97+
let shouldComment = false;
98+
if (conflictComments.length === 0) {
99+
shouldComment = true;
100+
} else {
101+
const lastComment = conflictComments[conflictComments.length - 1];
102+
const lastCommentTime = new Date(lastComment.created_at).getTime();
103+
const nowTime = new Date().getTime();
104+
const TWO_HOURS_MS = 2 * 60 * 60 * 1000;
105+
if (nowTime - lastCommentTime >= TWO_HOURS_MS) {
106+
shouldComment = true;
107+
}
108+
}
109+
110+
if (shouldComment) {
93111
await github.rest.issues.createComment({
94112
owner: context.repo.owner,
95113
repo: context.repo.repo,

.github/workflows/issue-management.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ jobs:
2222
contains(github.event.comment.body, '/assign') ||
2323
contains(github.event.comment.body, '/unassign') ||
2424
contains(github.event.comment.body, '/addlabel') ||
25-
contains(github.event.comment.body, '/claim')
25+
contains(github.event.comment.body, '/claim') ||
26+
contains(github.event.comment.body, '/unclaim')
2627
)
2728
steps:
2829
- name: Checkout Repository

0 commit comments

Comments
 (0)