21
21
const fs = require ( 'fs' ) ,
22
22
xml2js = require ( 'xml2js' ) ,
23
23
crypto = require ( 'crypto' ) ,
24
- assert = require ( 'assert' ) . strict ,
25
24
parser = new xml2js . Parser ( ) ,
26
25
path = require ( 'path' ) ;
27
- var timestamp , cb ;
26
+ var timestamp ;
28
27
29
28
var token = process . env . COVERALLS_TOKEN ;
30
29
@@ -33,14 +32,14 @@ var token = process.env.COVERALLS_TOKEN;
33
32
* Loads file containing source code, returns a hash and line count
34
33
* @param {String } path - Path to the source code file.
35
34
* @returns {Object } key `Hash` contains MD5 digest string of file; `count` contains number of lines in source file
36
- * @todo Make asynchronous
37
35
*/
38
36
function md5 ( path ) {
39
- var hash = crypto . createHash ( 'md5' ) ; // Creating hash object
40
- var buf = fs . readFileSync ( path , 'utf-8' ) ; // Read in file
41
- var count = buf . split ( / \r \n | \r | \n / ) . length ; // Count the number of lines
42
- hash . update ( buf , 'utf-8' ) ; // Update hash
43
- return { hash : hash . digest ( 'hex' ) , count : count } ;
37
+ const hash = crypto . createHash ( 'md5' ) ; // Creating hash object
38
+ const buf = fs . readFileSync ( path , 'utf-8' ) ; // Read in file
39
+ const count = buf . split ( / \r \n | \r | \n / ) . length ; // Count the number of lines
40
+ hash . update ( buf , 'utf-8' ) ; // Update hash
41
+
42
+ return { hash : hash . digest ( 'hex' ) , count : count } ;
44
43
}
45
44
46
45
@@ -50,42 +49,41 @@ function md5(path) {
50
49
* @param {Array } classList - An array of class objects from the loaded XML file.
51
50
* @param {String } srcPath - The root path of the code repository.
52
51
* @param {String } sha - The commit SHA for this coverage test.
53
- * @param {function } callback - The callback function to run when complete. Takes object containing array of source
54
- * code files and their code coverage
55
52
* @returns {Object }
56
53
* @todo Generalize path default
57
- * @fixme Doesn't work with python's coverage
58
54
*/
59
- function formatCoverage ( classList , srcPath , sha ) {
60
- var job = { } ;
61
- var sourceFiles = [ ] ;
62
- var digest ;
63
- srcPath = typeof srcPath != "undefined" ? srcPath : process . env . HOMEPATH ; // default to home dir
64
- // For each class, create file object containing array of lines covered and add to sourceFile array
65
- classList . forEach ( async c => {
66
- let file = { } ; // Initialize file object
67
- let fullPath = c . $ . filename . startsWith ( srcPath ) ? c . $ . filename : path . join ( srcPath , c . $ . filename ) ;
68
- digest = md5 ( fullPath ) ; // Create digest and line count for file
69
- let lines = new Array ( digest . count ) . fill ( null ) ; // Initialize line array the size of source code file
70
- c . lines [ 0 ] . line . forEach ( ln => {
71
- let n = Number ( ln . $ . number ) ;
72
- if ( n <= digest . count ) { lines [ n ] = Number ( ln . $ . hits ) }
73
- } ) ;
74
- // create source file object
75
- file . name = c . $ . filename ;
76
- file . source_digest = digest . hash ;
77
- file . coverage = lines ; // file.coverage[0] == line 1
78
- sourceFiles . push ( file ) ;
79
- } ) ;
55
+ async function formatCoverage ( classList , srcPath , sha ) {
56
+ var job = { } ;
57
+ var sourceFiles = [ ] ;
58
+ var digest ;
59
+ srcPath = typeof srcPath != 'undefined' ? srcPath : process . env . REPO_PATH ; // default to home dir
60
+ // For each class, create file object containing array of lines covered and add to sourceFile array
61
+ await Promise . all ( classList . map ( async c => {
62
+ let file = { } ; // Initialize file object
63
+ let fullPath = c . $ . filename . startsWith ( srcPath ) ? c . $ . filename : path . join ( srcPath , c . $ . filename ) ;
64
+ digest = md5 ( fullPath ) ; // Create digest and line count for file
65
+ let lines = new Array ( digest . count ) . fill ( null ) ; // Initialize line array the size of source code file
66
+ c . lines [ 0 ] . line . forEach ( ln => {
67
+ let n = Number ( ln . $ . number ) ;
68
+ if ( n <= digest . count ) {
69
+ lines [ n ] = Number ( ln . $ . hits ) ;
70
+ }
71
+ } ) ;
72
+ // create source file object
73
+ file . name = c . $ . filename ;
74
+ file . source_digest = digest . hash ;
75
+ file . coverage = lines ; // file.coverage[0] == line 1
76
+ sourceFiles . push ( file ) ;
77
+ } ) ) ;
80
78
81
- job . repo_token = token ; // env secret token?
82
- job . service_name = `coverage/${ process . env . USERDOMAIN } ` ;
83
- // The associated pull request ID of the build. Used for updating the status and/or commenting.
84
- job . service_pull_request = '' ;
85
- job . source_files = sourceFiles ;
86
- job . commit_sha = sha ;
87
- job . run_at = timestamp ; // "2013-02-18 00:52:48 -0800"
88
- cb ( job ) ;
79
+ job . repo_token = token ; // env secret token
80
+ job . service_name = `coverage/${ process . env . USERDOMAIN } ` ;
81
+ // The associated pull request ID of the build. Used for updating the status and/or commenting.
82
+ job . service_pull_request = '' ;
83
+ job . source_files = sourceFiles ;
84
+ job . commit_sha = sha ;
85
+ job . run_at = timestamp ; // "2013-02-18 00:52:48 -0800"
86
+ return job ;
89
87
}
90
88
91
89
/**
@@ -95,44 +93,42 @@ function formatCoverage(classList, srcPath, sha) {
95
93
* @param {String } sha - The commit SHA for this coverage test
96
94
* @param {String } repo - The repo to which the commit belongs
97
95
* @param {Array } submodules - A list of submodules for separating coverage into
98
- * @param {function } callback - The callback function to run when complete
99
96
* @see {@link https://github.com/cobertura/cobertura/wiki|Cobertura Wiki }
100
97
*/
101
- function coverage ( path , repo , sha , submodules , callback ) {
102
- cb = callback ; // @fixme Making callback global feels hacky
103
- fs . readFile ( path , function ( err , data ) { // Read in XML file
104
- if ( err ) { throw err } // @fixme deal with file not found errors
105
- parser . parseString ( data , function ( err , result ) { // Parse XML
106
- // Extract root code path
107
- const rootPath = ( result . coverage . sources [ 0 ] . source [ 0 ] || process . env . REPO_PATH ) . replace ( / [ \/ | \\ ] + $ / , '' )
108
- assert ( rootPath . endsWith ( process . env . REPO_NAME ) , 'Incorrect source code repository' )
109
- timestamp = new Date ( result . coverage . $ . timestamp * 1000 ) ; // Convert UNIX timestamp to Date object
110
- let classes = [ ] ; // Initialize classes array
98
+ function coverage ( path , repo , sha , submodules ) {
99
+ return fs . promises . readFile ( path ) // Read in XML file
100
+ . then ( parser . parseStringPromise ) // Parse XML
101
+ . then ( result => {
102
+ // Extract root code path
103
+ const rootPath = ( result . coverage . sources [ 0 ] . source [ 0 ] || process . env . REPO_PATH )
104
+ . replace ( / [ \/ | \\ ] + $ / , '' ) ;
105
+ timestamp = new Date ( result . coverage . $ . timestamp * 1000 ) ; // Convert UNIX timestamp to Date object
106
+ let classes = [ ] ; // Initialize classes array
111
107
112
- const packages = result . coverage . packages [ 0 ] . package ;
113
- packages . forEach ( pkg => { classes . push ( pkg . classes [ 0 ] . class ) } ) ; // Get all classes
114
- classes = classes . reduce ( ( acc , val ) => acc . concat ( val ) , [ ] ) ; // Flatten
108
+ const packages = result . coverage . packages [ 0 ] . package ;
109
+ packages . forEach ( pkg => { classes . push ( pkg . classes [ 0 ] . class ) ; } ) ; // Get all classes
110
+ classes = classes . reduce ( ( acc , val ) => acc . concat ( val ) , [ ] ) ; // Flatten
115
111
116
- // The submodules
117
- const byModule = { 'main' : [ ] } ;
118
- submodules . forEach ( ( x ) => { byModule [ x ] = [ ] ; } ) ; // initialize submodules
112
+ // The submodules
113
+ const byModule = { 'main' : [ ] } ;
114
+ submodules . forEach ( ( x ) => { byModule [ x ] = [ ] ; } ) ; // initialize submodules
119
115
120
- // Sort into piles
121
- byModule [ 'main' ] = classes . filter ( function ( e ) {
122
- if ( e . $ . filename . search ( / ( t e s t s \\ | _ .* t e s t | d o c s \\ ) / i) !== - 1 ) { return false ; } // Filter out tests and docs
123
- if ( ! Array . isArray ( e . lines [ 0 ] . line ) ) { return false ; } // Filter out files with no functional lines
124
- for ( let submodule of submodules ) {
125
- if ( e . $ . filename . startsWith ( submodule ) ) {
126
- byModule [ submodule ] . push ( e ) ; return false ;
127
- }
128
- }
129
- return true ;
116
+ // Sort into piles
117
+ byModule [ 'main' ] = classes . filter ( function ( e ) {
118
+ if ( e . $ . filename . search ( / ( t e s t s \\ | _ .* t e s t | d o c s \\ ) / i) !== - 1 ) return false ; // Filter out tests and docs
119
+ if ( ! Array . isArray ( e . lines [ 0 ] . line ) ) return false ; // Filter out files with no functional lines
120
+ for ( let submodule of submodules ) {
121
+ if ( e . $ . filename . startsWith ( submodule ) ) {
122
+ byModule [ submodule ] . push ( e ) ;
123
+ return false ;
124
+ }
125
+ }
126
+ return true ;
127
+ } ) ;
128
+ // Select module
129
+ let modules = byModule [ repo ] || byModule [ 'main' ] ;
130
+ return formatCoverage ( modules , rootPath , sha ) ;
130
131
} ) ;
131
- // Select module
132
- let modules = byModule [ repo ] || byModule [ 'main' ] ;
133
- formatCoverage ( modules , rootPath , callback ) ;
134
- } ) ;
135
- } ) ;
136
132
}
137
133
138
134
0 commit comments