2020-05-15 11:19:13 -04: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 11:59:12 -04:00
|
|
|
import {GitClientConfig, NgDevConfig} from '../../utils/config';
|
|
|
|
import {GithubClient} from '../../utils/git/github';
|
2020-05-15 11:19:13 -04:00
|
|
|
|
|
|
|
import {GithubApiMergeStrategyConfig} from './strategies/api-merge';
|
|
|
|
|
2020-07-24 11:59:12 -04:00
|
|
|
/** Describes possible values that can be returned for `branches` of a target label. */
|
|
|
|
export type TargetLabelBranchResult = string[]|Promise<string[]>;
|
|
|
|
|
2020-05-15 11:19:13 -04: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 12:05:51 -04:00
|
|
|
*
|
|
|
|
* @throws {InvalidTargetLabelError} Invalid label has been applied to pull request.
|
|
|
|
* @throws {InvalidTargetBranchError} Invalid Github target branch has been selected.
|
2020-05-15 11:19:13 -04:00
|
|
|
*/
|
2020-07-24 11:59:12 -04:00
|
|
|
branches: TargetLabelBranchResult|((githubTargetBranch: string) => TargetLabelBranchResult);
|
2020-05-15 11:19:13 -04:00
|
|
|
}
|
|
|
|
|
2020-05-15 11:21:01 -04: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 18:39:31 -04:00
|
|
|
export type MergeConfigWithRemote = MergeConfig&{remote: GitClientConfig};
|
2020-05-15 11:21:01 -04:00
|
|
|
|
2020-05-15 11:19:13 -04:00
|
|
|
/** Configuration for the merge script. */
|
|
|
|
export interface MergeConfig {
|
2020-05-15 11:21:01 -04: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 18:39:31 -04:00
|
|
|
remote?: GitClientConfig;
|
2020-05-15 11:19:13 -04: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-15 18:20:36 -04:00
|
|
|
/** Label that is applied when special attention from the caretaker is required. */
|
|
|
|
caretakerNoteLabel?: string|RegExp;
|
2020-05-15 11:19:13 -04: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 11:21:01 -04: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 11:59:12 -04:00
|
|
|
export type DevInfraMergeConfig =
|
|
|
|
NgDevConfig<{'merge': (api: GithubClient) => MergeConfig | Promise<MergeConfig>}>;
|
2020-05-15 11:21:01 -04:00
|
|
|
|
2020-05-15 11:19:13 -04:00
|
|
|
/** Loads and validates the merge configuration. */
|
2020-07-24 11:59:12 -04:00
|
|
|
export async function loadAndValidateConfig(
|
|
|
|
config: Partial<DevInfraMergeConfig>,
|
|
|
|
api: GithubClient): Promise<{config?: MergeConfig, errors?: string[]}> {
|
2020-05-15 11:21:01 -04:00
|
|
|
if (config.merge === undefined) {
|
2020-05-20 19:04:46 -04:00
|
|
|
return {errors: ['No merge configuration found. Set the `merge` configuration.']};
|
2020-05-15 11:19:13 -04:00
|
|
|
}
|
2020-05-15 11:21:01 -04:00
|
|
|
|
|
|
|
if (typeof config.merge !== 'function') {
|
2020-05-20 19:04:46 -04:00
|
|
|
return {errors: ['Expected merge configuration to be defined lazily through a function.']};
|
2020-05-15 11:21:01 -04:00
|
|
|
}
|
|
|
|
|
2020-07-24 11:59:12 -04:00
|
|
|
const mergeConfig = await config.merge(api);
|
2020-05-15 11:21:01 -04:00
|
|
|
const errors = validateMergeConfig(mergeConfig);
|
|
|
|
|
2020-05-15 11:19:13 -04:00
|
|
|
if (errors.length) {
|
|
|
|
return {errors};
|
|
|
|
}
|
2020-05-15 11:21:01 -04:00
|
|
|
|
2020-07-24 11:59:12 -04:00
|
|
|
return {config: mergeConfig};
|
2020-05-15 11:19:13 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/** Validates the specified configuration. Returns a list of failure messages. */
|
2020-05-15 11:21:01 -04:00
|
|
|
function validateMergeConfig(config: Partial<MergeConfig>): string[] {
|
2020-05-15 11:19:13 -04: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;
|
|
|
|
}
|