diff --git a/lib/constants/data-binary-source.ts b/lib/constants/data-binary-source.ts index 9f6d528d5763fdcaf7fe48fc7fdb71a50542f40f..46021a4454e04d15eefa7bbc803acc4aa4d66663 100644 --- a/lib/constants/data-binary-source.ts +++ b/lib/constants/data-binary-source.ts @@ -1,6 +1,6 @@ // Datasource export const DATASOURCE_CARGO = 'cargo'; -// export const DATASOURCE_CDNJS = 'cdnjs'; +export const DATASOURCE_CDNJS = 'cdnjs'; export const DATASOURCE_DART = 'dart'; export const DATASOURCE_DOCKER = 'docker'; export const DATASOURCE_GIT_SUBMODULES = 'gitSubmodules'; diff --git a/lib/datasource/cdnjs/index.ts b/lib/datasource/cdnjs/index.ts index acac254aa00f899ff9b7605fa19ad0b0f400dce8..7184c8f06f2726f77133da21473d90995ffa5382 100644 --- a/lib/datasource/cdnjs/index.ts +++ b/lib/datasource/cdnjs/index.ts @@ -2,12 +2,16 @@ import { logger } from '../../logger'; import got from '../../util/got'; import { ReleaseResult, PkgReleaseConfig } from '../common'; import { DATASOURCE_FAILURE } from '../../constants/error-messages'; +import { DATASOURCE_CDNJS } from '../../constants/data-binary-source'; interface CdnjsAsset { version: string; files: string[]; } +const cacheNamespace = `datasource-${DATASOURCE_CDNJS}`; +const cacheMinutes = 60; + interface CdnjsResponse { homepage?: string; repository?: { @@ -28,7 +32,16 @@ export async function getPkgReleases({ const [depName, ...assetParts] = lookupName.split('/'); const assetName = assetParts.join('/'); - const url = `https://api.cdnjs.com/libraries/${depName}`; + + const cacheKey = depName; + const cachedResult = await renovateCache.get<ReleaseResult>( + cacheNamespace, + cacheKey + ); + // istanbul ignore if + if (cachedResult) return cachedResult; + + const url = `https://api.cdnjs.com/libraries/${depName}?fields=homepage,repository,assets`; try { const res = await got(url, { json: true }); @@ -51,6 +64,8 @@ export async function getPkgReleases({ if (homepage) result.homepage = homepage; if (repository && repository.url) result.sourceUrl = repository.url; + await renovateCache.set(cacheNamespace, cacheKey, result, cacheMinutes); + return result; } catch (err) { const errorData = { depName, err }; diff --git a/test/datasource/cdnjs.spec.ts b/test/datasource/cdnjs.spec.ts index 30991b70c768e25ca92600a8586d3994bc3d8c20..f6c9d4262ca8aa995d53cfc1eaf24167fbc31a4d 100644 --- a/test/datasource/cdnjs.spec.ts +++ b/test/datasource/cdnjs.spec.ts @@ -3,7 +3,8 @@ import _got from '../../lib/util/got'; import { getPkgReleases } from '../../lib/datasource/cdnjs'; import { DATASOURCE_FAILURE } from '../../lib/constants/error-messages'; -const got: any = _got; +const got: jest.Mock<any> = _got as any; +jest.mock('../../lib/util/got'); let res1 = fs.readFileSync( 'test/datasource/cdnjs/_fixtures/d3-force.json', @@ -17,55 +18,36 @@ let res2 = fs.readFileSync( ); res2 = JSON.parse(res2); -jest.mock('../../lib/util/got'); - describe('datasource/cdnjs', () => { describe('getPkgReleases', () => { beforeEach(() => { jest.clearAllMocks(); - global.repoCache = {}; return global.renovateCache.rmAll(); }); it('returns null for empty result', async () => { - got.mockReturnValueOnce(null); + got.mockResolvedValueOnce(null); expect(await getPkgReleases({ lookupName: 'foo/bar' })).toBeNull(); }); it('returns null for missing fields', async () => { - got.mockReturnValueOnce({}); + got.mockResolvedValueOnce({}); expect(await getPkgReleases({ lookupName: 'foo/bar' })).toBeNull(); }); it('returns null for 404', async () => { - got.mockImplementationOnce(() => - Promise.reject({ - statusCode: 404, - }) - ); + got.mockRejectedValueOnce({ statusCode: 404 }); expect(await getPkgReleases({ lookupName: 'foo/bar' })).toBeNull(); }); it('returns null for 401', async () => { - got.mockImplementationOnce(() => - Promise.reject({ - statusCode: 401, - }) - ); + got.mockRejectedValueOnce({ statusCode: 401 }); expect(await getPkgReleases({ lookupName: 'foo/bar' })).toBeNull(); }); it('throws for 429', async () => { - got.mockImplementationOnce(() => - Promise.reject({ - statusCode: 429, - }) - ); + got.mockRejectedValueOnce({ statusCode: 429 }); await expect( getPkgReleases({ lookupName: 'foo/bar' }) ).rejects.toThrowError(DATASOURCE_FAILURE); }); it('throws for 5xx', async () => { - got.mockImplementationOnce(() => - Promise.reject({ - statusCode: 502, - }) - ); + got.mockRejectedValueOnce({ statusCode: 502 }); await expect( getPkgReleases({ lookupName: 'foo/bar' }) ).rejects.toThrowError(DATASOURCE_FAILURE); @@ -77,21 +59,17 @@ describe('datasource/cdnjs', () => { expect(await getPkgReleases({ lookupName: 'foo/bar' })).toBeNull(); }); it('returns null with wrong auth token', async () => { - got.mockReturnValueOnce( - Promise.reject({ - statusCode: 401, - }) - ); + got.mockRejectedValueOnce({ statusCode: 401 }); const res = await getPkgReleases({ lookupName: 'foo/bar' }); expect(res).toBeNull(); }); it('processes real data', async () => { - got.mockReturnValueOnce({ body: res1 }); + got.mockResolvedValueOnce({ body: res1 }); const res = await getPkgReleases({ lookupName: 'd3-force/d3-force.js' }); expect(res).toMatchSnapshot(); }); it('filters releases by asset presence', async () => { - got.mockReturnValueOnce({ body: res2 }); + got.mockResolvedValueOnce({ body: res2 }); const res = await getPkgReleases({ lookupName: 'bulma/only/0.7.5/style.css', }); diff --git a/test/datasource/cdnjs/_fixtures/bulma.json b/test/datasource/cdnjs/_fixtures/bulma.json index b972a5fe3c8cfd901b55e47ef05573773ec98d39..e1a4db5ecdb4bc5ad72d11bceea714e94c1c1eb8 100644 --- a/test/datasource/cdnjs/_fixtures/bulma.json +++ b/test/datasource/cdnjs/_fixtures/bulma.json @@ -1,26 +1,9 @@ { - "name": "bulma", - "filename": "css/bulma.min.css", - "version": "0.8.0", - "description": "Modern CSS framework based on Flexbox", "repository": { "type": "git", "url": "git+https://github.com/jgthms/bulma.git" }, - "keywords": [ - "css", - "sass", - "flexbox", - "responsive", - "framework" - ], - "author": "bulma", "homepage": "http://bulma.io", - "autoupdate": { - "source": "npm", - "target": "bulma" - }, - "license": "MIT", "assets": [ { "version": "0.8.0", diff --git a/test/datasource/cdnjs/_fixtures/d3-force.json b/test/datasource/cdnjs/_fixtures/d3-force.json index 8d4ffd6ed6fb4a5cffe6242845c241842f974a39..a462418acd74f77f276797c2148861709b0d693a 100644 --- a/test/datasource/cdnjs/_fixtures/d3-force.json +++ b/test/datasource/cdnjs/_fixtures/d3-force.json @@ -1,29 +1,9 @@ { - "name": "d3-force", - "filename": "d3-force.min.js", - "version": "1.1.0", - "description": "Force-directed graph layout using velocity Verlet integration.", "repository": { "type": "git", "url": "https://github.com/d3/d3-force.git" }, - "keywords": [ - "d3", - "d3-module", - "layout", - "network", - "graph", - "force", - "verlet", - "infovis" - ], - "author": "d3-force", "homepage": "https://d3js.org/d3-force/", - "autoupdate": { - "source": "npm", - "target": "d3-force" - }, - "license": "BSD-3-Clause", "assets": [ { "version": "1.1.0",