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(platform): re-attempt platform automerge on github and gitlab #26567

Merged
merged 26 commits into from Mar 18, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
77dfd20
feat(platform/github): re-attempt platform automerge
straub Jan 9, 2024
46f0aaa
Merge branch 'main' into feat/github-refreshPr-tryPrAutomerge
straub Jan 9, 2024
5667cf4
refactor(platform/github): use a new function, reattemptPlatformAutom…
straub Jan 10, 2024
206bdf9
refactor(platform/github): less renaming
straub Jan 10, 2024
967e9bb
docs(platformAutomerge): address new GitHub Merge Queue behavior
straub Jan 10, 2024
c69d58e
docs(platformAutomerge): rm extra blank line
straub Jan 10, 2024
d5591ca
Merge branch 'main' into feat/github-refreshPr-tryPrAutomerge
straub Jan 10, 2024
f3417d0
docs(platformAutomerge): fix typo
straub Jan 10, 2024
aa59178
fix(platform/github): correct inconsistent log message
straub Jan 10, 2024
318b7c2
refactor(platform/github): number -> prNo
straub Jan 10, 2024
e2515dd
refactor(workers/repository/update/branch): add boolean checks from t…
straub Jan 11, 2024
fafbc3a
fix(workers/repository/update/branch): use optional chaining on platf…
straub Jan 11, 2024
3023529
fix(workers/repository/update/branch): rm config.autoMergeAllowed che…
straub Jan 11, 2024
89227b7
Merge branch 'main' into feat/github-refreshPr-tryPrAutomerge
straub Jan 11, 2024
5de6b57
perf(platform/github): fetch PR from cache in reattemptPlatformAutomerge
straub Jan 16, 2024
e62dac6
Update lib/modules/platform/github/index.ts
viceice Jan 17, 2024
89b9f94
Update lib/modules/platform/github/index.ts
viceice Jan 17, 2024
1f6fb0a
Merge branch 'main' into feat/github-refreshPr-tryPrAutomerge
viceice Jan 17, 2024
3eb4a39
Merge branch 'main' into feat/github-refreshPr-tryPrAutomerge
straub Feb 29, 2024
5da6078
test(platform/github): add restGetPrList to mocks
straub Feb 29, 2024
2d9d267
Merge branch 'main' into feat/github-refreshPr-tryPrAutomerge
straub Mar 7, 2024
1d97360
Merge branch 'main' into feat/github-refreshPr-tryPrAutomerge
straub Mar 16, 2024
71550f3
refactor(platform/gitlab): move automerge re-attempt from updatePr to…
straub Mar 16, 2024
d556665
Merge branch 'main' into feat/github-refreshPr-tryPrAutomerge
straub Mar 16, 2024
b4d3419
test(platform/gitlab): resolve coverage issue
straub Mar 16, 2024
aa67c3e
Merge branch 'main' into feat/github-refreshPr-tryPrAutomerge
straub Mar 17, 2024
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
3 changes: 2 additions & 1 deletion docs/usage/configuration-options.md
Expand Up @@ -3003,8 +3003,9 @@ If enabled Renovate will pin Docker images or GitHub Actions by means of their S

If you have enabled `automerge` and set `automergeType=pr` in the Renovate config, then leaving `platformAutomerge` as `true` speeds up merging via the platform's native automerge functionality.

Renovate tries platform-native automerge only when it initially creates the PR.
On most platforms, Renovate tries platform-native automerge only when it initially creates the PR.
Any PR that is being updated will be automerged with the Renovate-based automerge.
On GitHub, Renovate re-enables the PR for automerge whenever it's rebased, so that merge conflicts encountered in the Merge Queue can be resolved.
straub marked this conversation as resolved.
Show resolved Hide resolved

`platformAutomerge` will configure PRs to be merged after all (if any) branch policies have been met.
This option is available for Azure, Gitea, GitHub and GitLab.
Expand Down
87 changes: 86 additions & 1 deletion lib/modules/platform/github/index.spec.ts
Expand Up @@ -17,7 +17,12 @@ import * as _hostRules from '../../../util/host-rules';
import { setBaseUrl } from '../../../util/http/github';
import { toBase64 } from '../../../util/string';
import { hashBody } from '../pr-body';
import type { CreatePRConfig, RepoParams, UpdatePrConfig } from '../types';
import type {
CreatePRConfig,
ReattemptPlatformAutomergeConfig,
RepoParams,
UpdatePrConfig,
} from '../types';
import * as branch from './branch';
import type { ApiPageCache, GhRestPr } from './types';
import * as github from '.';
Expand Down Expand Up @@ -3111,6 +3116,86 @@ describe('modules/platform/github/index', () => {
});
});

