Skip to content

Commit 17bd34d

Browse files
authored
feat: notify issues weekly (#1255)
1 parent e9ad896 commit 17bd34d

File tree

5 files changed

+10528
-7823
lines changed

5 files changed

+10528
-7823
lines changed

.github/scripts/issue-notification.js

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// import { Octokit } from "@octokit/rest";
2+
// import axios from "axios";
3+
(async () => {
4+
const { Octokit } = await import("@octokit/rest")
5+
const { default: axios } = await import('axios');
6+
7+
// Configuration
8+
const GITHUB_TOKEN = process.env.GITHUB_TOKEN;
9+
const SLACK_WEBHOOK_URL = process.env.SLACK_ISSUE_NOTIFY_WEBHOOK_URL;
10+
const MANAGER_SLACK_ID = process.env.DEVELOPER_MANAGER_SLACK_ID;
11+
const REPO_OWNER = "GreptimeTeam";
12+
const REPO_NAME = "docs";
13+
const GITHUB_TO_SLACK = JSON.parse(process.env.GITHUBID_SLACKID_MAPPING);
14+
15+
const octokit = new Octokit({
16+
auth: GITHUB_TOKEN
17+
});
18+
19+
// Function to fetch open issues from the GitHub repository
20+
async function fetchOpenIssues() {
21+
try {
22+
const issues = await octokit.issues.listForRepo({
23+
owner: REPO_OWNER,
24+
repo: REPO_NAME,
25+
state: "open", // Only fetch open issues
26+
per_page: 100 // Fetch 100 issues at a time
27+
});
28+
return issues.data;
29+
} catch (error) {
30+
console.error("Error fetching issues:", error);
31+
return [];
32+
}
33+
}
34+
35+
// Function to count issues per assignee
36+
function countIssuesByAssignee(issues) {
37+
const issueCountByAssignee = {};
38+
39+
issues.forEach(issue => {
40+
const assignees = issue.assignees;
41+
assignees.forEach(assignee => {
42+
const username = assignee.login;
43+
if (!issueCountByAssignee[username]) {
44+
issueCountByAssignee[username] = 0;
45+
}
46+
issueCountByAssignee[username] += 1;
47+
});
48+
});
49+
50+
const sortedIssueCounts = Object.entries(issueCountByAssignee).sort((a, b) => b[1] - a[1]);
51+
52+
const sortedIssueCountByAssignee = {};
53+
sortedIssueCounts.forEach(([username, count]) => {
54+
sortedIssueCountByAssignee[username] = count;
55+
});
56+
57+
return sortedIssueCountByAssignee;
58+
}
59+
60+
// Function to send a notification to Slack
61+
async function sendSlackNotification(issueCounts) {
62+
const messageLines = [`*🌼 Weekly GitHub Issue Report: 🌼* \n <@${MANAGER_SLACK_ID}>: Hey guys, let's close these issues together! 😉\n`];
63+
for (const [githubUser, count] of Object.entries(issueCounts)) {
64+
const slackUserId = GITHUB_TO_SLACK[githubUser];
65+
const slackMention = slackUserId ? `<@${slackUserId}>` : githubUser;
66+
67+
const issueLink = `https://github.com/${REPO_OWNER}/${REPO_NAME}/issues?q=is%3Aissue+is%3Aopen+assignee%3A${githubUser}`;
68+
const formattedLine = `${slackMention}: <${issueLink}|${count} open issues>`;
69+
70+
messageLines.push(formattedLine);
71+
}
72+
73+
const message = messageLines.join("\n");
74+
75+
try {
76+
const response = await axios.post(SLACK_WEBHOOK_URL, {
77+
text: message
78+
});
79+
80+
if (response.status !== 200) {
81+
throw new Error(`Error sending Slack notification: ${response.status}`);
82+
}
83+
console.log("Notification sent to Slack successfully.");
84+
} catch (error) {
85+
console.error("Error sending notification to Slack:", error);
86+
}
87+
}
88+
89+
async function run() {
90+
const issues = await fetchOpenIssues();
91+
const issueCounts = countIssuesByAssignee(issues);
92+
await sendSlackNotification(issueCounts);
93+
}
94+
95+
run();
96+
})()
97+

.github/workflows/issue-notifier.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
name: Weekly GitHub Issue Notifier
2+
3+
on:
4+
schedule:
5+
- cron: '0 2 * * 1' # Run every Monday at 2:00 AM UTC
6+
7+
jobs:
8+
notify:
9+
runs-on: ubuntu-latest
10+
11+
strategy:
12+
matrix:
13+
node-version: [18.x]
14+
15+
steps:
16+
- uses: actions/checkout@v4
17+
- name: Install pnpm
18+
uses: pnpm/action-setup@v4
19+
with:
20+
version: 8.6.0
21+
- name: Use Node.js ${{ matrix.node-version }}
22+
uses: actions/setup-node@v4
23+
with:
24+
node-version: ${{ matrix.node-version }}
25+
cache: 'pnpm'
26+
- run: pnpm install
27+
28+
- name: Run the notifier script
29+
env:
30+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # GitHub token for API access
31+
SLACK_ISSUE_NOTIFY_WEBHOOK_URL: ${{ vars.SLACK_ISSUE_NOTIFY_WEBHOOK_URL }} # Slack webhook URL
32+
DEVELOPER_MANAGER_SLACK_ID: ${{ vars.DEVELOPER_MANAGER_SLACK_ID }} # Slack ID of the manager
33+
GITHUBID_SLACKID_MAPPING: ${{ vars.GITHUBID_SLACKID_MAPPING }} # JSON string mapping GitHub to Slack usernames
34+
run: node .github/scripts/issue-notification.js
35+

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
.DS_Store
22
.docusaurus
33
node_modules
4-
build
4+
build
5+
.envrc

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
"@docusaurus/core": "3.4.0",
2020
"@docusaurus/preset-classic": "3.4.0",
2121
"@mdx-js/react": "^3.0.0",
22+
"@octokit/rest": "^21.0.2",
23+
"axios": "^1.7.7",
2224
"clsx": "^2.0.0",
2325
"prism-react-renderer": "^2.3.0",
2426
"react": "^18.0.0",

0 commit comments

Comments
 (0)