Skip to content
Snippets Groups Projects
Unverified Commit 0a68e19d authored by Sergei Zharinov's avatar Sergei Zharinov Committed by GitHub
Browse files

feat(presets): Support Bitbucket Cloud local presets (#9422)

parent 612be5e4
No related branches found
Tags 24.108.0
No related merge requests found
......@@ -202,7 +202,7 @@ To host your preset config on Gitea:
Renovate also supports local presets, e.g. presets that are hosted on the same platform as the target repository.
This is especially helpful in self-hosted scenarios where public presets cannot be used.
Local presets are only supported on GitHub, GitLab, Gitea and Bitbucket Server.
Local presets are only supported on GitHub, GitLab, Gitea, Bitbucket Cloud and Bitbucket Server.
Local presets are specified either by leaving out any prefix, e.g. `owner/name`, or explicitly by adding a `local>` prefix, e.g. `local>owner/name`.
Renovate will determine the current platform and look up the preset from there.
......
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`config/presets/bitbucket/index fetchJSONFile() returns JSON 1`] = `
Array [
Object {
"headers": Object {
"accept-encoding": "gzip, deflate",
"host": "api.bitbucket.org",
"user-agent": "https://github.com/renovatebot/renovate",
},
"method": "GET",
"url": "https://api.bitbucket.org/2.0/repositories/some/repo/src/HEAD/some-filename.json",
},
]
`;
exports[`config/presets/bitbucket/index fetchJSONFile() throws on error 1`] = `
Array [
Object {
"headers": Object {
"accept-encoding": "gzip, deflate",
"host": "api.bitbucket.org",
"user-agent": "https://github.com/renovatebot/renovate",
},
"method": "GET",
"url": "https://api.bitbucket.org/2.0/repositories/some/repo/src/HEAD/some-filename.json",
},
]
`;
exports[`config/presets/bitbucket/index fetchJSONFile() throws on invalid json 1`] = `
Array [
Object {
"headers": Object {
"accept-encoding": "gzip, deflate",
"host": "api.bitbucket.org",
"user-agent": "https://github.com/renovatebot/renovate",
},
"method": "GET",
"url": "https://api.bitbucket.org/2.0/repositories/some/repo/src/HEAD/some-filename.json",
},
]
`;
import * as httpMock from '../../../../test/http-mock';
import { getName } from '../../../../test/util';
import { setPlatformApi } from '../../../platform';
import { PRESET_DEP_NOT_FOUND, PRESET_INVALID_JSON } from '../util';
import * as bitbucket from '.';
jest.unmock('../../../platform');
const baseUrl = 'https://api.bitbucket.org';
const basePath = '/2.0/repositories/some/repo/src/HEAD';
describe(getName(__filename), () => {
beforeAll(() => {
setPlatformApi('bitbucket');
});
beforeEach(() => {
httpMock.setup();
});
afterEach(() => {
httpMock.reset();
});
describe('fetchJSONFile()', () => {
it('returns JSON', async () => {
const data = { foo: 'bar' };
httpMock
.scope(baseUrl)
.get(`${basePath}/some-filename.json`)
.reply(200, JSON.stringify(data));
const res = await bitbucket.fetchJSONFile(
'some/repo',
'some-filename.json'
);
expect(res).toEqual(data);
expect(httpMock.getTrace()).toMatchSnapshot();
});
it('throws on error', async () => {
httpMock.scope(baseUrl).get(`${basePath}/some-filename.json`).reply(404);
await expect(
bitbucket.fetchJSONFile('some/repo', 'some-filename.json')
).rejects.toThrow(PRESET_DEP_NOT_FOUND);
expect(httpMock.getTrace()).toMatchSnapshot();
});
it('throws on invalid json', async () => {
httpMock
.scope(baseUrl)
.get(`${basePath}/some-filename.json`)
.reply(200, '!@#');
await expect(
bitbucket.fetchJSONFile('some/repo', 'some-filename.json')
).rejects.toThrow(PRESET_INVALID_JSON);
expect(httpMock.getTrace()).toMatchSnapshot();
});
});
describe('getPresetFromEndpoint()', () => {
it('uses custom path', async () => {
const data = { foo: 'bar' };
httpMock
.scope(baseUrl)
.get(`${basePath}/foo/bar/some-filename.json`)
.reply(200, JSON.stringify(data));
const res = await bitbucket.getPresetFromEndpoint(
'some/repo',
'some-filename',
'foo/bar',
baseUrl
);
expect(res).toEqual(data);
});
});
});
export { fetchJSONFile, getPresetFromEndpoint } from '../local/common';
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`config/presets/local/index getPreset() forwards to bitbucket 1`] = `
Array [
Array [
"some/repo",
"default",
undefined,
undefined,
],
]
`;
exports[`config/presets/local/index getPreset() forwards to bitbucket 2`] = `
Object {
"resolved": "preset",
}
`;
exports[`config/presets/local/index getPreset() forwards to custom bitbucket-server 1`] = `
Array [
Array [
......
import { logger } from '../../../logger';
import { platform } from '../../../platform';
import { ExternalHostError } from '../../../types/errors/external-host-error';
import type { Preset } from '../types';
import {
PRESET_DEP_NOT_FOUND,
PRESET_INVALID_JSON,
fetchPreset,
} from '../util';
export async function fetchJSONFile(
repo: string,
fileName: string,
_endpoint: string = null
): Promise<Preset> {
let raw: string;
try {
raw = await platform.getRawFile(fileName, repo);
} catch (err) {
// istanbul ignore if: not testable with nock
if (err instanceof ExternalHostError) {
throw err;
}
logger.debug(
{ err, repo, fileName },
`Failed to retrieve ${fileName} from repo ${repo}`
);
throw new Error(PRESET_DEP_NOT_FOUND);
}
try {
return JSON.parse(raw);
} catch (err) {
throw new Error(PRESET_INVALID_JSON);
}
}
export function getPresetFromEndpoint(
pkgName: string,
filePreset: string,
presetPath: string,
endpoint: string
): Promise<Preset> {
return fetchPreset({
pkgName,
filePreset,
presetPath,
endpoint,
fetch: fetchJSONFile,
});
}
import { getName, mocked } from '../../../../test/util';
import * as _bitbucket from '../bitbucket';
import * as _bitbucketServer from '../bitbucket-server';
import * as _gitea from '../gitea';
import * as _github from '../github';
import * as _gitlab from '../gitlab';
import * as local from '.';
jest.mock('../bitbucket');
jest.mock('../bitbucket-server');
jest.mock('../gitea');
jest.mock('../github');
jest.mock('../gitlab');
const bitbucket = mocked(_bitbucket);
const bitbucketServer = mocked(_bitbucketServer);
const gitea = mocked(_gitea);
const github = mocked(_github);
......@@ -19,6 +22,7 @@ describe(getName(__filename), () => {
beforeEach(() => {
jest.resetAllMocks();
const preset = { resolved: 'preset' };
bitbucket.getPresetFromEndpoint.mockResolvedValueOnce(preset);
bitbucketServer.getPresetFromEndpoint.mockResolvedValueOnce(preset);
gitea.getPresetFromEndpoint.mockResolvedValueOnce(preset);
github.getPresetFromEndpoint.mockResolvedValueOnce(preset);
......@@ -48,6 +52,18 @@ describe(getName(__filename), () => {
}).rejects.toThrow();
});
it('forwards to bitbucket', async () => {
const content = await local.getPreset({
packageName: 'some/repo',
presetName: 'default',
baseConfig: {
platform: 'bitbucket',
},
});
expect(bitbucket.getPresetFromEndpoint.mock.calls).toMatchSnapshot();
expect(content).toMatchSnapshot();
});
it('forwards to custom bitbucket-server', async () => {
const content = await local.getPreset({
packageName: 'some/repo',
......
import {
PLATFORM_TYPE_BITBUCKET,
PLATFORM_TYPE_BITBUCKET_SERVER,
PLATFORM_TYPE_GITEA,
PLATFORM_TYPE_GITHUB,
PLATFORM_TYPE_GITLAB,
} from '../../../constants/platforms';
import * as bitbucket from '../bitbucket';
import * as bitbucketServer from '../bitbucket-server';
import * as gitea from '../gitea';
import * as github from '../github';
......@@ -11,6 +13,7 @@ import * as gitlab from '../gitlab';
import type { Preset, PresetConfig } from '../types';
const resolvers = {
[PLATFORM_TYPE_BITBUCKET]: bitbucket,
[PLATFORM_TYPE_BITBUCKET_SERVER]: bitbucketServer,
[PLATFORM_TYPE_GITEA]: gitea,
[PLATFORM_TYPE_GITHUB]: github,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment