diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 95d89a37..ec4c9e6e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,7 +7,7 @@ jobs: - uses: actions/checkout@v1 - uses: actions/setup-node@v1 with: - node-version: '10.x' + node-version: '12.x' - run: npm ci - run: npm test env: diff --git a/README.md b/README.md index 070b4183..f5703d4c 100644 --- a/README.md +++ b/README.md @@ -43,6 +43,7 @@ Type must be one of: - `java` - `go` - `pub` +- `cran` - `ping` Response: diff --git a/functional.spec.js b/functional.spec.js index 80b75a42..ab748451 100644 --- a/functional.spec.js +++ b/functional.spec.js @@ -124,4 +124,19 @@ describe('functional', () => { 'path', 'https://github.com/dart-lang/path', ); + testBulk( + 'cran', + 'fracdiff', + 'https://github.com/mmaechler/fracdiff', + ); + testBulk( + 'cran', + 'usethis', + 'https://github.com/r-lib/usethis', + ); + testBulk( + 'cran', + 'boot', + 'https://github.com/cran/boot', + ); }); diff --git a/src/handler.js b/src/handler.js index 66b7c37c..ceac7f5e 100644 --- a/src/handler.js +++ b/src/handler.js @@ -68,7 +68,7 @@ module.exports = async (req, res) => { await cache.auth(); const timingCacheAuth = Date.now() - timingCacheAuthStart; - let result; + let result = []; let timingTotalEnd; let completed = false; const payload = preparePayload(body); diff --git a/src/registries/config.json b/src/registries/config.json index 5c3e0dba..4ca83e90 100644 --- a/src/registries/config.json +++ b/src/registries/config.json @@ -22,6 +22,13 @@ "/project_uri" ] }, + "cran": { + "registry": "https://crandb.r-pkg.org/%s", + "fallback": "https://github.com/cran/%s", + "xpaths": [ + "/URL" + ] + }, "npm": { "registry": "https://registry.npmjs.org/%s", "fallback": "https://www.npmjs.com/package/%s", diff --git a/src/registries/index.js b/src/registries/index.js index 4bea6bee..4df657ac 100644 --- a/src/registries/index.js +++ b/src/registries/index.js @@ -7,6 +7,7 @@ const xpathHelper = require('./xpath-helper'); const registryConfig = require('./config.json'); const cache = require('../utils/cache'); const log = require('../utils/log'); +const { prioritiesHost } = require('../utils/url'); async function resolve(type, packageName) { const cacheKey = `${type}_${packageName}`; @@ -47,7 +48,7 @@ async function resolve(type, packageName) { return; } - const urls = xpathHelper(json, config.xpaths); + let urls = xpathHelper(json, config.xpaths); if (type === 'npm') { if (json.repository && json.repository.directory) { @@ -63,6 +64,13 @@ async function resolve(type, packageName) { } } + if (type === 'cran') { + // Some packages export multiple urls seperated by comma. + urls = urls.map((url) => url.split(',').map((str) => str.trim())).flat(); + + urls = prioritiesHost('https://github.com', urls); + } + const validUrls = urls.map((bestMatchUrl) => { try { let url = repositoryUrl(bestMatchUrl); diff --git a/src/utils/url.js b/src/utils/url.js new file mode 100644 index 00000000..21b600f6 --- /dev/null +++ b/src/utils/url.js @@ -0,0 +1,15 @@ +function prioritiesHost(host, urls = []) { + let insertIndex = 0; + return urls.reduce((memo, url) => { + if (url.includes(host)) { + memo.splice(insertIndex++, 0, url); // eslint-disable-line no-plusplus + } else { + memo.push(url); + } + return memo; + }, []); +} + +module.exports = { + prioritiesHost, +}; diff --git a/src/utils/url.spec.js b/src/utils/url.spec.js new file mode 100644 index 00000000..63ef125b --- /dev/null +++ b/src/utils/url.spec.js @@ -0,0 +1,39 @@ +const { prioritiesHost } = require('./url.js'); + +const inputUrls = [ + 'https://foo.com', + 'https://github.com/foo', + 'https://bar.com', + 'https://github.com/bar', +]; + +describe('url', () => { + describe('prioritiesHost', () => { + it('priorities github.com', () => { + expect(prioritiesHost('github.com', inputUrls)).toStrictEqual([ + 'https://github.com/foo', + 'https://github.com/bar', + 'https://foo.com', + 'https://bar.com', + ]); + }); + + it('priorities foo.com', () => { + expect(prioritiesHost('foo.com', inputUrls)).toStrictEqual([ + 'https://foo.com', + 'https://github.com/foo', + 'https://bar.com', + 'https://github.com/bar', + ]); + }); + + it('priorities bar.com', () => { + expect(prioritiesHost('bar.com', inputUrls)).toStrictEqual([ + 'https://bar.com', + 'https://foo.com', + 'https://github.com/foo', + 'https://github.com/bar', + ]); + }); + }); +});