Skip to content

Commit

Permalink
feat: output JSON with timings
Browse files Browse the repository at this point in the history
  • Loading branch information
bahmutov committed Oct 13, 2023
1 parent 7532fe8 commit 3d4d946
Show file tree
Hide file tree
Showing 4 changed files with 87 additions and 41 deletions.
12 changes: 12 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,17 @@ jobs:
with:
command: npm run timings

test-timings-no-file:
runs-on: ubuntu-22.04
steps:
- name: Checkout 🛎
uses: actions/checkout@v4
- name: Split specs based on non-existen timings json file 🧪
# https://github.com/cypress-io/github-action
uses: cypress-io/github-action@v5
with:
command: npm run timings-no-file

test-workflow-e2e:
# https://github.com/bahmutov/cypress-workflows
uses: bahmutov/cypress-workflows/.github/workflows/split.yml@v1
Expand Down Expand Up @@ -185,6 +196,7 @@ jobs:
test-subfolder,
test-index1,
test-timings,
test-timings-no-file,
]
runs-on: ubuntu-22.04
steps:
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ $ SPLIT_FILE=timings.json SPLIT=3 npx cypress run
$ npx cypress run --env split=3,splitFile=timings.json
```

For specs not in the timings file, it will use average duration of the known specs.
For specs not in the timings file, it will use average duration of the known specs. The timings file might not exist, in this case the specs are split by name. At the end of the run, the duration of all run specs is printed and can be saved into the timings JSON file. **Note:** you would need to combine the timings from different runners into a single JSON file yourself.

## CI summary

Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"test-names:component": "find-cypress-specs --component --names",
"deps": "npm audit --report --omit dev",
"subfolder": "DEBUG=cypress-split,find-cypress-specs SPLIT=2 SPLIT_INDEX=0 cypress run --config-file examples/my-app/tests/cypress.config.js",
"timings": "DEBUG=cypress-split SPLIT=2 SPLIT_INDEX=0 SPLIT_FILE=timings.json cypress run"
"timings": "DEBUG=cypress-split SPLIT=2 SPLIT_INDEX=0 SPLIT_FILE=timings.json cypress run",
"timings-no-file": "DEBUG=cypress-split SPLIT=1 SPLIT_INDEX=0 SPLIT_FILE=does-not-exist.json cypress run"
},
"repository": {
"type": "git",
Expand Down
111 changes: 72 additions & 39 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,39 +156,46 @@ function cypressSplit(on, config) {

if (SPLIT_FILE) {
debug('loading split file %s', SPLIT_FILE)
const splitFile = JSON.parse(fs.readFileSync(SPLIT_FILE, 'utf8'))
const previousDurations = splitFile.durations
const averageDuration =
previousDurations
.map((item) => item.duration)
.reduce((sum, duration) => (sum += duration), 0) /
previousDurations.length
const specsWithDurations = specs.map((specName) => {
const relativeSpec = path.relative(cwd, specName)
const foundInfo = previousDurations.find(
(item) => item.spec === relativeSpec,
)
if (!foundInfo) {
return {
specName,
duration: averageDuration,
}
} else {
return {
specName,
duration: foundInfo.duration,
try {
const splitFile = JSON.parse(fs.readFileSync(SPLIT_FILE, 'utf8'))
const previousDurations = splitFile.durations
const averageDuration =
previousDurations
.map((item) => item.duration)
.reduce((sum, duration) => (sum += duration), 0) /
previousDurations.length
const specsWithDurations = specs.map((specName) => {
const relativeSpec = path.relative(cwd, specName)
const foundInfo = previousDurations.find(
(item) => item.spec === relativeSpec,
)
if (!foundInfo) {
return {
specName,
duration: averageDuration,
}
} else {
return {
specName,
duration: foundInfo.duration,
}
}
}
})
debug('splitting by duration %d ways', splitN)
debug(specsWithDurations)
const { chunks, sums } = splitByDuration(splitN, specsWithDurations)
debug('split by duration')
debug(chunks)
debug('sums of durations for chunks')
debug(sums)

splitSpecs = chunks[splitIndex].map((item) => item.specName)
})
debug('splitting by duration %d ways', splitN)
debug(specsWithDurations)
const { chunks, sums } = splitByDuration(splitN, specsWithDurations)
debug('split by duration')
debug(chunks)
debug('sums of durations for chunks')
debug(sums)

splitSpecs = chunks[splitIndex].map((item) => item.specName)
} catch (err) {
console.error('%s Could not split specs by duration', label)
console.error(err.message)
console.error('%s splitting as is by name', label)
splitSpecs = getChunk(specs, splitN, splitIndex)
}
} else {
splitSpecs = getChunk(specs, splitN, splitIndex)
}
Expand Down Expand Up @@ -237,15 +244,41 @@ function cypressSplit(on, config) {
return specRows
}

const shouldWriteSummary = getEnvironmentFlag('SPLIT_SUMMARY', true)
debug('shouldWriteSummary', shouldWriteSummary)
on('after:run', () => {
if (SPLIT_FILE) {
console.log('%s here are spec timings', label)

if (shouldWriteSummary) {
if (process.env.GITHUB_ACTIONS) {
const specDurations = splitSpecs
.map((absoluteSpecPath, k) => {
const relativeName = specAbsoluteToRelative[absoluteSpecPath]
const specResult = specResults[absoluteSpecPath]
if (specResult) {
return {
spec: relativeName,
duration:
specResult.stats.duration ||
specResult.stats.wallClockDuration,
}
} else {
return
}
})
.filter(Boolean)

const timings = {
durations: specDurations,
}
console.log(JSON.stringify(timings, null, 2))
}

const shouldWriteSummary = getEnvironmentFlag('SPLIT_SUMMARY', true)
debug('shouldWriteSummary', shouldWriteSummary)

if (shouldWriteSummary) {
// only output the GitHub summary table AFTER the run
// because GH does not show the summary before the job finishes
// so we might as well wait for all spec results to come in
on('after:run', () => {
if (process.env.GITHUB_ACTIONS) {
const specRows = addSpecResults()

// https://github.blog/2022-05-09-supercharging-github-actions-with-job-summaries/
Expand All @@ -272,9 +305,9 @@ function cypressSplit(on, config) {
'https://github.com/bahmutov/cypress-split',
)
.write()
})
}
}
}
})

if (splitSpecs.length) {
debug('setting the spec pattern to')
Expand Down

0 comments on commit 3d4d946

Please sign in to comment.