@salesforce/plugin-release-management
Version:
A plugin for preparing and publishing npm packages
122 lines • 5.67 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
/*
* Copyright (c) 2020, salesforce.com, inc.
* All rights reserved.
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, camelcase*/
const os = require("os");
const command_1 = require("@salesforce/command");
const core_1 = require("@octokit/core");
const kit_1 = require("@salesforce/kit");
const ts_types_1 = require("@salesforce/ts-types");
const core_2 = require("@salesforce/core");
const dependabot_1 = require("../../dependabot");
core_2.Messages.importMessagesDirectory(__dirname);
const messages = core_2.Messages.loadMessages('@salesforce/plugin-release-management', 'dependabot.automerge');
const messagesFromConsolidate = core_2.Messages.loadMessages('@salesforce/plugin-release-management', 'dependabot.consolidate');
class AutoMerge extends command_1.SfdxCommand {
async run() {
const auth = (0, ts_types_1.ensureString)(new kit_1.Env().getString('GH_TOKEN') ?? new kit_1.Env().getString('GITHUB_TOKEN'), 'GH_TOKEN is required to be set in the environment');
const { owner, repo } = await (0, dependabot_1.getOwnerAndRepo)(this.flags.owner, this.flags.repo);
this.octokit = new core_1.Octokit({ auth });
this.baseRepoObject = {
owner,
repo,
};
this.ux.log(`owner: ${this.baseRepoObject.owner}, scope: ${this.baseRepoObject.repo}`);
const eligiblePRs = (await this.octokit.request('GET /repos/{owner}/{repo}/pulls', this.baseRepoObject)).data.filter((pr) => pr.state === 'open' && pr.user.login === 'dependabot[bot]');
const greenPRs = (await Promise.all(eligiblePRs.map((pr) => this.isGreen(pr)))).filter((pr) => pr !== undefined);
const mergeablePRs = (await Promise.all(greenPRs.map((pr) => this.isMergeable(pr)))).filter((pr) => pr !== undefined);
this.ux.table(mergeablePRs, {
title: { header: 'Green, Mergeable PR' },
html_url: { header: 'Link' },
});
this.ux.log('');
if (mergeablePRs.length === 0) {
this.ux.log('No PRs can be automerged');
return;
}
const prToMerge = mergeablePRs[0];
if (this.flags.dryrun === false) {
this.ux.log(`merging ${prToMerge.number.toString()} | ${prToMerge.title}`);
const opts = {
...this.baseRepoObject,
merge_method: this.flags['merge-method'],
pull_number: prToMerge.number,
};
if (this.flags['skip-ci']) {
opts.commit_title = `Merge pull request #${prToMerge.number} from ${prToMerge.head.ref} [skip ci]`;
}
const mergeResult = await this.octokit.request('PUT /repos/{owner}/{repo}/pulls/{pull_number}/merge', opts);
this.ux.logJson(mergeResult);
}
else {
this.ux.log(`dry run ${prToMerge.number.toString()} | ${prToMerge.title}`);
}
}
async isGreen(pr) {
const statusResponse = await this.octokit.request('GET /repos/{owner}/{repo}/commits/{ref}/status', {
...this.baseRepoObject,
ref: pr.head.sha,
});
// no point looking at check runs if the commit status is not green
if (statusResponse.data.state !== 'success') {
return undefined;
}
const checkRunResponse = await this.octokit.request('GET /repos/{owner}/{repo}/commits/{ref}/check-runs', {
...this.baseRepoObject,
ref: pr.head.sha,
});
this.ux.logJson(checkRunResponse.data);
if (checkRunResponse.data.check_runs.every((cr) => cr.status === 'completed' && ['success', 'skipped'].includes(cr.conclusion))) {
return pr;
}
}
async isMergeable(pr) {
const statusResponse = await this.octokit.request('GET /repos/{owner}/{repo}/pulls/{pull_number}', {
...this.baseRepoObject,
pull_number: pr.number,
});
// mergeable_state of 'blocked' is ok because that's just missing an approval.
// We're screening out 'behind' which might be merge conflicts.
// Dependabot should rebase this PR eventually
if (statusResponse.data.mergeable === true && statusResponse.data.mergeable_state !== 'behind') {
return pr;
}
}
}
exports.default = AutoMerge;
AutoMerge.description = messages.getMessage('description');
AutoMerge.examples = messages.getMessage('examples').split(os.EOL);
AutoMerge.flagsConfig = {
owner: command_1.flags.string({
char: 'o',
description: messagesFromConsolidate.getMessage('owner'),
dependsOn: ['repo'],
}),
repo: command_1.flags.string({
char: 'r',
description: messagesFromConsolidate.getMessage('repo'),
dependsOn: ['owner'],
}),
'max-version-bump': dependabot_1.maxVersionBumpFlag,
dryrun: command_1.flags.boolean({
description: messagesFromConsolidate.getMessage('dryrun'),
char: 'd',
default: false,
}),
'skip-ci': command_1.flags.boolean({
description: messages.getMessage('skipCi'),
char: 's',
default: false,
}),
'merge-method': command_1.flags.enum({
description: messages.getMessage('mergeMethod'),
options: ['merge', 'squash', 'rebase'],
default: 'merge',
}),
};
//# sourceMappingURL=automerge.js.map