@@ -24,7 +24,7 @@ class Settings {
2424 }
2525 }
2626
27- static async syncSubOrgs ( nop , context , suborg , repo , config , ref ) {
27+ static async syncSubOrgs ( nop , context , suborg , repo , config , ref ) {
2828 const settings = new Settings ( nop , context , repo , config , ref , suborg )
2929 try {
3030 await settings . loadConfigs ( )
@@ -36,7 +36,7 @@ class Settings {
3636 }
3737 }
3838
39- static async sync ( nop , context , repo , config , ref ) {
39+ static async sync ( nop , context , repo , config , ref ) {
4040 const settings = new Settings ( nop , context , repo , config , ref )
4141 try {
4242 await settings . loadConfigs ( repo )
@@ -51,13 +51,13 @@ class Settings {
5151 }
5252 }
5353
54- static async handleError ( nop , context , repo , config , ref , nopcommand ) {
54+ static async handleError ( nop , context , repo , config , ref , nopcommand ) {
5555 const settings = new Settings ( nop , context , repo , config , ref )
5656 settings . appendToResults ( [ nopcommand ] )
5757 await settings . handleResults ( )
5858 }
5959
60- constructor ( nop , context , repo , config , ref , suborg ) {
60+ constructor ( nop , context , repo , config , ref , suborg ) {
6161 this . ref = ref
6262 this . context = context
6363 this . installation_id = context . payload . installation . id
@@ -96,7 +96,7 @@ class Settings {
9696 }
9797
9898 // Create a check in the Admin repo for safe-settings.
99- async createCheckRun ( ) {
99+ async createCheckRun ( ) {
100100 const startTime = new Date ( )
101101 let conclusion = 'success'
102102 let details = `Run on: \`${ new Date ( ) . toISOString ( ) } \``
@@ -142,7 +142,7 @@ class Settings {
142142 } )
143143 }
144144
145- logError ( msg ) {
145+ logError ( msg ) {
146146 this . log . error ( msg )
147147 this . errors . push ( {
148148 owner : this . repo . owner ,
@@ -152,7 +152,7 @@ class Settings {
152152 } )
153153 }
154154
155- async handleResults ( ) {
155+ async handleResults ( ) {
156156 const { payload } = this . context
157157
158158 // Create a checkrun if not in nop mode
@@ -226,23 +226,23 @@ class Settings {
226226#### :robot: Safe-Settings config changes detected:
227227
228228${ this . results . reduce ( ( x , y ) => {
229- if ( ! y ) {
230- return x
231- }
232- if ( y . type === 'ERROR' ) {
233- error = true
234- return `${ x }
229+ if ( ! y ) {
230+ return x
231+ }
232+ if ( y . type === 'ERROR' ) {
233+ error = true
234+ return `${ x }
235235<tr><td> ❗ ${ y . action . msg } </td><td> ${ y . plugin } </td><td> ${ prettify ( y . repo ) } </td><td> ${ prettify ( y . action . additions ) } </td><td> ${ prettify ( y . action . deletions ) } </td><td> ${ prettify ( y . action . modifications ) } </td><tr>`
236- } else if ( y . action . additions === null && y . action . deletions === null && y . action . modifications === null ) {
237- return `${ x } `
238- } else {
239- if ( y . action === undefined ) {
240- return `${ x } `
241- }
242- return `${ x }
236+ } else if ( y . action . additions === null && y . action . deletions === null && y . action . modifications === null ) {
237+ return `${ x } `
238+ } else {
239+ if ( y . action === undefined ) {
240+ return `${ x } `
241+ }
242+ return `${ x }
243243<tr><td> ✋ </td><td> ${ y . plugin } </td><td> ${ prettify ( y . repo ) } </td><td> ${ prettify ( y . action . additions ) } </td><td> ${ prettify ( y . action . deletions ) } </td><td> ${ prettify ( y . action . modifications ) } </td><tr>`
244- }
245- } , table ) }
244+ }
245+ } , table ) }
246246`
247247
248248 const pullRequest = payload . check_run . check_suite . pull_requests [ 0 ]
@@ -272,12 +272,12 @@ ${this.results.reduce((x, y) => {
272272 await this . github . checks . update ( params )
273273 }
274274
275- async loadConfigs ( repo ) {
275+ async loadConfigs ( repo ) {
276276 this . subOrgConfigs = await this . getSubOrgConfigs ( )
277277 this . repoConfigs = await this . getRepoConfigs ( repo )
278278 }
279279
280- async updateOrg ( ) {
280+ async updateOrg ( ) {
281281 const rulesetsConfig = this . config . rulesets
282282 if ( rulesetsConfig ) {
283283 const RulesetsPlugin = Settings . PLUGINS . rulesets
@@ -287,7 +287,7 @@ ${this.results.reduce((x, y) => {
287287 }
288288 }
289289
290- async updateRepos ( repo ) {
290+ async updateRepos ( repo ) {
291291 this . subOrgConfigs = this . subOrgConfigs || await this . getSubOrgConfigs ( )
292292 let repoConfig = this . config . repository
293293 if ( repoConfig ) {
@@ -353,15 +353,15 @@ ${this.results.reduce((x, y) => {
353353 }
354354 }
355355
356- async updateAll ( ) {
356+ async updateAll ( ) {
357357 // this.subOrgConfigs = this.subOrgConfigs || await this.getSubOrgConfigs(this.github, this.repo, this.log)
358358 // this.repoConfigs = this.repoConfigs || await this.getRepoConfigs(this.github, this.repo, this.log)
359359 return this . eachRepositoryRepos ( this . github , this . config . restrictedRepos , this . log ) . then ( res => {
360360 this . appendToResults ( res )
361361 } )
362362 }
363363
364- getSubOrgConfig ( repoName ) {
364+ getSubOrgConfig ( repoName ) {
365365 if ( this . subOrgConfigs ) {
366366 for ( const k of Object . keys ( this . subOrgConfigs ) ) {
367367 const repoPattern = new Glob ( k )
@@ -374,13 +374,13 @@ ${this.results.reduce((x, y) => {
374374 }
375375
376376 // Remove Org specific configs from the repo config
377- returnRepoSpecificConfigs ( config ) {
377+ returnRepoSpecificConfigs ( config ) {
378378 const newConfig = Object . assign ( { } , config ) // clone
379379 delete newConfig . rulesets
380380 return newConfig
381381 }
382382
383- childPluginsList ( repo ) {
383+ childPluginsList ( repo ) {
384384 const repoName = repo . repo
385385 const subOrgOverrideConfig = this . getSubOrgConfig ( repoName )
386386 this . log . debug ( `suborg config for ${ repoName } is ${ JSON . stringify ( subOrgOverrideConfig ) } ` )
@@ -412,7 +412,7 @@ ${this.results.reduce((x, y) => {
412412 return childPlugins
413413 }
414414
415- validate ( section , baseConfig , overrideConfig ) {
415+ validate ( section , baseConfig , overrideConfig ) {
416416 const configValidator = this . configvalidators [ section ]
417417 if ( configValidator ) {
418418 this . log . debug ( `Calling configvalidator for key ${ section } ` )
@@ -431,7 +431,7 @@ ${this.results.reduce((x, y) => {
431431 }
432432 }
433433
434- isRestricted ( repoName ) {
434+ isRestricted ( repoName ) {
435435 const restrictedRepos = this . config . restrictedRepos
436436 // Skip configuring any restricted repos
437437 if ( Array . isArray ( restrictedRepos ) ) {
@@ -463,11 +463,11 @@ ${this.results.reduce((x, y) => {
463463 return false
464464 }
465465
466- includesRepo ( repoName , restrictedRepos ) {
466+ includesRepo ( repoName , restrictedRepos ) {
467467 return restrictedRepos . filter ( ( restrictedRepo ) => { return RegExp ( restrictedRepo ) . test ( repoName ) } ) . length > 0
468468 }
469469
470- async eachRepositoryRepos ( github , restrictedRepos , log ) {
470+ async eachRepositoryRepos ( github , restrictedRepos , log ) {
471471 log . debug ( 'Fetching repositories' )
472472 return github . paginate ( 'GET /installation/repositories' ) . then ( repositories => {
473473 return Promise . all ( repositories . map ( repository => {
@@ -488,7 +488,7 @@ ${this.results.reduce((x, y) => {
488488 * @param params Params to fetch the file with
489489 * @return The parsed YAML file
490490 */
491- async loadConfigMap ( params ) {
491+ async loadConfigMap ( params ) {
492492 try {
493493 this . log . debug ( ` In loadConfigMap ${ JSON . stringify ( params ) } ` )
494494 const response = await this . github . repos . getContent ( params ) . catch ( e => {
@@ -535,7 +535,7 @@ ${this.results.reduce((x, y) => {
535535 * @param params Params to fetch the file with
536536 * @return The parsed YAML file
537537 */
538- async getRepoConfigMap ( ) {
538+ async getRepoConfigMap ( ) {
539539 try {
540540 this . log . debug ( ` In getRepoConfigMap ${ JSON . stringify ( this . repo ) } ` )
541541 // GitHub getContent api has a hard limit of returning 1000 entries without
@@ -602,7 +602,7 @@ ${this.results.reduce((x, y) => {
602602 * @param params Params to fetch the file with
603603 * @return The parsed YAML file
604604 */
605- async getSubOrgConfigMap ( ) {
605+ async getSubOrgConfigMap ( ) {
606606 try {
607607 this . log . debug ( ` In getSubOrgConfigMap ${ JSON . stringify ( this . repo ) } ` )
608608 const repo = { owner : this . repo . owner , repo : env . ADMIN_REPO }
@@ -629,7 +629,7 @@ ${this.results.reduce((x, y) => {
629629 * @param {* } repo repo param
630630 * @returns repoConfigs object
631631 */
632- async getRepoConfigs ( repo ) {
632+ async getRepoConfigs ( repo ) {
633633 try {
634634 const overridePaths = await this . getRepoConfigMap ( )
635635 const repoConfigs = { }
@@ -681,7 +681,7 @@ ${this.results.reduce((x, y) => {
681681 * @param params Params to fetch the file with
682682 * @return The parsed YAML file
683683 */
684- async getSubOrgConfigs ( ) {
684+ async getSubOrgConfigs ( ) {
685685 try {
686686 if ( this . subOrgConfigMap ) {
687687 this . log . debug ( `SubOrg config was changed and the associated overridePaths is = ${ JSON . stringify ( this . subOrgConfigMap ) } ` )
@@ -698,7 +698,19 @@ ${this.results.reduce((x, y) => {
698698 subOrgConfigs [ override . name ] = data
699699 if ( data . suborgrepos ) {
700700 data . suborgrepos . forEach ( repository => {
701- subOrgConfigs [ repository ] = data
701+ this . storeSubOrgConfig ( subOrgConfigs , override . path , repository , data )
702+
703+ // In case support for multiple suborg configs for the same repo is required, merge the configs.
704+ //
705+ // Planned for the future to support multiple suborgrepos for the same repo
706+ //
707+ // if (existingConfigForRepo) {
708+ // subOrgConfigs[repository] = this.mergeDeep.mergeDeep({}, existingConfigForRepo, data)
709+ // } else {
710+ // subOrgConfigs[repository] = data
711+ // }
712+
713+ subOrgConfigs [ repository ] = Object . assign ( { } , data , { source : override . path } )
702714 } )
703715 }
704716 if ( data . suborgteams ) {
@@ -708,7 +720,7 @@ ${this.results.reduce((x, y) => {
708720 await Promise . all ( promises ) . then ( res => {
709721 res . forEach ( r => {
710722 r . forEach ( e => {
711- subOrgConfigs [ e . name ] = data
723+ this . storeSubOrgConfig ( subOrgConfigs , override . path , e . name , data )
712724 } )
713725 } )
714726 } )
@@ -720,7 +732,7 @@ ${this.results.reduce((x, y) => {
720732 await Promise . all ( promises ) . then ( res => {
721733 res . forEach ( r => {
722734 r . forEach ( e => {
723- subOrgConfigs [ e . repository_name ] = data
735+ this . storeSubOrgConfig ( subOrgConfigs , override . path , e . repository_name , data )
724736 } )
725737 } )
726738 } )
@@ -739,13 +751,21 @@ ${this.results.reduce((x, y) => {
739751 }
740752 }
741753
754+ storeSubOrgConfig ( subOrgConfigs , overridePath , repoName , data ) {
755+ const existingConfigForRepo = subOrgConfigs [ repoName ]
756+ if ( existingConfigForRepo && existingConfigForRepo . source !== overridePath ) {
757+ throw new Error ( `Multiple suborg configs for ${ repoName } in ${ overridePath } and ${ existingConfigForRepo ?. source } ` )
758+ }
759+ subOrgConfigs [ repoName ] = Object . assign ( { } , data , { source : overridePath } )
760+ }
761+
742762 /**
743763 * Loads a file from GitHub
744764 *
745765 * @param params Params to fetch the file with
746766 * @return The parsed YAML file
747767 */
748- async loadYaml ( filePath ) {
768+ async loadYaml ( filePath ) {
749769 try {
750770 const repo = { owner : this . repo . owner , repo : env . ADMIN_REPO }
751771 const params = Object . assign ( repo , { path : filePath , ref : this . ref } )
@@ -782,13 +802,13 @@ ${this.results.reduce((x, y) => {
782802 }
783803 }
784804
785- appendToResults ( res ) {
805+ appendToResults ( res ) {
786806 if ( this . nop ) {
787807 this . results = this . results . concat ( res . flat ( 3 ) )
788808 }
789809 }
790810
791- async getReposForTeam ( teamslug ) {
811+ async getReposForTeam ( teamslug ) {
792812 const options = this . github . rest . teams . listReposInOrg . endpoint . merge ( {
793813 org : this . repo . owner ,
794814 team_slug : teamslug ,
@@ -797,20 +817,19 @@ ${this.results.reduce((x, y) => {
797817 return this . github . paginate ( options )
798818 }
799819
800- async getReposForCustomProperty ( customPropertyTuple ) {
801- const name = Object . keys ( customPropertyTuple ) [ 0 ]
820+ async getReposForCustomProperty ( customPropertyTuple ) {
821+ const name = Object . keys ( customPropertyTuple ) [ 0 ]
802822 let q = `props.${ name } :${ customPropertyTuple [ name ] } `
803823 q = encodeURIComponent ( q )
804824 const options = this . github . request . endpoint ( ( `/orgs/${ this . repo . owner } /properties/values?repository_query=${ q } ` ) )
805825 return this . github . paginate ( options )
806826 }
807827
808-
809- isObject ( item ) {
828+ isObject ( item ) {
810829 return ( item && typeof item === 'object' && ! Array . isArray ( item ) )
811830 }
812831
813- isIterable ( obj ) {
832+ isIterable ( obj ) {
814833 // checks for null and undefined
815834 if ( obj == null ) {
816835 return false
0 commit comments