Files
pnpm/.github/scripts/bench-output-path.mjs
Zoltan Kochan 9ddc86b635 ci: track test suite durations in bencher (#12404)
## Summary

Adds CI duration tracking for the `pnpm-ci-performance` Bencher project.

Tracked Rust testbeds and benchmarks:

- `pacquet.ubuntu`, `pacquet.windows`, `pacquet.macos` -> `tests.all`
- `pnpr.ubuntu`, `pnpr.windows`, `pnpr.macos` -> `tests.all`

Tracked pnpm testbeds and benchmarks for full test runs:

- `pnpm.ubuntu.node22`, `pnpm.ubuntu.node24`, `pnpm.ubuntu.node26` -> `tests.all`, `tests.cli`
- `pnpm.windows.node22`, `pnpm.windows.node24`, `pnpm.windows.node26` -> `tests.all`, `tests.cli`

The test workflows produce Bencher-compatible JSON artifacts without receiving `BENCHER_API_TOKEN`. A separate `workflow_run` workflow downloads those artifacts only for same-repository runs, validates their metadata, and uploads from trusted workflow code using the existing `BENCHER_API_TOKEN` secret. The pnpm CLI e2e duration is extracted from `pnpm run --report-summary` output during the same full-test execution, so the CLI e2e suite is not run a second time.
2026-06-14 18:44:17 +02:00

68 lines
2.1 KiB
JavaScript

import { existsSync, lstatSync, mkdirSync, realpathSync } from 'node:fs'
import { dirname, isAbsolute, relative, resolve, sep } from 'node:path'
export function resolveBenchOutputPath (output) {
const benchDir = resolve('.bench')
const outputPath = resolve(output)
const relativePath = relative(benchDir, outputPath)
if (relativePath === '' || isOutside(relativePath)) {
throw new Error(`Output path must be under .bench/: ${output}`)
}
ensureBenchDir(benchDir, output)
assertNotSymlink(outputPath, output)
assertNoSymlinkAncestors(benchDir, dirname(outputPath), output)
const canonicalBenchDir = realpathSync(benchDir)
const canonicalParent = realpathSync(nearestExistingAncestor(dirname(outputPath)))
if (!isSameOrChild(canonicalBenchDir, canonicalParent)) {
throw new Error(`Output path must be under .bench/: ${output}`)
}
return outputPath
}
function ensureBenchDir (benchDir, output) {
if (!existsSync(benchDir)) {
mkdirSync(benchDir)
return
}
const stats = lstatSync(benchDir)
if (stats.isSymbolicLink() || !stats.isDirectory()) {
throw new Error(`Output path must be under .bench/: ${output}`)
}
}
function assertNoSymlinkAncestors (benchDir, outputParent, output) {
const relativeParent = relative(benchDir, outputParent)
if (relativeParent === '') return
let current = benchDir
for (const segment of relativeParent.split(sep)) {
current = resolve(current, segment)
assertNotSymlink(current, output)
}
}
function assertNotSymlink (path, output) {
if (existsSync(path) && lstatSync(path).isSymbolicLink()) {
throw new Error(`Output path must be under .bench/: ${output}`)
}
}
function nearestExistingAncestor (path) {
let current = path
while (!existsSync(current)) {
const parent = dirname(current)
if (parent === current) return current
current = parent
}
return current
}
function isSameOrChild (base, target) {
return !isOutside(relative(base, target))
}
function isOutside (relativePath) {
return relativePath === '..' || relativePath.startsWith(`..${sep}`) || isAbsolute(relativePath)
}