feat(dev-infra): support user-failures when computing branches for target label (#38223)
The merge tool provides a way for configurations to determine the branches for a label lazily. This is supported because it allows labels to respect the currently selected base branch through the Github UI. e.g. if `target: label` is applied on a PR and the PR is based on the patch branch, then the change could only go into the selected target branch, while if it would be based on `master`, the change would be cherry-picked to `master` too. This allows for convenient back-porting of changes if they did not apply cleanly to the primary development branch (`master`). We want to expand this function so that it is possible to report failures if an invalid target label is appplied (e.g. `target: major` not allowed in some situations), or if the Github base branch is not valid for the given target label (e.g. if `target: lts` is used, but it's not based on a LTS branch). PR Close #38223
This commit is contained in:
parent
576e329f33
commit
6f0f0d3ea2
|
@ -31,6 +31,9 @@ export interface TargetLabel {
|
||||||
* List of branches a pull request with this target label should be merged into.
|
* 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
|
* 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`.
|
* Github Web UI. This is useful for supporting labels like `target: development-branch`.
|
||||||
|
*
|
||||||
|
* @throws {InvalidTargetLabelError} Invalid label has been applied to pull request.
|
||||||
|
* @throws {InvalidTargetBranchError} Invalid Github target branch has been selected.
|
||||||
*/
|
*/
|
||||||
branches: TargetLabelBranchResult|((githubTargetBranch: string) => TargetLabelBranchResult);
|
branches: TargetLabelBranchResult|((githubTargetBranch: string) => TargetLabelBranchResult);
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import {GitClient} from '../../utils/git';
|
||||||
|
|
||||||
import {PullRequestFailure} from './failures';
|
import {PullRequestFailure} from './failures';
|
||||||
import {matchesPattern} from './string-pattern';
|
import {matchesPattern} from './string-pattern';
|
||||||
import {getBranchesFromTargetLabel, getTargetLabelFromPullRequest} from './target-label';
|
import {getBranchesFromTargetLabel, getTargetLabelFromPullRequest, InvalidTargetBranchError, InvalidTargetLabelError} from './target-label';
|
||||||
import {PullRequestMergeTask} from './task';
|
import {PullRequestMergeTask} from './task';
|
||||||
|
|
||||||
/** Interface that describes a pull request. */
|
/** Interface that describes a pull request. */
|
||||||
|
@ -83,6 +83,20 @@ export async function loadAndValidatePullRequest(
|
||||||
labels.some(name => matchesPattern(name, config.commitMessageFixupLabel));
|
labels.some(name => matchesPattern(name, config.commitMessageFixupLabel));
|
||||||
const hasCaretakerNote = !!config.caretakerNoteLabel &&
|
const hasCaretakerNote = !!config.caretakerNoteLabel &&
|
||||||
labels.some(name => matchesPattern(name, config.caretakerNoteLabel!));
|
labels.some(name => matchesPattern(name, config.caretakerNoteLabel!));
|
||||||
|
let targetBranches: string[];
|
||||||
|
|
||||||
|
// If branches are determined for a given target label, capture errors that are
|
||||||
|
// thrown as part of branch computation. This is expected because a merge configuration
|
||||||
|
// can lazily compute branches for a target label and throw. e.g. if an invalid target
|
||||||
|
// label is applied, we want to exit the script gracefully with an error message.
|
||||||
|
try {
|
||||||
|
targetBranches = await getBranchesFromTargetLabel(targetLabel, githubTargetBranch);
|
||||||
|
} catch (error) {
|
||||||
|
if (error instanceof InvalidTargetBranchError || error instanceof InvalidTargetLabelError) {
|
||||||
|
return new PullRequestFailure(error.failureMessage);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
url: prData.html_url,
|
url: prData.html_url,
|
||||||
|
@ -92,8 +106,8 @@ export async function loadAndValidatePullRequest(
|
||||||
githubTargetBranch,
|
githubTargetBranch,
|
||||||
needsCommitMessageFixup,
|
needsCommitMessageFixup,
|
||||||
hasCaretakerNote,
|
hasCaretakerNote,
|
||||||
|
targetBranches,
|
||||||
title: prData.title,
|
title: prData.title,
|
||||||
targetBranches: getBranchesFromTargetLabel(targetLabel, githubTargetBranch),
|
|
||||||
commitCount: prData.commits,
|
commitCount: prData.commits,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,22 @@
|
||||||
import {MergeConfig, TargetLabel} from './config';
|
import {MergeConfig, TargetLabel} from './config';
|
||||||
import {matchesPattern} from './string-pattern';
|
import {matchesPattern} from './string-pattern';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unique error that can be thrown in the merge configuration if an
|
||||||
|
* invalid branch is targeted.
|
||||||
|
*/
|
||||||
|
export class InvalidTargetBranchError {
|
||||||
|
constructor(public failureMessage: string) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unique error that can be thrown in the merge configuration if an
|
||||||
|
* invalid label has been applied to a pull request.
|
||||||
|
*/
|
||||||
|
export class InvalidTargetLabelError {
|
||||||
|
constructor(public failureMessage: string) {}
|
||||||
|
}
|
||||||
|
|
||||||
/** Gets the target label from the specified pull request labels. */
|
/** Gets the target label from the specified pull request labels. */
|
||||||
export function getTargetLabelFromPullRequest(config: MergeConfig, labels: string[]): TargetLabel|
|
export function getTargetLabelFromPullRequest(config: MergeConfig, labels: string[]): TargetLabel|
|
||||||
null {
|
null {
|
||||||
|
@ -21,8 +37,14 @@ export function getTargetLabelFromPullRequest(config: MergeConfig, labels: strin
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Gets the branches from the specified target label. */
|
/**
|
||||||
export function getBranchesFromTargetLabel(
|
* Gets the branches from the specified target label.
|
||||||
label: TargetLabel, githubTargetBranch: string): string[] {
|
*
|
||||||
return typeof label.branches === 'function' ? label.branches(githubTargetBranch) : label.branches;
|
* @throws {InvalidTargetLabelError} Invalid label has been applied to pull request.
|
||||||
|
* @throws {InvalidTargetBranchError} Invalid Github target branch has been selected.
|
||||||
|
*/
|
||||||
|
export async function getBranchesFromTargetLabel(
|
||||||
|
label: TargetLabel, githubTargetBranch: string): Promise<string[]> {
|
||||||
|
return typeof label.branches === 'function' ? await label.branches(githubTargetBranch) :
|
||||||
|
await label.branches;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue