From c1fd79bac767131bf3bf90c368f5fe8812bb40bd Mon Sep 17 00:00:00 2001 From: Rhys Arkins <rhys@arkins.net> Date: Sat, 1 Sep 2018 07:18:28 +0200 Subject: [PATCH] feat: cache github datasource results for 10 minutes --- lib/datasource/github.js | 49 +++++++++++++++++++ .../__snapshots__/github.spec.js.snap | 16 ++++++ test/datasource/github.spec.js | 14 ++++++ 3 files changed, 79 insertions(+) diff --git a/lib/datasource/github.js b/lib/datasource/github.js index 59448cbf73..287109edac 100644 --- a/lib/datasource/github.js +++ b/lib/datasource/github.js @@ -1,11 +1,55 @@ +const cacache = require('cacache/en'); +const os = require('os'); +const { DateTime } = require('luxon'); + const ghGot = require('../platform/github/gh-got-wrapper'); const versioning = require('../versioning'); module.exports = { getPreset, getPkgReleases, + rmAllCache, }; +const datasourceCache = + (process.env.RENOVATE_TMPDIR || os.tmpdir()) + + '/renovate-gh-datasource-cache-v1'; + +async function getCachedResult(repo, type) { + try { + const cacheVal = await cacache.get(datasourceCache, `${repo}-${type}`); + const cachedResult = JSON.parse(cacheVal.data.toString()); + if (cachedResult) { + if (DateTime.local() < DateTime.fromISO(cachedResult.expiry)) { + logger.debug( + { repo, type }, + 'Returning cached github datasource result' + ); + delete cachedResult.expiry; + return cachedResult; + } + // istanbul ignore next + logger.debug('Cache expiry'); + } + } catch (err) { + logger.debug('Cache miss'); + } + return null; +} + +async function setCachedResult(repo, type, res) { + logger.debug({ repo, type }, 'Saving cached github datasource'); + await cacache.put( + datasourceCache, + `${repo}-${type}`, + JSON.stringify({ ...res, expiry: DateTime.local().plus({ minutes: 10 }) }) + ); +} + +async function rmAllCache() { + await cacache.rm.all(datasourceCache); +} + const map = new Map(); async function getPreset(pkgName, presetName = 'default') { @@ -35,6 +79,10 @@ async function getPkgReleases(purl, config) { const { versionScheme } = config || {}; const { fullname: repo, qualifiers: options } = purl; let versions; + const cachedResult = await getCachedResult(repo, options.ref); + if (cachedResult) { + return cachedResult; + } try { if (options.ref === 'release') { const url = `repos/${repo}/releases?per_page=100`; @@ -69,5 +117,6 @@ async function getPkgReleases(purl, config) { version: options.sanitize === 'true' ? isVersion(version) : version, gitRef: version, })); + setCachedResult(repo, options.ref, dependency); return dependency; } diff --git a/test/datasource/__snapshots__/github.spec.js.snap b/test/datasource/__snapshots__/github.spec.js.snap index f3591d40bf..7520f91335 100644 --- a/test/datasource/__snapshots__/github.spec.js.snap +++ b/test/datasource/__snapshots__/github.spec.js.snap @@ -31,3 +31,19 @@ Object { "repositoryUrl": "https://github.com/some/dep", } `; + +exports[`datasource/github getPkgReleases returns releases from cache 1`] = ` +Object { + "releases": Array [ + Object { + "gitRef": "1.0.0", + "version": "1.0.0", + }, + Object { + "gitRef": "v1.1.0", + "version": "v1.1.0", + }, + ], + "repositoryUrl": "https://github.com/some/dep", +} +`; diff --git a/test/datasource/github.spec.js b/test/datasource/github.spec.js index 86d35bfc6a..597d26bd4e 100644 --- a/test/datasource/github.spec.js +++ b/test/datasource/github.spec.js @@ -1,3 +1,5 @@ +const delay = require('delay'); + const datasource = require('../../lib/datasource'); const github = require('../../lib/datasource/github'); const ghGot = require('../../lib/platform/github/gh-got-wrapper'); @@ -37,6 +39,7 @@ describe('datasource/github', () => { }); }); describe('getPkgReleases', () => { + beforeAll(() => github.rmAllCache()); it('returns cleaned tags', async () => { const body = [ { name: 'a' }, @@ -71,6 +74,17 @@ describe('datasource/github', () => { res.releases.find(release => release.version === 'v1.1.0') ).toBeDefined(); }); + it('returns releases from cache', async () => { + await delay(1000); + const res = await datasource.getPkgReleases( + 'pkg:github/some/dep?ref=release' + ); + expect(res).toMatchSnapshot(); + expect(res.releases).toHaveLength(2); + expect( + res.releases.find(release => release.version === 'v1.1.0') + ).toBeDefined(); + }); it('returns null for invalid ref', async () => { expect( await datasource.getPkgReleases('pkg:github/some/dep?ref=invalid') -- GitLab