Skip to content

Commit

Permalink
Add merge modes and refactor methods
Browse files Browse the repository at this point in the history
  • Loading branch information
0x2b3bfa0 authored Apr 3, 2022
1 parent 556138d commit a6d7dd7
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 70 deletions.
7 changes: 4 additions & 3 deletions bin/cml/pr.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ exports.builder = (yargs) =>
description: 'Output in markdown format [](url).'
},
autoMerge: {
type: 'boolean',
description:
'Mark the PR/MR for automatic merging after tests pass (unsupported by Bitbucket).'
type: 'string',
choices: ['merge', 'rebase', 'squash'],
coerce: (val) => (val === '' ? 'merge' : val),
description: 'Mark the PR/MR for automatic merging after tests pass.'
},
remote: {
type: 'string',
Expand Down
39 changes: 26 additions & 13 deletions src/drivers/bitbucket_cloud.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,32 +128,45 @@ class BitbucketCloud {
}
}
});
const endpoint = `/repositories/${projectPath}/pullrequests`;
const endpoint = `/repositories/${projectPath}/pullrequests/`;
const {
id,
links: {
html: { href }
}
} = await this.request({
method: 'POST',
endpoint: `${endpoint}/`,
endpoint,
body
});

if (autoMerge) {
winston.warn(
'Auto-merge is unsupported by Bitbucket Cloud; see https://jira.atlassian.com/browse/BCLOUD-14286. Trying to merge immediately...'
);
await this.request({
method: 'POST',
endpoint: `${endpoint}/${id}/merge`,
body
});
}

if (autoMerge)
await this.prAutoMerge({ pullRequestId: id, mergeMode: autoMerge });
return href;
}

async prAutoMerge({ pullRequestId, mergeMode, mergeMessage = undefined }) {
winston.warn(
'Auto-merge is unsupported by Bitbucket Cloud; see https://jira.atlassian.com/browse/BCLOUD-14286. Trying to merge immediately...'
);
const { projectPath } = this;
const endpoint = `/repositories/${projectPath}/pullrequests/${pullRequestId}/merge`;
const body = {
merge_strategy: {
merge: 'merge_commit',
rebase: 'fast_forward',
squash: 'squash'
}[mergeMode],
close_source_branch: true,
message: mergeMessage
};
await this.request({
method: 'POST',
endpoint,
body
});
}

