mirror of
https://github.com/pnpm/pnpm.git
synced 2026-06-28 09:55:39 -04:00
## 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.
68 lines
2.1 KiB
JavaScript
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)
|
|
}
|