Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: expose merge strategy for configuration when automerging #10627

Merged
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 19 additions & 0 deletions docs/usage/configuration-options.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,25 @@ Example use:
}
```

## automergeStrategy

This setting is only applicable if you opt-in by configuring `automerge` to `true` and `automergeType` to `pr` for any of your dependencies.

The automerge strategy defaults to `auto`, in which Renovate will make its best guess as to how to merge pull requests.
This generally results in Renovate respecting the strategy configured in the platform itself for the repository if possible.
Acceptable values are:

- `auto`, in which the choice is left to Renovate
- `fast-forward`, which generally involves no new commits in the resultant tree, but "fast-forwarding" the main branch reference
- `merge-commit`, which generally involves synthesizing a new merge commit
- `rebase`, which generally involves rewriting history as part of the merge — but usually retaining the individual commits
jbirch-atlassian marked this conversation as resolved.
Show resolved Hide resolved
- `squash`, which generally involves flattening the commits that are being merged into a single new commit

Not all platforms support all pull request merge strategies.
In cases where a merge strategy is not supported by the platform, Renovate will hold off on merging instead of silently merging in a way you didn't wish for.

The only platform that supports `automergeStrategy` is Bitbucket Cloud.

## automergeType

This setting is only applicable if you opt in to configure `automerge` to `true` for any of your dependencies.
Expand Down
8 changes: 8 additions & 0 deletions lib/config/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1284,6 +1284,14 @@ const options: RenovateOptions[] = [
allowedValues: ['branch', 'pr', 'pr-comment'],
default: 'pr',
},
{
name: 'automergeStrategy',
description:
'The merge strategy to use when automerging PRs. Used only if automergeType=pr or automergeType=pr-comment',
jbirch-atlassian marked this conversation as resolved.
Show resolved Hide resolved
type: 'string',
allowedValues: ['auto', 'fast-forward', 'merge-commit', 'rebase', 'squash'],
default: 'auto',
},
{
name: 'automergeComment',
description:
Expand Down
8 changes: 8 additions & 0 deletions lib/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface GroupConfig extends Record<string, unknown> {
export interface RenovateSharedConfig {
$schema?: string;
automerge?: boolean;
automergeStrategy?: MergeStrategy;
branchPrefix?: string;
branchName?: string;
manager?: string;
Expand Down Expand Up @@ -229,6 +230,13 @@ export type UpdateType =

export type MatchStringsStrategy = 'any' | 'recursive' | 'combination';

export type MergeStrategy =
| 'auto'
| 'fast-forward'
| 'merge-commit'
| 'rebase'
| 'squash';

// TODO: Proper typings
export interface PackageRule
extends RenovateSharedConfig,
Expand Down
5 changes: 5 additions & 0 deletions lib/platform/azure/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Azure DevOps and Azure DevOps Server

## Features awaiting implementation

- The `automergeStrategy` configuration option has not been implemented for this platform, and all values behave as if the value `auto` was used. Renovate will use the merge strategy configured in the Azure Repos repository itself, and this cannot be overridden yet
jbirch-atlassian marked this conversation as resolved.
Show resolved Hide resolved
1 change: 1 addition & 0 deletions lib/platform/bitbucket-server/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
## Features awaiting implementation

- Creating issues not implemented yet, used to alert users when there is a config error
- The `automergeStrategy` configuration option has not been implemented for this platform, and all values behave as if the value `auto` was used. Renovate will implicitly use the merge strategy configured as 'default' in the Bitbucket Server repository itself, and this cannot be overridden yet

## Testing

Expand Down
124 changes: 122 additions & 2 deletions lib/platform/bitbucket/__snapshots__/index.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -1254,7 +1254,7 @@ Array [

exports[`platform/bitbucket/index massageMarkdown() returns diff files 1`] = `"**foo**bartext"`;

exports[`platform/bitbucket/index mergePr() posts Merge 1`] = `
exports[`platform/bitbucket/index mergePr() posts Merge with auto 1`] = `
Array [
Object {
"headers": Object {
Expand All @@ -1268,7 +1268,67 @@ Array [
"url": "https://api.bitbucket.org/2.0/repositories/some/repo",
},
Object {
"body": "{\\"close_source_branch\\":true,\\"merge_strategy\\":\\"merge_commit\\",\\"message\\":\\"auto merged\\"}",
"body": "{\\"close_source_branch\\":true,\\"message\\":\\"auto merged\\"}",
"headers": Object {
"accept": "application/json",
"accept-encoding": "gzip, deflate, br",
"authorization": "Basic YWJjOjEyMw==",
"content-length": "52",
"content-type": "application/json",
"host": "api.bitbucket.org",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"method": "POST",
"url": "https://api.bitbucket.org/2.0/repositories/some/repo/pullrequests/5/merge",
},
]
`;

