├── .npmrc ├── test ├── fixtures │ ├── travis-ymls │ │ ├── testing-minimal.yml │ │ ├── testing-no-node.yml │ │ ├── testing-imports │ │ │ ├── partials │ │ │ │ ├── node-12.yml │ │ │ │ ├── node-14.yml │ │ │ │ ├── node-10.yml │ │ │ │ ├── indirect-node-14.yml │ │ │ │ ├── circular.yml │ │ │ │ ├── commitish.yml │ │ │ │ └── merge-invalid.yml │ │ │ ├── simple-single-string.yml │ │ │ ├── circular.yml │ │ │ ├── commitish.yml │ │ │ ├── simple-array-string.yml │ │ │ ├── indirect.yml │ │ │ ├── simple-array-object.yml │ │ │ ├── simple-single-object.yml │ │ │ ├── indirect-dot-slash.yml │ │ │ ├── merge-invalid.yml │ │ │ ├── conditional.yml │ │ │ ├── merge-shallow.yml │ │ │ ├── merge-deep.yml │ │ │ ├── another-repo.yml │ │ │ └── merge-deep-prepend-append.yml │ │ ├── testing-single-version.yml │ │ ├── nodejs-ci-config-travis-gte-10.yml │ │ ├── testing-no-env-matrix.yml │ │ ├── testing-invalid-version.yml │ │ ├── npm-promzard.yml │ │ ├── shinn-is-resolvable.yml │ │ ├── postcss-autoprefixer.yml │ │ ├── nodejs-readable-stream.yml │ │ ├── caolan-async.yml │ │ ├── kangax-html-minifier.yml │ │ ├── reactivex-rxjs.yml │ │ └── nodejs-nan.yml │ ├── hapi-package.json │ ├── deps-test │ │ ├── package.json │ │ └── npm-shrinkwrap.json │ ├── node-release-schedule.json │ ├── index.js │ └── packuments │ │ ├── is-ci.json │ │ ├── ms.json │ │ └── ci-info.json ├── cli-test.txt ├── utils.js ├── travis.js └── index.js ├── .labrc.js ├── .eslintrc ├── renovate.json ├── release.config.js ├── lib ├── constants.js ├── engines.js ├── index.js ├── loader │ ├── index.js │ ├── octokit-wrapper.js │ ├── path.js │ ├── npm.js │ └── repository.js ├── utils.js ├── logger.js ├── package.js ├── travis │ ├── merge.js │ ├── index.js │ └── imports.js └── deps.js ├── CODE_OF_CONDUCT.md ├── .gitignore ├── .travis.yml ├── .github └── workflows │ └── ci.yaml ├── LICENSE ├── package.json ├── CONTRIBUTING.md ├── bin └── detect-node-support └── README.md /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-minimal.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-no-node.yml: -------------------------------------------------------------------------------- 1 | language: generic 2 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-imports/partials/node-12.yml: -------------------------------------------------------------------------------- 1 | node_js: 2 | - "12" 3 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-imports/partials/node-14.yml: -------------------------------------------------------------------------------- 1 | node_js: 2 | - "14" 3 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-single-version.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: "10" 3 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/nodejs-ci-config-travis-gte-10.yml: -------------------------------------------------------------------------------- 1 | node_js: 2 | - 14 3 | - 12 4 | - 10 5 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-imports/partials/node-10.yml: -------------------------------------------------------------------------------- 1 | node_js: 2 | - "10.15" 3 | - "10.16" 4 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-no-env-matrix.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | env: 3 | - NO_MATRIX=true 4 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-imports/partials/indirect-node-14.yml: -------------------------------------------------------------------------------- 1 | import: 2 | - source: ./node-14.yml 3 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-invalid-version.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: "i-am-not-a-node-version" 3 | -------------------------------------------------------------------------------- /.labrc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.globals = [ 4 | 'Symbol(__RESOLVED_TEMP_DIRECTORY__)' 5 | ].join(','); 6 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-imports/simple-single-string.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | import: partials/node-14.yml 3 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-imports/circular.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | import: 3 | - source: partials/circular.yml 4 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-imports/commitish.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | import: 3 | - source: partials/commitish.yml 4 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-imports/simple-array-string.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | import: 3 | - partials/node-14.yml 4 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "plugin:@hapi/recommended", 3 | 4 | "parserOptions": { 5 | "ecmaVersion": 2019 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-imports/indirect.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | import: 3 | - source: partials/indirect-node-14.yml 4 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-imports/partials/circular.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | import: 3 | - source: partials/circular.yml 4 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-imports/simple-array-object.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | import: 3 | - source: partials/node-14.yml 4 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-imports/simple-single-object.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | import: 3 | source: partials/node-14.yml 4 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-imports/partials/commitish.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | import: 3 | - source: partials/node-14.yml@main 4 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base", 4 | ":preserveSemverRanges", 5 | ":disableDependencyDashboard" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-imports/indirect-dot-slash.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | import: 3 | - source: ./partials/indirect-node-14.yml 4 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-imports/merge-invalid.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | import: 5 | - source: partials/merge-invalid.yml 6 | -------------------------------------------------------------------------------- /release.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | branches: [ 5 | 'main', 6 | { name: 'alpha', prerelease: true } 7 | ] 8 | }; 9 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-imports/conditional.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | import: 3 | - source: partials/indirect-node-14.yml 4 | if: branch = master 5 | -------------------------------------------------------------------------------- /lib/constants.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Package = require('../package.json'); 4 | 5 | 6 | exports.userAgent = `${Package.name}/${Package.version} (${Package.homepage})`; 7 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | The Node.js Code of Conduct, which applies to this project, can be found at 4 | https://github.com/nodejs/admin/blob/master/CODE_OF_CONDUCT.md. 5 | -------------------------------------------------------------------------------- /test/cli-test.txt: -------------------------------------------------------------------------------- 1 | 2 | . 3 | detect-node-support 4 | @hapi/hapi 5 | pkgjs/detect-node-support 6 | https://github.com/pkgjs/detect-node-support 7 | git+https://github.com/pkgjs/detect-node-support.git 8 | -------------------------------------------------------------------------------- /test/fixtures/hapi-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@hapi/hapi", 3 | "version": "0.0.0-development", 4 | "repository": { 5 | "type": "git", 6 | "url": "git+https://github.com/hapijs/hapi.git" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/npm-promzard.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | language: node_js 3 | node_js: 4 | - '0.8' 5 | - '0.10' 6 | - '0.12' 7 | - 'iojs' 8 | before_install: 9 | - npm install -g npm@latest 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | **/node_modules 2 | /package-lock.json 3 | /npm-shrinkwrap.json 4 | 5 | coverage.* 6 | *.log* 7 | test-results.xml 8 | 9 | **/.DS_Store 10 | **/._* 11 | 12 | **/*.pem 13 | 14 | **/.vs 15 | **/.vscode 16 | **/.idea 17 | -------------------------------------------------------------------------------- /lib/engines.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.detect = ({ packageJson }) => { 4 | 5 | if (packageJson.engines) { 6 | 7 | return { 8 | engines: packageJson.engines.node 9 | }; 10 | } 11 | }; 12 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-imports/merge-shallow.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | import: 5 | - source: partials/node-14.yml # default merge: deep_merge_append 6 | - source: partials/node-12.yml 7 | mode: merge 8 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-imports/merge-deep.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | import: 5 | - source: partials/node-14.yml # default merge: deep_merge_append 6 | - source: partials/node-12.yml 7 | mode: deep_merge 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | import: 4 | - nodejs/ci-config-travis:lts/gte-14.yml 5 | 6 | cache: 7 | npm: false 8 | 9 | install: 10 | - "npm install -g npm" 11 | - "npm install --ignore-scripts" 12 | - "npx allow-scripts" 13 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-imports/partials/merge-invalid.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | import: 5 | - source: partials/node-14.yml # default merge: deep_merge_append 6 | - source: partials/node-12.yml 7 | mode: no_such_merge_mode 8 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-imports/another-repo.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | import: 3 | - source: pkgjs/detect-node-support:test/fixtures/travis-ymls/testing-imports/partials/indirect-node-14.yml 4 | - source: pkgjs/detect-node-support:test/fixtures/travis-ymls/testing-imports/partials/node-14.yml # cache hit 5 | -------------------------------------------------------------------------------- /test/fixtures/deps-test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@pkgjs/detect-node-support-deps-test", 3 | "version": "0.0.0-development", 4 | "private": true, 5 | "dependencies": { 6 | "is-ci": "^2.0.0", 7 | "ci-info": "^1.6.0" 8 | }, 9 | "devDependencies": { 10 | "debug": "^4.1.1" 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/testing-imports/merge-deep-prepend-append.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "8" 4 | import: 5 | - source: partials/node-14.yml # default merge: deep_merge_append 6 | - source: partials/node-12.yml 7 | mode: deep_merge_prepend 8 | - source: partials/node-10.yml 9 | mode: deep_merge_append 10 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/shinn-is-resolvable.yml: -------------------------------------------------------------------------------- 1 | # Source: https://github.com/shinnn/is-resolvable/blob/ad414e366d58ab47ae44099415fffac5d14b627a/.travis.yml#L1 2 | 3 | if: branch !~ ^v\d 4 | language: node_js 5 | node_js: node 6 | matrix: 7 | include: 8 | - after_script: node_modules/.bin/nyc report | npx coveralls 9 | - os: windows 10 | script: node test.js 11 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Deps = require('./deps'); 4 | const Package = require('./package'); 5 | 6 | exports.detect = async function (what, { deps, deep, dev } = {}) { 7 | 8 | const { result, meta } = await Package.detect(what); 9 | 10 | if (deps) { 11 | result.dependencies = await Deps.detect(meta, { deep, dev }); 12 | } 13 | 14 | return result; 15 | }; 16 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/postcss-autoprefixer.yml: -------------------------------------------------------------------------------- 1 | # Source: https://github.com/postcss/autoprefixer/blob/0ee84d70f3f474e6f408c3078fe61db65a26ee0a/.travis.yml 2 | 3 | language: node_js 4 | cache: yarn 5 | node_js: 6 | - node 7 | - "10" 8 | - "12" 9 | - "8" 10 | install: 11 | - yarn install --ignore-engines 12 | matrix: 13 | include: 14 | node_js: "6" 15 | script: yarn run jest 16 | -------------------------------------------------------------------------------- /lib/loader/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const NpmLoader = require('./npm'); 4 | const PathLoader = require('./path'); 5 | const RepositoryLoader = require('./repository'); 6 | 7 | 8 | exports.create = ({ path, repository, packageName }) => { 9 | 10 | if (repository) { 11 | return RepositoryLoader.create(repository); 12 | } 13 | 14 | if (packageName) { 15 | return NpmLoader.create(packageName); 16 | } 17 | 18 | return PathLoader.create(path); 19 | }; 20 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | 11 | test: 12 | uses: pkgjs/action/.github/workflows/node-test.yaml@v0 13 | with: 14 | post-checkout-steps: | 15 | - name: Set git user to avoid warnings 16 | shell: bash 17 | run: | 18 | git config --global user.name github-actions 19 | git config --global user.email github-actions@github.com 20 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/nodejs-readable-stream.yml: -------------------------------------------------------------------------------- 1 | # Source: https://github.com/nodejs/readable-stream/blob/ed213f0dfdc0da6ed94f1aefc54808cc1f74da7c/.travis.yml 2 | 3 | language: node_js 4 | notifications: 5 | email: false 6 | matrix: 7 | fast_finish: true 8 | include: 9 | - node_js: 6 10 | env: CMD=test 11 | - node_js: 8 12 | env: CMD=test 13 | - node_js: 9 14 | env: CMD=test 15 | - node_js: 10 16 | env: CMD=test 17 | - node_js: 12 18 | env: CMD=test 19 | - node_js: stable 20 | env: CMD=test-browsers 21 | addons: 22 | sauce_connect: true 23 | hosts: 24 | - airtap.local 25 | script: npm run $CMD 26 | -------------------------------------------------------------------------------- /lib/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const SimpleGit = require('simple-git'); 4 | 5 | /* $lab:coverage:off$ */ 6 | // this is wrapped primarily to be able to stub it 7 | exports.simpleGit = (...args) => { 8 | 9 | return SimpleGit(...args); 10 | }; 11 | /* $lab:coverage:on$ */ 12 | 13 | exports.getErrorMessage = (error) => { 14 | 15 | if (typeof error === 'string') { 16 | return error; 17 | } 18 | 19 | if (error && error.message) { 20 | return error.message; 21 | } 22 | 23 | return null; 24 | }; 25 | 26 | 27 | exports.toArray = (v) => { 28 | 29 | if (v === undefined) { 30 | return []; 31 | } 32 | 33 | return Array.isArray(v) ? v : [v]; 34 | }; 35 | -------------------------------------------------------------------------------- /lib/logger.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Debug = require('debug'); 4 | 5 | 6 | const internals = { 7 | loggers: {} 8 | }; 9 | 10 | 11 | internals.getLogger = (tags) => { 12 | 13 | const suffix = tags.join(':'); 14 | 15 | if (!internals.loggers[suffix]) { 16 | internals.loggers[suffix] = Debug(`detect-node-support:${suffix}`); 17 | } 18 | 19 | return internals.loggers[suffix]; 20 | }; 21 | 22 | 23 | exports.log = (tags, ...args) => { 24 | 25 | const logger = internals.getLogger(tags); 26 | logger(...args); 27 | }; 28 | 29 | 30 | exports.warn = (tags, ...args) => { 31 | 32 | exports.log(['warn', ...tags], ...args); 33 | }; 34 | 35 | 36 | exports.error = (tags, ...args) => { 37 | 38 | exports.log(['error', ...tags], ...args); 39 | }; 40 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/caolan-async.yml: -------------------------------------------------------------------------------- 1 | # Source: https://github.com/caolan/async/blob/f9ad468f7b464f5ef88116def2399a5c6e59e21d/.travis.yml 2 | 3 | sudo: false 4 | dist: xenial 5 | language: node_js 6 | node_js: 7 | - "8" 8 | - "10" 9 | - "12" 10 | 11 | services: 12 | - xvfb 13 | 14 | matrix: 15 | include: 16 | - node_js: "10" 17 | addons: 18 | firefox: "60.0" 19 | env: BROWSER=true MAKE_TEST=true 20 | env: 21 | matrix: BROWSER=false MAKE_TEST=false 22 | 23 | after_success: npm run coveralls 24 | 25 | 26 | # Needed to run Karma with Firefox on Travis 27 | # http://karma-runner.github.io/0.13/plus/travis.html 28 | before_script: 29 | - sudo apt-get install -y make 30 | - make --version 31 | 32 | script: 33 | - "[ $BROWSER == true ] || npm test" 34 | # ensure buildable 35 | - "[ $MAKE_TEST == false ] || make -j 4" 36 | # test in firefox 37 | - "[ $BROWSER == false ] || npm run mocha-browser-test" 38 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/kangax-html-minifier.yml: -------------------------------------------------------------------------------- 1 | # Source: https://github.com/kangax/html-minifier/blob/51ce10f4daedb1de483ffbcccecc41be1c873da2/.travis.yml 2 | 3 | addons: 4 | apt: 5 | sources: 6 | - ubuntu-toolchain-r-test 7 | packages: 8 | - libstdc++-4.9-dev 9 | 10 | language: generic 11 | 12 | matrix: 13 | fast_finish: true 14 | 15 | env: 16 | matrix: 17 | - NODEJS_VER=node/6 18 | - NODEJS_VER=node/8 19 | - NODEJS_VER=node/10 20 | - NODEJS_VER=node/latest 21 | 22 | before_install: 23 | - git clone --branch v1.4.2 --depth 1 https://github.com/jasongin/nvs.git ~/.nvs 24 | - . ~/.nvs/nvs.sh 25 | - nvs --version 26 | 27 | install: 28 | - nvs add $NODEJS_VER 29 | - nvs use $NODEJS_VER 30 | - node --version 31 | - npm --version --no-update-notifier 32 | - npm install --no-optional --no-save --no-update-notifier 33 | 34 | script: 35 | - npm test --no-update-notifier 36 | 37 | notifications: 38 | email: false 39 | -------------------------------------------------------------------------------- /lib/loader/octokit-wrapper.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { Octokit } = require('@octokit/rest'); 4 | const { throttling } = require('@octokit/plugin-throttling'); 5 | 6 | const Constants = require('../constants'); 7 | const Logger = require('../logger'); 8 | 9 | 10 | const internals = { 11 | Octokit: Octokit.plugin(throttling) 12 | }; 13 | 14 | 15 | exports.create = () => { 16 | 17 | const octokit = new internals.Octokit({ 18 | auth: process.env.GH_TOKEN, 19 | userAgent: Constants.userAgent, 20 | throttle: { 21 | onRateLimit: (retryAfter, options) => { 22 | 23 | Logger.warn(['loader'], 'Request quota exceeded for request %s %s. Will retry in %d seconds. Have you set a GH_TOKEN in env?', options.method, options.url, retryAfter); 24 | 25 | return true; 26 | }, 27 | onAbuseLimit: (retryAfter, options) => { 28 | 29 | return false; 30 | } 31 | } 32 | }); 33 | 34 | return octokit; 35 | }; 36 | -------------------------------------------------------------------------------- /lib/loader/path.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Fs = require('fs'); 4 | const Path = require('path'); 5 | 6 | const Utils = require('../utils'); 7 | 8 | 9 | exports.create = async (path) => { 10 | 11 | const simpleGit = Utils.simpleGit(path); 12 | const isRepo = await simpleGit.checkIsRepo(); 13 | 14 | if (!isRepo) { 15 | throw new Error(`${path} is not a git repository`); 16 | } 17 | 18 | if (!Fs.existsSync(Path.join(path, 'package.json'))) { 19 | throw new Error(`${path} does not contain a package.json`); 20 | } 21 | 22 | return { 23 | getCommit: () => { 24 | 25 | return simpleGit.revparse(['HEAD']); 26 | }, 27 | loadFile: (filename, options = {}) => { 28 | 29 | const fullPath = Path.join(path, filename); 30 | 31 | const buffer = Fs.readFileSync(fullPath); 32 | 33 | if (options.json) { 34 | return JSON.parse(buffer.toString()); 35 | } 36 | 37 | return buffer; 38 | } 39 | }; 40 | }; 41 | -------------------------------------------------------------------------------- /test/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Utils = require('../lib/utils'); 4 | 5 | const { describe, it } = exports.lab = require('@hapi/lab').script(); 6 | const { expect } = require('@hapi/code'); 7 | 8 | describe('Utils', () => { 9 | 10 | describe('getErrorMessage()', () => { 11 | 12 | it('returns error message when present', () => { 13 | 14 | expect(Utils.getErrorMessage(new Error('Test error'))).to.equal('Test error'); 15 | }); 16 | 17 | it('returns the string', () => { 18 | 19 | expect(Utils.getErrorMessage('Test error')).to.equal('Test error'); 20 | }); 21 | 22 | it('null for an object without a message', () => { 23 | 24 | expect(Utils.getErrorMessage({})).to.equal(null); 25 | }); 26 | 27 | it('null for null', () => { 28 | 29 | expect(Utils.getErrorMessage(null)).to.equal(null); 30 | }); 31 | 32 | 33 | it('null for undefined', () => { 34 | 35 | expect(Utils.getErrorMessage()).to.equal(null); 36 | }); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Contributors https://github.com/pkgjs/detect-node-support/graphs/contributors 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "detect-node-support", 3 | "version": "0.0.0-development", 4 | "description": "List the Node.js versions supported by the package/repository", 5 | "bin": { 6 | "detect-node-support": "./bin/detect-node-support" 7 | }, 8 | "files": [ 9 | "bin", 10 | "lib" 11 | ], 12 | "main": "lib/index.js", 13 | "scripts": { 14 | "test-cli": " while read p; do echo \"./bin/detect-node-support $p\"; ./bin/detect-node-support $p; done < ./test/cli-test.txt", 15 | "test": "lab -a @hapi/code -L -p 1 -t 100 -m 5000" 16 | }, 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/pkgjs/detect-node-support.git" 20 | }, 21 | "author": "Dominykas Blyžė ", 22 | "license": "MIT", 23 | "bugs": { 24 | "url": "https://github.com/pkgjs/detect-node-support/issues" 25 | }, 26 | "engines": { 27 | "node": ">=14" 28 | }, 29 | "homepage": "https://github.com/pkgjs/detect-node-support#readme", 30 | "devDependencies": { 31 | "@hapi/code": "^8.0.0", 32 | "@hapi/lab": "^24.0.0", 33 | "allow-scripts": "^1.5.2", 34 | "nock": "^13.0.0", 35 | "sinon": "^13.0.0" 36 | }, 37 | "dependencies": { 38 | "@npmcli/arborist": "^4.0.0", 39 | "@octokit/plugin-throttling": "^3.2.2", 40 | "@octokit/rest": "^18.0.0", 41 | "@pkgjs/nv": "0.2.1", 42 | "debug": "^4.1.1", 43 | "git-url-parse": "^11.1.2", 44 | "js-yaml": "^4.0.0", 45 | "minimist": "^1.2.5", 46 | "pacote": "^12.0.0", 47 | "simple-git": "^3.0.0", 48 | "tmp": "^0.2.0" 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Code of Conduct 4 | 5 | The Node.js project has a 6 | [Code of Conduct](https://github.com/nodejs/admin/blob/master/CODE_OF_CONDUCT.md) 7 | to which all contributors must adhere. 8 | 9 | See [details on our policy on Code of Conduct](https://github.com/nodejs/node/blob/master/doc/guides/contributing/code-of-conduct.md). 10 | 11 | 12 | ## Developer's Certificate of Origin 1.1 13 | 14 | By making a contribution to this project, I certify that: 15 | 16 | * (a) The contribution was created in whole or in part by me and I 17 | have the right to submit it under the open source license 18 | indicated in the file; or 19 | 20 | * (b) The contribution is based upon previous work that, to the best 21 | of my knowledge, is covered under an appropriate open source 22 | license and I have the right under that license to submit that 23 | work with modifications, whether created in whole or in part 24 | by me, under the same open source license (unless I am 25 | permitted to submit under a different license), as indicated 26 | in the file; or 27 | 28 | * (c) The contribution was provided directly to me by some other 29 | person who certified (a), (b) or (c) and I have not modified 30 | it. 31 | 32 | * (d) I understand and agree that this project and the contribution 33 | are public and that a record of the contribution (including all 34 | personal information I submit with it, including my sign-off) is 35 | maintained indefinitely and may be redistributed consistent with 36 | this project or the open source license(s) involved. 37 | -------------------------------------------------------------------------------- /test/fixtures/deps-test/npm-shrinkwrap.json: -------------------------------------------------------------------------------- 1 | { 2 | "requires": true, 3 | "lockfileVersion": 1, 4 | "dependencies": { 5 | "ci-info": { 6 | "version": "1.6.0", 7 | "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", 8 | "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==" 9 | }, 10 | "debug": { 11 | "version": "4.1.1", 12 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", 13 | "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", 14 | "dev": true, 15 | "requires": { 16 | "ms": "^2.1.1" 17 | } 18 | }, 19 | "is-ci": { 20 | "version": "2.0.0", 21 | "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", 22 | "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", 23 | "requires": { 24 | "ci-info": "^2.0.0" 25 | }, 26 | "dependencies": { 27 | "ci-info": { 28 | "version": "2.0.0", 29 | "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", 30 | "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==" 31 | } 32 | } 33 | }, 34 | "ms": { 35 | "version": "2.1.2", 36 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 37 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", 38 | "dev": true 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/reactivex-rxjs.yml: -------------------------------------------------------------------------------- 1 | # Source: https://github.com/ReactiveX/rxjs/blob/ef88ded3d671f48466ea3a42f9a2af656bd51d36/.travis.yml 2 | 3 | language: node_js 4 | sudo: false 5 | 6 | addons: 7 | sauce_connect: 8 | # Update SAUCE_USERNAME / SAUCE_ACCESS_KEY in travis if necessary 9 | # https://docs.travis-ci.com/user/environment-variables/#Defining-Variables-in-Repository-Settings 10 | sauce_connect: true 11 | 12 | cache: 13 | directories: 14 | - node_modules 15 | 16 | env: 17 | matrix: 18 | - NODE_VER=4 FULL_VALIDATE=false 19 | - NODE_VER=6 FULL_VALIDATE=true alias grunt=./node_modules/grunt-cli/bin/grunt 20 | - NODE_VER=7 FULL_VALIDATE=false 21 | matrix: 22 | fast_finish: true 23 | 24 | before_install: 25 | - nvm install $NODE_VER 26 | - npm install -g npm@4 && npm install -g npx && node -v && npm -v 27 | - if [ "$FULL_VALIDATE" == "true" ]; then npm install grunt@0.4.1 grunt-cli grunt-contrib-connect grunt-run; fi 28 | 29 | install: 30 | - npm install 31 | - if [ "$FULL_VALIDATE" == "true" ]; then npm run lint && npm run check_circular_dependencies; fi 32 | 33 | script: 34 | - if [ "$FULL_VALIDATE" == "true" ] && [ -n "DANGER_GITHUB_API_TOKEN" ]; then echo {} > ./.babelrc && npx danger; fi 35 | - npm run build_spec && npm run test_mocha && node ./node_modules/markdown-doctest/bin/cmd.js 36 | 37 | after_success: 38 | - if [ "$FULL_VALIDATE" == "true" ]; then npm run cover && cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js; fi 39 | - if [ "$FULL_VALIDATE" == "true" ] && [ "$TRAVIS_PULL_REQUEST" = "false" ] && [ -n "$SAUCE_ACCESS_KEY" ]; then npm run build_spec_browser && grunt --gruntfile spec/support/mocha.sauce.gruntfile.js; fi 40 | -------------------------------------------------------------------------------- /lib/package.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Fs = require('fs'); 4 | const { URL } = require('url'); 5 | 6 | const Engines = require('./engines'); 7 | const Loader = require('./loader'); 8 | const Travis = require('./travis'); 9 | 10 | 11 | const internals = {}; 12 | 13 | internals.what = (what) => { 14 | 15 | if (typeof what !== 'string') { 16 | return what; 17 | } 18 | 19 | try { 20 | var url = new URL(what); 21 | } 22 | catch (err) { 23 | // do nothing - attempt to use the string as a package name 24 | } 25 | 26 | if (url) { 27 | return { repository: url.href }; 28 | } 29 | 30 | if (Fs.existsSync(what)) { 31 | return { path: what }; 32 | } 33 | 34 | if (what.split('/').length === 2 && !what.startsWith('@')) { 35 | return { repository: what }; 36 | } 37 | 38 | return { packageName: what }; 39 | }; 40 | 41 | 42 | exports.detect = async (what) => { 43 | 44 | const { path, repository, packageName } = internals.what(what); 45 | 46 | const { loadFile, getCommit } = await Loader.create({ path, repository, packageName }); 47 | 48 | const packageJson = await loadFile('package.json', { json: true }); 49 | 50 | const meta = { 51 | packageJson, 52 | getCommit, 53 | loadFile 54 | }; 55 | 56 | const result = {}; 57 | 58 | result.name = packageJson.name; 59 | result.version = packageJson.version; 60 | result.commit = await meta.getCommit(); 61 | result.timestamp = Date.now(); 62 | 63 | const travis = await Travis.detect(meta); 64 | const engines = await Engines.detect(meta); 65 | 66 | Object.assign(result, travis, engines); 67 | 68 | return { result, meta }; 69 | }; 70 | -------------------------------------------------------------------------------- /lib/travis/merge.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | // ref: https://github.com/travis-ci/travis-yml/blob/bf82881491134c72a64778f9664a8dd3f97158e7/lib/travis/yml/support/merge.rb 4 | 5 | const internals = {}; 6 | 7 | 8 | internals.isObject = (arg) => typeof arg === 'object' && !Array.isArray(arg); 9 | 10 | 11 | exports.deep_merge_append = (left, right) => { 12 | 13 | for (const key in right) { 14 | 15 | if (internals.isObject(left[key]) && internals.isObject(right[key])) { 16 | exports.deep_merge_append(left[key], right[key]); 17 | continue; 18 | } 19 | 20 | if (Array.isArray(left[key]) && Array.isArray(right[key])) { 21 | left[key].push(...right[key]); 22 | continue; 23 | } 24 | 25 | left[key] = right[key]; 26 | } 27 | }; 28 | 29 | exports.deep_merge_prepend = (left, right) => { 30 | 31 | for (const key in right) { 32 | 33 | if (internals.isObject(left[key]) && internals.isObject(right[key])) { 34 | exports.deep_merge_prepend(left[key], right[key]); 35 | continue; 36 | } 37 | 38 | if (Array.isArray(left[key]) && Array.isArray(right[key])) { 39 | left[key].unshift(...right[key]); 40 | continue; 41 | } 42 | 43 | left[key] = right[key]; 44 | } 45 | }; 46 | 47 | exports.deep_merge = (left, right) => { 48 | 49 | for (const key in right) { 50 | 51 | if (internals.isObject(left[key]) && internals.isObject(right[key])) { 52 | exports.deep_merge(left[key], right[key]); 53 | continue; 54 | } 55 | 56 | left[key] = right[key]; 57 | } 58 | }; 59 | 60 | exports.merge = (left, right) => { 61 | 62 | for (const key in right) { 63 | left[key] = right[key]; 64 | } 65 | }; 66 | -------------------------------------------------------------------------------- /lib/loader/npm.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Pacote = require('pacote'); 4 | 5 | const Constants = require('../constants'); 6 | const RepositoryLoader = require('./repository'); 7 | 8 | const internals = {}; 9 | 10 | 11 | internals.parseRepository = (packument) => { 12 | 13 | if (typeof packument.repository === 'string') { 14 | return packument.repository; 15 | } 16 | 17 | if (!packument.repository || !packument.repository.url) { 18 | throw new Error(`Unable to determine the git repository for ${packument.name}`); 19 | } 20 | 21 | return packument.repository.url; 22 | }; 23 | 24 | 25 | exports.create = async (packageName) => { 26 | 27 | try { 28 | const packument = await Pacote.packument(packageName + '@latest', { 29 | 'fullMetadata': true, 30 | 'user-agent': Constants.userAgent 31 | }); 32 | 33 | const repository = internals.parseRepository(packument); 34 | 35 | const repositoryLoader = RepositoryLoader.create(repository); 36 | 37 | return { 38 | ...repositoryLoader, 39 | loadFile: async (filename, options) => { 40 | 41 | const result = await repositoryLoader.loadFile(filename, options); 42 | 43 | if (filename === 'package.json' && result.name !== packageName) { 44 | throw new Error(`${repository} does not contain ${packageName}. Monorepo not supported: https://github.com/pkgjs/detect-node-support/issues/6`); 45 | } 46 | 47 | return result; 48 | } 49 | }; 50 | } 51 | catch (err) { 52 | 53 | if (err.statusCode === 404) { 54 | throw new Error(`Package ${packageName} does not exist`); 55 | } 56 | 57 | throw err; 58 | 59 | } 60 | }; 61 | -------------------------------------------------------------------------------- /test/fixtures/node-release-schedule.json: -------------------------------------------------------------------------------- 1 | { 2 | "v0.10": { 3 | "start": "2013-03-11", 4 | "end": "2016-10-31" 5 | }, 6 | "v0.12": { 7 | "start": "2015-02-06", 8 | "end": "2016-12-31" 9 | }, 10 | "v4": { 11 | "start": "2015-09-08", 12 | "lts": "2015-10-12", 13 | "maintenance": "2017-04-01", 14 | "end": "2018-04-30", 15 | "codename": "Argon" 16 | }, 17 | "v5": { 18 | "start": "2015-10-29", 19 | "maintenance": "2016-04-30", 20 | "end": "2016-06-30" 21 | }, 22 | "v6": { 23 | "start": "2016-04-26", 24 | "lts": "2016-10-18", 25 | "maintenance": "2018-04-30", 26 | "end": "2019-04-30", 27 | "codename": "Boron" 28 | }, 29 | "v7": { 30 | "start": "2016-10-25", 31 | "maintenance": "2017-04-30", 32 | "end": "2017-06-30" 33 | }, 34 | "v8": { 35 | "start": "2017-05-30", 36 | "lts": "2017-10-31", 37 | "maintenance": "2019-01-01", 38 | "end": "2019-12-31", 39 | "codename": "Carbon" 40 | }, 41 | "v9": { 42 | "start": "2017-10-01", 43 | "maintenance": "2018-04-01", 44 | "end": "2018-06-30" 45 | }, 46 | "v10": { 47 | "start": "2018-04-24", 48 | "lts": "2018-10-30", 49 | "maintenance": "2020-04-01", 50 | "end": "2021-04-30", 51 | "codename": "Dubnium" 52 | }, 53 | "v11": { 54 | "start": "2018-10-23", 55 | "maintenance": "2019-04-22", 56 | "end": "2019-06-01" 57 | }, 58 | "v12": { 59 | "start": "2019-04-23", 60 | "lts": "2019-10-21", 61 | "maintenance": "2020-10-21", 62 | "end": "2022-04-30", 63 | "codename": "Erbium" 64 | }, 65 | "v13": { 66 | "start": "2019-10-22", 67 | "maintenance": "2020-04-01", 68 | "end": "2020-06-01" 69 | }, 70 | "v14": { 71 | "start": "2020-04-21", 72 | "lts": "2020-10-20", 73 | "maintenance": "2021-10-20", 74 | "end": "2023-04-30", 75 | "codename": "" 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /test/fixtures/travis-ymls/nodejs-nan.yml: -------------------------------------------------------------------------------- 1 | # Source: https://github.com/nodejs/nan/blob/60e86a9d4c4536fbbd2a76814470edd66b23114e/.travis.yml 2 | 3 | os: 4 | - linux 5 | - osx 6 | language: cpp 7 | addons: 8 | apt: 9 | sources: 10 | - ubuntu-toolchain-r-test 11 | packages: 12 | - bc 13 | - g++-4.8 14 | env: 15 | matrix: 16 | - TRAVIS_NODE_VERSION="0.10" 17 | - TRAVIS_NODE_VERSION="0.12" 18 | - TRAVIS_NODE_VERSION="4" 19 | - TRAVIS_NODE_VERSION="5" 20 | - TRAVIS_NODE_VERSION="6" 21 | - TRAVIS_NODE_VERSION="7" 22 | - TRAVIS_NODE_VERSION="8" 23 | - TRAVIS_NODE_VERSION="9" 24 | - TRAVIS_NODE_VERSION="10" 25 | - TRAVIS_NODE_VERSION="11" 26 | - TRAVIS_NODE_VERSION="12" 27 | - TRAVIS_NODE_VERSION="13" 28 | - TRAVIS_NODE_VERSION="lts/*" ELECTRON_VERSION="2.0.18" 29 | - TRAVIS_NODE_VERSION="lts/*" ELECTRON_VERSION="3.1.13" 30 | - TRAVIS_NODE_VERSION="lts/*" ELECTRON_VERSION="4.2.12" 31 | - TRAVIS_NODE_VERSION="lts/*" ELECTRON_VERSION="5.0.11" 32 | - TRAVIS_NODE_VERSION="lts/*" ELECTRON_VERSION="6.1.2" 33 | - TRAVIS_NODE_VERSION="lts/*" ELECTRON_VERSION="7.0.0" 34 | matrix: 35 | exclude: 36 | - os: osx 37 | env: TRAVIS_NODE_VERSION="0.12" 38 | install: 39 | - rm -rf ~/.nvm && git clone https://github.com/creationix/nvm.git ~/.nvm && (cd ~/.nvm && git checkout `git describe --abbrev=0 --tags`) && source ~/.nvm/nvm.sh && nvm install $TRAVIS_NODE_VERSION 40 | - if [[ $TRAVIS_OS_NAME == "linux" ]]; then export CXX=g++-4.8; fi 41 | - $CXX --version 42 | - if [[ $TRAVIS_NODE_VERSION == "0.8" ]]; then npm config set strict-ssl false; fi 43 | - if [[ -z "$ELECTRON_VERSION" && $(echo "$TRAVIS_NODE_VERSION < 4" | bc -l) == "1" ]]; then npm install npm@2 && mv node_modules npm && npm/.bin/npm --version && npm/.bin/npm install; else npm --version && npm install; fi 44 | - if [[ -z "$ELECTRON_VERSION" ]]; then node_modules/.bin/node-gyp rebuild --directory test; else node_modules/.bin/node-gyp rebuild --target=v$ELECTRON_VERSION --dist-url=https://atom.io/download/electron --directory test; fi 45 | script: 46 | - if [[ -z "$ELECTRON_VERSION" ]]; then node_modules/.bin/tap --gc test/js/*-test.js; fi 47 | -------------------------------------------------------------------------------- /bin/detect-node-support: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | 'use strict'; 4 | 5 | const Debug = require('debug'); 6 | const Fs = require('fs'); 7 | const Minimist = require('minimist'); 8 | const Tmp = require('tmp'); 9 | const Util = require('util'); 10 | 11 | const NodeSupport = require('..'); 12 | 13 | const internals = {}; 14 | 15 | 16 | internals.help = () => { 17 | 18 | return ` 19 | Usage: detect-node-support [--deps] [--dev] [--deep] [--json] 20 | 21 | can be an npm package name, or a Github URL, or a path 22 | with a package.json. 23 | 24 | Options: 25 | --deep When used with --deps, include indirect dependencies 26 | --deps Include the support information of direct production dependencies 27 | --dev When used with --deps, include direct dev dependencies 28 | --json Print JSON formatted output 29 | `; 30 | }; 31 | 32 | exports.main = async ({ _: [what], help, deps, deep, dev, json }) => { 33 | 34 | const enabledLogs = ['detect-node-support:warn:*', 'detect-node-support:error:*']; 35 | 36 | if (process.env.DEBUG) { 37 | enabledLogs.push(process.env.DEBUG); 38 | } 39 | 40 | Debug.enable(enabledLogs.join(',')); 41 | 42 | if (help) { 43 | console.log(internals.help()); 44 | return; 45 | } 46 | 47 | if (!what) { 48 | what = process.cwd(); 49 | } 50 | 51 | if (!deps && (deep || dev)) { 52 | console.log('--deep and --dev can only be used together with --deps\n'); 53 | console.log(internals.help()); 54 | return; 55 | } 56 | 57 | const result = await NodeSupport.detect(what, { deps, deep, dev }); 58 | 59 | const jsonOutput = JSON.stringify(result, null, ' '); 60 | const tmpFile = Tmp.fileSync({ postfix: '.json' }); 61 | Fs.writeFileSync(tmpFile.name, jsonOutput); 62 | 63 | if (json) { 64 | console.log(jsonOutput); 65 | } 66 | else { 67 | console.log(Util.inspect(result, false, null, true)); 68 | console.log(`Full output available in ${tmpFile.name}`); 69 | } 70 | }; 71 | 72 | exports.main(Minimist(process.argv.slice(2), { boolean: ['deps', 'dev', 'deep', 'json'] })) 73 | .catch((err) => { 74 | 75 | console.error(err); 76 | console.log(internals.help()); 77 | process.exit(1); 78 | }); 79 | -------------------------------------------------------------------------------- /lib/travis/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Nv = require('@pkgjs/nv'); 4 | const Yaml = require('js-yaml'); 5 | 6 | const TravisImports = require('./imports'); 7 | const Utils = require('../utils'); 8 | 9 | 10 | const internals = {}; 11 | 12 | 13 | internals.nodeAliases = { 14 | latest: 'active', 15 | node: 'active', 16 | stable: 'active' 17 | }; 18 | 19 | 20 | internals.scan = async (travisYaml, options) => { 21 | 22 | await TravisImports.apply(travisYaml, options); 23 | 24 | const rawSet = new Set(); 25 | 26 | for (const v of Utils.toArray(travisYaml.node_js)) { 27 | rawSet.add(v); 28 | } 29 | 30 | if (travisYaml.env) { 31 | 32 | for (const env of Utils.toArray(travisYaml.env.matrix)) { 33 | 34 | const matches = env.match(/(?:NODEJS_VER|TRAVIS_NODE_VERSION|NODE_VER)="?(node\/)?(?[\w./*]+)"?/); 35 | 36 | if (matches) { 37 | rawSet.add(matches.groups.version); 38 | } 39 | } 40 | } 41 | 42 | if (travisYaml.matrix) { 43 | 44 | for (const include of Utils.toArray(travisYaml.matrix.include)) { 45 | 46 | if (include.node_js) { 47 | rawSet.add(include.node_js); 48 | } 49 | } 50 | } 51 | 52 | if (travisYaml.language === 'node_js' && !rawSet.size) { 53 | rawSet.add('latest'); 54 | } 55 | 56 | const raw = [...rawSet]; 57 | const resolved = {}; 58 | 59 | for (const version of raw) { 60 | 61 | const nv = await Nv(internals.nodeAliases[version] || version); 62 | 63 | if (!nv.length) { 64 | resolved[version] = false; 65 | } 66 | else { 67 | resolved[version] = nv[nv.length - 1].version; 68 | } 69 | } 70 | 71 | return { raw, resolved }; 72 | }; 73 | 74 | 75 | exports.detect = async ({ loadFile }) => { 76 | 77 | try { 78 | var buffer = await loadFile('.travis.yml'); 79 | } 80 | catch (err) { 81 | 82 | if (err.code === 'ENOENT') { 83 | return; 84 | } 85 | 86 | throw err; 87 | } 88 | 89 | const travisYaml = Yaml.load(buffer, { 90 | schema: Yaml.FAILSAFE_SCHEMA, 91 | json: true 92 | }); 93 | 94 | return { 95 | travis: await internals.scan(travisYaml, { loadFile }) 96 | }; 97 | }; 98 | -------------------------------------------------------------------------------- /lib/loader/repository.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const GitUrlParse = require('git-url-parse'); 4 | 5 | const Logger = require('../logger'); 6 | const OctokitWrapper = require('./octokit-wrapper'); 7 | const Utils = require('../utils'); 8 | 9 | 10 | const internals = { 11 | cache: new Map() 12 | }; 13 | 14 | 15 | exports.create = (repository) => { 16 | 17 | if (repository.split('/').length === 2) { 18 | repository = `https://github.com/${repository}`; 19 | } 20 | 21 | const parsedRepository = GitUrlParse(repository); 22 | 23 | return { 24 | getCommit: async () => { 25 | 26 | const simpleGit = Utils.simpleGit(); 27 | const httpRepository = GitUrlParse.stringify(parsedRepository, 'http'); 28 | const result = await simpleGit.listRemote([httpRepository, 'HEAD']); 29 | const [head] = result.split(/\s+/); 30 | 31 | return head; 32 | }, 33 | loadFile: async (filename, options = {}) => { 34 | 35 | if (parsedRepository.source !== 'github.com') { 36 | throw new Error('Only github.com paths supported, feel free to PR at https://github.com/pkgjs/detect-node-support'); 37 | } 38 | 39 | const resource = `${parsedRepository.full_name}:${filename}@HEAD`; 40 | Logger.log(['loader'], 'Loading: %s', resource); 41 | 42 | const octokit = OctokitWrapper.create(); 43 | 44 | try { 45 | 46 | let result; 47 | if (internals.cache.has(resource)) { 48 | Logger.log(['loader'], 'From cache: %s', resource); 49 | result = internals.cache.get(resource); 50 | } 51 | else { 52 | result = await octokit.repos.getContent({ 53 | owner: parsedRepository.owner, 54 | repo: parsedRepository.name, 55 | path: filename 56 | }); 57 | } 58 | 59 | internals.cache.set(resource, result); 60 | 61 | Logger.log(['loader'], 'Loaded: %s', resource); 62 | 63 | const content = Buffer.from(result.data.content, 'base64'); 64 | 65 | if (options.json) { 66 | return JSON.parse(content.toString()); 67 | } 68 | 69 | return content; 70 | } 71 | catch (err) { 72 | 73 | if (err.status === 404) { 74 | Logger.log(['loader'], 'Not found: %s', resource); 75 | const error = new Error(`${repository} does not contain a ${filename}`); 76 | error.code = 'ENOENT'; 77 | throw error; 78 | } 79 | 80 | Logger.error(['loader'], 'Failed to load: %s', resource); 81 | throw err; 82 | } 83 | } 84 | }; 85 | }; 86 | 87 | 88 | exports.clearCache = () => { 89 | 90 | internals.cache = new Map(); 91 | }; 92 | -------------------------------------------------------------------------------- /lib/travis/imports.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Yaml = require('js-yaml'); 4 | 5 | const Loader = require('../loader'); 6 | const Utils = require('../utils'); 7 | 8 | const TravisMerge = require('./merge'); 9 | 10 | 11 | const internals = { 12 | validMergeModes: new Set(['deep_merge_append', 'deep_merge_prepend', 'deep_merge', 'merge']) 13 | }; 14 | 15 | 16 | internals.normalizeImports = (travisYaml, { relativeTo, breadcrumb }) => { 17 | 18 | const context = relativeTo ? relativeTo.source : '.travis.yml'; 19 | 20 | return Utils.toArray(travisYaml.import) 21 | .map((entry) => { 22 | 23 | if (typeof entry === 'string') { 24 | entry = { source: entry }; 25 | } 26 | 27 | const original = entry.source; 28 | 29 | if (entry.source.startsWith('./')) { 30 | entry.source = entry.source.substring(2); 31 | 32 | if (relativeTo) { 33 | const relativeParts = relativeTo.source.split('/'); 34 | relativeParts.pop(); 35 | relativeParts.push(entry.source); 36 | entry.source = relativeParts.join('/'); 37 | } 38 | } 39 | 40 | if (!entry.mode) { 41 | entry.mode = 'deep_merge_append'; 42 | } 43 | 44 | if (!internals.validMergeModes.has(entry.mode)) { 45 | throw new Error(`Invalid merge mode for ${original} in ${context}: ${entry.mode}`); 46 | } 47 | 48 | if (original.includes('@')) { 49 | throw new Error(`Importing at commitish unsupported in ${context}: ${original}`); 50 | } 51 | 52 | const alreadyImported = breadcrumb.indexOf(entry.source); 53 | if (alreadyImported >= 0) { 54 | throw new Error(`Circular dependency ${entry.source} requested by ${context} (already imported at ${breadcrumb[alreadyImported - 1]})`); 55 | } 56 | 57 | return entry; 58 | }) 59 | .filter((entry) => !entry.if); // @todo: log a warning 60 | }; 61 | 62 | 63 | internals.loadSource = async (source, { loadFile }) => { 64 | 65 | let path = source; 66 | 67 | if (source.includes(':')) { 68 | const [repository, fileName] = source.split(':'); 69 | const loader = await Loader.create({ repository: `https://github.com/${repository}` }); 70 | 71 | path = fileName; 72 | loadFile = loader.loadFile; 73 | } 74 | 75 | return loadFile(path); 76 | }; 77 | 78 | 79 | exports.apply = async (yaml, { loadFile, relativeTo, breadcrumb = ['.travis.yml'] }) => { 80 | 81 | if (!yaml.import) { 82 | return; 83 | } 84 | 85 | const imports = internals.normalizeImports(yaml, { relativeTo, breadcrumb }); 86 | 87 | for (const entry of imports) { 88 | 89 | const buffer = await internals.loadSource(entry.source, { loadFile }); 90 | 91 | const imported = Yaml.load(buffer, { 92 | schema: Yaml.FAILSAFE_SCHEMA, 93 | json: true 94 | }); 95 | 96 | await exports.apply(imported, { loadFile, relativeTo: entry, breadcrumb: [...breadcrumb, entry.source] }); 97 | 98 | delete imported.import; 99 | 100 | TravisMerge[entry.mode](yaml, imported); 101 | } 102 | }; 103 | -------------------------------------------------------------------------------- /lib/deps.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const { Arborist } = require('@npmcli/arborist'); 4 | const Fs = require('fs'); 5 | const Path = require('path'); 6 | const Tmp = require('tmp'); 7 | 8 | const Logger = require('./logger'); 9 | const Package = require('./package'); 10 | const Utils = require('./utils'); 11 | 12 | const internals = {}; 13 | 14 | 15 | internals.resolve = async ({ packageJson, lockfile }, options) => { 16 | 17 | const tmpDir = Tmp.dirSync({ unsafeCleanup: true }); 18 | const path = tmpDir.name; 19 | 20 | Fs.writeFileSync(Path.join(path, 'package.json'), JSON.stringify(packageJson, null, ' ')); 21 | 22 | if (lockfile) { 23 | Fs.writeFileSync(Path.join(path, 'package-lock.json'), JSON.stringify(lockfile, null, ' ')); 24 | } 25 | 26 | const arborist = new Arborist({ path }); 27 | 28 | await arborist.buildIdealTree(); 29 | 30 | const map = {}; 31 | 32 | for (const dep of arborist.idealTree.inventory.values()) { 33 | 34 | if (dep.isProjectRoot) { 35 | // root node is not a dep, really 36 | continue; 37 | } 38 | 39 | if (!options.dev && dep.dev) { 40 | // only include dev deps when `options.dev` flag is set 41 | continue; 42 | } 43 | 44 | if (!options.deep && ![...dep.edgesIn].some(({ from }) => from.isProjectRoot)) { 45 | continue; 46 | } 47 | 48 | map[dep.name] = map[dep.name] || new Set(); 49 | map[dep.name].add(dep.package.version); 50 | } 51 | 52 | const result = {}; 53 | 54 | for (const name of Object.keys(map).sort()) { 55 | result[name] = [...map[name]]; 56 | } 57 | 58 | tmpDir.removeCallback(); 59 | 60 | return result; 61 | }; 62 | 63 | internals.tryLoad = async (loadFile, filename) => { 64 | 65 | try { 66 | return await loadFile(filename, { json: true }); 67 | } 68 | catch (err) { 69 | if (err.code !== 'ENOENT') { 70 | throw err; 71 | } 72 | } 73 | }; 74 | 75 | exports.detect = async ({ packageJson, loadFile }, options) => { 76 | 77 | const lockfile = (await internals.tryLoad(loadFile, 'package-lock.json')) || (await internals.tryLoad(loadFile, 'npm-shrinkwrap.json')); 78 | if (lockfile) { 79 | Logger.log(['deps'], 'Lock file present'); 80 | } 81 | else { 82 | Logger.warn(['deps'], 'Lock file missing - things will be a bit slower'); 83 | } 84 | 85 | const versions = await internals.resolve({ packageJson, lockfile }, options); 86 | 87 | const support = []; 88 | const errors = {}; 89 | let hasErrors = false; 90 | 91 | const packages = Object.keys(versions).sort(); 92 | const n = packages.length; 93 | 94 | for (let i = 0; i < n; ++i) { 95 | 96 | const packageName = packages[i]; 97 | Logger.log(['deps'], `Resolving dependency ${i + 1} of ${n}: ${packageName}`); 98 | 99 | try { 100 | const { result } = await Package.detect({ packageName }); 101 | support.push(result); 102 | } 103 | catch (err) { 104 | hasErrors = true; 105 | errors[packageName] = { 106 | message: Utils.getErrorMessage(err) 107 | }; 108 | } 109 | } 110 | 111 | const result = { support, versions }; 112 | 113 | if (hasErrors) { 114 | result.errors = errors; 115 | } 116 | 117 | return result; 118 | }; 119 | -------------------------------------------------------------------------------- /test/fixtures/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Fs = require('fs'); 4 | const Nock = require('nock'); 5 | const Path = require('path'); 6 | const SimpleGit = require('simple-git'); 7 | const Sinon = require('sinon'); 8 | const Tmp = require('tmp'); 9 | 10 | const RepositoryLoader = require('../../lib/loader/repository'); 11 | const Utils = require('../../lib/utils'); 12 | 13 | 14 | module.exports = class TestContext { 15 | 16 | constructor() { 17 | 18 | this._cleanup = []; 19 | this.stubs = {}; 20 | 21 | Sinon.useFakeTimers({ 22 | now: +new Date('2020-02-02T20:00:02Z'), 23 | toFake: ['Date'] 24 | }); 25 | 26 | this._mockSimpleGit(); 27 | this._mockNetwork(); 28 | } 29 | 30 | cleanup() { 31 | 32 | RepositoryLoader.clearCache(); 33 | 34 | Sinon.restore(); 35 | 36 | this._cleanup.forEach((cleanup) => cleanup()); 37 | 38 | this._cleanup = []; 39 | } 40 | 41 | _mockSimpleGit() { 42 | 43 | this.stubs.listRemote = Sinon.stub().throws(); 44 | 45 | Sinon.stub(Utils, 'simpleGit').callsFake((...args) => { 46 | 47 | const simpleGit = SimpleGit(...args); 48 | 49 | Sinon.stub(simpleGit, 'listRemote').callsFake(this.stubs.listRemote); 50 | 51 | return simpleGit; 52 | }); 53 | } 54 | 55 | _mockNetwork() { 56 | 57 | if (!Nock.isActive()) { 58 | Nock.activate(); 59 | } 60 | 61 | Nock.disableNetConnect(); 62 | 63 | Nock('https://raw.githubusercontent.com') 64 | .persist() 65 | .get('/nodejs/Release/master/schedule.json') 66 | .reply(200, Fs.readFileSync(Path.join(__dirname, 'node-release-schedule.json'))); 67 | 68 | Nock('https://nodejs.org') 69 | .persist() 70 | .get('/dist/index.json') 71 | .reply(200, Fs.readFileSync(Path.join(__dirname, 'node-release-dist.json'))); 72 | 73 | Nock('https://api.github.com') 74 | .persist() 75 | .get('/repos/nodejs/ci-config-travis/contents/lts%2Fgte-14.yml') 76 | .reply(200, { 77 | // note: this is mocked out to an earlier version of node, to avoid having to update too many assertions/fixtures 78 | content: Fs.readFileSync(Path.join(__dirname, 'travis-ymls', 'nodejs-ci-config-travis-gte-10.yml')).toString('base64') 79 | }); 80 | 81 | this._cleanup.push(() => { 82 | 83 | Nock.restore(); 84 | Nock.cleanAll(); 85 | Nock.enableNetConnect(); 86 | }); 87 | } 88 | 89 | async setupRepoFolder({ travisYml, partials, packageJson, npmShrinkwrapJson, packageLockJson, git = true } = {}) { 90 | 91 | const tmpObj = Tmp.dirSync({ unsafeCleanup: true }); 92 | 93 | this.path = tmpObj.name; 94 | 95 | this._cleanup.push(() => tmpObj.removeCallback()); 96 | 97 | if (travisYml) { 98 | Fs.copyFileSync(Path.join(__dirname, 'travis-ymls', travisYml), Path.join(this.path, '.travis.yml')); 99 | } 100 | 101 | if (partials) { 102 | Fs.mkdirSync(Path.join(this.path, 'partials')); 103 | const partialYmls = [ 104 | 'circular.yml', 105 | 'commitish.yml', 106 | 'indirect-node-14.yml', 107 | 'merge-invalid.yml', 108 | 'node-10.yml', 109 | 'node-12.yml', 110 | 'node-14.yml' 111 | ]; 112 | for (const fn of partialYmls) { 113 | Fs.copyFileSync(Path.join(__dirname, 'travis-ymls', 'testing-imports', 'partials', fn), Path.join(this.path, 'partials', fn)); 114 | } 115 | } 116 | 117 | if (packageJson !== false) { 118 | Fs.writeFileSync(Path.join(this.path, 'package.json'), JSON.stringify(packageJson || { 119 | name: 'test-module', 120 | version: '0.0.0-development' 121 | })); 122 | } 123 | 124 | if (npmShrinkwrapJson) { 125 | Fs.copyFileSync(Path.join(__dirname, npmShrinkwrapJson), Path.join(this.path, 'npm-shrinkwrap.json')); 126 | } 127 | 128 | if (packageLockJson) { 129 | Fs.copyFileSync(Path.join(__dirname, packageLockJson), Path.join(this.path, 'package-lock.json')); 130 | } 131 | 132 | if (git) { 133 | const simpleGit = SimpleGit(this.path); 134 | await simpleGit.init(); 135 | await simpleGit.add('./*'); 136 | await simpleGit.commit('initial commit', ['--no-gpg-sign']); 137 | } 138 | } 139 | 140 | }; 141 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # detect-node-support 2 | 3 | List the Node.js versions supported by the package/repository 4 | 5 | This repository is managed by the [Package Maintenance Working Group](https://github.com/nodejs/package-maintenance), see [Governance](https://github.com/nodejs/package-maintenance/blob/master/Governance.md). 6 | 7 | ## Setup 8 | 9 | No setup is required, however if you do not have a `GH_TOKEN` environment limit, you will likely hit a request rate limit on Github API, which may result in very long wait times for retries. 10 | 11 | ## Usage (command line) 12 | 13 | ``` 14 | $ npx detect-node-support [options] 15 | ``` 16 | 17 | Prints the supported Node.js versions for the package at the specified path. When the path is not a git repository - tries to read the git repository from `package.json` and tries to detect the versions listed in the repository as well. 18 | 19 | When `path` is omitted, tries to detect the versions for `cwd`. 20 | 21 | ``` 22 | $ npx detect-node-support [options] 23 | ``` 24 | 25 | Prints supported Node.js versions for the package from the registry. 26 | 27 | ``` 28 | $ npx detect-node-support [options] 29 | ``` 30 | 31 | Prints supported Node.js versions for the package at the git URL. 32 | 33 | ### Options 34 | 35 | * `--deep` - when used with --deps, include indirect dependencies 36 | * `--deps` - include the support information of direct production dependencies 37 | * `--dev` - when used with --deps, include dev dependencies 38 | 39 | ## Usage (library) 40 | 41 | ``` 42 | const result = await require('detect-node-support').detect({ path }, options); 43 | ``` 44 | 45 | `path` should be a folder in the local file system. When the path is not a git repository - tries to read the git repository from `package.json` and tries to detect the versions listed in the repository as well. 46 | 47 | ``` 48 | const result = await require('detect-node-support').detect({ packageName }, options); 49 | ``` 50 | 51 | `packageName` is a string name for the package in the registry. 52 | 53 | ``` 54 | const result = await require('detect-node-support').detect({ repository }, options); 55 | ``` 56 | 57 | `repository` is a URL for a git repository. 58 | 59 | ``` 60 | const result = await require('detect-node-support').detect(what, options); 61 | ``` 62 | 63 | `what` is a string containing either a package name, or a local path, or a reference to a git repository. 64 | 65 | ### Options 66 | 67 | - `deep: false` - when `true` and used `deps: true`, include indirect dependencies 68 | - `deps: false` - when `true`, include the support information of all dependencies. 69 | - `dev: false` - when `true` and used with `deps: true`, include dev dependencies 70 | 71 | ### Result 72 | 73 | - Throws if the `path` / `repository` does not have a `package.json` 74 | - Throws if `packageName` does not exist in the registry 75 | - Throws when unable to detect a git repository for the package 76 | 77 | Otherwise returns an object with: 78 | 79 | ```javascript 80 | const result = { 81 | 82 | // the `name` field of the `package.json` 83 | "name": "package-name", 84 | 85 | // the `version` field of the `package.json` when used with `path` / `repository`, 86 | // the `latest` dist-tag version when used with `package` 87 | "version": "0.0.0", 88 | 89 | // the current time when the result is returned 90 | "timestamp": 1577115956099, 91 | 92 | // git commit hash of the repository HEAD at the time of scanning 93 | "commit": "2de28c8c4ab8ac998d403509123736929131908c", 94 | 95 | // will be left out when not present in the `package.json` 96 | // a copy of the `engines.node` field from the `package.json` if present 97 | "engines": ">=x.y.z", 98 | 99 | // will be left out when `.travis.yml` file is not present 100 | "travis": { 101 | // the list of versions as detected by inspecting `node_js` / `matrix` configuration 102 | // will be an empty array when no versions are detected or the project is not a Node.js project 103 | // will contain "latest" when `language: node_js` specified, but no explicit versions detected 104 | "raw": ["8", "10", "lts/*", "invalid-specifier"], 105 | 106 | // raw version specifiers and keywords (as keys) resolved to exact Node.js versions (as values) 107 | // the value will be `false` when the specifier/keyword is unrecognized 108 | // will be an empty object when the `raw` array is empty 109 | "resolved": { 110 | "8": "8.17.0", 111 | "10": "10.18.0", 112 | "lts/*": "12.14.0", 113 | "invalid-specifier": false 114 | } 115 | }, 116 | 117 | // only present when explicitly requested 118 | "dependencies": { 119 | 120 | // will contain a support object for every unique dependency in the tree 121 | // note that the `version` will be the _latest_ version available in the registry 122 | // see below for the actual versions installed 123 | "support": [ 124 | { 125 | "name": "dependency-A" 126 | /*... other fields ...*/ 127 | }, 128 | { 129 | "name": "dependency-B" 130 | /*... other fields ...*/ 131 | } 132 | ], 133 | 134 | // will contain a list of unique versions for each dependency found in the dependency tree 135 | "versions": { 136 | "dependency-A": ["0.0.10", "1.2.5"], 137 | "dependency-B": ["0.5.3", "1.0.0"], 138 | "dependency-C": ["7.8.9"] 139 | }, 140 | 141 | // will contain a list of errors that were encountered while resolving dependency support information 142 | "errors": { 143 | "dependency-C": { 144 | // the `message` will always be either a string or `null` 145 | "message": "Failed to download some information or something" 146 | } 147 | } 148 | } 149 | } 150 | ``` 151 | -------------------------------------------------------------------------------- /test/travis.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Fs = require('fs'); 4 | const Nock = require('nock'); 5 | const Path = require('path'); 6 | 7 | const NodeSupport = require('..'); 8 | const TravisMerge = require('../lib/travis/merge'); 9 | 10 | const TestContext = require('./fixtures'); 11 | 12 | 13 | const { describe, it, beforeEach, afterEach } = exports.lab = require('@hapi/lab').script(); 14 | const { expect } = require('@hapi/code'); 15 | 16 | 17 | const internals = {}; 18 | 19 | 20 | internals.assertCommit = (result) => { 21 | 22 | expect(result.commit).to.match(/^[0-9a-f]{40}$/); 23 | delete result.commit; 24 | }; 25 | 26 | 27 | describe('.travis.yml parsing', () => { 28 | 29 | let fixture; 30 | 31 | beforeEach(() => { 32 | 33 | fixture = new TestContext(); 34 | }); 35 | 36 | afterEach(() => { 37 | 38 | fixture.cleanup(); 39 | }); 40 | 41 | for (const yml of ['simple-single-object', 'simple-single-string', 'simple-array-object', 'simple-array-string']) { 42 | 43 | // eslint-disable-next-line no-loop-func 44 | it(`resolves simple local import (${yml})`, async () => { 45 | 46 | await fixture.setupRepoFolder({ 47 | partials: true, 48 | travisYml: `testing-imports/${yml}.yml` 49 | }); 50 | 51 | const result = await NodeSupport.detect({ path: fixture.path }); 52 | 53 | internals.assertCommit(result); 54 | 55 | expect(result).to.equal({ 56 | name: 'test-module', 57 | version: '0.0.0-development', 58 | timestamp: 1580673602000, 59 | travis: { 60 | raw: ['14'], 61 | resolved: { '14': '14.3.0' } 62 | } 63 | }); 64 | }); 65 | } 66 | 67 | it('resolves indirect imports', async () => { 68 | 69 | await fixture.setupRepoFolder({ 70 | partials: true, 71 | travisYml: `testing-imports/indirect.yml` 72 | }); 73 | 74 | const result = await NodeSupport.detect({ path: fixture.path }); 75 | 76 | internals.assertCommit(result); 77 | 78 | expect(result).to.equal({ 79 | name: 'test-module', 80 | version: '0.0.0-development', 81 | timestamp: 1580673602000, 82 | travis: { 83 | raw: ['14'], 84 | resolved: { '14': '14.3.0' } 85 | } 86 | }); 87 | }); 88 | 89 | it('resolves indirect imports (./)', async () => { 90 | 91 | await fixture.setupRepoFolder({ 92 | partials: true, 93 | travisYml: `testing-imports/indirect-dot-slash.yml` 94 | }); 95 | 96 | const result = await NodeSupport.detect({ path: fixture.path }); 97 | 98 | internals.assertCommit(result); 99 | 100 | expect(result).to.equal({ 101 | name: 'test-module', 102 | version: '0.0.0-development', 103 | timestamp: 1580673602000, 104 | travis: { 105 | raw: ['14'], 106 | resolved: { '14': '14.3.0' } 107 | } 108 | }); 109 | }); 110 | 111 | it('ignores conditional imports', async () => { 112 | 113 | await fixture.setupRepoFolder({ 114 | partials: true, 115 | travisYml: `testing-imports/conditional.yml` 116 | }); 117 | 118 | const result = await NodeSupport.detect({ path: fixture.path }); 119 | 120 | internals.assertCommit(result); 121 | 122 | expect(result).to.equal({ 123 | name: 'test-module', 124 | version: '0.0.0-development', 125 | timestamp: 1580673602000, 126 | travis: { 127 | raw: ['latest'], 128 | resolved: { 'latest': '13.14.0' } 129 | } 130 | }); 131 | }); 132 | 133 | it('resolves from another repo', async () => { 134 | 135 | Nock('https://api.github.com') 136 | .get(`/repos/pkgjs/detect-node-support/contents/${encodeURIComponent('test/fixtures/travis-ymls/testing-imports/partials/indirect-node-14.yml')}`) 137 | .reply(200, { 138 | content: Fs.readFileSync(Path.join(__dirname, 'fixtures', 'travis-ymls', 'testing-imports', 'partials', 'indirect-node-14.yml')).toString('base64') 139 | }) 140 | .get(`/repos/pkgjs/detect-node-support/contents/${encodeURIComponent('test/fixtures/travis-ymls/testing-imports/partials/node-14.yml')}`) 141 | .reply(200, { 142 | content: Fs.readFileSync(Path.join(__dirname, 'fixtures', 'travis-ymls', 'testing-imports', 'partials', 'node-14.yml')).toString('base64') 143 | }); 144 | 145 | await fixture.setupRepoFolder({ 146 | partials: true, 147 | travisYml: `testing-imports/another-repo.yml` 148 | }); 149 | 150 | const result = await NodeSupport.detect({ path: fixture.path }); 151 | 152 | internals.assertCommit(result); 153 | 154 | expect(result).to.equal({ 155 | name: 'test-module', 156 | version: '0.0.0-development', 157 | timestamp: 1580673602000, 158 | travis: { 159 | raw: ['14'], 160 | resolved: { '14': '14.3.0' } 161 | } 162 | }); 163 | 164 | // verify cache returns the same result 165 | const result2 = await NodeSupport.detect({ path: fixture.path }); 166 | internals.assertCommit(result2); 167 | expect(result2).to.equal(result); 168 | }); 169 | 170 | it('resolves and merges (prepend/append)', async () => { 171 | 172 | await fixture.setupRepoFolder({ 173 | partials: true, 174 | travisYml: `testing-imports/merge-deep-prepend-append.yml` 175 | }); 176 | 177 | const result = await NodeSupport.detect({ path: fixture.path }); 178 | 179 | internals.assertCommit(result); 180 | 181 | expect(result).to.equal({ 182 | name: 'test-module', 183 | version: '0.0.0-development', 184 | timestamp: 1580673602000, 185 | travis: { 186 | raw: ['12', '8', '14', '10.15', '10.16'], 187 | resolved: { 188 | '8': '8.17.0', 189 | '10.15': '10.15.3', 190 | '10.16': '10.16.3', 191 | '12': '12.17.0', 192 | '14': '14.3.0' 193 | } 194 | } 195 | }); 196 | }); 197 | 198 | it('resolves and merges (deep)', async () => { 199 | 200 | await fixture.setupRepoFolder({ 201 | partials: true, 202 | travisYml: `testing-imports/merge-deep.yml` 203 | }); 204 | 205 | const result = await NodeSupport.detect({ path: fixture.path }); 206 | 207 | internals.assertCommit(result); 208 | 209 | expect(result).to.equal({ 210 | name: 'test-module', 211 | version: '0.0.0-development', 212 | timestamp: 1580673602000, 213 | travis: { 214 | raw: ['12'], 215 | resolved: { 216 | '12': '12.17.0' 217 | } 218 | } 219 | }); 220 | }); 221 | 222 | it('resolves and merges (shallow)', async () => { 223 | 224 | await fixture.setupRepoFolder({ 225 | partials: true, 226 | travisYml: `testing-imports/merge-shallow.yml` 227 | }); 228 | 229 | const result = await NodeSupport.detect({ path: fixture.path }); 230 | 231 | internals.assertCommit(result); 232 | 233 | expect(result).to.equal({ 234 | name: 'test-module', 235 | version: '0.0.0-development', 236 | timestamp: 1580673602000, 237 | travis: { 238 | raw: ['12'], 239 | resolved: { 240 | '12': '12.17.0' 241 | } 242 | } 243 | }); 244 | }); 245 | 246 | it('throws on invalid merge mode', async () => { 247 | 248 | await fixture.setupRepoFolder({ 249 | partials: true, 250 | travisYml: `testing-imports/partials/merge-invalid.yml` 251 | }); 252 | 253 | await expect(NodeSupport.detect({ path: fixture.path })).to.reject('Invalid merge mode for partials/node-12.yml in .travis.yml: no_such_merge_mode'); 254 | }); 255 | 256 | it('throws on invalid merge mode (indirect)', async () => { 257 | 258 | await fixture.setupRepoFolder({ 259 | partials: true, 260 | travisYml: `testing-imports/merge-invalid.yml` 261 | }); 262 | 263 | await expect(NodeSupport.detect({ path: fixture.path })).to.reject('Invalid merge mode for partials/node-12.yml in partials/merge-invalid.yml: no_such_merge_mode'); 264 | }); 265 | 266 | it('throws when importing at commitish', async () => { 267 | 268 | await fixture.setupRepoFolder({ 269 | partials: true, 270 | travisYml: `testing-imports/partials/commitish.yml` 271 | }); 272 | 273 | await expect(NodeSupport.detect({ path: fixture.path })).to.reject('Importing at commitish unsupported in .travis.yml: partials/node-14.yml@main'); 274 | }); 275 | 276 | it('throws when importing at commitish (indirect)', async () => { 277 | 278 | await fixture.setupRepoFolder({ 279 | partials: true, 280 | travisYml: `testing-imports/commitish.yml` 281 | }); 282 | 283 | await expect(NodeSupport.detect({ path: fixture.path })).to.reject('Importing at commitish unsupported in partials/commitish.yml: partials/node-14.yml@main'); 284 | }); 285 | 286 | it('throws when importing a circular dependency', async () => { 287 | 288 | await fixture.setupRepoFolder({ 289 | partials: true, 290 | travisYml: `testing-imports/circular.yml` 291 | }); 292 | 293 | await expect(NodeSupport.detect({ path: fixture.path })).to.reject('Circular dependency partials/circular.yml requested by partials/circular.yml (already imported at .travis.yml)'); 294 | }); 295 | }); 296 | 297 | describe('Travis merging algorithms', () => { 298 | 299 | let left; 300 | let right; 301 | 302 | beforeEach(() => { 303 | 304 | left = { 305 | str1: 'left', 306 | str2: 'left', 307 | arr: ['left'], 308 | obj: { 309 | left: true, 310 | arr: ['left'], 311 | deep: { 312 | left: true, 313 | arr: ['left'] 314 | } 315 | }, 316 | mix1: ['left'], 317 | mix2: { left: true } 318 | }; 319 | 320 | right = { 321 | str1: 'right', 322 | str3: 'right', 323 | arr: ['right'], 324 | obj: { 325 | right: true, 326 | arr: ['right'], 327 | deep: { 328 | right: true, 329 | arr: ['right'] 330 | } 331 | }, 332 | mix1: { right: true }, 333 | mix2: ['right'] 334 | }; 335 | }); 336 | 337 | it('deep_merge_append', () => { 338 | 339 | TravisMerge.deep_merge_append(left, right); 340 | 341 | expect(left).to.equal({ 342 | str1: 'right', 343 | str2: 'left', 344 | str3: 'right', 345 | arr: ['left', 'right'], 346 | obj: { 347 | left: true, 348 | right: true, 349 | arr: ['left', 'right'], 350 | deep: { 351 | left: true, 352 | right: true, 353 | arr: ['left', 'right'] 354 | } 355 | }, 356 | mix1: { right: true }, 357 | mix2: ['right'] 358 | }); 359 | }); 360 | 361 | it('deep_merge_prepend', () => { 362 | 363 | TravisMerge.deep_merge_prepend(left, right); 364 | 365 | expect(left).to.equal({ 366 | str1: 'right', 367 | str2: 'left', 368 | str3: 'right', 369 | arr: ['right', 'left'], 370 | obj: { 371 | left: true, 372 | right: true, 373 | arr: ['right', 'left'], 374 | deep: { 375 | left: true, 376 | right: true, 377 | arr: ['right', 'left'] 378 | } 379 | }, 380 | mix1: { right: true }, 381 | mix2: ['right'] 382 | }); 383 | }); 384 | 385 | it('deep_merge', () => { 386 | 387 | TravisMerge.deep_merge(left, right); 388 | 389 | expect(left).to.equal({ 390 | str1: 'right', 391 | str2: 'left', 392 | str3: 'right', 393 | arr: ['right'], 394 | obj: { 395 | left: true, 396 | right: true, 397 | arr: ['right'], 398 | deep: { 399 | left: true, 400 | right: true, 401 | arr: ['right'] 402 | } 403 | }, 404 | mix1: { right: true }, 405 | mix2: ['right'] 406 | }); 407 | }); 408 | 409 | it('merge', () => { 410 | 411 | TravisMerge.merge(left, right); 412 | 413 | expect(left).to.equal({ 414 | str1: 'right', 415 | str2: 'left', 416 | str3: 'right', 417 | arr: ['right'], 418 | obj: { 419 | right: true, 420 | arr: ['right'], 421 | deep: { 422 | right: true, 423 | arr: ['right'] 424 | } 425 | }, 426 | mix1: { right: true }, 427 | mix2: ['right'] 428 | }); 429 | }); 430 | }); 431 | -------------------------------------------------------------------------------- /test/fixtures/packuments/is-ci.json: -------------------------------------------------------------------------------- 1 | {"_id":"is-ci","_rev":"18-3ff4caefed88441fbdf687039d180572","name":"is-ci","description":"Detect if the current environment is a CI server","dist-tags":{"latest":"2.0.0"},"versions":{"1.0.0":{"name":"is-ci","version":"1.0.0","description":"Detect if your code is running on a CI server","main":"index.js","dependencies":{},"devDependencies":{"standard":"^5.3.1"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"https://github.com/watson/is-ci.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/is-ci/issues"},"homepage":"https://github.com/watson/is-ci","coordinates":[55.6877333,12.5956366],"gitHead":"c23bab424aef3dff1c54dc1580126af6ab767e99","_id":"is-ci@1.0.0","_shasum":"4f82a591fcd24e572e5b79957f4d50402c7387c9","_from":".","_npmVersion":"1.4.28","_npmUser":{"name":"watson","email":"w@tson.dk"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"dist":{"shasum":"4f82a591fcd24e572e5b79957f4d50402c7387c9","tarball":"https://registry.npmjs.org/is-ci/-/is-ci-1.0.0.tgz"},"directories":{}},"1.0.1":{"name":"is-ci","version":"1.0.1","description":"Detect if your code is running on a CI server","main":"index.js","dependencies":{},"devDependencies":{"standard":"^5.3.1"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"https://github.com/watson/is-ci.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/is-ci/issues"},"homepage":"https://github.com/watson/is-ci","coordinates":[55.6877071,12.5956213],"gitHead":"2b44b3d250a5d54e009b91f04ea9db84dd8397ed","_id":"is-ci@1.0.1","_shasum":"167d497c2f32938a12364f0a9116ecca1b68dc31","_from":".","_npmVersion":"1.4.28","_npmUser":{"name":"watson","email":"w@tson.dk"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"dist":{"shasum":"167d497c2f32938a12364f0a9116ecca1b68dc31","tarball":"https://registry.npmjs.org/is-ci/-/is-ci-1.0.1.tgz"},"directories":{}},"1.0.2":{"name":"is-ci","version":"1.0.2","description":"Detect if your code is running on a CI server","main":"index.js","dependencies":{},"devDependencies":{"standard":"^5.3.1"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"https://github.com/watson/is-ci.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/is-ci/issues"},"homepage":"https://github.com/watson/is-ci","coordinates":[55.66658890000001,12.579851],"gitHead":"b8d583b090312c0a815479104846b341819fe737","_id":"is-ci@1.0.2","_shasum":"2b7f64c74532f6e5ebaeaf34fa35dc44add81922","_from":".","_npmVersion":"1.4.28","_npmUser":{"name":"watson","email":"w@tson.dk"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"dist":{"shasum":"2b7f64c74532f6e5ebaeaf34fa35dc44add81922","tarball":"https://registry.npmjs.org/is-ci/-/is-ci-1.0.2.tgz"},"directories":{}},"1.0.3":{"name":"is-ci","version":"1.0.3","description":"Detect if your code is running on a CI server","main":"index.js","dependencies":{},"devDependencies":{"standard":"^5.3.1"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"https://github.com/watson/is-ci.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/is-ci/issues"},"homepage":"https://github.com/watson/is-ci","coordinates":[55.6665983,12.5798843],"gitHead":"b382b60b6660ec045496991a32a242742c9352d7","_id":"is-ci@1.0.3","_shasum":"43890b37b1791ba5925276f46779a02c8df8bb9e","_from":".","_npmVersion":"1.4.28","_npmUser":{"name":"watson","email":"w@tson.dk"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"dist":{"shasum":"43890b37b1791ba5925276f46779a02c8df8bb9e","tarball":"https://registry.npmjs.org/is-ci/-/is-ci-1.0.3.tgz"},"directories":{}},"1.0.4":{"name":"is-ci","version":"1.0.4","description":"Detect if your code is running on a CI server","main":"index.js","dependencies":{},"devDependencies":{"standard":"^5.3.1"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"https://github.com/watson/is-ci.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/is-ci/issues"},"homepage":"https://github.com/watson/is-ci","coordinates":[55.6665609,12.5798558],"gitHead":"211946480b7c9fdae2c0a19f9bbdbb95db51480c","_id":"is-ci@1.0.4","_shasum":"5e98ca48f1ecf78238541947b9cfdc94f221931c","_from":".","_npmVersion":"1.4.28","_npmUser":{"name":"watson","email":"w@tson.dk"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"dist":{"shasum":"5e98ca48f1ecf78238541947b9cfdc94f221931c","tarball":"https://registry.npmjs.org/is-ci/-/is-ci-1.0.4.tgz"},"directories":{}},"1.0.5":{"name":"is-ci","version":"1.0.5","description":"Detect if your code is running on a CI server","main":"index.js","dependencies":{},"devDependencies":{"clear-require":"^1.0.1","standard":"^5.3.1"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"https://github.com/watson/is-ci.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/is-ci/issues"},"homepage":"https://github.com/watson/is-ci","coordinates":[55.6666019,12.5798988],"gitHead":"cc89aa9c9b1ac7946c69486f014100a3b484c922","_id":"is-ci@1.0.5","_shasum":"987d7dc08b1459ac70ce2b10bc4464661f7306c5","_from":".","_npmVersion":"1.4.28","_npmUser":{"name":"watson","email":"w@tson.dk"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"dist":{"shasum":"987d7dc08b1459ac70ce2b10bc4464661f7306c5","tarball":"https://registry.npmjs.org/is-ci/-/is-ci-1.0.5.tgz"},"directories":{}},"1.0.6":{"name":"is-ci","version":"1.0.6","description":"Detect if your code is running on a CI server","main":"index.js","dependencies":{},"devDependencies":{"clear-require":"^1.0.1","standard":"^5.3.1"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"https://github.com/watson/is-ci.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/is-ci/issues"},"homepage":"https://github.com/watson/is-ci","coordinates":[55.6665508,12.5800325],"gitHead":"d43b20dac82d381ac3e0671410b92bb21082623b","_id":"is-ci@1.0.6","_shasum":"79f6690b6da2f03f33bf670c91d7cafd62e365e1","_from":".","_npmVersion":"1.4.28","_npmUser":{"name":"watson","email":"w@tson.dk"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"dist":{"shasum":"79f6690b6da2f03f33bf670c91d7cafd62e365e1","tarball":"https://registry.npmjs.org/is-ci/-/is-ci-1.0.6.tgz"},"directories":{}},"1.0.7":{"name":"is-ci","version":"1.0.7","description":"Detect if your code is running on a CI server","main":"index.js","dependencies":{},"devDependencies":{"clear-require":"^1.0.1","standard":"^5.3.1"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"https://github.com/watson/is-ci.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/is-ci/issues"},"homepage":"https://github.com/watson/is-ci","coordinates":[55.6665983,12.5798458],"gitHead":"178b148ca3d114462e661f7d00b349cf9d3b6a89","_id":"is-ci@1.0.7","_shasum":"a39895b60a4e379b1eee110e960be2bb9e9e4146","_from":".","_npmVersion":"1.4.28","_npmUser":{"name":"watson","email":"w@tson.dk"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"dist":{"shasum":"a39895b60a4e379b1eee110e960be2bb9e9e4146","tarball":"https://registry.npmjs.org/is-ci/-/is-ci-1.0.7.tgz"},"directories":{}},"1.0.8":{"name":"is-ci","version":"1.0.8","description":"Detect if your code is running on a CI server","main":"index.js","dependencies":{},"devDependencies":{"clear-require":"^1.0.1","standard":"^5.3.1"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"git+https://github.com/watson/is-ci.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/is-ci/issues"},"homepage":"https://github.com/watson/is-ci","coordinates":[55.6665609,12.5800815],"gitHead":"01a9a431a622214bce4ef3469a0dfacd425518a2","_id":"is-ci@1.0.8","_shasum":"39e8de9c132fecb4e129c653c9ecbd6370905a87","_from":".","_npmVersion":"2.14.7","_nodeVersion":"4.2.2","_npmUser":{"name":"watson","email":"w@tson.dk"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"dist":{"shasum":"39e8de9c132fecb4e129c653c9ecbd6370905a87","tarball":"https://registry.npmjs.org/is-ci/-/is-ci-1.0.8.tgz"},"_npmOperationalInternal":{"host":"packages-9-west.internal.npmjs.com","tmp":"tmp/is-ci-1.0.8.tgz_1455302400543_0.5958312251605093"},"directories":{}},"1.0.9":{"name":"is-ci","version":"1.0.9","description":"Detect if your code is running on a CI server","main":"index.js","dependencies":{},"devDependencies":{"clear-require":"^1.0.1","standard":"^5.3.1"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"git+https://github.com/watson/is-ci.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/is-ci/issues"},"homepage":"https://github.com/watson/is-ci","coordinates":[55.6876717,12.5955801],"gitHead":"e7db28828f0fdb36e4ca671f07f6c883b6fb775c","_id":"is-ci@1.0.9","_shasum":"de2c5ffe49ab3237fda38c47c8a3bbfd55bbcca7","_from":".","_npmVersion":"2.15.5","_nodeVersion":"4.4.5","_npmUser":{"name":"watson","email":"w@tson.dk"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"dist":{"shasum":"de2c5ffe49ab3237fda38c47c8a3bbfd55bbcca7","tarball":"https://registry.npmjs.org/is-ci/-/is-ci-1.0.9.tgz"},"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/is-ci-1.0.9.tgz_1467926050551_0.5283787720836699"},"directories":{}},"1.0.10":{"name":"is-ci","version":"1.0.10","description":"Detect if your code is running on a CI server","main":"index.js","dependencies":{"ci-info":"^1.0.0"},"devDependencies":{"clear-require":"^1.0.1","standard":"^5.3.1"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"git+https://github.com/watson/is-ci.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/is-ci/issues"},"homepage":"https://github.com/watson/is-ci","coordinates":[55.6876732,12.5955341],"gitHead":"248e7a5fdf6be6d8e85fcbb825578e5b3bf744ed","_id":"is-ci@1.0.10","_shasum":"f739336b2632365061a9d48270cd56ae3369318e","_from":".","_npmVersion":"2.15.9","_nodeVersion":"4.5.0","_npmUser":{"name":"watson","email":"w@tson.dk"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"dist":{"shasum":"f739336b2632365061a9d48270cd56ae3369318e","tarball":"https://registry.npmjs.org/is-ci/-/is-ci-1.0.10.tgz"},"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/is-ci-1.0.10.tgz_1476979751234_0.24868635344319046"},"directories":{}},"1.1.0":{"name":"is-ci","version":"1.1.0","description":"Detect if your code is running on a CI server","bin":{"is-ci":"bin.js"},"main":"index.js","dependencies":{"ci-info":"^1.0.0"},"devDependencies":{"clear-require":"^1.0.1","standard":"^10.0.3"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"git+https://github.com/watson/is-ci.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/is-ci/issues"},"homepage":"https://github.com/watson/is-ci","coordinates":[56.0093252,11.9592058],"gitHead":"8153f8844ca631a4c95b7dbf30c034f5dbef6023","_id":"is-ci@1.1.0","_npmVersion":"5.6.0","_nodeVersion":"9.3.0","_npmUser":{"name":"watson","email":"w@tson.dk"},"dist":{"integrity":"sha512-c7TnwxLePuqIlxHgr7xtxzycJPegNHFuIrBkwbf8hc58//+Op1CqFkyS+xnIMkwn9UsJIwc174BIjkyBmSpjKg==","shasum":"247e4162e7860cebbdaf30b774d6b0ac7dcfe7a5","tarball":"https://registry.npmjs.org/is-ci/-/is-ci-1.1.0.tgz"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/is-ci-1.1.0.tgz_1514994233368_0.7427189615555108"},"directories":{}},"1.2.0":{"name":"is-ci","version":"1.2.0","description":"Detect if your code is running on a CI server","bin":{"is-ci":"bin.js"},"main":"index.js","dependencies":{"ci-info":"^1.3.0"},"devDependencies":{"clear-require":"^1.0.1","standard":"^11.0.1"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"git+https://github.com/watson/is-ci.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/is-ci/issues"},"homepage":"https://github.com/watson/is-ci","coordinates":[55.777776,12.592345],"gitHead":"bafae86769b698590005e40d0f543c91b149b995","_id":"is-ci@1.2.0","_npmVersion":"6.2.0","_nodeVersion":"10.8.0","_npmUser":{"name":"watson","email":"w@tson.dk"},"dist":{"integrity":"sha512-plgvKjQtalH2P3Gytb7L61Lmz95g2DlpzFiQyRSFew8WoJKxtKRzrZMeyRN2supblm3Psc8OQGy7Xjb6XG11jw==","shasum":"3f4a08d6303a09882cef3f0fb97439c5f5ce2d53","tarball":"https://registry.npmjs.org/is-ci/-/is-ci-1.2.0.tgz","fileCount":7,"unpackedSize":4706,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbdT6xCRA9TVsSAnZWagAAEiAP/0qay1CmSE0558nmIAQp\nfiURE7vHIWsCWeHUKD9i+6vG+6fObsMvt5vPcVcQfk3vI3dUkHoM6Uh+uPuL\niCyoURldmdk/lQ3h27Rhw2u5HnxyY8CCc/+EZ6yt+EBbO/xC+X/4rxEV0LEh\nYaUGfxocI8IW0L0E2AvQ1bsnK95Bm3pEgm7Z1L+WBvJTqgmIm3UOX2JPrsb1\nSBNw8s4w/cSLMiFJNKXuFnA9pUkj10D1vKB3AVaxJ1O02l0JEFOHaKD/RCWL\nv7OkPZ1u7msawJu0AOlHHsmL74yPW/BGzWV7/66kUB6EYZZmsrEdPD4VC/mf\n6k29YRe2SSdG7vBBKFfLCpH13sbijQYN6BB61H/efgr1UjckX9bZE6Paduqo\nqlJ+9SW/Giwac8Jmhti8DDhAbS6jwUPG30w87lnu2ZPwtozjTOy5pQ4Jaeq3\nDoGDQzbELIXWjMqNTIF7L5/BXZYV/Jgfk+HwywvkVuLCWVN/fxcYStbtIf5R\nNYGJqaSsjAaxnpXOJx5oChHRTY8fgLKXmuUlLxldtvSpWbFC7vKVQpyj9dbB\nbSXpSdD0HFMNcv6EIUXDLQB2v+1JRFDu6L2aQoYLgNt0M4i1SFebg5NiQGrf\nxpn4DNFJ4piO+3/UpoFgkaCl9tdxput/gXbK341aFMaz0OsNlBd1NfFvhX4a\nAePH\r\n=NvYa\r\n-----END PGP SIGNATURE-----\r\n"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/is-ci_1.2.0_1534410416464_0.938502217201985"},"_hasShrinkwrap":false},"1.2.1":{"name":"is-ci","version":"1.2.1","description":"Detect if the current environment is a CI server","bin":{"is-ci":"bin.js"},"main":"index.js","dependencies":{"ci-info":"^1.5.0"},"devDependencies":{"clear-require":"^1.0.1","standard":"^11.0.1"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"git+https://github.com/watson/is-ci.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/is-ci/issues"},"homepage":"https://github.com/watson/is-ci","coordinates":[55.778255,12.593033],"gitHead":"c441f9f2924e5c51656ee04e5cc203eba227c092","_id":"is-ci@1.2.1","_npmVersion":"6.4.1","_nodeVersion":"10.10.0","_npmUser":{"name":"watson","email":"w@tson.dk"},"dist":{"integrity":"sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==","shasum":"e3779c8ee17fccf428488f6e281187f2e632841c","tarball":"https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz","fileCount":5,"unpackedSize":3313,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJblNCACRA9TVsSAnZWagAAs4gP+wR868vEV+HggZKOkre6\nZp2tQNjUYfMCNjQGzgfERek1wnsZ8yQ/sklC9G+Z+ykkmxhAbWgNWESAqCug\ngzqp+/TiMii0bRm0IOGd+TWLd4b4SPNm7+baF+b5uvQS4WdoYNZyunnBlYaP\ngts9nEG+/n/QcxCBDPTFX2JitTFPyJhmFv1wm4GlMOherBap4OwG98c88nJ0\nVarif07+m6+/CjgshNnVrjOU5JU5z6ETr7QpTBaIWclVErijkvwbaUWowfMr\nbKUH51PRojSU4O0NObFWEh02O4RGL+tCy5B/Xhvpzq8edpLfwUhQ2Vlqlap/\nvLgzsOPfW5tNe7SvHIyam6PYmd4b6YTL/P55UvCipftL5MrBYgDr5GR5kgJG\nYb1H0LN3jabKl3ITQvfQSmoAlafiuJV/RiEQZVgUWHgEKH4xzoHvFvdPNj5M\nfYPMjsouxRyi+h+eU91uEMI4+vnWEOj1RlEcleyTucnLDvgmg7CjFCtTdVgw\nqPNeq2ioOlONiig959ZEvIRVgwLQFt/N2HBqRv/YEWWEZ5hJPJDZm57ssaeY\nkcRl8V++5YcEkLDT+VGMW9c//AaUb/ostV58CfFBIA1NBQcYB9ihJk2Hn7Ek\nf3KlvmayplxxaJfWjL2CJ4fl4FuUtiEi5xM/GgxFyo51Za+LFYV5YR+iUzPJ\noqwd\r\n=3jhe\r\n-----END PGP SIGNATURE-----\r\n"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/is-ci_1.2.1_1536479359206_0.9434570997663676"},"_hasShrinkwrap":false},"2.0.0":{"name":"is-ci","version":"2.0.0","description":"Detect if the current environment is a CI server","bin":{"is-ci":"bin.js"},"main":"index.js","dependencies":{"ci-info":"^2.0.0"},"devDependencies":{"clear-module":"^3.0.0","standard":"^12.0.1"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"git+https://github.com/watson/is-ci.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/is-ci/issues"},"homepage":"https://github.com/watson/is-ci","coordinates":[55.778272,12.593116],"gitHead":"8b88365d804abc1905ca93f312e99cf95b48fc8a","_id":"is-ci@2.0.0","_npmVersion":"6.4.1","_nodeVersion":"11.3.0","_npmUser":{"name":"watson","email":"w@tson.dk"},"dist":{"integrity":"sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==","shasum":"6bc6334181810e04b5c22b3d589fdca55026404c","tarball":"https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz","fileCount":6,"unpackedSize":3581,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcCEf/CRA9TVsSAnZWagAAMvwP/1cV6uY9uye3xn2vM6vC\nMAhvaWd12GWmBg9POPhJaGi9KwhnaogbAVPHV5hhRiecrhiVXmn/Zu0T/rHt\nIkwPTeZsZ8OH4PkucIEEquj76bSJAV3oGoEWD1j3xZmCw3euSM3qsbiioYDS\nMiOBUVXhfLFZpQ3VqbN7I7L6LeuD1TDWER4rKPAl7qQO5rDgNNhk2T8KR1r/\nwiRI6YYtD1mhPF6RhUAFjUS0mT14NJ+PT+2U0c2FO8ubKb01cUk+xWCAhxax\nj6ebQnpRYDeZqICPpNOdJyenOAmsAZbFbo6vWE8M2AO/j/8+X7+P/kocdKWz\n4xrXdkM3g2Iuy+muIR9WkroWH++r3553Ni7GR1vI0qL49hlm/93zh5Vsc93a\n+VbreKYr6FzcBH+j47LG+P9TO+DZ5medQxr9U8t0WcnK0+nPW62SUoEfzryt\n6dnxeHsSRCTCQDfbgKU7s4rvG7hFmMlHH29MYVFAIwWvSJjXIlUqDsD75DwM\nKoWqNZixUYC3024ioZNxhK8bjr7Vsf6aFmplTt0aILMDuGtKwBzA9ZcijhTQ\nhPdEs24sEly9jeLastC6kvJPKxYeqZkPHvtLjWuKZ3QZMlCQN24QFWSLh2rv\nrLMR55eow/XuPO6hEqlRhSN0W4TTppsoBiravL42eK41ylzd+l80ICLTh+CZ\npcQS\r\n=YX5I\r\n-----END PGP SIGNATURE-----\r\n"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/is-ci_2.0.0_1544046590680_0.06142265580938111"},"_hasShrinkwrap":false}},"readme":"# is-ci\n\nReturns `true` if the current environment is a Continuous Integration\nserver.\n\nPlease [open an issue](https://github.com/watson/is-ci/issues) if your\nCI server isn't properly detected :)\n\n[![npm](https://img.shields.io/npm/v/is-ci.svg)](https://www.npmjs.com/package/is-ci)\n[![Build status](https://travis-ci.org/watson/is-ci.svg?branch=master)](https://travis-ci.org/watson/is-ci)\n[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://github.com/feross/standard)\n\n## Installation\n\n```bash\nnpm install is-ci --save\n```\n\n## Programmatic Usage\n\n```js\nconst isCI = require('is-ci')\n\nif (isCI) {\n console.log('The code is running on a CI server')\n}\n```\n\n## CLI Usage\n\nFor CLI usage you need to have the `is-ci` executable in your `PATH`.\nThere's a few ways to do that:\n\n- Either install the module globally using `npm install is-ci -g`\n- Or add the module as a dependency to your app in which case it can be\n used inside your package.json scripts as is\n- Or provide the full path to the executable, e.g.\n `./node_modules/.bin/is-ci`\n\n```bash\nis-ci && echo \"This is a CI server\"\n```\n\n## Supported CI tools\n\nRefer to [ci-info](https://github.com/watson/ci-info#supported-ci-tools) docs for all supported CI's\n\n## License\n\n[MIT](LICENSE)\n","maintainers":[{"name":"watson","email":"w@tson.dk"}],"time":{"modified":"2019-01-04T05:37:01.129Z","created":"2015-10-07T23:49:36.993Z","1.0.0":"2015-10-07T23:49:36.993Z","1.0.1":"2015-10-08T00:12:22.827Z","1.0.2":"2015-10-08T10:36:38.039Z","1.0.3":"2015-10-08T10:47:20.467Z","1.0.4":"2015-10-08T11:12:25.410Z","1.0.5":"2015-10-15T09:04:19.368Z","1.0.6":"2015-10-16T16:41:30.759Z","1.0.7":"2015-10-16T16:42:38.626Z","1.0.8":"2016-02-12T18:40:05.201Z","1.0.9":"2016-07-07T21:14:12.675Z","1.0.10":"2016-10-20T16:09:11.830Z","1.1.0":"2018-01-03T15:43:54.241Z","1.2.0":"2018-08-16T09:06:56.543Z","1.2.1":"2018-09-09T07:49:19.379Z","2.0.0":"2018-12-05T21:49:50.810Z"},"homepage":"https://github.com/watson/is-ci","keywords":["ci","continuous","integration","test","detect"],"repository":{"type":"git","url":"git+https://github.com/watson/is-ci.git"},"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"bugs":{"url":"https://github.com/watson/is-ci/issues"},"license":"MIT","readmeFilename":"README.md","users":{"heartnett":true}} -------------------------------------------------------------------------------- /test/fixtures/packuments/ms.json: -------------------------------------------------------------------------------- 1 | {"_id":"ms","_rev":"176-c219504ade9ccde4736276aa5a1c37d3","name":"ms","description":"Tiny millisecond conversion utility","dist-tags":{"latest":"2.1.2"},"versions":{"0.1.0":{"name":"ms","version":"0.1.0","description":"Tiny ms conversion utility","main":"./ms","devDependencies":{"mocha":"*","expect.js":"*","serve":"*"},"_npmUser":{"name":"rauchg","email":"rauchg@gmail.com"},"_id":"ms@0.1.0","dependencies":{},"engines":{"node":"*"},"_engineSupported":true,"_npmVersion":"1.0.106","_nodeVersion":"v0.4.12","_defaultsLoaded":true,"dist":{"shasum":"f21fac490daf1d7667fd180fe9077389cc9442b2","tarball":"https://registry.npmjs.org/ms/-/ms-0.1.0.tgz"},"maintainers":[{"name":"rauchg","email":"rauchg@gmail.com"}],"directories":{}},"0.2.0":{"name":"ms","version":"0.2.0","description":"Tiny ms conversion utility","main":"./ms","devDependencies":{"mocha":"*","expect.js":"*","serve":"*"},"_id":"ms@0.2.0","dist":{"shasum":"6edfc5a063471f7bfd35a5831831c24275ce9dc5","tarball":"https://registry.npmjs.org/ms/-/ms-0.2.0.tgz"},"_npmVersion":"1.1.59","_npmUser":{"name":"rauchg","email":"rauchg@gmail.com"},"maintainers":[{"name":"rauchg","email":"rauchg@gmail.com"}],"directories":{}},"0.3.0":{"name":"ms","version":"0.3.0","description":"Tiny ms conversion utility","main":"./ms","devDependencies":{"mocha":"*","expect.js":"*","serve":"*"},"_id":"ms@0.3.0","dist":{"shasum":"03edc348d613e66a56486cfdac53bcbe899cbd61","tarball":"https://registry.npmjs.org/ms/-/ms-0.3.0.tgz"},"_npmVersion":"1.1.59","_npmUser":{"name":"rauchg","email":"rauchg@gmail.com"},"maintainers":[{"name":"rauchg","email":"rauchg@gmail.com"}],"directories":{}},"0.4.0":{"name":"ms","version":"0.4.0","description":"Tiny ms conversion utility","main":"./index","devDependencies":{"mocha":"*","expect.js":"*","serve":"*"},"_id":"ms@0.4.0","dist":{"shasum":"77ade5470b099bb2d83e232c25763c18cd6963f1","tarball":"https://registry.npmjs.org/ms/-/ms-0.4.0.tgz"},"_npmVersion":"1.1.59","_npmUser":{"name":"rauchg","email":"rauchg@gmail.com"},"maintainers":[{"name":"rauchg","email":"rauchg@gmail.com"}],"directories":{}},"0.5.0":{"name":"ms","version":"0.5.0","description":"Tiny ms conversion utility","main":"./index","devDependencies":{"mocha":"*","expect.js":"*","serve":"*"},"_id":"ms@0.5.0","dist":{"shasum":"8e52e7e1bf521f9cea30f726de958822eab0ee27","tarball":"https://registry.npmjs.org/ms/-/ms-0.5.0.tgz"},"_npmVersion":"1.1.59","_npmUser":{"name":"rauchg","email":"rauchg@gmail.com"},"maintainers":[{"name":"rauchg","email":"rauchg@gmail.com"}],"directories":{}},"0.5.1":{"name":"ms","version":"0.5.1","description":"Tiny ms conversion utility","main":"./index","devDependencies":{"mocha":"*","expect.js":"*","serve":"*"},"component":{"scripts":{"ms/index.js":"index.js"}},"_id":"ms@0.5.1","dist":{"shasum":"98058c8f9c64854d1703ab92bf3f1dcc8e713b4c","tarball":"https://registry.npmjs.org/ms/-/ms-0.5.1.tgz"},"_from":".","_npmVersion":"1.2.10","_npmUser":{"name":"rauchg","email":"rauchg@gmail.com"},"maintainers":[{"name":"rauchg","email":"rauchg@gmail.com"}],"directories":{}},"0.6.0":{"name":"ms","version":"0.6.0","description":"Tiny ms conversion utility","main":"./index","devDependencies":{"mocha":"*","expect.js":"*","serve":"*"},"component":{"scripts":{"ms/index.js":"index.js"}},"_id":"ms@0.6.0","dist":{"shasum":"21dc16a7d1dc2d8ed244dc0e6a71a5c2612b623b","tarball":"https://registry.npmjs.org/ms/-/ms-0.6.0.tgz"},"_from":".","_npmVersion":"1.2.10","_npmUser":{"name":"rauchg","email":"rauchg@gmail.com"},"maintainers":[{"name":"rauchg","email":"rauchg@gmail.com"}],"directories":{}},"0.6.1":{"name":"ms","version":"0.6.1","description":"Tiny ms conversion utility","main":"./index","devDependencies":{"mocha":"*","expect.js":"*","serve":"*"},"component":{"scripts":{"ms/index.js":"index.js"}},"_id":"ms@0.6.1","dist":{"shasum":"ed57e5f3fc736e09afc85017c5c912a47bc59ab9","tarball":"https://registry.npmjs.org/ms/-/ms-0.6.1.tgz"},"_from":".","_npmVersion":"1.2.18","_npmUser":{"name":"rauchg","email":"rauchg@gmail.com"},"maintainers":[{"name":"rauchg","email":"rauchg@gmail.com"}],"directories":{}},"0.6.2":{"name":"ms","version":"0.6.2","description":"Tiny ms conversion utility","repository":{"type":"git","url":"git://github.com/guille/ms.js.git"},"main":"./index","devDependencies":{"mocha":"*","expect.js":"*","serve":"*"},"component":{"scripts":{"ms/index.js":"index.js"}},"bugs":{"url":"https://github.com/guille/ms.js/issues"},"_id":"ms@0.6.2","dist":{"shasum":"d89c2124c6fdc1353d65a8b77bf1aac4b193708c","tarball":"https://registry.npmjs.org/ms/-/ms-0.6.2.tgz"},"_from":".","_npmVersion":"1.2.30","_npmUser":{"name":"rauchg","email":"rauchg@gmail.com"},"maintainers":[{"name":"rauchg","email":"rauchg@gmail.com"}],"directories":{}},"0.7.0":{"name":"ms","version":"0.7.0","description":"Tiny ms conversion utility","repository":{"type":"git","url":"git://github.com/guille/ms.js.git"},"main":"./index","devDependencies":{"mocha":"*","expect.js":"*","serve":"*"},"component":{"scripts":{"ms/index.js":"index.js"}},"gitHead":"1e9cd9b05ef0dc26f765434d2bfee42394376e52","bugs":{"url":"https://github.com/guille/ms.js/issues"},"homepage":"https://github.com/guille/ms.js","_id":"ms@0.7.0","scripts":{},"_shasum":"865be94c2e7397ad8a57da6a633a6e2f30798b83","_from":".","_npmVersion":"1.4.21","_npmUser":{"name":"rauchg","email":"rauchg@gmail.com"},"maintainers":[{"name":"rauchg","email":"rauchg@gmail.com"}],"dist":{"shasum":"865be94c2e7397ad8a57da6a633a6e2f30798b83","tarball":"https://registry.npmjs.org/ms/-/ms-0.7.0.tgz"},"directories":{}},"0.7.1":{"name":"ms","version":"0.7.1","description":"Tiny ms conversion utility","repository":{"type":"git","url":"git://github.com/guille/ms.js.git"},"main":"./index","devDependencies":{"mocha":"*","expect.js":"*","serve":"*"},"component":{"scripts":{"ms/index.js":"index.js"}},"gitHead":"713dcf26d9e6fd9dbc95affe7eff9783b7f1b909","bugs":{"url":"https://github.com/guille/ms.js/issues"},"homepage":"https://github.com/guille/ms.js","_id":"ms@0.7.1","scripts":{},"_shasum":"9cd13c03adbff25b65effde7ce864ee952017098","_from":".","_npmVersion":"2.7.5","_nodeVersion":"0.12.2","_npmUser":{"name":"rauchg","email":"rauchg@gmail.com"},"maintainers":[{"name":"rauchg","email":"rauchg@gmail.com"}],"dist":{"shasum":"9cd13c03adbff25b65effde7ce864ee952017098","tarball":"https://registry.npmjs.org/ms/-/ms-0.7.1.tgz"},"directories":{}},"0.7.2":{"name":"ms","version":"0.7.2","description":"Tiny milisecond conversion utility","repository":{"type":"git","url":"git+https://github.com/zeit/ms.git"},"main":"./index","files":["index.js"],"scripts":{"test":"xo && mocha test/index.js","test-browser":"serve ./test"},"license":"MIT","devDependencies":{"expect.js":"^0.3.1","mocha":"^3.0.2","serve":"^1.4.0","xo":"^0.17.0"},"component":{"scripts":{"ms/index.js":"index.js"}},"xo":{"space":true,"semicolon":false,"envs":["mocha"],"rules":{"complexity":0}},"gitHead":"ac92a7e0790ba2622a74d9d60690ca0d2c070a45","bugs":{"url":"https://github.com/zeit/ms/issues"},"homepage":"https://github.com/zeit/ms#readme","_id":"ms@0.7.2","_shasum":"ae25cf2512b3885a1d95d7f037868d8431124765","_from":".","_npmVersion":"3.10.8","_nodeVersion":"6.8.0","_npmUser":{"name":"leo","email":"leo@zeit.co"},"dist":{"shasum":"ae25cf2512b3885a1d95d7f037868d8431124765","tarball":"https://registry.npmjs.org/ms/-/ms-0.7.2.tgz"},"maintainers":[{"name":"leo","email":"leo@zeit.co"},{"name":"rauchg","email":"rauchg@gmail.com"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/ms-0.7.2.tgz_1477383407940_0.4743474116548896"},"directories":{}},"0.7.3":{"name":"ms","version":"0.7.3","description":"Tiny milisecond conversion utility","repository":{"type":"git","url":"git+https://github.com/zeit/ms.git"},"main":"./index","files":["index.js"],"scripts":{"test":"xo && mocha test/index.js","test-browser":"serve ./test"},"license":"MIT","devDependencies":{"expect.js":"0.3.1","mocha":"3.0.2","serve":"5.0.1","xo":"0.17.0"},"component":{"scripts":{"ms/index.js":"index.js"}},"xo":{"space":true,"semicolon":false,"envs":["mocha"],"rules":{"complexity":0}},"gitHead":"2006a7706041443fcf1f899b5752677bd7ae01a8","bugs":{"url":"https://github.com/zeit/ms/issues"},"homepage":"https://github.com/zeit/ms#readme","_id":"ms@0.7.3","_shasum":"708155a5e44e33f5fd0fc53e81d0d40a91be1fff","_from":".","_npmVersion":"4.1.2","_nodeVersion":"7.6.0","_npmUser":{"name":"leo","email":"leo@zeit.co"},"dist":{"shasum":"708155a5e44e33f5fd0fc53e81d0d40a91be1fff","tarball":"https://registry.npmjs.org/ms/-/ms-0.7.3.tgz"},"maintainers":[{"name":"leo","email":"leo@zeit.co"},{"name":"rauchg","email":"rauchg@gmail.com"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/ms-0.7.3.tgz_1489010366101_0.14404030703008175"},"directories":{}},"1.0.0":{"name":"ms","version":"1.0.0","description":"Tiny milisecond conversion utility","repository":{"type":"git","url":"git+https://github.com/zeit/ms.git"},"main":"./index","files":["index.js"],"scripts":{"precommit":"lint-staged","lint":"eslint lib/* bin/*","test":"mocha tests.js"},"eslintConfig":{"extends":"eslint:recommended","env":{"node":true,"es6":true}},"lint-staged":{"*.js":["npm run lint","prettier --single-quote --write","git add"]},"license":"MIT","devDependencies":{"eslint":"3.18.0","expect.js":"0.3.1","husky":"0.13.2","lint-staged":"3.4.0","mocha":"3.0.2"},"gitHead":"7daf984a9011e720cc3c165ed82c4506f3471b37","bugs":{"url":"https://github.com/zeit/ms/issues"},"homepage":"https://github.com/zeit/ms#readme","_id":"ms@1.0.0","_shasum":"59adcd22edc543f7b5381862d31387b1f4bc9473","_from":".","_npmVersion":"4.1.2","_nodeVersion":"7.7.3","_npmUser":{"name":"leo","email":"leo@zeit.co"},"dist":{"shasum":"59adcd22edc543f7b5381862d31387b1f4bc9473","tarball":"https://registry.npmjs.org/ms/-/ms-1.0.0.tgz"},"maintainers":[{"name":"leo","email":"leo@zeit.co"},{"name":"rauchg","email":"rauchg@gmail.com"}],"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/ms-1.0.0.tgz_1489959793252_0.42147551802918315"},"directories":{}},"2.0.0":{"name":"ms","version":"2.0.0","description":"Tiny milisecond conversion utility","repository":{"type":"git","url":"git+https://github.com/zeit/ms.git"},"main":"./index","files":["index.js"],"scripts":{"precommit":"lint-staged","lint":"eslint lib/* bin/*","test":"mocha tests.js"},"eslintConfig":{"extends":"eslint:recommended","env":{"node":true,"es6":true}},"lint-staged":{"*.js":["npm run lint","prettier --single-quote --write","git add"]},"license":"MIT","devDependencies":{"eslint":"3.19.0","expect.js":"0.3.1","husky":"0.13.3","lint-staged":"3.4.1","mocha":"3.4.1"},"gitHead":"9b88d1568a52ec9bb67ecc8d2aa224fa38fd41f4","bugs":{"url":"https://github.com/zeit/ms/issues"},"homepage":"https://github.com/zeit/ms#readme","_id":"ms@2.0.0","_shasum":"5608aeadfc00be6c2901df5f9861788de0d597c8","_from":".","_npmVersion":"4.2.0","_nodeVersion":"7.8.0","_npmUser":{"name":"leo","email":"leo@zeit.co"},"dist":{"shasum":"5608aeadfc00be6c2901df5f9861788de0d597c8","tarball":"https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"},"maintainers":[{"name":"leo","email":"leo@zeit.co"},{"name":"rauchg","email":"rauchg@gmail.com"}],"_npmOperationalInternal":{"host":"packages-18-east.internal.npmjs.com","tmp":"tmp/ms-2.0.0.tgz_1494937565215_0.34005374647676945"},"directories":{}},"2.1.0":{"name":"ms","version":"2.1.0","description":"Tiny millisecond conversion utility","repository":{"type":"git","url":"git+https://github.com/zeit/ms.git"},"main":"./index","files":["index.js"],"scripts":{"precommit":"lint-staged","lint":"eslint lib/* bin/*","test":"mocha tests.js"},"eslintConfig":{"extends":"eslint:recommended","env":{"node":true,"es6":true}},"lint-staged":{"*.js":["npm run lint","prettier --single-quote --write","git add"]},"license":"MIT","devDependencies":{"eslint":"4.12.1","expect.js":"0.3.1","husky":"0.14.3","lint-staged":"5.0.0","mocha":"4.0.1"},"gitHead":"845c302f155d955141d623a0276bbff3529ed626","bugs":{"url":"https://github.com/zeit/ms/issues"},"homepage":"https://github.com/zeit/ms#readme","_id":"ms@2.1.0","_npmVersion":"5.5.1","_nodeVersion":"9.2.0","_npmUser":{"name":"leo","email":"leo@zeit.co"},"dist":{"integrity":"sha512-gVZHb22Z7YDyiiaoGld9LD4tUuDDxdkDJUEfTIej9LFePFqiE9JxI0qTFfu6tD7Wu03lg7skmVwTmA6XkeMlPQ==","shasum":"9a345be8f6a4aadc6686d74d88a23c1b84720549","tarball":"https://registry.npmjs.org/ms/-/ms-2.1.0.tgz"},"maintainers":[{"name":"leo","email":"leo@zeit.co"},{"name":"rauchg","email":"rauchg@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ms-2.1.0.tgz_1512060855394_0.6358025514055043"},"directories":{}},"2.1.1":{"name":"ms","version":"2.1.1","description":"Tiny millisecond conversion utility","repository":{"type":"git","url":"git+https://github.com/zeit/ms.git"},"main":"./index","files":["index.js"],"scripts":{"precommit":"lint-staged","lint":"eslint lib/* bin/*","test":"mocha tests.js"},"eslintConfig":{"extends":"eslint:recommended","env":{"node":true,"es6":true}},"lint-staged":{"*.js":["npm run lint","prettier --single-quote --write","git add"]},"license":"MIT","devDependencies":{"eslint":"4.12.1","expect.js":"0.3.1","husky":"0.14.3","lint-staged":"5.0.0","mocha":"4.0.1"},"gitHead":"fe0bae301a6c41f68a01595658a4f4f0dcba0e84","bugs":{"url":"https://github.com/zeit/ms/issues"},"homepage":"https://github.com/zeit/ms#readme","_id":"ms@2.1.1","_npmVersion":"5.5.1","_nodeVersion":"9.2.0","_npmUser":{"name":"leo","email":"leo@zeit.co"},"dist":{"integrity":"sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==","shasum":"30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a","tarball":"https://registry.npmjs.org/ms/-/ms-2.1.1.tgz"},"maintainers":[{"name":"leo","email":"leo@zeit.co"},{"name":"rauchg","email":"rauchg@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ms-2.1.1.tgz_1512066615982_0.7117063472978771"},"directories":{}},"2.1.2":{"name":"ms","version":"2.1.2","description":"Tiny millisecond conversion utility","repository":{"type":"git","url":"git+https://github.com/zeit/ms.git"},"main":"./index","scripts":{"precommit":"lint-staged","lint":"eslint lib/* bin/*","test":"mocha tests.js"},"eslintConfig":{"extends":"eslint:recommended","env":{"node":true,"es6":true}},"lint-staged":{"*.js":["npm run lint","prettier --single-quote --write","git add"]},"license":"MIT","devDependencies":{"eslint":"4.12.1","expect.js":"0.3.1","husky":"0.14.3","lint-staged":"5.0.0","mocha":"4.0.1"},"gitHead":"7920885eb232fbe7a5efdab956d3e7c507c92ddf","bugs":{"url":"https://github.com/zeit/ms/issues"},"homepage":"https://github.com/zeit/ms#readme","_id":"ms@2.1.2","_npmVersion":"6.4.1","_nodeVersion":"10.15.3","_npmUser":{"name":"styfle","email":"steven@ceriously.com"},"dist":{"integrity":"sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==","shasum":"d09d1f357b443f493382a8eb3ccd183872ae6009","tarball":"https://registry.npmjs.org/ms/-/ms-2.1.2.tgz","fileCount":4,"unpackedSize":6842,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJc+U4MCRA9TVsSAnZWagAA71AP/2rpu0zYdK5Z/BXrrKNW\nljsVOs4oHNJ2jeZrzpcV8eZUZ6zAi78plyxcnMCbbG+TrpjXrPcb8qFq630G\nS6+srbEF0lCGCc+ktJrNJPTeXkDxukQXVrepgZ2kxZ4m3q/QIAVoK4t9ebuH\nNYa+39wwET9oPuPsk+YY0Z7fQ1vadyuzHYOrRmtudV3ZtyT0k74Ec3IhKamW\nlLDJtCklD7IGcwirrvPssxmYu8WP+PAyFnrVaOW+iior1o07oWO2mk7sk3Fx\nwBSBFf7vZqFJP6Qg1m3TVBAiipL+Pf+b3Dy8fhmn4NhTGj/9Wl7f/LcqogOV\nV9l77qsZldCERBwmwLsHlMyCSSl/b2qaz28ZBTRwHtHdo19QT6MqX8Yvomy4\n+gyPBBAHC6bqqLZ0veRKzSNFfJYoFw8tQzyjSjpmYcdxaB5w4z4QPZAkZCku\ns+sooI5Xo33E9rcEDWmyqxdUud+Au/fTttg0dReYe8NVrUgzyk4T1W+D7I4k\nu3XV7O9bOaJiBTNsb22lGIC6E/HtjfoqW7iwl0cdZ8iZcPTBClkzsy9Hz6a4\nmNKDARFL0wjzWF/CoXyKcI6t9ruOepTQRfbAtZDAo4LEYj/bGiqm2kbX5AP6\nicCOlufTNip74l2bXv2sJNwtjGzEYF/S79Oyc49IP/ovIua4quXXtSjAh8Bg\nLrV/\r\n=GrYx\r\n-----END PGP SIGNATURE-----\r\n"},"maintainers":[{"email":"alexandro@phi.nz","name":"alexaltea"},{"email":"ana.trajkovska2015@gmail.com","name":"anatrajkovska"},{"email":"artzbitz@gmail.com","name":"andybitz"},{"email":"arunoda.susiripala@gmail.com","name":"arunoda"},{"email":"franco@basement.studio","name":"arzafran"},{"email":"atcastle@gmail.com","name":"atcastle"},{"email":"ciao@sylin.me","name":"b3nnyl"},{"email":"caarlos0@gmail.com","name":"caarlos0"},{"email":"thecodetheory@gmail.com","name":"codetheory"},{"email":"allenhai03@gmail.com","name":"coetry"},{"email":"mail@connordav.is","name":"dav-is"},{"email":"fivepointseven@icloud.com","name":"fivepointseven"},{"email":"guybedford@gmail.com","name":"guybedford"},{"email":"hharnisc@gmail.com","name":"hharnisc"},{"email":"lukas@huvar.cz","name":"huvik"},{"email":"hello@evilrabb.it","name":"iamevilrabbit"},{"email":"igor@klopov.com","name":"igorklopov"},{"email":"jj@jjsweb.site","name":"ijjk"},{"email":"janicklasralph036@gmail.com","name":"janicklas-ralph"},{"email":"javier.velasco86@gmail.com","name":"javivelasco"},{"email":"joecohenr@gmail.com","name":"joecohens"},{"email":"juancampa@gmail.com","name":"juancampa"},{"email":"leo@zeit.co","name":"leo"},{"email":"luisito453@gmail.com","name":"lfades"},{"email":"luc.leray@gmail.com","name":"lucleray"},{"email":"manovotny@gmail.com","name":"manovotny"},{"email":"marcosnils@gmail.com","name":"marcosnils"},{"email":"me@matheus.top","name":"matheuss"},{"email":"mrfix84@gmail.com","name":"mfix22"},{"email":"mark.glagola@gmail.com","name":"mglagola"},{"email":"mail@msweeneydev.com","name":"msweeneydev"},{"email":"naoyuki.kanezawa@gmail.com","name":"nkzawa"},{"email":"olli@zeit.co","name":"olliv"},{"email":"pvco.coursey@gmail.com","name":"paco"},{"email":"paulogdemitri@gmail.com","name":"paulogdm"},{"email":"ds303077135@gmail.com","name":"quietshu"},{"email":"rabautse@gmail.com","name":"rabaut"},{"email":"ragojosefrancisco@gmail.com","name":"ragojose"},{"email":"rauchg@gmail.com","name":"rauchg"},{"email":"sbanskota08@gmail.com","name":"sarupbanskota"},{"email":"skllcrn@zeit.co","name":"skllcrn"},{"email":"t.sophearak@gmail.com","name":"sophearak"},{"email":"steven@ceriously.com","name":"styfle"},{"email":"timer150@gmail.com","name":"timer"},{"email":"tim@timneutkens.nl","name":"timneutkens"},{"email":"nathan@tootallnate.net","name":"tootallnate"},{"email":"iyatomi@gmail.com","name":"umegaya"},{"email":"williamli@bbi.io","name":"williamli"},{"email":"team@zeit.co","name":"zeit-bot"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ms_2.1.2_1559842315767_0.4700607530567853"},"_hasShrinkwrap":false}},"readme":"# ms\n\n[![Build Status](https://travis-ci.org/zeit/ms.svg?branch=master)](https://travis-ci.org/zeit/ms)\n[![Join the community on Spectrum](https://withspectrum.github.io/badge/badge.svg)](https://spectrum.chat/zeit)\n\nUse this package to easily convert various time formats to milliseconds.\n\n## Examples\n\n```js\nms('2 days') // 172800000\nms('1d') // 86400000\nms('10h') // 36000000\nms('2.5 hrs') // 9000000\nms('2h') // 7200000\nms('1m') // 60000\nms('5s') // 5000\nms('1y') // 31557600000\nms('100') // 100\nms('-3 days') // -259200000\nms('-1h') // -3600000\nms('-200') // -200\n```\n\n### Convert from Milliseconds\n\n```js\nms(60000) // \"1m\"\nms(2 * 60000) // \"2m\"\nms(-3 * 60000) // \"-3m\"\nms(ms('10 hours')) // \"10h\"\n```\n\n### Time Format Written-Out\n\n```js\nms(60000, { long: true }) // \"1 minute\"\nms(2 * 60000, { long: true }) // \"2 minutes\"\nms(-3 * 60000, { long: true }) // \"-3 minutes\"\nms(ms('10 hours'), { long: true }) // \"10 hours\"\n```\n\n## Features\n\n- Works both in [Node.js](https://nodejs.org) and in the browser\n- If a number is supplied to `ms`, a string with a unit is returned\n- If a string that contains the number is supplied, it returns it as a number (e.g.: it returns `100` for `'100'`)\n- If you pass a string with a number and a valid unit, the number of equivalent milliseconds is returned\n\n## Related Packages\n\n- [ms.macro](https://github.com/knpwrs/ms.macro) - Run `ms` as a macro at build-time.\n\n## Caught a Bug?\n\n1. [Fork](https://help.github.com/articles/fork-a-repo/) this repository to your own GitHub account and then [clone](https://help.github.com/articles/cloning-a-repository/) it to your local device\n2. Link the package to the global module directory: `npm link`\n3. Within the module you want to test your local development instance of ms, just link it to the dependencies: `npm link ms`. Instead of the default one from npm, Node.js will now use your clone of ms!\n\nAs always, you can run the tests using: `npm test`\n","maintainers":[{"email":"samko9522@gmail.com","name":"samsisle"},{"email":"chris@leishman.org","name":"cleishm"},{"email":"nazareno@basement.studio","name":"nazarenooviedo"},{"email":"maxwell.leiter@gmail.com","name":"maxleiter"},{"email":"shu@chibicode.com","name":"chibicode"},{"email":"g.cobben@gmail.com","name":"gielcobben"},{"email":"jared@palmer.net","name":"jaredpalmer"},{"email":"jan.krems@gmail.com","name":"jkrems"},{"email":"prateek89born@gmail.com","name":"prateekbh"},{"email":"josefrancisco.verdu@gmail.com","name":"kikobeats"},{"email":"gbmonaco@google.com","name":"gmonaco"},{"email":"houssein.djirdeh@gmail.com","name":"housseindjirdeh"},{"email":"jason@developit.ca","name":"developit"},{"email":"shubhie@gmail.com","name":"spanicker"},{"email":"npm@keanulee.com","name":"keanulee"},{"email":"atcastle@gmail.com","name":"atcastle"},{"email":"janicklasralph036@gmail.com","name":"janicklas-ralph"},{"email":"skllcrn@zeit.co","name":"skllcrn"},{"email":"pvco.coursey@gmail.com","name":"paco"},{"email":"guybedford@gmail.com","name":"guybedford"},{"email":"ragojosefrancisco@gmail.com","name":"ragojose"},{"email":"williamli@bbi.io","name":"williamli"},{"email":"mail@msweeneydev.com","name":"msweeneydev"},{"email":"allenhai03@gmail.com","name":"coetry"},{"email":"rabautse@gmail.com","name":"rabaut"},{"email":"luisito453@gmail.com","name":"lfades"},{"email":"mrfix84@gmail.com","name":"mfix22"},{"email":"jj@jjsweb.site","name":"ijjk"},{"email":"franco@basement.studio","name":"arzafran"},{"email":"caarlos0@gmail.com","name":"caarlos0"},{"email":"iyatomi@gmail.com","name":"umegaya"},{"email":"sbanskota08@gmail.com","name":"sarupbanskota"},{"email":"timer150@gmail.com","name":"timer"},{"email":"ana.trajkovska2015@gmail.com","name":"anatrajkovska"},{"email":"paulogdemitri@gmail.com","name":"paulogdm"},{"email":"artzbitz@gmail.com","name":"andybitz"},{"email":"alexandro@phi.nz","name":"alexaltea"},{"email":"mark.glagola@gmail.com","name":"mglagola"},{"email":"luc.leray@gmail.com","name":"lucleray"},{"email":"team@zeit.co","name":"zeit-bot"},{"email":"steven@ceriously.com","name":"styfle"},{"email":"juancampa@gmail.com","name":"juancampa"},{"email":"mail@connordav.is","name":"dav-is"},{"email":"ds303077135@gmail.com","name":"quietshu"},{"email":"fivepointseven@icloud.com","name":"fivepointseven"},{"email":"joecohenr@gmail.com","name":"joecohens"},{"email":"thecodetheory@gmail.com","name":"codetheory"},{"email":"me@matheus.top","name":"matheuss"},{"email":"arunoda.susiripala@gmail.com","name":"arunoda"},{"email":"igor@klopov.com","name":"igorklopov"},{"email":"mindrun@icloud.com","name":"leo"},{"email":"naoyuki.kanezawa@gmail.com","name":"nkzawa"},{"email":"nathan@tootallnate.net","name":"tootallnate"},{"email":"rauchg@gmail.com","name":"rauchg"},{"email":"tim@timneutkens.nl","name":"timneutkens"},{"email":"javier.velasco86@gmail.com","name":"javivelasco"},{"email":"hello@evilrabb.it","name":"iamevilrabbit"}],"time":{"modified":"2020-03-20T19:16:19.881Z","created":"2011-12-21T19:38:08.664Z","0.1.0":"2011-12-21T19:38:26.538Z","0.2.0":"2012-09-03T20:33:06.093Z","0.3.0":"2012-09-07T20:36:45.931Z","0.4.0":"2012-10-22T17:01:26.046Z","0.5.0":"2012-11-10T00:39:49.944Z","0.5.1":"2013-02-24T20:27:27.010Z","0.6.0":"2013-03-15T15:26:35.127Z","0.6.1":"2013-05-10T15:38:08.059Z","0.6.2":"2013-12-05T15:57:45.292Z","0.7.0":"2014-11-24T07:59:08.195Z","0.7.1":"2015-04-20T23:38:57.957Z","0.7.2":"2016-10-25T08:16:49.773Z","0.7.3":"2017-03-08T21:59:28.048Z","1.0.0":"2017-03-19T21:43:15.128Z","2.0.0":"2017-05-16T12:26:06.610Z","2.1.0":"2017-11-30T16:54:16.315Z","2.1.1":"2017-11-30T18:30:16.876Z","2.1.2":"2019-06-06T17:31:55.859Z"},"users":{"285858315":true,"dodo":true,"aaron":true,"pid":true,"hughsk":true,"eknkc":true,"forbeslindesay":true,"tur-nr":true,"humantriangle":true,"yasinaydin":true,"silas":true,"tunnckocore":true,"coderaiser":true,"fgribreau":true,"awaterma":true,"robermac":true,"subso":true,"rdcl":true,"dimd13":true,"stretchgz":true,"battlemidget":true,"pensierinmusica":true,"mcortesi":true,"pandao":true,"cshao":true,"intuitivcloud":true,"bapinney":true,"dac2205":true,"jerrywu":true,"crazyorr":true,"jesusgoku":true,"wangnan0610":true,"algonzo":true,"detj":true,"sedge":true,"hugojosefson":true,"spanser":true,"danielbankhead":true,"princetoad":true,"shanewholloway":true,"snowdream":true,"shlomi":true,"xieranmaya":true,"francisbrito":true,"andreaspizsa":true,"largepuma":true,"isaacvitor":true,"manikantag":true,"cbetancourt":true,"zoomyzoom":true,"ash":true,"neo1":true,"michalskuza":true,"writeosahon":true,"rocket0191":true,"lestad":true,"mojaray2k":true,"jondotsoy":true,"ahsanshafiq":true,"miguhruiz":true,"seangenabe":true,"mikestaub":true,"panlw":true,"hugovila":true,"dpjayasekara":true,"yatsu":true,"abhisekp":true,"daizch":true,"jondashkyle":true,"lichangwei":true,"xinwangwang":true,"ssljivic":true,"terrychan":true,"l3au":true,"brend":true,"nisimjoseph":true,"raycharles":true,"travis346":true,"nalindak":true,"usex":true,"hitalos":true,"machinabio":true,"h0ward":true,"larrychen":true,"anhulife":true,"shuoshubao":true,"shushanfx":true,"ahmedelgabri":true,"edwardxyt":true,"danieljameskay":true,"monkeyyy11":true,"bhaskarmelkani":true,"gtopia":true,"ccastelli":true,"mjurincic":true,"ganeshkbhat":true,"dexfs":true,"rajiff":true,"roccomuso":true,"hayathuk":true,"parkerproject":true,"xgheaven":true,"zhenguo.zhao":true,"hearsid":true,"kamikadze4game":true,"chrisx":true,"cr8tiv":true,"gerst20051":true,"losymear":true,"zuojiang":true,"xiechao06":true,"huiyifyj":true,"yuler":true},"repository":{"type":"git","url":"git+https://github.com/zeit/ms.git"},"bugs":{"url":"https://github.com/zeit/ms/issues"},"readmeFilename":"readme.md","homepage":"https://github.com/zeit/ms#readme","license":"MIT"} -------------------------------------------------------------------------------- /test/fixtures/packuments/ci-info.json: -------------------------------------------------------------------------------- 1 | {"_id":"ci-info","_rev":"16-1f9e7efb512fa3fde5993ab19b021c10","name":"ci-info","description":"Get details about the current Continuous Integration environment","dist-tags":{"latest":"2.0.0"},"versions":{"1.0.0":{"name":"ci-info","version":"1.0.0","description":"Get details about the current Continuous Integration environment","main":"index.js","dependencies":{},"devDependencies":{"clear-require":"^1.0.1","standard":"^8.4.0"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"git+https://github.com/watson/ci-info.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/ci-info/issues"},"homepage":"https://github.com/watson/ci-info","coordinates":[55.68768499999999,12.5955698],"gitHead":"b9b1629b602f09ff8ee0b6158bfd16bb5af432b3","_id":"ci-info@1.0.0","_shasum":"dc5285f2b4e251821683681c381c3388f46ec534","_from":".","_npmVersion":"2.15.9","_nodeVersion":"4.5.0","_npmUser":{"name":"watson","email":"w@tson.dk"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"dist":{"shasum":"dc5285f2b4e251821683681c381c3388f46ec534","tarball":"https://registry.npmjs.org/ci-info/-/ci-info-1.0.0.tgz"},"_npmOperationalInternal":{"host":"packages-12-west.internal.npmjs.com","tmp":"tmp/ci-info-1.0.0.tgz_1476979279035_0.6885495139285922"},"directories":{}},"1.0.1":{"name":"ci-info","version":"1.0.1","description":"Get details about the current Continuous Integration environment","main":"index.js","dependencies":{},"devDependencies":{"clear-require":"^1.0.1","standard":"^8.4.0"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"git+https://github.com/watson/ci-info.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/ci-info/issues"},"homepage":"https://github.com/watson/ci-info","coordinates":[55.6773705,12.5614183],"gitHead":"aac11e070bf228af71192d8720c2dff6ad2b56ba","_id":"ci-info@1.0.1","_npmVersion":"5.3.0","_nodeVersion":"8.2.1","_npmUser":{"name":"watson","email":"w@tson.dk"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"dist":{"integrity":"sha512-u+kVhyCfR37aSKEneBwRcsff8tCLIyBvngsqL/fgOoWJsBhSFVVRaXWUI3HuAQKu8cLawFFRxNxpDUktZUXScw==","shasum":"e5913b63f7e1fda8db99a3125d45cbabcde55ba9","tarball":"https://registry.npmjs.org/ci-info/-/ci-info-1.0.1.tgz"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ci-info-1.0.1.tgz_1504539054919_0.6077480302192271"},"directories":{}},"1.1.0":{"name":"ci-info","version":"1.1.0","description":"Get details about the current Continuous Integration environment","main":"index.js","dependencies":{},"devDependencies":{"clear-require":"^1.0.1","standard":"^8.4.0"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"git+https://github.com/watson/ci-info.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/ci-info/issues"},"homepage":"https://github.com/watson/ci-info","coordinates":[55.681141,12.5643633],"gitHead":"4142f07e702c4b9aeb9d7161df815c2043d2f96f","_id":"ci-info@1.1.0","_npmVersion":"5.3.0","_nodeVersion":"8.2.1","_npmUser":{"name":"watson","email":"w@tson.dk"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"dist":{"integrity":"sha512-Kdy57gJlQwVmleFb/XKd1ZJ/iSgYGlh2sKeT8uY4t544qv27FdcnWvb1BH8LKok2lgdKa/w5qHlvAOqz2NR0bA==","shasum":"37f6e917002864c263af2579cedcb4abb24fa467","tarball":"https://registry.npmjs.org/ci-info/-/ci-info-1.1.0.tgz"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ci-info-1.1.0.tgz_1504611213844_0.9689220797736198"},"directories":{}},"1.1.1":{"name":"ci-info","version":"1.1.1","description":"Get details about the current Continuous Integration environment","main":"index.js","dependencies":{},"devDependencies":{"clear-require":"^1.0.1","standard":"^10.0.3"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"git+https://github.com/watson/ci-info.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/ci-info/issues"},"homepage":"https://github.com/watson/ci-info","coordinates":[55.6773705,12.5614183],"gitHead":"e75edeafca0330955d71ee0eb0ea4af412d63003","_id":"ci-info@1.1.1","_npmVersion":"5.4.0","_nodeVersion":"8.2.1","_npmUser":{"name":"watson","email":"w@tson.dk"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"dist":{"integrity":"sha512-vHDDF/bP9RYpTWtUhpJRhCFdvvp3iDWvEbuDbWgvjUrNGV1MXJrE0MPcwGtEled04m61iwdBLUIHZtDgzWS4ZQ==","shasum":"47b44df118c48d2597b56d342e7e25791060171a","tarball":"https://registry.npmjs.org/ci-info/-/ci-info-1.1.1.tgz"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ci-info-1.1.1.tgz_1504612390657_0.2857714928686619"},"directories":{}},"1.1.2":{"name":"ci-info","version":"1.1.2","description":"Get details about the current Continuous Integration environment","main":"index.js","dependencies":{},"devDependencies":{"clear-require":"^1.0.1","standard":"^10.0.3"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"git+https://github.com/watson/ci-info.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/ci-info/issues"},"homepage":"https://github.com/watson/ci-info","coordinates":[55.777569,12.589702],"gitHead":"bd4e2a1e4ff616764c4967e83f3e3b3c415ae476","_id":"ci-info@1.1.2","_npmVersion":"5.5.1","_nodeVersion":"9.2.0","_npmUser":{"name":"watson","email":"w@tson.dk"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"dist":{"integrity":"sha512-uTGIPNx/nSpBdsF6xnseRXLLtfr9VLqkz8ZqHXr3Y7b6SftyRxBGjwMtJj1OhNbmlc1wZzLNAlAcvyIiE8a6ZA==","shasum":"03561259db48d0474c8bdc90f5b47b068b6bbfb4","tarball":"https://registry.npmjs.org/ci-info/-/ci-info-1.1.2.tgz"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ci-info-1.1.2.tgz_1510945915514_0.49366038176231086"},"directories":{}},"1.1.3":{"name":"ci-info","version":"1.1.3","description":"Get details about the current Continuous Integration environment","main":"index.js","dependencies":{},"devDependencies":{"clear-require":"^1.0.1","standard":"^10.0.3"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"git+https://github.com/watson/ci-info.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/ci-info/issues"},"homepage":"https://github.com/watson/ci-info","coordinates":[55.777613,12.589943],"gitHead":"a8d33c93296bcca821b0b9b56d4567dcf5393235","_id":"ci-info@1.1.3","_npmVersion":"5.7.1","_nodeVersion":"9.6.1","_npmUser":{"name":"watson","email":"w@tson.dk"},"dist":{"integrity":"sha512-SK/846h/Rcy8q9Z9CAwGBLfCJ6EkjJWdpelWDufQpqVDYq2Wnnv8zlSO6AMQap02jvhVruKKpEtQOufo3pFhLg==","shasum":"710193264bb05c77b8c90d02f5aaf22216a667b2","tarball":"https://registry.npmjs.org/ci-info/-/ci-info-1.1.3.tgz","fileCount":4,"unpackedSize":6120},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ci-info_1.1.3_1520884277112_0.3492393126009503"},"_hasShrinkwrap":false},"1.2.0":{"name":"ci-info","version":"1.2.0","description":"Get details about the current Continuous Integration environment","main":"index.js","dependencies":{},"devDependencies":{"clear-require":"^1.0.1","standard":"^10.0.3"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"git+https://github.com/watson/ci-info.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/ci-info/issues"},"homepage":"https://github.com/watson/ci-info","coordinates":[55.6809148,12.5644041],"gitHead":"cf3fbe16d1b1dc4a14ed41267cc5439fce61b557","_id":"ci-info@1.2.0","_npmVersion":"6.2.0","_nodeVersion":"10.8.0","_npmUser":{"name":"watson","email":"w@tson.dk"},"dist":{"integrity":"sha512-U4aoLsSz44FhOyZ2E7bCufaBr2IUzNYujBd+b9vHiFH7SUzIhKcD94PQP5QSFn7ngPof6OF2yPk4/hygqwMJhA==","shasum":"8d1e9cb4051482ff70cd52a89b4b095a8fb635f6","tarball":"https://registry.npmjs.org/ci-info/-/ci-info-1.2.0.tgz","fileCount":5,"unpackedSize":7142,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbcpKdCRA9TVsSAnZWagAA5hQP/jCwmJ7c7vBO3N9GjA2M\nUqSjQoWKJEANIO2j3AovAFU0KlzLzxXHSjYa26oOCJ9uzwc1Lv6hM42jo8kS\n+uPi9+fGgk2eTbEtNTY1pjqDHpxHtgiFl/edXfRLg1ppWnMDtjMDF2EHREOS\nffZ1SQD5o47rIRuGBbjOkoZnE9Nf0EfyEvpXaAoJfJCfHzdTiHLj/84hjGE3\nsFGkd4ldtTGaCuKhf+DYsEm/L9KcZtNr3rOUfoKPhKG4iAUOTLS9LDavTDL+\nJS3hefGZuvmNHNnSaV/VVvodFRa7Ojk+AcLX6Ka4fbggLgNmLLjRkE+2SAXu\nMQjpXlDnrysQi+1swp8sM4bGqaknAe6noMqH2q9Z+CcTr2jerud3Wt5FJtpf\nzQP+zu42wSZz+SkHfMoJMD6pD8IRtBDoSW3m7NBZYKjO7Z4r3XCZaH6wG7kC\nAKsu8pq4mnr0cWjc1kNXyIGOc+VPkQD1dsSf3Szwso8yYRr7j8xuPHtD5M8n\n5p6/CWDoPBTK7qHFoBfrz1TI7sgqqKrUaKO6Ty1N7IwW48YpgkJ+tesfLRSr\nP1p7tCMkbnZh0MZtWPZbHxCv99pyAz9gHAJtbU4tsZ6FU0dhXRqjoSox8+wz\nm24hguI1KPEobNPfZW7IN45GYI050vwVevulylXXg5ilWqVAyI9PZuPPbTjy\nW0co\r\n=Coai\r\n-----END PGP SIGNATURE-----\r\n"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ci-info_1.2.0_1534235293084_0.09870438557547523"},"_hasShrinkwrap":false},"1.3.0":{"name":"ci-info","version":"1.3.0","description":"Get details about the current Continuous Integration environment","main":"index.js","dependencies":{},"devDependencies":{"clear-require":"^1.0.1","standard":"^11.0.1"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"git+https://github.com/watson/ci-info.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/ci-info/issues"},"homepage":"https://github.com/watson/ci-info","coordinates":[55.777197,12.592028],"gitHead":"fc23ab9ad05a32d690eacdef5821d691bfc48a65","_id":"ci-info@1.3.0","_npmVersion":"6.2.0","_nodeVersion":"10.8.0","_npmUser":{"name":"watson","email":"w@tson.dk"},"dist":{"integrity":"sha512-mPdvoljUhH3Feai3dakD3bwYl/8I0tSo16Ge2W+tY88yfYDKGVnXV2vFxZC8VGME01CYp+DaAZnE93VHYVapnA==","shasum":"ea8219b0355a58692b762baf1cdd76ceb4503283","tarball":"https://registry.npmjs.org/ci-info/-/ci-info-1.3.0.tgz","fileCount":5,"unpackedSize":7526,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbc0eTCRA9TVsSAnZWagAAFQoP/3IS1P2bKTht9EcFb353\nd/uNyp+EKFKb2gOKPG5cZWiFZOSnfNEsBf84sdR4g8WcGIHyvejV43H8NTNq\nVC2AjlP/aWcRs4Ocmr8olkl6+p6yM/H2zZRLWnalPBytoKiqtxmLsCqwZAy+\n7thjekY5Buyh088udaNYFHtz68lT0DG+a1LbvVMWL5l2RNImXMgLXCpEk7sd\nS5e8RzJSwVrtTjm4lqyg9EGTY7QBS5JcRxsEoHx7rRP9j/eKIUO+eI+uC50j\nG3YjQJgZ2hAVPxIsWLU/zpjIvlTNKuS/cnMF1hk6ND9rs5Z4lJlEgAAIu9rN\nNGRdGJ2LcYn3YntzkIorRB8v+UfiVTWBTSom9XgA+VwaSLcA+o6IIb46mv3K\nk29lWXlgkyds2+9pifGcb7UfIDWr/2uejuodsjiyAVtJJDwh5BW59XrMkM81\nsFNgSR3z94UBXAQUd3hG7pPxXNiApAiV03iDL+qI42VAG1IPfx66XUMwtnVw\nEAf/B1G5s98862EJIS5qrRl/fjXi/bf8+DyqjnGOnqk2FgRKpvxnhEMet75K\nHXp/PwX+4vLG2j1bGC062GkqEbfGG9fASUG57aD/Zp8RIUQbhSjs4LsiIKST\nVRyUMbUY34gNePaojZcEYMwixLlk/MxRm6OuVH6iZevbVJ9F5IVdjCkVNf1/\n0xSt\r\n=70AB\r\n-----END PGP SIGNATURE-----\r\n"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ci-info_1.3.0_1534281618862_0.3978395804022148"},"_hasShrinkwrap":false},"1.3.1":{"name":"ci-info","version":"1.3.1","description":"Get details about the current Continuous Integration environment","main":"index.js","dependencies":{},"devDependencies":{"clear-require":"^1.0.1","standard":"^11.0.1"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"git+https://github.com/watson/ci-info.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/ci-info/issues"},"homepage":"https://github.com/watson/ci-info","coordinates":[55.777514,12.592202],"gitHead":"fe48e8e67211262d10bfc8744cdcb1b69c921b95","_id":"ci-info@1.3.1","_npmVersion":"6.2.0","_nodeVersion":"10.8.0","_npmUser":{"name":"watson","email":"w@tson.dk"},"dist":{"integrity":"sha512-l4wK/SFEN8VVTQ9RO1I5yzIL2vw1w6My29qA6Gwaec80QeHxfXbruuUWqn1knyMoJn/X5kav3zVY1TlRHSKeIA==","shasum":"da21bc65a5f0d0d250c19a169065532b42fa048c","tarball":"https://registry.npmjs.org/ci-info/-/ci-info-1.3.1.tgz","fileCount":4,"unpackedSize":6612,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbdZx+CRA9TVsSAnZWagAAKDMP/1ETs7jSSHS0tUlOPCZx\nzFUqUhtSQoxaRZ3xQLI5C2OihxCdYVdXMRCaDpBUebLBHLl9unR8zMtdS3kp\nrGw1xWi3EbLfraRXceHh5CMHJNM2HUf37VOxcqMOlv3P0zt2aLjrx+radMCm\nSlIbAtaUlNs4rLzHITK5yXCZObOVnK3b1123OKWkE8SsKkOWYYlJ1Ginuq3g\nW/CrDswcgbNtN9Gzb9cXJeaZuuJ5snrQV2xkR/4XHbUFmVGM01Fs290uZ9Vv\nKQddshENl+n/BhsROsqsxlyg208enGVZYZozeJYMk1sH9MHigNUYJjteAzEo\nQJ7+2DrODwAZl7sQcAqk0QJ8Re0rv0zSJqaQaxXUphS6hOQZ4pkXSLJx23Gh\n0wJ6/ONjzm/T9uxydcWawLitFgtHLSrwJKMD0SN30bzWsH2P7Qq6q4jfFLEx\n0qENy0g0ZK++eaSyuO48gtNLxpfeR2WV4ESBCAyCtC6aFsL73mem26JfriPj\nTz8rQ+QCK91gllw58kl/Hr5CIw/WwDSDfoGQ7lacUCn80LUvLvPAa9g0aMfH\nMpTndzYQOebI7BR2Y0sJmszKiboz753rfihk+0Ljwy2Be9BFJ444duYjiIfu\ndFxBVPxPyTdSvAD7oAuwQ1QOoDi8YAbdiGVKZkvETE8yt1Plgyh0ur5uqHJU\nEga5\r\n=+CgS\r\n-----END PGP SIGNATURE-----\r\n"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ci-info_1.3.1_1534434429486_0.6573735856162741"},"_hasShrinkwrap":false},"1.4.0":{"name":"ci-info","version":"1.4.0","description":"Get details about the current Continuous Integration environment","main":"index.js","dependencies":{},"devDependencies":{"clear-require":"^1.0.1","standard":"^11.0.1"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"git+https://github.com/watson/ci-info.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/ci-info/issues"},"homepage":"https://github.com/watson/ci-info","coordinates":[55.0113914,14.9747494],"gitHead":"5f1b8850452ad7be2ced88711cc3087d854c1878","_id":"ci-info@1.4.0","_npmVersion":"6.2.0","_nodeVersion":"10.8.0","_npmUser":{"name":"watson","email":"w@tson.dk"},"dist":{"integrity":"sha512-Oqmw2pVfCl8sCL+1QgMywPfdxPJPkC51y4usw0iiE2S9qnEOAqXy8bwl1CpMpnoU39g4iKJTz6QZj+28FvOnjQ==","shasum":"4841d53cad49f11b827b648ebde27a6e189b412f","tarball":"https://registry.npmjs.org/ci-info/-/ci-info-1.4.0.tgz","fileCount":5,"unpackedSize":8012,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbepCFCRA9TVsSAnZWagAA9RoQAJSxL0P6PUyfjG+ClvG+\nlAAjyF3V5vi/LDrK4ULf9vHhLKGNXYugaGsrIdf+sA1yx6WIwpkMpV2PCaZR\nNuSHDIdheOY2IvrQI6lUE01dbWHg9sTWsJUO372Te6Sj9LSwqAJd4exfhNr/\n9E9VZklGlp9/kOVlucSZrvcUPh7DzjGs1ym/Ng1QnpHWltP5GIgqGiwJds2J\nnUineJxFdqC9Yf/jitbfX35cDruk378VYpNjZG5dewy6k+ZQLg58rAGDTyDR\nge7LTMasne0eTk96w/SB8++4wy4kafY5ZlIUHjtHQmT7ge1mJT0zaqBZDGh3\nCtY/n0n0ypx+iJtdIjoazAH+VNxMYH/8RGsfq0+RcDOWUufLHWzUV0S/eJVi\n0sDTvVKrFGGaUj5AdlOEx0AEKz62DqjYMungUIOKf21/GolF1Md8BJ5hQqHf\nyns3bbFnEq5OzgxOTdGqZ7dXCgTRyYqeYMZZDObgDglGOMth5ckBGbs/yv7H\nTaxe9HdZGGxNBNr8whWAqTPGW6zkSI21jtc7v3YvIzzoVafED2AvamnfB9+d\nKkFan2HKKdCOxUabj2wcmfeEXuGa/voJaZj2Cr77zxTmUcrKdjWAF1J9RxSN\nZx3sxetKi2zgqn4uCRQidqS5wDrx9jorm05nl4CyFr7Grr0dJOdSr5bfAgqf\nKGLj\r\n=dyHn\r\n-----END PGP SIGNATURE-----\r\n"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ci-info_1.4.0_1534759044627_0.7635631480866367"},"_hasShrinkwrap":false},"1.5.0":{"name":"ci-info","version":"1.5.0","description":"Get details about the current Continuous Integration environment","main":"index.js","dependencies":{},"devDependencies":{"clear-require":"^1.0.1","standard":"^12.0.1","tape":"^4.9.1"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"git+https://github.com/watson/ci-info.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/ci-info/issues"},"homepage":"https://github.com/watson/ci-info","coordinates":[55.776761,12.592082],"gitHead":"32a557ca8e9e193dbca085773842e4db4aa98752","_id":"ci-info@1.5.0","_npmVersion":"6.4.1","_nodeVersion":"10.10.0","_npmUser":{"name":"watson","email":"w@tson.dk"},"dist":{"integrity":"sha512-Bx/xWOzip4whERIvC97aIHjWCa8FxEn0ezng0oVn4kma6p+90Fbs3bTcJw6ZL0da2EPHydxsXJPZxNUv5oWb1Q==","shasum":"38327c69e98dab18487744b84e5d6e841a09a1a7","tarball":"https://registry.npmjs.org/ci-info/-/ci-info-1.5.0.tgz","fileCount":6,"unpackedSize":10579,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJblGJVCRA9TVsSAnZWagAA1/oP/i9cxFjqPcE57cdVRFiv\n6bpRVlJ2LMfhGPpsACbDIUdUoku2SE23DnUUvjrahhWvfgStwzUsEOhug1OJ\nFW+uUKRxpsPBT4xnHVe9U0Zb+w/pzyH+qVcbL3JXJ0Ekmc0mdB8omb1spYB7\ninssw1kbCbNEyer9wixOOgXQlU6QJuCivPeyc5Fj6lQ8crUi8m0w7hnlP1z0\nGW9TJPjY9iKBCJ3nJfowmt6tjgrBR7jadVw8UnUfBeEPnNSN+upD/1/IFpfT\n7gvLVHRtBuJPCL7lMQl/sKZJJHggEXw9hhhXvFZ6l7XN5c0bNJrkMK1LpZr+\nkSLz0qS9KWnfOkWW7RAXCcQKL6DLtzQC6RTqSPCQMdHnI3rDLWPNrT6CYPtp\nZ7STW3bhZKlb6CG4SL50FGU2fXmc1ByJRutFt8CMIbYzUInwJb/9F4o0ptPE\nOJZRgSTRLTvc9xo/rxtvhAm4Ro9tn0b14/ZU/wkM5Ta5sU8NSgudnngF7cnA\nuWfWCGzs1ioFb3iEmvNyvjWSuA9cteskfa08jRWMA/vrjUMrc8VMxfPFLcXo\nuos/LavXIUdCwH2sXZUxtkPhd7kMYVsMFHY7bY4br6hI0VOxO2FpzOFQ9scH\nqRAKaYZsZKAB/wTIhYUDNeD9UzL/+Vu/eoCMpKzUu+v4tQ3EC+KNZgbh0mU5\nRxzk\r\n=gLea\r\n-----END PGP SIGNATURE-----\r\n"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ci-info_1.5.0_1536451156728_0.12514766830933355"},"_hasShrinkwrap":false},"1.5.1":{"name":"ci-info","version":"1.5.1","description":"Get details about the current Continuous Integration environment","main":"index.js","dependencies":{},"devDependencies":{"clear-require":"^1.0.1","standard":"^12.0.1","tape":"^4.9.1"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"git+https://github.com/watson/ci-info.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/ci-info/issues"},"homepage":"https://github.com/watson/ci-info","coordinates":[55.778273,12.593054],"gitHead":"d2837c895da577a1a63698d97fb6a78780c1c404","_id":"ci-info@1.5.1","_npmVersion":"6.4.1","_nodeVersion":"10.10.0","_npmUser":{"name":"watson","email":"w@tson.dk"},"dist":{"integrity":"sha512-fKFIKXaYiL1exImwJ0AhR/6jxFPSKQBk2ayV5NiNoruUs2+rxC2kNw0EG+1Z9dugZRdCrppskQ8DN2cyaUM1Hw==","shasum":"17e8eb5de6f8b2b6038f0cbb714d410bfa9f3030","tarball":"https://registry.npmjs.org/ci-info/-/ci-info-1.5.1.tgz","fileCount":6,"unpackedSize":10584,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJblPerCRA9TVsSAnZWagAAp9EP/3VdZoPIJEXby7IgLqTM\nJ7J3sCBTPb+Oxa2kd94Sav8EQ3KcA76HfYvCT7tvtTtChNlymZGz7LNfgmSJ\ncovADvxHZ5oglqEvfLLxSqlwMtq6jGABL91thJqBit72C4RNC4Ecyolkr6CE\nDINeteOjFLlJDGAaCXbdw32+FYCyufJFNnbl1mpF6oeSil6ACtIcTwnGLu1R\nUXsTG9YJcQlDe1WZmpufdHv2i9GP/BeQD1fRIHxwjkjCNtR8Xp5knyw6Yedr\nAbJTdxMvJds8rGLGsSRvyIYR5HrAUM96PXgpwyTR2CWmGJ9u+zE7q3BCvFWq\nVtLHZGu6ew09S8d//b0V5ASaytGVzyQPavRjAQ5wibZHT9b/5pbj/sqSqJjE\njZIC/pa5dlG+Lt4sSF80R5+bm704Jmh+PX96z/aQGb2IQMoNaWVKvBsN2rod\n+AuzQZyX25RLCeFVKJLCf9SET8pTz+R9Aj3vVw+rcRh5Xdhi/E3D9w8Hc+wR\nBcsPKHjZGN6kRFHsI7Rjk8OUs5cLDtU366UNlBVMEShJYMRLEpw0N5EJI4SU\nLGZ8kEDO53Pvj0M71HadECDJVXgm+g73yoadvQaMTgCsnknCUANnIjtFqydc\n5jsSj8cUPelZ49Zg82dKnvxDr89GPHjkJ69b4ORkYpjXaRoBRZJOrzfvPCLH\nH2nw\r\n=AseE\r\n-----END PGP SIGNATURE-----\r\n"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ci-info_1.5.1_1536489386481_0.010115633667440393"},"_hasShrinkwrap":false},"1.6.0":{"name":"ci-info","version":"1.6.0","description":"Get details about the current Continuous Integration environment","main":"index.js","dependencies":{},"devDependencies":{"clear-require":"^1.0.1","standard":"^12.0.1","tape":"^4.9.1"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"git+https://github.com/watson/ci-info.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/ci-info/issues"},"homepage":"https://github.com/watson/ci-info","coordinates":[55.778271,12.593091],"gitHead":"3d07175c39b07090ab939471c47ef363ea74ab97","_id":"ci-info@1.6.0","_npmVersion":"6.4.1","_nodeVersion":"10.10.0","_npmUser":{"name":"watson","email":"w@tson.dk"},"dist":{"integrity":"sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==","shasum":"2ca20dbb9ceb32d4524a683303313f0304b1e497","tarball":"https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz","fileCount":6,"unpackedSize":11845,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJbo1wtCRA9TVsSAnZWagAANfwP/ROk4A97KwBmsJw5o/ev\nlaftMiVwnI/966mQ6Ak1GfTWx28SjLWKnE+IGKK+1dXDOoXrb6td8TCl/FUQ\n2e7khqDoPswsPtUJfJWY4dYCtS8UfvfJk6BlsMR7ebHxDc9dVpIhZ+V0MpVk\n7HdW3ay5sGoLUXenULN/8WoaRkpujVPJ9sltX25ZkEj1fvGuF33VszNAC7b5\nYXRKCPVFsMZF7APoJiMs9120tlIdw+uiT812ZY6QiwX0HlcHnYswE33h70NA\nZ7Od1js8nAWpdZi1FPiJtCQtl99iAIZboBijRhpkDILdeGR8S/f25HDTvjHW\n3oXk5/Im6hzFnPYezUs3EKf4GT92Bs4fDuCF8Sp1EoChtE+r35L09WFNRKzE\npp7L4+ZHPsszHz44z7Q84TZKtmBPX51fwoTSL//2ix1g31ZrMfYuvCA/s1Yf\n7+3IVlNMW0sUnzGepgF8+jevtOE238XcLHBrTl4LhTsSwmEyR9sRKs6xD1Lx\nQbmyBRWpsluaHnmxaQVoVxzJCz0J7RReE6/UUfGzzmeF6vrKtd6eCv2ZUECk\nSQwVW90PUjr1IgPaVa8stjq9kFxQtG0mwTS2eEO+gxM3hb0RT2t3ecdG3Zq9\n0INHULVlKDtKMXpoQ2QEV3XaZM0X2j2sqnQxuYsQHt6Al45Q43rcz/yGgjWT\nICTT\r\n=iAOM\r\n-----END PGP SIGNATURE-----\r\n"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ci-info_1.6.0_1537432620983_0.7446311114890938"},"_hasShrinkwrap":false},"2.0.0":{"name":"ci-info","version":"2.0.0","description":"Get details about the current Continuous Integration environment","main":"index.js","dependencies":{},"devDependencies":{"clear-require":"^1.0.1","standard":"^12.0.1","tape":"^4.9.1"},"scripts":{"test":"standard && node test.js"},"repository":{"type":"git","url":"git+https://github.com/watson/ci-info.git"},"keywords":["ci","continuous","integration","test","detect"],"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"license":"MIT","bugs":{"url":"https://github.com/watson/ci-info/issues"},"homepage":"https://github.com/watson/ci-info","coordinates":[55.778231,12.593179],"gitHead":"18fe88088b626a6dcefc66e66fb32badb05ea216","_id":"ci-info@2.0.0","_npmVersion":"6.4.1","_nodeVersion":"11.3.0","_npmUser":{"name":"watson","email":"w@tson.dk"},"dist":{"integrity":"sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==","shasum":"67a9e964be31a51e15e5010d58e6f12834002f46","tarball":"https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz","fileCount":6,"unpackedSize":12808,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.4\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJcCEClCRA9TVsSAnZWagAAew4P/32dPsJ9LK3e9rXxaZtj\n32KCjxPFBFTCTNQT0CYdSU0plsSDuyc0WLM+CXmlVHUDp9nSkqayo6prPQhV\n9qjDh7y0YPRSgQF+QXzMhlGafHTdkMXy3OVE/2DLSLD7DkeEe+4XL1H0sSke\n4rS/y2EtanHtkp0L7wdIrkdVveBqSMk952vkIjyT6ehqOQoz22n5HGZOJ2aD\nxkkDemY0tZwDFOcGRNMPj+3D6bvppIPt+daZEK2jCVk2rAIeTCV8UIvwpoPR\nNt+49d0q84iiV9Q1sYg6VYv7qGjLgDPXoZwFw1NEnp6bOccT5mvCV7+jPeup\nw6S92VLOFP1ovGYX8EwvYXXOzw+bjCoqGUUSNf4IuMOA736G+nWXFkIVEi4M\n+jZSr8LYLo+ehabsqseDqlCLtKrWG7hXreqSgUaFuXn+qbu3LSicaWVs2VUs\nUeddGWOVcYJuJpoVy+emVbqH9MN9rRDm18/FI6We+u6u+ES9MtxRV6wcefaM\nHOaUUKI7phseccZUIIlu5EdFAE8pnCaBB9q7yTSva7DvtaesSEH4IS99dvzQ\ndIx6ASWwq4Djkse4dybrXIMQTSMy2FSKQDabHVFG1WC7RuckSg6T4im8cN7E\nHWwBEf1SivrkTUCoJ8UsWmnZA1A0R/0MiiN2q5/DUtEq6G2BDLs914AjCgrV\npShr\r\n=Du3l\r\n-----END PGP SIGNATURE-----\r\n"},"maintainers":[{"name":"watson","email":"w@tson.dk"}],"directories":{},"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/ci-info_2.0.0_1544044708403_0.40541284673323297"},"_hasShrinkwrap":false}},"readme":"# ci-info\n\nGet details about the current Continuous Integration environment.\n\nPlease [open an\nissue](https://github.com/watson/ci-info/issues/new?template=ci-server-not-detected.md)\nif your CI server isn't properly detected :)\n\n[![npm](https://img.shields.io/npm/v/ci-info.svg)](https://www.npmjs.com/package/ci-info)\n[![Build status](https://travis-ci.org/watson/ci-info.svg?branch=master)](https://travis-ci.org/watson/ci-info)\n[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](https://github.com/feross/standard)\n\n## Installation\n\n```bash\nnpm install ci-info --save\n```\n\n## Usage\n\n```js\nvar ci = require('ci-info')\n\nif (ci.isCI) {\n console.log('The name of the CI server is:', ci.name)\n} else {\n console.log('This program is not running on a CI server')\n}\n```\n\n## Supported CI tools\n\nOfficially supported CI servers:\n\n| Name | Constant | isPR |\n|------|----------|------|\n| [AWS CodeBuild](https://aws.amazon.com/codebuild/) | `ci.CODEBUILD` | 🚫 |\n| [AppVeyor](http://www.appveyor.com) | `ci.APPVEYOR` | ✅ |\n| [Azure Pipelines](https://azure.microsoft.com/en-us/services/devops/pipelines/) | `ci.AZURE_PIPELINES` | ✅ |\n| [Bamboo](https://www.atlassian.com/software/bamboo) by Atlassian | `ci.BAMBOO` | 🚫 |\n| [Bitbucket Pipelines](https://bitbucket.org/product/features/pipelines) | `ci.BITBUCKET` | ✅ |\n| [Bitrise](https://www.bitrise.io/) | `ci.BITRISE` | ✅ |\n| [Buddy](https://buddy.works/) | `ci.BUDDY` | ✅ |\n| [Buildkite](https://buildkite.com) | `ci.BUILDKITE` | ✅ |\n| [CircleCI](http://circleci.com) | `ci.CIRCLE` | ✅ |\n| [Cirrus CI](https://cirrus-ci.org) | `ci.CIRRUS` | ✅ |\n| [Codeship](https://codeship.com) | `ci.CODESHIP` | 🚫 |\n| [Drone](https://drone.io) | `ci.DRONE` | ✅ |\n| [dsari](https://github.com/rfinnie/dsari) | `ci.DSARI` | 🚫 |\n| [GitLab CI](https://about.gitlab.com/gitlab-ci/) | `ci.GITLAB` | 🚫 |\n| [GoCD](https://www.go.cd/) | `ci.GOCD` | 🚫 |\n| [Hudson](http://hudson-ci.org) | `ci.HUDSON` | 🚫 |\n| [Jenkins CI](https://jenkins-ci.org) | `ci.JENKINS` | ✅ |\n| [Magnum CI](https://magnum-ci.com) | `ci.MAGNUM` | 🚫 |\n| [Netlify CI](https://www.netlify.com/) | `ci.NETLIFY` | ✅ |\n| [Sail CI](https://sail.ci/) | `ci.SAIL` | ✅ |\n| [Semaphore](https://semaphoreci.com) | `ci.SEMAPHORE` | ✅ |\n| [Shippable](https://www.shippable.com/) | `ci.SHIPPABLE` | ✅ |\n| [Solano CI](https://www.solanolabs.com/) | `ci.SOLANO` | ✅ |\n| [Strider CD](https://strider-cd.github.io/) | `ci.STRIDER` | 🚫 |\n| [TaskCluster](http://docs.taskcluster.net) | `ci.TASKCLUSTER` | 🚫 |\n| [TeamCity](https://www.jetbrains.com/teamcity/) by JetBrains | `ci.TEAMCITY` | 🚫 |\n| [Travis CI](http://travis-ci.org) | `ci.TRAVIS` | ✅ |\n\n## API\n\n### `ci.name`\n\nReturns a string containing name of the CI server the code is running on.\nIf CI server is not detected, it returns `null`.\n\nDon't depend on the value of this string not to change for a specific\nvendor. If you find your self writing `ci.name === 'Travis CI'`, you\nmost likely want to use `ci.TRAVIS` instead.\n\n### `ci.isCI`\n\nReturns a boolean. Will be `true` if the code is running on a CI server,\notherwise `false`.\n\nSome CI servers not listed here might still trigger the `ci.isCI`\nboolean to be set to `true` if they use certain vendor neutral\nenvironment variables. In those cases `ci.name` will be `null` and no\nvendor specific boolean will be set to `true`.\n\n### `ci.isPR`\n\nReturns a boolean if PR detection is supported for the current CI server. Will\nbe `true` if a PR is being tested, otherwise `false`. If PR detection is\nnot supported for the current CI server, the value will be `null`.\n\n### `ci.`\n\nA vendor specific boolean constant is exposed for each support CI\nvendor. A constant will be `true` if the code is determined to run on\nthe given CI server, otherwise `false`.\n\nExamples of vendor constants are `ci.TRAVIS` or `ci.APPVEYOR`. For a\ncomplete list, see the support table above.\n\nDeprecated vendor constants that will be removed in the next major\nrelease:\n\n- `ci.TDDIUM` (Solano CI) This have been renamed `ci.SOLANO`\n\n## License\n\n[MIT](LICENSE)\n","maintainers":[{"name":"watson","email":"w@tson.dk"}],"time":{"modified":"2019-01-08T05:32:48.012Z","created":"2016-10-20T16:01:20.750Z","1.0.0":"2016-10-20T16:01:20.750Z","1.0.1":"2017-09-04T15:30:55.785Z","1.1.0":"2017-09-05T11:33:34.768Z","1.1.1":"2017-09-05T11:53:11.571Z","1.1.2":"2017-11-17T19:11:56.371Z","1.1.3":"2018-03-12T19:51:17.183Z","1.2.0":"2018-08-14T08:28:13.186Z","1.3.0":"2018-08-14T21:20:19.004Z","1.3.1":"2018-08-16T15:47:09.554Z","1.4.0":"2018-08-20T09:57:24.747Z","1.5.0":"2018-09-08T23:59:16.943Z","1.5.1":"2018-09-09T10:36:26.599Z","1.6.0":"2018-09-20T08:37:01.113Z","2.0.0":"2018-12-05T21:18:28.926Z"},"homepage":"https://github.com/watson/ci-info","keywords":["ci","continuous","integration","test","detect"],"repository":{"type":"git","url":"git+https://github.com/watson/ci-info.git"},"author":{"name":"Thomas Watson Steen","email":"w@tson.dk","url":"https://twitter.com/wa7son"},"bugs":{"url":"https://github.com/watson/ci-info/issues"},"license":"MIT","readmeFilename":"README.md","users":{"vdsabev":true,"hualei":true}} -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Fs = require('fs'); 4 | const Nock = require('nock'); 5 | const Path = require('path'); 6 | const Sinon = require('sinon'); 7 | 8 | const NodeSupport = require('..'); 9 | 10 | const OctokitWrapper = require('../lib/loader/octokit-wrapper'); 11 | const TestContext = require('./fixtures'); 12 | 13 | 14 | const { describe, it, beforeEach, afterEach } = exports.lab = require('@hapi/lab').script(); 15 | const { expect } = require('@hapi/code'); 16 | 17 | 18 | const internals = {}; 19 | 20 | 21 | internals.assertCommit = (result) => { 22 | 23 | expect(result.commit).to.match(/^[0-9a-f]{40}$/); 24 | delete result.commit; 25 | }; 26 | 27 | describe('detect-node-support', () => { 28 | 29 | let fixture; 30 | 31 | beforeEach(() => { 32 | 33 | fixture = new TestContext(); 34 | }); 35 | 36 | afterEach(() => { 37 | 38 | fixture.cleanup(); 39 | }); 40 | 41 | describe('detect()', () => { 42 | 43 | describe('path', () => { 44 | 45 | it('returns node versions from `.travis.yml` at the path', async () => { 46 | 47 | const path = Path.join(__dirname, '..'); 48 | 49 | const result = await NodeSupport.detect({ path }); 50 | 51 | internals.assertCommit(result); 52 | 53 | expect(result).to.equal({ 54 | name: 'detect-node-support', 55 | version: '0.0.0-development', 56 | timestamp: 1580673602000, 57 | travis: { 58 | raw: ['14', '12', '10'], 59 | resolved: { 60 | '10': '10.20.1', 61 | '12': '12.17.0', 62 | '14': '14.3.0' 63 | } 64 | }, 65 | engines: '>=14' 66 | }); 67 | }); 68 | 69 | it('leaves out `travis` when no `.travis.yml` present', async () => { 70 | 71 | await fixture.setupRepoFolder(); 72 | 73 | const result = await NodeSupport.detect({ path: fixture.path }); 74 | 75 | internals.assertCommit(result); 76 | 77 | expect(result).to.equal({ 78 | name: 'test-module', 79 | version: '0.0.0-development', 80 | timestamp: 1580673602000 81 | }); 82 | }); 83 | 84 | it('returns the single node version', async () => { 85 | 86 | await fixture.setupRepoFolder({ 87 | travisYml: 'testing-single-version.yml' 88 | }); 89 | 90 | const result = await NodeSupport.detect({ path: fixture.path }); 91 | 92 | internals.assertCommit(result); 93 | 94 | expect(result).to.equal({ 95 | name: 'test-module', 96 | version: '0.0.0-development', 97 | timestamp: 1580673602000, 98 | travis: { 99 | raw: ['10'], 100 | resolved: { '10': '10.20.1' } 101 | } 102 | }); 103 | }); 104 | 105 | it('returns default node version', async () => { 106 | 107 | await fixture.setupRepoFolder({ 108 | travisYml: 'testing-minimal.yml' 109 | }); 110 | 111 | const result = await NodeSupport.detect({ path: fixture.path }); 112 | 113 | internals.assertCommit(result); 114 | 115 | expect(result).to.equal({ 116 | name: 'test-module', 117 | version: '0.0.0-development', 118 | timestamp: 1580673602000, 119 | travis: { 120 | raw: ['latest'], 121 | resolved: { latest: '13.14.0' } 122 | } 123 | }); 124 | }); 125 | 126 | it('returns empty array when no node detected', async () => { 127 | 128 | await fixture.setupRepoFolder({ 129 | travisYml: 'testing-no-node.yml' 130 | }); 131 | 132 | const result = await NodeSupport.detect({ path: fixture.path }); 133 | 134 | internals.assertCommit(result); 135 | 136 | expect(result).to.equal({ 137 | name: 'test-module', 138 | version: '0.0.0-development', 139 | timestamp: 1580673602000, 140 | travis: { 141 | raw: [], 142 | resolved: {} 143 | } 144 | }); 145 | }); 146 | 147 | it('returns node versions from matrix env vars (NODEJS_VER)', async () => { 148 | 149 | await fixture.setupRepoFolder({ 150 | travisYml: 'kangax-html-minifier.yml' 151 | }); 152 | 153 | const result = await NodeSupport.detect({ path: fixture.path }); 154 | 155 | internals.assertCommit(result); 156 | 157 | expect(result).to.equal({ 158 | name: 'test-module', 159 | version: '0.0.0-development', 160 | timestamp: 1580673602000, 161 | travis: { 162 | raw: ['6', '8', '10', 'latest'], 163 | resolved: { 164 | '6': '6.17.1', 165 | '8': '8.17.0', 166 | '10': '10.20.1', 167 | latest: '13.14.0' 168 | } 169 | } 170 | }); 171 | }); 172 | 173 | it('returns node versions from matrix env vars (TRAVIS_NODE_VERSION)', async () => { 174 | 175 | await fixture.setupRepoFolder({ 176 | travisYml: 'nodejs-nan.yml' 177 | }); 178 | 179 | const result = await NodeSupport.detect({ path: fixture.path }); 180 | 181 | internals.assertCommit(result); 182 | 183 | expect(result).to.equal({ 184 | name: 'test-module', 185 | version: '0.0.0-development', 186 | timestamp: 1580673602000, 187 | travis: { 188 | raw: ['0.10', '0.12', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', 'lts/*'], 189 | resolved: { 190 | '0.10': '0.10.48', 191 | '0.12': '0.12.18', 192 | '4': '4.9.1', 193 | '5': '5.12.0', 194 | '6': '6.17.1', 195 | '7': '7.10.1', 196 | '8': '8.17.0', 197 | '9': '9.11.2', 198 | '10': '10.20.1', 199 | '11': '11.15.0', 200 | '12': '12.17.0', 201 | '13': '13.14.0', 202 | 'lts/*': '12.17.0' 203 | } 204 | } 205 | }); 206 | }); 207 | 208 | it('returns node versions from matrix env vars (NODE_VER)', async () => { 209 | 210 | await fixture.setupRepoFolder({ 211 | travisYml: 'reactivex-rxjs.yml' 212 | }); 213 | 214 | const result = await NodeSupport.detect({ path: fixture.path }); 215 | 216 | internals.assertCommit(result); 217 | 218 | expect(result).to.equal({ 219 | name: 'test-module', 220 | version: '0.0.0-development', 221 | timestamp: 1580673602000, 222 | travis: { 223 | raw: ['4', '6', '7'], 224 | resolved: { 225 | '4': '4.9.1', 226 | '6': '6.17.1', 227 | '7': '7.10.1' 228 | } 229 | } 230 | }); 231 | }); 232 | 233 | it('handles non-matching matrix env vars', async () => { 234 | 235 | await fixture.setupRepoFolder({ 236 | travisYml: 'caolan-async.yml' 237 | }); 238 | 239 | const result = await NodeSupport.detect({ path: fixture.path }); 240 | 241 | internals.assertCommit(result); 242 | 243 | expect(result).to.equal({ 244 | name: 'test-module', 245 | version: '0.0.0-development', 246 | timestamp: 1580673602000, 247 | travis: { 248 | raw: ['8', '10', '12'], 249 | resolved: { 250 | '8': '8.17.0', 251 | '10': '10.20.1', 252 | '12': '12.17.0' 253 | } 254 | } 255 | }); 256 | }); 257 | 258 | it('returns node versions from matrix include', async () => { 259 | 260 | await fixture.setupRepoFolder({ 261 | travisYml: 'nodejs-readable-stream.yml' 262 | }); 263 | 264 | const result = await NodeSupport.detect({ path: fixture.path }); 265 | 266 | internals.assertCommit(result); 267 | 268 | expect(result).to.equal({ 269 | name: 'test-module', 270 | version: '0.0.0-development', 271 | timestamp: 1580673602000, 272 | travis: { 273 | raw: ['6', '8', '9', '10', '12', 'stable'], 274 | resolved: { 275 | '6': '6.17.1', 276 | '8': '8.17.0', 277 | '9': '9.11.2', 278 | '10': '10.20.1', 279 | '12': '12.17.0', 280 | 'stable': '13.14.0' 281 | } 282 | } 283 | }); 284 | }); 285 | 286 | it('handles single matrix include', async () => { 287 | 288 | await fixture.setupRepoFolder({ 289 | travisYml: 'postcss-autoprefixer.yml' 290 | }); 291 | 292 | const result = await NodeSupport.detect({ path: fixture.path }); 293 | 294 | internals.assertCommit(result); 295 | 296 | expect(result).to.equal({ 297 | name: 'test-module', 298 | version: '0.0.0-development', 299 | timestamp: 1580673602000, 300 | travis: { 301 | raw: ['node', '10', '12', '8', '6'], 302 | resolved: { 303 | 'node': '13.14.0', 304 | '10': '10.20.1', 305 | '12': '12.17.0', 306 | '8': '8.17.0', 307 | '6': '6.17.1' 308 | } 309 | } 310 | }); 311 | }); 312 | 313 | it('handles matrix includes without node versions', async () => { 314 | 315 | await fixture.setupRepoFolder({ 316 | travisYml: 'shinn-is-resolvable.yml' 317 | }); 318 | 319 | const result = await NodeSupport.detect({ path: fixture.path }); 320 | 321 | internals.assertCommit(result); 322 | 323 | expect(result).to.equal({ 324 | name: 'test-module', 325 | version: '0.0.0-development', 326 | timestamp: 1580673602000, 327 | travis: { 328 | raw: ['node'], 329 | resolved: { node: '13.14.0' } 330 | } 331 | }); 332 | }); 333 | 334 | it('handles missing env.matrix', async () => { 335 | 336 | await fixture.setupRepoFolder({ 337 | travisYml: 'testing-no-env-matrix.yml' 338 | }); 339 | 340 | const result = await NodeSupport.detect({ path: fixture.path }); 341 | 342 | internals.assertCommit(result); 343 | 344 | expect(result).to.equal({ 345 | name: 'test-module', 346 | version: '0.0.0-development', 347 | timestamp: 1580673602000, 348 | travis: { 349 | raw: ['latest'], 350 | resolved: { latest: '13.14.0' } 351 | } 352 | }); 353 | }); 354 | 355 | it('handles invalid node versions', async () => { 356 | 357 | await fixture.setupRepoFolder({ 358 | travisYml: 'testing-invalid-version.yml' 359 | }); 360 | 361 | const result = await NodeSupport.detect({ path: fixture.path }); 362 | 363 | internals.assertCommit(result); 364 | 365 | expect(result).to.equal({ 366 | name: 'test-module', 367 | version: '0.0.0-development', 368 | timestamp: 1580673602000, 369 | travis: { 370 | raw: ['i-am-not-a-node-version'], 371 | resolved: { 'i-am-not-a-node-version': false } 372 | } 373 | }); 374 | }); 375 | 376 | it('handles duplicate key in .travis.yml', async () => { 377 | 378 | await fixture.setupRepoFolder({ 379 | travisYml: 'npm-promzard.yml' 380 | }); 381 | 382 | const result = await NodeSupport.detect({ path: fixture.path }); 383 | 384 | internals.assertCommit(result); 385 | 386 | expect(result).to.equal({ 387 | name: 'test-module', 388 | version: '0.0.0-development', 389 | timestamp: 1580673602000, 390 | travis: { 391 | raw: ['0.8', '0.10', '0.12', 'iojs'], 392 | resolved: { 393 | '0.8': '0.8.28', 394 | '0.10': '0.10.48', 395 | '0.12': '0.12.18', 396 | 'iojs': false 397 | } 398 | } 399 | }); 400 | }); 401 | 402 | it('throws when path is not a git repo', async () => { 403 | 404 | await fixture.setupRepoFolder({ git: false }); 405 | 406 | await expect(NodeSupport.detect({ path: fixture.path })) 407 | .to.reject(`${fixture.path} is not a git repository`); 408 | }); 409 | 410 | it('throws when path does not have a package.json', async () => { 411 | 412 | await fixture.setupRepoFolder({ 413 | travisYml: 'testing-no-node.yml', 414 | packageJson: false 415 | }); 416 | 417 | await expect(NodeSupport.detect({ path: fixture.path })) 418 | .to.reject(`${fixture.path} does not contain a package.json`); 419 | }); 420 | }); 421 | 422 | describe('repository', () => { 423 | 424 | it('returns node versions from `.travis.yml` in the repository', async () => { 425 | 426 | fixture.stubs.listRemote 427 | .returns('9cef39d21ad229dea4b10295f55b0d9a83800b23\tHEAD\n'); 428 | 429 | Nock('https://api.github.com') 430 | .get('/repos/pkgjs/detect-node-support/contents/package.json') 431 | .reply(200, { 432 | content: Fs.readFileSync(Path.join(__dirname, '..', 'package.json')).toString('base64') 433 | }) 434 | .get('/repos/pkgjs/detect-node-support/contents/.travis.yml') 435 | .reply(200, { 436 | content: Fs.readFileSync(Path.join(__dirname, '..', '.travis.yml')).toString('base64') 437 | }); 438 | 439 | const result = await NodeSupport.detect({ repository: 'git+https://github.com/pkgjs/detect-node-support.git' }); 440 | 441 | expect(fixture.stubs.listRemote.callCount).to.equal(1); 442 | expect(fixture.stubs.listRemote.args[0]).to.equal([['http://github.com/pkgjs/detect-node-support.git', 'HEAD']]); 443 | 444 | expect(result).to.equal({ 445 | name: 'detect-node-support', 446 | version: '0.0.0-development', 447 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23', 448 | timestamp: 1580673602000, 449 | travis: { 450 | raw: ['14', '12', '10'], 451 | resolved: { 452 | '10': '10.20.1', 453 | '12': '12.17.0', 454 | '14': '14.3.0' 455 | } 456 | }, 457 | engines: '>=14' 458 | }); 459 | }); 460 | 461 | it('supports "owner/repo" style repository string', async () => { 462 | 463 | fixture.stubs.listRemote 464 | .returns('9cef39d21ad229dea4b10295f55b0d9a83800b23\tHEAD\n'); 465 | 466 | Nock('https://api.github.com') 467 | .get('/repos/pkgjs/detect-node-support/contents/package.json') 468 | .reply(200, { 469 | content: Fs.readFileSync(Path.join(__dirname, '..', 'package.json')).toString('base64') 470 | }) 471 | .get('/repos/pkgjs/detect-node-support/contents/.travis.yml') 472 | .reply(200, { 473 | content: Fs.readFileSync(Path.join(__dirname, '..', '.travis.yml')).toString('base64') 474 | }); 475 | 476 | const result = await NodeSupport.detect({ repository: 'pkgjs/detect-node-support' }); 477 | 478 | expect(fixture.stubs.listRemote.callCount).to.equal(1); 479 | expect(fixture.stubs.listRemote.args[0]).to.equal([['http://github.com/pkgjs/detect-node-support', 'HEAD']]); 480 | 481 | expect(result).to.equal({ 482 | name: 'detect-node-support', 483 | version: '0.0.0-development', 484 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23', 485 | timestamp: 1580673602000, 486 | travis: { 487 | raw: ['14', '12', '10'], 488 | resolved: { 489 | '10': '10.20.1', 490 | '12': '12.17.0', 491 | '14': '14.3.0' 492 | } 493 | }, 494 | engines: '>=14' 495 | }); 496 | }); 497 | 498 | it('leaves out `travis` when no `.travis.yml` present', async () => { 499 | 500 | fixture.stubs.listRemote 501 | .returns('9cef39d21ad229dea4b10295f55b0d9a83800b23\tHEAD\n'); 502 | 503 | Nock('https://api.github.com') 504 | .get('/repos/pkgjs/detect-node-support/contents/package.json') 505 | .reply(200, { 506 | content: Fs.readFileSync(Path.join(__dirname, '..', 'package.json')).toString('base64') 507 | }) 508 | .get('/repos/pkgjs/detect-node-support/contents/.travis.yml') 509 | .reply(404); 510 | 511 | const result = await NodeSupport.detect({ repository: 'git+https://github.com/pkgjs/detect-node-support.git' }); 512 | 513 | expect(fixture.stubs.listRemote.callCount).to.equal(1); 514 | expect(fixture.stubs.listRemote.args[0]).to.equal([['http://github.com/pkgjs/detect-node-support.git', 'HEAD']]); 515 | 516 | expect(result).to.equal({ 517 | name: 'detect-node-support', 518 | version: '0.0.0-development', 519 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23', 520 | timestamp: 1580673602000, 521 | engines: '>=14' 522 | }); 523 | }); 524 | 525 | it('throws when loading `.travis.yml` fails', async () => { 526 | 527 | fixture.stubs.listRemote 528 | .returns('9cef39d21ad229dea4b10295f55b0d9a83800b23\tHEAD\n'); 529 | 530 | Nock('https://api.github.com') 531 | .get('/repos/pkgjs/detect-node-support/contents/package.json') 532 | .reply(200, { 533 | content: Fs.readFileSync(Path.join(__dirname, '..', 'package.json')).toString('base64') 534 | }) 535 | .get('/repos/pkgjs/detect-node-support/contents/.travis.yml') 536 | .reply(500, 'Simulated server error'); 537 | 538 | await expect(NodeSupport.detect({ repository: 'git+https://github.com/pkgjs/detect-node-support.git' })).to.reject('Simulated server error'); 539 | }); 540 | 541 | it('throws when repository does not have a package.json', async () => { 542 | 543 | fixture.stubs.listRemote 544 | .returns('9cef39d21ad229dea4b10295f55b0d9a83800b23\tHEAD\n'); 545 | 546 | Nock('https://api.github.com') 547 | .get('/repos/pkgjs/detect-node-support/contents/package.json') 548 | .reply(404) 549 | .get('/repos/pkgjs/detect-node-support/contents/.travis.yml') 550 | .reply(200, { 551 | content: Fs.readFileSync(Path.join(__dirname, '..', '.travis.yml')).toString('base64') 552 | }); 553 | 554 | await expect(NodeSupport.detect({ repository: 'git+https://github.com/pkgjs/detect-node-support.git' })) 555 | .to.reject(`git+https://github.com/pkgjs/detect-node-support.git does not contain a package.json`); 556 | }); 557 | 558 | it('rethrows server errors', async () => { 559 | 560 | Nock('https://api.github.com') 561 | .get('/repos/pkgjs/detect-node-support/contents/package.json') 562 | .reply(500) 563 | .get('/repos/pkgjs/detect-node-support/contents/.travis.yml') 564 | .reply(200, { 565 | content: Fs.readFileSync(Path.join(__dirname, '..', '.travis.yml')).toString('base64') 566 | }); 567 | 568 | const err = await expect(NodeSupport.detect({ repository: 'git+https://github.com/pkgjs/detect-node-support.git' })).to.reject(); 569 | expect(err.name).to.equal('HttpError'); 570 | }); 571 | 572 | it('rethrows generic errors', async () => { 573 | 574 | const err = new Error('Something went wrong'); 575 | 576 | Sinon.stub(OctokitWrapper, 'create').throws(err); 577 | 578 | await expect(NodeSupport.detect({ repository: 'git+https://github.com/pkgjs/detect-node-support.git' })) 579 | .to.reject('Something went wrong'); 580 | }); 581 | 582 | it('throws when a package does not live on public github.com', async () => { 583 | 584 | await expect(NodeSupport.detect({ repository: 'git+https://github.example.com/pkgjs/detect-node-support.git' })) 585 | .to.reject('Only github.com paths supported, feel free to PR at https://github.com/pkgjs/detect-node-support'); 586 | }); 587 | 588 | it('retries when rate limited', async () => { 589 | 590 | fixture.stubs.listRemote 591 | .returns('9cef39d21ad229dea4b10295f55b0d9a83800b23\tHEAD\n'); 592 | 593 | Nock('https://api.github.com') 594 | .get('/repos/pkgjs/detect-node-support/contents/package.json') 595 | .reply(200, { 596 | content: Fs.readFileSync(Path.join(__dirname, '..', 'package.json')).toString('base64') 597 | }) 598 | .get('/repos/pkgjs/detect-node-support/contents/.travis.yml') 599 | .reply(403, '', { 600 | 'x-ratelimit-limit': '60', 601 | 'x-ratelimit-remaining': '0', 602 | 'x-ratelimit-reset': `${Math.round(Date.now() / 1000) + 1}` 603 | }) 604 | .get('/repos/pkgjs/detect-node-support/contents/.travis.yml') 605 | .reply(200, { 606 | content: Fs.readFileSync(Path.join(__dirname, '..', '.travis.yml')).toString('base64') 607 | }); 608 | 609 | const result = await NodeSupport.detect({ repository: 'git+https://github.com/pkgjs/detect-node-support.git' }); 610 | 611 | expect(result).to.equal({ 612 | name: 'detect-node-support', 613 | version: '0.0.0-development', 614 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23', 615 | timestamp: 1580673602000, 616 | travis: { 617 | raw: ['14', '12', '10'], 618 | resolved: { 619 | '10': '10.20.1', 620 | '12': '12.17.0', 621 | '14': '14.3.0' 622 | } 623 | }, 624 | engines: '>=14' 625 | }); 626 | }); 627 | 628 | it('aborts on abuse limit', async () => { 629 | 630 | fixture.stubs.listRemote 631 | .returns('9cef39d21ad229dea4b10295f55b0d9a83800b23\tHEAD\n'); 632 | 633 | Nock('https://api.github.com') 634 | .get('/repos/pkgjs/detect-node-support/contents/package.json') 635 | .reply(200, { 636 | content: Fs.readFileSync(Path.join(__dirname, '..', 'package.json')).toString('base64') 637 | }) 638 | // https://docs.github.com/en/rest/overview/resources-in-the-rest-api#secondary-rate-limits 639 | .get('/repos/pkgjs/detect-node-support/contents/.travis.yml') 640 | .reply(403, 'You have exceeded a secondary rate limit'); 641 | 642 | await expect(NodeSupport.detect({ repository: 'git+https://github.com/pkgjs/detect-node-support.git' })).to.reject(/You have exceeded a secondary rate limit/); 643 | }); 644 | }); 645 | 646 | describe('packageName', () => { 647 | 648 | it('returns node versions from `.travis.yml` in the package repository', async () => { 649 | 650 | fixture.stubs.listRemote 651 | .returns('9cef39d21ad229dea4b10295f55b0d9a83800b23\tHEAD\n'); 652 | 653 | Nock('https://api.github.com', { 654 | reqheaders: { 655 | 'user-agent': /detect-node-support\/.* \(https:\/\/github.com\/pkgjs\/detect-node-support#readme\)/ 656 | } 657 | }) 658 | .get('/repos/pkgjs/detect-node-support/contents/package.json') 659 | .reply(200, { 660 | content: Fs.readFileSync(Path.join(__dirname, '..', 'package.json')).toString('base64') 661 | }) 662 | .get('/repos/pkgjs/detect-node-support/contents/.travis.yml') 663 | .reply(200, { 664 | content: Fs.readFileSync(Path.join(__dirname, '..', '.travis.yml')).toString('base64') 665 | }); 666 | 667 | Nock('https://registry.npmjs.org') 668 | .get('/detect-node-support') 669 | .reply(200, Fs.readFileSync(Path.join(__dirname, '..', 'package.json'))); 670 | 671 | const result = await NodeSupport.detect({ packageName: 'detect-node-support' }); 672 | 673 | expect(fixture.stubs.listRemote.callCount).to.equal(1); 674 | expect(fixture.stubs.listRemote.args[0]).to.equal([['http://github.com/pkgjs/detect-node-support.git', 'HEAD']]); 675 | 676 | expect(result).to.equal({ 677 | name: 'detect-node-support', 678 | version: '0.0.0-development', 679 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23', 680 | timestamp: 1580673602000, 681 | travis: { 682 | raw: ['14', '12', '10'], 683 | resolved: { 684 | '10': '10.20.1', 685 | '12': '12.17.0', 686 | '14': '14.3.0' 687 | } 688 | }, 689 | engines: '>=14' 690 | }); 691 | }); 692 | 693 | it('leaves out `travis` when no `.travis.yml` present', async () => { 694 | 695 | fixture.stubs.listRemote 696 | .returns('9cef39d21ad229dea4b10295f55b0d9a83800b23\tHEAD\n'); 697 | 698 | Nock('https://api.github.com') 699 | .get('/repos/pkgjs/detect-node-support/contents/package.json') 700 | .reply(200, { 701 | content: Fs.readFileSync(Path.join(__dirname, '..', 'package.json')).toString('base64') 702 | }) 703 | .get('/repos/pkgjs/detect-node-support/contents/.travis.yml') 704 | .reply(404); 705 | 706 | Nock('https://registry.npmjs.org') 707 | .get('/detect-node-support') 708 | .reply(200, Fs.readFileSync(Path.join(__dirname, '..', 'package.json'))); 709 | 710 | const result = await NodeSupport.detect({ packageName: 'detect-node-support' }); 711 | 712 | expect(fixture.stubs.listRemote.callCount).to.equal(1); 713 | expect(fixture.stubs.listRemote.args[0]).to.equal([['http://github.com/pkgjs/detect-node-support.git', 'HEAD']]); 714 | 715 | expect(result).to.equal({ 716 | name: 'detect-node-support', 717 | version: '0.0.0-development', 718 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23', 719 | timestamp: 1580673602000, 720 | engines: '>=14' 721 | }); 722 | }); 723 | 724 | it('throws when package does not exist in the registry', async () => { 725 | 726 | Nock('https://registry.npmjs.org') 727 | .get('/detect-node-support') 728 | .reply(404); 729 | 730 | await expect(NodeSupport.detect({ packageName: 'detect-node-support' })) 731 | .to.reject(`Package detect-node-support does not exist`); 732 | }); 733 | 734 | it('rethrows registry server errors', async () => { 735 | 736 | Nock('https://registry.npmjs.org') 737 | .get('/detect-node-support') 738 | .reply(500); 739 | 740 | await expect(NodeSupport.detect({ packageName: 'detect-node-support' })) 741 | .to.reject(/Internal Server Error/); 742 | }); 743 | 744 | it('rethrows generic errors', async () => { 745 | 746 | Nock('https://registry.npmjs.org') 747 | .get('/detect-node-support') 748 | .reply(200, Fs.readFileSync(Path.join(__dirname, '..', 'package.json'))); 749 | 750 | const err = new Error('Something went wrong'); 751 | 752 | Sinon.stub(OctokitWrapper, 'create').throws(err); 753 | 754 | await expect(NodeSupport.detect({ packageName: 'detect-node-support' })) 755 | .to.reject('Something went wrong'); 756 | }); 757 | 758 | it('throws when packument does not contain a `repository` field', async () => { 759 | 760 | Nock('https://registry.npmjs.org') 761 | .get('/detect-node-support') 762 | .reply(200, JSON.stringify({ name: 'detect-node-support' })); 763 | 764 | await expect(NodeSupport.detect({ packageName: 'detect-node-support' })) 765 | .to.reject('Unable to determine the git repository for detect-node-support'); 766 | }); 767 | 768 | it('throws when packument does not contain a `repository.url` field', async () => { 769 | 770 | Nock('https://registry.npmjs.org') 771 | .get('/detect-node-support') 772 | .reply(200, JSON.stringify({ name: 'detect-node-support', repository: {} })); 773 | 774 | await expect(NodeSupport.detect({ packageName: 'detect-node-support' })) 775 | .to.reject('Unable to determine the git repository for detect-node-support'); 776 | }); 777 | 778 | it('returns node versions from `.travis.yml` in the package repository (string repository)', async () => { 779 | 780 | fixture.stubs.listRemote 781 | .returns('9cef39d21ad229dea4b10295f55b0d9a83800b23\tHEAD\n'); 782 | 783 | Nock('https://api.github.com') 784 | .get('/repos/pkgjs/detect-node-support/contents/package.json') 785 | .reply(200, { 786 | content: Fs.readFileSync(Path.join(__dirname, '..', 'package.json')).toString('base64') 787 | }) 788 | .get('/repos/pkgjs/detect-node-support/contents/.travis.yml') 789 | .reply(200, { 790 | content: Fs.readFileSync(Path.join(__dirname, '..', '.travis.yml')).toString('base64') 791 | }); 792 | 793 | Nock('https://registry.npmjs.org') 794 | .get('/detect-node-support') 795 | .reply(200, JSON.stringify({ 796 | name: 'detect-node-support', 797 | repository: 'git+https://github.com/pkgjs/detect-node-support.git' 798 | })); 799 | 800 | const result = await NodeSupport.detect({ packageName: 'detect-node-support' }); 801 | 802 | expect(fixture.stubs.listRemote.callCount).to.equal(1); 803 | expect(fixture.stubs.listRemote.args[0]).to.equal([['http://github.com/pkgjs/detect-node-support.git', 'HEAD']]); 804 | 805 | expect(result).to.equal({ 806 | name: 'detect-node-support', 807 | version: '0.0.0-development', 808 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23', 809 | timestamp: 1580673602000, 810 | travis: { 811 | raw: ['14', '12', '10'], 812 | resolved: { 813 | '10': '10.20.1', 814 | '12': '12.17.0', 815 | '14': '14.3.0' 816 | } 817 | }, 818 | engines: '>=14' 819 | }); 820 | }); 821 | 822 | it('throws when repo package name does not match', async () => { 823 | 824 | fixture.stubs.listRemote 825 | .returns('9cef39d21ad229dea4b10295f55b0d9a83800b23\tHEAD\n'); 826 | 827 | Nock('https://api.github.com') 828 | .get('/repos/pkgjs/detect-node-support/contents/package.json') 829 | .reply(200, { 830 | content: Buffer.from(JSON.stringify({ name: 'something-else' })).toString('base64') 831 | }) 832 | .get('/repos/pkgjs/detect-node-support/contents/.travis.yml') 833 | .reply(200, { 834 | content: Fs.readFileSync(Path.join(__dirname, '..', '.travis.yml')).toString('base64') 835 | }); 836 | 837 | Nock('https://registry.npmjs.org') 838 | .get('/detect-node-support') 839 | .reply(200, Fs.readFileSync(Path.join(__dirname, '..', 'package.json'))); 840 | 841 | await expect(NodeSupport.detect({ packageName: 'detect-node-support' })) 842 | .to.reject('git+https://github.com/pkgjs/detect-node-support.git does not contain detect-node-support. Monorepo not supported: https://github.com/pkgjs/detect-node-support/issues/6'); 843 | }); 844 | }); 845 | 846 | describe('string (auto-detect)', () => { 847 | 848 | it('returns node versions from `.travis.yml` at the path', async () => { 849 | 850 | const path = Path.join(__dirname, '..'); 851 | 852 | const result = await NodeSupport.detect(path); 853 | 854 | internals.assertCommit(result); 855 | 856 | expect(result).to.equal({ 857 | name: 'detect-node-support', 858 | version: '0.0.0-development', 859 | timestamp: 1580673602000, 860 | travis: { 861 | raw: ['14', '12', '10'], 862 | resolved: { 863 | '10': '10.20.1', 864 | '12': '12.17.0', 865 | '14': '14.3.0' 866 | } 867 | }, 868 | engines: '>=14' 869 | }); 870 | }); 871 | 872 | it('returns node versions from `.travis.yml` in the repository (url case)', async () => { 873 | 874 | fixture.stubs.listRemote 875 | .returns('9cef39d21ad229dea4b10295f55b0d9a83800b23\tHEAD\n'); 876 | 877 | Nock('https://api.github.com') 878 | .get('/repos/pkgjs/detect-node-support/contents/package.json') 879 | .reply(200, { 880 | content: Fs.readFileSync(Path.join(__dirname, '..', 'package.json')).toString('base64') 881 | }) 882 | .get('/repos/pkgjs/detect-node-support/contents/.travis.yml') 883 | .reply(200, { 884 | content: Fs.readFileSync(Path.join(__dirname, '..', '.travis.yml')).toString('base64') 885 | }); 886 | 887 | const result = await NodeSupport.detect('git+https://github.com/pkgjs/detect-node-support.git'); 888 | 889 | expect(fixture.stubs.listRemote.callCount).to.equal(1); 890 | expect(fixture.stubs.listRemote.args[0]).to.equal([['http://github.com/pkgjs/detect-node-support.git', 'HEAD']]); 891 | 892 | expect(result).to.equal({ 893 | name: 'detect-node-support', 894 | version: '0.0.0-development', 895 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23', 896 | timestamp: 1580673602000, 897 | travis: { 898 | raw: ['14', '12', '10'], 899 | resolved: { 900 | '10': '10.20.1', 901 | '12': '12.17.0', 902 | '14': '14.3.0' 903 | } 904 | }, 905 | engines: '>=14' 906 | }); 907 | }); 908 | 909 | it('returns node versions from `.travis.yml` in the repository ("org/repo" case)', async () => { 910 | 911 | fixture.stubs.listRemote 912 | .returns('9cef39d21ad229dea4b10295f55b0d9a83800b23\tHEAD\n'); 913 | 914 | Nock('https://api.github.com') 915 | .get('/repos/pkgjs/detect-node-support/contents/package.json') 916 | .reply(200, { 917 | content: Fs.readFileSync(Path.join(__dirname, '..', 'package.json')).toString('base64') 918 | }) 919 | .get('/repos/pkgjs/detect-node-support/contents/.travis.yml') 920 | .reply(200, { 921 | content: Fs.readFileSync(Path.join(__dirname, '..', '.travis.yml')).toString('base64') 922 | }); 923 | 924 | const result = await NodeSupport.detect('pkgjs/detect-node-support'); 925 | 926 | expect(fixture.stubs.listRemote.callCount).to.equal(1); 927 | expect(fixture.stubs.listRemote.args[0]).to.equal([['http://github.com/pkgjs/detect-node-support', 'HEAD']]); 928 | 929 | expect(result).to.equal({ 930 | name: 'detect-node-support', 931 | version: '0.0.0-development', 932 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23', 933 | timestamp: 1580673602000, 934 | travis: { 935 | raw: ['14', '12', '10'], 936 | resolved: { 937 | '10': '10.20.1', 938 | '12': '12.17.0', 939 | '14': '14.3.0' 940 | } 941 | }, 942 | engines: '>=14' 943 | }); 944 | }); 945 | 946 | it('returns node versions from `.travis.yml` in the package repository', async () => { 947 | 948 | fixture.stubs.listRemote 949 | .returns('9cef39d21ad229dea4b10295f55b0d9a83800b23\tHEAD\n'); 950 | 951 | Nock('https://api.github.com') 952 | .get('/repos/pkgjs/detect-node-support/contents/package.json') 953 | .reply(200, { 954 | content: Fs.readFileSync(Path.join(__dirname, '..', 'package.json')).toString('base64') 955 | }) 956 | .get('/repos/pkgjs/detect-node-support/contents/.travis.yml') 957 | .reply(200, { 958 | content: Fs.readFileSync(Path.join(__dirname, '..', '.travis.yml')).toString('base64') 959 | }); 960 | 961 | Nock('https://registry.npmjs.org') 962 | .get('/detect-node-support') 963 | .reply(200, Fs.readFileSync(Path.join(__dirname, '..', 'package.json'))); 964 | 965 | const result = await NodeSupport.detect('detect-node-support'); 966 | 967 | expect(fixture.stubs.listRemote.callCount).to.equal(1); 968 | expect(fixture.stubs.listRemote.args[0]).to.equal([['http://github.com/pkgjs/detect-node-support.git', 'HEAD']]); 969 | 970 | expect(result).to.equal({ 971 | name: 'detect-node-support', 972 | version: '0.0.0-development', 973 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23', 974 | timestamp: 1580673602000, 975 | travis: { 976 | raw: ['14', '12', '10'], 977 | resolved: { 978 | '10': '10.20.1', 979 | '12': '12.17.0', 980 | '14': '14.3.0' 981 | } 982 | }, 983 | engines: '>=14' 984 | }); 985 | }); 986 | 987 | it('returns node versions from `.travis.yml` in the package repository (scoped)', async () => { 988 | 989 | fixture.stubs.listRemote 990 | .returns('9cef39d21ad229dea4b10295f55b0d9a83800b23\tHEAD\n'); 991 | 992 | Nock('https://api.github.com') 993 | .get('/repos/hapijs/hapi/contents/package.json') 994 | .reply(200, { 995 | content: Fs.readFileSync(Path.join(__dirname, 'fixtures', 'hapi-package.json')).toString('base64') 996 | }) 997 | .get('/repos/hapijs/hapi/contents/.travis.yml') 998 | .reply(200, { 999 | content: Fs.readFileSync(Path.join(__dirname, '..', '.travis.yml')).toString('base64') 1000 | }); 1001 | 1002 | Nock('https://registry.npmjs.org') 1003 | .get('/@hapi%2fhapi') 1004 | .reply(200, Fs.readFileSync(Path.join(__dirname, 'fixtures', 'hapi-package.json'))); 1005 | 1006 | const result = await NodeSupport.detect('@hapi/hapi'); 1007 | 1008 | expect(fixture.stubs.listRemote.callCount).to.equal(1); 1009 | expect(fixture.stubs.listRemote.args[0]).to.equal([['http://github.com/hapijs/hapi.git', 'HEAD']]); 1010 | 1011 | expect(result).to.equal({ 1012 | name: '@hapi/hapi', 1013 | version: '0.0.0-development', 1014 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23', 1015 | timestamp: 1580673602000, 1016 | travis: { 1017 | raw: ['14', '12', '10'], 1018 | resolved: { 1019 | '10': '10.20.1', 1020 | '12': '12.17.0', 1021 | '14': '14.3.0' 1022 | } 1023 | } 1024 | }); 1025 | }); 1026 | }); 1027 | 1028 | describe('with dependencies', () => { 1029 | 1030 | beforeEach(() => { 1031 | 1032 | fixture.stubs.listRemote 1033 | .returns('9cef39d21ad229dea4b10295f55b0d9a83800b23\tHEAD\n'); 1034 | 1035 | Nock('https://registry.npmjs.org') 1036 | .persist() 1037 | .get('/is-ci') 1038 | .reply(200, Fs.readFileSync(Path.join(__dirname, 'fixtures', 'packuments', 'is-ci.json'))) 1039 | .get('/ci-info') 1040 | .reply(200, Fs.readFileSync(Path.join(__dirname, 'fixtures', 'packuments', 'ci-info.json'))) 1041 | .get('/debug') 1042 | .reply(200, Fs.readFileSync(Path.join(__dirname, 'fixtures', 'packuments', 'debug.json'))) 1043 | .get('/ms') 1044 | .reply(200, Fs.readFileSync(Path.join(__dirname, 'fixtures', 'packuments', 'ms.json'))) 1045 | .get('/rimraf') 1046 | .reply(200, Fs.readFileSync(Path.join(__dirname, 'fixtures', 'packuments', 'rimraf.json'))); 1047 | 1048 | Nock('https://api.github.com') 1049 | .get('/repos/watson/is-ci/contents/package.json') 1050 | .reply(200, { 1051 | content: Buffer.from(JSON.stringify({ name: 'is-ci', version: '2.0.0' })).toString('base64') 1052 | }) 1053 | .get('/repos/watson/is-ci/contents/.travis.yml') 1054 | .reply(200, { 1055 | content: Fs.readFileSync(Path.join(__dirname, 'fixtures', 'travis-ymls', 'testing-single-version.yml')).toString('base64') 1056 | }) 1057 | .get('/repos/watson/ci-info/contents/package.json') 1058 | .reply(200, { 1059 | content: Buffer.from(JSON.stringify({ name: 'ci-info', version: '2.0.0' })).toString('base64') 1060 | }) 1061 | .get('/repos/watson/ci-info/contents/.travis.yml') 1062 | .reply(200, { 1063 | content: Fs.readFileSync(Path.join(__dirname, 'fixtures', 'travis-ymls', 'testing-single-version.yml')).toString('base64') 1064 | }) 1065 | .get('/repos/visionmedia/debug/contents/package.json') 1066 | .reply(200, { 1067 | content: Buffer.from(JSON.stringify({ name: 'debug', version: '4.1.1' })).toString('base64') 1068 | }) 1069 | .get('/repos/visionmedia/debug/contents/.travis.yml') 1070 | .reply(404) 1071 | .get('/repos/zeit/ms/contents/package.json') 1072 | .reply(200, { 1073 | content: Buffer.from(JSON.stringify({ name: 'ms', version: '2.1.2' })).toString('base64') 1074 | }) 1075 | .get('/repos/zeit/ms/contents/.travis.yml') 1076 | .reply(404) 1077 | .get('/repos/isaacs/rimraf/contents/package.json') 1078 | .reply(404); 1079 | }); 1080 | 1081 | it('resolves direct prod dep information', async () => { 1082 | 1083 | await fixture.setupRepoFolder({ 1084 | packageJson: JSON.parse(Fs.readFileSync(Path.join(__dirname, 'fixtures', 'deps-test', 'package.json')).toString()) 1085 | }); 1086 | 1087 | const result = await NodeSupport.detect({ path: fixture.path }, { deps: true }); 1088 | 1089 | internals.assertCommit(result); 1090 | 1091 | expect(result).to.equal({ 1092 | name: '@pkgjs/detect-node-support-deps-test', 1093 | version: '0.0.0-development', 1094 | timestamp: 1580673602000, 1095 | dependencies: { 1096 | versions: { 1097 | 'ci-info': ['1.6.0'], 1098 | 'is-ci': ['2.0.0'] 1099 | }, 1100 | support: [ 1101 | { 1102 | name: 'ci-info', 1103 | version: '2.0.0', 1104 | timestamp: 1580673602000, 1105 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23', 1106 | travis: { 1107 | raw: ['10'], 1108 | resolved: { '10': '10.20.1' } 1109 | } 1110 | }, 1111 | { 1112 | name: 'is-ci', 1113 | version: '2.0.0', 1114 | timestamp: 1580673602000, 1115 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23', 1116 | travis: { 1117 | raw: ['10'], 1118 | resolved: { '10': '10.20.1' } 1119 | } 1120 | } 1121 | ] 1122 | } 1123 | }); 1124 | }); 1125 | 1126 | it('resolves deps from shrinkwrap', async () => { 1127 | 1128 | await fixture.setupRepoFolder({ 1129 | packageJson: JSON.parse(Fs.readFileSync(Path.join(__dirname, 'fixtures', 'deps-test', 'package.json')).toString()), 1130 | npmShrinkwrapJson: 'deps-test/npm-shrinkwrap.json' 1131 | }); 1132 | 1133 | const result = await NodeSupport.detect({ path: fixture.path }, { deps: true }); 1134 | 1135 | internals.assertCommit(result); 1136 | 1137 | expect(result).to.equal({ 1138 | name: '@pkgjs/detect-node-support-deps-test', 1139 | version: '0.0.0-development', 1140 | timestamp: 1580673602000, 1141 | dependencies: { 1142 | versions: { 1143 | 'ci-info': ['1.6.0'], 1144 | 'is-ci': ['2.0.0'] 1145 | }, 1146 | support: [ 1147 | { 1148 | name: 'ci-info', 1149 | version: '2.0.0', 1150 | timestamp: 1580673602000, 1151 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23', 1152 | travis: { 1153 | raw: ['10'], 1154 | resolved: { '10': '10.20.1' } 1155 | } 1156 | }, 1157 | { 1158 | name: 'is-ci', 1159 | version: '2.0.0', 1160 | timestamp: 1580673602000, 1161 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23', 1162 | travis: { 1163 | raw: ['10'], 1164 | resolved: { '10': '10.20.1' } 1165 | } 1166 | } 1167 | ] 1168 | } 1169 | }); 1170 | }); 1171 | 1172 | it('resolves deps from package-lock', async () => { 1173 | 1174 | await fixture.setupRepoFolder({ 1175 | packageJson: JSON.parse(Fs.readFileSync(Path.join(__dirname, 'fixtures', 'deps-test', 'package.json')).toString()), 1176 | packageLockJson: 'deps-test/npm-shrinkwrap.json' 1177 | }); 1178 | 1179 | const result = await NodeSupport.detect({ path: fixture.path }, { deps: true }); 1180 | 1181 | internals.assertCommit(result); 1182 | 1183 | expect(result).to.equal({ 1184 | name: '@pkgjs/detect-node-support-deps-test', 1185 | version: '0.0.0-development', 1186 | timestamp: 1580673602000, 1187 | dependencies: { 1188 | versions: { 1189 | 'ci-info': ['1.6.0'], 1190 | 'is-ci': ['2.0.0'] 1191 | }, 1192 | support: [ 1193 | { 1194 | name: 'ci-info', 1195 | version: '2.0.0', 1196 | timestamp: 1580673602000, 1197 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23', 1198 | travis: { 1199 | raw: ['10'], 1200 | resolved: { '10': '10.20.1' } 1201 | } 1202 | }, 1203 | { 1204 | name: 'is-ci', 1205 | version: '2.0.0', 1206 | timestamp: 1580673602000, 1207 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23', 1208 | travis: { 1209 | raw: ['10'], 1210 | resolved: { '10': '10.20.1' } 1211 | } 1212 | } 1213 | ] 1214 | } 1215 | }); 1216 | }); 1217 | 1218 | it('resolves all deps', async () => { 1219 | 1220 | await fixture.setupRepoFolder({ 1221 | packageJson: JSON.parse(Fs.readFileSync(Path.join(__dirname, 'fixtures', 'deps-test', 'package.json')).toString()), 1222 | npmShrinkwrapJson: 'deps-test/npm-shrinkwrap.json' 1223 | }); 1224 | 1225 | const result = await NodeSupport.detect({ path: fixture.path }, { deps: true, deep: true, dev: true }); 1226 | 1227 | internals.assertCommit(result); 1228 | 1229 | expect(result).to.equal({ 1230 | name: '@pkgjs/detect-node-support-deps-test', 1231 | version: '0.0.0-development', 1232 | timestamp: 1580673602000, 1233 | dependencies: { 1234 | versions: { 1235 | 'ci-info': ['1.6.0', '2.0.0'], 1236 | 'is-ci': ['2.0.0'], 1237 | debug: ['4.1.1'], 1238 | ms: ['2.1.2'] 1239 | }, 1240 | support: [ 1241 | { 1242 | name: 'ci-info', 1243 | version: '2.0.0', 1244 | timestamp: 1580673602000, 1245 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23', 1246 | travis: { 1247 | raw: ['10'], 1248 | resolved: { '10': '10.20.1' } 1249 | } 1250 | }, 1251 | { 1252 | name: 'debug', 1253 | version: '4.1.1', 1254 | timestamp: 1580673602000, 1255 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23' 1256 | }, 1257 | { 1258 | name: 'is-ci', 1259 | version: '2.0.0', 1260 | timestamp: 1580673602000, 1261 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23', 1262 | travis: { 1263 | raw: ['10'], 1264 | resolved: { '10': '10.20.1' } 1265 | } 1266 | }, 1267 | { 1268 | name: 'ms', 1269 | version: '2.1.2', 1270 | timestamp: 1580673602000, 1271 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23' 1272 | } 1273 | ] 1274 | } 1275 | }); 1276 | }); 1277 | 1278 | it('resolves direct deps', async () => { 1279 | 1280 | await fixture.setupRepoFolder({ 1281 | packageJson: JSON.parse(Fs.readFileSync(Path.join(__dirname, 'fixtures', 'deps-test', 'package.json')).toString()), 1282 | npmShrinkwrapJson: 'deps-test/npm-shrinkwrap.json' 1283 | }); 1284 | 1285 | const result = await NodeSupport.detect({ path: fixture.path }, { deps: true, dev: true }); 1286 | 1287 | internals.assertCommit(result); 1288 | 1289 | expect(result).to.equal({ 1290 | name: '@pkgjs/detect-node-support-deps-test', 1291 | version: '0.0.0-development', 1292 | timestamp: 1580673602000, 1293 | dependencies: { 1294 | versions: { 1295 | 'ci-info': ['1.6.0'], 1296 | 'is-ci': ['2.0.0'], 1297 | debug: ['4.1.1'] 1298 | }, 1299 | support: [ 1300 | { 1301 | name: 'ci-info', 1302 | version: '2.0.0', 1303 | timestamp: 1580673602000, 1304 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23', 1305 | travis: { 1306 | raw: ['10'], 1307 | resolved: { '10': '10.20.1' } 1308 | } 1309 | }, 1310 | { 1311 | name: 'debug', 1312 | version: '4.1.1', 1313 | timestamp: 1580673602000, 1314 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23' 1315 | }, 1316 | { 1317 | name: 'is-ci', 1318 | version: '2.0.0', 1319 | timestamp: 1580673602000, 1320 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23', 1321 | travis: { 1322 | raw: ['10'], 1323 | resolved: { '10': '10.20.1' } 1324 | } 1325 | } 1326 | ] 1327 | } 1328 | }); 1329 | }); 1330 | 1331 | it('resolves all prod deps', async () => { 1332 | 1333 | await fixture.setupRepoFolder({ 1334 | packageJson: JSON.parse(Fs.readFileSync(Path.join(__dirname, 'fixtures', 'deps-test', 'package.json')).toString()), 1335 | npmShrinkwrapJson: 'deps-test/npm-shrinkwrap.json' 1336 | }); 1337 | 1338 | const result = await NodeSupport.detect({ path: fixture.path }, { deps: true, deep: true }); 1339 | 1340 | internals.assertCommit(result); 1341 | 1342 | expect(result).to.equal({ 1343 | name: '@pkgjs/detect-node-support-deps-test', 1344 | version: '0.0.0-development', 1345 | timestamp: 1580673602000, 1346 | dependencies: { 1347 | versions: { 1348 | 'ci-info': ['1.6.0', '2.0.0'], 1349 | 'is-ci': ['2.0.0'] 1350 | }, 1351 | support: [ 1352 | { 1353 | name: 'ci-info', 1354 | version: '2.0.0', 1355 | timestamp: 1580673602000, 1356 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23', 1357 | travis: { 1358 | raw: ['10'], 1359 | resolved: { '10': '10.20.1' } 1360 | } 1361 | }, 1362 | { 1363 | name: 'is-ci', 1364 | version: '2.0.0', 1365 | timestamp: 1580673602000, 1366 | commit: '9cef39d21ad229dea4b10295f55b0d9a83800b23', 1367 | travis: { 1368 | raw: ['10'], 1369 | resolved: { '10': '10.20.1' } 1370 | } 1371 | } 1372 | ] 1373 | } 1374 | }); 1375 | }); 1376 | 1377 | it('rethrows lock file parsing errors', async () => { 1378 | 1379 | await fixture.setupRepoFolder({ 1380 | packageJson: JSON.parse(Fs.readFileSync(Path.join(__dirname, 'fixtures', 'deps-test', 'package.json')).toString()), 1381 | packageLockJson: 'travis-ymls/testing-single-version.yml' // not a json file 1382 | }); 1383 | 1384 | await expect(NodeSupport.detect({ path: fixture.path }, { deps: true })).to.reject('Unexpected token l in JSON at position 0'); 1385 | }); 1386 | 1387 | it('handles failures to load packages', async () => { 1388 | 1389 | Sinon.stub(console, 'warn'); 1390 | 1391 | await fixture.setupRepoFolder({ 1392 | packageJson: { 1393 | name: '@pkgjs/detect-node-support-deps-test', 1394 | version: '0.0.0-development', 1395 | dependencies: { 1396 | rimraf: '1.x' 1397 | } 1398 | } 1399 | }); 1400 | 1401 | const result = await NodeSupport.detect({ path: fixture.path }, { deps: true }); 1402 | 1403 | internals.assertCommit(result); 1404 | 1405 | expect(result).to.equal({ 1406 | name: '@pkgjs/detect-node-support-deps-test', 1407 | version: '0.0.0-development', 1408 | timestamp: 1580673602000, 1409 | dependencies: { 1410 | support: [], 1411 | versions: { 1412 | rimraf: ['1.0.9'] 1413 | }, 1414 | errors: { 1415 | rimraf: { 1416 | message: 'git://github.com/isaacs/rimraf.git does not contain a package.json' 1417 | } 1418 | } 1419 | } 1420 | }); 1421 | }); 1422 | }); 1423 | }); 1424 | }); 1425 | --------------------------------------------------------------------------------