Skip to content

Commit 7d971da

Browse files
Trottdanielleadams
authored andcommitted
tools,meta: update README and tools to reflect changes in TSC charter
Ref: nodejs/TSC#1350 PR-URL: #47126 Refs: nodejs/TSC#1350 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Darshan Sen <raisinten@gmail.com>
1 parent 0edcfed commit 7d971da

3 files changed

Lines changed: 79 additions & 120 deletions

File tree

‎.github/workflows/find-inactive-tsc.yml‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Find inactive TSC members
1+
name: Find inactive TSC voting members
22

33
on:
44
schedule:
@@ -38,7 +38,7 @@ jobs:
3838
with:
3939
node-version: ${{ env.NODE_VERSION }}
4040

41-
- name: Find inactive TSC members
41+
- name: Find inactive TSC voting members
4242
run: tools/find-inactive-tsc.mjs >> $GITHUB_ENV
4343

4444
- name: Open pull request
@@ -56,6 +56,6 @@ jobs:
5656
@nodejs/tsc ${{ env.INACTIVE_TSC_HANDLES }}
5757
5858
${{ env.DETAILS_FOR_COMMIT_BODY }}
59-
commit-message: 'meta: move one or more TSC members to emeritus'
59+
commit-message: 'meta: move TSC voting member(s) to regular member(s)'
6060
labels: meta
61-
title: 'meta: move one or more TSC members to emeritus'
61+
title: 'meta: move TSC voting member(s) to regular member(s)'

‎README.md‎

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ For information about the governance of the Node.js project, see
158158

159159
### TSC (Technical Steering Committee)
160160

161+
#### TSC voting members
162+
161163
<!--lint disable prohibited-strings-->
162164

