Skip to content

Commit

Permalink
feat(platform/gitlab): handle detailed_merge_status to proceed with a…
Browse files Browse the repository at this point in the history
…utomerge (#26438)

Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
  • Loading branch information
javaxiss and viceice committed Jan 5, 2024
1 parent 8bcf740 commit 31dc0fd
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 4 deletions.
8 changes: 7 additions & 1 deletion docs/usage/self-hosted-experimental.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ If set, Renovate will terminate the whole process group of a terminated child pr
## `RENOVATE_X_GITLAB_AUTO_MERGEABLE_CHECK_ATTEMPS`

If set to an positive integer, Renovate will use this as the number of attempts to check if a merge request on GitLab is mergable before trying to automerge.
The formula for the delay between attempts is `250 * attempt * attempt` milliseconds.
The formula for the delay between attempts is `RENOVATE_X_GITLAB_MERGE_REQUEST_DELAY * attempt * attempt` milliseconds.

Default value: `5` (attempts results in max. 13.75 seconds timeout).

Expand All @@ -108,6 +108,12 @@ Can be useful for slow-running, self-hosted GitLab instances that don't react fa

Default value: `1000` (milliseconds).

## `RENOVATE_X_GITLAB_MERGE_REQUEST_DELAY`

If set, Renovate will use this as a delay to proceed with an automerge.

Default value: `250` (milliseconds).

## `RENOVATE_X_HARD_EXIT`

If set to any value, Renovate will use a "hard" `process.exit()` once all work is done, even if a sub-process is otherwise delaying Node.js from exiting.
Expand Down
40 changes: 40 additions & 0 deletions lib/modules/platform/gitlab/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ describe('modules/platform/gitlab/index', () => {
delete process.env.GITLAB_IGNORE_REPO_URL;
delete process.env.RENOVATE_X_GITLAB_BRANCH_STATUS_DELAY;
delete process.env.RENOVATE_X_GITLAB_AUTO_MERGEABLE_CHECK_ATTEMPS;
delete process.env.RENOVATE_X_GITLAB_MERGE_REQUEST_DELAY;
});

async function initFakePlatform(version: string) {
Expand Down Expand Up @@ -1867,6 +1868,45 @@ describe('modules/platform/gitlab/index', () => {
]);
});

it('should parse detailed_merge_status attribute on >= 15.6', async () => {
await initPlatform('15.6.0-ee');
httpMock
.scope(gitlabApiHost)
.post('/api/v4/projects/undefined/merge_requests')
.reply(200, {
id: 1,
iid: 12345,
title: 'some title',
})
.get('/api/v4/projects/undefined/merge_requests/12345')
.reply(200)
.get('/api/v4/projects/undefined/merge_requests/12345')
.reply(200)
.get('/api/v4/projects/undefined/merge_requests/12345')
.reply(200)
.put('/api/v4/projects/undefined/merge_requests/12345/merge')
.reply(200);
process.env.RENOVATE_X_GITLAB_AUTO_MERGEABLE_CHECK_ATTEMPS = '3';
process.env.RENOVATE_X_GITLAB_MERGE_REQUEST_DELAY = '100';
const pr = await gitlab.createPr({
sourceBranch: 'some-branch',
targetBranch: 'master',
prTitle: 'some-title',
prBody: 'the-body',
platformOptions: {
usePlatformAutomerge: true,
},
});
expect(pr).toEqual({
id: 1,
iid: 12345,
number: 12345,
sourceBranch: 'some-branch',
title: 'some title',
});
expect(timers.setTimeout.mock.calls).toMatchObject([[100], [400], [900]]);
});

it('raises with squash enabled when repository squash option is default_on', async () => {
await initPlatform('14.0.0');

Expand Down
26 changes: 23 additions & 3 deletions lib/modules/platform/gitlab/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -644,26 +644,46 @@ async function tryPrAutomerge(
await ignoreApprovals(pr);
}

const desiredStatus = 'can_be_merged';
let desiredStatus = 'can_be_merged';
// The default value of 5 attempts results in max. 13.75 seconds timeout if no pipeline created.
const retryTimes = parseInteger(
process.env.RENOVATE_X_GITLAB_AUTO_MERGEABLE_CHECK_ATTEMPS,
5,
);

if (semver.gte(defaults.version, '15.6.0')) {
logger.trace(
{ version: defaults.version },
'In GitLab 15.6 merge_status, using detailed_merge_status to check the merge request status',
);
desiredStatus = 'mergeable';
}

const mergeDelay = parseInteger(
process.env.RENOVATE_X_GITLAB_MERGE_REQUEST_DELAY,
250,
);

// Check for correct merge request status before setting `merge_when_pipeline_succeeds` to `true`.
for (let attempt = 1; attempt <= retryTimes; attempt += 1) {
const { body } = await gitlabApi.getJson<{
merge_status: string;
detailed_merge_status?: string;
pipeline: string;
}>(`projects/${config.repository}/merge_requests/${pr}`, {
memCache: false,
});
// Only continue if the merge request can be merged and has a pipeline.
if (body.merge_status === desiredStatus && body.pipeline !== null) {
if (
((desiredStatus === 'mergeable' &&
body.detailed_merge_status === desiredStatus) ||
(desiredStatus === 'can_be_merged' &&
body.merge_status === desiredStatus)) &&
body.pipeline !== null
) {
break;
}
await setTimeout(250 * attempt ** 2); // exponential backoff
await setTimeout(mergeDelay * attempt ** 2); // exponential backoff
}

await gitlabApi.putJson(
Expand Down

0 comments on commit 31dc0fd

Please sign in to comment.