exports[`platform/bitbucket/index mergePr() posts Merge with fast-forward 1`] = `
Array [
Object {
"headers": Object {
"accept": "application/json",
"accept-encoding": "gzip, deflate, br",
"authorization": "Basic YWJjOjEyMw==",
"host": "api.bitbucket.org",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"method": "GET",
"url": "https://api.bitbucket.org/2.0/repositories/some/repo",
},
Object {
"body": "{\\"close_source_branch\\":true,\\"message\\":\\"auto merged\\",\\"merge_strategy\\":\\"fast_forward\\"}",
"headers": Object {
"accept": "application/json",
"accept-encoding": "gzip, deflate, br",
"authorization": "Basic YWJjOjEyMw==",
"content-length": "84",
"content-type": "application/json",
"host": "api.bitbucket.org",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"method": "POST",
"url": "https://api.bitbucket.org/2.0/repositories/some/repo/pullrequests/5/merge",
},
]
`;

exports[`platform/bitbucket/index mergePr() posts Merge with merge-commit 1`] = `
Array [
Object {
"headers": Object {
"accept": "application/json",
"accept-encoding": "gzip, deflate, br",
"authorization": "Basic YWJjOjEyMw==",
"host": "api.bitbucket.org",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"method": "GET",
"url": "https://api.bitbucket.org/2.0/repositories/some/repo",
},
Object {
"body": "{\\"close_source_branch\\":true,\\"message\\":\\"auto merged\\",\\"merge_strategy\\":\\"merge_commit\\"}",
"headers": Object {
"accept": "application/json",
"accept-encoding": "gzip, deflate, br",
Expand All @@ -1284,6 +1344,66 @@ Array [
]
`;

exports[`platform/bitbucket/index mergePr() posts Merge with optional merge strategy 1`] = `
Array [
Object {
"headers": Object {
"accept": "application/json",
"accept-encoding": "gzip, deflate, br",
"authorization": "Basic YWJjOjEyMw==",
"host": "api.bitbucket.org",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"method": "GET",
"url": "https://api.bitbucket.org/2.0/repositories/some/repo",
},
Object {
"body": "{\\"close_source_branch\\":true,\\"message\\":\\"auto merged\\"}",
"headers": Object {
"accept": "application/json",
"accept-encoding": "gzip, deflate, br",
"authorization": "Basic YWJjOjEyMw==",
"content-length": "52",
"content-type": "application/json",
"host": "api.bitbucket.org",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"method": "POST",
"url": "https://api.bitbucket.org/2.0/repositories/some/repo/pullrequests/5/merge",
},
]
`;

