@@ -20,9 +20,11 @@ type ReviewReport = {
2020 usersToRequest ?: string [ ] ;
2121 /** If applicable, the missing minimum fellows rank required to review */
2222 missingRank ?: number ;
23+ /** If applicable, reviews that count towards this rule */
24+ countingReviews : string [ ] ;
2325} ;
2426
25- export type RuleReport = { name : string } & ReviewReport ;
27+ export type RuleReport = { name : string ; type : RuleTypes } & ReviewReport ;
2628
2729type ReviewState = [ true ] | [ false , ReviewReport ] ;
2830
@@ -96,7 +98,7 @@ export class ActionRunner {
9698 const [ result , missingData ] = await this . evaluateCondition ( rule , rule . countAuthor ) ;
9799 if ( ! result ) {
98100 this . logger . error ( `Missing the reviews from ${ JSON . stringify ( missingData . missingUsers ) } ` ) ;
99- errorReports . push ( { ...missingData , name : rule . name } ) ;
101+ errorReports . push ( { ...missingData , name : rule . name , type : rule . type } ) ;
100102 }
101103
102104 break ;
@@ -112,7 +114,7 @@ export class ActionRunner {
112114 }
113115 }
114116 if ( reports . length > 0 ) {
115- const finalReport = unifyReport ( reports , rule . name ) ;
117+ const finalReport = unifyReport ( reports , rule . name , rule . type ) ;
116118 this . logger . error ( `Missing the reviews from ${ JSON . stringify ( finalReport . missingUsers ) } ` ) ;
117119 errorReports . push ( finalReport ) ;
118120 }
@@ -139,7 +141,7 @@ export class ActionRunner {
139141 . reduce ( ( a , b ) => ( a < b ? a : b ) , 999 ) ;
140142 // We get the lowest rank required
141143 // We unify the reports
142- const finalReport = unifyReport ( reports , rule . name ) ;
144+ const finalReport = unifyReport ( reports , rule . name , rule . type ) ;
143145 // We set the value to the minimum neccesary
144146 finalReport . missingReviews = lowerAmountOfReviewsNeeded ;
145147 this . logger . error ( `Missing the reviews from ${ JSON . stringify ( finalReport . missingUsers ) } ` ) ;
@@ -152,15 +154,15 @@ export class ActionRunner {
152154 const [ result , missingData ] = await this . andDistinctEvaluation ( rule ) ;
153155 if ( ! result ) {
154156 this . logger . error ( `Missing the reviews from ${ JSON . stringify ( missingData . missingUsers ) } ` ) ;
155- errorReports . push ( { ...missingData , name : rule . name } ) ;
157+ errorReports . push ( { ...missingData , name : rule . name , type : rule . type } ) ;
156158 }
157159 break ;
158160 }
159161 case RuleTypes . Fellows : {
160162 const [ result , missingData ] = await this . fellowsEvaluation ( rule ) ;
161163 if ( ! result ) {
162164 this . logger . error ( `Missing the reviews from ${ JSON . stringify ( missingData . missingUsers ) } ` ) ;
163- errorReports . push ( { ...missingData , name : rule . name } ) ;
165+ errorReports . push ( { ...missingData , name : rule . name , type : rule . type } ) ;
164166 }
165167 break ;
166168 }
@@ -177,21 +179,27 @@ export class ActionRunner {
177179 return { files : modifiedFiles , reports : errorReports } ;
178180 }
179181
180- /** WIP - Class that will assign the requests for review */
181182 async requestReviewers (
182183 reports : RuleReport [ ] ,
183184 preventReviewRequests : ConfigurationFile [ "preventReviewRequests" ] ,
184185 ) : Promise < void > {
185186 if ( reports . length === 0 ) {
186187 return ;
187188 }
188- const finalReport : ReviewReport = { missingReviews : 0 , missingUsers : [ ] , teamsToRequest : [ ] , usersToRequest : [ ] } ;
189+ const finalReport : ReviewReport = {
190+ missingReviews : 0 ,
191+ missingUsers : [ ] ,
192+ teamsToRequest : [ ] ,
193+ usersToRequest : [ ] ,
194+ countingReviews : [ ] ,
195+ } ;
189196
190197 for ( const report of reports ) {
191198 finalReport . missingReviews += report . missingReviews ;
192199 finalReport . missingUsers = concatArraysUniquely ( finalReport . missingUsers , report . missingUsers ) ;
193200 finalReport . teamsToRequest = concatArraysUniquely ( finalReport . teamsToRequest , report . teamsToRequest ) ;
194201 finalReport . usersToRequest = concatArraysUniquely ( finalReport . usersToRequest , report . usersToRequest ) ;
202+ finalReport . countingReviews = concatArraysUniquely ( finalReport . countingReviews , report . countingReviews ) ;
195203 }
196204
197205 this . logger . debug ( `Request data: ${ JSON . stringify ( finalReport ) } ` ) ;
@@ -243,11 +251,38 @@ export class ActionRunner {
243251 }
244252
245253 for ( const report of reports ) {
254+ const ruleExplanation = ( type : RuleTypes ) => {
255+ switch ( type ) {
256+ case RuleTypes . Basic :
257+ return "Rule 'Basic' requires a given amount of reviews from users/teams" ;
258+ case RuleTypes . And :
259+ return "Rule 'And' has many required reviewers/teams and requires all of them to be fulfilled." ;
260+ case RuleTypes . Or :
261+ return "Rule 'Or' has many required reviewers/teams and requires at least one of them to be fulfilled." ;
262+ case RuleTypes . AndDistinct :
263+ return (
264+ "Rule 'And Distinct' has many required reviewers/teams and requires all of them to be fulfilled **by different users**.\n\n" +
265+ "The approval of one user that belongs to _two teams_ will count only towards one team."
266+ ) ;
267+ case RuleTypes . Fellows :
268+ return "Rule 'Fellows' requires a given amount of reviews from users whose Fellowship ranking is the required rank or great." ;
269+ default :
270+ console . error ( "Out of range for rule type" , type ) ;
271+ return "Unhandled rule" ;
272+ }
273+ } ;
274+
246275 check . output . summary += `- **${ report . name } **\n` ;
247276 let text = summary
248277 . emptyBuffer ( )
249278 . addHeading ( report . name , 2 )
250- . addHeading ( `Missing ${ report . missingReviews } review${ report . missingReviews > 1 ? "s" : "" } ` , 4 ) ;
279+ . addHeading ( `Missing ${ report . missingReviews } review${ report . missingReviews > 1 ? "s" : "" } ` , 4 )
280+ . addDetails (
281+ "Rule explanation" ,
282+ `${ ruleExplanation (
283+ report . type ,
284+ ) } \n\nFor more info found out how the rules work in [Review-bot types](https://github.com/paritytech/review-bot#types)`,
285+ ) ;
251286 if ( report . usersToRequest && report . usersToRequest . length > 0 ) {
252287 text = text
253288 . addHeading ( "Missing users" , 3 )
@@ -263,6 +298,13 @@ export class ActionRunner {
263298 . addRaw ( `Missing reviews from rank \`${ report . missingRank } \` or above` )
264299 . addEOL ( ) ;
265300 }
301+ if ( report . countingReviews . length > 0 ) {
302+ text = text
303+ . addHeading ( "Users approvals that counted towards this rule" , 3 )
304+ . addEOL ( )
305+ . addList ( report . countingReviews )
306+ . addEOL ( ) ;
307+ }
266308
267309 check . output . text += text . stringify ( ) + "\n" ;
268310 }
@@ -289,6 +331,8 @@ export class ActionRunner {
289331 // We get the list of users that approved the PR
290332 const approvals = await this . prApi . listApprovedReviewsAuthors ( rule . countAuthor ?? false ) ;
291333
334+ let countingReviews : string [ ] = [ ] ;
335+
292336 // Utility method used to generate error
293337 const generateErrorReport = ( ) : ReviewReport => {
294338 const filterMissingUsers = ( reviewData : { users ?: string [ ] } [ ] ) : string [ ] =>
@@ -301,6 +345,7 @@ export class ActionRunner {
301345 missingUsers : filterMissingUsers ( requirements ) ,
302346 teamsToRequest : rule . reviewers . flatMap ( ( r ) => r . teams ?? [ ] ) ,
303347 usersToRequest : filterMissingUsers ( rule . reviewers ) ,
348+ countingReviews,
304349 } ;
305350 } ;
306351
@@ -327,6 +372,8 @@ export class ActionRunner {
327372 }
328373 this . logger . debug ( `Matching approvals: ${ JSON . stringify ( conditionApprovals ) } ` ) ;
329374
375+ countingReviews = [ ...new Set ( conditionApprovals . flatMap ( ( { matchingUsers } ) => matchingUsers ) ) ] ;
376+
330377 // If one of the rules doesn't have the required approval we fail the evaluation
331378 if ( conditionApprovals . some ( ( cond ) => cond . matchingUsers . length === 0 ) ) {
332379 this . logger . warn ( "One of the groups does not have any approvals" ) ;
@@ -421,12 +468,16 @@ export class ActionRunner {
421468 const approvals = await this . prApi . listApprovedReviewsAuthors ( countAuthor ?? false ) ;
422469 this . logger . info ( `Found ${ approvals . length } approvals.` ) ;
423470
471+ // List of user reviews which fulfill this rule
472+ const countingReviews : string [ ] = [ ] ;
473+
424474 // This is the amount of reviews required. To succeed this should be 0 or lower
425475 let missingReviews = rule . minApprovals ;
426476 for ( const requiredUser of requiredUsers ) {
427477 // We check for the approvals, if it is a required reviewer we lower the amount of missing reviews
428478 if ( approvals . indexOf ( requiredUser ) > - 1 ) {
429479 missingReviews -- ;
480+ countingReviews . push ( requiredUser ) ;
430481 }
431482 }
432483
@@ -444,6 +495,7 @@ export class ActionRunner {
444495 missingUsers : requiredUsers . filter ( ( u ) => approvals . indexOf ( u ) < 0 ) . filter ( ( u ) => u !== author ) ,
445496 teamsToRequest : rule . teams ? rule . teams : undefined ,
446497 usersToRequest : rule . users ? rule . users . filter ( ( u ) => approvals . indexOf ( u ) ) : undefined ,
498+ countingReviews,
447499 } ,
448500 ] ;
449501 } else {
@@ -472,12 +524,16 @@ export class ActionRunner {
472524 const approvals = await this . prApi . listApprovedReviewsAuthors ( rule . countAuthor ?? false ) ;
473525 this . logger . info ( `Found ${ approvals . length } approvals.` ) ;
474526
527+ // List of user reviews which fulfill this rule
528+ const countingReviews : string [ ] = [ ] ;
529+
475530 // This is the amount of reviews required. To succeed this should be 0 or lower
476531 let missingReviews = rule . minApprovals ;
477532 for ( const requiredUser of requiredUsers ) {
478533 // We check for the approvals, if it is a required reviewer we lower the amount of missing reviews
479534 if ( approvals . indexOf ( requiredUser ) > - 1 ) {
480535 missingReviews -- ;
536+ countingReviews . push ( requiredUser ) ;
481537 }
482538 }
483539
@@ -494,6 +550,7 @@ export class ActionRunner {
494550 // Remove all the users who approved the PR + the author (if he belongs to the group)
495551 missingUsers : requiredUsers . filter ( ( u ) => approvals . indexOf ( u ) < 0 ) . filter ( ( u ) => u !== author ) ,
496552 missingRank : rule . minRank ,
553+ countingReviews,
497554 } ,
498555 ] ;
499556 } else {
@@ -589,7 +646,7 @@ const getRequiredRanks = (reports: Pick<ReviewReport, "missingRank">[]): number[
589646 }
590647} ;
591648
592- const unifyReport = ( reports : ReviewReport [ ] , name : string ) : RuleReport => {
649+ const unifyReport = ( reports : ReviewReport [ ] , name : string , type : RuleTypes ) : RuleReport => {
593650 const ranks = getRequiredRanks ( reports ) ;
594651 const missingRank = ranks ? Math . max ( ...( ranks as number [ ] ) ) : undefined ;
595652
@@ -599,6 +656,8 @@ const unifyReport = (reports: ReviewReport[], name: string): RuleReport => {
599656 teamsToRequest : [ ...new Set ( reports . flatMap ( ( r ) => r . teamsToRequest ?? [ ] ) ) ] ,
600657 usersToRequest : [ ...new Set ( reports . flatMap ( ( r ) => r . usersToRequest ?? [ ] ) ) ] ,
601658 name,
659+ type,
602660 missingRank,
661+ countingReviews : [ ...new Set ( reports . flatMap ( ( r ) => r . countingReviews ) ) ] ,
603662 } ;
604663} ;
0 commit comments