@@ -7,6 +7,7 @@ const path = require('path');
77const createDebug = require ( 'debug' ) ;
88const localtunnel = require ( 'localtunnel' ) ;
99const kill = require ( 'tree-kill' ) ;
10+ const shell = require ( 'shelljs' ) ;
1011
1112const config = require ( './config/config' ) . settings ;
1213const Coverage = require ( './coverage' ) ;
@@ -175,19 +176,6 @@ function partial(func) {
175176 } ;
176177}
177178
178- function chain ( func ) {
179- return function curried ( ...args ) {
180- if ( args . length >= func . length ) {
181- return func . apply ( this , args ) ;
182- } else {
183- return function ( ...args2 ) {
184- return curried . apply ( this , args2 . concat ( args ) ) ;
185- }
186- }
187- } ;
188- }
189-
190-
191179
192180/**
193181 * Check if job already has record, if so, update from record and finish, otherwise call tests function.
@@ -235,6 +223,42 @@ const openTunnel = async () => {
235223}
236224
237225
226+ /**
227+ * Lists the submodules within a Git repository. If none are found null is returned.
228+ * @param {String } repoPath - The path of the repository
229+ * @returns {Array } A list of submodule names, or null if none were found
230+ */
231+ function listSubmodules ( repoPath ) {
232+ if ( ! shell . which ( 'git' ) ) { throw new Error ( 'Git not found on path' ) ; }
233+ shell . pushd ( repoPath ) ;
234+ let listModules = 'git config --file .gitmodules --get-regexp path' ;
235+ const modules = shell . exec ( listModules )
236+ shell . popd ( ) ;
237+ return ( ! modules . code && modules . stdout !== '' ) ? modules . match ( / (?< = s u b m o d u l e .) [ \w - ] + / g) : [ ] ;
238+ }
239+
240+
241+ /**
242+ * Get the corresponding repository path for a given repo. The function first checks the settings.
243+ * If the `repos` field doesn't exist, the path in ENV is used. If the name is not a key in the
244+ * `repos` object then we check each repo path for submodules and return the first matching
245+ * submodule path. Otherwise returns null.
246+ * @param {String } name - The name of the repository
247+ * @returns {String } The repository path if found
248+ */
249+ function getRepoPath ( name ) {
250+ if ( ! config . repos ) { return process . env [ 'REPO_PATH' ] ; } // Legacy, to remove
251+ if ( config . repos [ name ] ) { return config . repos [ name ] ; } // Found path, return
252+ const modules = listSubmodules ( process . env [ 'REPO_PATH' ] ) ;
253+ let repoPath = process . env [ 'REPO_PATH' ] ;
254+ if ( modules && modules . includes ( name ) ) {
255+ // If the repo is a submodule, modify path
256+ repoPath += ( path . sep + name ) ;
257+ }
258+ return repoPath ; // No modules matched, return default
259+ }
260+
261+
238262/**
239263 * Starts a timer with a callback to kill the job's process.
240264 * @param {Object } job - The Job with an associated process in the data field.
@@ -263,8 +287,9 @@ function computeCoverage(job) {
263287 return ;
264288 }
265289 console . log ( 'Updating coverage for job #' + job . id )
266- let xmlPath = path . join ( config . dataPath , 'reports' , job . data . sha , 'CoverageResults.xml' )
267- Coverage ( xmlPath , job . data . repo , job . data . sha , obj => {
290+ const xmlPath = path . join ( config . dataPath , 'reports' , job . data . sha , 'CoverageResults.xml' )
291+ const modules = listSubmodules ( process . env . REPO_PATH ) ;
292+ Coverage ( xmlPath , job . data . repo , job . data . sha , modules , obj => {
268293 // Digest and save percentage coverage
269294 let misses = 0 , hits = 0 ;
270295 for ( let file of obj . source_files ) {
@@ -388,7 +413,7 @@ function getBadgeData(data) {
388413 report [ 'color' ] = 'orange' ;
389414 // Check test isn't already on the pile
390415 let onPile = false ;
391- for ( let job of queue . pile ) { if ( job . id === id ) { onPile = true ; break ; } }
416+ for ( let job of queue . pile ) { if ( job . data . sha === id ) { onPile = true ; break ; } }
392417 if ( ! onPile ) { // Add test to queue
393418 data [ 'skipPost' ] = true
394419 queue . add ( data ) ;
@@ -397,7 +422,7 @@ function getBadgeData(data) {
397422 record = Array . isArray ( record ) ? record . pop ( ) : record ; // in case of duplicates, take last
398423 switch ( data . context ) {
399424 case 'status' :
400- if ( record [ 'status' ] === 'error' || ! record [ 'coverage' ] ) {
425+ if ( record [ 'status' ] === 'error' ) {
401426 report [ 'message' ] = 'unknown' ;
402427 report [ 'color' ] = 'orange' ;
403428 } else {
@@ -433,5 +458,5 @@ class APIError extends Error {
433458module . exports = {
434459 ensureArray, loadTestRecords, compareCoverage, computeCoverage, getBadgeData, log, shortID,
435460 openTunnel, APIError, queue, partial, startJobTimer, updateJobFromRecord, shortCircuit, isSHA,
436- fullpath, strToBool, saveTestRecords
461+ fullpath, strToBool, saveTestRecords, listSubmodules , getRepoPath
437462}
0 commit comments