Skip to content

Commit a03d74f

Browse files
Merge branch 'main' into test/radarchart-ui-1529
2 parents cdd5fe5 + 2e604a1 commit a03d74f

321 files changed

Lines changed: 39868 additions & 3547 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.

.env.local.example

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@
2020
# Generate new token (classic)
2121
# Required scope: read:user
2222
# ------------------------------------------------------------
23-
GITHUB_TOKEN=ghp_your_personal_access_token_here
24-
23+
GITHUB_TOKEN=
2524

2625
# ------------------------------------------------------------
2726
# REQUIRED — Public site URL
@@ -48,3 +47,19 @@ NEXT_PUBLIC_SITE_URL=http://localhost:3000
4847
# 4. Replace <password> with your DB user's password
4948
# ------------------------------------------------------------
5049
# MONGODB_URI=mongodb+srv://<username>:<password>@cluster.mongodb.net/commitpulse?retryWrites=true&w=majority
50+
51+
# ------------------------------------------------------------
52+
# OPTIONAL — Upstash Redis / Vercel KV (Distributed Rate Limiting)
53+
# ------------------------------------------------------------
54+
# Enables distributed rate limiting across all serverless instances.
55+
# Without these, rate limiting is per-instance (each Vercel function
56+
# gets its own counter), which allows N× the intended limit under load.
57+
#
58+
# How to get one (free):
59+
# 1. Create a free Upstash Redis database at https://console.upstash.com
60+
# 2. Copy the REST API URL and token
61+
# 3. If using Vercel KV, link it to your project in the Vercel dashboard
62+
# — it sets KV_REST_API_URL and KV_REST_API_TOKEN automatically.
63+
# ------------------------------------------------------------
64+
# KV_REST_API_URL=https://<your-db>.upstash.io
65+
# KV_REST_API_TOKEN=<your-token>

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ async function findExistingAssignments(github, owner, repo, username, currentIss
1010
return issues.filter((issue) => !issue.pull_request && issue.number !== currentIssueNumber);
1111
}
1212

13-
const MAX_ASSIGNED_ISSUES = 3;
13+
const MAX_ASSIGNED_ISSUES = 5;
1414

1515
async function handleAssign({ github, context, username, hasWriteAccess }) {
1616
const { owner, repo } = context.repo;

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ async function findExistingAssignments(github, owner, repo, username, currentIss
1010
return issues.filter((issue) => !issue.pull_request && issue.number !== currentIssueNumber);
1111
}
1212

13-
const MAX_ASSIGNED_ISSUES = 3;
13+
const MAX_ASSIGNED_ISSUES = 5;
1414

1515
async function handleClaim({ github, context }) {
1616
const { owner, repo } = context.repo;
@@ -74,7 +74,7 @@ async function handleClaim({ github, context }) {
7474
owner,
7575
repo,
7676
issue_number: issueNumber,
77-
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}`,
7878
});
7979
return;
8080
}

.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

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 };

.github/workflows/assign-request-reminder.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ jobs:
9393
``,
9494
`## 📋 A Few Things to Know`,
9595
``,
96-
`- You can hold a **maximum of 3 open issues** at a time.`,
96+
`- You can hold a **maximum of 5 open issues** at a time.`,
9797
`- If there's **no activity for 3 days**, the assignment will automatically expire so others can pick it up.`,
9898
`- 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.`,
9999
``,

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ on:
55
branches: [main, dev]
66
pull_request:
77
branches: [main, dev]
8+
merge_group: # Run CI on the merged commit before it lands on main
89

910
jobs:
1011
quality:

.github/workflows/conflict-notifier.yml

Lines changed: 2 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77
branches:
88
- main
99
pull_request_target:
10-
types: [opened, synchronize, reopened, edited]
10+
types: [synchronize, reopened, edited]
1111
workflow_dispatch:
1212

1313
permissions:
@@ -79,35 +79,8 @@ jobs:
7979
issue_number: pr.number,
8080
labels: [label],
8181
});
82-
}
83-
84-
// Check existing comments to enforce a 2-hour notification gap
85-
const { data: comments } = await github.rest.issues.listComments({
86-
owner: context.repo.owner,
87-
repo: context.repo.repo,
88-
issue_number: pr.number,
89-
per_page: 100,
90-
});
91-
92-
const conflictComments = comments.filter(c =>
93-
c.user?.login === 'github-actions[bot]' &&
94-
c.body?.includes('merge conflicts with the main branch')
95-
);
96-
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-
}
10982
110-
if (shouldComment) {
83+
// Post notification comment ONLY ONCE (when the label is first applied)
11184
await github.rest.issues.createComment({
11285
owner: context.repo.owner,
11386
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)