-
-
Notifications
You must be signed in to change notification settings - Fork 179
171 lines (145 loc) · 6.67 KB
/
Copy pathvote-notify.yml
File metadata and controls
171 lines (145 loc) · 6.67 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
name: Notify TSC Members about Voting Status
on:
workflow_dispatch:
inputs:
notification_method:
description: 'Which channel(s) to notify on manual dispatch'
required: true
default: 'both'
type: choice
options:
- email
- slack
- both
schedule:
# Daily at 9:00 UTC
- cron: '0 9 * * *'
jobs:
notify-tsc-members:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# To store the state of the votes and the last time the TSC members were notified
# The format of the file is:
# {
# "issue_number": {
# "status": "open" | "closed",
# "last_notified": "2021-09-01T00:00:00Z"
# }
# }
# Example: https://github.com/ash17290/asyncapi-community/blob/vote_state/vote_status.json
- uses: jorgebg/stateful-action@bd279992190b64c6a5906c3b75a6f2835823ab46
id: state
with:
branch: vote_state
# List all the open issues with the label "vote open"
- name: List current open issues
uses: actions/github-script@v7
id: list
with:
script: |
const { data: issues } = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
labels: 'gitvote/open'
});
return issues;
github-token: ${{ secrets.GITHUB_TOKEN }}
# Fetch the current state from the vote_status.json file
- name: Fetch Current State
id: fetch
run: |
# This file comes from the branch vote_state which is created by the stateful-action
# Eg: https://github.com/ash17290/asyncapi-community/tree/vote_state
cd .vote_state
# Check if the file exists, not empty and readable and create if not
if [ ! -f vote_status.json ] || [ ! -s vote_status.json ] || [ ! -r vote_status.json ]; then
echo "Initializing vote_status.json"
echo "{}" > vote_status.json
fi
# Read the file and export it as JSON
export json=$(cat vote_status.json | jq -c)
echo "::debug::vote_status=$json"
# Store in GitHub Output
echo "vote_status=$json" >> $GITHUB_OUTPUT
# Needed as axios and js-yaml are not available in the default environment
- name: Install the dependencies
run: npm install js-yaml@4.1.0 axios@1.7.4 node-mailjet@6.0.9
shell: bash
- name: Notify TSC Members
uses: actions/github-script@v7
id: notify
env:
MAILJET_API_KEY: ${{ secrets.MAILJET_PUBLIC_KEY}}
MAILJET_API_SECRET: ${{ secrets.MAILJET_PRIVATE_KEY }}
# default to 'both' if inputs.notification_method is undefined (schedule runs)
NOTIFY_METHOD: ${{ github.event.inputs.notification_method || 'both' }}
SLACK_DM: ${{ secrets.SLACK_DM_TSC }}
with:
script: |
const yaml = require('js-yaml');
const fs = require('fs');
const {
filterIssues,
getTSCLeftToVote,
sendSlackNotification,
sendMailNotification
} = require('./.github/workflows/vote-notify-helpers/index.js');
const { sendMail } = require('./.github/workflows/mailing/index.js');
// Creates list of issues for which the TSC members need to be notified
// The number of buffer days is easily configurable by changing the value of the days variable
const issues = ${{ steps.list.outputs.result }};
const initialState = ${{ steps.fetch.outputs.vote_status }};
// On manual dispatch, override to 0; on schedule keep 5
// If workflow_dispatch is used (manual workflow trigger) then we want to set 0 to force notification sending, even if it was just sent or the other day
const daysBuffer = context.eventName === 'workflow_dispatch' ? 0 : 5;
const config = { days: daysBuffer };
const { issuesToNotify, state } = filterIssues(issues, initialState, config);
// Read TSC members from MAINTAINERS.yaml
const tscMembers = yaml.load(fs.readFileSync('MAINTAINERS.yaml', 'utf8')).filter(member => member.isTscMember);
const failingSlackIds = new Set();
const failingEmails = new Set();
const method = process.env.NOTIFY_METHOD; // 'email' | 'slack' | 'both'
console.log(`Notification method: ${method}`);
console.log(`Issues to notify: ${JSON.stringify(issuesToNotify.map(issue => issue.number))}`);
for (const issue of issuesToNotify) {
const { leftToVote, daysSinceStart, voteCommentURL } = await getTSCLeftToVote(issue, tscMembers, github, context);
for (const member of leftToVote) {
console.log(`Notifying ${member.name} about issue #${issue.number}`);
// Only send Slack if requested
if (method === 'slack' || method === 'both') {
if (!await sendSlackNotification(member, issue, daysSinceStart, process.env.SLACK_DM, voteCommentURL)) {
failingSlackIds.add(member.slack);
}
}
// Only send Email if requested
if (method === 'email' || method === 'both') {
if (!await sendMailNotification(member, issue, daysSinceStart, process.env.SLACK_DM, sendMail, voteCommentURL)) {
failingEmails.add(member.email);
}
}
}
// Update last_notified timestamp
state[issue.number].last_notified = new Date().toISOString();
}
// Store the failing IDs in GITHUB_ENV
const failingIds = [...failingSlackIds, ...failingEmails];
if (failingIds.length > 0) {
process.env.FAILED_IDS = failingIds.join(',');
core.exportVariable('FAILED_IDS', JSON.stringify(failingIds));
}
// Store the state back
return JSON.stringify(state);
- name: Update State
if: ${{ steps.notify.outputs.result }}
run: |
echo ${{ steps.notify.outputs.result }} | jq > ./.vote_state/vote_status.json
# Always alert on any failures, regardless of method
- name: Notify about failing Slack DMs
if: ${{ env.FAILED_IDS }}
uses: rtCamp/action-slack-notify@v2
env:
SLACK_WEBHOOK: ${{ secrets.SLACK_CI_FAIL_NOTIFY }}
SLACK_TITLE: 🚨 Vote notifications couldn’t be sent 🚨
SLACK_MESSAGE: ${{ env.FAILED_IDS }}
MSG_MINIMAL: true