feat(dev-infra): provide tooling to check what branches a pr targets (#39504)
Create a command in the `ng-dev` toolset that allows user's to check what branches a PR will merge into based on its targeting. PR Close #39504
This commit is contained in:
parent
7e33cb9626
commit
d0dd0e80f6
@ -2599,6 +2599,235 @@ function buildNgbotParser(localYargs) {
|
|||||||
return localYargs.help().strict().demandCommand().command('verify', 'Verify the NgBot config', {}, () => verify());
|
return localYargs.help().strict().demandCommand().command('verify', 'Verify the NgBot config', {}, () => verify());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
/** Loads and validates the merge configuration. */
|
||||||
|
function loadAndValidateConfig(config, api) {
|
||||||
|
return tslib.__awaiter(this, void 0, void 0, function () {
|
||||||
|
var mergeConfig, errors;
|
||||||
|
return tslib.__generator(this, function (_a) {
|
||||||
|
switch (_a.label) {
|
||||||
|
case 0:
|
||||||
|
if (config.merge === undefined) {
|
||||||
|
return [2 /*return*/, { errors: ['No merge configuration found. Set the `merge` configuration.'] }];
|
||||||
|
}
|
||||||
|
if (typeof config.merge !== 'function') {
|
||||||
|
return [2 /*return*/, { errors: ['Expected merge configuration to be defined lazily through a function.'] }];
|
||||||
|
}
|
||||||
|
return [4 /*yield*/, config.merge(api)];
|
||||||
|
case 1:
|
||||||
|
mergeConfig = _a.sent();
|
||||||
|
errors = validateMergeConfig(mergeConfig);
|
||||||
|
if (errors.length) {
|
||||||
|
return [2 /*return*/, { errors: errors }];
|
||||||
|
}
|
||||||
|
return [2 /*return*/, { config: mergeConfig }];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** Validates the specified configuration. Returns a list of failure messages. */
|
||||||
|
function validateMergeConfig(config) {
|
||||||
|
var errors = [];
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
/** Checks whether the specified value matches the given pattern. */
|
||||||
|
function matchesPattern(value, pattern) {
|
||||||
|
return typeof pattern === 'string' ? value === pattern : pattern.test(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* Unique error that can be thrown in the merge configuration if an
|
||||||
|
* invalid branch is targeted.
|
||||||
|
*/
|
||||||
|
var InvalidTargetBranchError = /** @class */ (function () {
|
||||||
|
function InvalidTargetBranchError(failureMessage) {
|
||||||
|
this.failureMessage = failureMessage;
|
||||||
|
}
|
||||||
|
return InvalidTargetBranchError;
|
||||||
|
}());
|
||||||
|
/**
|
||||||
|
* Unique error that can be thrown in the merge configuration if an
|
||||||
|
* invalid label has been applied to a pull request.
|
||||||
|
*/
|
||||||
|
var InvalidTargetLabelError = /** @class */ (function () {
|
||||||
|
function InvalidTargetLabelError(failureMessage) {
|
||||||
|
this.failureMessage = failureMessage;
|
||||||
|
}
|
||||||
|
return InvalidTargetLabelError;
|
||||||
|
}());
|
||||||
|
/** Gets the target label from the specified pull request labels. */
|
||||||
|
function getTargetLabelFromPullRequest(config, labels) {
|
||||||
|
var e_1, _a;
|
||||||
|
var _loop_1 = function (label) {
|
||||||
|
var match = config.labels.find(function (_a) {
|
||||||
|
var pattern = _a.pattern;
|
||||||
|
return matchesPattern(label, pattern);
|
||||||
|
});
|
||||||
|
if (match !== undefined) {
|
||||||
|
return { value: match };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
for (var labels_1 = tslib.__values(labels), labels_1_1 = labels_1.next(); !labels_1_1.done; labels_1_1 = labels_1.next()) {
|
||||||
|
var label = labels_1_1.value;
|
||||||
|
var state_1 = _loop_1(label);
|
||||||
|
if (typeof state_1 === "object")
|
||||||
|
return state_1.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
||||||
|
finally {
|
||||||
|
try {
|
||||||
|
if (labels_1_1 && !labels_1_1.done && (_a = labels_1.return)) _a.call(labels_1);
|
||||||
|
}
|
||||||
|
finally { if (e_1) throw e_1.error; }
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Gets the branches from the specified target label.
|
||||||
|
*
|
||||||
|
* @throws {InvalidTargetLabelError} Invalid label has been applied to pull request.
|
||||||
|
* @throws {InvalidTargetBranchError} Invalid Github target branch has been selected.
|
||||||
|
*/
|
||||||
|
function getBranchesFromTargetLabel(label, githubTargetBranch) {
|
||||||
|
return tslib.__awaiter(this, void 0, void 0, function () {
|
||||||
|
var _a;
|
||||||
|
return tslib.__generator(this, function (_b) {
|
||||||
|
switch (_b.label) {
|
||||||
|
case 0:
|
||||||
|
if (!(typeof label.branches === 'function')) return [3 /*break*/, 2];
|
||||||
|
return [4 /*yield*/, label.branches(githubTargetBranch)];
|
||||||
|
case 1:
|
||||||
|
_a = _b.sent();
|
||||||
|
return [3 /*break*/, 4];
|
||||||
|
case 2: return [4 /*yield*/, label.branches];
|
||||||
|
case 3:
|
||||||
|
_a = _b.sent();
|
||||||
|
_b.label = 4;
|
||||||
|
case 4: return [2 /*return*/, _a];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
function checkTargetBranchesForPr(prNumber, jsonOutput = false) {
|
||||||
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
||||||
|
/** The ng-dev configuration. */
|
||||||
|
const config = getConfig();
|
||||||
|
/** Repo owner and name for the github repository. */
|
||||||
|
const { owner, name: repo } = config.github;
|
||||||
|
/** The git client to get a Github API service instance. */
|
||||||
|
const git = new GitClient(undefined, config);
|
||||||
|
/** The validated merge config. */
|
||||||
|
const { config: mergeConfig, errors } = yield loadAndValidateConfig(config, git.github);
|
||||||
|
if (errors !== undefined) {
|
||||||
|
throw Error(`Invalid configuration found: ${errors}`);
|
||||||
|
}
|
||||||
|
/** The current state of the pull request from Github. */
|
||||||
|
const prData = (yield git.github.pulls.get({ owner, repo, pull_number: prNumber })).data;
|
||||||
|
/** The list of labels on the PR as strings. */
|
||||||
|
const labels = prData.labels.map(l => l.name);
|
||||||
|
/** The branch targetted via the Github UI. */
|
||||||
|
const githubTargetBranch = prData.base.ref;
|
||||||
|
/** The active label which is being used for targetting the PR. */
|
||||||
|
const targetLabel = getTargetLabelFromPullRequest(mergeConfig, labels);
|
||||||
|
if (targetLabel === null) {
|
||||||
|
error(red(`No target label was found on pr #${prNumber}`));
|
||||||
|
process.exitCode = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/** The target branches based on the target label and branch targetted in the Github UI. */
|
||||||
|
const targets = yield getBranchesFromTargetLabel(targetLabel, githubTargetBranch);
|
||||||
|
// When requested, print a json output to stdout, rather than using standard ng-dev logging.
|
||||||
|
if (jsonOutput) {
|
||||||
|
process.stdout.write(JSON.stringify(targets));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
info.group(`PR #${prNumber} will merge into:`);
|
||||||
|
targets.forEach(target => info(`- ${target}`));
|
||||||
|
info.groupEnd();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
/** Builds the command. */
|
||||||
|
function builder$5(yargs) {
|
||||||
|
return yargs
|
||||||
|
.positional('pr', {
|
||||||
|
description: 'The pull request number',
|
||||||
|
type: 'number',
|
||||||
|
demandOption: true,
|
||||||
|
})
|
||||||
|
.option('json', {
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
description: 'Print response as json',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** Handles the command. */
|
||||||
|
function handler$5({ pr, json }) {
|
||||||
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
||||||
|
yield checkTargetBranchesForPr(pr, json);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
/** yargs command module describing the command. */
|
||||||
|
const CheckTargetBranchesModule = {
|
||||||
|
handler: handler$5,
|
||||||
|
builder: builder$5,
|
||||||
|
command: 'check-target-branches <pr>',
|
||||||
|
describe: 'Check a PR to determine what branches it is currently targeting',
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @license
|
* @license
|
||||||
* Copyright Google LLC All Rights Reserved.
|
* Copyright Google LLC All Rights Reserved.
|
||||||
@ -2799,11 +3028,11 @@ function checkOutPullRequestLocally(prNumber, githubToken, opts = {}) {
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
/** Builds the checkout pull request command. */
|
/** Builds the checkout pull request command. */
|
||||||
function builder$5(yargs) {
|
function builder$6(yargs) {
|
||||||
return addGithubTokenOption(yargs).positional('prNumber', { type: 'number', demandOption: true });
|
return addGithubTokenOption(yargs).positional('prNumber', { type: 'number', demandOption: true });
|
||||||
}
|
}
|
||||||
/** Handles the checkout pull request command. */
|
/** Handles the checkout pull request command. */
|
||||||
function handler$5({ prNumber, githubToken }) {
|
function handler$6({ prNumber, githubToken }) {
|
||||||
return tslib.__awaiter(this, void 0, void 0, function* () {
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
||||||
const prCheckoutOptions = { allowIfMaintainerCannotModify: true, branchName: `pr-${prNumber}` };
|
const prCheckoutOptions = { allowIfMaintainerCannotModify: true, branchName: `pr-${prNumber}` };
|
||||||
yield checkOutPullRequestLocally(prNumber, githubToken, prCheckoutOptions);
|
yield checkOutPullRequestLocally(prNumber, githubToken, prCheckoutOptions);
|
||||||
@ -2811,8 +3040,8 @@ function handler$5({ prNumber, githubToken }) {
|
|||||||
}
|
}
|
||||||
/** yargs command module for checking out a PR */
|
/** yargs command module for checking out a PR */
|
||||||
const CheckoutCommandModule = {
|
const CheckoutCommandModule = {
|
||||||
handler: handler$5,
|
handler: handler$6,
|
||||||
builder: builder$5,
|
builder: builder$6,
|
||||||
command: 'checkout <pr-number>',
|
command: 'checkout <pr-number>',
|
||||||
describe: 'Checkout a PR from the upstream repo',
|
describe: 'Checkout a PR from the upstream repo',
|
||||||
};
|
};
|
||||||
@ -2985,59 +3214,6 @@ function getThirtyDaysAgoDate() {
|
|||||||
return date.getTime();
|
return date.getTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
/** Loads and validates the merge configuration. */
|
|
||||||
function loadAndValidateConfig(config, api) {
|
|
||||||
return tslib.__awaiter(this, void 0, void 0, function () {
|
|
||||||
var mergeConfig, errors;
|
|
||||||
return tslib.__generator(this, function (_a) {
|
|
||||||
switch (_a.label) {
|
|
||||||
case 0:
|
|
||||||
if (config.merge === undefined) {
|
|
||||||
return [2 /*return*/, { errors: ['No merge configuration found. Set the `merge` configuration.'] }];
|
|
||||||
}
|
|
||||||
if (typeof config.merge !== 'function') {
|
|
||||||
return [2 /*return*/, { errors: ['Expected merge configuration to be defined lazily through a function.'] }];
|
|
||||||
}
|
|
||||||
return [4 /*yield*/, config.merge(api)];
|
|
||||||
case 1:
|
|
||||||
mergeConfig = _a.sent();
|
|
||||||
errors = validateMergeConfig(mergeConfig);
|
|
||||||
if (errors.length) {
|
|
||||||
return [2 /*return*/, { errors: errors }];
|
|
||||||
}
|
|
||||||
return [2 /*return*/, { config: mergeConfig }];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
/** Validates the specified configuration. Returns a list of failure messages. */
|
|
||||||
function validateMergeConfig(config) {
|
|
||||||
var errors = [];
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @license
|
* @license
|
||||||
* Copyright Google LLC All Rights Reserved.
|
* Copyright Google LLC All Rights Reserved.
|
||||||
@ -3121,101 +3297,6 @@ function getTargettedBranchesConfirmationPromptMessage(pullRequest) {
|
|||||||
return "Pull request #" + pullRequest.prNumber + " will merge into:\n" + targetBranchListAsString + "\nDo you want to proceed merging?";
|
return "Pull request #" + pullRequest.prNumber + " will merge into:\n" + targetBranchListAsString + "\nDo you want to proceed merging?";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
/** Checks whether the specified value matches the given pattern. */
|
|
||||||
function matchesPattern(value, pattern) {
|
|
||||||
return typeof pattern === 'string' ? value === pattern : pattern.test(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
*/
|
|
||||||
/**
|
|
||||||
* Unique error that can be thrown in the merge configuration if an
|
|
||||||
* invalid branch is targeted.
|
|
||||||
*/
|
|
||||||
var InvalidTargetBranchError = /** @class */ (function () {
|
|
||||||
function InvalidTargetBranchError(failureMessage) {
|
|
||||||
this.failureMessage = failureMessage;
|
|
||||||
}
|
|
||||||
return InvalidTargetBranchError;
|
|
||||||
}());
|
|
||||||
/**
|
|
||||||
* Unique error that can be thrown in the merge configuration if an
|
|
||||||
* invalid label has been applied to a pull request.
|
|
||||||
*/
|
|
||||||
var InvalidTargetLabelError = /** @class */ (function () {
|
|
||||||
function InvalidTargetLabelError(failureMessage) {
|
|
||||||
this.failureMessage = failureMessage;
|
|
||||||
}
|
|
||||||
return InvalidTargetLabelError;
|
|
||||||
}());
|
|
||||||
/** Gets the target label from the specified pull request labels. */
|
|
||||||
function getTargetLabelFromPullRequest(config, labels) {
|
|
||||||
var e_1, _a;
|
|
||||||
var _loop_1 = function (label) {
|
|
||||||
var match = config.labels.find(function (_a) {
|
|
||||||
var pattern = _a.pattern;
|
|
||||||
return matchesPattern(label, pattern);
|
|
||||||
});
|
|
||||||
if (match !== undefined) {
|
|
||||||
return { value: match };
|
|
||||||
}
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
for (var labels_1 = tslib.__values(labels), labels_1_1 = labels_1.next(); !labels_1_1.done; labels_1_1 = labels_1.next()) {
|
|
||||||
var label = labels_1_1.value;
|
|
||||||
var state_1 = _loop_1(label);
|
|
||||||
if (typeof state_1 === "object")
|
|
||||||
return state_1.value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (e_1_1) { e_1 = { error: e_1_1 }; }
|
|
||||||
finally {
|
|
||||||
try {
|
|
||||||
if (labels_1_1 && !labels_1_1.done && (_a = labels_1.return)) _a.call(labels_1);
|
|
||||||
}
|
|
||||||
finally { if (e_1) throw e_1.error; }
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* Gets the branches from the specified target label.
|
|
||||||
*
|
|
||||||
* @throws {InvalidTargetLabelError} Invalid label has been applied to pull request.
|
|
||||||
* @throws {InvalidTargetBranchError} Invalid Github target branch has been selected.
|
|
||||||
*/
|
|
||||||
function getBranchesFromTargetLabel(label, githubTargetBranch) {
|
|
||||||
return tslib.__awaiter(this, void 0, void 0, function () {
|
|
||||||
var _a;
|
|
||||||
return tslib.__generator(this, function (_b) {
|
|
||||||
switch (_b.label) {
|
|
||||||
case 0:
|
|
||||||
if (!(typeof label.branches === 'function')) return [3 /*break*/, 2];
|
|
||||||
return [4 /*yield*/, label.branches(githubTargetBranch)];
|
|
||||||
case 1:
|
|
||||||
_a = _b.sent();
|
|
||||||
return [3 /*break*/, 4];
|
|
||||||
case 2: return [4 /*yield*/, label.branches];
|
|
||||||
case 3:
|
|
||||||
_a = _b.sent();
|
|
||||||
_b.label = 4;
|
|
||||||
case 4: return [2 /*return*/, _a];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @license
|
* @license
|
||||||
* Copyright Google LLC All Rights Reserved.
|
* Copyright Google LLC All Rights Reserved.
|
||||||
@ -4251,7 +4332,8 @@ function buildPrParser(localYargs) {
|
|||||||
.command('merge <pr-number>', 'Merge pull requests', buildMergeCommand, handleMergeCommand)
|
.command('merge <pr-number>', 'Merge pull requests', buildMergeCommand, handleMergeCommand)
|
||||||
.command('discover-new-conflicts <pr-number>', 'Check if a pending PR causes new conflicts for other pending PRs', buildDiscoverNewConflictsCommand, handleDiscoverNewConflictsCommand)
|
.command('discover-new-conflicts <pr-number>', 'Check if a pending PR causes new conflicts for other pending PRs', buildDiscoverNewConflictsCommand, handleDiscoverNewConflictsCommand)
|
||||||
.command('rebase <pr-number>', 'Rebase a pending PR and push the rebased commits back to Github', buildRebaseCommand, handleRebaseCommand)
|
.command('rebase <pr-number>', 'Rebase a pending PR and push the rebased commits back to Github', buildRebaseCommand, handleRebaseCommand)
|
||||||
.command(CheckoutCommandModule);
|
.command(CheckoutCommandModule)
|
||||||
|
.command(CheckTargetBranchesModule);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -4718,7 +4800,7 @@ function buildReleaseOutput() {
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
/** Yargs command builder for configuring the `ng-dev release build` command. */
|
/** Yargs command builder for configuring the `ng-dev release build` command. */
|
||||||
function builder$6(argv) {
|
function builder$7(argv) {
|
||||||
return argv.option('json', {
|
return argv.option('json', {
|
||||||
type: 'boolean',
|
type: 'boolean',
|
||||||
description: 'Whether the built packages should be printed to stdout as JSON.',
|
description: 'Whether the built packages should be printed to stdout as JSON.',
|
||||||
@ -4726,7 +4808,7 @@ function builder$6(argv) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
/** Yargs command handler for building a release. */
|
/** Yargs command handler for building a release. */
|
||||||
function handler$6(args) {
|
function handler$7(args) {
|
||||||
return tslib.__awaiter(this, void 0, void 0, function* () {
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
||||||
const { npmPackages } = getReleaseConfig();
|
const { npmPackages } = getReleaseConfig();
|
||||||
let builtPackages = yield buildReleaseOutput();
|
let builtPackages = yield buildReleaseOutput();
|
||||||
@ -4761,8 +4843,8 @@ function handler$6(args) {
|
|||||||
}
|
}
|
||||||
/** CLI command module for building release output. */
|
/** CLI command module for building release output. */
|
||||||
const ReleaseBuildCommandModule = {
|
const ReleaseBuildCommandModule = {
|
||||||
builder: builder$6,
|
builder: builder$7,
|
||||||
handler: handler$6,
|
handler: handler$7,
|
||||||
command: 'build',
|
command: 'build',
|
||||||
describe: 'Builds the release output for the current branch.',
|
describe: 'Builds the release output for the current branch.',
|
||||||
};
|
};
|
||||||
@ -6217,11 +6299,11 @@ class ReleaseTool {
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
/** Yargs command builder for configuring the `ng-dev release publish` command. */
|
/** Yargs command builder for configuring the `ng-dev release publish` command. */
|
||||||
function builder$7(argv) {
|
function builder$8(argv) {
|
||||||
return addGithubTokenOption(argv);
|
return addGithubTokenOption(argv);
|
||||||
}
|
}
|
||||||
/** Yargs command handler for staging a release. */
|
/** Yargs command handler for staging a release. */
|
||||||
function handler$7(args) {
|
function handler$8(args) {
|
||||||
return tslib.__awaiter(this, void 0, void 0, function* () {
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
||||||
const config = getConfig();
|
const config = getConfig();
|
||||||
const releaseConfig = getReleaseConfig(config);
|
const releaseConfig = getReleaseConfig(config);
|
||||||
@ -6244,8 +6326,8 @@ function handler$7(args) {
|
|||||||
}
|
}
|
||||||
/** CLI command module for publishing a release. */
|
/** CLI command module for publishing a release. */
|
||||||
const ReleasePublishCommandModule = {
|
const ReleasePublishCommandModule = {
|
||||||
builder: builder$7,
|
builder: builder$8,
|
||||||
handler: handler$7,
|
handler: handler$8,
|
||||||
command: 'publish',
|
command: 'publish',
|
||||||
describe: 'Publish new releases and configure version branches.',
|
describe: 'Publish new releases and configure version branches.',
|
||||||
};
|
};
|
||||||
@ -6257,7 +6339,7 @@ const ReleasePublishCommandModule = {
|
|||||||
* Use of this source code is governed by an MIT-style license that can be
|
* 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
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
function builder$8(args) {
|
function builder$9(args) {
|
||||||
return args
|
return args
|
||||||
.positional('tagName', {
|
.positional('tagName', {
|
||||||
type: 'string',
|
type: 'string',
|
||||||
@ -6271,7 +6353,7 @@ function builder$8(args) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
/** Yargs command handler for building a release. */
|
/** Yargs command handler for building a release. */
|
||||||
function handler$8(args) {
|
function handler$9(args) {
|
||||||
return tslib.__awaiter(this, void 0, void 0, function* () {
|
return tslib.__awaiter(this, void 0, void 0, function* () {
|
||||||
const { targetVersion: rawVersion, tagName } = args;
|
const { targetVersion: rawVersion, tagName } = args;
|
||||||
const { npmPackages, publishRegistry } = getReleaseConfig();
|
const { npmPackages, publishRegistry } = getReleaseConfig();
|
||||||
@ -6303,8 +6385,8 @@ function handler$8(args) {
|
|||||||
}
|
}
|
||||||
/** CLI command module for setting an NPM dist tag. */
|
/** CLI command module for setting an NPM dist tag. */
|
||||||
const ReleaseSetDistTagCommand = {
|
const ReleaseSetDistTagCommand = {
|
||||||
builder: builder$8,
|
builder: builder$9,
|
||||||
handler: handler$8,
|
handler: handler$9,
|
||||||
command: 'set-dist-tag <tag-name> <target-version>',
|
command: 'set-dist-tag <tag-name> <target-version>',
|
||||||
describe: 'Sets a given NPM dist tag for all release packages.',
|
describe: 'Sets a given NPM dist tag for all release packages.',
|
||||||
};
|
};
|
||||||
|
@ -6,6 +6,7 @@ ts_library(
|
|||||||
module_name = "@angular/dev-infra-private/pr",
|
module_name = "@angular/dev-infra-private/pr",
|
||||||
visibility = ["//dev-infra:__subpackages__"],
|
visibility = ["//dev-infra:__subpackages__"],
|
||||||
deps = [
|
deps = [
|
||||||
|
"//dev-infra/pr/check-target-branches",
|
||||||
"//dev-infra/pr/checkout",
|
"//dev-infra/pr/checkout",
|
||||||
"//dev-infra/pr/discover-new-conflicts",
|
"//dev-infra/pr/discover-new-conflicts",
|
||||||
"//dev-infra/pr/merge",
|
"//dev-infra/pr/merge",
|
||||||
|
13
dev-infra/pr/check-target-branches/BUILD.bazel
Normal file
13
dev-infra/pr/check-target-branches/BUILD.bazel
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
load("@npm//@bazel/typescript:index.bzl", "ts_library")
|
||||||
|
|
||||||
|
ts_library(
|
||||||
|
name = "check-target-branches",
|
||||||
|
srcs = glob(["*.ts"]),
|
||||||
|
module_name = "@angular/dev-infra-private/pr/check-target-branches",
|
||||||
|
visibility = ["//dev-infra:__subpackages__"],
|
||||||
|
deps = [
|
||||||
|
"//dev-infra/pr/merge",
|
||||||
|
"//dev-infra/utils",
|
||||||
|
"@npm//@types/yargs",
|
||||||
|
],
|
||||||
|
)
|
52
dev-infra/pr/check-target-branches/check-target-branches.ts
Normal file
52
dev-infra/pr/check-target-branches/check-target-branches.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {getConfig} from '../../utils/config';
|
||||||
|
import {error, info, red} from '../../utils/console';
|
||||||
|
import {GitClient} from '../../utils/git/index';
|
||||||
|
import {loadAndValidateConfig} from '../merge/config';
|
||||||
|
import {getBranchesFromTargetLabel, getTargetLabelFromPullRequest} from '../merge/target-label';
|
||||||
|
|
||||||
|
export async function checkTargetBranchesForPr(prNumber: number, jsonOutput = false) {
|
||||||
|
/** The ng-dev configuration. */
|
||||||
|
const config = getConfig();
|
||||||
|
/** Repo owner and name for the github repository. */
|
||||||
|
const {owner, name: repo} = config.github;
|
||||||
|
/** The git client to get a Github API service instance. */
|
||||||
|
const git = new GitClient(undefined, config);
|
||||||
|
/** The validated merge config. */
|
||||||
|
const {config: mergeConfig, errors} = await loadAndValidateConfig(config, git.github);
|
||||||
|
if (errors !== undefined) {
|
||||||
|
throw Error(`Invalid configuration found: ${errors}`);
|
||||||
|
}
|
||||||
|
/** The current state of the pull request from Github. */
|
||||||
|
const prData = (await git.github.pulls.get({owner, repo, pull_number: prNumber})).data;
|
||||||
|
/** The list of labels on the PR as strings. */
|
||||||
|
const labels = prData.labels.map(l => l.name);
|
||||||
|
/** The branch targetted via the Github UI. */
|
||||||
|
const githubTargetBranch = prData.base.ref;
|
||||||
|
/** The active label which is being used for targetting the PR. */
|
||||||
|
const targetLabel = getTargetLabelFromPullRequest(mergeConfig!, labels);
|
||||||
|
if (targetLabel === null) {
|
||||||
|
error(red(`No target label was found on pr #${prNumber}`));
|
||||||
|
process.exitCode = 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/** The target branches based on the target label and branch targetted in the Github UI. */
|
||||||
|
const targets = await getBranchesFromTargetLabel(targetLabel, githubTargetBranch);
|
||||||
|
|
||||||
|
// When requested, print a json output to stdout, rather than using standard ng-dev logging.
|
||||||
|
if (jsonOutput) {
|
||||||
|
process.stdout.write(JSON.stringify(targets));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
info.group(`PR #${prNumber} will merge into:`);
|
||||||
|
targets.forEach(target => info(`- ${target}`));
|
||||||
|
info.groupEnd();
|
||||||
|
}
|
44
dev-infra/pr/check-target-branches/cli.ts
Normal file
44
dev-infra/pr/check-target-branches/cli.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* @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
|
||||||
|
*/
|
||||||
|
|
||||||
|
import {Arguments, Argv, CommandModule} from 'yargs';
|
||||||
|
|
||||||
|
import {checkTargetBranchesForPr} from './check-target-branches';
|
||||||
|
|
||||||
|
export interface CheckTargetBranchesOptions {
|
||||||
|
pr: number;
|
||||||
|
json: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Builds the command. */
|
||||||
|
function builder(yargs: Argv) {
|
||||||
|
return yargs
|
||||||
|
.positional('pr', {
|
||||||
|
description: 'The pull request number',
|
||||||
|
type: 'number',
|
||||||
|
demandOption: true,
|
||||||
|
})
|
||||||
|
.option('json', {
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
|
description: 'Print response as json',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Handles the command. */
|
||||||
|
async function handler({pr, json}: Arguments<CheckTargetBranchesOptions>) {
|
||||||
|
await checkTargetBranchesForPr(pr, json);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** yargs command module describing the command. */
|
||||||
|
export const CheckTargetBranchesModule: CommandModule<{}, CheckTargetBranchesOptions> = {
|
||||||
|
handler,
|
||||||
|
builder,
|
||||||
|
command: 'check-target-branches <pr>',
|
||||||
|
describe: 'Check a PR to determine what branches it is currently targeting',
|
||||||
|
};
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
import * as yargs from 'yargs';
|
import * as yargs from 'yargs';
|
||||||
|
|
||||||
|
import {CheckTargetBranchesModule} from './check-target-branches/cli';
|
||||||
import {CheckoutCommandModule} from './checkout/cli';
|
import {CheckoutCommandModule} from './checkout/cli';
|
||||||
import {buildDiscoverNewConflictsCommand, handleDiscoverNewConflictsCommand} from './discover-new-conflicts/cli';
|
import {buildDiscoverNewConflictsCommand, handleDiscoverNewConflictsCommand} from './discover-new-conflicts/cli';
|
||||||
import {buildMergeCommand, handleMergeCommand} from './merge/cli';
|
import {buildMergeCommand, handleMergeCommand} from './merge/cli';
|
||||||
@ -26,5 +27,6 @@ export function buildPrParser(localYargs: yargs.Argv) {
|
|||||||
.command(
|
.command(
|
||||||
'rebase <pr-number>', 'Rebase a pending PR and push the rebased commits back to Github',
|
'rebase <pr-number>', 'Rebase a pending PR and push the rebased commits back to Github',
|
||||||
buildRebaseCommand, handleRebaseCommand)
|
buildRebaseCommand, handleRebaseCommand)
|
||||||
.command(CheckoutCommandModule);
|
.command(CheckoutCommandModule)
|
||||||
|
.command(CheckTargetBranchesModule);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user