diff --git a/lib/util/got/__snapshots__/index.spec.ts.snap b/lib/util/got/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000000000000000000000000000000000..7d80f0a7891b9e4195fb6201bfc1cfce410cf144 --- /dev/null +++ b/lib/util/got/__snapshots__/index.spec.ts.snap @@ -0,0 +1,415 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`util/got/index uses basic auth 1`] = ` +Object { + "body": Object {}, + "options": Object { + "auth": ":test", + "baseUrl": "https://api.github.com/", + "cache": false, + "decompress": true, + "followRedirect": true, + "form": false, + "gotTimeout": Object { + "request": 60000, + }, + "hash": "", + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "hooks": Object { + "afterResponse": Array [], + "beforeError": Array [], + "beforeRedirect": Array [], + "beforeRequest": Array [], + "beforeRetry": Array [], + "init": Array [], + }, + "hostname": "api.github.com", + "href": "https://api.github.com/some", + "json": true, + "method": "GET", + "path": "/some", + "pathname": "/some", + "protocol": "https:", + "retry": Object { + "errorCodes": Set {}, + "methods": Set {}, + "retries": [Function], + "statusCodes": Set {}, + }, + "search": "", + "stream": false, + "throwHttpErrors": true, + "useElectronNet": false, + }, +} +`; + +exports[`util/got/index uses basic auth 2`] = ` +Object { + "body": Object {}, + "options": Object { + "auth": ":test", + "baseUrl": "https://api.github.com/", + "cache": false, + "decompress": true, + "followRedirect": true, + "form": false, + "gotTimeout": Object { + "request": 60000, + }, + "hash": "", + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "hooks": Object { + "afterResponse": Array [], + "beforeError": Array [], + "beforeRedirect": Array [], + "beforeRequest": Array [], + "beforeRetry": Array [], + "init": Array [], + }, + "hostname": "api.github.com", + "href": "https://api.github.com/some", + "json": true, + "method": "GET", + "path": "/some", + "pathname": "/some", + "protocol": "https:", + "retry": Object { + "errorCodes": Set {}, + "methods": Set {}, + "retries": [Function], + "statusCodes": Set {}, + }, + "search": "", + "stream": false, + "throwHttpErrors": true, + "useElectronNet": false, + }, +} +`; + +exports[`util/got/index uses bearer auth 1`] = ` +Object { + "body": Object {}, + "options": Object { + "baseUrl": "https://api.github.com/", + "cache": false, + "decompress": true, + "followRedirect": true, + "form": false, + "hash": "", + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "authorization": "Bearer XXX", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "hooks": Object { + "afterResponse": Array [], + "beforeError": Array [], + "beforeRedirect": Array [], + "beforeRequest": Array [], + "beforeRetry": Array [], + "init": Array [], + }, + "hostname": "api.github.com", + "href": "https://api.github.com/some", + "json": true, + "method": "GET", + "path": "/some", + "pathname": "/some", + "protocol": "https:", + "retry": Object { + "errorCodes": Set {}, + "methods": Set {}, + "retries": [Function], + "statusCodes": Set {}, + }, + "search": "", + "stream": false, + "throwHttpErrors": true, + "useElectronNet": false, + }, +} +`; + +exports[`util/got/index uses bearer auth 2`] = ` +Object { + "body": Object {}, + "options": Object { + "baseUrl": "https://api.github.com/", + "cache": false, + "decompress": true, + "followRedirect": true, + "form": false, + "hash": "", + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "authorization": "Bearer XXX", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "hooks": Object { + "afterResponse": Array [], + "beforeError": Array [], + "beforeRedirect": Array [], + "beforeRequest": Array [], + "beforeRetry": Array [], + "init": Array [], + }, + "hostname": "api.github.com", + "href": "https://api.github.com/some", + "json": true, + "method": "GET", + "path": "/some", + "pathname": "/some", + "protocol": "https:", + "retry": Object { + "errorCodes": Set {}, + "methods": Set {}, + "retries": [Function], + "statusCodes": Set {}, + }, + "search": "", + "stream": false, + "throwHttpErrors": true, + "useElectronNet": false, + }, +} +`; + +exports[`util/got/index uses cache 1`] = ` +Object { + "body": Object {}, + "options": Object { + "baseUrl": "https://api.github.com/", + "cache": false, + "decompress": true, + "followRedirect": true, + "form": false, + "hash": "", + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "hooks": Object { + "afterResponse": Array [], + "beforeError": Array [], + "beforeRedirect": Array [], + "beforeRequest": Array [], + "beforeRetry": Array [], + "init": Array [], + }, + "hostType": "github", + "hostname": "api.github.com", + "href": "https://api.github.com/some", + "json": true, + "method": "GET", + "path": "/some", + "pathname": "/some", + "protocol": "https:", + "retry": Object { + "errorCodes": Set {}, + "methods": Set {}, + "retries": [Function], + "statusCodes": Set {}, + }, + "search": "", + "stream": false, + "throwHttpErrors": true, + "useElectronNet": false, + }, +} +`; + +exports[`util/got/index uses no cache 1`] = ` +Object { + "body": Object {}, + "options": Object { + "baseUrl": "https://api.github.com/", + "cache": false, + "decompress": true, + "followRedirect": true, + "form": false, + "hash": "", + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "hooks": Object { + "afterResponse": Array [], + "beforeError": Array [], + "beforeRedirect": Array [], + "beforeRequest": Array [], + "beforeRetry": Array [], + "init": Array [], + }, + "hostType": "github", + "hostname": "api.github.com", + "href": "https://api.github.com/some", + "json": true, + "method": "GET", + "path": "/some", + "pathname": "/some", + "protocol": "https:", + "retry": Object { + "errorCodes": Set {}, + "methods": Set {}, + "retries": [Function], + "statusCodes": Set {}, + }, + "search": "", + "stream": false, + "throwHttpErrors": true, + "useCache": false, + "useElectronNet": false, + }, +} +`; + +exports[`util/got/index uses no cache 2`] = ` +Object { + "body": Object {}, + "options": Object { + "baseUrl": "https://api.github.com/", + "cache": false, + "decompress": true, + "followRedirect": true, + "form": false, + "hash": "", + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "hooks": Object { + "afterResponse": Array [], + "beforeError": Array [], + "beforeRedirect": Array [], + "beforeRequest": Array [], + "beforeRetry": Array [], + "init": Array [], + }, + "hostType": "github", + "hostname": "api.github.com", + "href": "https://api.github.com/some", + "json": true, + "method": "HEAD", + "path": "/some", + "pathname": "/some", + "protocol": "https:", + "retry": Object { + "errorCodes": Set {}, + "methods": Set {}, + "retries": [Function], + "statusCodes": Set {}, + }, + "search": "", + "stream": false, + "throwHttpErrors": true, + "useElectronNet": false, + }, +} +`; + +exports[`util/got/index uses private-token auth 1`] = ` +Object { + "body": Object {}, + "options": Object { + "baseUrl": "https://api.github.com/", + "cache": false, + "decompress": true, + "followRedirect": true, + "form": false, + "hash": "", + "headers": Object { + "Private-token": "XXX", + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "hooks": Object { + "afterResponse": Array [], + "beforeError": Array [], + "beforeRedirect": Array [], + "beforeRequest": Array [], + "beforeRetry": Array [], + "init": Array [], + }, + "hostType": "gitlab", + "hostname": "api.github.com", + "href": "https://api.github.com/some", + "json": true, + "method": "GET", + "path": "/some", + "pathname": "/some", + "protocol": "https:", + "retry": Object { + "errorCodes": Set {}, + "methods": Set {}, + "retries": [Function], + "statusCodes": Set {}, + }, + "search": "", + "stream": false, + "throwHttpErrors": true, + "useElectronNet": false, + }, +} +`; + +exports[`util/got/index uses token auth 1`] = ` +Object { + "body": Object {}, + "options": Object { + "baseUrl": "https://api.github.com/", + "cache": false, + "decompress": true, + "followRedirect": true, + "form": false, + "hash": "", + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "authorization": "token XXX", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "hooks": Object { + "afterResponse": Array [], + "beforeError": Array [], + "beforeRedirect": Array [], + "beforeRequest": Array [], + "beforeRetry": Array [], + "init": Array [], + }, + "hostType": "gitea", + "hostname": "api.github.com", + "href": "https://api.github.com/some", + "json": true, + "method": "GET", + "path": "/some", + "pathname": "/some", + "protocol": "https:", + "retry": Object { + "errorCodes": Set {}, + "methods": Set {}, + "retries": [Function], + "statusCodes": Set {}, + }, + "search": "", + "stream": false, + "throwHttpErrors": true, + "useElectronNet": false, + }, +} +`; diff --git a/lib/util/got/auth.ts b/lib/util/got/auth.ts index df329ea12e699deadd9fc3e058a91a4093e73d84..7374474a7973039480f1895bd2f370526ef7d6f6 100644 --- a/lib/util/got/auth.ts +++ b/lib/util/got/auth.ts @@ -6,7 +6,6 @@ import { PLATFORM_TYPE_GITLAB, } from '../../constants/platforms'; -// istanbul ignore next export default create({ options: {}, handler: (options, next) => { diff --git a/lib/util/got/cache-get.ts b/lib/util/got/cache-get.ts index ac889634d4f39e8191bcef0dc756bbd9a0ae843e..8b934f7cd74853423b41442d125e651c885c34c2 100644 --- a/lib/util/got/cache-get.ts +++ b/lib/util/got/cache-get.ts @@ -5,13 +5,13 @@ import { clone } from '../clone'; // global.repoCache is reset to {} every time a repository is initialized // With this caching, it means every GET request is cached during each repository run -// istanbul ignore next export default create({ options: {}, handler: (options, next) => { if (!global.repoCache) { return next(options); } + if (options.stream) { return next(options); } diff --git a/lib/util/got/common.ts b/lib/util/got/common.ts index 1d881e8511305bc9cbcf2d9fab482117842e22c3..b431d7fbe93c54e33b90216b13b208713c88d73e 100644 --- a/lib/util/got/common.ts +++ b/lib/util/got/common.ts @@ -4,6 +4,7 @@ import { Url } from 'url'; export interface Options { hostType?: string; search?: string; + token?: string; useCache?: boolean; } diff --git a/lib/util/got/got.spec.ts b/lib/util/got/got.spec.ts index a45da3edde641f4e9d563ff01bc15d8826779b8a..6820be0ac0002575c4905dd57a93f795684aa839 100644 --- a/lib/util/got/got.spec.ts +++ b/lib/util/got/got.spec.ts @@ -1,6 +1,7 @@ import nock from 'nock'; import { getConfigResponse } from '../../datasource/docker'; +// TODO: move to datasource/docker ? describe('getConfigResponse', () => { beforeEach(() => { nock.disableNetConnect(); diff --git a/lib/util/got/host-rules.ts b/lib/util/got/host-rules.ts index 75e72a76666e3066fe662da9054e87efc998e01c..2c849a3ba95ec11ffbd0fdab77e8fd2381480183 100644 --- a/lib/util/got/host-rules.ts +++ b/lib/util/got/host-rules.ts @@ -5,10 +5,10 @@ import { create } from './util'; // Apply host rules to requests -// istanbul ignore next export default create({ options: {}, handler: (options, next) => { + // istanbul ignore if: never happen? if (!options.hostname) { return next(options); } diff --git a/lib/util/got/index.spec.ts b/lib/util/got/index.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..3f8de68ada8500917576188546345834a59cf52d --- /dev/null +++ b/lib/util/got/index.spec.ts @@ -0,0 +1,138 @@ +import nock from 'nock'; +import { getName } from '../../../test/util'; +import { api } from '.'; +import * as hostRules from '../host-rules'; +import { GotJSONOptions } from './common'; +import { + PLATFORM_TYPE_GITEA, + PLATFORM_TYPE_GITLAB, + PLATFORM_TYPE_GITHUB, +} from '../../constants/platforms'; + +const baseUrl = 'https://api.github.com'; + +describe(getName(__filename), () => { + beforeEach(() => { + nock.disableNetConnect(); + }); + + afterEach(() => { + nock.cleanAll(); + hostRules.clear(); + global.repoCache = {}; + nock.enableNetConnect(); + }); + + async function got(opts?: Partial<GotJSONOptions>) { + const { body, request } = (await api('some', { + method: 'GET', + baseUrl, + json: true, + ...opts, + })) as any; + return { body, options: request.gotOptions }; + } + + function mock(opts?: nock.Options, times = 1) { + return nock(baseUrl, opts) + .get('/some') + .times(times) + .reply(200, {}); + } + + it('uses bearer auth', async () => { + const req = mock({ reqheaders: { authorization: 'Bearer XXX' } }, 2); + hostRules.add({ baseUrl, token: 'XXX' }); + + expect(await got()).toMatchSnapshot(); + expect(await got({ token: 'XXX' })).toMatchSnapshot(); + expect(req.isDone()).toBe(true); + }); + + it('uses basic auth', async () => { + const req = mock({ reqheaders: { authorization: 'Basic OnRlc3Q=' } }, 2); + + hostRules.add({ password: 'test', timeout: 60000 }); + + expect(await got()).toMatchSnapshot(); + expect(await got({ auth: ':test' })).toMatchSnapshot(); + expect(req.isDone()).toBe(true); + }); + + it('uses token auth', async () => { + const req = mock({ reqheaders: { authorization: 'token XXX' } }); + hostRules.add({ baseUrl, token: 'XXX' }); + expect(await got({ hostType: PLATFORM_TYPE_GITEA })).toMatchSnapshot(); + expect(req.isDone()).toBe(true); + }); + + it('uses private-token auth', async () => { + const req = mock({ reqheaders: { 'private-token': 'XXX' } }); + hostRules.add({ baseUrl, token: 'XXX' }); + global.repoCache = null; + expect(await got({ hostType: PLATFORM_TYPE_GITLAB })).toMatchSnapshot(); + expect(req.isDone()).toBe(true); + }); + + it('uses cache', async () => { + const req = mock(); + const res = await got({ hostType: PLATFORM_TYPE_GITHUB }); + expect(res).toMatchSnapshot(); + expect(await got({ hostType: PLATFORM_TYPE_GITHUB })).toMatchObject(res); + expect(req.isDone()).toBe(true); + }); + + it('uses no cache', async () => { + const req = mock({}) + .head('/some') + .reply(200, {}) + .get('/some') + .replyWithError('not-found'); + + expect( + await got({ + hostType: PLATFORM_TYPE_GITHUB, + useCache: false, + }) + ).toMatchSnapshot(); + + expect( + await got({ hostType: PLATFORM_TYPE_GITHUB, method: 'HEAD' }) + ).toMatchSnapshot(); + + global.repoCache = {}; + + await expect(got({ hostType: PLATFORM_TYPE_GITHUB })).rejects.toThrowError( + 'not-found' + ); + + expect(req.isDone()).toBe(true); + expect(global.repoCache).toEqual({}); + }); + + it('streams no cache', async () => { + const req = mock(); + + const stream = api.stream('/some', { + baseUrl, + }); + expect(stream).toBeDefined(); + + let data = ''; + + stream.on('data', c => { + data += c; + }); + + const done = new Promise((resolve, reject) => { + stream.on('end', resolve); + stream.on('error', reject); + }); + + await done; + + expect(data).toBe('{}'); + expect(req.isDone()).toBe(true); + expect(global.repoCache).toEqual({}); + }); +});