exports[`platform/bitbucket/index mergePr() posts Merge with squash 1`] = `
Array [
Object {
"headers": Object {
"accept": "application/json",
"accept-encoding": "gzip, deflate, br",
"authorization": "Basic YWJjOjEyMw==",
"host": "api.bitbucket.org",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"method": "GET",
"url": "https://api.bitbucket.org/2.0/repositories/some/repo",
},
Object {
"body": "{\\"close_source_branch\\":true,\\"message\\":\\"auto merged\\",\\"merge_strategy\\":\\"squash\\"}",
"headers": Object {
"accept": "application/json",
"accept-encoding": "gzip, deflate, br",
"authorization": "Basic YWJjOjEyMw==",
"content-length": "78",
"content-type": "application/json",
"host": "api.bitbucket.org",
"user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)",
},
"method": "POST",
"url": "https://api.bitbucket.org/2.0/repositories/some/repo/pullrequests/5/merge",
},
]
`;

exports[`platform/bitbucket/index setBranchStatus() posts status 1`] = `
Array [
Object {
Expand Down
1 change: 1 addition & 0 deletions lib/platform/bitbucket/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Unsupported platform features/concepts

- Adding assignees to PRs not supported (does not seem to be a Bitbucket concept)
- `automergeStrategy=rebase` not supported by BitBucket Cloud, see [Jira issue BCLOUD-16610](https://jira.atlassian.com/browse/BCLOUD-16610)

## Features requiring implementation

Expand Down
35 changes: 34 additions & 1 deletion lib/platform/bitbucket/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -819,12 +819,45 @@ describe(getName(), () => {
});

describe('mergePr()', () => {
it('posts Merge', async () => {
it('posts Merge with optional merge strategy', async () => {
const scope = await initRepoMock();
scope.post('/2.0/repositories/some/repo/pullrequests/5/merge').reply(200);
await bitbucket.mergePr(5, 'branch');
expect(httpMock.getTrace()).toMatchSnapshot();
});

it('posts Merge with auto', async () => {
const scope = await initRepoMock();
scope.post('/2.0/repositories/some/repo/pullrequests/5/merge').reply(200);
await bitbucket.mergePr(5, 'branch', 'auto');
expect(httpMock.getTrace()).toMatchSnapshot();
});

it('posts Merge with merge-commit', async () => {
const scope = await initRepoMock();
scope.post('/2.0/repositories/some/repo/pullrequests/5/merge').reply(200);
await bitbucket.mergePr(5, 'branch', 'merge-commit');
expect(httpMock.getTrace()).toMatchSnapshot();
});

it('posts Merge with squash', async () => {
const scope = await initRepoMock();
scope.post('/2.0/repositories/some/repo/pullrequests/5/merge').reply(200);
await bitbucket.mergePr(5, 'branch', 'squash');
expect(httpMock.getTrace()).toMatchSnapshot();
});

it('does not post Merge with rebase', async () => {
await bitbucket.mergePr(5, 'branch', 'rebase');
expect(httpMock.getTrace()).toEqual([]);
});

it('posts Merge with fast-forward', async () => {
const scope = await initRepoMock();
scope.post('/2.0/repositories/some/repo/pullrequests/5/merge').reply(200);
await bitbucket.mergePr(5, 'branch', 'fast-forward');
expect(httpMock.getTrace()).toMatchSnapshot();
});
});

describe('getVulnerabilityAlerts()', () => {
Expand Down
22 changes: 13 additions & 9 deletions lib/platform/bitbucket/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import URL from 'url';
import is from '@sindresorhus/is';
import parseDiff from 'parse-diff';
import type { MergeStrategy } from '../../config/types';
import { REPOSITORY_NOT_FOUND } from '../../constants/error-messages';
import { PLATFORM_TYPE_BITBUCKET } from '../../constants/platforms';
import { logger } from '../../logger';
Expand Down Expand Up @@ -29,7 +30,7 @@ import { smartTruncate } from '../utils/pr-body';
import { readOnlyIssueBody } from '../utils/read-only-issue-body';
import * as comments from './comments';
import * as utils from './utils';
import { PrResponse, RepoInfoBody } from './utils';
import { PrResponse, RepoInfoBody, mergeBodyTransformer } from './utils';

const bitbucketHttp = new BitbucketHttp();

Expand Down Expand Up @@ -395,7 +396,7 @@ export async function setBranchStatus({
const sha = await getBranchCommit(branchName);

// TargetUrl can not be empty so default to bitbucket
const url = targetUrl || /* istanbul ignore next */ 'http://bitbucket.org';
const url = targetUrl || /* istanbul ignore next */ 'https://bitbucket.org';

const body = {
name: context,
Expand Down Expand Up @@ -752,19 +753,22 @@ export async function updatePr({

export async function mergePr(
prNo: number,
branchName: string
branchName: string,
mergeStrategy: MergeStrategy
): Promise<boolean> {
logger.debug(`mergePr(${prNo}, ${branchName})`);
logger.debug(`mergePr(${prNo}, ${branchName}, ${mergeStrategy})`);

// Bitbucket Cloud does not support a rebase-alike; https://jira.atlassian.com/browse/BCLOUD-16610
if (mergeStrategy === 'rebase') {
logger.warn('Bitbucket Cloud does not support a "rebase" strategy.');
return false;
}

try {
await bitbucketHttp.postJson(
`/2.0/repositories/${config.repository}/pullrequests/${prNo}/merge`,
{
body: {
close_source_branch: true,
merge_strategy: 'merge_commit',
message: 'auto merged',
},
body: mergeBodyTransformer(mergeStrategy),
}
);
logger.debug('Automerging succeeded');
Expand Down
7 changes: 7 additions & 0 deletions lib/platform/bitbucket/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export type BitbucketMergeStrategy = 'fast_forward' | 'merge_commit' | 'squash';

export interface MergeRequestBody {
close_source_branch?: boolean;
message: string;
merge_strategy?: BitbucketMergeStrategy;
}
25 changes: 25 additions & 0 deletions lib/platform/bitbucket/utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import url from 'url';
import type { MergeStrategy } from '../../config/types';
import { BranchStatus, PrState } from '../../types';
import { HttpOptions, HttpPostOptions, HttpResponse } from '../../util/http';
import { BitbucketHttp } from '../../util/http/bitbucket';
import type { Pr } from '../types';
import type { BitbucketMergeStrategy, MergeRequestBody } from './types';

const bitbucketHttp = new BitbucketHttp();

Expand Down Expand Up @@ -56,6 +58,29 @@ export function repoInfoTransformer(repoInfoBody: RepoInfoBody): RepoInfo {
};
}

const bitbucketMergeStrategies: Map<MergeStrategy, BitbucketMergeStrategy> =
new Map([
['squash', 'squash'],
['merge-commit', 'merge_commit'],
['fast-forward', 'fast_forward'],
]);

export function mergeBodyTransformer(
mergeStrategy: MergeStrategy
): MergeRequestBody {
const body: MergeRequestBody = {
close_source_branch: true,
message: 'auto merged',
};

// The `auto` strategy will use the strategy configured inside Bitbucket.
if (mergeStrategy !== 'auto') {
body.merge_strategy = bitbucketMergeStrategies.get(mergeStrategy);
}

return body;
}

export const prStates = {
open: ['OPEN'],
notOpen: ['MERGED', 'DECLINED', 'SUPERSEDED'],
Expand Down
4 changes: 4 additions & 0 deletions lib/platform/gitea/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@
## Unsupported platform features/concepts

- **Adding reviewers to PRs not supported**: Gitea versions older than v1.14.0 do not have the required API.

## Features awaiting implementation

- The `automergeStrategy` configuration option has not been implemented for this platform, and all values behave as if the value `auto` was used. Renovate will use the merge strategy configured in the Gitea repository itself, and this cannot be overridden yet
5 changes: 5 additions & 0 deletions lib/platform/github/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# GitHub and GitHub Enterprise

## Features awaiting implementation

- The `automergeStrategy` configuration option has not been implemented for this platform, and all values behave as if the value `auto` was used. Renovate will use the merge strategy configured in the GitHub repository itself, and this cannot be overridden yet