diff --git a/.github/workflows/find-inactive-collaborators.yml b/.github/workflows/find-inactive-collaborators.yml index 45b3a8cebcd350..2103bb5960cdca 100644 --- a/.github/workflows/find-inactive-collaborators.yml +++ b/.github/workflows/find-inactive-collaborators.yml @@ -28,3 +28,13 @@ jobs: - name: Find inactive collaborators run: tools/find-inactive-collaborators.mjs ${{ env.NUM_COMMITS }} + + - name: Open pull request + uses: gr2m/create-or-update-pull-request-action@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + title: "meta: move one or more collaborators to emeritus" + body: This PR was generated by tools/find-inactive-collaborators.yml. + commit-message: "meta: move one or more collaborators to emeritus" + labels: meta diff --git a/README.md b/README.md index c4079eade75783..3276470203988a 100644 --- a/README.md +++ b/README.md @@ -152,6 +152,8 @@ For information on reporting security vulnerabilities in Node.js, see For information about the governance of the Node.js project, see [GOVERNANCE.md](./GOVERNANCE.md). + ### TSC (Technical Steering Committee) @@ -249,6 +251,9 @@ For information about the governance of the Node.js project, see + ### Collaborators * [addaleax](https://github.com/addaleax) - @@ -273,8 +278,6 @@ For information about the governance of the Node.js project, see **Beth Griggs** <bgriggs@redhat.com> (she/her) * [bmeck](https://github.com/bmeck) - **Bradley Farias** <bradley.meck@gmail.com> -* [bmeurer](https://github.com/bmeurer) - -**Benedikt Meurer** <benedikt.meurer@gmail.com> * [boneskull](https://github.com/boneskull) - **Christopher Hiller** <boneskull@boneskull.com> (he/him) * [BridgeAR](https://github.com/BridgeAR) - @@ -319,8 +322,6 @@ For information about the governance of the Node.js project, see **Gerhard Stöbich** <deb2001-github@yahoo.de> (he/they) * [gabrielschulhof](https://github.com/gabrielschulhof) - **Gabriel Schulhof** <gabrielschulhof@gmail.com> -* [geek](https://github.com/geek) - -**Wyatt Preul** <wpreul@gmail.com> * [gengjiawen](https://github.com/gengjiawen) - **Jiawen Geng** <technicalcute@gmail.com> * [GeoffreyBooth](https://github.com/geoffreybooth) - @@ -377,8 +378,6 @@ For information about the governance of the Node.js project, see **Milad Fa** <mfarazma@redhat.com> (he/him) * [mildsunrise](https://github.com/mildsunrise) - **Alba Mendez** <me@alba.sh> (she/her) -* [misterdjules](https://github.com/misterdjules) - -**Julien Gilli** <jgilli@netflix.com> * [mmarchini](https://github.com/mmarchini) - **Mary Marchini** <oss@mmarchini.me> (she/her) * [mscdex](https://github.com/mscdex) - @@ -397,8 +396,6 @@ For information about the governance of the Node.js project, see **Stephen Belanger** <admin@stephenbelanger.com> (he/him) * [RaisinTen](https://github.com/RaisinTen) - **Darshan Sen** <raisinten@gmail.com> (he/him) -* [refack](https://github.com/refack) - -**Refael Ackermann (רפאל פלחי)** <refack@gmail.com> (he/him/הוא/אתה) * [rexagod](https://github.com/rexagod) - **Pranshu Srivastava** <rexagod@gmail.com> (he/him) * [richardlau](https://github.com/richardlau) - @@ -451,8 +448,6 @@ For information about the governance of the Node.js project, see **Yash Ladha** <yash@yashladha.in> (he/him) * [yhwang](https://github.com/yhwang) - **Yihong Wang** <yh.wang@ibm.com> -* [yorkie](https://github.com/yorkie) - -**Yorkie Liu** <yorkiefixer@gmail.com> * [yosuke-furukawa](https://github.com/yosuke-furukawa) - **Yosuke Furukawa** <yosuke.furukawa@gmail.com> * [ZYSzys](https://github.com/ZYSzys) - @@ -462,6 +457,8 @@ For information about the governance of the Node.js project, see Emeriti + ### Collaborator emeriti * [andrasq](https://github.com/andrasq) - @@ -472,6 +469,8 @@ For information about the governance of the Node.js project, see **Andreas Madsen** <amwebdk@gmail.com> (he/him) * [aqrln](https://github.com/aqrln) - **Alexey Orlenko** <eaglexrlnk@gmail.com> (he/him) +* [bmeurer](https://github.com/bmeurer) - +**Benedikt Meurer** <benedikt.meurer@gmail.com> * [bnoordhuis](https://github.com/bnoordhuis) - **Ben Noordhuis** <info@bnoordhuis.nl> * [brendanashworth](https://github.com/brendanashworth) - @@ -494,6 +493,8 @@ For information about the governance of the Node.js project, see **Daniel Wang** <wangyang0123@gmail.com> * [gdams](https://github.com/gdams) - **George Adams** <george.adams@microsoft.com> (he/him) +* [geek](https://github.com/geek) - +**Wyatt Preul** <wpreul@gmail.com> * [gibfahn](https://github.com/gibfahn) - **Gibson Fahnestock** <gibfahn@gmail.com> (he/him) * [glentiki](https://github.com/glentiki) - @@ -538,6 +539,8 @@ For information about the governance of the Node.js project, see **Nicu Micleușanu** <micnic90@gmail.com> (he/him) * [mikeal](https://github.com/mikeal) - **Mikeal Rogers** <mikeal.rogers@gmail.com> +* [misterdjules](https://github.com/misterdjules) - +**Julien Gilli** <jgilli@netflix.com> * [monsanto](https://github.com/monsanto) - **Christopher Monsanto** <chris@monsan.to> * [MoonBall](https://github.com/MoonBall) - @@ -564,6 +567,8 @@ For information about the governance of the Node.js project, see **Prince John Wesley** <princejohnwesley@gmail.com> * [psmarshall](https://github.com/psmarshall) - **Peter Marshall** <petermarshall@chromium.org> (he/him) +* [refack](https://github.com/refack) - +**Refael Ackermann (רפאל פלחי)** <refack@gmail.com> (he/him/הוא/אתה) * [rlidwka](https://github.com/rlidwka) - **Alex Kocharin** <alex@kocharin.ru> * [rmg](https://github.com/rmg) - @@ -602,6 +607,8 @@ For information about the governance of the Node.js project, see **Vse Mozhet Byt** <vsemozhetbyt@gmail.com> (he/him) * [whitlockjc](https://github.com/whitlockjc) - **Jeremy Whitlock** <jwhitlock@apache.org> +* [yorkie](https://github.com/yorkie) - +**Yorkie Liu** <yorkiefixer@gmail.com> diff --git a/tools/find-inactive-collaborators.mjs b/tools/find-inactive-collaborators.mjs index 0d89d2869cf4f7..9f7ac239d2df01 100755 --- a/tools/find-inactive-collaborators.mjs +++ b/tools/find-inactive-collaborators.mjs @@ -100,6 +100,85 @@ async function getCollaboratorsFromReadme() { return returnedArray; } +async function moveCollaboratorToEmeritus(peopleToMove) { + const readmeText = readline.createInterface({ + input: fs.createReadStream(new URL('../README.md', import.meta.url)), + crlfDelay: Infinity, + }); + let fileContents = ''; + let inCollaboratorsSection = false; + let inCollaboratorEmeritusSection = false; + let collaboratorFirstLine = ''; + const textToMove = []; + for await (const line of readmeText) { + // If we've been processing collaborator emeriti and we reach the end of + // the list, print out the remaining entries to be moved because they come + // alphabetically after the last item. + if (inCollaboratorEmeritusSection && line === '' && + fileContents.endsWith('>\n')) { + while (textToMove.length) { + fileContents += textToMove.pop(); + } + } + + // If we've found the collaborator heading already, stop processing at the + // next heading. + if (line.startsWith('#')) { + inCollaboratorsSection = false; + inCollaboratorEmeritusSection = false; + } + + const isCollaborator = inCollaboratorsSection && line.length; + const isCollaboratorEmeritus = inCollaboratorEmeritusSection && line.length; + + if (line === '### Collaborators') { + inCollaboratorsSection = true; + } + if (line === '### Collaborator emeriti') { + inCollaboratorEmeritusSection = true; + } + + if (isCollaborator) { + if (line.startsWith('* ')) { + collaboratorFirstLine = line; + } else if (line.startsWith('**')) { + const [, name, email] = /^\*\*([^*]+)\*\* <(.+)>/.exec(line); + if (peopleToMove.some((entry) => { + return entry.name === name && entry.email === email; + })) { + textToMove.push(`${collaboratorFirstLine}\n${line}\n`); + } else { + fileContents += `${collaboratorFirstLine}\n${line}\n`; + } + } else { + fileContents += `${line}\n`; + } + } + + if (isCollaboratorEmeritus) { + if (line.startsWith('* ')) { + collaboratorFirstLine = line; + } else if (line.startsWith('**')) { + const currentLine = `${collaboratorFirstLine}\n${line}\n`; + // If textToMove is empty, this still works because when undefined is + // used in a comparison with <, the result is always false. + while (textToMove[0] < currentLine) { + fileContents += textToMove.shift(); + } + fileContents += currentLine; + } else { + fileContents += `${line}\n`; + } + } + + if (!isCollaborator && !isCollaboratorEmeritus) { + fileContents += `${line}\n`; + } + } + + return fileContents; +} + // Get list of current collaborators from README.md. const collaborators = await getCollaboratorsFromReadme(); @@ -113,9 +192,13 @@ const inactive = collaborators.filter((collaborator) => !authors.has(collaborator.mailmap) && !landers.has(collaborator.mailmap) && !approvingReviewers.has(collaborator.name) -).map((collaborator) => collaborator.name); +); if (inactive.length) { console.log('\nInactive collaborators:\n'); - console.log(inactive.map((name) => `* ${name}`).join('\n')); + console.log(inactive.map((entry) => `* ${entry.name}`).join('\n')); + console.log('\nGenerating new README.md file...'); + const newReadmeText = await moveCollaboratorToEmeritus(inactive); + fs.writeFileSync(new URL('../README.md', import.meta.url), newReadmeText); + console.log('Updated README.md generated. Please commit these changes.'); }