-
-
Notifications
You must be signed in to change notification settings - Fork 107
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add workflow for automated vote notification #1337
base: master
Are you sure you want to change the base?
Changes from all commits
7bf5ef3
4e0758f
3272948
f62b13a
4a7bfe1
e1b858f
fd1a32a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
name: Notify TSC Members about Voting Status | ||
|
||
on: | ||
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" | ||
# } | ||
# } | ||
- 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: 'vote 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: | | ||
cd .vote_state | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. where it comes from? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A branch stores the data between workflow runs https://github.com/ash17290/asyncapi-community/tree/vote_state There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok, please extend description then, for future generations :D |
||
|
||
if [ ! -f vote_status.json ]; then | ||
echo "{}" > vote_status.json | ||
fi | ||
|
||
export json=$(cat vote_status.json | jq -c) | ||
|
||
echo "::debug::vote_status=$json" | ||
|
||
# Store in GitHub Output | ||
echo "vote_status=$json" >> $GITHUB_OUTPUT | ||
|
||
- name: Install the dependencies | ||
run: npm install js-yaml@4.1.0 axios@1.7.4 | ||
shell: bash | ||
|
||
- name: Notify TSC Members | ||
# if: steps.list.outputs.result.length > 0 | ||
uses: actions/github-script@v7 | ||
id: notify | ||
with: | ||
script: | | ||
const yaml = require('js-yaml'); | ||
const fs = require('fs'); | ||
const axios = require('axios'); | ||
|
||
const issues = ${{ steps.list.outputs.result }}; | ||
const state = ${{ steps.fetch.outputs.vote_status }}; | ||
|
||
// Add new issues and close old ones | ||
const newIssues = issues.filter(issue => !state[issue.number]); | ||
const closedIssues = Object.keys(state).filter(issue => !issues.find(i => i.number === parseInt(issue))); | ||
|
||
// Update state | ||
for (const issue of newIssues) { | ||
state[issue.number] = { | ||
status: 'open', | ||
last_notified: null, | ||
} | ||
} | ||
|
||
for (const issue of closedIssues) { | ||
state[issue] = { | ||
...state[issue], | ||
status: 'closed', | ||
} | ||
} | ||
|
||
const issuesToNotify = issues.filter(issue => | ||
state[issue.number].status === 'open' && | ||
(!state[issue.number].last_notified || | ||
new Date(state[issue.number].last_notified) + 7 * 24 * 60 * 60 * 1000 < new Date() || true) | ||
); | ||
|
||
const tscMembers = yaml.load(fs.readFileSync('MAINTAINERS.yaml', 'utf8')); | ||
|
||
for (const issue of issuesToNotify) { | ||
const { data: comments } = await github.rest.issues.listComments({ | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
issue_number: issue.number, | ||
}); | ||
|
||
const voteOpeningComment = comments.findLast(comment => comment.body.includes('Vote created') && comment.user.login === 'git-vote[bot]'); | ||
|
||
if (!voteOpeningComment) { | ||
console.log(`Vote Opening Comment not found for issue #${issue.number}`); | ||
continue; | ||
} | ||
|
||
const { data: reactions } = await github.rest.reactions.listForIssueComment({ | ||
owner: context.repo.owner, | ||
repo: context.repo.repo, | ||
comment_id: voteOpeningComment.id, | ||
}); | ||
|
||
const validReactions = reactions.filter(reaction => reaction.content === '+1' || reaction.content === '-1'); | ||
|
||
const leftToVote = tscMembers.filter(member => !validReactions.find(reaction => reaction.user.login === member.github)); | ||
|
||
for (const member of leftToVote) { | ||
console.log(`Notifying ${member.name} about issue #${issue.number}`); | ||
|
||
const message = `👋 Hi ${member.name},\nWe need your vote on the following topic: *${issue.title}*.\n*Issue Details*: ${issue.html_url}\nYour input is crucial to our decision-making process. Please take a moment to review the voting topic and share your thoughts.\nThank you for your contribution! 🙏`; | ||
|
||
// Sending Slack DM via API | ||
const response = await axios.post('https://slack.com/api/chat.postMessage', { | ||
channel: member.slack, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you need to either set a proper error handling here, or just check it before calling API
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, give me some time I will do this as well. |
||
text: message, | ||
}, { | ||
headers: { | ||
'Authorization': `Bearer ${{ secrets.SLACK_TOKEN }}`, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we use existing one, no need to do anything here, right? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, regarding this I don't know which secret has access to post messages. Need There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah, there basically is no secret like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. tested with below
did you get it @Shurtu-gal ? |
||
'Content-Type': 'application/json', | ||
}, | ||
}); | ||
|
||
console.log(`Slack DM sent to ${member.name}`); | ||
} | ||
state[issue.number].last_notified = new Date().toISOString(); | ||
} | ||
|
||
return JSON.stringify(state); | ||
|
||
- name: Update State | ||
run: | | ||
echo ${{ steps.notify.outputs.result }} | jq > ./.vote_state/vote_status.json |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
node_modules | ||
.terraform | ||
*tfstate.backup | ||
*.tfvars | ||
*.tfvars | ||
.vote_state/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will it list PRs as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so does
gitvote
allow PR voting as well?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Facing a problem with PRs though, getting filtered results by
vote-open
label is not possible. Should I go ahead with manually filtering the whole list of PRs.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, you either do it "manually"
or use search API
I personally have bad experience with search and its accuracy, so I guess manual is better