codecov
Version:
Uploading report to Codecov: https://codecov.io
593 lines (564 loc) • 16.1 kB
JavaScript
var fs = require('fs')
var path = require('path')
var request = require('teeny-request').teenyRequest
var urlgrey = require('urlgrey')
var jsYaml = require('js-yaml')
var walk = require('ignore-walk')
var execFileSync = require('child_process').execFileSync
var execSync = require('child_process').execSync
var detectProvider = require('./detect')
var version = 'v' + require('../package.json').version
var patterns = ''
var more_patterns = ''
var winPatterns = ''
var isWindows =
process.platform.match(/win32/) || process.platform.match(/win64/)
if (!isWindows) {
patterns = (
'-type f ( ' +
'-name *coverage.* ' +
'-or -name *.gcov ' +
'-or -name *.lcov ' +
'-or -name *.lst ' +
'-or -name clover.xml ' +
'-or -name cobertura.xml ' +
'-or -name coverage-final.json ' +
'-or -name gcov.info ' +
'-or -name jacoco*.xml ' +
'-or -name lcov.info ' +
'-or -name luacov.report.out ' +
'-or -name nosetests.xml ' +
'-or -name report.xml ' +
') ' +
'-not -name *.sh ' +
'-not -name *.data ' +
'-not -name *.py ' +
'-not -name *.class ' +
'-not -name *.xcconfig ' +
'-not -name Coverage.profdata ' +
'-not -name phpunit-code-coverage.xml ' +
'-not -name coverage.serialized ' +
'-not -name *.pyc ' +
'-not -name *.cfg ' +
'-not -name *.egg ' +
'-not -name *.whl ' +
'-not -name *.html ' +
'-not -name *.js ' +
'-not -name *.cpp ' +
'-not -name coverage.jade ' +
'-not -name include.lst ' +
'-not -name inputFiles.lst ' +
'-not -name createdFiles.lst ' +
'-not -name coverage.html ' +
'-not -name scoverage.measurements.* ' +
'-not -name test_*_coverage.txt ' +
'-not -path */vendor/* ' +
'-not -path */htmlcov/* ' +
'-not -path */home/cainus/* ' +
'-not -path */virtualenv/* ' +
'-not -path */js/generated/coverage/* ' +
'-not -path */.virtualenv/* ' +
'-not -path */virtualenvs/* ' +
'-not -path */.virtualenvs/* ' +
'-not -path */.env/* ' +
'-not -path */.envs/* ' +
'-not -path */env/* ' +
'-not -path */envs/* ' +
'-not -path */.venv/* ' +
'-not -path */.venvs/* ' +
'-not -path */venv/* ' +
'-not -path */venvs/* ' +
'-not -path */.git/* ' +
'-not -path */.hg/* ' +
'-not -path */.tox/* ' +
'-not -path */__pycache__/* ' +
'-not -path */.egg-info* ' +
'-not -path */$bower_components/* ' +
'-not -path */node_modules/* ' +
'-not -path */conftest_*.c.gcov'
).split(' ')
} else {
winPatterns = (
'/a:-d /b /s *coverage.* ' +
'/s nosetests.xml ' +
'/s jacoco*.xml ' +
'/s clover.xml ' +
'/s report.xml ' +
'/s cobertura.xml ' +
'/s luacov.report.out ' +
'/s lcov.info ' +
'/s *.lcov ' +
'/s gcov.info ' +
'/s *.gcov ' +
'/s *.lst' +
'| findstr /i /v \\.sh$ ' +
'| findstr /i /v \\.data$ ' +
'| findstr /i /v \\.py$ ' +
'| findstr /i /v \\.class$ ' +
'| findstr /i /v \\.xcconfig$ ' +
'| findstr /i /v Coverage\\.profdata$ ' +
'| findstr /i /v phpunit-code-coverage\\.xml$ ' +
'| findstr /i /v coverage\\.serialized$ ' +
'| findstr /i /v \\.pyc$ ' +
'| findstr /i /v \\.cfg$ ' +
'| findstr /i /v \\.egg$ ' +
'| findstr /i /v \\.whl$ ' +
'| findstr /i /v \\.html$ ' +
'| findstr /i /v \\.js$ ' +
'| findstr /i /v \\.cpp$ ' +
'| findstr /i /v coverage\\.jade$ ' +
'| findstr /i /v include\\.lst$ ' +
'| findstr /i /v inputFiles\\.lst$ ' +
'| findstr /i /v createdFiles\\.lst$ ' +
'| findstr /i /v coverage\\.html$ ' +
'| findstr /i /v scoverage\\.measurements\\..* ' +
'| findstr /i /v test_.*_coverage\\.txt ' +
'| findstr /i /v \\vendor\\ ' +
'| findstr /i /v \\htmlcov\\ ' +
'| findstr /i /v \\home\\cainus\\ ' +
'| findstr /i /v \\js\\generated\\coverage\\ ' +
'| findstr /i /v \\virtualenv\\ ' +
'| findstr /i /v \\virtualenvs\\ ' +
'| findstr /i /v \\\\.virtualenv\\ ' +
'| findstr /i /v \\\\.virtualenvs\\ ' +
'| findstr /i /v \\\\.env\\ ' +
'| findstr /i /v \\\\.envs\\ ' +
'| findstr /i /v \\env\\ ' +
'| findstr /i /v \\envs\\ ' +
'| findstr /i /v \\\\.venv\\ ' +
'| findstr /i /v \\\\.venvs\\ ' +
'| findstr /i /v \\venv\\ ' +
'| findstr /i /v \\venvs\\ ' +
'| findstr /i /v \\\\.git\\ ' +
'| findstr /i /v \\\\.hg\\ ' +
'| findstr /i /v \\\\.tox\\ ' +
'| findstr /i /v \\__pycache__\\ ' +
'| findstr /i /v \\\\.egg-info* ' +
'| findstr /i /v \\\\$bower_components\\ ' +
'| findstr /i /v \\node_modules\\ ' +
'| findstr /i /v \\conftest_.*\\.c\\.gcov '
).split(' ')
}
var sendToCodecovV2 = function (
codecov_endpoint,
query,
upload_body,
on_success,
on_failure
) {
// Direct to Codecov
request(
{
uri: urlgrey(codecov_endpoint + '/upload/v2')
.query(query)
.toString(),
method: 'POST',
body: upload_body,
headers: {
'Content-Type': 'text/plain',
Accept: 'text/plain',
},
},
function (err, response) {
if (err || response.statusCode !== 200) {
console.log(' ' + (err || response.body))
return response
? on_failure(response.statusCode, response.body)
: on_failure(err.code, err.message)
} else {
console.log(' Success!')
console.log(' View report at: ' + response.body)
return on_success(response.body)
}
}
)
}
var sendToCodecovV4 = function (
codecov_endpoint,
query,
upload_body,
on_success,
on_failure
) {
// Direct to S3
request(
{
uri: urlgrey(codecov_endpoint + '/upload/v4')
.query(query)
.toString(),
method: 'POST',
body: '',
headers: {
'Content-Type': 'text/plain',
Accept: 'text/plain',
},
},
function (err, response, result) {
if (err) {
sendToCodecovV2(
codecov_endpoint,
query,
upload_body,
on_success,
on_failure
)
} else if (result.split('\n').length !== 2) {
console.log(' Could not upload to Codecov: ' + result)
} else {
var codecov_report_url = result.split('\n')[0]
request(
{
uri: result.split('\n')[1],
method: 'PUT',
body: upload_body,
headers: {
'Content-Type': 'text/plain',
},
},
function (err) {
if (err) {
sendToCodecovV2(
codecov_endpoint,
query,
upload_body,
on_success,
on_failure
)
} else {
console.log(' Success!')
console.log(' View report at: ' + codecov_report_url)
on_success(codecov_report_url)
}
}
)
}
}
)
}
var upload = function (args, on_success, on_failure) {
// Build query
var codecov_endpoint =
args.options.url ||
process.env.codecov_url ||
process.env.CODECOV_URL ||
'https://codecov.io'
var query = {}
var debug = []
var yamlFile =
args.options.yml ||
process.env.codecov_yml ||
process.env.CODECOV_YML ||
'codecov.yml'
console.log(
'' +
' _____ _ \n' +
' / ____| | | \n' +
'| | ___ __| | ___ ___ _____ __ \n' +
'| | / _ \\ / _` |/ _ \\/ __/ _ \\ \\ / / \n' +
'| |___| (_) | (_| | __/ (_| (_) \\ V / \n' +
' \\_____\\___/ \\__,_|\\___|\\___\\___/ \\_/ \n' +
' ' +
version
)
if ((args.options.disable || '').split(',').indexOf('detect') === -1) {
console.log('==> Detecting CI Provider')
query = detectProvider()
} else {
debug.push('disabled detect')
}
query.yaml = [yamlFile, '.codecov.yml'].reduce(function (result, file) {
return (
result ||
(fs.existsSync(path.resolve(process.cwd(), file))
? path.resolve(process.cwd(), file)
: undefined)
)
}, undefined)
if (args.options.build) {
query.build = args.options.build
}
if (args.options.commit) {
query.commit = args.options.commit
}
if (args.options.branch) {
query.branch = args.options.branch
}
if (args.options.slug) {
query.slug = args.options.slug
}
var flags =
args.options.flags || process.env.codecov_flags || process.env.CODECOV_FLAGS
if (flags) {
query.flags = flags
}
var yamlToken
try {
var loadedYamlFile = jsYaml.safeLoad(fs.readFileSync(query.yaml, 'utf8'))
yamlToken =
loadedYamlFile && loadedYamlFile.codecov && loadedYamlFile.codecov.token
} catch (e) {
// silently fail
}
var token =
args.options.token ||
yamlToken ||
process.env.codecov_token ||
process.env.CODECOV_TOKEN
if (token) {
query.token = token
}
query.package = 'node-' + version
console.log('==> Configuration: ')
console.log(' Endpoint: ' + codecov_endpoint)
// Don't output `query` directly as it contains the upload token
console.log({
commit: query.commit,
branch: query.branch,
package: query.package,
})
var upload = ''
// Add specified env vars
var env_found = false
if (args.options.env || process.env.CODECOV_ENV || process.env.codecov_env) {
var env = (
args.options.env +
',' +
(process.env.CODECOV_ENV || '') +
',' +
(process.env.codecov_env || '')
).split(',')
for (var i = env.length - 1; i >= 0; i--) {
if (env[i]) {
upload += env[i] + '=' + (process.env[env[i]] || '').toString() + '\n'
env_found = true
}
}
if (env_found) {
upload += '<<<<<< ENV\n'
}
}
// List git files
var root = path.resolve(args.options.root || query.root || '.')
console.log('==> Building file structure')
try {
var network = execFileSync('git', ['ls-files'], { cwd: root })
if (network === '') {
network = execFileSync('hg', ['locate'], { cwd: root })
}
upload += network.toString().trim() + '\n<<<<<< network\n'
} catch (err) {
// not a git/hg dir, emulating git/hg ignore behavior
upload +=
walk
.sync({ path: root, ignoreFiles: ['.gitignore', '.hgignore'] })
.join('\n')
.trim() + '\n<<<<<< network\n'
}
// Make gcov reports
if ((args.options.disable || '').split(',').indexOf('gcov') === -1) {
try {
console.log('==> Generating gcov reports (skip via --disable=gcov)')
var gcg = args.options['gcov-glob'] || ''
if (gcg) {
if (!isWindows) {
gcg = gcg
.split(' ')
.map(function (p) {
return "-not -path '" + p + "'"
})
.join(' ')
} else {
gcg = gcg
.split(' ')
.map(function (p) {
return '^| findstr /i /v ' + p
})
.join(' ')
}
}
var gcov
if (!isWindows) {
gcov =
'find ' +
(sanitizeVar(args.options['gcov-root']) || root) +
" -type f -name '*.gcno' " +
gcg +
' -exec ' +
(sanitizeVar(args.options['gcov-exec']) || 'gcov') +
' ' +
(sanitizeVar(args.options['gcov-args']) || '') +
' {} +'
} else {
// @TODO support for root
// not straight forward due to nature of windows command dir
gcov =
'for /f "delims=" %g in (\'dir /a-d /b /s *.gcno ' +
gcg +
"') do " +
(sanitizeVar(args.options['gcov-exec']) || 'gcov') +
' ' +
(sanitizeVar(args.options['gcov-args']) || '') +
' %g'
}
debug.push(gcov)
console.log(' $ ' + gcov)
execFileSync(gcov)
} catch (e) {
console.log(' Failed to run gcov command.')
}
} else {
debug.push('disabled gcov')
}
// Detect .bowerrc
var bowerrc
if (!isWindows) {
bowerrc = execSync('test -f .bowerrc && cat .bowerrc || echo ""', {
cwd: root,
})
.toString()
.trim()
} else {
bowerrc = fs.existsSync('.bowerrc')
}
if (bowerrc) {
bowerrc = JSON.parse(bowerrc).directory
if (bowerrc) {
if (!isWindows) {
more_patterns = (
" -not -path '*/" +
bowerrc.toString().replace(/\/$/, '') +
"/*'"
).split(' ')
} else {
more_patterns = (
'| findstr /i /v \\' +
bowerrc.toString().replace(/\/$/, '') +
'\\'
).split(' ')
}
}
}
var files = [],
file = null
if (args.options.pipe) {
// Append piped reports
upload += '# path=piped\n' + args.options.pipe.join('') + '\n<<<<<< EOF\n'
console.log('==> Reading report from stdin')
} else if (args.options.file) {
// Append manually entered reports
file = args.options.file
console.log('==> Targeting specific file')
try {
upload +=
'# path=' +
file +
'\n' +
fs.readFileSync(file, 'utf8').toString() +
'\n<<<<<< EOF\n'
console.log(' + ' + file)
files.push(file)
} catch (e) {
debug.push('failed: ' + file.split('/').pop())
console.log(' X Failed to read file at ' + file)
}
} else if ((args.options.disable || '').split(',').indexOf('search') === -1) {
console.log('==> Scanning for reports')
var _files
var _findArgs
if (!isWindows) {
// @TODO support for a root directory
// It's not straightforward due to the nature of the find command
_findArgs = [root].concat(patterns)
if (more_patterns) {
_findArgs.concat(more_patterns)
}
_files = execFileSync('find', _findArgs).toString().trim().split('\n')
} else {
// @TODO support for a root directory
// It's not straightforward due to the nature of the dir command
_findArgs = [root].concat(winPatterns)
if (more_patterns) {
_findArgs.concat(more_patterns)
}
_files = execSync('dir ' + winPatterns.join(' ') + more_patterns)
.toString()
.trim()
.split('\r\n')
}
if (_files) {
for (var i2 = _files.length - 1; i2 >= 0; i2--) {
file = _files[i2]
try {
upload +=
'# path=' +
file +
'\n' +
fs.readFileSync(file, 'utf8').toString() +
'\n<<<<<< EOF\n'
console.log(' + ' + file)
files.push(file)
} catch (e) {
debug.push('failed: ' + file.split('/').pop())
console.log(' X Failed to read file at ' + file)
}
}
}
} else {
debug.push('disabled search')
}
if (files) {
// Upload to Codecov
if (args.options.dump) {
console.log('-------- DEBUG START --------')
console.log(upload)
console.log('-------- DEBUG END --------')
} else {
console.log('==> Uploading reports')
var _upload
if ((args.options.disable || '').split(',').indexOf('s3') === -1) {
_upload = sendToCodecovV4
} else {
_upload = sendToCodecovV2
}
_upload(
codecov_endpoint,
query,
upload,
function () {
// remove files after Uploading
if (args.options.clear) {
for (var i = files.length - 1; i >= 0; i--) {
try {
fs.unlinkSync(files[i])
} catch (e) {}
}
}
if (on_success) {
on_success.apply(this, arguments)
}
},
on_failure || function () {}
)
}
}
return {
body: upload,
files: files,
query: query,
debug: debug,
url: codecov_endpoint,
}
}
function sanitizeVar(arg) {
if (!arg) {
return ''
}
return arg.replace(/&/g, '')
}
module.exports = {
sanitizeVar: sanitizeVar,
upload: upload,
version: version,
sendToCodecovV2: sendToCodecovV2,
sendToCodecovV4: sendToCodecovV4,
}