@@ -22,6 +22,7 @@ const AUTOMATED_TEST_PATTERNS = [
2222 / ( ^ | \/ ) e 2 e \/ / ,
2323 / ( ^ | \/ ) w d i o \/ /
2424] ;
25+ const SKIP_RELEASE_VALIDATION_LABEL = 'skip-release-validation' ;
2526
2627if ( ! githubToken ) throw new Error ( 'Missing GITHUB_TOKEN env var' ) ;
2728if ( ! spreadsheetId ) throw new Error ( 'Missing SHEET_ID env var' ) ;
@@ -223,7 +224,7 @@ async function readRows(authClient, title) {
223224 const res = await sheets . spreadsheets . values . get ( {
224225 spreadsheetId,
225226 auth : authClient ,
226- range : `${ title } !A3:H ` ,
227+ range : `${ title } !A3:J ` ,
227228 } ) ;
228229 return res . data . values || [ ] ;
229230 } catch ( e ) {
@@ -237,7 +238,7 @@ async function appendRows(authClient, title, rows) {
237238 await sheets . spreadsheets . values . append ( {
238239 spreadsheetId,
239240 auth : authClient ,
240- range : `${ title } !A4:H ` ,
241+ range : `${ title } !A4:J ` ,
241242 valueInputOption : 'USER_ENTERED' ,
242243 insertDataOption : 'INSERT_ROWS' ,
243244 requestBody : { values : rows } ,
@@ -384,6 +385,73 @@ function splitByReleaseAndTitle(items) {
384385 return { relevant, skippedByTitle } ;
385386}
386387
388+ function getAutoSkipLabelsForPR ( labels , repoName ) {
389+ const labelNames = ( labels || [ ] ) . map ( ( label ) => label . name ) . filter ( Boolean ) ;
390+ const hasSkipAll = labelNames . includes ( SKIP_RELEASE_VALIDATION_LABEL ) ;
391+
392+ const granularLabels = labelNames . filter ( ( name ) =>
393+ / ^ s k i p - r e l e a s e - v a l i d a t i o n \[ ( a n d r o i d | i o s | d e s i g n | c h r o m e | f i r e f o x ) \] $ / i. test ( name ) ,
394+ ) ;
395+
396+ const lowerRepoName = String ( repoName || '' ) . toLowerCase ( ) ;
397+ const isMobile = lowerRepoName . endsWith ( '-mobile' ) ;
398+ const isExtension = lowerRepoName . endsWith ( '-extension' ) ;
399+
400+ const validGranularLabels = granularLabels . filter ( ( name ) => {
401+ const target = name . toLowerCase ( ) ;
402+ if ( isMobile && ( target . includes ( '[chrome]' ) || target . includes ( '[firefox]' ) ) ) {
403+ return false ;
404+ }
405+ if ( isExtension && ( target . includes ( '[android]' ) || target . includes ( '[ios]' ) ) ) {
406+ return false ;
407+ }
408+ return true ;
409+ } ) ;
410+
411+ return {
412+ hasSkipAll,
413+ validLabels : validGranularLabels ,
414+ } ;
415+ }
416+
417+ function applyAutoSkipToRow ( row , labels , repoName ) {
418+
419+ const { hasSkipAll, validLabels } = getAutoSkipLabelsForPR ( labels , repoName ) ;
420+ if ( ! hasSkipAll && validLabels . length === 0 ) {
421+ return row ;
422+ }
423+
424+ const updatedRow = [ ...row ] ;
425+ const validLabelSet = new Set ( validLabels . map ( ( label ) => label . toLowerCase ( ) ) ) ;
426+ const isMobile = String ( repoName || '' ) . toLowerCase ( ) . endsWith ( '-mobile' ) ;
427+
428+ const shouldSkipFirstValidated =
429+ hasSkipAll ||
430+ validLabelSet . has ( 'skip-release-validation[design]' ) ||
431+ validLabelSet . has ( isMobile ? 'skip-release-validation[android]' : 'skip-release-validation[chrome]' ) ;
432+ const shouldSkipSecondValidated =
433+ hasSkipAll ||
434+ validLabelSet . has ( 'skip-release-validation[design]' ) ||
435+ validLabelSet . has ( isMobile ? 'skip-release-validation[ios]' : 'skip-release-validation[firefox]' ) ;
436+
437+ if ( shouldSkipFirstValidated ) {
438+ updatedRow [ 6 ] = 'Skipped' ;
439+ }
440+ if ( shouldSkipSecondValidated ) {
441+ updatedRow [ 7 ] = 'Skipped' ;
442+ }
443+
444+ const labelsForComment = hasSkipAll
445+ ? [ SKIP_RELEASE_VALIDATION_LABEL , ...validLabels ]
446+ : validLabels ;
447+
448+ if ( shouldSkipFirstValidated || shouldSkipSecondValidated ) {
449+ updatedRow [ 9 ] = `Release validation automatically skipped due to PR labels: ${ labelsForComment . join ( ', ' ) } ` ;
450+ }
451+
452+ return updatedRow ;
453+ }
454+
387455// Add efficient version detection with caching
388456let versionCache = new Map ( ) ; // Cache version bumps per repo
389457
@@ -538,6 +606,10 @@ async function buildTabGrouping(owner, repo, relevantItems, sinceDateISO) {
538606 for ( const pr of prs ) {
539607 // Check if PR modifies automated test files
540608 const automatedTestsModified = await checkAutomatedTestFiles ( owner , repo , pr . number ) ;
609+ const validatedA = '' ;
610+ const validatedB = '' ;
611+ const designValidation = '' ;
612+ const comments = '' ;
541613
542614 const row = [
543615 makePrHyperlinkCell ( pr . html_url , pr . title , pr . number ) ,
@@ -546,10 +618,16 @@ async function buildTabGrouping(owner, repo, relevantItems, sinceDateISO) {
546618 extractSize ( pr . labels || [ ] ) ,
547619 automatedTestsModified ,
548620 extractTeam ( pr . labels || [ ] ) ,
549- '' ,
550- '' ,
621+ validatedA ,
622+ validatedB ,
623+ designValidation ,
624+ comments ,
551625 ] ;
552- tabToRows . get ( title ) . entries . push ( { row, mergedAtIso : pr . closed_at || '' } ) ;
626+ tabToRows . get ( title ) . entries . push ( {
627+ row,
628+ mergedAtIso : pr . closed_at || '' ,
629+ labels : pr . labels || [ ] ,
630+ } ) ;
553631 }
554632 }
555633
@@ -736,7 +814,7 @@ async function processTab(authClient, title, entries, platformType) {
736814 const sortedRows = entries
737815 . slice ( )
738816 . sort ( ( a , b ) => new Date ( a . mergedAtIso ) - new Date ( b . mergedAtIso ) )
739- . map ( ( e ) => e . row ) ;
817+ . map ( ( e ) => applyAutoSkipToRow ( e . row , e . labels , repo ) ) ;
740818 const deduped = [ ] ;
741819 for ( const r of sortedRows ) {
742820 const num = parsePrNumberFromCell ( r [ 0 ] ) ;
@@ -830,4 +908,4 @@ async function main() {
830908main ( ) . catch ( ( e ) => {
831909 console . error ( e ) ;
832910 process . exit ( 1 ) ;
833- } ) ;
911+ } ) ;
0 commit comments