Skip to content

Commit a191156

Browse files
authored
Merge pull request #124 from microsoft/aochengwang/alert
chore: notify issue assignees
2 parents 114bf42 + dc3475f commit a191156

File tree

3 files changed

+125
-0
lines changed

3 files changed

+125
-0
lines changed

.github/scripts/notify-issues.js

+86
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
const process = require("process");
2+
const cp = require("child_process");
3+
4+
const Labels = {
5+
needsAttention: "needs attention",
6+
};
7+
8+
const workflowMaintainer = process.env.WORKFLOW_MAINTAINER_EMAIL;
9+
const repoMaintainers = JSON.parse(process.env.REPO_MAINTAINERS);
10+
const repoMaintainersMap = new Map(
11+
repoMaintainers.maintainers.map((m) => [m.github, m.alias])
12+
);
13+
14+
async function sendEmail(to, subject, body) {
15+
return cp.execSync(".github/scripts/send-email.sh", {
16+
env: {
17+
...process.env,
18+
SUBJECT: subject,
19+
TO: to,
20+
BODY: JSON.stringify(body),
21+
},
22+
});
23+
}
24+
25+
async function main() {
26+
const repo = "microsoft/vscode-ai-toolkit";
27+
const output = cp.execSync(
28+
`gh issue list --repo ${repo} --state open --json number,title,assignees,labels,url`,
29+
{ encoding: "utf-8" }
30+
);
31+
const issues = JSON.parse(output);
32+
33+
let unknownAssignees = new Set();
34+
// alias => issue[]
35+
const userMapping = new Map();
36+
for (const issue of issues) {
37+
const needsAttention = !!issue?.labels?.find((label) => label?.name === Labels.needsAttention);
38+
if (needsAttention && issue?.assignees?.length && issue.assignees.length > 0) {
39+
const emails = issue.assignees.map((assignee) => {
40+
const alias = repoMaintainersMap.get(assignee.login);
41+
if (!alias) {
42+
unknownAssignees.add(assignee.login);
43+
return undefined;
44+
} else {
45+
return `${alias}@microsoft.com`;
46+
}
47+
}).filter((email) => !!email);
48+
49+
for (const email of emails) {
50+
if (!userMapping.has(email)) {
51+
userMapping.set(email, []);
52+
}
53+
userMapping.set(email, [...userMapping.get(email), issue]);
54+
}
55+
}
56+
}
57+
58+
// Send email once for each assigned user
59+
for (const [email, issues] of userMapping.entries()) {
60+
console.log(`Sending email to ${email} for issue ${JSON.stringify(issues)}`);
61+
const body = `
62+
<p>Hi, here are GitHub issues that needs your attention:</p>
63+
${issues.map((issue) =>`<p><a href="${issue.url}">#${issue.number}</a>: ${issue.title} (${issue.url})</p>`)}
64+
`;
65+
await sendEmail(
66+
email,
67+
`[Needs attention] AI Toolkit GitHub issue report`,
68+
body,
69+
);
70+
}
71+
72+
if (unknownAssignees.size > 0) {
73+
await sendEmail(
74+
workflowMaintainer,
75+
`There are unknown assignees in ${repo}`,
76+
`There are unknown assignees in the issues: ${Array.from(
77+
unknownAssignees
78+
).join(
79+
", "
80+
)}, please update <a href="https://github.com/microsoft/vscode-ai-toolkit/blob/main/.github/data/maintainers.json">maintainers.json</a>. `
81+
);
82+
}
83+
}
84+
85+
86+
main()

.github/scripts/send-email.sh

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/bin/bash
2+
set -xue
3+
4+
response=$(curl \
5+
--request POST \
6+
--header "Content-Type: application/x-www-form-urlencoded" \
7+
--data "grant_type=client_credentials&client_id=${MAIL_CLIENT_ID}&client_secret=${MAIL_CLIENT_SECRET}&resource=https://management.core.windows.net" \
8+
"https://login.microsoftonline.com/${MAIL_TENANT_ID}/oauth2/token")
9+
10+
access_token=`echo $response | jq -r '. | select(.access_token) | .access_token'`
11+
12+
curl \
13+
--request POST \
14+
--header "Content-Type: application/json" \
15+
--header "Authorization: Bearer $access_token" \
16+
--data "{\"to\": \"${TO}\", \"body\": ${BODY}, \"subject\": \"${SUBJECT}\"}" \
17+
'https://prod-18.northcentralus.logic.azure.com:443/workflows/b33d7861bfc64832a6f62cc8f2213988/triggers/manual/paths/invoke?api-version=2016-10-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0'
+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
on:
2+
workflow_dispatch:
3+
schedule:
4+
# 07:42 Shanghai time zone, every day
5+
- cron: "42 23 * * *"
6+
jobs:
7+
main:
8+
runs-on: ubuntu-latest
9+
permissions:
10+
issues: read
11+
steps:
12+
- name: Checkout
13+
uses: actions/checkout@v3
14+
15+
- name: Check issues that needs attention
16+
run: node .github/scripts/notify-issues.js
17+
env:
18+
REPO_MAINTAINERS: ${{ env.REPO_MAINTAINERS }}
19+
WORKFLOW_MAINTAINER_EMAIL: ${{ env.SCHEDULED_NOTIFICATION_MAINTAINER_EMAIL }}
20+
MAIL_CLIENT_ID: ${{ secrets.EMAIL_CLIENT_ID }}
21+
MAIL_CLIENT_SECRET: ${{ secrets.EMAIL_CLIENT_SECRET }}
22+
MAIL_TENANT_ID: ${{ secrets.EMAIL_TENANT_ID }}

0 commit comments

Comments
 (0)