From 56bd6004859d5c68b1419068993dcd392b94d27a Mon Sep 17 00:00:00 2001 From: Felipe Santos Date: Sun, 1 Dec 2024 15:51:45 +0000 Subject: [PATCH] feat(gitlab,azure): try approving before auto-merge --- lib/modules/platform/azure/index.ts | 55 +++++++++++++++------------- lib/modules/platform/gerrit/index.ts | 2 +- lib/modules/platform/gitlab/http.ts | 5 +++ lib/modules/platform/gitlab/index.ts | 19 ++++++++++ lib/modules/platform/gitlab/types.ts | 4 ++ 5 files changed, 59 insertions(+), 26 deletions(-) diff --git a/lib/modules/platform/azure/index.ts b/lib/modules/platform/azure/index.ts index 21bd44eaa3f58cc..c6929bf872353ab 100644 --- a/lib/modules/platform/azure/index.ts +++ b/lib/modules/platform/azure/index.ts @@ -513,18 +513,7 @@ export async function createPr({ ); } if (platformPrOptions?.autoApprove) { - await azureApiGit.createPullRequestReviewer( - { - reviewerUrl: pr.createdBy!.url, - vote: AzurePrVote.Approved, - isFlagged: false, - isRequired: false, - }, - config.repoId, - // TODO #22198 - pr.pullRequestId!, - pr.createdBy!.id!, - ); + await approvePr(pr); } await Promise.all( labels!.map((label) => @@ -581,19 +570,7 @@ export async function updatePr({ objToUpdate.status = PullRequestStatus.Abandoned; } if (platformPrOptions?.autoApprove) { - const pr = await azureApiGit.getPullRequestById(prNo, config.project); - await azureApiGit.createPullRequestReviewer( - { - reviewerUrl: pr.createdBy!.url, - vote: AzurePrVote.Approved, - isFlagged: false, - isRequired: false, - }, - config.repoId, - // TODO #22198 - pr.pullRequestId!, - pr.createdBy!.id!, - ); + await approvePr(prNo); } const updatedPr = await azureApiGit.updatePullRequest( @@ -1015,3 +992,31 @@ export async function deleteLabel( const azureApiGit = await azureApi.gitApi(); await azureApiGit.deletePullRequestLabels(config.repoId, prNumber, label); } + +export async function approvePr( + prNumberOrPr: number | GitPullRequest, +): Promise { + const azureApiGit = await azureApi.gitApi(); + const pr = + typeof prNumberOrPr === 'number' + ? await azureApiGit.getPullRequestById(prNumberOrPr, config.project) + : prNumberOrPr; + if ( + pr.reviewers?.some((reviewer) => reviewer.vote === AzurePrVote.Approved) + ) { + logger.debug('PR is already approved'); + return; + } + await azureApiGit.createPullRequestReviewer( + { + reviewerUrl: pr.createdBy!.url, + vote: AzurePrVote.Approved, + isFlagged: false, + isRequired: false, + }, + config.repoId, + // TODO #22198 + pr.pullRequestId!, + pr.createdBy!.id!, + ); +} diff --git a/lib/modules/platform/gerrit/index.ts b/lib/modules/platform/gerrit/index.ts index 0d3989e148757b8..c0274dcdeadd015 100644 --- a/lib/modules/platform/gerrit/index.ts +++ b/lib/modules/platform/gerrit/index.ts @@ -196,7 +196,7 @@ export async function createPr(prConfig: CreatePRConfig): Promise { TAG_PULL_REQUEST_BODY, ); if (prConfig.platformPrOptions?.autoApprove) { - await client.approveChange(pr._number); + await approvePr(pr._number); } return getPr(pr._number); } diff --git a/lib/modules/platform/gitlab/http.ts b/lib/modules/platform/gitlab/http.ts index 51f6fc401f56a59..623d3bb0c73b3df 100644 --- a/lib/modules/platform/gitlab/http.ts +++ b/lib/modules/platform/gitlab/http.ts @@ -19,6 +19,11 @@ export async function getUserID(username: string): Promise { return userInfo[0].id; } +export async function getSelfUserID(): Promise { + const userInfo = (await gitlabApi.getJson<{ id: number }>(`user`)).body; + return userInfo.id; +} + async function getMembers(group: string): Promise { const groupEncoded = encodeURIComponent(group); return ( diff --git a/lib/modules/platform/gitlab/index.ts b/lib/modules/platform/gitlab/index.ts index 30965b963085058..bee85be01dbf694 100644 --- a/lib/modules/platform/gitlab/index.ts +++ b/lib/modules/platform/gitlab/index.ts @@ -57,6 +57,7 @@ import { smartTruncate } from '../utils/pr-body'; import { getMemberUserIDs, getMemberUsernames, + getSelfUserID, getUserID, gitlabApi, isUserBusy, @@ -65,6 +66,7 @@ import { getMR, updateMR } from './merge-request'; import { LastPipelineId } from './schema'; import type { GitLabMergeRequest, + GitLabMergeRequestApprovals, GitlabComment, GitlabIssue, GitlabPr, @@ -711,6 +713,23 @@ async function tryPrAutomerge( } async function approvePr(pr: number): Promise { + try { + const { body: approvals } = + await gitlabApi.getJson( + `projects/${config.repository}/merge_requests/${pr}/approvals`, + ); + const selfUserId = await getSelfUserID(); + if ( + approvals.approved_by?.some( + (approval) => approval.user?.id === selfUserId, + ) + ) { + logger.debug('MR already approved'); + return; + } + } catch (err) { + logger.warn({ err }, 'GitLab: Error checking if merge request is approved'); + } try { await gitlabApi.postJson( `projects/${config.repository}/merge_requests/${pr}/approve`, diff --git a/lib/modules/platform/gitlab/types.ts b/lib/modules/platform/gitlab/types.ts index 244ec8366361e6b..c37243b8a44bec5 100644 --- a/lib/modules/platform/gitlab/types.ts +++ b/lib/modules/platform/gitlab/types.ts @@ -77,3 +77,7 @@ export interface GitlabUserStatus { emoji?: string; availability: 'not_set' | 'busy'; } + +export interface GitLabMergeRequestApprovals { + approved_by?: { user?: GitLabUser }[]; +}