Skip to content

Commit

Permalink
fix(reconfigure/pr): find reconfigure pr separately (#25954)
Browse files Browse the repository at this point in the history
Co-authored-by: Rhys Arkins <rhys@arkins.net>
  • Loading branch information
RahulGautamSingh and rarkins committed Dec 29, 2023
1 parent 831fba0 commit 5f16355
Show file tree
Hide file tree
Showing 12 changed files with 280 additions and 7 deletions.
44 changes: 44 additions & 0 deletions lib/modules/platform/bitbucket-server/index.spec.ts
Expand Up @@ -1306,6 +1306,50 @@ describe('modules/platform/bitbucket-server/index', () => {
}),
).toBeNull();
});

it('finds pr from other authors', async () => {
const scope = await initRepo();
scope
.get(
`${urlPath}/rest/api/1.0/projects/SOME/repos/repo/pull-requests?state=OPEN&direction=outgoing&at=refs/heads/branch&limit=1`,
)
.reply(200, {
isLastPage: true,
values: [prMock(url, 'SOME', 'repo')],
});
expect(
await bitbucket.findPr({
branchName: 'branch',
state: 'open',
includeOtherAuthors: true,
}),
).toMatchObject({
number: 5,
sourceBranch: 'userName1/pullRequest5',
targetBranch: 'master',
title: 'title',
state: 'open',
});
});

it('returns null if no pr found - (includeOtherAuthors)', async () => {
const scope = await initRepo();
scope
.get(
`${urlPath}/rest/api/1.0/projects/SOME/repos/repo/pull-requests?state=OPEN&direction=outgoing&at=refs/heads/branch&limit=1`,
)
.reply(200, {
isLastPage: true,
values: [],
});

const pr = await bitbucket.findPr({
branchName: 'branch',
state: 'open',
includeOtherAuthors: true,
});
expect(pr).toBeNull();
});
});

describe('createPr()', () => {
Expand Down
26 changes: 26 additions & 0 deletions lib/modules/platform/bitbucket-server/index.ts
Expand Up @@ -324,8 +324,34 @@ export async function findPr({
prTitle,
state = 'all',
refreshCache,
includeOtherAuthors,
}: FindPRConfig): Promise<Pr | null> {
logger.debug(`findPr(${branchName}, "${prTitle!}", "${state}")`);

if (includeOtherAuthors) {
// PR might have been created by anyone, so don't use the cached Renovate PR list
const searchParams: Record<string, string> = {
state: 'OPEN',
};
searchParams['direction'] = 'outgoing';
searchParams['at'] = `refs/heads/${branchName}`;

const query = getQueryString(searchParams);
const prs = await utils.accumulateValues(
`./rest/api/1.0/projects/${config.projectKey}/repos/${config.repositorySlug}/pull-requests?${query}`,
'get',
{},
1, // only fetch the latest pr
);

if (!prs.length) {
logger.debug(`No PR found for branch ${branchName}`);
return null;
}

return utils.prInfo(prs[0]);
}

const prList = await getPrList(refreshCache);
const pr = prList.find(isRelevantPr(branchName, prTitle, state));
if (pr) {
Expand Down
40 changes: 40 additions & 0 deletions lib/modules/platform/bitbucket/index.spec.ts
Expand Up @@ -954,6 +954,46 @@ describe('modules/platform/bitbucket/index', () => {
});
expect(pr?.number).toBe(5);
});

it('finds pr from other authors', async () => {
const scope = await initRepoMock();
scope
.get(
'/2.0/repositories/some/repo/pullrequests?q=source.branch.name="branch"&state=open',
)
.reply(200, { values: [pr] });
expect(
await bitbucket.findPr({
branchName: 'branch',
state: 'open',
includeOtherAuthors: true,
}),
).toMatchObject({
number: 5,
sourceBranch: 'branch',
targetBranch: 'master',
title: 'title',
state: 'open',
});
});

it('returns null if no open pr exists - (includeOtherAuthors)', async () => {
const scope = await initRepoMock();
scope
.get(
'/2.0/repositories/some/repo/pullrequests?q=source.branch.name="branch"&state=open',
)
.reply(200, {
values: [],
});

const pr = await bitbucket.findPr({
branchName: 'branch',
state: 'open',
includeOtherAuthors: true,
});
expect(pr).toBeNull();
});
});

