Skip to content

Commit

Permalink
feat(presets): extract generic platform preset fetch (#6467)
Browse files Browse the repository at this point in the history
  • Loading branch information
viceice committed Jun 9, 2020
1 parent a77d73f commit 5a87c8b
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 39 deletions.
2 changes: 1 addition & 1 deletion lib/config/presets/github/__snapshots__/index.spec.ts.snap
Expand Up @@ -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 {
Expand Down
18 changes: 10 additions & 8 deletions 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), () => {
Expand All @@ -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();
Expand Down Expand Up @@ -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`)
Expand All @@ -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;
}
Expand Down
42 changes: 12 additions & 30 deletions lib/config/presets/github/index.ts
Expand Up @@ -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);

Expand Down Expand Up @@ -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();
Expand All @@ -46,39 +48,19 @@ export async function fetchJSONFile(
export async function getPresetFromEndpoint(
pkgName: string,
filePreset: string,
endpoint = 'https://api.github.com/'
endpoint = Endpoint
): Promise<Preset> {
// 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<Preset> {
return getPresetFromEndpoint(pkgName, presetName);
return getPresetFromEndpoint(pkgName, presetName, Endpoint);
}
67 changes: 67 additions & 0 deletions 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<Preset>({}));

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);
});
});
63 changes: 63 additions & 0 deletions 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<Preset>;

export type FetchPresetConfig = {
pkgName: string;
filePreset: string;
endpoint: string;
fetch: PresetFetcher;
};

export async function fetchPreset({
pkgName,
filePreset,
endpoint,
fetch,
}: FetchPresetConfig): Promise<Preset | undefined> {
// 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;
}

0 comments on commit 5a87c8b

Please sign in to comment.