tools,meta: update README and tools to reflect changes in TSC charter
Ref: https://github.com/nodejs/TSC/pull/1350 PR-URL: https://github.com/nodejs/node/pull/47126 Refs: https://github.com/nodejs/TSC/pull/1350 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Darshan Sen <raisinten@gmail.com>
This commit is contained in:
parent
3807dfbacd
commit
b351f12a85
8
.github/workflows/find-inactive-tsc.yml
vendored
8
.github/workflows/find-inactive-tsc.yml
vendored
@ -1,4 +1,4 @@
|
|||||||
name: Find inactive TSC members
|
name: Find inactive TSC voting members
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
@ -38,7 +38,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
|
|
||||||
- name: Find inactive TSC members
|
- name: Find inactive TSC voting members
|
||||||
run: tools/find-inactive-tsc.mjs >> $GITHUB_ENV
|
run: tools/find-inactive-tsc.mjs >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Open pull request
|
- name: Open pull request
|
||||||
@ -56,6 +56,6 @@ jobs:
|
|||||||
@nodejs/tsc ${{ env.INACTIVE_TSC_HANDLES }}
|
@nodejs/tsc ${{ env.INACTIVE_TSC_HANDLES }}
|
||||||
|
|
||||||
${{ env.DETAILS_FOR_COMMIT_BODY }}
|
${{ env.DETAILS_FOR_COMMIT_BODY }}
|
||||||
commit-message: 'meta: move one or more TSC members to emeritus'
|
commit-message: 'meta: move TSC voting member(s) to regular member(s)'
|
||||||
labels: meta
|
labels: meta
|
||||||
title: 'meta: move one or more TSC members to emeritus'
|
title: 'meta: move TSC voting member(s) to regular member(s)'
|
||||||
|
39
README.md
39
README.md
@ -158,6 +158,8 @@ For information about the governance of the Node.js project, see
|
|||||||
|
|
||||||
### TSC (Technical Steering Committee)
|
### TSC (Technical Steering Committee)
|
||||||
|
|
||||||
|
#### TSC voting members
|
||||||
|
|
||||||
<!--lint disable prohibited-strings-->
|
<!--lint disable prohibited-strings-->
|
||||||
|
|
||||||
* [aduh95](https://github.com/aduh95) -
|
* [aduh95](https://github.com/aduh95) -
|
||||||
@ -205,28 +207,39 @@ For information about the governance of the Node.js project, see
|
|||||||
* [Trott](https://github.com/Trott) -
|
* [Trott](https://github.com/Trott) -
|
||||||
**Rich Trott** <<rtrott@gmail.com>> (he/him)
|
**Rich Trott** <<rtrott@gmail.com>> (he/him)
|
||||||
|
|
||||||
<details>
|
#### TSC regular members
|
||||||
|
|
||||||
<summary>Emeriti</summary>
|
|
||||||
|
|
||||||
### TSC emeriti
|
|
||||||
|
|
||||||
* [addaleax](https://github.com/addaleax) -
|
* [addaleax](https://github.com/addaleax) -
|
||||||
**Anna Henningsen** <<anna@addaleax.net>> (she/her)
|
**Anna Henningsen** <<anna@addaleax.net>> (she/her)
|
||||||
* [bnoordhuis](https://github.com/bnoordhuis) -
|
* [bnoordhuis](https://github.com/bnoordhuis) -
|
||||||
**Ben Noordhuis** <<info@bnoordhuis.nl>>
|
**Ben Noordhuis** <<info@bnoordhuis.nl>>
|
||||||
* [chrisdickinson](https://github.com/chrisdickinson) -
|
|
||||||
**Chris Dickinson** <<christopher.s.dickinson@gmail.com>>
|
|
||||||
* [codebytere](https://github.com/codebytere) -
|
* [codebytere](https://github.com/codebytere) -
|
||||||
**Shelley Vohr** <<shelley.vohr@gmail.com>> (she/her)
|
**Shelley Vohr** <<shelley.vohr@gmail.com>> (she/her)
|
||||||
* [danbev](https://github.com/danbev) -
|
* [danbev](https://github.com/danbev) -
|
||||||
**Daniel Bevenius** <<daniel.bevenius@gmail.com>> (he/him)
|
**Daniel Bevenius** <<daniel.bevenius@gmail.com>> (he/him)
|
||||||
|
* [gabrielschulhof](https://github.com/gabrielschulhof) -
|
||||||
|
**Gabriel Schulhof** <<gabrielschulhof@gmail.com>>
|
||||||
|
* [mscdex](https://github.com/mscdex) -
|
||||||
|
**Brian White** <<mscdex@mscdex.net>>
|
||||||
|
* [MylesBorins](https://github.com/MylesBorins) -
|
||||||
|
**Myles Borins** <<myles.borins@gmail.com>> (he/him)
|
||||||
|
* [rvagg](https://github.com/rvagg) -
|
||||||
|
**Rod Vagg** <<r@va.gg>>
|
||||||
|
* [TimothyGu](https://github.com/TimothyGu) -
|
||||||
|
**Tiancheng "Timothy" Gu** <<timothygu99@gmail.com>> (he/him)
|
||||||
|
|
||||||
|
<details>
|
||||||
|
|
||||||
|
<summary>TSC emeriti members</summary>
|
||||||
|
|
||||||
|
#### TSC emeriti members
|
||||||
|
|
||||||
|
* [chrisdickinson](https://github.com/chrisdickinson) -
|
||||||
|
**Chris Dickinson** <<christopher.s.dickinson@gmail.com>>
|
||||||
* [evanlucas](https://github.com/evanlucas) -
|
* [evanlucas](https://github.com/evanlucas) -
|
||||||
**Evan Lucas** <<evanlucas@me.com>> (he/him)
|
**Evan Lucas** <<evanlucas@me.com>> (he/him)
|
||||||
* [Fishrock123](https://github.com/Fishrock123) -
|
* [Fishrock123](https://github.com/Fishrock123) -
|
||||||
**Jeremiah Senkpiel** <<fishrock123@rocketmail.com>> (he/they)
|
**Jeremiah Senkpiel** <<fishrock123@rocketmail.com>> (he/they)
|
||||||
* [gabrielschulhof](https://github.com/gabrielschulhof) -
|
|
||||||
**Gabriel Schulhof** <<gabrielschulhof@gmail.com>>
|
|
||||||
* [gibfahn](https://github.com/gibfahn) -
|
* [gibfahn](https://github.com/gibfahn) -
|
||||||
**Gibson Fahnestock** <<gibfahn@gmail.com>> (he/him)
|
**Gibson Fahnestock** <<gibfahn@gmail.com>> (he/him)
|
||||||
* [indutny](https://github.com/indutny) -
|
* [indutny](https://github.com/indutny) -
|
||||||
@ -237,10 +250,6 @@ For information about the governance of the Node.js project, see
|
|||||||
**Josh Gavant** <<josh.gavant@outlook.com>>
|
**Josh Gavant** <<josh.gavant@outlook.com>>
|
||||||
* [mmarchini](https://github.com/mmarchini) -
|
* [mmarchini](https://github.com/mmarchini) -
|
||||||
**Mary Marchini** <<oss@mmarchini.me>> (she/her)
|
**Mary Marchini** <<oss@mmarchini.me>> (she/her)
|
||||||
* [mscdex](https://github.com/mscdex) -
|
|
||||||
**Brian White** <<mscdex@mscdex.net>>
|
|
||||||
* [MylesBorins](https://github.com/MylesBorins) -
|
|
||||||
**Myles Borins** <<myles.borins@gmail.com>> (he/him)
|
|
||||||
* [nebrius](https://github.com/nebrius) -
|
* [nebrius](https://github.com/nebrius) -
|
||||||
**Bryan Hughes** <<bryan@nebri.us>>
|
**Bryan Hughes** <<bryan@nebri.us>>
|
||||||
* [ofrobots](https://github.com/ofrobots) -
|
* [ofrobots](https://github.com/ofrobots) -
|
||||||
@ -249,16 +258,12 @@ For information about the governance of the Node.js project, see
|
|||||||
**Alexis Campailla** <<orangemocha@nodejs.org>>
|
**Alexis Campailla** <<orangemocha@nodejs.org>>
|
||||||
* [piscisaureus](https://github.com/piscisaureus) -
|
* [piscisaureus](https://github.com/piscisaureus) -
|
||||||
**Bert Belder** <<bertbelder@gmail.com>>
|
**Bert Belder** <<bertbelder@gmail.com>>
|
||||||
* [rvagg](https://github.com/rvagg) -
|
|
||||||
**Rod Vagg** <<r@va.gg>>
|
|
||||||
* [sam-github](https://github.com/sam-github) -
|
* [sam-github](https://github.com/sam-github) -
|
||||||
**Sam Roberts** <<vieuxtech@gmail.com>>
|
**Sam Roberts** <<vieuxtech@gmail.com>>
|
||||||
* [shigeki](https://github.com/shigeki) -
|
* [shigeki](https://github.com/shigeki) -
|
||||||
**Shigeki Ohtsu** <<ohtsu@ohtsu.org>> (he/him)
|
**Shigeki Ohtsu** <<ohtsu@ohtsu.org>> (he/him)
|
||||||
* [thefourtheye](https://github.com/thefourtheye) -
|
* [thefourtheye](https://github.com/thefourtheye) -
|
||||||
**Sakthipriyan Vairamani** <<thechargingvolcano@gmail.com>> (he/him)
|
**Sakthipriyan Vairamani** <<thechargingvolcano@gmail.com>> (he/him)
|
||||||
* [TimothyGu](https://github.com/TimothyGu) -
|
|
||||||
**Tiancheng "Timothy" Gu** <<timothygu99@gmail.com>> (he/him)
|
|
||||||
* [trevnorris](https://github.com/trevnorris) -
|
* [trevnorris](https://github.com/trevnorris) -
|
||||||
**Trevor Norris** <<trev.norris@gmail.com>>
|
**Trevor Norris** <<trev.norris@gmail.com>>
|
||||||
|
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
// Identify inactive TSC members.
|
// Identify inactive TSC voting members.
|
||||||
|
|
||||||
// From the TSC Charter:
|
// From the TSC Charter:
|
||||||
// A TSC member is automatically removed from the TSC if, during a 3-month
|
// A TSC voting member is automatically converted to a TSC regular member if
|
||||||
// period, all of the following are true:
|
// they do not participate in three consecutive TSC votes.
|
||||||
// * They attend fewer than 25% of the regularly scheduled meetings.
|
|
||||||
// * They do not participate in any TSC votes.
|
|
||||||
|
|
||||||
import cp from 'node:child_process';
|
import cp from 'node:child_process';
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
@ -20,9 +18,8 @@ const args = parseArgs({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const verbose = args.values.verbose;
|
const verbose = args.values.verbose;
|
||||||
const SINCE = args.positionals[0] || '3 months ago';
|
|
||||||
|
|
||||||
async function runGitCommand(cmd, options = {}) {
|
async function runShellCommand(cmd, options = {}) {
|
||||||
const childProcess = cp.spawn('/bin/sh', ['-c', cmd], {
|
const childProcess = cp.spawn('/bin/sh', ['-c', cmd], {
|
||||||
cwd: options.cwd ?? new URL('..', import.meta.url),
|
cwd: options.cwd ?? new URL('..', import.meta.url),
|
||||||
encoding: 'utf8',
|
encoding: 'utf8',
|
||||||
@ -34,17 +31,14 @@ async function runGitCommand(cmd, options = {}) {
|
|||||||
const errorHandler = new Promise(
|
const errorHandler = new Promise(
|
||||||
(_, reject) => childProcess.on('error', reject),
|
(_, reject) => childProcess.on('error', reject),
|
||||||
);
|
);
|
||||||
let returnValue = options.mapFn ? new Set() : '';
|
let returnValue = options.returnAsArray ? [] : '';
|
||||||
await Promise.race([errorHandler, Promise.resolve()]);
|
await Promise.race([errorHandler, Promise.resolve()]);
|
||||||
// If no mapFn, return the value. If there is a mapFn, use it to make a Set to
|
// If no mapFn, return the value. If there is a mapFn, use it to make a Set to
|
||||||
// return.
|
// return.
|
||||||
for await (const line of lines) {
|
for await (const line of lines) {
|
||||||
await Promise.race([errorHandler, Promise.resolve()]);
|
await Promise.race([errorHandler, Promise.resolve()]);
|
||||||
if (options.mapFn) {
|
if (options.returnAsArray) {
|
||||||
const val = options.mapFn(line);
|
returnValue.push(line);
|
||||||
if (val) {
|
|
||||||
returnValue.add(val);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
returnValue += line;
|
returnValue += line;
|
||||||
}
|
}
|
||||||
@ -60,6 +54,13 @@ async function getTscFromReadme() {
|
|||||||
const returnedArray = [];
|
const returnedArray = [];
|
||||||
let foundTscHeading = false;
|
let foundTscHeading = false;
|
||||||
for await (const line of readmeText) {
|
for await (const line of readmeText) {
|
||||||
|
// Until three votes have passed from March 16, 2023, we will need this.
|
||||||
|
// After that point, we can use this for setting `foundTscHeading` below
|
||||||
|
// and remove this.
|
||||||
|
if (line === '#### TSC voting members') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// If we've found the TSC heading already, stop processing at the next
|
// If we've found the TSC heading already, stop processing at the next
|
||||||
// heading.
|
// heading.
|
||||||
if (foundTscHeading && line.startsWith('#')) {
|
if (foundTscHeading && line.startsWith('#')) {
|
||||||
@ -84,36 +85,6 @@ async function getTscFromReadme() {
|
|||||||
return returnedArray;
|
return returnedArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getAttendance(tscMembers, meetings) {
|
|
||||||
const attendance = {};
|
|
||||||
for (const member of tscMembers) {
|
|
||||||
attendance[member] = 0;
|
|
||||||
}
|
|
||||||
for (const meeting of meetings) {
|
|
||||||
// Get the file contents.
|
|
||||||
const meetingFile =
|
|
||||||
await fs.promises.readFile(path.join('.tmp', meeting), 'utf8');
|
|
||||||
// Extract the attendee list.
|
|
||||||
const startMarker = '## Present';
|
|
||||||
const start = meetingFile.indexOf(startMarker) + startMarker.length;
|
|
||||||
const end = meetingFile.indexOf('## Agenda');
|
|
||||||
meetingFile.substring(start, end).trim().split('\n')
|
|
||||||
.map((line) => {
|
|
||||||
const match = line.match(/@(\S+)/);
|
|
||||||
if (match) {
|
|
||||||
return match[1];
|
|
||||||
}
|
|
||||||
// Using `console.warn` so that stdout output is not generated.
|
|
||||||
// The stdout output is consumed in find-inactive-tsc.yml.
|
|
||||||
console.warn(`Attendee entry does not contain GitHub handle: ${line}`);
|
|
||||||
return '';
|
|
||||||
})
|
|
||||||
.filter((handle) => tscMembers.includes(handle))
|
|
||||||
.forEach((handle) => { attendance[handle]++; });
|
|
||||||
}
|
|
||||||
return attendance;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getVotingRecords(tscMembers, votes) {
|
async function getVotingRecords(tscMembers, votes) {
|
||||||
const votingRecords = {};
|
const votingRecords = {};
|
||||||
for (const member of tscMembers) {
|
for (const member of tscMembers) {
|
||||||
@ -122,7 +93,7 @@ async function getVotingRecords(tscMembers, votes) {
|
|||||||
for (const vote of votes) {
|
for (const vote of votes) {
|
||||||
// Get the vote data.
|
// Get the vote data.
|
||||||
const voteData = JSON.parse(
|
const voteData = JSON.parse(
|
||||||
await fs.promises.readFile(path.join('.tmp', vote), 'utf8'),
|
await fs.promises.readFile(path.join('.tmp/votes', vote), 'utf8'),
|
||||||
);
|
);
|
||||||
for (const member in voteData.votes) {
|
for (const member in voteData.votes) {
|
||||||
if (tscMembers.includes(member)) {
|
if (tscMembers.includes(member)) {
|
||||||
@ -133,22 +104,22 @@ async function getVotingRecords(tscMembers, votes) {
|
|||||||
return votingRecords;
|
return votingRecords;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function moveTscToEmeritus(peopleToMove) {
|
async function moveVotingToRegular(peopleToMove) {
|
||||||
const readmeText = readline.createInterface({
|
const readmeText = readline.createInterface({
|
||||||
input: fs.createReadStream(new URL('../README.md', import.meta.url)),
|
input: fs.createReadStream(new URL('../README.md', import.meta.url)),
|
||||||
crlfDelay: Infinity,
|
crlfDelay: Infinity,
|
||||||
});
|
});
|
||||||
let fileContents = '';
|
let fileContents = '';
|
||||||
let inTscSection = false;
|
let inTscVotingSection = false;
|
||||||
let inTscEmeritusSection = false;
|
let inTscRegularSection = false;
|
||||||
let memberFirstLine = '';
|
let memberFirstLine = '';
|
||||||
const textToMove = [];
|
const textToMove = [];
|
||||||
let moveToInactive = false;
|
let moveToInactive = false;
|
||||||
for await (const line of readmeText) {
|
for await (const line of readmeText) {
|
||||||
// If we've been processing TSC emeriti and we reach the end of
|
// If we've been processing TSC regular members and we reach the end of
|
||||||
// the list, print out the remaining entries to be moved because they come
|
// the list, print out the remaining entries to be moved because they come
|
||||||
// alphabetically after the last item.
|
// alphabetically after the last item.
|
||||||
if (inTscEmeritusSection && line === '' &&
|
if (inTscRegularSection && line === '' &&
|
||||||
fileContents.endsWith('>\n')) {
|
fileContents.endsWith('>\n')) {
|
||||||
while (textToMove.length) {
|
while (textToMove.length) {
|
||||||
fileContents += textToMove.pop();
|
fileContents += textToMove.pop();
|
||||||
@ -158,21 +129,21 @@ async function moveTscToEmeritus(peopleToMove) {
|
|||||||
// If we've found the TSC heading already, stop processing at the
|
// If we've found the TSC heading already, stop processing at the
|
||||||
// next heading.
|
// next heading.
|
||||||
if (line.startsWith('#')) {
|
if (line.startsWith('#')) {
|
||||||
inTscSection = false;
|
inTscVotingSection = false;
|
||||||
inTscEmeritusSection = false;
|
inTscRegularSection = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isTsc = inTscSection && line.length;
|
const isTscVoting = inTscVotingSection && line.length;
|
||||||
const isTscEmeritus = inTscEmeritusSection && line.length;
|
const isTscRegular = inTscRegularSection && line.length;
|
||||||
|
|
||||||
if (line === '### TSC (Technical Steering Committee)') {
|
if (line === '#### TSC voting members') {
|
||||||
inTscSection = true;
|
inTscVotingSection = true;
|
||||||
}
|
}
|
||||||
if (line === '### TSC emeriti') {
|
if (line === '#### TSC regular members') {
|
||||||
inTscEmeritusSection = true;
|
inTscRegularSection = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isTsc) {
|
if (isTscVoting) {
|
||||||
if (line.startsWith('* ')) {
|
if (line.startsWith('* ')) {
|
||||||
memberFirstLine = line;
|
memberFirstLine = line;
|
||||||
const match = line.match(/^\* \[([^\]]+)/);
|
const match = line.match(/^\* \[([^\]]+)/);
|
||||||
@ -191,7 +162,7 @@ async function moveTscToEmeritus(peopleToMove) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isTscEmeritus) {
|
if (isTscRegular) {
|
||||||
if (line.startsWith('* ')) {
|
if (line.startsWith('* ')) {
|
||||||
memberFirstLine = line;
|
memberFirstLine = line;
|
||||||
} else if (line.startsWith(' **')) {
|
} else if (line.startsWith(' **')) {
|
||||||
@ -207,7 +178,7 @@ async function moveTscToEmeritus(peopleToMove) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isTsc && !isTscEmeritus) {
|
if (!isTscVoting && !isTscRegular) {
|
||||||
fileContents += `${line}\n`;
|
fileContents += `${line}\n`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -215,71 +186,54 @@ async function moveTscToEmeritus(peopleToMove) {
|
|||||||
return fileContents;
|
return fileContents;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get current TSC members, then get TSC members at start of period. Only check
|
// Get current TSC voting members, then get TSC voting members at start of
|
||||||
// TSC members who are on both lists. This way, we don't flag someone who has
|
// period. Only check TSC voting members who are on both lists. This way, we
|
||||||
// only been on the TSC for a week and therefore hasn't attended any meetings.
|
// don't flag someone who hasn't been on the TSC long enough to have missed 3
|
||||||
|
// consecutive votes.
|
||||||
const tscMembersAtEnd = await getTscFromReadme();
|
const tscMembersAtEnd = await getTscFromReadme();
|
||||||
|
|
||||||
const startCommit = await runGitCommand(`git rev-list -1 --before '${SINCE}' HEAD`);
|
// Get the last three votes.
|
||||||
await runGitCommand(`git checkout ${startCommit} -- README.md`);
|
// Assumes that the TSC repo is cloned in the .tmp dir.
|
||||||
|
const votes = await runShellCommand(
|
||||||
|
'ls *.json | sort -rn | head -3',
|
||||||
|
{ cwd: '.tmp/votes', returnAsArray: true },
|
||||||
|
);
|
||||||
|
|
||||||
|
// Reverse the votes list so the oldest of the three votes is first.
|
||||||
|
votes.reverse();
|
||||||
|
|
||||||
|
const startCommit = await runShellCommand(`git rev-list -1 --before '${votes[0]}' HEAD`);
|
||||||
|
await runShellCommand(`git checkout ${startCommit} -- README.md`);
|
||||||
const tscMembersAtStart = await getTscFromReadme();
|
const tscMembersAtStart = await getTscFromReadme();
|
||||||
await runGitCommand('git reset HEAD README.md');
|
await runShellCommand('git reset HEAD README.md');
|
||||||
await runGitCommand('git checkout -- README.md');
|
await runShellCommand('git checkout -- README.md');
|
||||||
|
|
||||||
const tscMembers = tscMembersAtEnd.filter(
|
const tscMembers = tscMembersAtEnd.filter(
|
||||||
(memberAtEnd) => tscMembersAtStart.includes(memberAtEnd),
|
(memberAtEnd) => tscMembersAtStart.includes(memberAtEnd),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Get all meetings since SINCE.
|
|
||||||
// Assumes that the TSC repo is cloned in the .tmp dir.
|
|
||||||
const meetings = await runGitCommand(
|
|
||||||
`git whatchanged --since '${SINCE}' --name-only --pretty=format: meetings`,
|
|
||||||
{ cwd: '.tmp', mapFn: (line) => line },
|
|
||||||
);
|
|
||||||
|
|
||||||
// Get TSC meeting attendance.
|
|
||||||
const attendance = await getAttendance(tscMembers, meetings);
|
|
||||||
const lightAttendance = tscMembers.filter(
|
|
||||||
(member) => attendance[member] < meetings.size * 0.25,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Get all votes since SINCE.
|
|
||||||
// Assumes that the TSC repo is cloned in the .tmp dir.
|
|
||||||
const votes = await runGitCommand(
|
|
||||||
`git whatchanged --since '${SINCE}' --name-only --pretty=format: votes/*.json`,
|
|
||||||
{ cwd: '.tmp', mapFn: (line) => line },
|
|
||||||
);
|
|
||||||
|
|
||||||
// Check voting record.
|
// Check voting record.
|
||||||
const votingRecords = await getVotingRecords(tscMembers, votes);
|
const votingRecords = await getVotingRecords(tscMembers, votes);
|
||||||
const noVotes = tscMembers.filter(
|
const inactive = tscMembers.filter(
|
||||||
(member) => votingRecords[member] === 0,
|
(member) => votingRecords[member] === 0,
|
||||||
);
|
);
|
||||||
|
|
||||||
const inactive = lightAttendance.filter((member) => noVotes.includes(member));
|
|
||||||
|
|
||||||
if (inactive.length) {
|
if (inactive.length) {
|
||||||
// The stdout output is consumed in find-inactive-tsc.yml. If format of output
|
// The stdout output is consumed in find-inactive-tsc.yml. If format of output
|
||||||
// changes, find-inactive-tsc.yml may need to be updated.
|
// changes, find-inactive-tsc.yml may need to be updated.
|
||||||
console.log(`INACTIVE_TSC_HANDLES=${inactive.map((entry) => '@' + entry).join(' ')}`);
|
console.log(`INACTIVE_TSC_HANDLES=${inactive.map((entry) => '@' + entry).join(' ')}`);
|
||||||
const commitDetails = inactive.map((entry) => {
|
const commitDetails = `${inactive.join(' ')} did not participate in three consecutive TSC votes: ${votes.join(' ')}`;
|
||||||
let details = `Since ${SINCE}, `;
|
console.log(`DETAILS_FOR_COMMIT_BODY=${commitDetails}`);
|
||||||
details += `${entry} attended ${attendance[entry]} out of ${meetings.size} meetings`;
|
|
||||||
details += ` and voted in ${votingRecords[entry]} of ${votes.size} votes.`;
|
|
||||||
return details;
|
|
||||||
});
|
|
||||||
console.log(`DETAILS_FOR_COMMIT_BODY=${commitDetails.join(' ')}`);
|
|
||||||
|
|
||||||
if (process.env.GITHUB_ACTIONS) {
|
if (process.env.GITHUB_ACTIONS) {
|
||||||
// Using console.warn() to avoid messing with find-inactive-tsc which
|
// Using console.warn() to avoid messing with find-inactive-tsc which
|
||||||
// consumes stdout.
|
// consumes stdout.
|
||||||
console.warn('Generating new README.md file...');
|
console.warn('Generating new README.md file...');
|
||||||
const newReadmeText = await moveTscToEmeritus(inactive);
|
const newReadmeText = await moveVotingToRegular(inactive);
|
||||||
fs.writeFileSync(new URL('../README.md', import.meta.url), newReadmeText);
|
fs.writeFileSync(new URL('../README.md', import.meta.url), newReadmeText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
console.log(attendance);
|
|
||||||
console.log(votingRecords);
|
console.log(votingRecords);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user