163165
*[aduh95](https://github.com/aduh95) -
@@ -205,28 +207,39 @@ For information about the governance of the Node.js project, see
205207
*[Trott](https://github.com/Trott) -
206208
**Rich Trott** <<rtrott@gmail.com>> (he/him)
207209

208-
<details>
209-
210-
<summary>Emeriti</summary>
211-
212-
### TSC emeriti
210+
#### TSC regular members
213211

214212
*[addaleax](https://github.com/addaleax) -
215213
**Anna Henningsen** <<anna@addaleax.net>> (she/her)
216214
*[bnoordhuis](https://github.com/bnoordhuis) -
217215
**Ben Noordhuis** <<info@bnoordhuis.nl>>
218-
*[chrisdickinson](https://github.com/chrisdickinson) -
219-
**Chris Dickinson** <<christopher.s.dickinson@gmail.com>>
220216
*[codebytere](https://github.com/codebytere) -
221217
**Shelley Vohr** <<shelley.vohr@gmail.com>> (she/her)
222218
*[danbev](https://github.com/danbev) -
223219
**Daniel Bevenius** <<daniel.bevenius@gmail.com>> (he/him)
220+
*[gabrielschulhof](https://github.com/gabrielschulhof) -
221+
**Gabriel Schulhof** <<gabrielschulhof@gmail.com>>
222+
*[mscdex](https://github.com/mscdex) -
223+
**Brian White** <<mscdex@mscdex.net>>
224+
*[MylesBorins](https://github.com/MylesBorins) -
225+
**Myles Borins** <<myles.borins@gmail.com>> (he/him)
226+
*[rvagg](https://github.com/rvagg) -
227+
**Rod Vagg** <<r@va.gg>>
228+
*[TimothyGu](https://github.com/TimothyGu) -
229+
**Tiancheng "Timothy" Gu** <<timothygu99@gmail.com>> (he/him)
230+
231+
<details>
232+
233+
<summary>TSC emeriti members</summary>
234+
235+
#### TSC emeriti members
236+
237+
*[chrisdickinson](https://github.com/chrisdickinson) -
238+
**Chris Dickinson** <<christopher.s.dickinson@gmail.com>>
224239
*[evanlucas](https://github.com/evanlucas) -
225240
**Evan Lucas** <<evanlucas@me.com>> (he/him)
226241
*[Fishrock123](https://github.com/Fishrock123) -
227242
**Jeremiah Senkpiel** <<fishrock123@rocketmail.com>> (he/they)
228-
*[gabrielschulhof](https://github.com/gabrielschulhof) -
229-
**Gabriel Schulhof** <<gabrielschulhof@gmail.com>>
230243
*[gibfahn](https://github.com/gibfahn) -
231244
**Gibson Fahnestock** <<gibfahn@gmail.com>> (he/him)
232245
*[indutny](https://github.com/indutny) -
@@ -237,10 +250,6 @@ For information about the governance of the Node.js project, see
237250
**Josh Gavant** <<josh.gavant@outlook.com>>
238251
*[mmarchini](https://github.com/mmarchini) -
239252
**Mary Marchini** <<oss@mmarchini.me>> (she/her)
240-
*[mscdex](https://github.com/mscdex) -
241-
**Brian White** <<mscdex@mscdex.net>>
242-
*[MylesBorins](https://github.com/MylesBorins) -
243-
**Myles Borins** <<myles.borins@gmail.com>> (he/him)
244253
*[nebrius](https://github.com/nebrius) -
245254
**Bryan Hughes** <<bryan@nebri.us>>
246255
*[ofrobots](https://github.com/ofrobots) -
@@ -249,16 +258,12 @@ For information about the governance of the Node.js project, see
249258
**Alexis Campailla** <<orangemocha@nodejs.org>>
250259
*[piscisaureus](https://github.com/piscisaureus) -
251260
**Bert Belder** <<bertbelder@gmail.com>>
252-
*[rvagg](https://github.com/rvagg) -
253-
**Rod Vagg** <<r@va.gg>>
254261
*[sam-github](https://github.com/sam-github) -
255262
**Sam Roberts** <<vieuxtech@gmail.com>>
256263
*[shigeki](https://github.com/shigeki) -
257264
**Shigeki Ohtsu** <<ohtsu@ohtsu.org>> (he/him)
258265
*[thefourtheye](https://github.com/thefourtheye) -
259266
**Sakthipriyan Vairamani** <<thechargingvolcano@gmail.com>> (he/him)
260-
*[TimothyGu](https://github.com/TimothyGu) -
261-
**Tiancheng "Timothy" Gu** <<timothygu99@gmail.com>> (he/him)
262267
*[trevnorris](https://github.com/trevnorris) -
263268
**Trevor Norris** <<trev.norris@gmail.com>>
264269

‎tools/find-inactive-tsc.mjs‎

Lines changed: 53 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
#!/usr/bin/env node
22

3-
// Identify inactive TSC members.
3+
// Identify inactive TSC voting members.
44

55
// From the TSC Charter:
6-
// A TSC member is automatically removed from the TSC if, during a 3-month
7-
// period, all of the following are true:
8-
// * They attend fewer than 25% of the regularly scheduled meetings.
9-
// * They do not participate in any TSC votes.
6+
// A TSC voting member is automatically converted to a TSC regular member if
7+
// they do not participate in three consecutive TSC votes.
108

119
importcpfrom'node:child_process';
1210
importfsfrom'node:fs';
@@ -20,9 +18,8 @@ const args = parseArgs({
2018
});
2119

2220
constverbose=args.values.verbose;
23-
constSINCE=args.positionals[0]||'3 months ago';
2421

25-
asyncfunctionrunGitCommand(cmd,options={}){
22+
asyncfunctionrunShellCommand(cmd,options={}){
2623
constchildProcess=cp.spawn('/bin/sh',['-c',cmd],{
2724
cwd: options.cwd??newURL('..',import.meta.url),
2825
encoding: 'utf8',
@@ -34,17 +31,14 @@ async function runGitCommand(cmd, options = {}) {
3431
consterrorHandler=newPromise(
3532
(_,reject)=>childProcess.on('error',reject),
3633
);
37-
letreturnValue=options.mapFn ? newSet() : '';
34+
letreturnValue=options.returnAsArray ? [] : '';
3835
awaitPromise.race([errorHandler,Promise.resolve()]);
3936
// If no mapFn, return the value. If there is a mapFn, use it to make a Set to
4037
// return.
4138
forawait(constlineoflines){
4239
awaitPromise.race([errorHandler,Promise.resolve()]);
43-
if(options.mapFn){
44-
constval=options.mapFn(line);
45-
if(val){
46-
returnValue.add(val);
47-
}
40+
if(options.returnAsArray){
41+
returnValue.push(line);
4842
}else{
4943
returnValue+=line;
5044
}
@@ -60,6 +54,13 @@ async function getTscFromReadme() {
6054
constreturnedArray=[];
6155
letfoundTscHeading=false;
6256
forawait(constlineofreadmeText){
57+
// Until three votes have passed from March 16, 2023, we will need this.
58+
// After that point, we can use this for setting `foundTscHeading` below
59+
// and remove this.
60+
if(line==='#### TSC voting members'){
61+
continue;
62+
}
63+
6364
// If we've found the TSC heading already, stop processing at the next
6465
// heading.
6566
if(foundTscHeading&&line.startsWith('#')){
@@ -84,36 +85,6 @@ async function getTscFromReadme() {
8485
returnreturnedArray;
8586
}
8687

87-
asyncfunctiongetAttendance(tscMembers,meetings){
88-
constattendance={};
89-
for(constmemberoftscMembers){
90-
attendance[member]=0;
91-
}
92-
for(constmeetingofmeetings){
93-
// Get the file contents.
94-
constmeetingFile=
95-
awaitfs.promises.readFile(path.join('.tmp',meeting),'utf8');
96-
// Extract the attendee list.
97-
conststartMarker='## Present';
98-
conststart=meetingFile.indexOf(startMarker)+startMarker.length;
99-
constend=meetingFile.indexOf('## Agenda');
100-
meetingFile.substring(start,end).trim().split('\n')
101-
.map((line)=>{
102-
constmatch=line.match(/@(\S+)/);
103-
if(match){
104-
returnmatch[1];
105-
}
106-
// Using `console.warn` so that stdout output is not generated.
107-
// The stdout output is consumed in find-inactive-tsc.yml.
108-
console.warn(`Attendee entry does not contain GitHub handle: ${line}`);
109-
return'';
110-
})
111-
.filter((handle)=>tscMembers.includes(handle))
112-
.forEach((handle)=>{attendance[handle]++;});
113-
}
114-
returnattendance;
115-
}
116-
11788
asyncfunctiongetVotingRecords(tscMembers,votes){
11889
constvotingRecords={};
11990
for(constmemberoftscMembers){
@@ -122,7 +93,7 @@ async function getVotingRecords(tscMembers, votes) {
12293
for(constvoteofvotes){
12394
// Get the vote data.
12495
constvoteData=JSON.parse(
125-
awaitfs.promises.readFile(path.join('.tmp',vote),'utf8'),
96+
awaitfs.promises.readFile(path.join('.tmp/votes',vote),'utf8'),
12697
);
12798
for(constmemberinvoteData.votes){
12899
if(tscMembers.includes(member)){
@@ -133,22 +104,22 @@ async function getVotingRecords(tscMembers, votes) {
133104
returnvotingRecords;
134105
}
135106

136-
asyncfunctionmoveTscToEmeritus(peopleToMove){
107+
asyncfunctionmoveVotingToRegular(peopleToMove){
137108
constreadmeText=readline.createInterface({
138109
input: fs.createReadStream(newURL('../README.md',import.meta.url)),
139110
crlfDelay: Infinity,
140111
});
141112
letfileContents='';
142-
letinTscSection=false;
143-
letinTscEmeritusSection=false;
113+
letinTscVotingSection=false;
114+
letinTscRegularSection=false;
144115
letmemberFirstLine='';
145116
consttextToMove=[];
146117
letmoveToInactive=false;
147118
forawait(constlineofreadmeText){
148-
// If we've been processing TSC emeriti and we reach the end of
119+
// If we've been processing TSC regular members and we reach the end of
149120
// the list, print out the remaining entries to be moved because they come
150121
// alphabetically after the last item.
151-
if(inTscEmeritusSection&&line===''&&
122+
if(inTscRegularSection&&line===''&&
152123
fileContents.endsWith('>\n')){
153124
while(textToMove.length){
154125
fileContents+=textToMove.pop();
@@ -158,21 +129,21 @@ async function moveTscToEmeritus(peopleToMove) {
158129
// If we've found the TSC heading already, stop processing at the
159130
// next heading.
160131
if(line.startsWith('#')){
161-
inTscSection=false;
162-
inTscEmeritusSection=false;
132+
inTscVotingSection=false;
133+
inTscRegularSection=false;
163134
}
164135

165-
constisTsc=inTscSection&&line.length;
166-
constisTscEmeritus=inTscEmeritusSection&&line.length;
136+
constisTscVoting=inTscVotingSection&&line.length;
137+
constisTscRegular=inTscRegularSection&&line.length;
167138

168-
if(line==='### TSC (Technical Steering Committee)'){
169-
inTscSection=true;
139+
if(line==='#### TSC voting members'){
140+
inTscVotingSection=true;
170141
}
171-
if(line==='### TSC emeriti'){
172-
inTscEmeritusSection=true;
142+
if(line==='#### TSC regular members'){
143+
inTscRegularSection=true;
173144
}
174145

175-
if(isTsc){
146+
if(isTscVoting){
176147
if(line.startsWith('* ')){
177148
memberFirstLine=line;
178149
constmatch=line.match(/^\*\[([^\]]+)/);
@@ -191,7 +162,7 @@ async function moveTscToEmeritus(peopleToMove) {
191162
}
192163
}
193164

194-
if(isTscEmeritus){
165+
if(isTscRegular){
195166
if(line.startsWith('* ')){
196167
memberFirstLine=line;
197168
}elseif(line.startsWith(' **')){
@@ -207,79 +178,62 @@ async function moveTscToEmeritus(peopleToMove) {
207178
}
208179
}
209180

210-
if(!isTsc&&!isTscEmeritus){
181+
if(!isTscVoting&&!isTscRegular){
211182
fileContents+=`${line}\n`;
212183
}
213184
}
214185

215186
returnfileContents;
216187
}
217188

218-
// Get current TSC members, then get TSC members at start of period. Only check
219-
// TSC members who are on both lists. This way, we don't flag someone who has
220-
// only been on the TSC for a week and therefore hasn't attended any meetings.
189+
// Get current TSC voting members, then get TSC voting members at start of
190+
// period. Only check TSC voting members who are on both lists. This way, we
191+
// don't flag someone who hasn't been on the TSC long enough to have missed 3
192+
// consecutive votes.
221193
consttscMembersAtEnd=awaitgetTscFromReadme();
222194

223-
conststartCommit=awaitrunGitCommand(`git rev-list -1 --before '${SINCE}' HEAD`);
224-
awaitrunGitCommand(`git checkout ${startCommit} -- README.md`);
225-
consttscMembersAtStart=awaitgetTscFromReadme();
226-
awaitrunGitCommand('git reset HEAD README.md');
227-
awaitrunGitCommand('git checkout -- README.md');
228-
229-
consttscMembers=tscMembersAtEnd.filter(
230-
(memberAtEnd)=>tscMembersAtStart.includes(memberAtEnd),
231-
);
232-
233-
// Get all meetings since SINCE.
195+
// Get the last three votes.
234196
// Assumes that the TSC repo is cloned in the .tmp dir.
235-
constmeetings=awaitrunGitCommand(
236-
`git whatchanged --since '${SINCE}' --name-only --pretty=format: meetings`,
237-
{cwd: '.tmp',mapFn: (line)=>line},
197+
constvotes=awaitrunShellCommand(
198+
'ls *.json | sort -rn | head -3',
199+
{cwd: '.tmp/votes',returnAsArray: true},
238200
);
239201

240-
// Get TSC meeting attendance.
241-
constattendance=awaitgetAttendance(tscMembers,meetings);
242-
constlightAttendance=tscMembers.filter(
243-
(member)=>attendance[member]<meetings.size*0.25,
244-
);
202+
// Reverse the votes list so the oldest of the three votes is first.
203+
votes.reverse();
245204

246-
// Get all votes since SINCE.
247-
// Assumes that the TSC repo is cloned in the .tmp dir.
248-
constvotes=awaitrunGitCommand(
249-
`git whatchanged --since '${SINCE}' --name-only --pretty=format: votes/*.json`,
250-
{cwd: '.tmp',mapFn: (line)=>line},
205+
conststartCommit=awaitrunShellCommand(`git rev-list -1 --before '${votes[0]}' HEAD`);
206+
awaitrunShellCommand(`git checkout ${startCommit} -- README.md`);
207+
consttscMembersAtStart=awaitgetTscFromReadme();
208+
awaitrunShellCommand('git reset HEAD README.md');
209+
awaitrunShellCommand('git checkout -- README.md');
210+
211+
consttscMembers=tscMembersAtEnd.filter(
212+
(memberAtEnd)=>tscMembersAtStart.includes(memberAtEnd),
251213
);
252214

253215
// Check voting record.
254216
constvotingRecords=awaitgetVotingRecords(tscMembers,votes);
255-
constnoVotes=tscMembers.filter(
217+
constinactive=tscMembers.filter(
256218
(member)=>votingRecords[member]===0,
257219
);
258220

259-
constinactive=lightAttendance.filter((member)=>noVotes.includes(member));
260-
261221
if(inactive.length){
262222
// The stdout output is consumed in find-inactive-tsc.yml. If format of output
263223
// changes, find-inactive-tsc.yml may need to be updated.
264224
console.log(`INACTIVE_TSC_HANDLES=${inactive.map((entry)=>'@'+entry).join(' ')}`);
265-
constcommitDetails=inactive.map((entry)=>{
266-
letdetails=`Since ${SINCE}, `;
267-
details+=`${entry} attended ${attendance[entry]} out of ${meetings.size} meetings`;
268-
details+=` and voted in ${votingRecords[entry]} of ${votes.size} votes.`;
269-
returndetails;
270-
});
271-
console.log(`DETAILS_FOR_COMMIT_BODY=${commitDetails.join(' ')}`);
225+
constcommitDetails=`${inactive.join(' ')} did not participate in three consecutive TSC votes: ${votes.join(' ')}`;
226+
console.log(`DETAILS_FOR_COMMIT_BODY=${commitDetails}`);
272227

273228
if(process.env.GITHUB_ACTIONS){
274229
// Using console.warn() to avoid messing with find-inactive-tsc which
275230
// consumes stdout.
276231
console.warn('Generating new README.md file...');
277-
constnewReadmeText=awaitmoveTscToEmeritus(inactive);
232+
constnewReadmeText=awaitmoveVotingToRegular(inactive);
278233
fs.writeFileSync(newURL('../README.md',import.meta.url),newReadmeText);
279234
}
280235
}
281236

282237
if(verbose){
283-
console.log(attendance);
284238
console.log(votingRecords);
285239
}

0 commit comments

Comments
 (0)