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(bitbucket): Implement PR cache for repositories #26345

Merged
merged 15 commits into from
Jan 4, 2024
Merged
71 changes: 42 additions & 29 deletions lib/modules/platform/bitbucket/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import * as httpMock from '../../../../test/http-mock';
import type { logger as _logger } from '../../../logger';
import { reset as memCacheReset } from '../../../util/cache/memory';
import type * as _git from '../../../util/git';
import { setBaseUrl } from '../../../util/http/bitbucket';
import type { Platform, PlatformResult, RepoParams } from '../types';
import { prFieldsFilter } from './utils';

jest.mock('../../../util/git');
jest.mock('../../../util/host-rules');
Expand Down Expand Up @@ -43,6 +43,7 @@ describe('modules/platform/bitbucket/index', () => {
});

setBaseUrl(baseUrl);
memCacheReset();
});

async function initRepoMock(
Expand Down Expand Up @@ -235,9 +236,8 @@ describe('modules/platform/bitbucket/index', () => {
it('bitbucket finds PR for branch', async () => {
const scope = await initRepoMock();
scope
.get(
`/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&fields=${prFieldsFilter}&pagelen=50`,
)
.get(`/2.0/repositories/some/repo/pullrequests`)
.query(true)
.reply(200, { values: [pr] })
.get('/2.0/repositories/some/repo/pullrequests/5')
.reply(200, pr);
Expand All @@ -248,9 +248,8 @@ describe('modules/platform/bitbucket/index', () => {
it('returns null if no PR for branch', async () => {
const scope = await initRepoMock();
scope
.get(
`/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&fields=${prFieldsFilter}&pagelen=50`,
)
.get(`/2.0/repositories/some/repo/pullrequests`)
.query(true)
.reply(200, { values: [pr] });

const res = await bitbucket.getBranchPr('branch_without_pr');
Expand Down Expand Up @@ -753,9 +752,8 @@ describe('modules/platform/bitbucket/index', () => {
await bitbucket.initPlatform({ username: 'renovate', password: 'pass' });
await initRepoMock(undefined, null, scope);
scope
.get(
`/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&q=author.uuid="12345"&fields=${prFieldsFilter}&pagelen=50`,
)
.get(`/2.0/repositories/some/repo/pullrequests`)
.query(true)
.reply(200, {
values: [
{
Expand All @@ -779,9 +777,8 @@ describe('modules/platform/bitbucket/index', () => {
it('finds pr', async () => {
const scope = await initRepoMock();
scope
.get(
`/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&fields=${prFieldsFilter}&pagelen=50`,
)
.get(`/2.0/repositories/some/repo/pullrequests`)
.query(true)
.reply(200, { values: [pr] });
expect(
await bitbucket.findPr({
Expand All @@ -805,9 +802,8 @@ describe('modules/platform/bitbucket/index', () => {

const scope = await initRepoMock();
scope
.get(
`/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&fields=${prFieldsFilter}&pagelen=50`,
)
.get(`/2.0/repositories/some/repo/pullrequests`)
.query(true)
.reply(200, {
values: [
{
Expand Down Expand Up @@ -843,9 +839,8 @@ describe('modules/platform/bitbucket/index', () => {

const scope = await initRepoMock({}, { is_private: true });
scope
.get(
`/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&fields=${prFieldsFilter}&pagelen=50`,
)
.get(`/2.0/repositories/some/repo/pullrequests`)
.query(true)
.reply(200, {
values: [
{
Expand Down Expand Up @@ -883,9 +878,8 @@ describe('modules/platform/bitbucket/index', () => {

const scope = await initRepoMock({}, { is_private: false });
scope
.get(
`/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&fields=${prFieldsFilter}&pagelen=50`,
)
.get(`/2.0/repositories/some/repo/pullrequests`)
.query(true)
.reply(200, {
values: [
{
Expand Down Expand Up @@ -927,9 +921,8 @@ describe('modules/platform/bitbucket/index', () => {

const scope = await initRepoMock({}, { is_private: false });
scope
.get(
`/2.0/repositories/some/repo/pullrequests?state=OPEN&state=MERGED&state=DECLINED&state=SUPERSEDED&fields=${prFieldsFilter}&pagelen=50`,
)
.get(`/2.0/repositories/some/repo/pullrequests`)
.query(true)
.reply(200, {
values: [
{
Expand Down Expand Up @@ -1025,7 +1018,12 @@ describe('modules/platform/bitbucket/index', () => {
values: [projectReviewer, repoReviewer],
})
.post('/2.0/repositories/some/repo/pullrequests')
.reply(200, { id: 5 });
.reply(200, { id: 5 })
.get(`/2.0/repositories/some/repo/pullrequests`)
.query(true)
.reply(200, {
values: [{ id: 5 }],
});
const pr = await bitbucket.createPr({
sourceBranch: 'branch',
targetBranch: 'master',
Expand Down Expand Up @@ -1103,7 +1101,12 @@ describe('modules/platform/bitbucket/index', () => {
account_status: 'inactive',
})
.post('/2.0/repositories/some/repo/pullrequests')
.reply(200, { id: 5 });
.reply(200, { id: 5 })
.get(`/2.0/repositories/some/repo/pullrequests`)
.query(true)
.reply(200, {
values: [{ id: 5 }],
});
const pr = await bitbucket.createPr({
sourceBranch: 'branch',
targetBranch: 'master',
Expand Down Expand Up @@ -1161,7 +1164,12 @@ describe('modules/platform/bitbucket/index', () => {
)
.reply(200)
.post('/2.0/repositories/some/repo/pullrequests')
.reply(200, { id: 5 });
.reply(200, { id: 5 })
.get(`/2.0/repositories/some/repo/pullrequests`)
.query(true)
.reply(200, {
values: [{ id: 5 }],
});
const pr = await bitbucket.createPr({
sourceBranch: 'branch',
targetBranch: 'master',
Expand Down Expand Up @@ -1257,7 +1265,12 @@ describe('modules/platform/bitbucket/index', () => {
},
})
.post('/2.0/repositories/some/repo/pullrequests')
.reply(200, { id: 5 });
.reply(200, { id: 5 })
.get(`/2.0/repositories/some/repo/pullrequests`)
.query(true)
.reply(200, {
values: [{ id: 5 }],
});
const pr = await bitbucket.createPr({
sourceBranch: 'branch',
targetBranch: 'master',
Expand Down
60 changes: 25 additions & 35 deletions lib/modules/platform/bitbucket/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { repoFingerprint } from '../util';
import { smartTruncate } from '../utils/pr-body';
import { readOnlyIssueBody } from '../utils/read-only-issue-body';
import * as comments from './comments';
import { BitbucketPrCache } from './pr-cache';
import type {
Account,
BitbucketStatus,
Expand All @@ -44,7 +45,7 @@ import type {
RepoInfoBody,
} from './types';
import * as utils from './utils';
import { mergeBodyTransformer, prFieldsFilter } from './utils';
import { mergeBodyTransformer } from './utils';

export const id = 'bitbucket';

Expand Down Expand Up @@ -273,28 +274,11 @@ function matchesState(state: string, desiredState: string): boolean {

export async function getPrList(): Promise<Pr[]> {
logger.debug('getPrList()');
if (!config.prList) {
logger.debug('Retrieving PR list');
const querySearchParams = new URL.URLSearchParams();
for (const state of utils.prStates.all) {
querySearchParams.append('state', state);
}
if (renovateUserUuid && !config.ignorePrAuthor) {
querySearchParams.append('q', `author.uuid="${renovateUserUuid}"`);
}
querySearchParams.append('fields', prFieldsFilter);
const query = querySearchParams.toString();
const url = `/2.0/repositories/${config.repository}/pullrequests?${query}`;
const prs = (
await bitbucketHttp.getJson<PagedResult<PrResponse>>(url, {
paginate: true,
pagelen: 50,
})
).body.values;
config.prList = prs.map(utils.prInfo);
logger.debug(`Retrieved Pull Requests, count: ${config.prList.length}`);
}
return config.prList;
return await BitbucketPrCache.getPrs(
bitbucketHttp,
config.repository,
renovateUserUuid,
);
}

export async function findPr({
Expand Down Expand Up @@ -328,15 +312,17 @@ export async function findPr({
(!prTitle || p.title.toUpperCase() === prTitle.toUpperCase()) &&
matchesState(p.state, state),
);
if (pr) {
logger.debug(`Found PR #${pr.number}`);

if (!pr) {
return null;
}
logger.debug(`Found PR #${pr.number}`);

/**
* Bitbucket doesn't support renaming or reopening declined PRs.
* Instead, we have to use comment-driven signals.
*/
if (pr?.state === 'closed') {
if (pr.state === 'closed') {
const reopenComments = await comments.reopenComments(config, pr.number);

if (is.nonEmptyArray(reopenComments)) {
Expand All @@ -359,7 +345,7 @@ export async function findPr({
}
}

return pr ?? null;
return pr;
}

// Gets details for a PR
Expand Down Expand Up @@ -913,10 +899,12 @@ export async function createPr({
)
).body;
const pr = utils.prInfo(prRes);
// istanbul ignore if
if (config.prList) {
config.prList.push(pr);
}
await BitbucketPrCache.addPr(
bitbucketHttp,
config.repository,
renovateUserUuid,
pr,
);
return pr;
} catch (err) /* istanbul ignore next */ {
// Try sanitizing reviewers
Expand All @@ -938,10 +926,12 @@ export async function createPr({
)
).body;
const pr = utils.prInfo(prRes);
// istanbul ignore if
if (config.prList) {
config.prList.push(pr);
}
await BitbucketPrCache.addPr(
bitbucketHttp,
config.repository,
renovateUserUuid,
pr,
);
return pr;
}
}
Expand Down
Loading