describe('createPr()', () => {
Expand Down
18 changes: 18 additions & 0 deletions lib/modules/platform/bitbucket/index.ts
Expand Up @@ -301,8 +301,26 @@ export async function findPr({
branchName,
prTitle,
state = 'all',
includeOtherAuthors,
}: FindPRConfig): Promise<Pr | null> {
logger.debug(`findPr(${branchName}, ${prTitle}, ${state})`);

if (includeOtherAuthors) {
// PR might have been created by anyone, so don't use the cached Renovate PR list
const prs = (
await bitbucketHttp.getJson<PagedResult<PrResponse>>(
`/2.0/repositories/${config.repository}/pullrequests?q=source.branch.name="${branchName}"&state=open`,
)
).body.values;

if (prs.length === 0) {
logger.debug(`No PR found for branch ${branchName}`);
return null;
}

return utils.prInfo(prs[0]);
}

const prList = await getPrList();
const pr = prList.find(
(p) =>
Expand Down
10 changes: 9 additions & 1 deletion lib/modules/platform/gitea/index.ts
Expand Up @@ -13,6 +13,7 @@ import type { BranchStatus } from '../../../types';
import { parseJson } from '../../../util/common';
import * as git from '../../../util/git';
import { setBaseUrl } from '../../../util/http/gitea';
import { regEx } from '../../../util/regex';
import { sanitize } from '../../../util/sanitize';
import { ensureTrailingSlash } from '../../../util/url';
import { getPrBodyStruct, hashBody } from '../pr-body';
Expand Down Expand Up @@ -70,6 +71,7 @@ interface GiteaRepoConfig {
export const id = 'gitea';

const DRAFT_PREFIX = 'WIP: ';
const reconfigurePrRegex = regEx(/reconfigure$/g);

const defaults = {
hostType: 'gitea',
Expand Down Expand Up @@ -109,7 +111,12 @@ function toRenovatePR(data: PR): Pr | null {
}

const createdBy = data.user?.username;
if (createdBy && botUserName && createdBy !== botUserName) {
if (
createdBy &&
botUserName &&
!reconfigurePrRegex.test(data.head.label) &&
createdBy !== botUserName
) {
return null;
}

Expand Down Expand Up @@ -493,6 +500,7 @@ const platform: Platform = {
branchName,
prTitle: title,
state = 'all',
includeOtherAuthors,
}: FindPRConfig): Promise<Pr | null> {
logger.debug(`findPr(${branchName}, ${title!}, ${state})`);
const prList = await platform.getPrList();
Expand Down
45 changes: 45 additions & 0 deletions lib/modules/platform/github/index.spec.ts
Expand Up @@ -2428,6 +2428,51 @@ describe('modules/platform/github/index', () => {
res = await github.findPr({ branchName: 'branch-b' });
expect(res).toBeNull();
});

it('finds pr from other authors', async () => {
const scope = httpMock.scope(githubApiHost);
initRepoMock(scope, 'some/repo');
scope
.get('/repos/some/repo/pulls?head=some/repo:branch&state=open')
.reply(200, [
{
number: 1,
head: { ref: 'branch-a', repo: { full_name: 'some/repo' } },
title: 'branch a pr',
state: 'open',
},
]);
await github.initRepo({ repository: 'some/repo' });
expect(
await github.findPr({
branchName: 'branch',
state: 'open',
includeOtherAuthors: true,
}),
).toMatchObject({
number: 1,
sourceBranch: 'branch-a',
sourceRepo: 'some/repo',
state: 'open',
title: 'branch a pr',
updated_at: undefined,
});
});

it('returns null if no pr found - (includeOtherAuthors)', async () => {
const scope = httpMock.scope(githubApiHost);
initRepoMock(scope, 'some/repo');
scope
.get('/repos/some/repo/pulls?head=some/repo:branch&state=open')
.reply(200, []);
await github.initRepo({ repository: 'some/repo' });
const pr = await github.findPr({
branchName: 'branch',
state: 'open',
includeOtherAuthors: true,
});
expect(pr).toBeNull();
});
});

describe('createPr()', () => {
Expand Down
18 changes: 18 additions & 0 deletions lib/modules/platform/github/index.ts
Expand Up @@ -798,8 +798,26 @@ export async function findPr({
branchName,
prTitle,
state = 'all',
includeOtherAuthors,
}: FindPRConfig): Promise<GhPr | null> {
logger.debug(`findPr(${branchName}, ${prTitle}, ${state})`);

if (includeOtherAuthors) {
const repo = config.parentRepo ?? config.repository;
// PR might have been created by anyone, so don't use the cached Renovate PR list
const response = await githubApi.getJson<GhRestPr[]>(
`repos/${repo}/pulls?head=${repo}:${branchName}&state=open`,
);

const { body: prList } = response;
if (!prList.length) {
logger.debug(`No PR found for branch ${branchName}`);
return null;
}

return coerceRestPr(prList[0]);
}

const prList = await getPrList();
const pr = prList.find((p) => {
if (p.sourceBranch !== branchName) {
Expand Down
43 changes: 43 additions & 0 deletions lib/modules/platform/gitlab/index.spec.ts
Expand Up @@ -1678,6 +1678,49 @@ describe('modules/platform/gitlab/index', () => {
});
expect(res).toBeDefined();
});

it('finds pr from other authors', async () => {
httpMock
.scope(gitlabApiHost)
.get(
'/api/v4/projects/undefined/merge_requests?source_branch=branch&state=opened',
)
.reply(200, [
{
iid: 1,
source_branch: 'branch',
title: 'branch a pr',
state: 'opened',
},
]);
expect(
await gitlab.findPr({
branchName: 'branch',
state: 'open',
includeOtherAuthors: true,
}),
).toMatchObject({
number: 1,
sourceBranch: 'branch',
state: 'open',
title: 'branch a pr',
});
});

it('returns null if no pr found - (includeOtherAuthors)', async () => {
httpMock
.scope(gitlabApiHost)
.get(
'/api/v4/projects/undefined/merge_requests?source_branch=branch&state=opened',
)
.reply(200, []);
const pr = await gitlab.findPr({
branchName: 'branch',
state: 'open',
includeOtherAuthors: true,
});
expect(pr).toBeNull();
});
});

async function initPlatform(gitlabVersion: string) {
Expand Down
28 changes: 28 additions & 0 deletions lib/modules/platform/gitlab/index.ts
Expand Up @@ -863,8 +863,36 @@ export async function findPr({
branchName,
prTitle,
state = 'all',
includeOtherAuthors,
}: FindPRConfig): Promise<Pr | null> {
logger.debug(`findPr(${branchName}, ${prTitle!}, ${state})`);

if (includeOtherAuthors) {
// PR might have been created by anyone, so don't use the cached Renovate MR list
const response = await gitlabApi.getJson<GitLabMergeRequest[]>(
`projects/${config.repository}/merge_requests?source_branch=${branchName}&state=opened`,
);

const { body: mrList } = response;
if (!mrList.length) {
logger.debug(`No MR found for branch ${branchName}`);
return null;
}

// return the latest merge request
const mr = mrList[0];

// only pass necessary info
const pr: GitlabPr = {
sourceBranch: mr.source_branch,
number: mr.iid,
state: 'open',
title: mr.title,
};

return massagePr(pr);
}

const prList = await getPrList();
return (
prList.find(
Expand Down
1 change: 1 addition & 0 deletions lib/modules/platform/types.ts
Expand Up @@ -143,6 +143,7 @@ export interface FindPRConfig {
state?: 'open' | 'closed' | '!open' | 'all';
refreshCache?: boolean;
targetBranch?: string | null;
includeOtherAuthors?: boolean;
}
export interface MergePRConfig {
branchName?: string;
Expand Down

0 comments on commit 5f16355

Please sign in to comment.