@@ -10,7 +10,7 @@ const octokit = new Octokit({
10
10
/**
11
11
* This script is used to filter and group commits by teams based on unique commit messages.
12
12
* It takes two branches as input and generates a CSV file with the commit message, author,PR link, team,release tag and commit hash
13
- * The teams and their members are defined in the 'authorTeams' object .
13
+ * The teams and their members are defined in the 'teams.json' file .
14
14
*
15
15
* Command to run the script: node development/generate-rc-commits.js origin/branchA origin/branchB
16
16
*
@@ -19,96 +19,24 @@ const octokit = new Octokit({
19
19
* Output: the generated commits will be in a file named 'commits.csv'.
20
20
*/
21
21
22
- // JSON mapping authors to teams
23
- const authorTeams = {
24
- Accounts : [
25
- 'Owen Craston' ,
26
- 'Gustavo Antunes' ,
27
- 'Monte Lai' ,
28
- 'Daniel Rocha' ,
29
- 'Howard Braham' ,
30
- 'Kate Johnson' ,
31
- 'Xiaoming Wang' ,
32
- 'Charly Chevalier' ,
33
- 'Mike B' ,
34
- ] ,
35
- 'Wallet UX' : [ 'David Walsh' , 'Nidhi Kumari' , 'Jony Bursztyn' ] ,
36
- 'Extension Platform' : [
37
- 'chloeYue' ,
38
- 'Chloe Gao' ,
39
- 'danjm' ,
40
- 'Danica Shen' ,
41
- 'Brad Decker' ,
42
- 'hjetpoluru' ,
43
- 'Harika Jetpoluru' ,
44
- 'Marina Boboc' ,
45
- 'Gauthier Petetin' ,
46
- 'Dan Miller' ,
47
- 'Dan J Miller' ,
48
- 'David Murdoch' ,
49
- 'Niranjana Binoy' ,
50
- 'Victor Thomas' ,
51
- 'vthomas13' ,
52
- 'seaona' ,
53
- 'Norbert Elter' ,
54
- ] ,
55
- 'Wallet API' : [ 'tmashuang' , 'jiexi' , 'BelfordZ' , 'Shane' ] ,
56
- Confirmations : [
57
- 'Pedro Figueiredo' ,
58
- 'Sylva Elendu' ,
59
- 'Olusegun Akintayo' ,
60
- 'Jyoti Puri' ,
61
- 'Ariella Vu' ,
62
- 'OGPoyraz' ,
63
- 'vinistevam' ,
64
- 'Matthew Walsh' ,
65
- 'cryptotavares' ,
66
- 'Vinicius Stevam' ,
67
- 'Derek Brans' ,
68
- 'sleepytanya' ,
69
- 'Priya' ,
70
- ] ,
71
- 'Design Systems' : [
72
- 'georgewrmarshall' ,
73
- 'Garrett Bear' ,
74
- 'George Marshall' ,
75
- 'Devin' ,
76
- ] ,
77
- Snaps : [
78
- 'David Drazic' ,
79
- 'hmalik88' ,
80
- 'Montoya' ,
81
- 'Mrtenz' ,
82
- 'Frederik Bolding' ,
83
- 'Bowen Sanders' ,
84
- 'Guillaume Roux' ,
85
- 'Hassan Malik' ,
86
- 'Maarten Zuidhoorn' ,
87
- 'Jonathan Ferreira' ,
88
- ] ,
89
- Assets : [ 'salimtb' , 'sahar-fehri' , 'Brian Bergeron' ] ,
90
- Linea : [ 'VGau' , 'Victorien Gauch' ] ,
91
- lavamoat : [ 'weizman' , 'legobeat' , 'kumavis' , 'LeoTM' ] ,
92
- 'Wallet Framework' : [
93
- 'Michele Esposito' ,
94
- 'Elliot Winkler' ,
95
- 'Gudahtt' ,
96
- 'Jongsun Suh' ,
97
- 'Mark Stacey' ,
98
- ] ,
99
- MMI : [
100
- 'António Regadas' ,
101
- 'Albert Olivé' ,
102
- 'Ramon AC' ,
103
- 'Shane T' ,
104
- 'Bernardo Garces Chapero' ,
105
- ] ,
106
- Swaps : [ 'Daniel' , 'Davide Brocchetto' , 'Nicolas Ferro' , 'infiniteflower' ] ,
107
- Devex : [ 'Thomas Huang' , 'Alex Donesky' , 'jiexi' , 'Zachary Belford' ] ,
108
- Notifications : [ 'Prithpal-Sooriya' , 'Matteo Scurati' , 'Prithpal Sooriya' ] ,
109
- Bridging : [ 'Bilal' , 'micaelae' , 'Ethan Wessel' ] ,
110
- Ramps : [ 'George Weiler' ] ,
111
- } ;
22
+ // Function to fetch author teams mapping file from teams.json
23
+ async function fetchAuthorTeamsFile ( ) {
24
+ try {
25
+ const { data } = await octokit . request (
26
+ 'GET /repos/{owner}/{repo}/contents/{path}' ,
27
+ {
28
+ owner : 'MetaMask' ,
29
+ repo : 'MetaMask-planning' ,
30
+ path : 'teams.json' ,
31
+ } ,
32
+ ) ;
33
+ const content = Buffer . from ( data . content , 'base64' ) . toString ( 'utf-8' ) ;
34
+ return JSON . parse ( content ) ; // Assuming the file is in JSON format
35
+ } catch ( error ) {
36
+ console . error ( 'Error fetching author teams mapping file:' , error ) ;
37
+ return { } ;
38
+ }
39
+ }
112
40
113
41
// Function to get PR labels
114
42
async function getPRLabels ( owner , repo , prNumber ) {
@@ -129,18 +57,26 @@ async function getPRLabels(owner, repo, prNumber) {
129
57
}
130
58
}
131
59
132
- // Function to get the team for a given author
133
- function getTeamForAuthor ( authorName ) {
134
- for ( const [ team , authors ] of Object . entries ( authorTeams ) ) {
135
- if ( authors . includes ( authorName ) ) {
136
- return team ;
137
- }
60
+ // Function to get the GitHub username for a given commit hash
61
+ async function getGitHubUsername ( commitHash ) {
62
+ try {
63
+ const { data } = await octokit . request (
64
+ 'GET /repos/{owner}/{repo}/commits/{ref}' ,
65
+ {
66
+ owner : 'MetaMask' ,
67
+ repo : 'metamask-extension' ,
68
+ ref : commitHash ,
69
+ } ,
70
+ ) ;
71
+ return data . author ? data . author . login : null ;
72
+ } catch ( error ) {
73
+ console . error ( 'Error fetching GitHub username:' , error ) ;
74
+ return null ;
138
75
}
139
- return 'Other/Unknown' ; // Default team for unknown authors
140
76
}
141
77
142
78
// Function to filter commits based on unique commit messages and group by teams
143
- async function filterCommitsByTeam ( branchA , branchB ) {
79
+ async function filterCommitsByTeam ( branchA , branchB , authorTeams ) {
144
80
try {
145
81
const git = simpleGit ( ) ;
146
82
@@ -157,17 +93,27 @@ async function filterCommitsByTeam(branchA, branchB) {
157
93
const log = await git . log ( logOptions ) ;
158
94
const seenMessages = new Set ( ) ;
159
95
const commitsByTeam = { } ;
96
+ let processedCommits = 0 ;
160
97
161
98
const MAX_COMMITS = 500 ; // Limit the number of commits to process
99
+
162
100
console . log ( 'Generation of the CSV file "commits.csv" is in progress...' ) ;
163
101
164
102
for ( const commit of log . all ) {
165
- const { author, message, hash } = commit ;
166
- if ( commitsByTeam . length >= MAX_COMMITS ) {
103
+ if ( processedCommits >= MAX_COMMITS ) {
167
104
break ;
168
105
}
169
106
170
- const team = getTeamForAuthor ( author ) ;
107
+ const { author, message, hash } = commit ;
108
+ const githubUsername = await getGitHubUsername ( hash ) ;
109
+ let team = authorTeams [ githubUsername ] || 'Other/Unknown' ;
110
+
111
+ // Format the team label
112
+ team = team
113
+ . replace ( / ^ t e a m - / u, '' ) // Remove the "team-" prefix
114
+ . split ( '-' ) // Split the string into an array of words
115
+ . map ( ( word ) => word . charAt ( 0 ) . toUpperCase ( ) + word . slice ( 1 ) ) // Capitalize the first letter of each word
116
+ . join ( ' ' ) ; // Join the words back into a string with spaces
171
117
172
118
// Extract PR number from the commit message using regex
173
119
const prMatch = message . match ( / \( # ( \d + ) \) / u) ;
@@ -206,9 +152,9 @@ async function filterCommitsByTeam(branchA, branchB) {
206
152
releaseLabel,
207
153
hash : hash . substring ( 0 , 10 ) ,
208
154
} ) ;
155
+ processedCommits += 1 ;
209
156
}
210
157
}
211
-
212
158
return commitsByTeam ;
213
159
} catch ( error ) {
214
160
console . error ( error ) ;
@@ -233,7 +179,7 @@ function formatAsCSV(commitsByTeam) {
233
179
} ) ;
234
180
}
235
181
csvContent . unshift (
236
- 'Commit Message,Author,PR Link,Team,Release Label, Commit Hash' ,
182
+ 'Commit Message,Author,PR Link,Team,Release Label,Commit Hash' ,
237
183
) ;
238
184
239
185
return csvContent ;
@@ -250,7 +196,14 @@ async function main() {
250
196
const branchA = args [ 0 ] ;
251
197
const branchB = args [ 1 ] ;
252
198
253
- const commitsByTeam = await filterCommitsByTeam ( branchA , branchB ) ;
199
+ // Fetch author teams mapping from the teams.json file
200
+ const authorTeams = await fetchAuthorTeamsFile ( ) ;
201
+
202
+ const commitsByTeam = await filterCommitsByTeam (
203
+ branchA ,
204
+ branchB ,
205
+ authorTeams ,
206
+ ) ;
254
207
255
208
if ( Object . keys ( commitsByTeam ) . length === 0 ) {
256
209
console . log ( 'No unique commits found.' ) ;
0 commit comments