describe('reattemptPlatformAutomerge(prNo, platformOptions)', () => {
const getPrResp = {
number: 123,
node_id: 'abcd',
head: { repo: { full_name: 'some/repo' } },
};

const graphqlAutomergeResp = {
data: {
enablePullRequestAutoMerge: {
pullRequest: {
number: 123,
},
},
},
};

const pr: ReattemptPlatformAutomergeConfig = {
prNo: 123,
platformOptions: { usePlatformAutomerge: true },
};

const mockScope = async (repoOpts: any = {}): Promise<httpMock.Scope> => {
const scope = httpMock.scope(githubApiHost);
initRepoMock(scope, 'some/repo', repoOpts);
scope.get('/repos/some/repo/pulls/123').reply(200, getPrResp);
await github.initRepo({ repository: 'some/repo' });
return scope;
};

const graphqlGetRepo = {
method: 'POST',
url: 'https://api.github.com/graphql',
graphql: { query: { repository: {} } },
};

const restGetPr = {
method: 'GET',
url: 'https://api.github.com/repos/some/repo/pulls/123',
};

const graphqlAutomerge = {
method: 'POST',
url: 'https://api.github.com/graphql',
graphql: {
mutation: {
__vars: {
$pullRequestId: 'ID!',
$mergeMethod: 'PullRequestMergeMethod!',
},
enablePullRequestAutoMerge: {
__args: {
input: {
pullRequestId: '$pullRequestId',
mergeMethod: '$mergeMethod',
},
},
},
},
variables: {
pullRequestId: 'abcd',
mergeMethod: 'REBASE',
},
},
};

it('should set automatic merge', async () => {
const scope = await mockScope();
scope.post('/graphql').reply(200, graphqlAutomergeResp);

await expect(github.reattemptPlatformAutomerge(pr)).toResolve();

expect(httpMock.getTrace()).toMatchObject([
graphqlGetRepo,
restGetPr,
graphqlAutomerge,
]);
});
});

describe('mergePr(prNo)', () => {
it('should merge the PR', async () => {
const scope = httpMock.scope(githubApiHost);
Expand Down
20 changes: 20 additions & 0 deletions lib/modules/platform/github/index.ts
Expand Up @@ -56,6 +56,7 @@ import type {
PlatformParams,
PlatformPrOptions,
PlatformResult,
ReattemptPlatformAutomergeConfig,
RepoParams,
RepoResult,
UpdatePrConfig,
Expand Down Expand Up @@ -1731,6 +1732,25 @@ export async function updatePr({
}
}

export async function reattemptPlatformAutomerge({
prNo,
platformOptions,
}: ReattemptPlatformAutomergeConfig): Promise<void> {
try {
const result = (await getPr(prNo))!;
const { number, node_id } = result;

await tryPrAutomerge(number, node_id, platformOptions);
rarkins marked this conversation as resolved.
Show resolved Hide resolved

logger.debug(`PR platform automerge re-attempted...prNo: ${prNo}`);
} catch (err) /* istanbul ignore next */ {
straub marked this conversation as resolved.
Show resolved Hide resolved
if (err instanceof ExternalHostError) {
throw err;
}
logger.warn({ err }, 'Error re-attempting PR platform automerge');
}
}

export async function mergePr({
branchName,
id: prNo,
Expand Down
7 changes: 7 additions & 0 deletions lib/modules/platform/types.ts
Expand Up @@ -121,6 +121,10 @@ export interface UpdatePrConfig {
state?: 'open' | 'closed';
targetBranch?: string;
}
export interface ReattemptPlatformAutomergeConfig {
prNo: number;
platformOptions?: PlatformPrOptions;
}
export interface EnsureIssueConfig {
title: string;
reuseTitle?: string;
Expand Down Expand Up @@ -223,6 +227,9 @@ export interface Platform {
getPr(number: number): Promise<Pr | null>;
findPr(findPRConfig: FindPRConfig): Promise<Pr | null>;
refreshPr?(number: number): Promise<void>;
reattemptPlatformAutomerge?(
prConfig: ReattemptPlatformAutomergeConfig,
): Promise<void>;
getBranchStatus(
branchName: string,
internalChecksAsSuccess: boolean,
Expand Down
4 changes: 4 additions & 0 deletions lib/workers/repository/update/branch/index.spec.ts
Expand Up @@ -108,6 +108,7 @@ describe('workers/repository/update/branch/index', () => {
beforeEach(() => {
scm.branchExists.mockResolvedValue(false);
prWorker.ensurePr = jest.fn();
prWorker.getPlatformPrOptions = jest.fn();
prAutomerge.checkAutoMerge = jest.fn();
// TODO: incompatible types (#22198)
config = {
Expand All @@ -133,6 +134,9 @@ describe('workers/repository/update/branch/index', () => {
state: '',
}),
});
prWorker.getPlatformPrOptions.mockReturnValue({
usePlatformAutomerge: true,
});
GlobalConfig.set(adminConfig);
// TODO: fix types, jest is using wrong overload (#22198)
sanitize.sanitize.mockImplementation((input) => input!);
Expand Down
21 changes: 17 additions & 4 deletions lib/workers/repository/update/branch/index.ts
Expand Up @@ -36,7 +36,7 @@ import * as template from '../../../../util/template';
import { isLimitReached } from '../../../global/limits';
import type { BranchConfig, BranchResult, PrBlockedBy } from '../../../types';
import { embedChangelogs } from '../../changelog';
import { ensurePr } from '../pr';
import { ensurePr, getPlatformPrOptions } from '../pr';
import { checkAutoMerge } from '../pr/automerge';
import { setArtifactErrorStatus } from './artifacts';
import { tryBranchAutomerge } from './automerge';
Expand Down Expand Up @@ -570,9 +570,22 @@ export async function processBranch(
await scm.checkoutBranch(config.baseBranch);
updatesVerified = true;
}
// istanbul ignore if
if (branchPr && platform.refreshPr) {
await platform.refreshPr(branchPr.number);

if (branchPr) {
const platformOptions = getPlatformPrOptions(config);
if (
platformOptions.usePlatformAutomerge &&
platform.reattemptPlatformAutomerge
) {
await platform.reattemptPlatformAutomerge({
prNo: branchPr.number,
platformOptions,
});
}
// istanbul ignore if
if (platform.refreshPr) {
await platform.refreshPr(branchPr.number);
}
}
if (!commitSha && !branchExists) {
return {
Expand Down