mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-12 06:56:24 +00:00
fix(reconfigure/pr): find reconfigure pr separately (#25954)
Co-authored-by: Rhys Arkins <rhys@arkins.net>
This commit is contained in:
parent
831fba0262
commit
5f163552a9
12 changed files with 280 additions and 7 deletions
|
@ -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()', () => {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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()', () => {
|
||||
|
|
|
@ -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) =>
|
||||
|
|
|
@ -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';
|
||||
|
@ -70,6 +71,7 @@ interface GiteaRepoConfig {
|
|||
export const id = 'gitea';
|
||||
|
||||
const DRAFT_PREFIX = 'WIP: ';
|
||||
const reconfigurePrRegex = regEx(/reconfigure$/g);
|
||||
|
||||
const defaults = {
|
||||
hostType: 'gitea',
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
|
|
@ -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()', () => {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -143,6 +143,7 @@ export interface FindPRConfig {
|
|||
state?: 'open' | 'closed' | '!open' | 'all';
|
||||
refreshCache?: boolean;
|
||||
targetBranch?: string | null;
|
||||
includeOtherAuthors?: boolean;
|
||||
}
|
||||
export interface MergePRConfig {
|
||||
branchName?: string;
|
||||
|
|
|
@ -8,6 +8,7 @@ import {
|
|||
platform,
|
||||
scm,
|
||||
} from '../../../../test/util';
|
||||
import { GlobalConfig } from '../../../config/global';
|
||||
import { logger } from '../../../logger';
|
||||
import type { Pr } from '../../../modules/platform/types';
|
||||
import * as _cache from '../../../util/cache/repository';
|
||||
|
@ -39,8 +40,8 @@ describe('workers/repository/reconfigure/index', () => {
|
|||
cache.getCache.mockReturnValue({});
|
||||
git.getBranchCommit.mockReturnValue('sha' as LongCommitSha);
|
||||
fs.readLocalFile.mockResolvedValue(null);
|
||||
platform.getBranchPr.mockResolvedValue(null);
|
||||
platform.getBranchStatusCheck.mockResolvedValue(null);
|
||||
GlobalConfig.reset();
|
||||
});
|
||||
|
||||
it('no effect on repo with no reconfigure branch', async () => {
|
||||
|
@ -126,7 +127,7 @@ describe('workers/repository/reconfigure/index', () => {
|
|||
"enabledManagers": ["docker"]
|
||||
}
|
||||
`);
|
||||
platform.getBranchPr.mockResolvedValueOnce(mock<Pr>({ number: 1 }));
|
||||
platform.findPr.mockResolvedValueOnce(mock<Pr>({ number: 1 }));
|
||||
await validateReconfigureBranch(config);
|
||||
expect(logger.debug).toHaveBeenCalledWith(
|
||||
{ errors: expect.any(String) },
|
||||
|
@ -229,7 +230,6 @@ describe('workers/repository/reconfigure/index', () => {
|
|||
"enabledManagers": ["npm",]
|
||||
}
|
||||
`);
|
||||
platform.getBranchPr.mockResolvedValueOnce(mock<Pr>({ number: 1 }));
|
||||
await validateReconfigureBranch(config);
|
||||
expect(platform.setBranchStatus).toHaveBeenCalledWith({
|
||||
branchName: 'prefix/reconfigure',
|
||||
|
|
|
@ -161,10 +161,11 @@ export async function validateReconfigureBranch(
|
|||
);
|
||||
|
||||
// add comment to reconfigure PR if it exists
|
||||
const branchPr = await platform.getBranchPr(
|
||||
const branchPr = await platform.findPr({
|
||||
branchName,
|
||||
config.defaultBranch,
|
||||
);
|
||||
state: 'open',
|
||||
includeOtherAuthors: true,
|
||||
});
|
||||
if (branchPr) {
|
||||
let body = `There is an error with this repository's Renovate configuration that needs to be fixed.\n\n`;
|
||||
body += `Location: \`${configFileName}\`\n`;
|
||||
|
@ -179,6 +180,7 @@ export async function validateReconfigureBranch(
|
|||
content: body,
|
||||
});
|
||||
}
|
||||
|
||||
await setBranchStatus(branchName, 'Validation Failed', 'red', context);
|
||||
setReconfigureBranchCache(branchSha, false);
|
||||
await scm.checkoutBranch(config.baseBranch!);
|
||||
|
|
Loading…
Reference in a new issue