diff --git a/.github/workflows/vote-notify.yml b/.github/workflows/vote-notify.yml new file mode 100644 index 000000000..f1c30d186 --- /dev/null +++ b/.github/workflows/vote-notify.yml @@ -0,0 +1,156 @@ +name: Notify TSC Members about Voting Status + +on: + schedule: + # Daily at 9:00 UTC + - cron: '0 9 * * *' + + push: + branches: + - master + +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 + + 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 issues) { + 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},\nYour vote is required on the following issue: *#${issue.number}*.\n*Issue Details*: <${issue.html_url}>\nYour input is crucial to our decision-making process. Please take a moment to review the issue 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, + text: message, + }, { + headers: { + 'Authorization': `Bearer ${{ secrets.SLACK_TOKEN }}`, + '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 \ No newline at end of file diff --git a/.gitignore b/.gitignore index b0f0a309f..443b46d59 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ node_modules .terraform *tfstate.backup -*.tfvars \ No newline at end of file +*.tfvars +.vote_state/ \ No newline at end of file diff --git a/.gitvote.yml b/.gitvote.yml index c1dffc24b..8f4b87b1c 100644 --- a/.gitvote.yml +++ b/.gitvote.yml @@ -3,7 +3,4 @@ profiles: duration: 4w pass_threshold: 51 periodic_status_check: "1 week" - close_on_passing: true - allowed_voters: - teams: - - tsc_members \ No newline at end of file + close_on_passing: true \ No newline at end of file diff --git a/MAINTAINERS.yaml b/MAINTAINERS.yaml index 29ad9ddb3..b06a42e06 100644 --- a/MAINTAINERS.yaml +++ b/MAINTAINERS.yaml @@ -1,523 +1,9 @@ -- name: Aishat Muibudeen - github: Mayaleeeee - linkedin: aishatmuibudeen - slack: U03CNHGEUR1 - twitter: maya_ux_ui - availableForHire: true - isTscMember: true - repos: - - website -- name: Aayush Sahu - github: aayushmau5 - linkedin: aayushmau5 - slack: U01QRHR1ABH - twitter: aayushmau5 - availableForHire: false - isTscMember: true - repos: - - diff -- name: Abir Pal - linkedin: imabp - slack: U01S8EQ9LQ2 - twitter: imabptweets - github: imabp - availableForHire: false - isTscMember: true - repos: - - problem -- name: Akshat Nema - github: akshatnema - linkedin: akshat-nema - slack: U02TAMG2VKN - twitter: AksNema - availableForHire: true - isTscMember: true - repos: - - website -- name: Ansh Goyal - github: anshgoyalevil - linkedin: thisisanshg - slack: U057J527M24 - twitter: thisisanshg - availableForHire: true - isTscMember: true - repos: - - website -- name: Anand Sunderraman - github: anandsunderraman - linkedin: anand-sunderraman-a6b7a131 - slack: U0231F9KXNK - availableForHire: false - isTscMember: true - repos: - - go-watermill-template - name: Ashish Padhy github: Shurtu-gal linkedin: ashish-padhy3023 - slack: U0572R8J927 + slack: U06QWQKA51P twitter: Shurtu_Gal availableForHire: true isTscMember: true repos: - - github-action-for-cli -- name: Cameron Rushton - github: CameronRushton - slack: U01DVKKAV5K - availableForHire: false - company: Solace - isTscMember: true - repos: - - java-spring-cloud-stream-template - - python-paho-template - - bindings -- name: Dale Lane - github: dalelane - linkedin: dalelane - slack: U01EYAFR5BR - twitter: dalelane - availableForHire: false - isTscMember: true - company: IBM - repos: - - avro-schema-parser - - bindings - - java-template -- name: Emiliano Zublena - github: emilianozublena - linkedin: emilianozublena - slack: U01LYC8PW0M - availableForHire: false - isTscMember: false - repos: - - asyncapi-php-template -- name: Fran Méndez - github: fmvilas - slack: U34F2JRRS - availableForHire: false - linkedin: fmvilas - isTscMember: true - repos: - - raml-dt-schema-parser - - avro-schema-parser - - openapi-schema-parser - - asyncapi-react - - glee - - nodejs-ws-template - - parser-js - - spec - - spec-json-schemas - - bindings -- name: Gerald Loeffler - github: GeraldLoeffler - linkedin: geraldloeffler - slack: U01P5QDLP0X - availableForHire: false - isTscMember: false - repos: - - bindings -- name: Jonas Lagoni - github: jonaslagoni - linkedin: jonaslagoni - slack: UQ2ANBG1E - availableForHire: false - company: Postman - isTscMember: true - repos: - - dotnet-nats-template - - ts-nats-template - - generator-react-sdk - - generator - - modelina - - parser-js - - parser-api - - simulator -- name: Khuda Dad Nomani - github: KhudaDad414 - twitter: KhudaDadNomani - linkedin: khudadadnomani - slack: U01RVRD1TCL - availableForHire: false - company: Postman - isTscMember: true - repos: - - bindings - - glee - - .github - - optimizer -- name: Laurent Broudoux - github: lbroudoux - twitter: lbroudoux - linkedin: laurentbroudoux - slack: U018NLDV5E1 - availableForHire: false - company: Postman - isTscMember: true - repos: - - bindings -- name: Ludovic Dussart - github: M3lkior - linkedin: ludovic-dussart-846a8063 - slack: U01BM49KL3Z - twitter: ldussart - availableForHire: false - company: zatsit - isTscMember: true - repos: - - avro-schema-parser -- name: Lukasz Gornicki - github: derberg - linkedin: lukasz-gornicki-a621914 - slack: UD698Q5LM - twitter: derberq - availableForHire: false - company: Postman - isTscMember: true - repos: - - diff - - generator-filters - - generator-hooks - - github-action-for-generator - - generator - - nodejs-template - - nodejs-ws-template - - spec - - spec-json-schemas - - template-for-generator-templates - - website -- name: Maciej Urbańczyk - github: magicmatatjahu - availableForHire: false - linkedin: maciej-urbańczyk-909547164 - slack: U01EB02BP7A - company: Travelping GmbH - isTscMember: true - repos: - - asyncapi-react - - converter-go - - generator-react-sdk - - generator - - html-template - - markdown-template - - modelina - - parser-js - - parser-go - - server-api - - template-for-go-projects - - website -- name: Azeez Elegbede - linkedin: acebuild - github: AceTheCreator - twitter: _acebuild - slack: U01RWDD69PZ - company: Postman - availableForHire: false - isTscMember: true - repos: - - chatbot -- name: Michael Davis - github: damaru-inc - availableForHire: false - slack: UH3B166TD - isTscMember: false - repos: - - java-spring-cloud-stream-template - - python-paho-template - - bindings -- name: Missy Turco - github: mcturco - twitter: missyturco - slack: U02JVEQ6S9W - linkedin: missy-turco-a476a6126 - availableForHire: false - company: Postman - isTscMember: false - repos: - - brand -- name: Nektarios Fifes - github: NektariosFifes - linkedin: nektarios-fifes-372740220 - slack: U01SE93Q48N - availableForHire: true - isTscMember: true - repos: - - simulator -- name: Pavel Bodiachevskii - github: Pakisan - slack: U0132LQU8C9 - twitter: pbodiachevskii - availableForHire: false - isTscMember: true - repos: - - jasyncapi -- name: Philip Schlesinger - github: theschles - slack: U054UUYBNLF - twitter: philschlesinger - availableForHire: false - isTscMember: true - repos: - - jasyncapi-idea-plugin -- name: Prince Rajpoot - github: princerajpoot20 - linkedin: princerajpoot - slack: U04STTQHV18 - twitter: iamPrince_2003 - availableForHire: true - isTscMember: true - repos: - - studio -- name: Richard Coppen - github: rcoppen - linkedin: richard-coppen - slack: U01L3FH3BUH - availableForHire: false - company: IBM - isTscMember: true - repos: - - bindings -- name: Samir AMZANI - github: Amzani - slack: U01N6AW5V5G - twitter: amzani - linkedin: amzani - availableForHire: false - company: Postman - isTscMember: true - repos: - - studio -- name: Sergio Moya - github: smoya - linkedin: smoya - slack: UN22ZTLHG - twitter: smoyac - availableForHire: false - company: Postman - isTscMember: true - repos: - - spec - - spec-json-schemas - - bindings - - parser-api - - parser-js - - avro-schema-parser - - openapi-schema-parser - - raml-dt-schema-parser - - server-api - - parser-go - - converter-go - - go-watermill-template - - template-for-go-projects -- name: Souvik De - github: Souvikns - slack: U01SGCZMJKW - twitter: souvik_ns - linkedin: souvik-de-a2b941169 - availableForHire: false - company: Postman - isTscMember: true - repos: - - cli - - bundler - - glee -- name: Quetzalli Writes - github: quetzalliwrites - twitter: QuetzalliWrites - slack: U02AKC14WAJ - linkedin: quetzalli-writes - availableForHire: false - company: Postman - isTscMember: true - repos: - - website - - training - - community -- name: David Pereira - github: BOLT04 - twitter: BOLT2938 - slack: U02EC8BT0TX - linkedin: josé-david-pereira-13ba5315a - availableForHire: false - company: Create IT - isTscMember: true - repos: - - server-api -- name: Daniel Raper - github: dan-r - slack: U02FP8WBFQE - linkedin: danielr - availableForHire: false - isTscMember: true - repos: - - java-template -- name: Kieran Murphy - github: KieranM1999 - linkedin: kieran-murphy-175b0412b - availableForHire: false - slack: U02FT2TKM37 - company: IBM - isTscMember: false - repos: - - java-template -- name: Tom Jefferson - github: JEFFLUFC - linkedin: t-jefferson - slack: U02FPPCEH6H - availableForHire: false - company: IBM - isTscMember: false - repos: - - java-template -- name: Lewis Relph - github: lewis-relph - availableForHire: false - slack: U02G8MDDEF3 - company: IBM - isTscMember: false - repos: - - java-template -- name: Semen Tenishchev - github: Tenischev - linkedin: semen-tenishchev - availableForHire: true - slack: U011D1DAU6S - isTscMember: true - repos: - - java-spring-template -- name: Samridhi Agrawal - github: Samridhi-98 - slack: U02T2MY9W5T - linkedin: samridhi-agrawal-1713201ab - availableForHire: false - company: ThoughtWorks - isTscMember: true - repos: - - modelina -- name: Debajyoti Halder - github: ron-debajyoti - twitter: rondebajyoti - slack: U02UK9RUPGQ - linkedin: rondebajyoti - availableForHire: false - company: Narvar - isTscMember: false - repos: - - modelina -- name: Ivan Garcia Sainz-Aja - github: ivangsa - linkedin: ivangarciasainzaja - slack: UTCN3ET4M - availableForHire: false - company: SNGULAR - isTscMember: true - repos: - - vs-asyncapi-preview -- name: Florence Njeri - github: Florence-Njeri - linkedin: florencenjeri - slack: U03D18YKX2M - twitter: njericodes - availableForHire: true - isTscMember: true - repos: - - generator -- name: Jeremy Whitlock - github: whitlockjc - linkedin: whitlockjc - slack: U03HBC08EBB - twitter: whitlockjc - availableForHire: false - company: Google - isTscMember: true - repos: - - bindings -- name: Vladimír Gorej - github: char0n - linkedin: vladimirgorej - slack: U03NV5L4S49 - twitter: vladimirgorej - availableForHire: false - company: SmartBear - isTscMember: false - repos: - - bindings - - spec - - spec-json-schemas -- name: Alexander Wichmann - github: VisualBean - linkedin: alexcarlsen - slack: U04C58GB8TF - availableForHire: false - company: The LEGO Group - isTscMember: true - repos: - - bindings -- name: Kenneth Aasan - github: kennethaasan - slack: U037S2HK4TS - twitter: kennethaasan - availableForHire: false - company: Sportradar - isTscMember: true - repos: - - modelina -- name: Heiko Henning - github: GreenRover - slack: U03AC4G51H8 - availableForHire: false - company: mtrail GmbH - isTscMember: true - repos: - - protobuf-schema-parser -- name: connil - github: connil - slack: U03A51H8 - availableForHire: false - company: GmbH - isTscMember: false - repos: - - dotnet-rabbitmq-template -- name: mr-nuno - github: mr-nuno - slack: U03A5145 - availableForHire: false - company: GmbH - isTscMember: false - repos: - - dotnet-rabbitmq-template -- name: Thulisile Sibanda - github: thulieblack - linkedin: v-thulisile-sibanda - twitter: thulieblack - slack: U03CNJPMT7C - availableForHire: false - company: AsyncAPI Initiative - isTscMember: true - repos: - - website - - community -- name: Ashmit JaiSarita Gupta - github: devilkiller-ag - linkedin: jaisarita - twitter: jaisarita - slack: U062LA14E58 - availableForHire: true - isTscMember: true - repos: - - modelina -- name: Sambhav Gupta - github: sambhavgupta0705 - linkedin: sambhavgupta0705 - twitter: sambhavgupta75 - slack: U04630DU3N3 - availableForHire: true - isTscMember: true - repos: - - website -- name: Viacheslav Turovskyi - github: aeworxet - slack: U01G3U01SVC - availableForHire: false - isTscMember: false - repos: - - bundler - - optimizer + - github-action-for-cli \ No newline at end of file