From 56065a782da09b42f75345ef21b09ebb934ec6fd Mon Sep 17 00:00:00 2001 From: sparshithNR Date: Mon, 1 Feb 2021 09:40:26 -0800 Subject: [PATCH 1/8] Support url based evaluation --- lib/help.js | 1 + lib/read-from-url.js | 61 +++++++++++++++++++++++++++++++ tests/raw-file-server.js | 71 +++++++++++++++++++++++++++++++++++++ tests/read-from-url-test.js | 29 +++++++++++++++ 4 files changed, 162 insertions(+) create mode 100644 lib/read-from-url.js create mode 100644 tests/raw-file-server.js create mode 100644 tests/read-from-url-test.js diff --git a/lib/help.js b/lib/help.js index 2f96676..1a099f8 100644 --- a/lib/help.js +++ b/lib/help.js @@ -20,5 +20,6 @@ module.exports = (commandName = 'supported', packageLink = pkg.homepage) => { {cyan --current-date, -c} optional current date to use when calculating support {bold Examples} {gray $} {cyan ${commandName} ./path/to/project/} + {gray $} {cyan ${commandName} https://github.com/stefanpenner/supported} `; }; diff --git a/lib/read-from-url.js b/lib/read-from-url.js new file mode 100644 index 0000000..5c52dec --- /dev/null +++ b/lib/read-from-url.js @@ -0,0 +1,61 @@ +'use strict'; +const tmp = require('tmp'); +const fetch = require('minipass-fetch'); +const fs = require('fs'); +const debug = require('debug')('supported:read-from-url'); + +const RAW_CONTENT_HOST = 'raw.githubusercontent.com'; + +async function setupProjectPath(_url, rawFileHost) { + let tempDir = tmp.dirSync(); + + let url = new URL(_url); + url.host = rawFileHost || RAW_CONTENT_HOST; + if(url.pathname.indexOf('tree') == -1) { + url.pathname += "/master/package.json" + } + + debug(`packageJSON url: ${url.toString()}`); + const packageJSON = await fetch(url.toString()).then(async request => { + if (request.status === 200) { + return request.json(); + } else if (request.status === 404) { + const { error } = await request.json(); + const e = new Error( + `[${error.code}][http.status=${request.status}] url:${url} ${error.summary}\n${error.details}`, + ); + e.code = error.code; + throw e; + } else { + throw new Error(`[http.status=${request.status}] url:${url}`); + } + }); + + url.pathname = url.pathname.replace('package.json', 'yarn.lock'); + const yarnLock = await fetch(url.toString()).then(async request => { + if (request.status === 200) { + return request.text(); + } else if (request.status === 404) { + const { error } = await request.json(); + const e = new Error( + `[${error.code}][http.status=${request.status}] url:${url} ${error.summary}\n${error.details}`, + ); + e.code = error.code; + throw e; + } else { + throw new Error(`[http.status=${request.status}] url:${url}`); + } + }); + + let projectPath = `${tempDir.name}/${packageJSON.name}`; + fs.mkdirSync(projectPath); + fs.writeFileSync(`${projectPath}/package.json`, JSON.stringify(packageJSON), 'UTF-8'); + fs.writeFileSync(`${projectPath}/yarn.lock`, yarnLock, 'UTF-8'); + + debug(`Project path set to: ${projectPath}`); + return projectPath; +} + +module.exports = { + setupProjectPath +} \ No newline at end of file diff --git a/tests/raw-file-server.js b/tests/raw-file-server.js new file mode 100644 index 0000000..ab6aa15 --- /dev/null +++ b/tests/raw-file-server.js @@ -0,0 +1,71 @@ +'use strict'; + +const Koa = require('koa'); +const fs = require('fs'); +const resolve = require('resolve-path'); + +function server(projectPath, port) { + const app = new Koa(); + + app.use(async (ctx, next) => { + if (ctx.method === 'GET') { + let urlSplit = ctx.url.split('/'); + const file = resolve(projectPath, urlSplit[urlSplit.length - 1]); + if (fs.existsSync(file)) { + ctx.body = fs.readFileSync(file, 'UTF8'); + } else { + ctx.throw( + 404, + JSON.stringify({ + error: { + code: 'E404', + summary: '', + details: 'File not found', + }, + }), + ); + } + } else { + next(); + } + }); + + return app.listen(port); +} + +{ + const root = `${__dirname}/fixtures`; + let fileServer = null; + const FILE_SERVER_PORT_1 = 3002; + const FILE_SERVER_PORT_2 = 3003; + + function startAll() { + if (fileServer !== null) { + throw new Error('already started'); + } + fileServer = Object.create(null); + + fileServer.supported = server(`${root}/supported-project`, FILE_SERVER_PORT_1); + + fileServer.fileNotFound = server(`${root}/not-found-project`, FILE_SERVER_PORT_2); + }; + + function stopAll() { + if (fileServer == null) { + throw new Error('not yet started'); + } + + for (const listener of Object.values(fileServer)) { + listener.close(); + } + fileServer = null; + }; + + module.exports = { + startAll, + stopAll, + FILE_SERVER_PORT_1, + FILE_SERVER_PORT_2, + server + } +} \ No newline at end of file diff --git a/tests/read-from-url-test.js b/tests/read-from-url-test.js new file mode 100644 index 0000000..61bad43 --- /dev/null +++ b/tests/read-from-url-test.js @@ -0,0 +1,29 @@ +'use strict'; + +const { expect } = require('chai'); +const fs = require('fs'); +const { setupProjectPath } = require('../lib/read-from-url'); +const fileServer = require('./raw-file-server'); + +describe('read file from URL', function () { + beforeEach(function () { + fileServer.startAll() + }); + + afterEach(function () { + fileServer.stopAll(); + }); + + it('package.json and yarn.lock is created', async function () { + let projectPath = await setupProjectPath(`http://github.com:${fileServer.FILE_SERVER_PORT_1}/supported-project`, 'localhost'); + expect(fs.existsSync(projectPath + '/package.json')).to.be.true; + expect(fs.existsSync(projectPath + '/yarn.lock')).to.be.true; + }); + it('package.json and yarn.lock is created', async function () { + try { + let projectPath = await setupProjectPath(`http://github.com:${fileServer.FILE_SERVER_PORT_2}/supported-projects`, 'localhost'); + } catch (e) { + expect(e.code).to.eq('E404'); + } + }); +}); \ No newline at end of file From 4243670f49f3ce0dd6339b8a71234da2edef2786 Mon Sep 17 00:00:00 2001 From: sparshithNR Date: Mon, 1 Feb 2021 10:19:50 -0800 Subject: [PATCH 2/8] Fix the lint errors and adding missing files --- lib/read-from-url.js | 8 ++++---- package.json | 2 +- tests/raw-file-server.js | 10 +++++----- tests/read-from-url-test.js | 17 ++++++++++++----- yarn.lock | 14 +++++++++++++- 5 files changed, 35 insertions(+), 16 deletions(-) diff --git a/lib/read-from-url.js b/lib/read-from-url.js index 5c52dec..7f1d74b 100644 --- a/lib/read-from-url.js +++ b/lib/read-from-url.js @@ -11,8 +11,8 @@ async function setupProjectPath(_url, rawFileHost) { let url = new URL(_url); url.host = rawFileHost || RAW_CONTENT_HOST; - if(url.pathname.indexOf('tree') == -1) { - url.pathname += "/master/package.json" + if (url.pathname.indexOf('tree') == -1) { + url.pathname += '/master/package.json'; } debug(`packageJSON url: ${url.toString()}`); @@ -57,5 +57,5 @@ async function setupProjectPath(_url, rawFileHost) { } module.exports = { - setupProjectPath -} \ No newline at end of file + setupProjectPath, +}; diff --git a/package.json b/package.json index 0b0dca6..cd445fb 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "npm": "7.11.2" }, "engines": { - "node": "10.* || 12.* || 14.* || >= 15" + "node": ">=12.9.* || 14.* || >= 15" }, "devDependencies": { "chai": "^4.2.0", diff --git a/tests/raw-file-server.js b/tests/raw-file-server.js index ab6aa15..99b4f3e 100644 --- a/tests/raw-file-server.js +++ b/tests/raw-file-server.js @@ -39,7 +39,7 @@ function server(projectPath, port) { const FILE_SERVER_PORT_1 = 3002; const FILE_SERVER_PORT_2 = 3003; - function startAll() { + let startAll = function () { if (fileServer !== null) { throw new Error('already started'); } @@ -50,7 +50,7 @@ function server(projectPath, port) { fileServer.fileNotFound = server(`${root}/not-found-project`, FILE_SERVER_PORT_2); }; - function stopAll() { + let stopAll = function () { if (fileServer == null) { throw new Error('not yet started'); } @@ -66,6 +66,6 @@ function server(projectPath, port) { stopAll, FILE_SERVER_PORT_1, FILE_SERVER_PORT_2, - server - } -} \ No newline at end of file + server, + }; +} diff --git a/tests/read-from-url-test.js b/tests/read-from-url-test.js index 61bad43..1d7e74d 100644 --- a/tests/read-from-url-test.js +++ b/tests/read-from-url-test.js @@ -7,7 +7,7 @@ const fileServer = require('./raw-file-server'); describe('read file from URL', function () { beforeEach(function () { - fileServer.startAll() + fileServer.startAll(); }); afterEach(function () { @@ -15,15 +15,22 @@ describe('read file from URL', function () { }); it('package.json and yarn.lock is created', async function () { - let projectPath = await setupProjectPath(`http://github.com:${fileServer.FILE_SERVER_PORT_1}/supported-project`, 'localhost'); + let projectPath = await setupProjectPath( + `http://github.com:${fileServer.FILE_SERVER_PORT_1}/supported-project`, + 'localhost', + ); expect(fs.existsSync(projectPath + '/package.json')).to.be.true; expect(fs.existsSync(projectPath + '/yarn.lock')).to.be.true; }); - it('package.json and yarn.lock is created', async function () { + + it('throws file not found error', async function () { try { - let projectPath = await setupProjectPath(`http://github.com:${fileServer.FILE_SERVER_PORT_2}/supported-projects`, 'localhost'); + await setupProjectPath( + `http://github.com:${fileServer.FILE_SERVER_PORT_2}/supported-projects`, + 'localhost', + ); } catch (e) { expect(e.code).to.eq('E404'); } }); -}); \ No newline at end of file +}); diff --git a/yarn.lock b/yarn.lock index b776274..5569d3a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2342,7 +2342,7 @@ retry@^0.12.0: resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= -rimraf@^3.0.2: +rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== @@ -2660,6 +2660,13 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= +tmp@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" + to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -2763,6 +2770,11 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== +valid-url@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/valid-url/-/valid-url-1.0.9.tgz#1c14479b40f1397a75782f115e4086447433a200" + integrity sha1-HBRHm0DxOXp1eC8RXkCGRHQzogA= + validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" From 86e1ec497ae31eb23db67d1acd21590538ba2f72 Mon Sep 17 00:00:00 2001 From: sparshithNR Date: Mon, 1 Feb 2021 10:49:13 -0800 Subject: [PATCH 3/8] Fixing allSettled --- package.json | 3 +- yarn.lock | 108 +++++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 89 insertions(+), 22 deletions(-) diff --git a/package.json b/package.json index cd445fb..e5811c7 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "npm": "7.11.2" }, "engines": { - "node": ">=12.9.* || 14.* || >= 15" + "node": "10.* || 12.* || 14.* || >= 15" }, "devDependencies": { "chai": "^4.2.0", @@ -63,7 +63,6 @@ "parse-duration": "^1.0.0", "parse-package-name": "^0.1.0", "promise.allsettled": "^1.0.4", - "resolve-path": "^1.4.0", "semver": "^7.3.4", "strip-ansi": "^6.0.0", "terminal-link": "^2.1.1" diff --git a/yarn.lock b/yarn.lock index 5569d3a..971928c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -201,11 +201,6 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - array.prototype.map@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/array.prototype.map/-/array.prototype.map-1.0.3.tgz#1609623618d3d84134a37d4a220030c2bd18420b" @@ -328,6 +323,14 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" +call-bind@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" + integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== + dependencies: + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -719,6 +722,45 @@ es-get-iterator@^1.0.2: is-string "^1.0.5" isarray "^2.0.5" +es-abstract@^1.18.0-next.2: + version "1.18.0-next.2" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.2.tgz#088101a55f0541f595e7e057199e27ddc8f3a5c2" + integrity sha512-Ih4ZMFHEtZupnUh6497zEL4y2+w8+1ljnCyaTa+adcoafI1GOvMwFlDjBLfWR7y9VLfrjRJe9ocuHY1PSR9jjw== + dependencies: + call-bind "^1.0.2" + es-to-primitive "^1.2.1" + function-bind "^1.1.1" + get-intrinsic "^1.0.2" + has "^1.0.3" + has-symbols "^1.0.1" + is-callable "^1.2.2" + is-negative-zero "^2.0.1" + is-regex "^1.1.1" + object-inspect "^1.9.0" + object-keys "^1.1.1" + object.assign "^4.1.2" + string.prototype.trimend "^1.0.3" + string.prototype.trimstart "^1.0.3" + +es-array-method-boxes-properly@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" + integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== + +es-get-iterator@^1.0.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.2.tgz#9234c54aba713486d7ebde0220864af5e2b283f7" + integrity sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.1.0" + has-symbols "^1.0.1" + is-arguments "^1.1.0" + is-map "^2.0.2" + is-set "^2.0.2" + is-string "^1.0.5" + isarray "^2.0.5" + es-to-primitive@^1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" @@ -1048,6 +1090,15 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: has "^1.0.3" has-symbols "^1.0.1" +get-intrinsic@^1.0.2, get-intrinsic@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.0.tgz#892e62931e6938c8a23ea5aaebcfb67bd97da97e" + integrity sha512-M11rgtQp5GZMZzDL7jLTNxbDfurpzuau5uqRWDPvlHjfvg3TdScAZo96GLvhMjImrmR8uAt0FS2RLoMrfWGKlg== + dependencies: + function-bind "^1.1.1" + has "^1.0.3" + has-symbols "^1.0.1" + get-stdin@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b" @@ -1380,16 +1431,16 @@ is-map@^2.0.2: resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== +is-negative-zero@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.0.tgz#9553b121b0fac28869da9ed459e20c7543788461" + integrity sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE= + is-negative-zero@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== -is-number-object@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" - integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== - is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -1428,7 +1479,7 @@ is-string@^1.0.5: resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== -is-symbol@^1.0.2, is-symbol@^1.0.3: +is-symbol@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== @@ -1953,12 +2004,17 @@ object-inspect@^1.9.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a" integrity sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw== +object-inspect@^1.9.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a" + integrity sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw== + object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object.assign@^4.1.2: +object.assign@^4.1.1, object.assign@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== @@ -2219,6 +2275,18 @@ promise.allsettled@^1.0.4: get-intrinsic "^1.0.2" iterate-value "^1.0.2" +promise.allsettled@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/promise.allsettled/-/promise.allsettled-1.0.4.tgz#65e71f2a604082ed69c548b68603294090ee6803" + integrity sha512-o73CbvQh/OnPFShxHcHxk0baXR2a1m4ozb85ha0H14VEoi/EJJLa9mnPfEWJx9RjA9MLfhdjZ8I6HhWtBa64Ag== + dependencies: + array.prototype.map "^1.0.3" + call-bind "^1.0.2" + define-properties "^1.1.3" + es-abstract "^1.18.0-next.2" + get-intrinsic "^1.0.2" + iterate-value "^1.0.2" + punycode@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" @@ -2537,18 +2605,18 @@ string.prototype.padend@^3.0.0: define-properties "^1.1.3" es-abstract "^1.18.0-next.2" -string.prototype.trimend@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" - integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== +string.prototype.trimend@^1.0.1, string.prototype.trimend@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz#a22bd53cca5c7cf44d7c9d5c732118873d6cd18b" + integrity sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" -string.prototype.trimstart@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" - integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== +string.prototype.trimstart@^1.0.1, string.prototype.trimstart@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz#9b4cb590e123bb36564401d59824298de50fd5aa" + integrity sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" From abc947db5eb715a1435880019227b0c58fe6f229 Mon Sep 17 00:00:00 2001 From: sparshithNR Date: Thu, 25 Mar 2021 11:30:04 -0700 Subject: [PATCH 4/8] Support URL as input. Cases covered: 1. Github repo URL 2. Private Github Repo (token needed) 3. Braches in the repo 4. External URL which can return package.json, yarn.lock, npmrc (optional) files Test cases added for each cases All operations done in memory --- README.md | 5 ++ lib/cli.js | 11 ++- lib/help.js | 4 + lib/project/multiple-projects.js | 4 +- lib/project/setup-project.js | 65 ++++++++++++---- lib/read-from-url.js | 104 ++++++++++++++----------- lib/util.js | 58 ++++++++++++++ package.json | 3 +- tests/cli-test.js | 31 +++++++- tests/raw-file-server.js | 71 ----------------- tests/read-from-url-test.js | 43 +++++++---- tests/test-helpers/registries.js | 19 +++-- tests/util-test.js | 64 +++++++++++++++- yarn.lock | 127 +++++++++++-------------------- 14 files changed, 372 insertions(+), 237 deletions(-) delete mode 100644 tests/raw-file-server.js diff --git a/README.md b/README.md index 56604df..0a5420c 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,11 @@ ```sh npx supported npx supported <[array/of/node_modules]> +// Generate token using https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token +npx supported https://github.com/stefanpenner/supported +npx supported https://github.com/stefanpenner/supported/tree/some-branch +npx supported https://test.githubprivate.com/stefanpenner/supported -t $TOKEN +npx supported supported --hostUrl=https://raw.githubusercontent.com/stefanpenner/supported/main/ ``` #### Optional Flags diff --git a/lib/cli.js b/lib/cli.js index e49c006..fce6cc7 100644 --- a/lib/cli.js +++ b/lib/cli.js @@ -9,6 +9,7 @@ const { displayResults } = require('../lib/output/cli-output'); const { processPolicies } = require('../lib/project/multiple-projects'); const { DEFAULT_SUPPORT_MESSAGE } = require('./output/messages'); const { generateCsv } = require('../lib/output/csv-output'); +const { inputHasGithubPrivate } = require('./util'); async function main(cli, { policyDetails, setupProjectFn }) { const projectPaths = handleInput(cli.input, process.cwd()); @@ -22,7 +23,7 @@ async function main(cli, { policyDetails, setupProjectFn }) { let result; let processed = false; try { - result = await processPolicies(projectPaths, setupProjectFn, spinner, currentDate); + result = await processPolicies(projectPaths, setupProjectFn, spinner, currentDate, cli.flags); if (result.isInSupportWindow === false) { process.exitCode = 1; } @@ -87,6 +88,14 @@ async function run( type: 'string', alias: 'c', }, + token: { + type: 'string', + alias: 't', + isRequired: inputHasGithubPrivate, + }, + hostUrl: { + type: 'string', + }, }, }), { policyDetails, setupProjectFn }, diff --git a/lib/help.js b/lib/help.js index 1a099f8..1a6e04b 100644 --- a/lib/help.js +++ b/lib/help.js @@ -18,8 +18,12 @@ module.exports = (commandName = 'supported', packageLink = pkg.homepage) => { {cyan --supported, -s} outputs detailed report of supported packages only {cyan --csv} outputs csv file in the project path {cyan --current-date, -c} optional current date to use when calculating support + {cyan --token, -t} token to access raw file from github private instance + {cyan --hostUrl} URL endpoint that returns package.json, yarn.lock and npmrc files. {bold Examples} {gray $} {cyan ${commandName} ./path/to/project/} {gray $} {cyan ${commandName} https://github.com/stefanpenner/supported} + {gray $} {cyan ${commandName} https://test.githubprivate.com/stefanpenner/supported -t $TOKEN} + {gray $} {cyan ${commandName} supported --hostUrl=https://raw.githubusercontent.com/stefanpenner/supported/main/} `; }; diff --git a/lib/project/multiple-projects.js b/lib/project/multiple-projects.js index adb00e9..433fd5a 100644 --- a/lib/project/multiple-projects.js +++ b/lib/project/multiple-projects.js @@ -10,7 +10,7 @@ const { ProgressLogger } = require('../util'); const DEFAULT_SETUP_FILE = './setup-project'; module.exports.processPolicies = processPolicies; -async function processPolicies(projectPaths, setupProjectFn, spinner, today) { +async function processPolicies(projectPaths, setupProjectFn, spinner, today, flags) { const setupProject = setupProjectFn ? setupProjectFn : require(DEFAULT_SETUP_FILE); let result = { isInSupportWindow: true, @@ -29,7 +29,7 @@ async function processPolicies(projectPaths, setupProjectFn, spinner, today) { for (const projectPath of projectPaths) { work.push( queue.add(async () => { - let { dependenciesToCheck, pkg } = await setupProject(projectPath); + let { dependenciesToCheck, pkg } = await setupProject(projectPath, flags); progressLogger.updateTotalDepCount(dependenciesToCheck.length); let auditResult = await isInSupportWindow( dependenciesToCheck, diff --git a/lib/project/setup-project.js b/lib/project/setup-project.js index 00251d5..c63e996 100644 --- a/lib/project/setup-project.js +++ b/lib/project/setup-project.js @@ -3,32 +3,65 @@ const semverCoerce = require('semver/functions/coerce'); const YarnLockfile = require('@yarnpkg/lockfile'); const npa = require('npm-package-arg'); +const ini = require('ini'); const fs = require('fs'); const path = require('path'); const debug = require('debug')('supported:project'); +const { setupProjectPath } = require('../read-from-url'); const npmConfig = require('../npm/config'); -module.exports = async function setupProject(projectRoot) { - const config = await npmConfig(projectRoot); // kinda slow, TODO: re-implement as standalone lib - // const { policies } = options; - const pkgPath = `${projectRoot}/package.json`; - if (!fs.existsSync(pkgPath)) { - throw new Error(`${pkgPath} does not exist, are you sure this is a valid package?`); - } - if (!fs.statSync(pkgPath).isFile()) { - throw new Error(`${pkgPath} is not a file, are you sure this is a valid package?`); +module.exports = async function setupProject(projectRoot, flags = {}) { + let projectInfo = {}; + if (!fs.existsSync(projectRoot)) { + projectInfo = await setupProjectPath(projectRoot, { + token: flags.token, + hostUrl: flags.hostUrl, + }); + // if project root is a URL then use homedir as root + projectRoot = require('os').homedir(); } - const file = fs.readFileSync(pkgPath, 'utf-8'); - let pkg; - try { - pkg = JSON.parse(file); - } catch (e) { - throw new Error(`${pkgPath} is not a valid JSON file, are you sure this is a valid package?`); + + let config = await npmConfig(projectRoot); // kinda slow, TODO: re-implement as standalone lib + let pkg = {}; + let lockfileContent = ''; + if (projectInfo.packageJSON) { + pkg = projectInfo.packageJSON; + lockfileContent = projectInfo['yarn.lock']; + if (projectInfo['.npmrc']) { + try { + let localConfig = ini.parse(projectInfo['.npmrc']); + config = { + config, + ...localConfig, + }; + } catch (e) { + throw new Error( + `Couldn't parse the npmrc file, are you sure project URL has a valid npmrc?`, + ); + } + } + } else { + const pkgPath = `${projectRoot}/package.json`; + if (!fs.existsSync(pkgPath)) { + throw new Error(`${pkgPath} does not exist, are you sure this is a valid package?`); + } + if (!fs.statSync(pkgPath).isFile()) { + throw new Error(`${pkgPath} is not a file, are you sure this is a valid package?`); + } + const file = fs.readFileSync(pkgPath, 'utf-8'); + try { + pkg = JSON.parse(file); + } catch (e) { + throw new Error(`${pkgPath} is not a valid JSON file, are you sure this is a valid package?`); + } + const lockfilePath = path.join(projectRoot, 'yarn.lock'); + lockfileContent = fs.readFileSync(lockfilePath, 'utf-8'); } + // const { policies } = options; const lockfilePath = path.join(projectRoot, 'yarn.lock'); // TODO: npm support - const { object: lockfile } = YarnLockfile.parse(fs.readFileSync(lockfilePath, 'utf-8')); + const { object: lockfile } = YarnLockfile.parse(lockfileContent); const dependenciesToCheck = []; if (pkg.dependencies) { diff --git a/lib/read-from-url.js b/lib/read-from-url.js index 7f1d74b..deaea29 100644 --- a/lib/read-from-url.js +++ b/lib/read-from-url.js @@ -1,59 +1,75 @@ 'use strict'; -const tmp = require('tmp'); const fetch = require('minipass-fetch'); -const fs = require('fs'); const debug = require('debug')('supported:read-from-url'); +const { default: PQueue } = require('p-queue'); +const allSettled = require('promise.allsettled'); +const os = require('os'); +const { getFetchUrl } = require('./util'); -const RAW_CONTENT_HOST = 'raw.githubusercontent.com'; +async function setupProjectPath(_url, options = {}) { + let url = getFetchUrl(_url, options); -async function setupProjectPath(_url, rawFileHost) { - let tempDir = tmp.dirSync(); - - let url = new URL(_url); - url.host = rawFileHost || RAW_CONTENT_HOST; - if (url.pathname.indexOf('tree') == -1) { - url.pathname += '/master/package.json'; + const work = []; + const queue = new PQueue({ + concurrency: os.cpus().length, + }); + let result = {}; + let packageJSON; + // check if the code moved to main or still using master + // https://github.com/SparshithNR/doc-tester/blob/master/package.json + // https://github.com/stefanpenner/supported/blob/main/package.json + try { + packageJSON = await runFetch(url + 'package.json', true); + } catch (e) { + if (e.code === 404) { + url = url.replace('main', 'master'); + packageJSON = await runFetch(url + 'package.json', true); + } else { + throw e; + } + } + for (const fileName of ['yarn.lock', '.npmrc']) { + work.push( + queue.add(async () => { + const requestURL = url + fileName; + result[fileName] = await runFetch(requestURL); + }), + ); + } + await queue.onIdle(); + for (const settled of await allSettled(work)) { + if (settled.status === 'rejected') { + throw settled.reason; + } } debug(`packageJSON url: ${url.toString()}`); - const packageJSON = await fetch(url.toString()).then(async request => { - if (request.status === 200) { - return request.json(); - } else if (request.status === 404) { - const { error } = await request.json(); - const e = new Error( - `[${error.code}][http.status=${request.status}] url:${url} ${error.summary}\n${error.details}`, - ); - e.code = error.code; - throw e; - } else { - throw new Error(`[http.status=${request.status}] url:${url}`); - } - }); - url.pathname = url.pathname.replace('package.json', 'yarn.lock'); - const yarnLock = await fetch(url.toString()).then(async request => { - if (request.status === 200) { - return request.text(); - } else if (request.status === 404) { - const { error } = await request.json(); - const e = new Error( - `[${error.code}][http.status=${request.status}] url:${url} ${error.summary}\n${error.details}`, - ); - e.code = error.code; + return { + packageJSON, + ...result, + }; +} + +async function runFetch(requestURL, isJson) { + let response = await fetch(requestURL); + if (response.status === 200) { + if (isJson) { + return response.json(); + } + return response.text(); + } else if (response.status === 404) { + if (!requestURL.includes('.npmrc')) { + const text = await response.buffer(); + const e = new Error(`[http.status=${response.status}] url:${requestURL} : error: ${text}`); + e.code = response.status; throw e; } else { - throw new Error(`[http.status=${request.status}] url:${url}`); + debug(`Fetch failed for .npmrc , ${await response.buffer()}`); } - }); - - let projectPath = `${tempDir.name}/${packageJSON.name}`; - fs.mkdirSync(projectPath); - fs.writeFileSync(`${projectPath}/package.json`, JSON.stringify(packageJSON), 'UTF-8'); - fs.writeFileSync(`${projectPath}/yarn.lock`, yarnLock, 'UTF-8'); - - debug(`Project path set to: ${projectPath}`); - return projectPath; + } else { + throw new Error(`[http.status=${response.status}] url:${requestURL}`); + } } module.exports = { diff --git a/lib/util.js b/lib/util.js index 460292d..fc483f0 100644 --- a/lib/util.js +++ b/lib/util.js @@ -14,6 +14,12 @@ exports.MS_IN_QTR = MS_IN_QTR; // expiring soon if the package expires within 4 qtrs const THRESHOLD_QTRS = 5; +// github url constants +const RAW_CONTENT_HOST = 'raw.githubusercontent.com'; +const GITHUB_PRIVATE = 'githubprivate'; +const GITHUB = 'github.com'; +const MISSING_TOKEN = chalk`{red Private instances of github needs token. To generate token follow https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token}`; + /** * * @param {int} timeDiff duration between latest version and resolved version release date @@ -232,3 +238,55 @@ module.exports.handleInput = function (input, cwd) { return input; } }; + +/** + * Generates the fetch URL to get package.json and other required files. + */ +module.exports.getFetchUrl = function(_url, options = {}) { + let { token, hostUrl } = options; + _url = hostUrl || _url; + _url += _url.endsWith('/') ? '' : '/'; + if (hostUrl) { + return _url; + } + let url = new URL(_url); + let branch = url.pathname.indexOf('/tree/'); + let hostname = url.hostname; + let pathname = url.pathname; + if (hostname.includes(GITHUB)) { + hostname = RAW_CONTENT_HOST; + if (branch == -1) { + pathname += 'main/'; + } + } else if (hostname.includes(GITHUB_PRIVATE)) { + if (!token) { + throw new Error(MISSING_TOKEN); + } + hostname = `${token}@raw.${hostname}`; + if (branch == -1) { + pathname += 'master/'; + } + } + if (branch !== -1) { + pathname = pathname.replace('/tree/', '/'); + } + let currentURL = url.toString(); + currentURL = currentURL.replace(url.hostname, hostname); + currentURL = currentURL.replace(url.pathname, pathname); + currentURL += currentURL.endsWith('/') ? '' : '/'; + return currentURL; +} + +/** + * Returns true if the given list of input has private instance, and token is provided. + */ +module.exports.inputHasGithubPrivate = function(flags, input) { + input = Array.isArray(input) ? input : [input]; + let isPrivate = input.some(inputUrl => { + return inputUrl.includes(GITHUB_PRIVATE); + }); + if (isPrivate && !flags.token) { + console.log(MISSING_TOKEN); + } + return isPrivate; +} diff --git a/package.json b/package.json index e5811c7..af66a21 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "cli-table": "^0.3.4", "debug": "^4.3.1", "execa": "^5.0.0", - "ini": "^1.3.7", + "ini": "^2.0.0", "json2csv": "^5.0.6", "koa": "^2.13.0", "meow": "^8.0.0", @@ -63,6 +63,7 @@ "parse-duration": "^1.0.0", "parse-package-name": "^0.1.0", "promise.allsettled": "^1.0.4", + "resolve-path": "^1.4.0", "semver": "^7.3.4", "strip-ansi": "^6.0.0", "terminal-link": "^2.1.1" diff --git a/tests/cli-test.js b/tests/cli-test.js index ef35441..7887fdd 100644 --- a/tests/cli-test.js +++ b/tests/cli-test.js @@ -36,8 +36,15 @@ describe('CLI', function () { // Test in windows are failing // Issue may be caused by npmconfig command we have in the code base. For now we are increasing the timeout. this.timeout(4000); + let FILE_SERVER_PORT_1 = 3005; beforeEach(function () { - registries.startAll(); + registries.startAll([ + { + name: 'supported-project', + recordingRoot: `./tests/fixtures/supported-project`, + port: FILE_SERVER_PORT_1, + }, + ]); }); afterEach(function () { @@ -133,6 +140,28 @@ describe('CLI', function () { expect(child.stdout).to.includes('✗ unsupported-project'); expect(child.stdout).to.includes('✓ supported-project'); }); + + it('works against a fully supported project with hosturl', async function () { + const child = await runSupportedCmd([ + `supported-project`, + '--hostUrl', + `http://localhost:${FILE_SERVER_PORT_1}/`, + ]); + expect(child.exitCode).to.eql(0); + expect(child.stderr).to.includes('✓ SemVer Policy'); + expect(child.stdout).to.includes('Congrats!'); + }); + + it('error out when token not passed for github private instance', async function () { + const child = await runSupportedCmd([ + `https://test.githubprivate.com/stefanpenner/supported`, + ]); + expect(child.exitCode).to.eql(2); + expect(child.stderr).to.includes('Missing required flag\n\t--token, -t'); + expect(child.stdout).to.includes( + `Private instances of github needs token. To generate token follow https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token`, + ); + }); }); describe('--verbose', function () { diff --git a/tests/raw-file-server.js b/tests/raw-file-server.js deleted file mode 100644 index 99b4f3e..0000000 --- a/tests/raw-file-server.js +++ /dev/null @@ -1,71 +0,0 @@ -'use strict'; - -const Koa = require('koa'); -const fs = require('fs'); -const resolve = require('resolve-path'); - -function server(projectPath, port) { - const app = new Koa(); - - app.use(async (ctx, next) => { - if (ctx.method === 'GET') { - let urlSplit = ctx.url.split('/'); - const file = resolve(projectPath, urlSplit[urlSplit.length - 1]); - if (fs.existsSync(file)) { - ctx.body = fs.readFileSync(file, 'UTF8'); - } else { - ctx.throw( - 404, - JSON.stringify({ - error: { - code: 'E404', - summary: '', - details: 'File not found', - }, - }), - ); - } - } else { - next(); - } - }); - - return app.listen(port); -} - -{ - const root = `${__dirname}/fixtures`; - let fileServer = null; - const FILE_SERVER_PORT_1 = 3002; - const FILE_SERVER_PORT_2 = 3003; - - let startAll = function () { - if (fileServer !== null) { - throw new Error('already started'); - } - fileServer = Object.create(null); - - fileServer.supported = server(`${root}/supported-project`, FILE_SERVER_PORT_1); - - fileServer.fileNotFound = server(`${root}/not-found-project`, FILE_SERVER_PORT_2); - }; - - let stopAll = function () { - if (fileServer == null) { - throw new Error('not yet started'); - } - - for (const listener of Object.values(fileServer)) { - listener.close(); - } - fileServer = null; - }; - - module.exports = { - startAll, - stopAll, - FILE_SERVER_PORT_1, - FILE_SERVER_PORT_2, - server, - }; -} diff --git a/tests/read-from-url-test.js b/tests/read-from-url-test.js index 1d7e74d..74e3237 100644 --- a/tests/read-from-url-test.js +++ b/tests/read-from-url-test.js @@ -1,36 +1,51 @@ 'use strict'; const { expect } = require('chai'); -const fs = require('fs'); const { setupProjectPath } = require('../lib/read-from-url'); -const fileServer = require('./raw-file-server'); +const fileServer = require('./test-helpers/registries'); describe('read file from URL', function () { + const FILE_SERVER_PORT_1 = 3454; + const FILE_SERVER_PORT_2 = 3455; beforeEach(function () { - fileServer.startAll(); + let root = `./tests/fixtures`; + fileServer.startAll([ + { + name: 'supported-project', + recordingRoot: `${root}/supported-project`, + port: FILE_SERVER_PORT_1, + }, + { + name: 'not-found-project', + recordingRoot: `${root}/not-found-project`, + port: FILE_SERVER_PORT_2, + }, + ]); }); afterEach(function () { fileServer.stopAll(); }); - it('package.json and yarn.lock is created', async function () { - let projectPath = await setupProjectPath( - `http://github.com:${fileServer.FILE_SERVER_PORT_1}/supported-project`, - 'localhost', + it('package.json and yarn.lock and .npmrc is created', async function () { + let projectInfo = await setupProjectPath( + `http://github.com:${FILE_SERVER_PORT_1}/supported-project`, + { + hostUrl: `http://localhost:${FILE_SERVER_PORT_1}`, + }, ); - expect(fs.existsSync(projectPath + '/package.json')).to.be.true; - expect(fs.existsSync(projectPath + '/yarn.lock')).to.be.true; + expect(projectInfo.packageJSON.name).to.equal('supported-project'); + expect(projectInfo['yarn.lock']).to.include('# yarn lockfile v1'); + expect(projectInfo['.npmrc']).to.include('@stefanpenner:registry=http://0.0.0.0:3001'); }); it('throws file not found error', async function () { try { - await setupProjectPath( - `http://github.com:${fileServer.FILE_SERVER_PORT_2}/supported-projects`, - 'localhost', - ); + await setupProjectPath(`http://github.com:${FILE_SERVER_PORT_2}/supported-projects`, { + hostUrl: `http://localhost:${FILE_SERVER_PORT_2}`, + }); } catch (e) { - expect(e.code).to.eq('E404'); + expect(e.code).to.eq(404); } }); }); diff --git a/tests/test-helpers/registries.js b/tests/test-helpers/registries.js index 9556fb5..5e0d8f9 100644 --- a/tests/test-helpers/registries.js +++ b/tests/test-helpers/registries.js @@ -3,6 +3,7 @@ const Koa = require('koa'); const fs = require('fs'); const resolve = require('resolve-path'); +const { extname } = require('path'); const BASE_PORT = 3000; // disable inherited registry (when calling yarn you get this set...) @@ -13,9 +14,16 @@ function server(recordingRoot, port) { app.use(async (ctx, next) => { if (ctx.method === 'GET') { - const moduleName = ctx.url.slice(1); - // use resolve-path to prevent directory traversal - const file = resolve(recordingRoot, `${moduleName}.json`); + let urlSplit = ctx.url.split('/'); + let file = urlSplit[urlSplit.length - 1]; + // check if the request is for a specific file. + if (extname(file) || file === '.npmrc') { + file = resolve(recordingRoot, file); + } else { + const moduleName = ctx.url.slice(1); + // use resolve-path to prevent directory traversal + file = resolve(recordingRoot, `${moduleName}.json`); + } if (fs.existsSync(file)) { ctx.body = fs.readFileSync(file, 'UTF8'); } else { @@ -52,8 +60,9 @@ function server(recordingRoot, port) { // registry for the @stefanpenner scope registries.stefanpenner = server(`${root}/recordings/stefanpenner`, BASE_PORT + 1); // if developers want to add more server while extending - additionalRegistries.forEach(({ name, recordingRoot }, index) => { - registries[name] = server(recordingRoot, BASE_PORT + 2 + index); + additionalRegistries.forEach(({ name, recordingRoot, port }, index) => { + port = port || BASE_PORT + 2 + index; + registries[name] = server(recordingRoot, port); }); }; diff --git a/tests/util-test.js b/tests/util-test.js index 60558e9..925d407 100644 --- a/tests/util-test.js +++ b/tests/util-test.js @@ -2,7 +2,7 @@ const chai = require('chai'); const { expect } = chai; -const { sortLibraries, checkNodeCompatibility, handleInput } = require('../lib/util'); +const { sortLibraries, checkNodeCompatibility, handleInput, getFetchUrl, inputHasGithubPrivate } = require('../lib/util'); chai.use(require('chai-datetime')); @@ -172,4 +172,66 @@ describe('util test', function () { ]); }); }); + describe('getFetchUrl', function () { + it('returns hosturl', function () { + expect(getFetchUrl('test-url.com', { hostUrl: 'localhost:3400' })).to.be.eql( + 'localhost:3400/', + ); + }); + it('returns github content url', function () { + expect(getFetchUrl('https://github.com/stefanpenner/supported')).to.be.eql( + 'https://raw.githubusercontent.com/stefanpenner/supported/main/', + ); + }); + it('returns github content url with given branch', function () { + expect( + getFetchUrl('https://github.com/stefanpenner/supported/tree/error-out-node'), + ).to.be.eql('https://raw.githubusercontent.com/stefanpenner/supported/error-out-node/'); + }); + it('returns github content url private repo', function () { + expect( + getFetchUrl('https://test.githubprivate.com/stefanpenner/supported/', { token: 'a1b2c3' }), + ).to.be.eql('https://a1b2c3@raw.test.githubprivate.com/stefanpenner/supported/master/'); + }); + it('returns github content url private repo with given branch', function () { + expect( + getFetchUrl('https://test.githubprivate.com/stefanpenner/supported/tree/error-out-node', { + token: 'a1b2c3', + }), + ).to.be.eql( + 'https://a1b2c3@raw.test.githubprivate.com/stefanpenner/supported/error-out-node/', + ); + }); + it('errors github content url private repo with no token', function () { + expect(() => { + getFetchUrl('https://test.githubprivate.com/stefanpenner/supported/tree/error-out-node'); + }).throws( + /Private instances of github needs token. To generate token follow https:\/\/docs.github.com\/en\/github\/authenticating-to-github\/creating-a-personal-access-token/, + ); + }); + }); + + describe('inputHasGithubPrivate', function () { + //setting token to true so that console.log won't appear. + it('return true if github private instance present', function () { + expect( + inputHasGithubPrivate( + { token: true }, + 'https://test.githubprivate.com/stefanpenner/supported/', + ), + ).to.be.true; + }); + it('return false if github private instance present', function () { + expect(inputHasGithubPrivate({ token: true }, 'https://test.com/stefanpenner/supported/')).to + .be.false; + }); + it('return true if github private instance present in multiple inputs', function () { + expect( + inputHasGithubPrivate({ token: true }, [ + 'https://test.com/stefanpenner/supported/', + 'https://test.githubprivate.com/stefanpenner/supported/', + ]), + ).to.be.true; + }); + }); }); diff --git a/yarn.lock b/yarn.lock index 971928c..31ecf0b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -201,6 +201,11 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + array.prototype.map@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/array.prototype.map/-/array.prototype.map-1.0.3.tgz#1609623618d3d84134a37d4a220030c2bd18420b" @@ -323,14 +328,6 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" -call-bind@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" - integrity sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA== - dependencies: - function-bind "^1.1.1" - get-intrinsic "^1.0.2" - callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -681,7 +678,7 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" -es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2: +es-abstract@^1.18.0-next.1: version "1.18.0" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0.tgz#ab80b359eecb7ede4c298000390bc5ac3ec7b5a4" integrity sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw== @@ -703,25 +700,6 @@ es-abstract@^1.18.0-next.1, es-abstract@^1.18.0-next.2: string.prototype.trimstart "^1.0.4" unbox-primitive "^1.0.0" -es-array-method-boxes-properly@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" - integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== - -es-get-iterator@^1.0.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.2.tgz#9234c54aba713486d7ebde0220864af5e2b283f7" - integrity sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.0" - has-symbols "^1.0.1" - is-arguments "^1.1.0" - is-map "^2.0.2" - is-set "^2.0.2" - is-string "^1.0.5" - isarray "^2.0.5" - es-abstract@^1.18.0-next.2: version "1.18.0-next.2" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.18.0-next.2.tgz#088101a55f0541f595e7e057199e27ddc8f3a5c2" @@ -1081,19 +1059,19 @@ get-func-name@^2.0.0: resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= -get-intrinsic@^1.0.2, get-intrinsic@^1.1.0, get-intrinsic@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" - integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== +get-intrinsic@^1.0.2, get-intrinsic@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.0.tgz#892e62931e6938c8a23ea5aaebcfb67bd97da97e" + integrity sha512-M11rgtQp5GZMZzDL7jLTNxbDfurpzuau5uqRWDPvlHjfvg3TdScAZo96GLvhMjImrmR8uAt0FS2RLoMrfWGKlg== dependencies: function-bind "^1.1.1" has "^1.0.3" has-symbols "^1.0.1" -get-intrinsic@^1.0.2, get-intrinsic@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.0.tgz#892e62931e6938c8a23ea5aaebcfb67bd97da97e" - integrity sha512-M11rgtQp5GZMZzDL7jLTNxbDfurpzuau5uqRWDPvlHjfvg3TdScAZo96GLvhMjImrmR8uAt0FS2RLoMrfWGKlg== +get-intrinsic@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" + integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== dependencies: function-bind "^1.1.1" has "^1.0.3" @@ -1331,10 +1309,10 @@ inherits@2.0.3: resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -ini@^1.3.7: - version "1.3.8" - resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" - integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== +ini@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" + integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== ip@^1.1.5: version "1.1.5" @@ -1372,7 +1350,7 @@ is-boolean-object@^1.1.0: dependencies: call-bind "^1.0.0" -is-callable@^1.1.4, is-callable@^1.2.3: +is-callable@^1.1.4, is-callable@^1.2.2, is-callable@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.3.tgz#8b1e0500b73a1d76c70487636f368e519de8db8e" integrity sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ== @@ -1431,16 +1409,16 @@ is-map@^2.0.2: resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.2.tgz#00922db8c9bf73e81b7a335827bc2a43f2b91127" integrity sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg== -is-negative-zero@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.0.tgz#9553b121b0fac28869da9ed459e20c7543788461" - integrity sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE= - is-negative-zero@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.1.tgz#3de746c18dda2319241a53675908d8f766f11c24" integrity sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w== +is-number-object@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.4.tgz#36ac95e741cf18b283fc1ddf5e83da798e3ec197" + integrity sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw== + is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -1456,7 +1434,7 @@ is-plain-obj@^2.1.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== -is-regex@^1.1.2: +is-regex@^1.1.1, is-regex@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.2.tgz#81c8ebde4db142f2cf1c53fc86d6a45788266251" integrity sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg== @@ -1479,7 +1457,7 @@ is-string@^1.0.5: resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== -is-symbol@^1.0.2: +is-symbol@^1.0.2, is-symbol@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== @@ -2004,17 +1982,12 @@ object-inspect@^1.9.0: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a" integrity sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw== -object-inspect@^1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.9.0.tgz#c90521d74e1127b67266ded3394ad6116986533a" - integrity sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw== - object-keys@^1.0.12, object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object.assign@^4.1.1, object.assign@^4.1.2: +object.assign@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.2.tgz#0ed54a342eceb37b38ff76eb831a0e788cb63940" integrity sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ== @@ -2275,18 +2248,6 @@ promise.allsettled@^1.0.4: get-intrinsic "^1.0.2" iterate-value "^1.0.2" -promise.allsettled@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/promise.allsettled/-/promise.allsettled-1.0.4.tgz#65e71f2a604082ed69c548b68603294090ee6803" - integrity sha512-o73CbvQh/OnPFShxHcHxk0baXR2a1m4ozb85ha0H14VEoi/EJJLa9mnPfEWJx9RjA9MLfhdjZ8I6HhWtBa64Ag== - dependencies: - array.prototype.map "^1.0.3" - call-bind "^1.0.2" - define-properties "^1.1.3" - es-abstract "^1.18.0-next.2" - get-intrinsic "^1.0.2" - iterate-value "^1.0.2" - punycode@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" @@ -2410,7 +2371,7 @@ retry@^0.12.0: resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= -rimraf@^3.0.0, rimraf@^3.0.2: +rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== @@ -2605,18 +2566,34 @@ string.prototype.padend@^3.0.0: define-properties "^1.1.3" es-abstract "^1.18.0-next.2" -string.prototype.trimend@^1.0.1, string.prototype.trimend@^1.0.3: +string.prototype.trimend@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.3.tgz#a22bd53cca5c7cf44d7c9d5c732118873d6cd18b" integrity sha512-ayH0pB+uf0U28CtjlLvL7NaohvR1amUvVZk+y3DYb0Ey2PUV5zPkkKy9+U1ndVEIXO8hNg18eIv9Jntbii+dKw== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + +string.prototype.trimend@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz#e75ae90c2942c63504686c18b287b4a0b1a45f80" + integrity sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" -string.prototype.trimstart@^1.0.1, string.prototype.trimstart@^1.0.3: +string.prototype.trimstart@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.3.tgz#9b4cb590e123bb36564401d59824298de50fd5aa" integrity sha512-oBIBUy5lea5tt0ovtOFiEQaBkoBBkyJhZXzJYrSmDo5IUUqbOPvVezuRs/agBIdZ2p2Eo1FD6bD9USyBLfl3xg== + dependencies: + call-bind "^1.0.0" + define-properties "^1.1.3" + +string.prototype.trimstart@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz#b36399af4ab2999b4c9c648bd7a3fb2bb26feeed" + integrity sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw== dependencies: call-bind "^1.0.2" define-properties "^1.1.3" @@ -2728,13 +2705,6 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ= -tmp@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.2.1.tgz#8457fc3037dcf4719c251367a1af6500ee1ccf14" - integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== - dependencies: - rimraf "^3.0.0" - to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -2838,11 +2808,6 @@ v8-compile-cache@^2.0.3: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== -valid-url@^1.0.9: - version "1.0.9" - resolved "https://registry.yarnpkg.com/valid-url/-/valid-url-1.0.9.tgz#1c14479b40f1397a75782f115e4086447433a200" - integrity sha1-HBRHm0DxOXp1eC8RXkCGRHQzogA= - validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" From ef09f23d9639f2910614c6a05a996545129a4f7d Mon Sep 17 00:00:00 2001 From: sparshithNR Date: Thu, 25 Mar 2021 11:52:52 -0700 Subject: [PATCH 5/8] Error when URL is not reachable --- lib/read-from-url.js | 10 +++++++++- tests/cli-test.js | 10 ++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/lib/read-from-url.js b/lib/read-from-url.js index deaea29..4232462 100644 --- a/lib/read-from-url.js +++ b/lib/read-from-url.js @@ -5,6 +5,7 @@ const { default: PQueue } = require('p-queue'); const allSettled = require('promise.allsettled'); const os = require('os'); const { getFetchUrl } = require('./util'); +const chalk = require('chalk'); async function setupProjectPath(_url, options = {}) { let url = getFetchUrl(_url, options); @@ -52,7 +53,14 @@ async function setupProjectPath(_url, options = {}) { } async function runFetch(requestURL, isJson) { - let response = await fetch(requestURL); + let response = {}; + try { + response = await fetch(requestURL); + } catch (e) { + let error = new Error(chalk`{red Couldn't reach server, please check the URL provided.} + ${e.message}`); + throw error; + } if (response.status === 200) { if (isJson) { return response.json(); diff --git a/tests/cli-test.js b/tests/cli-test.js index 7887fdd..754c995 100644 --- a/tests/cli-test.js +++ b/tests/cli-test.js @@ -162,6 +162,16 @@ describe('CLI', function () { `Private instances of github needs token. To generate token follow https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token`, ); }); + + it('error out with clear message when url is not reachable', async function () { + const child = await runSupportedCmd([ + `https://test.githubprivate.com/stefanpenner/supported`, + '-t', + 'abac', + ]); + expect(child.exitCode).to.eql(1); + expect(child.stderr).to.includes(`Couldn't reach server, please check the URL provided`); + }); }); describe('--verbose', function () { From 1ae8fe3184dde8d9e64e59de0f901abfa1d3771a Mon Sep 17 00:00:00 2001 From: sparshithNR Date: Mon, 17 May 2021 12:52:10 -0700 Subject: [PATCH 6/8] Addressing review comments. --- README.md | 18 +++++++++++++++++- lib/project/setup-project.js | 2 +- lib/read-from-url.js | 4 ++-- 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 0a5420c..5265de9 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,9 @@ npx supported https://test.githubprivate.com/stefanpenner/supported -t $TOKEN npx supported supported --hostUrl=https://raw.githubusercontent.com/stefanpenner/supported/main/ ``` -#### Optional Flags +### Optional Flags +#### current date The `--current-date` (`-c`) flag enables a form of limited time travel, and attempts to run the tools internal date calculations based on a specified date, rather then the current date. @@ -31,6 +32,21 @@ Anything that `new Date(input)` parses, or if that fails it will assume to be a relative duration starting today parsed by [parse-duration@^1.0.0's own micro-syntax](https://github.com/jkroso/parse-duration#available-unit-types-are). +#### hostURL +The `--hostURL` flag enables a way to provide a valid URL which will return package.json, lock file and npmrc file if exists. +some examples: + +* `--hostUrl=https://raw.githubusercontent.com/stefanpenner/supported/main/`, gets the above listed file from the provided URL. +* `--hostUrl=https://${TOKEN}@raw.githubprivate.com/stefanpenner/supported/main/`, gets the above listed file from the private instance URL provided, +private instance needs token, that must be passed as part of URL. + +#### token +The `--token` (`-t`) is to pass the token generated to access the private instances of the github. This will enable this tool to evaluate +the github private instance repositories. Generating a personal access token is explained in detail [here](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token). + +Example: +`supported https://test.githubprivate.com/stefanpenner/supported -t $TOKEN` + ### As a node module diff --git a/lib/project/setup-project.js b/lib/project/setup-project.js index c63e996..6fcef3a 100644 --- a/lib/project/setup-project.js +++ b/lib/project/setup-project.js @@ -37,7 +37,7 @@ module.exports = async function setupProject(projectRoot, flags = {}) { }; } catch (e) { throw new Error( - `Couldn't parse the npmrc file, are you sure project URL has a valid npmrc?`, + `Couldn't parse the npmrc file, are you sure project URL has a valid npmrc?\n ${e}`, ); } } diff --git a/lib/read-from-url.js b/lib/read-from-url.js index 4232462..aa880af 100644 --- a/lib/read-from-url.js +++ b/lib/read-from-url.js @@ -14,7 +14,7 @@ async function setupProjectPath(_url, options = {}) { const queue = new PQueue({ concurrency: os.cpus().length, }); - let result = {}; + let result = Object.create(null); let packageJSON; // check if the code moved to main or still using master // https://github.com/SparshithNR/doc-tester/blob/master/package.json @@ -53,7 +53,7 @@ async function setupProjectPath(_url, options = {}) { } async function runFetch(requestURL, isJson) { - let response = {}; + let response; try { response = await fetch(requestURL); } catch (e) { From c4a0a9df7869040a42309f014d3b8fbec0787499 Mon Sep 17 00:00:00 2001 From: sparshithNR Date: Mon, 17 May 2021 13:01:56 -0700 Subject: [PATCH 7/8] Updating ember LTS version as 3.20 is the latest. https://emberjs.com/releases/lts/ --- lib/lts/ember-lts.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/lts/ember-lts.json b/lib/lts/ember-lts.json index ad8e041..84824ee 100644 --- a/lib/lts/ember-lts.json +++ b/lib/lts/ember-lts.json @@ -1,14 +1,14 @@ { - "3.16.*": { - "versionRange": "3.16.*", - "start_date": "2020-03-04T00:00:00.000Z", - "maintenance_start_date": "2020-11-11T00:00:00.000Z", - "end_date": "2021-03-17T00:00:00.000Z" - }, "3.20.*": { "versionRange": ">=3.20.*", "start_date": "2020-08-24T00:00:00.000Z", "maintenance_start_date": "2021-05-03T00:00:00.000Z", "end_date": "2021-09-06T00:00:00.000Z" + }, + "3.24.*": { + "versionRange": ">=3.24.*", + "start_date": "2021-02-25T00:00:00.000Z", + "maintenance_start_date": "2021-11-04T00:00:00.000Z", + "end_date": "2022-03-10T00:00:00.000Z" } } \ No newline at end of file From 662f8f7134b20fcaa09f4aa95916ee2af8e120e6 Mon Sep 17 00:00:00 2001 From: sparshithNR Date: Mon, 17 May 2021 13:05:57 -0700 Subject: [PATCH 8/8] Fixing lint issues --- lib/util.js | 8 ++++---- tests/util-test.js | 8 +++++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/lib/util.js b/lib/util.js index fc483f0..dd4f85d 100644 --- a/lib/util.js +++ b/lib/util.js @@ -242,7 +242,7 @@ module.exports.handleInput = function (input, cwd) { /** * Generates the fetch URL to get package.json and other required files. */ -module.exports.getFetchUrl = function(_url, options = {}) { +module.exports.getFetchUrl = function (_url, options = {}) { let { token, hostUrl } = options; _url = hostUrl || _url; _url += _url.endsWith('/') ? '' : '/'; @@ -275,12 +275,12 @@ module.exports.getFetchUrl = function(_url, options = {}) { currentURL = currentURL.replace(url.pathname, pathname); currentURL += currentURL.endsWith('/') ? '' : '/'; return currentURL; -} +}; /** * Returns true if the given list of input has private instance, and token is provided. */ -module.exports.inputHasGithubPrivate = function(flags, input) { +module.exports.inputHasGithubPrivate = function (flags, input) { input = Array.isArray(input) ? input : [input]; let isPrivate = input.some(inputUrl => { return inputUrl.includes(GITHUB_PRIVATE); @@ -289,4 +289,4 @@ module.exports.inputHasGithubPrivate = function(flags, input) { console.log(MISSING_TOKEN); } return isPrivate; -} +}; diff --git a/tests/util-test.js b/tests/util-test.js index 925d407..323db75 100644 --- a/tests/util-test.js +++ b/tests/util-test.js @@ -2,7 +2,13 @@ const chai = require('chai'); const { expect } = chai; -const { sortLibraries, checkNodeCompatibility, handleInput, getFetchUrl, inputHasGithubPrivate } = require('../lib/util'); +const { + sortLibraries, + checkNodeCompatibility, + handleInput, + getFetchUrl, + inputHasGithubPrivate, +} = require('../lib/util'); chai.use(require('chai-datetime'));