Repository: codecov/uploader
Pull request #871 (2022-09-01 15:25:44)

Release 0.3.0


Patch:
diff --git a/.circleci/config.yml b/.circleci/config.yml
index 39833f1..6c85713 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -439,7 +439,7 @@ jobs:
             - release_tag
   release:
     docker:
-      - image: google/cloud-sdk:398.0.0-slim@sha256:2c63781317816109976151a4f233222926dd62baee33d402a5fb9ee2707c9745
+      - image: google/cloud-sdk:399.0.0-slim@sha256:a0cc3949f11370297384710b4bd6f680edb8d7fbf225a7d04a48384d54277a3a
     steps:
       - attach_workspace:
           at: .
diff --git a/.gitignore b/.gitignore
index 9d8191b..28edf13 100644
--- a/.gitignore
+++ b/.gitignore
@@ -73,3 +73,5 @@ codecov.exe
 .coverage
 # File genrated as part of XCode tests
 coverage-report-test.json
+
+*.coverage.txt
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a034533..de46d4f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,40 @@
 
 All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
 
+## [0.3.0](https://github.com/codecov/uploader/compare/v0.2.0...v0.3.0) (2022-09-01)
+
+
+### Features
+
+* accept comma-separated files in args ([#861](https://github.com/codecov/uploader/issues/861)) ([2a3e897](https://github.com/codecov/uploader/commit/2a3e897ba654eea43005e27768435f83ce074d92))
+* add gcov executable ([#794](https://github.com/codecov/uploader/issues/794)) ([fecf6b4](https://github.com/codecov/uploader/commit/fecf6b401ea44dcb14f52820107f23170c21709a))
+* create fixes on c-like and php files ([#869](https://github.com/codecov/uploader/issues/869)) ([29b240c](https://github.com/codecov/uploader/commit/29b240c07ca4bfc0312c66eb4d2fd78f2bf6c0db))
+* ignore files ending in .*js ([#798](https://github.com/codecov/uploader/issues/798)) ([1cd0d23](https://github.com/codecov/uploader/commit/1cd0d23322988a9af7f06d7fd8681ce4e5558b5c))
+
+
+### Bug Fixes
+
+* **deps:** pin dependency undici to 5.5.1 ([#806](https://github.com/codecov/uploader/issues/806)) ([894b823](https://github.com/codecov/uploader/commit/894b8233d0b92694d5f21df8145b908ffb180524))
+* **deps:** update dependency https-proxy-agent to v5.0.1 ([90a68c0](https://github.com/codecov/uploader/commit/90a68c021b0cc7f098fb644934b1d29771e4fd88))
+* **deps:** update dependency undici to v5.10.0 ([#862](https://github.com/codecov/uploader/issues/862)) ([65aa5f0](https://github.com/codecov/uploader/commit/65aa5f0b17ffdb0b63909f27d800ada4e5d8280a))
+* **deps:** update dependency undici to v5.2.0 ([e7fb541](https://github.com/codecov/uploader/commit/e7fb54164013773066c144140344dcd5f88b0eba))
+* **deps:** update dependency undici to v5.4.0 ([#777](https://github.com/codecov/uploader/issues/777)) ([9ff8396](https://github.com/codecov/uploader/commit/9ff83961ca0e09acf4d0f137ad9d65e5f4089f4d))
+* **deps:** update dependency undici to v5.5.1 ([#804](https://github.com/codecov/uploader/issues/804)) ([ef52c46](https://github.com/codecov/uploader/commit/ef52c46ac47eb0011e7ae112e516f86a999f9217))
+* **deps:** update dependency undici to v5.6.0 ([#819](https://github.com/codecov/uploader/issues/819)) ([ac8eed9](https://github.com/codecov/uploader/commit/ac8eed9c0ceca1ce9ee8db41b4d0d73b9782dc01))
+* **deps:** update dependency undici to v5.8.0 ([#826](https://github.com/codecov/uploader/issues/826)) ([948d38d](https://github.com/codecov/uploader/commit/948d38d662708f0e885e5b0b9093b07c3db6f87f))
+* **deps:** update dependency undici to v5.8.1 ([#843](https://github.com/codecov/uploader/issues/843)) ([84059c4](https://github.com/codecov/uploader/commit/84059c4556c897599ac65422cf3730e94071bd74))
+* **deps:** update dependency undici to v5.8.2 ([#844](https://github.com/codecov/uploader/issues/844)) ([469c64b](https://github.com/codecov/uploader/commit/469c64b560f62066d7c48370a8f093286ab76ff6))
+* **deps:** update dependency undici to v5.9.1 ([#854](https://github.com/codecov/uploader/issues/854)) ([0e6c734](https://github.com/codecov/uploader/commit/0e6c734109c78ca4ed746a05a1ff9be24b33c361))
+* **deps:** update dependency yargs to v17.4.1 ([d0d9548](https://github.com/codecov/uploader/commit/d0d95483cc1aa5a7da86969af3f42d7824d280ef))
+* **deps:** update dependency yargs to v17.5.0 ([5911bb5](https://github.com/codecov/uploader/commit/5911bb541a0474cbeb6ad01b095f154a0ea0b7dd))
+* **deps:** update dependency yargs to v17.5.1 ([#764](https://github.com/codecov/uploader/issues/764)) ([fe181a2](https://github.com/codecov/uploader/commit/fe181a210765f6c6e6ddfe7c29c933b4e1329909))
+* increase maxBuffer of spawnSync ([c121446](https://github.com/codecov/uploader/commit/c12144697e95051b061488feae60db4b98d600c2))
+* parse both versions of ssh urls for remotes ([#793](https://github.com/codecov/uploader/issues/793)) ([84df6d1](https://github.com/codecov/uploader/commit/84df6d138c97db110d73345a74f97bca9a904d96))
+* store upload file contents on a Buffer ([0209be2](https://github.com/codecov/uploader/commit/0209be276dc9df75b41da8436f5d7209ae368a11))
+* suppress errors during glob for files ([#855](https://github.com/codecov/uploader/issues/855)) ([f8d7a3a](https://github.com/codecov/uploader/commit/f8d7a3a82034a3138aa4d9ddc99f7d9fa17d8dc9))
+* throw error when flags do not match pattern ([#831](https://github.com/codecov/uploader/issues/831)) ([cf2585c](https://github.com/codecov/uploader/commit/cf2585cef6ae72f1ac8fc0fba9ec645ae2750d7e)), closes [#829](https://github.com/codecov/uploader/issues/829) [#835](https://github.com/codecov/uploader/issues/835)
+* typo ([#812](https://github.com/codecov/uploader/issues/812)) ([3b2e37d](https://github.com/codecov/uploader/commit/3b2e37d290e429e7d12210e7e8dd56674f089a3c))
+
 ### [0.2.6](https://github.com/codecov/uploader/compare/v0.2.0...v0.2.6) (2022-08-24)
 
 
diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json
index 29b61b8..da0062e 100644
--- a/npm-shrinkwrap.json
+++ b/npm-shrinkwrap.json
@@ -1,12 +1,12 @@
 {
   "name": "@codecov/uploader",
-  "version": "0.2.6",
+  "version": "0.3.0",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "@codecov/uploader",
-      "version": "0.2.6",
+      "version": "0.3.0",
       "license": "ISC",
       "dependencies": {
         "fast-glob": "3.2.11",
diff --git a/package.json b/package.json
index 56fa880..47d12b5 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@codecov/uploader",
-  "version": "0.2.6",
+  "version": "0.3.0",
   "description": "Codecov Report Uploader",
   "private": true,
   "bin": {
diff --git a/src/helpers/cli.ts b/src/helpers/cli.ts
index 312fb52..be84807 100644
--- a/src/helpers/cli.ts
+++ b/src/helpers/cli.ts
@@ -178,6 +178,7 @@ const args: ICLIArgument[] = [
     name: 'feature',
     type: 'string',
     description: `Toggle functionalities. Separate multiple ones by comma: -X network,search
+      -X fixes         Enable file fixes to ignore common lines from coverage (e.g. blank lines or empty brackets)
       -X network       Disable uploading the file network
       -X search        Disable searching for coverage files`,
   },
diff --git a/src/helpers/fixes.ts b/src/helpers/fixes.ts
new file mode 100644
index 0000000..6f031d6
--- /dev/null
+++ b/src/helpers/fixes.ts
@@ -0,0 +1,70 @@
+import fs from 'fs'
+import readline from 'readline'
+
+import { getAllFiles } from './files'
+import { UploadLogger } from './logger'
+
+export const FIXES_HEADER = '# path=fixes\n'
+
+export async function generateFixes(projectRoot: string): Promise<string> {
+  // Fake out the UploaderArgs as they are not needed
+  const allFiles = await getAllFiles(projectRoot, projectRoot, {
+    flags: '',
+    slug: '',
+    upstream: '',
+  })
+
+  const allAdjustments: string[] = []
+  const EMPTYLINE = /^\s*$/mg
+  // { or }
+  const SYNTAXBRACKET = /^\s*[{}]\s*(\/\/.*)?$/m
+  // [ or ]
+  const SYNTAXLIST = /^\s*[[\]]\s*(\/\/.*)?$/m
+
+  for (const file of allFiles) {
+    let lineAdjustments: string[] = []
+
+    if (
+        file.match(/\.c$/) ||
+        file.match(/\.cpp$/) ||
+        file.match(/\.h$/) ||
+        file.match(/\.hpp$/) ||
+        file.match(/\.m$/) ||
+        file.match(/\.swift$/) ||
+        file.match(/\.vala$/)
+    ) {
+      lineAdjustments = await getMatchedLines(file, [EMPTYLINE, SYNTAXBRACKET])
+    } else if (
+        file.match(/\.php$/)
+    ) {
+      lineAdjustments = await getMatchedLines(file, [SYNTAXBRACKET, SYNTAXLIST])
+    }
+
+    if (lineAdjustments.length > 0) {
+      UploadLogger.verbose(`Matched file ${file} for adjustments: ${lineAdjustments.join(',')}`)
+      allAdjustments.push(`${file}:${lineAdjustments.join(',')}\n`)
+    }
+  }
+  return allAdjustments.join('')
+}
+
+async function getMatchedLines(file: string, matchers: RegExp[]): Promise<string[]> {
+  const fileStream = fs.createReadStream(file)
+  const rl = readline.createInterface({
+    input: fileStream,
+    crlfDelay: Infinity
+  });
+
+  const matchedLines: string[] = []
+  let lineNumber = 1
+
+  for await (const line of rl) {
+    for (const matcher of matchers) {
+      if (line.match(matcher)) {
+        matchedLines.push(lineNumber.toString())
+      }
+    }
+    lineNumber++
+  }
+  return matchedLines
+}
diff --git a/src/index.ts b/src/index.ts
index 333bb51..3c721d9 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -23,6 +23,7 @@ import {
   removeFile,
 } from './helpers/files'
 import { generateCoveragePyFile } from './helpers/coveragepy'
+import { generateFixes, FIXES_HEADER } from './helpers/fixes'
 import { generateGcovCoverageFiles } from './helpers/gcov'
 import { generateXcodeCoverageFiles } from './helpers/xcode'
 import { argAsArray } from './helpers/util'
@@ -322,6 +323,16 @@ export async function main(
     uploadFileChunks.push(Buffer.from(MARKER_ENV_END))
   }
 
+  // Fixes
+  if (args.feature && args.feature.split(',').includes('fixes') === true) {
+    info('Generating file fixes...')
+    const fixes = await generateFixes(projectRoot)
+    uploadFileChunks.push(Buffer.from(FIXES_HEADER))
+    uploadFileChunks.push(Buffer.from(fixes))
+    uploadFileChunks.push(Buffer.from(MARKER_ENV_END))
+    info('Finished generating file fixes')
+  }
+
   const uploadFile = Buffer.concat(uploadFileChunks)
   const gzippedFile = zlib.gzipSync(uploadFile)
 


Test patch:
diff --git a/test/fixtures/fixes/example.php b/test/fixtures/fixes/example.php
new file mode 100644
index 0000000..004ce62
--- /dev/null
+++ b/test/fixtures/fixes/example.php
@@ -0,0 +1,20 @@
+<?php namespace Example;
+
+class Example
+{
+    public static function go()
+    {
+        $test_array = [
+          1,
+          2,
+          3,
+        ]
+
+        if (false) {
+            return true;
+        }
+
+        return false;
+
+    }
+}
diff --git a/test/helpers/fixes.test.ts b/test/helpers/fixes.test.ts
new file mode 100644
index 0000000..c98d89f
--- /dev/null
+++ b/test/helpers/fixes.test.ts
@@ -0,0 +1,66 @@
+import td from 'testdouble'
+import childProcess from 'child_process'
+
+import * as fixesHelpers from '../../src/helpers/fixes'
+
+describe('Fixes Helpers', () => {
+  afterEach(() => {
+    td.reset()
+  })
+
+  it('provides no fixes if none are applicable', async () => {
+    const files = ['package.json']
+    td.replace(childProcess, 'spawnSync', () => {
+      return {
+        stdout: files.join('\n'),
+        status: 0,
+        error: undefined,
+      }
+    })
+    expect(
+      await fixesHelpers.generateFixes('.')
+    ).toBe('')
+  })
+
+  it('provides proper fixes for c-like files', async () => {
+    const files = ['test/fixtures/gcov/main.c']
+    td.replace(childProcess, 'spawnSync', () => {
+      return {
+        stdout: files.join('\n'),
+        status: 0,
+        error: undefined,
+      }
+    })
+    expect(
+      await fixesHelpers.generateFixes('.')
+    ).toBe('test/fixtures/gcov/main.c:2,4,11,12,13,14,16,20\n')
+  })
+
+  it('provides proper fixes for php-like files', async () => {
+    const files = ['test/fixtures/fixes/example.php']
+    td.replace(childProcess, 'spawnSync', () => {
+      return {
+        stdout: files.join('\n'),
+        status: 0,
+        error: undefined,
+      }
+    })
+    expect(
+      await fixesHelpers.generateFixes('.')
+    ).toBe('test/fixtures/fixes/example.php:4,6,11,15,19,20\n')
+  })
+
+  it('provides multiple fixes for files', async () => {
+    const files = ['test/fixtures/fixes/example.php', 'test/fixtures/gcov/main.c']
+    td.replace(childProcess, 'spawnSync', () => {
+      return {
+        stdout: files.join('\n'),
+        status: 0,
+        error: undefined,
+      }
+    })
+    expect(
+      await fixesHelpers.generateFixes('.')
+    ).toBe('test/fixtures/fixes/example.php:4,6,11,15,19,20\ntest/fixtures/gcov/main.c:2,4,11,12,13,14,16,20\n')
+  })
+})
diff --git a/test/index.test.ts b/test/index.test.ts
index 04979a0..fb965a7 100644
--- a/test/index.test.ts
+++ b/test/index.test.ts
@@ -509,4 +509,20 @@ describe('Uploader Core', () => {
       expect.stringMatching(/<<<<<< network/),
     )
   })
+
+  it('Can create fixes', async () => {
+    await app.main({
+      name: 'customname',
+      token: 'abcdefg',
+      url: 'https://codecov.io',
+      dryRun: 'true',
+      feature: 'fixes',
+      flags: '',
+      slug: '',
+      upstream: ''
+    })
+    expect(console.log).toHaveBeenCalledWith(
+      expect.stringMatching(/# path=fixes\ntest\/fixtures\/fixes\/example.php:4,6,11,15,19,20\ntest\/fixtures\/gcov\/main.c:2,4,11,12,13,14,16,20/)
+    )
+  })
 })