diff --git a/lib/config/presets/github/__snapshots__/index.spec.ts.snap b/lib/config/presets/github/__snapshots__/index.spec.ts.snap index 1bb03714ea7dc0..bf489876d85f26 100644 --- a/lib/config/presets/github/__snapshots__/index.spec.ts.snap +++ b/lib/config/presets/github/__snapshots__/index.spec.ts.snap @@ -86,7 +86,7 @@ Array [ ] `; -exports[`config/presets/github/index getPreset() should return undefined 1`] = ` +exports[`config/presets/github/index getPreset() should throws not-found 1`] = ` Array [ Object { "headers": Object { diff --git a/lib/config/presets/github/index.spec.ts b/lib/config/presets/github/index.spec.ts index bf812a2bab7457..23186b8dd65d74 100644 --- a/lib/config/presets/github/index.spec.ts +++ b/lib/config/presets/github/index.spec.ts @@ -1,13 +1,14 @@ import * as httpMock from '../../../../test/httpMock'; import { getName, mocked } from '../../../../test/util'; import * as _hostRules from '../../../util/host-rules'; +import { PRESET_NOT_FOUND } from '../util'; import * as github from '.'; jest.mock('../../../util/host-rules'); const hostRules = mocked(_hostRules); -const githubApiHost = 'https://api.github.com/'; +const githubApiHost = github.Endpoint; const basePath = '/repos/some/repo/contents'; describe(getName(__filename), () => { @@ -30,7 +31,7 @@ describe(getName(__filename), () => { const res = await github.fetchJSONFile( 'some/repo', 'some-filename.json', - 'https://api.github.com/' + githubApiHost ); expect(res).toMatchSnapshot(); expect(httpMock.getTrace()).toMatchSnapshot(); @@ -145,7 +146,7 @@ describe(getName(__filename), () => { expect(httpMock.getTrace()).toMatchSnapshot(); }); - it('should return undefined', async () => { + it('should throws not-found', async () => { httpMock .scope(githubApiHost) .get(`${basePath}/somefile.json`) @@ -155,11 +156,12 @@ describe(getName(__filename), () => { try { global.appMode = true; - const content = await github.getPreset({ - packageName: 'some/repo', - presetName: 'somefile/somename/somesubname', - }); - expect(content).toBeUndefined(); + await expect( + github.getPreset({ + packageName: 'some/repo', + presetName: 'somefile/somename/somesubname', + }) + ).rejects.toThrow(PRESET_NOT_FOUND); } finally { delete global.appMode; } diff --git a/lib/config/presets/github/index.ts b/lib/config/presets/github/index.ts index 2e40d93f9965df..7363c3810dce02 100644 --- a/lib/config/presets/github/index.ts +++ b/lib/config/presets/github/index.ts @@ -2,8 +2,10 @@ import { PLATFORM_FAILURE } from '../../../constants/error-messages'; import { PLATFORM_TYPE_GITHUB } from '../../../constants/platforms'; import { logger } from '../../../logger'; import { Http, HttpOptions } from '../../../util/http'; -import { ensureTrailingSlash } from '../../../util/url'; import { Preset, PresetConfig } from '../common'; +import { PRESET_DEP_NOT_FOUND, fetchPreset } from '../util'; + +export const Endpoint = 'https://api.github.com/'; const http = new Http(PLATFORM_TYPE_GITHUB); @@ -32,7 +34,7 @@ export async function fetchJSONFile( { statusCode: err.statusCode }, `Failed to retrieve ${fileName} from repo` ); - throw new Error('dep not found'); + throw new Error(PRESET_DEP_NOT_FOUND); } try { const content = Buffer.from(res.body.content, 'base64').toString(); @@ -46,39 +48,19 @@ export async function fetchJSONFile( export async function getPresetFromEndpoint( pkgName: string, filePreset: string, - endpoint = 'https://api.github.com/' + endpoint = Endpoint ): Promise { - // eslint-disable-next-line no-param-reassign - endpoint = ensureTrailingSlash(endpoint); - const [fileName, presetName, subPresetName] = filePreset.split('/'); - let jsonContent: any; - if (fileName === 'default') { - try { - jsonContent = await fetchJSONFile(pkgName, 'default.json', endpoint); - } catch (err) { - if (err.message !== 'dep not found') { - throw err; - } - logger.debug('default.json preset not found - trying renovate.json'); - jsonContent = await fetchJSONFile(pkgName, 'renovate.json', endpoint); - } - } else { - jsonContent = await fetchJSONFile(pkgName, `${fileName}.json`, endpoint); - } - if (presetName) { - if (subPresetName) { - return jsonContent[presetName] - ? jsonContent[presetName][subPresetName] - : undefined; - } - return jsonContent[presetName]; - } - return jsonContent; + return fetchPreset({ + pkgName, + filePreset, + 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/config/presets/util.spec.ts b/lib/config/presets/util.spec.ts new file mode 100644 index 00000000000000..64ecca6364432a --- /dev/null +++ b/lib/config/presets/util.spec.ts @@ -0,0 +1,67 @@ +import { getName } from '../../../test/util'; +import { Preset } from './common'; +import { + FetchPresetConfig, + PRESET_DEP_NOT_FOUND, + PRESET_NOT_FOUND, + fetchPreset, +} from './util'; + +const config: FetchPresetConfig = { + pkgName: 'some/repo', + filePreset: 'default', + endpoint: 'endpoint', + fetch: undefined, +}; + +const fetch = jest.fn(() => Promise.resolve({})); + +describe(getName(__filename), () => { + beforeEach(() => { + fetch.mockReset(); + }); + it('works', async () => { + fetch.mockResolvedValue({ sub: { preset: { foo: true } } }); + expect(await fetchPreset({ ...config, fetch })).toEqual({ + sub: { preset: { foo: true } }, + }); + + expect( + await fetchPreset({ ...config, filePreset: 'some/sub', fetch }) + ).toEqual({ preset: { foo: true } }); + + expect( + await fetchPreset({ ...config, filePreset: 'some/sub/preset', fetch }) + ).toEqual({ foo: true }); + }); + + it('fails', async () => { + fetch.mockRejectedValueOnce(new Error('fails')); + await expect(fetchPreset({ ...config, fetch })).rejects.toThrow('fails'); + }); + + it(PRESET_DEP_NOT_FOUND, async () => { + fetch.mockResolvedValueOnce(null); + await expect(fetchPreset({ ...config, fetch })).rejects.toThrow( + PRESET_DEP_NOT_FOUND + ); + + fetch.mockRejectedValueOnce(new Error(PRESET_DEP_NOT_FOUND)); + fetch.mockRejectedValueOnce(new Error(PRESET_DEP_NOT_FOUND)); + await expect(fetchPreset({ ...config, fetch })).rejects.toThrow( + PRESET_DEP_NOT_FOUND + ); + }); + + it(PRESET_NOT_FOUND, async () => { + fetch.mockResolvedValueOnce({}); + await expect( + fetchPreset({ ...config, filePreset: 'some/sub/preset', fetch }) + ).rejects.toThrow(PRESET_NOT_FOUND); + + fetch.mockResolvedValueOnce({ sub: {} }); + await expect( + fetchPreset({ ...config, filePreset: 'some/sub/preset', fetch }) + ).rejects.toThrow(PRESET_NOT_FOUND); + }); +}); diff --git a/lib/config/presets/util.ts b/lib/config/presets/util.ts new file mode 100644 index 00000000000000..8c3b648c7616b1 --- /dev/null +++ b/lib/config/presets/util.ts @@ -0,0 +1,63 @@ +import { logger } from '../../logger'; +import { ensureTrailingSlash } from '../../util/url'; +import { Preset } from './common'; + +export const PRESET_DEP_NOT_FOUND = 'dep not found'; +export const PRESET_NOT_FOUND = 'preset not found'; + +export type PresetFetcher = ( + repo: string, + fileName: string, + endpoint: string +) => Promise; + +export type FetchPresetConfig = { + pkgName: string; + filePreset: string; + endpoint: string; + fetch: PresetFetcher; +}; + +export async function fetchPreset({ + pkgName, + filePreset, + endpoint, + fetch, +}: FetchPresetConfig): Promise { + // eslint-disable-next-line no-param-reassign + endpoint = ensureTrailingSlash(endpoint); + const [fileName, presetName, subPresetName] = filePreset.split('/'); + let jsonContent: any | undefined; + if (fileName === 'default') { + try { + jsonContent = await fetch(pkgName, 'default.json', endpoint); + } catch (err) { + if (err.message !== PRESET_DEP_NOT_FOUND) { + throw err; + } + logger.debug('default.json preset not found - trying renovate.json'); + jsonContent = await fetch(pkgName, 'renovate.json', endpoint); + } + } else { + jsonContent = await fetch(pkgName, `${fileName}.json`, endpoint); + } + + if (!jsonContent) { + throw new Error(PRESET_DEP_NOT_FOUND); + } + if (presetName) { + const preset = jsonContent[presetName]; + if (!preset) { + throw new Error(PRESET_NOT_FOUND); + } + if (subPresetName) { + const subPreset = preset[subPresetName]; + if (!subPreset) { + throw new Error(PRESET_NOT_FOUND); + } + return subPreset; + } + return preset; + } + return jsonContent; +}