Skip to content

Commit

Permalink
refactor: ExternalHostError (#6563)
Browse files Browse the repository at this point in the history
  • Loading branch information
rarkins committed Jun 22, 2020
1 parent cb84fa9 commit 52a074e
Show file tree
Hide file tree
Showing 51 changed files with 211 additions and 223 deletions.
4 changes: 2 additions & 2 deletions lib/config/presets/github/index.ts
@@ -1,6 +1,6 @@
import { PLATFORM_FAILURE } from '../../../constants/error-messages';
import { PLATFORM_TYPE_GITHUB } from '../../../constants/platforms';
import { logger } from '../../../logger';
import { ExternalHostError } from '../../../types/error';
import { Http, HttpOptions } from '../../../util/http';
import { Preset, PresetConfig } from '../common';
import { PRESET_DEP_NOT_FOUND, fetchPreset } from '../util';
Expand All @@ -27,7 +27,7 @@ export async function fetchJSONFile(
res = await http.getJson(url, opts);
} catch (err) {
// istanbul ignore if: not testable with nock
if (err.message === PLATFORM_FAILURE) {
if (err instanceof ExternalHostError) {
throw err;
}
logger.debug(
Expand Down
2 changes: 1 addition & 1 deletion lib/config/presets/gitlab/__snapshots__/index.spec.ts.snap
Expand Up @@ -70,7 +70,7 @@ Array [
]
`;

exports[`config/presets/gitlab/index getPreset() throws platform-failure 1`] = `
exports[`config/presets/gitlab/index getPreset() throws EXTERNAL_HOST_ERROR 1`] = `
Array [
Object {
"headers": Object {
Expand Down
6 changes: 3 additions & 3 deletions lib/config/presets/gitlab/index.spec.ts
@@ -1,6 +1,6 @@
import * as httpMock from '../../../../test/httpMock';
import { getName } from '../../../../test/util';
import { PLATFORM_FAILURE } from '../../../constants/error-messages';
import { EXTERNAL_HOST_ERROR } from '../../../constants/error-messages';
import { PRESET_DEP_NOT_FOUND } from '../util';
import * as gitlab from '.';

Expand All @@ -18,14 +18,14 @@ describe(getName(__filename), () => {
});

describe('getPreset()', () => {
it('throws platform-failure', async () => {
it('throws EXTERNAL_HOST_ERROR', async () => {
httpMock.scope(gitlabApiHost).get(`${basePath}/branches`).reply(500);
await expect(
gitlab.getPreset({
packageName: 'some/repo',
presetName: 'non-default',
})
).rejects.toThrow(PLATFORM_FAILURE);
).rejects.toThrow(EXTERNAL_HOST_ERROR);
expect(httpMock.getTrace()).toMatchSnapshot();
});

Expand Down
4 changes: 2 additions & 2 deletions lib/config/presets/gitlab/index.ts
@@ -1,5 +1,5 @@
import { PLATFORM_FAILURE } from '../../../constants/error-messages';
import { logger } from '../../../logger';
import { ExternalHostError } from '../../../types/error';
import type { GitLabBranch } from '../../../types/platform/gitlab';
import { GitlabHttp } from '../../../util/http/gitlab';
import { Preset, PresetConfig } from '../common';
Expand Down Expand Up @@ -42,7 +42,7 @@ export async function fetchJSONFile(
const url = `${endpoint}projects/${urlEncodedRepo}/repository/files/${urlEncodedPkgName}/raw?ref=${defautlBranchName}`;
return (await gitlabApi.getJson<Preset>(url)).body;
} catch (err) {
if (err.message === PLATFORM_FAILURE) {
if (err instanceof ExternalHostError) {
throw err;
}
logger.debug(
Expand Down
12 changes: 3 additions & 9 deletions lib/config/presets/index.ts
@@ -1,10 +1,7 @@
import is from '@sindresorhus/is';
import {
CONFIG_VALIDATION,
DATASOURCE_FAILURE,
PLATFORM_FAILURE,
} from '../../constants/error-messages';
import { CONFIG_VALIDATION } from '../../constants/error-messages';
import { logger } from '../../logger';
import { ExternalHostError } from '../../types/error';
import { regEx } from '../../util/regex';
import { RenovateConfig } from '../common';
import * as massage from '../massage';
Expand Down Expand Up @@ -207,10 +204,7 @@ export async function resolveConfigPresets(
} catch (err) {
logger.debug({ preset, err }, 'Preset fetch error');
// istanbul ignore if
if (
err.message === PLATFORM_FAILURE ||
err.message === DATASOURCE_FAILURE
) {
if (err instanceof ExternalHostError) {
throw err;
}
const error = new Error(CONFIG_VALIDATION);
Expand Down
5 changes: 2 additions & 3 deletions lib/constants/error-messages.ts
Expand Up @@ -5,7 +5,6 @@ export const SYSTEM_INSUFFICIENT_MEMORY = 'out-of-memory';
// Platform Error
export const PLATFORM_AUTHENTICATION_ERROR = 'authentication-error';
export const PLATFORM_BAD_CREDENTIALS = 'bad-credentials';
export const PLATFORM_FAILURE = 'platform-failure';
export const PLATFORM_GPG_FAILED = 'gpg-failed';
export const PLATFORM_INTEGRATION_UNAUTHORIZED = 'integration-unauthorized';
export const PLATFORM_NOT_FOUND = 'platform-not-found';
Expand Down Expand Up @@ -34,8 +33,8 @@ export const REPOSITORY_UNINITIATED = 'uninitiated';
export const MANAGER_LOCKFILE_ERROR = 'lockfile-error';
export const MANAGER_NO_PACKAGE_FILES = 'no-package-files';

// Datasource error
export const DATASOURCE_FAILURE = 'registry-failure';
// Host error
export const EXTERNAL_HOST_ERROR = 'external-host-error';

// Worker Error
export const WORKER_FILE_UPDATE_FAILED = 'update-failure';
Expand Down
14 changes: 7 additions & 7 deletions lib/datasource/cdnjs/index.spec.ts
@@ -1,7 +1,7 @@
import fs from 'fs';
import { getPkgReleases } from '..';
import * as httpMock from '../../../test/httpMock';
import { DATASOURCE_FAILURE } from '../../constants/error-messages';
import { EXTERNAL_HOST_ERROR } from '../../constants/error-messages';
import { id as datasource } from '.';

let res1 = fs.readFileSync(
Expand Down Expand Up @@ -36,14 +36,14 @@ describe('datasource/cdnjs', () => {
httpMock.scope(baseUrl).get(pathFor('foo/bar')).reply(200, null);
await expect(
getPkgReleases({ datasource, depName: 'foo/bar' })
).rejects.toThrow(DATASOURCE_FAILURE);
).rejects.toThrow(EXTERNAL_HOST_ERROR);
expect(httpMock.getTrace()).toMatchSnapshot();
});
it('throws for error', async () => {
httpMock.scope(baseUrl).get(pathFor('foo/bar')).replyWithError('error');
await expect(
getPkgReleases({ datasource, depName: 'foo/bar' })
).rejects.toThrow(DATASOURCE_FAILURE);
).rejects.toThrow(EXTERNAL_HOST_ERROR);
expect(httpMock.getTrace()).toMatchSnapshot();
});
it('returns null for 404', async () => {
Expand All @@ -70,28 +70,28 @@ describe('datasource/cdnjs', () => {
httpMock.scope(baseUrl).get(pathFor('foo/bar')).reply(401);
await expect(
getPkgReleases({ datasource, depName: 'foo/bar' })
).rejects.toThrow(DATASOURCE_FAILURE);
).rejects.toThrow(EXTERNAL_HOST_ERROR);
expect(httpMock.getTrace()).toMatchSnapshot();
});
it('throws for 429', async () => {
httpMock.scope(baseUrl).get(pathFor('foo/bar')).reply(429);
await expect(
getPkgReleases({ datasource, depName: 'foo/bar' })
).rejects.toThrow(DATASOURCE_FAILURE);
).rejects.toThrow(EXTERNAL_HOST_ERROR);
expect(httpMock.getTrace()).toMatchSnapshot();
});
it('throws for 5xx', async () => {
httpMock.scope(baseUrl).get(pathFor('foo/bar')).reply(502);
await expect(
getPkgReleases({ datasource, depName: 'foo/bar' })
).rejects.toThrow(DATASOURCE_FAILURE);
).rejects.toThrow(EXTERNAL_HOST_ERROR);
expect(httpMock.getTrace()).toMatchSnapshot();
});
it('returns null for unknown error', async () => {
httpMock.scope(baseUrl).get(pathFor('foo/bar')).replyWithError('error');
await expect(
getPkgReleases({ datasource, depName: 'foo/bar' })
).rejects.toThrow(DATASOURCE_FAILURE);
).rejects.toThrow(EXTERNAL_HOST_ERROR);
expect(httpMock.getTrace()).toMatchSnapshot();
});
it('processes real data', async () => {
Expand Down
7 changes: 4 additions & 3 deletions lib/datasource/cdnjs/index.ts
@@ -1,7 +1,8 @@
import { logger } from '../../logger';
import { ExternalHostError } from '../../types/error';
import { Http } from '../../util/http';
import { CachePromise, cacheAble } from '../cache';
import { DatasourceError, GetReleasesConfig, ReleaseResult } from '../common';
import { GetReleasesConfig, ReleaseResult } from '../common';

export const id = 'cdnjs';

Expand Down Expand Up @@ -60,7 +61,7 @@ export async function getReleases({
logger.debug({ library }, 'cdnjs library not found');
return null;
}
// Throw a DatasourceError for all other types of errors
throw new DatasourceError(err);
// Throw an ExternalHostError for all other types of errors
throw new ExternalHostError(err);
}
}
17 changes: 0 additions & 17 deletions lib/datasource/common.ts
@@ -1,5 +1,3 @@
import { DATASOURCE_FAILURE } from '../constants/error-messages';

export interface Config {
datasource?: string;
depName?: string;
Expand Down Expand Up @@ -80,18 +78,3 @@ export interface Datasource {
defaultConfig?: object;
registryStrategy?: 'first' | 'hunt' | 'merge';
}

export class DatasourceError extends Error {
err: Error;

datasource?: string;

lookupName?: string;

constructor(err: Error) {
super(DATASOURCE_FAILURE);
// Set the prototype explicitly: https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#extending-built-ins-like-error-array-and-map-may-no-longer-work
Object.setPrototypeOf(this, DatasourceError.prototype);
this.err = err;
}
}
2 changes: 1 addition & 1 deletion lib/datasource/crate/__snapshots__/index.spec.ts.snap
Expand Up @@ -764,7 +764,7 @@ Array [
]
`;

exports[`datasource/crate getReleases throws for 5xx 1`] = `[Error: registry-failure]`;
exports[`datasource/crate getReleases throws for 5xx 1`] = `[Error: external-host-error]`;

exports[`datasource/crate getReleases throws for 5xx 2`] = `
Array [
Expand Down
10 changes: 3 additions & 7 deletions lib/datasource/crate/index.ts
@@ -1,12 +1,8 @@
import { logger } from '../../logger';
import { ExternalHostError } from '../../types/error';
import * as globalCache from '../../util/cache/global';
import { Http } from '../../util/http';
import {
DatasourceError,
GetReleasesConfig,
Release,
ReleaseResult,
} from '../common';
import { GetReleasesConfig, Release, ReleaseResult } from '../common';

export const id = 'crate';

Expand Down Expand Up @@ -105,7 +101,7 @@ export async function getReleases({
err.statusCode === 429 ||
(err.statusCode >= 500 && err.statusCode < 600)
) {
throw new DatasourceError(err);
throw new ExternalHostError(err);
}
logger.warn({ err, lookupName }, 'crates.io lookup failure: Unknown error');
return null;
Expand Down
2 changes: 1 addition & 1 deletion lib/datasource/dart/__snapshots__/index.spec.ts.snap
Expand Up @@ -144,7 +144,7 @@ Array [
]
`;

exports[`datasource/dart getReleases throws for 5xx 1`] = `[Error: registry-failure]`;
exports[`datasource/dart getReleases throws for 5xx 1`] = `[Error: external-host-error]`;

exports[`datasource/dart getReleases throws for 5xx 2`] = `
Array [
Expand Down
5 changes: 3 additions & 2 deletions lib/datasource/dart/index.ts
@@ -1,6 +1,7 @@
import { logger } from '../../logger';
import { ExternalHostError } from '../../types/error';
import { Http, HttpResponse } from '../../util/http';
import { DatasourceError, GetReleasesConfig, ReleaseResult } from '../common';
import { GetReleasesConfig, ReleaseResult } from '../common';

export const id = 'dart';

Expand Down Expand Up @@ -33,7 +34,7 @@ export async function getReleases({
err.statusCode === 429 ||
(err.statusCode >= 500 && err.statusCode < 600)
) {
throw new DatasourceError(err);
throw new ExternalHostError(err);
}
logger.warn(
{ err, lookupName },
Expand Down
6 changes: 3 additions & 3 deletions lib/datasource/docker/index.spec.ts
Expand Up @@ -2,7 +2,7 @@ import AWS from 'aws-sdk';
import AWSMock from 'aws-sdk-mock';
import { getDigest, getPkgReleases } from '..';
import * as httpMock from '../../../test/httpMock';
import { DATASOURCE_FAILURE } from '../../constants/error-messages';
import { EXTERNAL_HOST_ERROR } from '../../constants/error-messages';
import * as _hostRules from '../../util/host-rules';
import * as docker from '.';

Expand Down Expand Up @@ -331,13 +331,13 @@ describe('api/docker', () => {
httpMock.scope(baseUrl).get('/').replyWithError({ statusCode: 429 });
await expect(
getDigest({ datasource: 'docker', depName: 'some-dep' }, 'latest')
).rejects.toThrow(Error(DATASOURCE_FAILURE));
).rejects.toThrow(EXTERNAL_HOST_ERROR);
});
it('should throw error for 5xx', async () => {
httpMock.scope(baseUrl).get('/').replyWithError({ statusCode: 504 });
await expect(
getDigest({ datasource: 'docker', depName: 'some-dep' }, 'latest')
).rejects.toThrow(Error(DATASOURCE_FAILURE));
).rejects.toThrow(EXTERNAL_HOST_ERROR);
});
});
describe('getReleases', () => {
Expand Down
25 changes: 13 additions & 12 deletions lib/datasource/docker/index.ts
Expand Up @@ -6,10 +6,11 @@ import parseLinkHeader from 'parse-link-header';
import wwwAuthenticate from 'www-authenticate';
import { logger } from '../../logger';
import { HostRule } from '../../types';
import { ExternalHostError } from '../../types/error';
import * as globalCache from '../../util/cache/global';
import * as hostRules from '../../util/host-rules';
import { Http, HttpResponse } from '../../util/http';
import { DatasourceError, GetReleasesConfig, ReleaseResult } from '../common';
import { GetReleasesConfig, ReleaseResult } from '../common';

// TODO: add got typings when available
// TODO: replace www-authenticate with https://www.npmjs.com/package/auth-header ?
Expand Down Expand Up @@ -220,14 +221,14 @@ async function getAuthHeaders(
}
// prettier-ignore
if (err.name === 'RequestError' && registry.endsWith('docker.io')) { // lgtm [js/incomplete-url-substring-sanitization]
throw new DatasourceError(err);
throw new ExternalHostError(err);
}
// prettier-ignore
if (err.statusCode === 429 && registry.endsWith('docker.io')) { // lgtm [js/incomplete-url-substring-sanitization]
throw new DatasourceError(err);
throw new ExternalHostError(err);
}
if (err.statusCode >= 500 && err.statusCode < 600) {
throw new DatasourceError(err);
throw new ExternalHostError(err);
}
logger.warn(
{ registry, dockerRepository: repository, err },
Expand Down Expand Up @@ -267,7 +268,7 @@ async function getManifestResponse(
});
return manifestResponse;
} catch (err) /* istanbul ignore next */ {
if (err instanceof DatasourceError) {
if (err instanceof ExternalHostError) {
throw err;
}
if (err.statusCode === 401) {
Expand All @@ -292,10 +293,10 @@ async function getManifestResponse(
}
// prettier-ignore
if (err.statusCode === 429 && registry.endsWith('docker.io')) { // lgtm [js/incomplete-url-substring-sanitization]
throw new DatasourceError(err);
throw new ExternalHostError(err);
}
if (err.statusCode >= 500 && err.statusCode < 600) {
throw new DatasourceError(err);
throw new ExternalHostError(err);
}
if (err.code === 'ETIMEDOUT') {
logger.debug(
Expand Down Expand Up @@ -356,7 +357,7 @@ export async function getDigest(
logger.debug({ digest }, 'Got docker digest');
}
} catch (err) /* istanbul ignore next */ {
if (err instanceof DatasourceError) {
if (err instanceof ExternalHostError) {
throw err;
}
logger.debug(
Expand Down Expand Up @@ -413,7 +414,7 @@ async function getTags(
await globalCache.set(cacheNamespace, cacheKey, tags, cacheMinutes);
return tags;
} catch (err) /* istanbul ignore next */ {
if (err instanceof DatasourceError) {
if (err instanceof ExternalHostError) {
throw err;
}
logger.debug(
Expand Down Expand Up @@ -441,14 +442,14 @@ async function getTags(
{ registry, dockerRepository: repository, err },
'docker registry failure: too many requests'
);
throw new DatasourceError(err);
throw new ExternalHostError(err);
}
if (err.statusCode >= 500 && err.statusCode < 600) {
logger.warn(
{ registry, dockerRepository: repository, err },
'docker registry failure: internal error'
);
throw new DatasourceError(err);
throw new ExternalHostError(err);
}
if (err.code === 'ETIMEDOUT') {
logger.debug(
Expand Down Expand Up @@ -543,7 +544,7 @@ async function getLabels(
await globalCache.set(cacheNamespace, cacheKey, labels, cacheMinutes);
return labels;
} catch (err) {
if (err instanceof DatasourceError) {
if (err instanceof ExternalHostError) {
throw err;
}
if (err.statusCode === 400 || err.statusCode === 401) {
Expand Down

0 comments on commit 52a074e

Please sign in to comment.