diff --git a/lib/types/github.spec.ts b/lib/constants/platform.spec.ts similarity index 50% rename from lib/types/github.spec.ts rename to lib/constants/platform.spec.ts index 8e79ef350a37a68f5459bb88447f2398050aec17..22984c3e06143ffd7f65c5a5436d341fe9d6474d 100644 --- a/lib/types/github.spec.ts +++ b/lib/constants/platform.spec.ts @@ -1,13 +1,32 @@ -import { - PLATFORM_TYPE_GITHUB, - PLATFORM_TYPE_GITLAB, -} from '../constants/platforms'; import { id as GH_RELEASES_DS } from '../datasource/github-releases'; import { id as GH_TAGS_DS } from '../datasource/github-tags'; +import { GitlabReleasesDatasource } from '../datasource/gitlab-releases'; +import { id as GL_TAGS_DS } from '../datasource/gitlab-tags'; import { id as POD_DS } from '../datasource/pod'; -import { GITHUB_API_USING_HOST_TYPES } from './github'; +import { + GITHUB_API_USING_HOST_TYPES, + GITLAB_API_USING_HOST_TYPES, + PLATFORM_TYPE_GITHUB, + PLATFORM_TYPE_GITLAB, +} from './platforms'; + +describe('constants/platform', () => { + it('should be part of the GITLAB_API_USING_HOST_TYPES', () => { + expect(GITLAB_API_USING_HOST_TYPES.includes(GL_TAGS_DS)).toBeTrue(); + expect( + GITLAB_API_USING_HOST_TYPES.includes(GitlabReleasesDatasource.id) + ).toBeTrue(); + expect( + GITLAB_API_USING_HOST_TYPES.includes(PLATFORM_TYPE_GITLAB) + ).toBeTrue(); + }); + + it('should be not part of the GITLAB_API_USING_HOST_TYPES ', () => { + expect( + GITLAB_API_USING_HOST_TYPES.includes(PLATFORM_TYPE_GITHUB) + ).toBeFalse(); + }); -describe('types/github', () => { it('should be part of the GITHUB_API_USING_HOST_TYPES ', () => { expect(GITHUB_API_USING_HOST_TYPES.includes(GH_TAGS_DS)).toBeTrue(); expect(GITHUB_API_USING_HOST_TYPES.includes(GH_RELEASES_DS)).toBeTrue(); diff --git a/lib/constants/platforms.ts b/lib/constants/platforms.ts index 07b779c55ec8f5f25dd6895c4cae006ae719b3a8..94725ae52da84d6b5c694eb210f53287d47686b8 100644 --- a/lib/constants/platforms.ts +++ b/lib/constants/platforms.ts @@ -4,3 +4,16 @@ export const PLATFORM_TYPE_BITBUCKET_SERVER = 'bitbucket-server'; export const PLATFORM_TYPE_GITEA = 'gitea'; export const PLATFORM_TYPE_GITHUB = 'github'; export const PLATFORM_TYPE_GITLAB = 'gitlab'; + +export const GITHUB_API_USING_HOST_TYPES = [ + PLATFORM_TYPE_GITHUB, + 'github-releases', + 'github-tags', + 'pod', +]; + +export const GITLAB_API_USING_HOST_TYPES = [ + PLATFORM_TYPE_GITLAB, + 'gitlab-releases', + 'gitlab-tags', +]; diff --git a/lib/platform/github/__snapshots__/index.spec.ts.snap b/lib/platform/github/__snapshots__/index.spec.ts.snap index 57149d2ed26f04c366147c8477d263b96584320b..37ff4dedb235e284b933f4fb5741ca9c32e3190d 100644 --- a/lib/platform/github/__snapshots__/index.spec.ts.snap +++ b/lib/platform/github/__snapshots__/index.spec.ts.snap @@ -6875,33 +6875,6 @@ Array [ ] `; -exports[`platform/github/index initPlatform() should add initialized platform with predefined generic host rule for github api 1`] = ` -Object { - "endpoint": "https://api.github.com/", - "gitAuthor": "renovate@whitesourcesoftware.com", - "renovateUsername": "renovate-bot", -} -`; - -exports[`platform/github/index initPlatform() should add initialized platform with predefined generic host rule for github api 2`] = ` -[MockFunction] { - "calls": Array [ - Array [ - Object { - "matchHost": "api.github.com", - "token": "abc123", - }, - ], - ], - "results": Array [ - Object { - "type": "return", - "value": undefined, - }, - ], -} -`; - exports[`platform/github/index initPlatform() should support custom endpoint 1`] = ` Object { "endpoint": "https://ghe.renovatebot.com/", diff --git a/lib/platform/github/index.spec.ts b/lib/platform/github/index.spec.ts index ff04c1f864f4d3a186085da9c42286cb99932584..23271d258b7127ab2a86895666be8e17e1ddddae 100644 --- a/lib/platform/github/index.spec.ts +++ b/lib/platform/github/index.spec.ts @@ -129,17 +129,6 @@ describe('platform/github/index', () => { ).toMatchSnapshot(); expect(httpMock.getTrace()).toMatchSnapshot(); }); - - it('should add initialized platform with predefined generic host rule for github api', async () => { - expect( - await github.initPlatform({ - token: 'abc123', - username: 'renovate-bot', - gitAuthor: 'renovate@whitesourcesoftware.com', - } as any) - ).toMatchSnapshot(); - expect(hostRules.add).toMatchSnapshot(); - }); }); describe('getRepos', () => { diff --git a/lib/platform/github/index.ts b/lib/platform/github/index.ts index f45144e82a77c8d878c1526d5939dc5bef3c9a0e..76c599a40ad337e3c775f188ecdd5b864eab6635 100644 --- a/lib/platform/github/index.ts +++ b/lib/platform/github/index.ts @@ -23,7 +23,7 @@ import * as git from '../../util/git'; import * as hostRules from '../../util/host-rules'; import * as githubHttp from '../../util/http/github'; import { sanitize } from '../../util/sanitize'; -import { ensureTrailingSlash, parseUrl } from '../../util/url'; +import { ensureTrailingSlash } from '../../util/url'; import type { AggregatedVulnerabilities, BranchStatusConfig, @@ -115,12 +115,6 @@ export async function initPlatform({ renovateUsername, }; - // Generic github hostRule that per default all datasources using github api are enabled - const genericGithubHostRule = { - matchHost: parseUrl(defaults.endpoint).hostname, - token, - }; - hostRules.add(genericGithubHostRule); return platformConfig; } diff --git a/lib/types/github.ts b/lib/types/github.ts deleted file mode 100644 index 9281983377cb52f47e2c283d0de49e6c9134978e..0000000000000000000000000000000000000000 --- a/lib/types/github.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { PLATFORM_TYPE_GITHUB } from '../constants/platforms'; - -export const GITHUB_API_USING_HOST_TYPES = [ - PLATFORM_TYPE_GITHUB, - 'github-releases', - 'github-tags', - 'pod', -]; diff --git a/lib/types/index.ts b/lib/types/index.ts index a89dd317986f5274c2425fe4adb7f43de323765d..e1e0fa9d4271991258fb868c06e04e77c5541fe6 100644 --- a/lib/types/index.ts +++ b/lib/types/index.ts @@ -4,4 +4,3 @@ export * from './versioning'; export * from './branch-status'; export * from './vulnerability-alert'; export * from './pr-state'; -export * from './github'; diff --git a/lib/types/platform/gitlab/index.spec.ts b/lib/types/platform/gitlab/index.spec.ts deleted file mode 100644 index 945f2e4476ccd053cf2b3cf4cb5684f906b8a73a..0000000000000000000000000000000000000000 --- a/lib/types/platform/gitlab/index.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { - PLATFORM_TYPE_GITHUB, - PLATFORM_TYPE_GITLAB, -} from '../../../constants/platforms'; -import { GitlabReleasesDatasource } from '../../../datasource/gitlab-releases'; -import { id as GL_TAGS_DS } from '../../../datasource/gitlab-tags'; -import { GITLAB_API_USING_HOST_TYPES } from './index'; - -describe('types/platform/gitlab/index', () => { - it('should be part of the GITLAB_API_USING_HOST_TYPES', () => { - expect(GITLAB_API_USING_HOST_TYPES.includes(GL_TAGS_DS)).toBeTrue(); - expect( - GITLAB_API_USING_HOST_TYPES.includes(GitlabReleasesDatasource.id) - ).toBeTrue(); - expect( - GITLAB_API_USING_HOST_TYPES.includes(PLATFORM_TYPE_GITLAB) - ).toBeTrue(); - }); - - it('should be not part of the GITLAB_API_USING_HOST_TYPES ', () => { - expect( - GITLAB_API_USING_HOST_TYPES.includes(PLATFORM_TYPE_GITHUB) - ).toBeFalse(); - }); -}); diff --git a/lib/types/platform/gitlab/index.ts b/lib/types/platform/gitlab/index.ts index 999f9149b1818982571747cdbfa8ccbaa1c742cf..a67df13e1ae81c1c0443e9f0c7fba585a246f1a9 100644 --- a/lib/types/platform/gitlab/index.ts +++ b/lib/types/platform/gitlab/index.ts @@ -1,4 +1,3 @@ -import { PLATFORM_TYPE_GITLAB } from '../../../constants/platforms'; import { GitTreeNode } from '../../git'; export type GitLabBranch = { @@ -13,9 +12,3 @@ export type GitlabTreeNode = { id: string; name: string; } & GitTreeNode; - -export const GITLAB_API_USING_HOST_TYPES = [ - PLATFORM_TYPE_GITLAB, - 'gitlab-releases', - 'gitlab-tags', -]; diff --git a/lib/util/http/auth.ts b/lib/util/http/auth.ts index b3a5383dfc5c421276818b1c8a1a1ac3f9a57191..a8dfc3f42f4448d4c1bcd4f551eddeddc41374a8 100644 --- a/lib/util/http/auth.ts +++ b/lib/util/http/auth.ts @@ -1,9 +1,11 @@ import is from '@sindresorhus/is'; -import { NormalizedOptions } from 'got'; -import { PLATFORM_TYPE_GITEA } from '../../constants/platforms'; -import { GITHUB_API_USING_HOST_TYPES } from '../../types'; -import { GITLAB_API_USING_HOST_TYPES } from '../../types/platform/gitlab'; -import { GotOptions } from './types'; +import type { NormalizedOptions } from 'got'; +import { + GITHUB_API_USING_HOST_TYPES, + GITLAB_API_USING_HOST_TYPES, + PLATFORM_TYPE_GITEA, +} from '../../constants/platforms'; +import type { GotOptions } from './types'; export function applyAuthorization(inOptions: GotOptions): GotOptions { const options: GotOptions = { ...inOptions }; diff --git a/lib/util/http/host-rules.spec.ts b/lib/util/http/host-rules.spec.ts index ea59b0461ff26721b70ef1da4e73a3dbd1312b40..a46e6d3230828811a2680541eb961906066de956 100644 --- a/lib/util/http/host-rules.spec.ts +++ b/lib/util/http/host-rules.spec.ts @@ -36,6 +36,11 @@ describe('util/http/host-rules', () => { authType: 'Basic', token: 'XXX', }); + + hostRules.add({ + hostType: 'gitlab-tags', + token: 'abc', + }); }); afterEach(() => { @@ -111,4 +116,40 @@ describe('util/http/host-rules', () => { } `); }); + + it('noAuth', () => { + expect(applyHostRules(url, { ...options, noAuth: true })) + .toMatchInlineSnapshot(` + Object { + "hostType": "github", + "noAuth": true, + } + `); + }); + + it('fallback to github', () => { + expect(applyHostRules(url, { ...options, hostType: 'github-tags' })) + .toMatchInlineSnapshot(` + Object { + "context": Object { + "authType": undefined, + }, + "hostType": "github-tags", + "token": "token", + } + `); + }); + + it('fallback to gitlab', () => { + expect(applyHostRules(url, { ...options, hostType: 'gitlab-tags' })) + .toMatchInlineSnapshot(` + Object { + "context": Object { + "authType": undefined, + }, + "hostType": "gitlab-tags", + "token": "abc", + } + `); + }); }); diff --git a/lib/util/http/host-rules.ts b/lib/util/http/host-rules.ts index 975a2ae5412871ce9cdc7937cb9f42ca16c1e03c..d327f0418e9363d96bea9458deb41c5e4e1e7d3b 100644 --- a/lib/util/http/host-rules.ts +++ b/lib/util/http/host-rules.ts @@ -1,17 +1,54 @@ +import { + GITHUB_API_USING_HOST_TYPES, + GITLAB_API_USING_HOST_TYPES, + PLATFORM_TYPE_GITHUB, + PLATFORM_TYPE_GITLAB, +} from '../../constants/platforms'; import { logger } from '../../logger'; import { hasProxy } from '../../proxy'; +import type { HostRule } from '../../types'; import * as hostRules from '../host-rules'; -import { GotOptions } from './types'; +import type { GotOptions } from './types'; -// Apply host rules to requests +function findMatchingRules(options: GotOptions, url: string): HostRule { + const { hostType } = options; + let res = hostRules.find({ hostType, url }); + + // Fallback to `github` hostType + if ( + GITHUB_API_USING_HOST_TYPES.includes(hostType) && + hostType !== PLATFORM_TYPE_GITHUB + ) { + res = { + ...hostRules.find({ + hostType: PLATFORM_TYPE_GITHUB, + url, + }), + ...res, + }; + } + + // Fallback to `gitlab` hostType + if ( + GITLAB_API_USING_HOST_TYPES.includes(hostType) && + hostType !== PLATFORM_TYPE_GITLAB + ) { + res = { + ...hostRules.find({ + hostType: PLATFORM_TYPE_GITLAB, + url, + }), + ...res, + }; + } + return res; +} + +// Apply host rules to requests export function applyHostRules(url: string, inOptions: GotOptions): GotOptions { const options: GotOptions = { ...inOptions }; - const foundRules = - hostRules.find({ - hostType: options.hostType, - url, - }) || /* istanbul ignore next: can only happen in tests */ {}; + const foundRules = findMatchingRules(options, url); const { username, password, token, enabled, authType } = foundRules; if (options.noAuth) { logger.trace({ url }, `Authorization disabled`); diff --git a/lib/util/http/index.spec.ts b/lib/util/http/index.spec.ts index d7c7531a46ed81c6cea8cb48eb085647392eef75..c42837687d107251345e86500f286d9e0d058f64 100644 --- a/lib/util/http/index.spec.ts +++ b/lib/util/http/index.spec.ts @@ -208,4 +208,11 @@ describe('util/http/index', () => { expect(bar).toBeTrue(); expect(baz).toBeTrue(); }); + + it('getBuffer', async () => { + httpMock.scope(baseUrl).get('/').reply(200, Buffer.from('test')); + const res = await http.getBuffer('http://renovate.com'); + expect(res.body).toBeInstanceOf(Buffer); + expect(res.body.toString('utf-8')).toEqual('test'); + }); }); diff --git a/lib/util/http/index.ts b/lib/util/http/index.ts index a3530c952606cbd5889686c27bf9a9aebc69773e..d9c727ecab81f63f0c4c801bf28079d747f46d03 100644 --- a/lib/util/http/index.ts +++ b/lib/util/http/index.ts @@ -53,12 +53,16 @@ export interface HttpResponse<T = string> { authorization?: boolean; } -function cloneResponse<T>(response: any): HttpResponse<T> { +function cloneResponse<T extends Buffer | string | any>( + response: HttpResponse<T> +): HttpResponse<T> { + const { body, statusCode, headers } = response; // clone body and headers so that the cached result doesn't get accidentally mutated + // Don't use json clone for buffers return { - statusCode: response.statusCode, - body: clone<T>(response.body), - headers: clone(response.headers), + statusCode, + body: body instanceof Buffer ? (body.slice() as T) : clone<T>(body), + headers: clone(headers), authorization: !!response.authorization, }; } @@ -95,7 +99,8 @@ async function gotRoutine<T>( // Cheat the TS compiler using `as` to pick a specific overload. // Otherwise it doesn't typecheck. const resp = await got<T>(url, options as GotJSONOptions); - const duration = resp.timings.phases.total || 0; + const duration = + resp.timings.phases.total || /* istanbul ignore next: can't be tested */ 0; const httpRequests = memCache.get('http-requests') || []; httpRequests.push({ ...requestStats, duration }); @@ -166,6 +171,7 @@ export class Http<GetOptions = HttpOptions, PostOptions = HttpPostOptions> { resPromise = memCache.get(cacheKey); } + // istanbul ignore else: no cache tests if (!resPromise) { const startTime = Date.now(); const queueTask = (): Promise<Response<T>> => {