UNPKG

coverage

Version:

A command-line tool to collect and report code coverage of a JavaScript program

229 lines (200 loc) 5.46 kB
#!/usr/bin/env node 'use strict'; const {createWriteStream, promises: {mkdir}} = require('fs'); const {dirname, extname, join, resolve: resolvePath} = require('path'); const {once} = require('events'); const {promisify} = require('util'); const {spawn} = require('child_process'); const foregroundChild = require('foreground-child'); const normalizePackageData = require('normalize-package-data'); const slash = require('slash'); const which = require('which'); const yargsParser = require('yargs-parser'); const cwd = process.cwd(); const c8PackageJsonPath = require.resolve('c8/package.json'); const c8PackageData = require(c8PackageJsonPath); normalizePackageData(c8PackageData); const c8BinPath = join(dirname(c8PackageJsonPath), c8PackageData.bin.c8); const nodePath = process.execPath; const optionArgs = process.argv.slice(2); const {_: [command], reporter} = yargsParser(optionArgs); const promisifiedWhich = promisify(which); const timeout = 2 ** 32 / 2 - 1; const willUploadLcov = /^1|true$/ui.test(process.env.CI) || !!process.env.GITHUB_ACTION; const isTravisCi = process.env.TRAVIS === 'true'; // On Windows, write codecov-bash to a file instead of memory to avoid ENAMETOOLONG error const codecovBashPath = process.platform === 'win32' ? join(cwd, 'coverage', Math.random().toString()) : null; (async () => { if (command === undefined) { require(c8BinPath); return; } if (command === 'report') { foregroundChild(nodePath, [c8BinPath, ...optionArgs]); return; } const prepareArgs = (async () => { const ext = extname(command).slice(1).toLowerCase(); let isJavaScriptFile = false; if (ext === 'cjs' || ext === 'js' || ext === 'mjs') { isJavaScriptFile = true; } else { try { await promisifiedWhich(command); } catch { isJavaScriptFile = true; } } if (isJavaScriptFile) { let entryPath = resolvePath(cwd, command); try { entryPath = require.resolve(entryPath); } catch { console.error(`Both a command \`${command}\` and a Node.js entry point ${entryPath} don't exist.`); process.exit(127); } optionArgs.splice( optionArgs.indexOf(command), 1, nodePath, ...ext === 'mjs' ? [ '--experimental-modules', '--es-module-specifier-resolution=node', '--no-warnings' ] : [], entryPath ); } return [ nodePath, [ c8BinPath, ...require('test-exclude').defaultExclude.map(pattern => `--exclude="${ pattern // Remove this when https://github.com/istanbuljs/istanbuljs/pull/381 is merged .replace(/(?<=\.)(?=js$)/ui, '{,c,m}') // Remove this when https://github.com/istanbuljs/istanbuljs/pull/419 is merged .replace(/(?<=test)(?=\/)/ui, '{,s}') }"`), '--exclude="**/*.json"', ...reporter === undefined ? [ '--reporter=text', `--reporter=${willUploadLcov ? 'lcovonly' : 'html'}` ] : [], ...optionArgs ] ]; })(); if (!willUploadLcov) { foregroundChild(...await prepareArgs); return; } const [code, codecovBash] = await Promise.all([ (async () => (await once(spawn(...await prepareArgs, { cwd, stdio: 'inherit', timeout }), 'exit'))[0])(), (async () => { try { // The default shell of Travis CI Windows build is Git BASH if (!(process.platform === 'win32' && isTravisCi)) { await Promise.all([promisifiedWhich('bash'), promisifiedWhich('git')]); } } catch { await once(spawn('npm', [ 'install', '--no-package-lock', '--no-save', 'codecov@3' ], { cwd, shell: process.platform === 'win32', timeout }), 'exit'); return null; } const {connect} = require('http2'); const {pipeline, Writable} = require('stream'); const client = connect('https://codecov.io'); const request = client.request({':path': '/bash'}); let body = ''; request.setEncoding('utf8'); request.end(); if (codecovBashPath) { await mkdir(dirname(codecovBashPath), {recursive: true}); } await promisify(pipeline)([ request, codecovBashPath ? createWriteStream(codecovBashPath) : new Writable({ write(chunk, _, cb) { body += chunk; cb(); } }) ]); await promisify(client.close.bind(client))(); return body; })() ]); if (code !== 0) { process.exitCode = code; return; } if (isTravisCi) { console.log('travis_fold:start:codecov\nupload coverage to codecov.io'); } const reportArgs = codecovBash !== null ? [ 'bash', [ ...codecovBashPath ? [codecovBashPath] : ['-c', codecovBash, '--'], '-X', 'coveragepy', '-X', 'fix', '-X', 'gcov', '-X', 'gcovout', '-X', 'search', '-X', 'xcode', '-f', slash(join(cwd, 'coverage', 'lcov.info')) ] ] : [ 'npx', [ 'codecov', '--disable=gcov,search', `--file=${join(cwd, 'coverage', 'lcov.info')}` ] ]; if (process.env.GITHUB_ACTION) { const branch = (process.env.GITHUB_REF || '').replace(/^refs\/heads\//u, ''); if (codecovBash) { reportArgs[1].push( '-r', process.env.GITHUB_REPOSITORY, '-B', branch, '-C', process.env.GITHUB_SHA ); } else { reportArgs[1].push( '--disable=detect,gcov,search', `--slug=${process.env.GITHUB_REPOSITORY}`, `--branch=${branch}`, `--commit=${process.env.GITHUB_SHA}` ); } } foregroundChild(...reportArgs, ...isTravisCi ? [ done => { console.log('travis_fold:end:codecov'); done(); } ] : []); })();