Skip to content

Commit 25ae92d

Browse files
feat(platform/bitbucket-server): allow blobless clone (#27975)
1 parent bf91e94 commit 25ae92d

File tree

3 files changed

+79
-10
lines changed

3 files changed

+79
-10
lines changed

docs/usage/self-hosted-experimental.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,8 @@ The expected value for this environment variable is a JSON array of strings.
143143

144144
## `RENOVATE_X_PLATFORM_VERSION`
145145

146-
If set, Renovate will use this string as GitLab server version instead of checking via the GitLab API.
147-
This can be useful when you use the GitLab `CI_JOB_TOKEN` to authenticate Renovate.
146+
Specify this string for Renovate to skip API checks and provide GitLab/Bitbucket server version directly.
147+
Particularly useful with GitLab's `CI_JOB_TOKEN` to authenticate Renovate or to reduce API calls for Bitbucket.
148148

149149
Read [platform details](modules/platform/gitlab/index.md) to learn why we need the server version on GitLab.
150150

lib/modules/platform/bitbucket-server/index.spec.ts

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import is from '@sindresorhus/is';
22
import { mockDeep } from 'jest-mock-extended';
33
import * as httpMock from '../../../../test/http-mock';
4+
import { mocked } from '../../../../test/util';
45
import {
56
REPOSITORY_CHANGED,
67
REPOSITORY_EMPTY,
78
REPOSITORY_NOT_FOUND,
89
} from '../../../constants/error-messages';
10+
import type { logger as _logger } from '../../../logger';
911
import type * as _git from '../../../util/git';
1012
import type { LongCommitSha } from '../../../util/git/types';
1113
import type { Platform } from '../types';
@@ -185,6 +187,7 @@ describe('modules/platform/bitbucket-server/index', () => {
185187

186188
let hostRules: jest.Mocked<HostRules>;
187189
let git: jest.Mocked<typeof _git>;
190+
let logger: jest.Mocked<typeof _logger>;
188191
const username = 'abc';
189192
const password = '123';
190193

@@ -211,6 +214,7 @@ describe('modules/platform/bitbucket-server/index', () => {
211214
// reset module
212215
jest.resetModules();
213216
bitbucket = await import('.');
217+
logger = mocked(await import('../../../logger')).logger;
214218
hostRules = jest.requireMock('../../../util/host-rules');
215219
git = jest.requireMock('../../../util/git');
216220
git.branchExists.mockReturnValue(true);
@@ -226,6 +230,10 @@ describe('modules/platform/bitbucket-server/index', () => {
226230
username,
227231
password,
228232
});
233+
httpMock
234+
.scope(urlHost)
235+
.get(`${urlPath}/rest/api/1.0/application-properties`)
236+
.reply(200, { version: '8.0.0' });
229237
await bitbucket.initPlatform({
230238
endpoint,
231239
username,
@@ -234,19 +242,52 @@ describe('modules/platform/bitbucket-server/index', () => {
234242
});
235243

236244
describe('initPlatform()', () => {
237-
it('should throw if no endpoint', () => {
245+
it('should throw if no endpoint', async () => {
238246
expect.assertions(1);
239-
expect(() => bitbucket.initPlatform({})).toThrow();
247+
await expect(bitbucket.initPlatform({})).rejects.toThrow();
240248
});
241249

242-
it('should throw if no username/password', () => {
250+
it('should throw if no username/password', async () => {
243251
expect.assertions(1);
244-
expect(() =>
252+
await expect(
245253
bitbucket.initPlatform({ endpoint: 'endpoint' }),
246-
).toThrow();
254+
).rejects.toThrow();
255+
});
256+
257+
it('should throw if version could not be fetched', async () => {
258+
httpMock
259+
.scope('https://stash.renovatebot.com')
260+
.get('/rest/api/1.0/application-properties')
261+
.reply(403);
262+
263+
await bitbucket.initPlatform({
264+
endpoint: 'https://stash.renovatebot.com',
265+
username: 'abc',
266+
password: '123',
267+
});
268+
expect(logger.debug).toHaveBeenCalledWith(
269+
expect.any(Object),
270+
'Error authenticating with Bitbucket. Check that your token includes "api" permissions',
271+
);
272+
});
273+
274+
it('should skip api call to fetch version when platform version is set in environment', async () => {
275+
process.env.RENOVATE_X_PLATFORM_VERSION = '8.0.0';
276+
await expect(
277+
bitbucket.initPlatform({
278+
endpoint: 'https://stash.renovatebot.com',
279+
username: 'abc',
280+
password: '123',
281+
}),
282+
).toResolve();
283+
delete process.env.RENOVATE_X_PLATFORM_VERSION;
247284
});
248285

249286
it('should init', async () => {
287+
httpMock
288+
.scope('https://stash.renovatebot.com')
289+
.get('/rest/api/1.0/application-properties')
290+
.reply(200, { version: '8.0.0' });
250291
expect(
251292
await bitbucket.initPlatform({
252293
endpoint: 'https://stash.renovatebot.com',

lib/modules/platform/bitbucket-server/index.ts

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { setTimeout } from 'timers/promises';
2+
import semver from 'semver';
23
import type { PartialDeep } from 'type-fest';
34
import {
45
REPOSITORY_CHANGED,
@@ -68,8 +69,10 @@ const bitbucketServerHttp = new BitbucketServerHttp();
6869
const defaults: {
6970
endpoint?: string;
7071
hostType: string;
72+
version: string;
7173
} = {
7274
hostType: 'bitbucket-server',
75+
version: '0.0.0',
7376
};
7477

7578
/* istanbul ignore next */
@@ -79,7 +82,7 @@ function updatePrVersion(pr: number, version: number): number {
7982
return res;
8083
}
8184

82-
export function initPlatform({
85+
export async function initPlatform({
8386
endpoint,
8487
username,
8588
password,
@@ -98,7 +101,32 @@ export function initPlatform({
98101
const platformConfig: PlatformResult = {
99102
endpoint: defaults.endpoint,
100103
};
101-
return Promise.resolve(platformConfig);
104+
try {
105+
let bitbucketServerVersion: string;
106+
// istanbul ignore if: experimental feature
107+
if (process.env.RENOVATE_X_PLATFORM_VERSION) {
108+
bitbucketServerVersion = process.env.RENOVATE_X_PLATFORM_VERSION;
109+
} else {
110+
const { version } = (
111+
await bitbucketServerHttp.getJson<{ version: string }>(
112+
`./rest/api/1.0/application-properties`,
113+
)
114+
).body;
115+
bitbucketServerVersion = version;
116+
logger.debug('Bitbucket Server version is: ' + bitbucketServerVersion);
117+
}
118+
119+
if (semver.valid(bitbucketServerVersion)) {
120+
defaults.version = bitbucketServerVersion;
121+
}
122+
} catch (err) {
123+
logger.debug(
124+
{ err },
125+
'Error authenticating with Bitbucket. Check that your token includes "api" permissions',
126+
);
127+
}
128+
129+
return platformConfig;
102130
}
103131

104132
// Get all repositories that the user has access to
@@ -204,7 +232,7 @@ export async function initRepo({
204232
...config,
205233
url,
206234
cloneSubmodules,
207-
fullClone: true,
235+
fullClone: semver.lte(defaults.version, '8.0.0'),
208236
});
209237

210238
config.mergeMethod = 'merge';

0 commit comments

Comments
 (0)