Skip to content

Commit c8a2a63

Browse files
committed
ci(all-green): skip the json coverage merge for already-uploaded runs
Skipping a cached run's codecovcli upload still paid for merging its istanbul JSON report, which only Codecov reads — istanbul-lib-coverage's merge is far slower than the lcov merge on a run with many cells, so it dominated rerun time even with the upload itself skipped. Pass skipJson through to mergeRunCoverage so a cached run only redoes the cheap lcov merge that the Datadog batch upload still needs. Generated by Claude Code.
1 parent f33e063 commit c8a2a63

3 files changed

Lines changed: 36 additions & 8 deletions

File tree

scripts/group-coverage.mjs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,17 +253,22 @@ function mergeCoverageJson (reportPaths) {
253253
* @param {string|number} runId
254254
* @param {string} [inputDir]
255255
* @param {string} [outputDir]
256+
* @param {boolean} [skipJson] Skip merging the istanbul JSON reports — only Codecov reads them
257+
* (see `upload-coverage.mjs`), and `istanbul-lib-coverage`'s merge is far slower than `mergeLcov`
258+
* on a run with many cells, so a run whose Codecov upload already succeeded in a previous job
259+
* attempt can skip this merge entirely instead of paying for it only to discard the result.
256260
* @returns {{ lcovDir: string|null, jsonDir: string|null }} Directories containing the merged
257-
* `lcov.info` and `coverage-final.json`, each null if the run produced no report in that format.
261+
* `lcov.info` and `coverage-final.json`, each null if the run produced no report in that format
262+
* (or, for `jsonDir`, if `skipJson` was set).
258263
*/
259-
function mergeRunCoverage (runId, inputDir = INPUT_DIR, outputDir = OUTPUT_DIR) {
264+
function mergeRunCoverage (runId, inputDir = INPUT_DIR, outputDir = OUTPUT_DIR, skipJson = false) {
260265
const files = collectCoverageFiles(join(inputDir, String(runId)), [], { runId: String(runId) })
261266
if (files.length === 0) return { lcovDir: null, jsonDir: null }
262267

263268
const { reportsByArtifact, artifacts } = planCoverageGroups(files)
264269
const reports = artifacts.flatMap(artifact => reportsByArtifact.get(artifact))
265270
const lcovReportPaths = reports.filter(r => r.format === 'lcov').map(r => r.reportPath)
266-
const jsonReportPaths = reports.filter(r => r.format === 'json').map(r => r.reportPath)
271+
const jsonReportPaths = skipJson ? [] : reports.filter(r => r.format === 'json').map(r => r.reportPath)
267272

268273
let lcovDir = null
269274
if (lcovReportPaths.length > 0) {

scripts/group-coverage.spec.mjs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,21 @@ describe('group-coverage', () => {
218218
)
219219
})
220220

221+
it('skips the json merge when skipJson is set, but still merges lcov', () => {
222+
const input = join(dir, 'coverage-results')
223+
const output = join(dir, 'coverage-upload')
224+
const cellDir = join(input, '42', 'coverage-apm-integrations-axios__a-0', 'node-20-x')
225+
mkdirSync(cellDir, { recursive: true })
226+
writeFileSync(join(cellDir, 'lcov.info'), 'SF:a.js\nDA:1,1\nend_of_record\n')
227+
writeFileSync(join(cellDir, 'coverage-final.json'), JSON.stringify({}))
228+
229+
const { lcovDir, jsonDir } = mergeRunCoverage('42', input, output, true)
230+
231+
assert.equal(lcovDir, join(output, '42', 'lcov'))
232+
assert.equal(jsonDir, null)
233+
assert.equal(existsSync(join(output, '42', 'json')), false)
234+
})
235+
221236
it('ignores other runs\' cells', () => {
222237
const input = join(dir, 'coverage-results')
223238
const otherCellDir = join(input, '7', 'coverage-appsec-express__job-0', 'node-20-x')

scripts/upload-coverage.mjs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -93,18 +93,26 @@ export function hasCodecovCommit () {
9393
* lcov files that came from cells with the same content is safe, but merging Codecov uploads that
9494
* each need a different flag isn't.
9595
*
96-
* The merge always runs, even when `skipUpload` is set, since the lcov half it also produces feeds
97-
* the Datadog batch upload, which has no per-run cache of its own — see `all-green.mjs`.
96+
* The lcov merge always runs, even when `skipUpload` is set, since it also feeds the Datadog batch
97+
* upload, which has no per-run cache of its own — see `all-green.mjs`. The json merge is skipped
98+
* along with the upload, since only Codecov reads it and it's the slow half of the merge on a run
99+
* with many cells.
98100
*
99101
* @param {{ id: number, name: string }} run
100102
* @param {{ sha: string, branch: string, prNumber?: string, eventName: string, baseRef: string }} options
101-
* @param {boolean} [skipUpload] Skip the `codecovcli do-upload` call — set when a previous All
102-
* Green job attempt already uploaded this run's coverage to Codecov successfully.
103+
* @param {boolean} [skipUpload] Skip merging the json report and the `codecovcli do-upload` call —
104+
* set when a previous All Green job attempt already uploaded this run's coverage to Codecov
105+
* successfully.
103106
* @returns {Promise<import('./run-upload.mjs').UploadResult[]>}
104107
*/
105108
export async function uploadCoverage (run, options, skipUpload = false) {
109+
if (skipUpload) {
110+
mergeRunCoverage(run.id, undefined, undefined, true)
111+
return []
112+
}
113+
106114
const { jsonDir } = mergeRunCoverage(run.id)
107-
if (!jsonDir || skipUpload) return []
115+
if (!jsonDir) return []
108116

109117
const commitReady = await ensureCodecovCommit(options)
110118
if (!commitReady) return []

0 commit comments

Comments
 (0)