UNPKG

15.5 kBJavaScriptView Raw
1var fs = require('fs')
2var path = require('path')
3var request = require('teeny-request').teenyRequest
4var urlgrey = require('urlgrey')
5var jsYaml = require('js-yaml')
6var walk = require('ignore-walk')
7var execSync = require('child_process').execSync
8
9var detectProvider = require('./detect')
10
11var version = 'v' + require('../package.json').version
12
13var patterns,
14 more_patterns = ''
15
16var isWindows =
17 process.platform.match(/win32/) || process.platform.match(/win64/)
18
19if (!isWindows) {
20 patterns =
21 "-type f \\( -name '*coverage.*' " +
22 "-or -name 'nosetests.xml' " +
23 "-or -name 'jacoco*.xml' " +
24 "-or -name 'clover.xml' " +
25 "-or -name 'report.xml' " +
26 "-or -name 'cobertura.xml' " +
27 "-or -name 'luacov.report.out' " +
28 "-or -name 'lcov.info' " +
29 "-or -name '*.lcov' " +
30 "-or -name 'gcov.info' " +
31 "-or -name '*.gcov' " +
32 "-or -name '*.lst' \\) " +
33 "-not -name '*.sh' " +
34 "-not -name '*.data' " +
35 "-not -name '*.py' " +
36 "-not -name '*.class' " +
37 "-not -name '*.xcconfig' " +
38 "-not -name 'Coverage.profdata' " +
39 "-not -name 'phpunit-code-coverage.xml' " +
40 "-not -name 'coverage.serialized' " +
41 "-not -name '*.pyc' " +
42 "-not -name '*.cfg' " +
43 "-not -name '*.egg' " +
44 "-not -name '*.whl' " +
45 "-not -name '*.html' " +
46 "-not -name '*.js' " +
47 "-not -name '*.cpp' " +
48 "-not -name 'coverage.jade' " +
49 "-not -name 'include.lst' " +
50 "-not -name 'inputFiles.lst' " +
51 "-not -name 'createdFiles.lst' " +
52 "-not -name 'coverage.html' " +
53 "-not -name 'scoverage.measurements.*' " +
54 "-not -name 'test_*_coverage.txt' " +
55 "-not -path '*/vendor/*' " +
56 "-not -path '*/htmlcov/*' " +
57 "-not -path '*/home/cainus/*' " +
58 "-not -path '*/virtualenv/*' " +
59 "-not -path '*/js/generated/coverage/*' " +
60 "-not -path '*/.virtualenv/*' " +
61 "-not -path '*/virtualenvs/*' " +
62 "-not -path '*/.virtualenvs/*' " +
63 "-not -path '*/.env/*' " +
64 "-not -path '*/.envs/*' " +
65 "-not -path '*/env/*' " +
66 "-not -path '*/envs/*' " +
67 "-not -path '*/.venv/*' " +
68 "-not -path '*/.venvs/*' " +
69 "-not -path '*/venv/*' " +
70 "-not -path '*/venvs/*' " +
71 "-not -path '*/.git/*' " +
72 "-not -path '*/.hg/*' " +
73 "-not -path '*/.tox/*' " +
74 "-not -path '*/__pycache__/*' " +
75 "-not -path '*/.egg-info*' " +
76 "-not -path '*/$bower_components/*' " +
77 "-not -path '*/node_modules/*' " +
78 "-not -path '*/conftest_*.c.gcov'"
79} else {
80 patterns =
81 '/a-d /b /s *coverage.* ' +
82 '/s nosetests.xml ' +
83 '/s jacoco*.xml ' +
84 '/s clover.xml ' +
85 '/s report.xml ' +
86 '/s cobertura.xml ' +
87 '/s luacov.report.out ' +
88 '/s lcov.info ' +
89 '/s *.lcov ' +
90 '/s gcov.info ' +
91 '/s *.gcov ' +
92 '/s *.lst' +
93 '| findstr /i /v \\.sh$ ' +
94 '| findstr /i /v \\.data$ ' +
95 '| findstr /i /v \\.py$ ' +
96 '| findstr /i /v \\.class$ ' +
97 '| findstr /i /v \\.xcconfig$ ' +
98 '| findstr /i /v Coverage\\.profdata$ ' +
99 '| findstr /i /v phpunit-code-coverage\\.xml$ ' +
100 '| findstr /i /v coverage\\.serialized$ ' +
101 '| findstr /i /v \\.pyc$ ' +
102 '| findstr /i /v \\.cfg$ ' +
103 '| findstr /i /v \\.egg$ ' +
104 '| findstr /i /v \\.whl$ ' +
105 '| findstr /i /v \\.html$ ' +
106 '| findstr /i /v \\.js$ ' +
107 '| findstr /i /v \\.cpp$ ' +
108 '| findstr /i /v coverage\\.jade$ ' +
109 '| findstr /i /v include\\.lst$ ' +
110 '| findstr /i /v inputFiles\\.lst$ ' +
111 '| findstr /i /v createdFiles\\.lst$ ' +
112 '| findstr /i /v coverage\\.html$ ' +
113 '| findstr /i /v scoverage\\.measurements\\..* ' +
114 '| findstr /i /v test_.*_coverage\\.txt ' +
115 '| findstr /i /v \\vendor\\ ' +
116 '| findstr /i /v \\htmlcov\\ ' +
117 '| findstr /i /v \\home\\cainus\\ ' +
118 '| findstr /i /v \\js\\generated\\coverage\\ ' +
119 '| findstr /i /v \\virtualenv\\ ' +
120 '| findstr /i /v \\virtualenvs\\ ' +
121 '| findstr /i /v \\\\.virtualenv\\ ' +
122 '| findstr /i /v \\\\.virtualenvs\\ ' +
123 '| findstr /i /v \\\\.env\\ ' +
124 '| findstr /i /v \\\\.envs\\ ' +
125 '| findstr /i /v \\env\\ ' +
126 '| findstr /i /v \\envs\\ ' +
127 '| findstr /i /v \\\\.venv\\ ' +
128 '| findstr /i /v \\\\.venvs\\ ' +
129 '| findstr /i /v \\venv\\ ' +
130 '| findstr /i /v \\venvs\\ ' +
131 '| findstr /i /v \\\\.git\\ ' +
132 '| findstr /i /v \\\\.hg\\ ' +
133 '| findstr /i /v \\\\.tox\\ ' +
134 '| findstr /i /v \\__pycache__\\ ' +
135 '| findstr /i /v \\\\.egg-info* ' +
136 '| findstr /i /v \\\\$bower_components\\ ' +
137 '| findstr /i /v \\node_modules\\ ' +
138 '| findstr /i /v \\conftest_.*\\.c\\.gcov '
139}
140
141var sendToCodecovV2 = function(
142 codecov_endpoint,
143 query,
144 upload_body,
145 on_success,
146 on_failure
147) {
148 // Direct to Codecov
149 request(
150 {
151 uri: urlgrey(codecov_endpoint + '/upload/v2')
152 .query(query)
153 .toString(),
154 method: 'POST',
155 body: upload_body,
156 headers: {
157 'Content-Type': 'text/plain',
158 Accept: 'text/plain',
159 },
160 },
161 function(err, response) {
162 if (err || response.statusCode !== 200) {
163 console.log(' ' + (err || response.body))
164 return response
165 ? on_failure(response.statusCode, response.body)
166 : on_failure(err.code, err.message)
167 } else {
168 console.log(' Success!')
169 console.log(' View report at: ' + response.body)
170 return on_success(response.body)
171 }
172 }
173 )
174}
175
176var sendToCodecovV3 = function(
177 codecov_endpoint,
178 query,
179 upload_body,
180 on_success,
181 on_failure
182) {
183 // Direct to S3
184 request(
185 {
186 uri: urlgrey(codecov_endpoint + '/upload/v4')
187 .query(query)
188 .toString(),
189 method: 'POST',
190 body: '',
191 headers: {
192 'Content-Type': 'text/plain',
193 Accept: 'text/plain',
194 },
195 },
196 function(err, response, result) {
197 if (err) {
198 sendToCodecovV2(
199 codecov_endpoint,
200 query,
201 upload_body,
202 on_success,
203 on_failure
204 )
205 } else {
206 var codecov_report_url = result.split('\n')[0]
207 request(
208 {
209 uri: result.split('\n')[1],
210 method: 'PUT',
211 body: upload_body,
212 headers: {
213 'Content-Type': 'text/plain',
214 },
215 },
216 function(err) {
217 if (err) {
218 sendToCodecovV2(
219 codecov_endpoint,
220 query,
221 upload_body,
222 on_success,
223 on_failure
224 )
225 } else {
226 console.log(' Success!')
227 console.log(' View report at: ' + codecov_report_url)
228 on_success(codecov_report_url)
229 }
230 }
231 )
232 }
233 }
234 )
235}
236
237var upload = function(args, on_success, on_failure) {
238 // Build query
239 var codecov_endpoint =
240 args.options.url ||
241 process.env.codecov_url ||
242 process.env.CODECOV_URL ||
243 'https://codecov.io'
244 var query = {}
245 var debug = []
246 var yamlFile =
247 args.options.yml ||
248 process.env.codecov_yml ||
249 process.env.CODECOV_YML ||
250 'codecov.yml'
251
252 console.log(
253 '' +
254 ' _____ _ \n' +
255 ' / ____| | | \n' +
256 '| | ___ __| | ___ ___ _____ __ \n' +
257 '| | / _ \\ / _` |/ _ \\/ __/ _ \\ \\ / / \n' +
258 '| |___| (_) | (_| | __/ (_| (_) \\ V / \n' +
259 ' \\_____\\___/ \\__,_|\\___|\\___\\___/ \\_/ \n' +
260 ' ' +
261 version
262 )
263
264 if ((args.options.disable || '').split(',').indexOf('detect') === -1) {
265 console.log('==> Detecting CI Provider')
266 query = detectProvider()
267 } else {
268 debug.push('disabled detect')
269 }
270
271 query.yaml = [yamlFile, '.codecov.yml'].reduce(function(result, file) {
272 return (
273 result ||
274 (fs.existsSync(path.resolve(process.cwd(), file))
275 ? path.resolve(process.cwd(), file)
276 : undefined)
277 )
278 }, undefined)
279
280 if (args.options.build) {
281 query.build = args.options.build
282 }
283
284 if (args.options.commit) {
285 query.commit = args.options.commit
286 }
287
288 if (args.options.branch) {
289 query.branch = args.options.branch
290 }
291
292 if (args.options.slug) {
293 query.slug = args.options.slug
294 }
295
296 var flags =
297 args.options.flags || process.env.codecov_flags || process.env.CODECOV_FLAGS
298 if (flags) {
299 query.flags = flags
300 }
301
302 var yamlToken
303 try {
304 var loadedYamlFile = jsYaml.safeLoad(fs.readFileSync(query.yaml, 'utf8'))
305 yamlToken =
306 loadedYamlFile && loadedYamlFile.codecov && loadedYamlFile.codecov.token
307 } catch (e) {
308 // silently fail
309 }
310 var token =
311 args.options.token ||
312 yamlToken ||
313 process.env.codecov_token ||
314 process.env.CODECOV_TOKEN
315 if (token) {
316 query.token = token
317 }
318
319 query.package = 'node-' + version
320
321 console.log('==> Configuration: ')
322 console.log(' Endpoint: ' + codecov_endpoint)
323 // Don't output `query` directly as it contains the upload token
324 console.log({
325 commit: query.commit,
326 branch: query.branch,
327 package: query.package,
328 })
329
330 var upload = ''
331
332 // Add specified env vars
333 var env_found = false
334 if (args.options.env || process.env.CODECOV_ENV || process.env.codecov_env) {
335 var env = (
336 args.options.env +
337 ',' +
338 (process.env.CODECOV_ENV || '') +
339 ',' +
340 (process.env.codecov_env || '')
341 ).split(',')
342 for (var i = env.length - 1; i >= 0; i--) {
343 if (env[i]) {
344 upload += env[i] + '=' + (process.env[env[i]] || '').toString() + '\n'
345 env_found = true
346 }
347 }
348 if (env_found) {
349 upload += '<<<<<< ENV\n'
350 }
351 }
352
353 // List git files
354 var root = path.resolve(args.options.root || query.root || '.')
355 console.log('==> Building file structure')
356 try {
357 upload +=
358 execSync('git ls-files || hg locate', { cwd: root })
359 .toString()
360 .trim() + '\n<<<<<< network\n'
361 } catch (err) {
362 // not a git/hg dir, emulating git/hg ignore behavior
363 upload +=
364 walk
365 .sync({ path: root, ignoreFiles: ['.gitignore', '.hgignore'] })
366 .join('\n')
367 .trim() + '\n<<<<<< network\n'
368 }
369 // Make gcov reports
370 if ((args.options.disable || '').split(',').indexOf('gcov') === -1) {
371 try {
372 console.log('==> Generating gcov reports (skip via --disable=gcov)')
373 var gcg = args.options['gcov-glob'] || ''
374 if (gcg) {
375 if (!isWindows) {
376 gcg = gcg
377 .split(' ')
378 .map(function(p) {
379 return "-not -path '" + p + "'"
380 })
381 .join(' ')
382 } else {
383 gcg = gcg
384 .split(' ')
385 .map(function(p) {
386 return '^| findstr /i /v ' + p
387 })
388 .join(' ')
389 }
390 }
391 var gcov
392 if (!isWindows) {
393 gcov =
394 'find ' +
395 (sanitizeVar(args.options['gcov-root']) || root) +
396 " -type f -name '*.gcno' " +
397 gcg +
398 ' -exec ' +
399 (sanitizeVar(args.options['gcov-exec']) || 'gcov') +
400 ' ' +
401 (sanitizeVar(args.options['gcov-args']) || '') +
402 ' {} +'
403 } else {
404 // @TODO support for root
405 // not straight forward due to nature of windows command dir
406 gcov =
407 'for /f "delims=" %g in (\'dir /a-d /b /s *.gcno ' +
408 gcg +
409 "') do " +
410 (sanitizeVar(args.options['gcov-exec']) || 'gcov') +
411 ' ' +
412 (sanitizeVar(args.options['gcov-args']) || '') +
413 ' %g'
414 }
415 debug.push(gcov)
416 console.log(' $ ' + gcov)
417 execSync(gcov)
418 } catch (e) {
419 console.log(' Failed to run gcov command.')
420 }
421 } else {
422 debug.push('disabled gcov')
423 }
424
425 // Detect .bowerrc
426 var bowerrc
427 if (!isWindows) {
428 bowerrc = execSync('test -f .bowerrc && cat .bowerrc || echo ""', {
429 cwd: root,
430 })
431 .toString()
432 .trim()
433 } else {
434 bowerrc = execSync('if exist .bowerrc type .bowerrc', { cwd: root })
435 .toString()
436 .trim()
437 }
438 if (bowerrc) {
439 bowerrc = JSON.parse(bowerrc).directory
440 if (bowerrc) {
441 if (!isWindows) {
442 more_patterns =
443 " -not -path '*/" + bowerrc.toString().replace(/\/$/, '') + "/*'"
444 } else {
445 more_patterns =
446 '| findstr /i /v \\' + bowerrc.toString().replace(/\/$/, '') + '\\'
447 }
448 }
449 }
450
451 var files = [],
452 file = null
453 if (args.options.pipe) {
454 // Append piped reports
455 upload += '# path=piped\n' + args.options.pipe.join('') + '\n<<<<<< EOF\n'
456 console.log('==> Reading report from stdin')
457 } else if (args.options.file) {
458 // Append manually entered reports
459 file = args.options.file
460 console.log('==> Targeting specific file')
461 try {
462 upload +=
463 '# path=' +
464 file +
465 '\n' +
466 fs.readFileSync(file, 'utf8').toString() +
467 '\n<<<<<< EOF\n'
468 console.log(' + ' + file)
469 files.push(file)
470 } catch (e) {
471 debug.push('failed: ' + file.split('/').pop())
472 console.log(' X Failed to read file at ' + file)
473 }
474 } else if ((args.options.disable || '').split(',').indexOf('search') === -1) {
475 console.log('==> Scanning for reports')
476 var _files
477 if (!isWindows) {
478 _files = execSync('find ' + root + ' ' + patterns + more_patterns)
479 .toString()
480 .trim()
481 .split('\n')
482 } else {
483 // @TODO support for a root directory
484 // It's not straightforward due to the nature of the dir command
485 _files = execSync('dir ' + patterns + more_patterns)
486 .toString()
487 .trim()
488 .split('\r\n')
489 }
490 if (_files) {
491 for (var i2 = _files.length - 1; i2 >= 0; i2--) {
492 file = _files[i2]
493 try {
494 upload +=
495 '# path=' +
496 file +
497 '\n' +
498 fs.readFileSync(file, 'utf8').toString() +
499 '\n<<<<<< EOF\n'
500 console.log(' + ' + file)
501 files.push(file)
502 } catch (e) {
503 debug.push('failed: ' + file.split('/').pop())
504 console.log(' X Failed to read file at ' + file)
505 }
506 }
507 }
508 } else {
509 debug.push('disabled search')
510 }
511
512 if (files) {
513 // Upload to Codecov
514 if (args.options.dump) {
515 console.log('-------- DEBUG START --------')
516 console.log(upload)
517 console.log('-------- DEBUG END --------')
518 } else {
519 console.log('==> Uploading reports')
520 var _upload
521 if ((args.options.disable || '').split(',').indexOf('s3') === -1) {
522 _upload = sendToCodecovV3
523 } else {
524 _upload = sendToCodecovV2
525 }
526 _upload(
527 codecov_endpoint,
528 query,
529 upload,
530 function() {
531 // remove files after Uploading
532 if (args.options.clear) {
533 for (var i = files.length - 1; i >= 0; i--) {
534 try {
535 fs.unlinkSync(files[i])
536 } catch (e) {}
537 }
538 }
539 if (on_success) {
540 on_success.apply(this, arguments)
541 }
542 },
543 on_failure || function() {}
544 )
545 }
546 }
547
548 return {
549 body: upload,
550 files: files,
551 query: query,
552 debug: debug,
553 url: codecov_endpoint,
554 }
555}
556
557function sanitizeVar(arg) {
558 return arg.replace(/&/g, '')
559}
560
561module.exports = {
562 sanitizeVar: sanitizeVar,
563 upload: upload,
564 version: version,
565 sendToCodecovV2: sendToCodecovV2,
566 sendToCodecovV3: sendToCodecovV3,
567}