| 
									
										
										
										
											2020-05-15 17:19:13 +02:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @license | 
					
						
							|  |  |  |  * Copyright Google LLC All Rights Reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Use of this source code is governed by an MIT-style license that can be | 
					
						
							|  |  |  |  * found in the LICENSE file at https://angular.io/license
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-24 17:59:12 +02:00
										 |  |  | import {GitClientConfig, NgDevConfig} from '../../utils/config'; | 
					
						
							|  |  |  | import {GithubClient} from '../../utils/git/github'; | 
					
						
							| 
									
										
										
										
											2020-05-15 17:19:13 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | import {GithubApiMergeStrategyConfig} from './strategies/api-merge'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-24 17:59:12 +02:00
										 |  |  | /** Describes possible values that can be returned for `branches` of a target label. */ | 
					
						
							|  |  |  | export type TargetLabelBranchResult = string[]|Promise<string[]>; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-15 17:19:13 +02:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Possible merge methods supported by the Github API. | 
					
						
							|  |  |  |  * https://developer.github.com/v3/pulls/#merge-a-pull-request-merge-button.
 | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | export type GithubApiMergeMethod = 'merge'|'squash'|'rebase'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * Target labels represent Github pull requests labels. These labels instruct the merge | 
					
						
							|  |  |  |  * script into which branches a given pull request should be merged to. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | export interface TargetLabel { | 
					
						
							|  |  |  |   /** Pattern that matches the given target label. */ | 
					
						
							|  |  |  |   pattern: RegExp|string; | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * List of branches a pull request with this target label should be merged into. | 
					
						
							|  |  |  |    * Can also be wrapped in a function that accepts the target branch specified in the | 
					
						
							|  |  |  |    * Github Web UI. This is useful for supporting labels like `target: development-branch`. | 
					
						
							| 
									
										
										
										
											2020-07-24 18:05:51 +02:00
										 |  |  |    * | 
					
						
							|  |  |  |    * @throws {InvalidTargetLabelError} Invalid label has been applied to pull request. | 
					
						
							|  |  |  |    * @throws {InvalidTargetBranchError} Invalid Github target branch has been selected. | 
					
						
							| 
									
										
										
										
											2020-05-15 17:19:13 +02:00
										 |  |  |    */ | 
					
						
							| 
									
										
										
										
											2020-07-24 17:59:12 +02:00
										 |  |  |   branches: TargetLabelBranchResult|((githubTargetBranch: string) => TargetLabelBranchResult); | 
					
						
							| 
									
										
										
										
											2020-05-15 17:19:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-15 17:21:01 +02:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Configuration for the merge script with all remote options specified. The | 
					
						
							|  |  |  |  * default `MergeConfig` has does not require any of these options as defaults | 
					
						
							|  |  |  |  * are provided by the common dev-infra github configuration. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-05-27 15:39:31 -07:00
										 |  |  | export type MergeConfigWithRemote = MergeConfig&{remote: GitClientConfig}; | 
					
						
							| 
									
										
										
										
											2020-05-15 17:21:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-15 17:19:13 +02:00
										 |  |  | /** Configuration for the merge script. */ | 
					
						
							|  |  |  | export interface MergeConfig { | 
					
						
							| 
									
										
										
										
											2020-05-15 17:21:01 +02:00
										 |  |  |   /** | 
					
						
							|  |  |  |    * Configuration for the upstream remote. All of these options are optional as | 
					
						
							|  |  |  |    * defaults are provided by the common dev-infra github configuration. | 
					
						
							|  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2020-05-27 15:39:31 -07:00
										 |  |  |   remote?: GitClientConfig; | 
					
						
							| 
									
										
										
										
											2020-05-15 17:19:13 +02:00
										 |  |  |   /** List of target labels. */ | 
					
						
							|  |  |  |   labels: TargetLabel[]; | 
					
						
							|  |  |  |   /** Required base commits for given branches. */ | 
					
						
							|  |  |  |   requiredBaseCommits?: {[branchName: string]: string}; | 
					
						
							|  |  |  |   /** Pattern that matches labels which imply a signed CLA. */ | 
					
						
							|  |  |  |   claSignedLabel: string|RegExp; | 
					
						
							|  |  |  |   /** Pattern that matches labels which imply a merge ready pull request. */ | 
					
						
							|  |  |  |   mergeReadyLabel: string|RegExp; | 
					
						
							| 
									
										
										
										
											2020-06-16 00:20:36 +02:00
										 |  |  |   /** Label that is applied when special attention from the caretaker is required. */ | 
					
						
							|  |  |  |   caretakerNoteLabel?: string|RegExp; | 
					
						
							| 
									
										
										
										
											2020-05-15 17:19:13 +02:00
										 |  |  |   /** Label which can be applied to fixup commit messages in the merge script. */ | 
					
						
							|  |  |  |   commitMessageFixupLabel: string|RegExp; | 
					
						
							|  |  |  |   /** | 
					
						
							|  |  |  |    * Whether pull requests should be merged using the Github API. This can be enabled | 
					
						
							|  |  |  |    * if projects want to have their pull requests show up as `Merged` in the Github UI. | 
					
						
							|  |  |  |    * The downside is that fixup or squash commits no longer work as the Github API does | 
					
						
							|  |  |  |    * not support this. | 
					
						
							|  |  |  |    */ | 
					
						
							|  |  |  |   githubApiMerge: false|GithubApiMergeStrategyConfig; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-15 17:21:01 +02:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Configuration of the merge script in the dev-infra configuration. Note that the | 
					
						
							|  |  |  |  * merge configuration is retrieved lazily as usually these configurations rely | 
					
						
							|  |  |  |  * on branch name computations. We don't want to run these immediately whenever | 
					
						
							|  |  |  |  * the dev-infra configuration is loaded as that could slow-down other commands. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-07-24 17:59:12 +02:00
										 |  |  | export type DevInfraMergeConfig = | 
					
						
							|  |  |  |     NgDevConfig<{'merge': (api: GithubClient) => MergeConfig | Promise<MergeConfig>}>; | 
					
						
							| 
									
										
										
										
											2020-05-15 17:21:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-15 17:19:13 +02:00
										 |  |  | /** Loads and validates the merge configuration. */ | 
					
						
							| 
									
										
										
										
											2020-07-24 17:59:12 +02:00
										 |  |  | export async function loadAndValidateConfig( | 
					
						
							|  |  |  |     config: Partial<DevInfraMergeConfig>, | 
					
						
							|  |  |  |     api: GithubClient): Promise<{config?: MergeConfig, errors?: string[]}> { | 
					
						
							| 
									
										
										
										
											2020-05-15 17:21:01 +02:00
										 |  |  |   if (config.merge === undefined) { | 
					
						
							| 
									
										
										
										
											2020-05-20 16:04:46 -07:00
										 |  |  |     return {errors: ['No merge configuration found. Set the `merge` configuration.']}; | 
					
						
							| 
									
										
										
										
											2020-05-15 17:19:13 +02:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-05-15 17:21:01 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |   if (typeof config.merge !== 'function') { | 
					
						
							| 
									
										
										
										
											2020-05-20 16:04:46 -07:00
										 |  |  |     return {errors: ['Expected merge configuration to be defined lazily through a function.']}; | 
					
						
							| 
									
										
										
										
											2020-05-15 17:21:01 +02:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-24 17:59:12 +02:00
										 |  |  |   const mergeConfig = await config.merge(api); | 
					
						
							| 
									
										
										
										
											2020-05-15 17:21:01 +02:00
										 |  |  |   const errors = validateMergeConfig(mergeConfig); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-15 17:19:13 +02:00
										 |  |  |   if (errors.length) { | 
					
						
							|  |  |  |     return {errors}; | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2020-05-15 17:21:01 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-24 17:59:12 +02:00
										 |  |  |   return {config: mergeConfig}; | 
					
						
							| 
									
										
										
										
											2020-05-15 17:19:13 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** Validates the specified configuration. Returns a list of failure messages. */ | 
					
						
							| 
									
										
										
										
											2020-05-15 17:21:01 +02:00
										 |  |  | function validateMergeConfig(config: Partial<MergeConfig>): string[] { | 
					
						
							| 
									
										
										
										
											2020-05-15 17:19:13 +02:00
										 |  |  |   const errors: string[] = []; | 
					
						
							|  |  |  |   if (!config.labels) { | 
					
						
							|  |  |  |     errors.push('No label configuration.'); | 
					
						
							|  |  |  |   } else if (!Array.isArray(config.labels)) { | 
					
						
							|  |  |  |     errors.push('Label configuration needs to be an array.'); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (!config.claSignedLabel) { | 
					
						
							|  |  |  |     errors.push('No CLA signed label configured.'); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (!config.mergeReadyLabel) { | 
					
						
							|  |  |  |     errors.push('No merge ready label configured.'); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   if (config.githubApiMerge === undefined) { | 
					
						
							|  |  |  |     errors.push('No explicit choice of merge strategy. Please set `githubApiMerge`.'); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return errors; | 
					
						
							|  |  |  | } |