Repository: codecov/uploader
Pull request #269 (2021-08-03 15:12:02)

Fix support glob files
fixes https://github.com/codecov/codecov-action/issues/428


Patch:
diff --git a/bin/codecov.ts b/bin/codecov.ts
index ac828ab..08e8163 100755
--- a/bin/codecov.ts
+++ b/bin/codecov.ts
@@ -124,7 +124,7 @@ main(argv)
     )
   })
   .catch(error => {
-    error(`Error!: ${error}`, { level: 'error', argv })
+    logError(`Error!: ${error}`)
     const end = Date.now()
     verbose(`End of uploader: ${end - start} milliseconds`, argv.verbose)
     process.exit(argv.nonZero ? -1 : 0)
diff --git a/src/helpers/files.ts b/src/helpers/files.ts
index c026eb7..93e12ba 100644
--- a/src/helpers/files.ts
+++ b/src/helpers/files.ts
@@ -5,7 +5,7 @@ import fs from 'fs'
 import glob from 'fast-glob'
 import { posix as path } from 'path'
 import { logAndThrow } from './util'
-import { logError, verbose } from './logger'
+import { info, logError, verbose } from './logger'
 
 export const MARKER_NETWORK_END = '<<<<<< network\n'
 export const MARKER_FILE_END = '<<<<<< EOF\n'
@@ -307,6 +307,16 @@ export function readCoverageFile(
   return ''
 }
 
+/**
+ *
+ * @param {string} projectRoot
+ * @param {string} filePath
+ * @returns boolean
+ */
+export function fileExists(projectRoot: string, filePath: string): boolean {
+  return fs.existsSync(getFilePath(projectRoot, filePath))
+}
+
 /**
  *
  * @param {string} filePath
diff --git a/src/index.ts b/src/index.ts
index 12dbffa..d753a33 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -11,9 +11,11 @@ import { getToken } from './helpers/token'
 import {
   coverageFilePatterns,
   fetchGitRoot,
+  fileExists,
   fileHeader,
   getCoverageFiles,
   getFileListing,
+  getFilePath,
   MARKER_ENV_END,
   MARKER_FILE_END,
   MARKER_NETWORK_END,
@@ -132,44 +134,46 @@ export async function main(
   // == Step 5: select coverage files (search or specify)
 
   // Look for files
-  let coverageFilePaths = []
-  if (!args.file) {
-    info('Searching for coverage files...')
-    coverageFilePaths = await getCoverageFiles(
-      args.dir || projectRoot,
-      coverageFilePatterns(),
-    )
-    if (coverageFilePaths.length > 0) {
-      info(`=> Found ${coverageFilePaths.length} possible coverage files:`)
-      info(coverageFilePaths.join('\n'))
-    } else {
-      logAndThrow(
-        'No coverage files located, please try use `-f`, or change the project root with `-R`',
-      )
-    }
-  } else {
+  let coverageFilePaths: string[] = []
+  info('Searching for coverage files...')
+  if (args.file) {
     if (typeof args.file === 'string') {
       coverageFilePaths = [args.file]
     } else {
       coverageFilePaths = args.file
     }
-
-    coverageFilePaths.filter(file => {
-      return validateHelpers.validateFileNamePath(file)
-    })
-    if (coverageFilePaths.length === 0) {
-      logAndThrow('No coverage files found, exiting.')
-    }
   }
+  coverageFilePaths = coverageFilePaths.concat(await getCoverageFiles(
+    args.dir || projectRoot,
+    coverageFilePaths.length > 0 ? coverageFilePaths : coverageFilePatterns(),
+  ))
+
+  // Remove invalid and duplicate file paths
+  coverageFilePaths = [... new Set(coverageFilePaths.filter(file => {
+    return validateHelpers.validateFileNamePath(file) &&
+      fileExists(args.dir || projectRoot, file)
+  }))]
+
+  if (coverageFilePaths.length > 0) {
+    info(`=> Found ${coverageFilePaths.length} possible coverage files:\n  ` +
+        coverageFilePaths.join('\n  '))
+  } else {
+    const noFilesError = args.file ?
+      'No coverage files found, exiting.' :
+      'No coverage files located, please try use `-f`, or change the project root with `-R`'
+    logAndThrow(noFilesError)
+  }
+
   verbose('End of network processing', Boolean(args.verbose))
   // == Step 6: generate upload file
   // TODO: capture envs
 
   // Get coverage report contents
+  let coverageFileAdded = false
   for (const coverageFile of coverageFilePaths) {
     let fileContents
     try {
-      info(`Processing ${coverageFile}...`),
+      info(`Processing ${getFilePath(args.dir || projectRoot, coverageFile)}...`),
         (fileContents = await readCoverageFile(
           args.dir || projectRoot,
           coverageFile,
@@ -183,6 +187,10 @@ export async function main(
       .concat(fileHeader(coverageFile))
       .concat(fileContents)
       .concat(MARKER_FILE_END)
+    coverageFileAdded = true
+  }
+  if (!coverageFileAdded) {
+    logAndThrow( 'No coverage files could be found to upload, exiting.')
   }
 
   // Cleanup


Test patch:
diff --git a/test/helpers/files.test.ts b/test/helpers/files.test.ts
index df0579a..e6e7289 100644
--- a/test/helpers/files.test.ts
+++ b/test/helpers/files.test.ts
@@ -106,6 +106,17 @@ describe('File Helpers', () => {
         expect(fileHelpers.coverageFilePatterns()).toContain('jacoco*.xml')
       })
     })
+    describe('file exists', () => {
+      it('returns true if file exists', () => {
+        expect(fileHelpers.fileExists('', 'test/fixtures/coverage.txt'))
+      })
+      it('returns false if file doesnt exist', () => {
+        expect(fileHelpers.fileExists('', 'test/fake/path/to/file.txt'))
+      })
+      it('returns true if file exists in a directory', () => {
+        expect(fileHelpers.fileExists('test/fixtures', 'coverage.txt'))
+      })
+    })
     describe('getFilePath()', () => {
       it('should return path when file path has no starting slash', () => {
         expect(fileHelpers.getFilePath('/usr/', 'coverage.xml')).toEqual(
diff --git a/test/index.test.ts b/test/index.test.ts
index 25f40da..e5f600f 100644
--- a/test/index.test.ts
+++ b/test/index.test.ts
@@ -192,7 +192,7 @@ describe('Uploader Core', () => {
       flags: '',
     })
     expect(log).toHaveBeenCalledWith(
-      expect.stringMatching('Processing test/fixtures/coverage.txt...'),
+      expect.stringMatching(/Processing.*test\/fixtures\/coverage\.txt\.\.\./),
     )
   })
 
@@ -211,18 +211,36 @@ describe('Uploader Core', () => {
       flags: '',
     })
     expect(log).toHaveBeenCalledWith(
-      expect.stringMatching('Processing test/fixtures/coverage.txt...'),
+      expect.stringMatching(/Processing.*test\/fixtures\/coverage\.txt\.\.\./),
     )
     expect(log).toHaveBeenCalledWith(
-      expect.stringMatching('Processing test/fixtures/coverage.txt...'),
+      expect.stringMatching(/Processing.*test\/fixtures\/other\/coverage\.txt\.\.\./),
     )
+    expect(log).not.toHaveBeenCalledWith(
+      expect.stringMatching(/Processing.*test\/does\/not\/exist\.txt\.\.\./),
+    )
+  })
+
+  it('Can handle glob files', async () => {
+    const log = jest.spyOn(console, 'log').mockImplementation(() => {})
+    await app.main({
+      dryRun: 'true',
+      file: [
+        'cover*.txt',
+      ],
+      name: 'customname',
+      token: 'abcdefg',
+      url: 'https://codecov.io',
+      flags: '',
+    })
     expect(log).toHaveBeenCalledWith(
-      expect.stringMatching('Processing test/does/not/exist.txt...'),
+      expect.stringMatching(/Processing.*test\/fixtures\/coverage\.txt\.\.\./),
     )
     expect(log).toHaveBeenCalledWith(
-      expect.stringContaining(
-        'Could not read coverage file (test/does/not/exist.txt):',
-      ),
+      expect.stringMatching(/Processing.*test\/fixtures\/other\/coverage\.txt\.\.\./),
+    )
+    expect(log).not.toHaveBeenCalledWith(
+      expect.stringMatching(/Processing.*test\/does\/not\/exist\.txt\.\.\./),
     )
   })