async prCommentCreate(opts = {}) {
const { projectPath } = this;
const { report, prNumber } = opts;
Expand Down
78 changes: 47 additions & 31 deletions src/drivers/github.js
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ class Github {
const { pulls } = octokit(this.token, this.repo);

const {
data: { html_url: htmlUrl, node_id: nodeId, number }
data: { html_url: htmlUrl, node_id: nodeId }
} = await pulls.create({
owner,
repo,
Expand All @@ -363,17 +363,12 @@ class Github {
body
});

if (autoMerge) {
try {
await this.prAutoMerge({ pullRequestId: nodeId, base });
} catch ({ message }) {
winston.warn(
`Failed to enable auto-merge: ${message}. Trying to merge immediately...`
);
await pulls.merge({ owner, repo, pull_number: number });
}
}

if (autoMerge)
await this.prAutoMerge({
pullRequestId: nodeId,
mergeMode: autoMerge,
base
});
return htmlUrl;
}

Expand Down Expand Up @@ -403,45 +398,66 @@ class Github {
* @param {{ pullRequestId: number, base: string }} param0
* @returns {Promise<void>}
*/
async prAutoMerge({ pullRequestId, base }) {
async prAutoMerge({
pullRequestId,
mergeMode,
mergeMessage = undefined,
base
}) {
const octo = octokit(this.token, this.repo);
const graphql = withCustomRequest(octo.request);

const [commitHeadline, commitBody] =
mergeMessage === undefined ? [] : mergeMessage.split(/\n\n(.*)/s);
try {
await graphql(
`
mutation autoMerge($pullRequestId: ID!) {
enablePullRequestAutoMerge(
input: { pullRequestId: $pullRequestId }
input: {
pullRequestId: $pullRequestId
mergeMethod: $mergeMethod
commitHeadline: $commitHeadline
commitBody: $commitBody
}
) {
clientMutationId
}
}
`,
{
pullRequestId
pullRequestId,
mergeMethod: mergeMode.toUpperCase(),
commitHeadline,
commitBody
}
);
} catch (error) {
} catch (err) {
if (
error.message.includes("Can't enable auto-merge for this pull request")
) {
const { owner, repo } = this.ownerRepo();
const settingsUrl = `https://github.com/${owner}/${repo}/settings`;

const isProtected = await this.isProtected({ branch: base });
if (!isProtected) {
throw new Error(
`Enabling Auto-Merge failed. Please set up branch protection and add "required status checks" for branch '${base}': ${settingsUrl}/branches`
);
}
!err.message.includes("Can't enable auto-merge for this pull request")
)
throw err;

const { owner, repo } = this.ownerRepo();
const settingsUrl = `https://github.com/${owner}/${repo}/settings`;

throw new Error(
`Enabling Auto-Merge failed. Enable the feature in your repository settings: ${settingsUrl}#merge_types_auto_merge`
if (!(await this.isProtected({ branch: base }))) {
winston.warn(
`Failed to enable auto-merge: Set up branch protection and add "required status checks" for branch '${base}': ${settingsUrl}/branches. Trying to merge immediately...`
);
} else {
winston.warn(
`Failed to enable auto-merge: Enable the feature in your repository settings: ${settingsUrl}#merge_types_auto_merge. Trying to merge immediately...`
);
}

throw error;
await octo.pulls.merge({
owner,
repo,
pull_number: pullRequestId,
merge_method: mergeMode,
commit_title: commitHeadline,
commit_message: commitBody
});
}
}

Expand Down
54 changes: 31 additions & 23 deletions src/drivers/gitlab.js
Original file line number Diff line number Diff line change
Expand Up @@ -272,41 +272,49 @@ class Gitlab {
body
});

if (autoMerge) {
try {
await this.prAutoMerge({ mergeRequestId: iid });
} catch ({ message }) {
winston.warn(
`Failed to enable auto-merge: ${message}. Trying to merge immediately...`
);
await this.prAutoMerge({
mergeRequestId: iid,
whenPipelineSucceeds: false
});
}
}

if (autoMerge)
await this.prAutoMerge({ pullRequestId: iid, mergeMode: autoMerge });
return url;
}

/**
* @param {{ mergeRequestId: string }} param0
* @returns {Promise<void>}
*/
async prAutoMerge({ mergeRequestId, whenPipelineSucceeds = true }) {
async prAutoMerge({ mergeRequestId, mergeMode, mergeMessage = undefined }) {
if (mergeMode === 'rebase')
throw new Error(`Rebase auto-merge mode not implemented for GitLab`);

const projectPath = await this.projectPath();

const endpoint = `/projects/${projectPath}/merge_requests/${mergeRequestId}/merge`;
const body = new URLSearchParams();
body.append('merge_when_pipeline_succeeds', whenPipelineSucceeds);
body.append('merge_when_pipeline_succeeds', true);
body.append('squash', mergeMode === 'squash');
if (mergeMessage !== undefined)
body.append(`${mergeMode}_commit_message`, mergeMessage);

await backOff(() =>
this.request({
endpoint,
method: 'PUT',
body
})
);
try {
await backOff(() =>
this.request({
endpoint,
method: 'PUT',
body
})
);
} catch ({ message }) {
winston.warn(
`Failed to enable auto-merge: ${message}. Trying to merge immediately...`
);
body.delete('merge_when_pipeline_succeeds');
await backOff(() =>
this.request({
endpoint,
method: 'PUT',
body
})
);
}
}

async prCommentCreate(opts = {}) {
Expand Down

0 comments on commit a6d7dd7

Please sign in to comment.