diff --git a/lib/config/presets/gitlab/__snapshots__/index.spec.ts.snap b/lib/config/presets/gitlab/__snapshots__/index.spec.ts.snap index 648e242a2dde22..a04e3707f89e47 100644 --- a/lib/config/presets/gitlab/__snapshots__/index.spec.ts.snap +++ b/lib/config/presets/gitlab/__snapshots__/index.spec.ts.snap @@ -20,12 +20,12 @@ Array [ "user-agent": "https://github.com/renovatebot/renovate", }, "method": "GET", - "url": "https://gitlab.com/api/v4/projects/some%2Frepo/repository/files/renovate.json?ref=master", + "url": "https://gitlab.com/api/v4/projects/some%2Frepo/repository/files/default.json/raw?ref=master", }, ] `; -exports[`config/presets/gitlab/index getPreset() throws if fails to parse 1`] = ` +exports[`config/presets/gitlab/index getPreset() throws if missing 1`] = ` Array [ Object { "headers": Object { @@ -45,12 +45,32 @@ Array [ "user-agent": "https://github.com/renovatebot/renovate", }, "method": "GET", - "url": "https://gitlab.com/api/v4/projects/some%2Frepo/repository/files/renovate.json?ref=master", + "url": "https://gitlab.com/api/v4/projects/some%2Frepo/repository/files/default.json/raw?ref=master", + }, + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "host": "gitlab.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://gitlab.com/api/v4/projects/some%2Frepo/repository/branches", + }, + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "host": "gitlab.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://gitlab.com/api/v4/projects/some%2Frepo/repository/files/renovate.json/raw?ref=master", }, ] `; -exports[`config/presets/gitlab/index getPreset() throws if no content 1`] = ` +exports[`config/presets/gitlab/index getPreset() throws platform-failure 1`] = ` Array [ Object { "headers": Object { @@ -65,8 +85,6 @@ Array [ ] `; -exports[`config/presets/gitlab/index getPreset() throws if not default 1`] = `Array []`; - exports[`config/presets/gitlab/index getPresetFromEndpoint() uses custom endpoint 1`] = ` Array [ Object { @@ -87,7 +105,7 @@ Array [ "user-agent": "https://github.com/renovatebot/renovate", }, "method": "GET", - "url": "https://gitlab.example.org/api/v4/projects/some%2Frepo/repository/files/renovate.json?ref=devel", + "url": "https://gitlab.example.org/api/v4/projects/some%2Frepo/repository/files/some.json/raw?ref=devel", }, ] `; @@ -112,7 +130,7 @@ Array [ "user-agent": "https://github.com/renovatebot/renovate", }, "method": "GET", - "url": "https://gitlab.com/api/v4/projects/some%2Frepo/repository/files/renovate.json?ref=devel", + "url": "https://gitlab.com/api/v4/projects/some%2Frepo/repository/files/some.json/raw?ref=devel", }, ] `; diff --git a/lib/config/presets/gitlab/index.spec.ts b/lib/config/presets/gitlab/index.spec.ts index d7959a905549cc..e180961dd3fb92 100644 --- a/lib/config/presets/gitlab/index.spec.ts +++ b/lib/config/presets/gitlab/index.spec.ts @@ -1,5 +1,7 @@ import * as httpMock from '../../../../test/httpMock'; import { getName } from '../../../../test/util'; +import { PLATFORM_FAILURE } from '../../../constants/error-messages'; +import { PRESET_DEP_NOT_FOUND } from '../util'; import * as gitlab from '.'; const gitlabApiHost = 'https://gitlab.com'; @@ -16,38 +18,30 @@ describe(getName(__filename), () => { }); describe('getPreset()', () => { - it('throws if no content', async () => { - httpMock.scope(gitlabApiHost).get(`${basePath}/branches`).reply(500, {}); - await expect( - gitlab.getPreset({ - packageName: 'some/repo', - presetName: 'default', - }) - ).rejects.toThrow(); - expect(httpMock.getTrace()).toMatchSnapshot(); - }); - - it('throws if not default', async () => { + it('throws platform-failure', async () => { + httpMock.scope(gitlabApiHost).get(`${basePath}/branches`).reply(500); await expect( gitlab.getPreset({ packageName: 'some/repo', presetName: 'non-default', }) - ).rejects.toThrow(); + ).rejects.toThrow(PLATFORM_FAILURE); expect(httpMock.getTrace()).toMatchSnapshot(); }); - it('throws if fails to parse', async () => { + it('throws if missing', async () => { httpMock .scope(gitlabApiHost) .get(`${basePath}/branches`) + .twice() .reply(200, []) - .get(`${basePath}/files/renovate.json?ref=master`) - .reply(200, { content: Buffer.from('not json').toString('base64') }); - + .get(`${basePath}/files/default.json/raw?ref=master`) + .reply(404, null) + .get(`${basePath}/files/renovate.json/raw?ref=master`) + .reply(404, null); await expect( gitlab.getPreset({ packageName: 'some/repo' }) - ).rejects.toThrow(); + ).rejects.toThrow(PRESET_DEP_NOT_FOUND); expect(httpMock.getTrace()).toMatchSnapshot(); }); @@ -64,14 +58,8 @@ describe(getName(__filename), () => { default: true, }, ]) - .get(`${basePath}/files/renovate.json?ref=master`) - .reply( - 200, - { - content: Buffer.from('{"foo":"bar"}').toString('base64'), - }, - {} - ); + .get(`${basePath}/files/default.json/raw?ref=master`) + .reply(200, { foo: 'bar' }, {}); const content = await gitlab.getPreset({ packageName: 'some/repo' }); expect(content).toEqual({ foo: 'bar' }); @@ -90,10 +78,10 @@ describe(getName(__filename), () => { default: true, }, ]) - .get(`${basePath}/files/renovate.json?ref=devel`) - .reply(200, { content: Buffer.from('{}').toString('base64') }); + .get(`${basePath}/files/some.json/raw?ref=devel`) + .reply(200, { preset: { file: {} } }); expect( - await gitlab.getPresetFromEndpoint('some/repo', 'default') + await gitlab.getPresetFromEndpoint('some/repo', 'some/preset/file') ).toEqual({}); expect(httpMock.getTrace()).toMatchSnapshot(); }); @@ -108,15 +96,15 @@ describe(getName(__filename), () => { default: true, }, ]) - .get(`${basePath}/files/renovate.json?ref=devel`) + .get(`${basePath}/files/some.json/raw?ref=devel`) .reply(404); await expect( gitlab.getPresetFromEndpoint( 'some/repo', - 'default', + 'some/preset/file', 'https://gitlab.example.org/api/v4' ) - ).rejects.toThrow(); + ).rejects.toThrow(PRESET_DEP_NOT_FOUND); expect(httpMock.getTrace()).toMatchSnapshot(); }); }); diff --git a/lib/config/presets/gitlab/index.ts b/lib/config/presets/gitlab/index.ts index a3a742978fde08..7bec62cc2fff73 100644 --- a/lib/config/presets/gitlab/index.ts +++ b/lib/config/presets/gitlab/index.ts @@ -1,21 +1,20 @@ +import { PLATFORM_FAILURE } from '../../../constants/error-messages'; import { logger } from '../../../logger'; +import type { GitLabBranch } from '../../../types/platform/gitlab'; import { GitlabHttp } from '../../../util/http/gitlab'; -import { ensureTrailingSlash } from '../../../util/url'; import { Preset, PresetConfig } from '../common'; +import { PRESET_DEP_NOT_FOUND, fetchPreset } from '../util'; const gitlabApi = new GitlabHttp(); +export const Endpoint = 'https://gitlab.com/api/v4/'; async function getDefaultBranchName( urlEncodedPkgName: string, endpoint: string ): Promise { const branchesUrl = `${endpoint}projects/${urlEncodedPkgName}/repository/branches`; - type GlBranch = { - default: boolean; - name: string; - }[]; - const res = await gitlabApi.getJson(branchesUrl); + const res = await gitlabApi.getJson(branchesUrl); const branches = res.body; let defautlBranchName = 'master'; for (const branch of branches) { @@ -28,48 +27,48 @@ async function getDefaultBranchName( return defautlBranchName; } -export async function getPresetFromEndpoint( - pkgName: string, - presetName: string, - endpoint = 'https://gitlab.com/api/v4/' +export async function fetchJSONFile( + repo: string, + fileName: string, + endpoint: string ): Promise { - // eslint-disable-next-line no-param-reassign - endpoint = ensureTrailingSlash(endpoint); - if (presetName !== 'default') { - // TODO: proper error contructor - throw new Error( - // { pkgName, presetName }, - 'Sub-preset names are not supported with Gitlab datasource' - ); - } - let res: string; try { - const urlEncodedPkgName = encodeURIComponent(pkgName); + const urlEncodedRepo = encodeURIComponent(repo); + const urlEncodedPkgName = encodeURIComponent(fileName); const defautlBranchName = await getDefaultBranchName( - urlEncodedPkgName, + urlEncodedRepo, endpoint ); - - const presetUrl = `${endpoint}projects/${urlEncodedPkgName}/repository/files/renovate.json?ref=${defautlBranchName}`; - res = Buffer.from( - (await gitlabApi.getJson<{ content: string }>(presetUrl)).body.content, - 'base64' - ).toString(); + const url = `${endpoint}projects/${urlEncodedRepo}/repository/files/${urlEncodedPkgName}/raw?ref=${defautlBranchName}`; + return (await gitlabApi.getJson(url)).body; } catch (err) { - logger.debug({ err }, 'Failed to retrieve renovate.json from repo'); - throw new Error('dep not found'); - } - try { - return JSON.parse(res); - } catch (err) /* istanbul ignore next */ { - logger.debug('Failed to parse renovate.json'); - throw new Error('invalid preset JSON'); + if (err.message === PLATFORM_FAILURE) { + throw err; + } + logger.debug( + { statusCode: err.statusCode }, + `Failed to retrieve ${fileName} from repo` + ); + throw new Error(PRESET_DEP_NOT_FOUND); } } +export async function getPresetFromEndpoint( + pkgName: string, + presetName: string, + endpoint = Endpoint +): Promise { + return fetchPreset({ + pkgName, + filePreset: presetName, + endpoint, + fetch: fetchJSONFile, + }); +} + export function getPreset({ packageName: pkgName, presetName = 'default', }: PresetConfig): Promise { - return getPresetFromEndpoint(pkgName, presetName); + return getPresetFromEndpoint(pkgName, presetName, Endpoint); } diff --git a/lib/types/platform/gitlab/index.ts b/lib/types/platform/gitlab/index.ts new file mode 100644 index 00000000000000..8a602d0f73aa78 --- /dev/null +++ b/lib/types/platform/gitlab/index.ts @@ -0,0 +1,4 @@ +export type GitLabBranch = { + default: boolean; + name: string; +};