mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-19 09:48:39 +00:00
CI: remove Vitest JSON report artifacts (#30976)
* CI: remove vitest JSON report upload steps * Tests: stop injecting vitest JSON reporter * Tests: remove vitest slowest report script
This commit is contained in:
38
.github/workflows/ci.yml
vendored
38
.github/workflows/ci.yml
vendored
@@ -208,10 +208,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
install-bun: "${{ matrix.runtime == 'bun' }}"
|
install-bun: "${{ matrix.runtime == 'bun' }}"
|
||||||
|
|
||||||
- name: Configure vitest JSON reports
|
|
||||||
if: (github.event_name != 'push' || matrix.runtime != 'bun') && matrix.task == 'test' && matrix.runtime == 'node'
|
|
||||||
run: echo "OPENCLAW_VITEST_REPORT_DIR=$RUNNER_TEMP/vitest-reports" >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
- name: Configure Node test resources
|
- name: Configure Node test resources
|
||||||
if: (github.event_name != 'push' || matrix.runtime != 'bun') && matrix.task == 'test' && matrix.runtime == 'node'
|
if: (github.event_name != 'push' || matrix.runtime != 'bun') && matrix.task == 'test' && matrix.runtime == 'node'
|
||||||
run: |
|
run: |
|
||||||
@@ -224,21 +220,6 @@ jobs:
|
|||||||
if: matrix.runtime != 'bun' || github.event_name != 'push'
|
if: matrix.runtime != 'bun' || github.event_name != 'push'
|
||||||
run: ${{ matrix.command }}
|
run: ${{ matrix.command }}
|
||||||
|
|
||||||
- name: Summarize slowest tests
|
|
||||||
if: (github.event_name != 'push' || matrix.runtime != 'bun') && matrix.task == 'test' && matrix.runtime == 'node'
|
|
||||||
run: |
|
|
||||||
node scripts/vitest-slowest.mjs --dir "$OPENCLAW_VITEST_REPORT_DIR" --top 50 --out "$RUNNER_TEMP/vitest-slowest.md" > /dev/null
|
|
||||||
echo "Slowest test summary written to $RUNNER_TEMP/vitest-slowest.md"
|
|
||||||
|
|
||||||
- name: Upload vitest reports
|
|
||||||
if: (github.event_name != 'push' || matrix.runtime != 'bun') && matrix.task == 'test' && matrix.runtime == 'node'
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: vitest-reports-${{ runner.os }}-${{ matrix.runtime }}
|
|
||||||
path: |
|
|
||||||
${{ env.OPENCLAW_VITEST_REPORT_DIR }}
|
|
||||||
${{ runner.temp }}/vitest-slowest.md
|
|
||||||
|
|
||||||
# Types, lint, and format check.
|
# Types, lint, and format check.
|
||||||
check:
|
check:
|
||||||
name: "check"
|
name: "check"
|
||||||
@@ -513,28 +494,9 @@ jobs:
|
|||||||
echo "OPENCLAW_TEST_SHARDS=${{ matrix.shard_count }}" >> "$GITHUB_ENV"
|
echo "OPENCLAW_TEST_SHARDS=${{ matrix.shard_count }}" >> "$GITHUB_ENV"
|
||||||
echo "OPENCLAW_TEST_SHARD_INDEX=${{ matrix.shard_index }}" >> "$GITHUB_ENV"
|
echo "OPENCLAW_TEST_SHARD_INDEX=${{ matrix.shard_index }}" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
- name: Configure vitest JSON reports
|
|
||||||
if: matrix.task == 'test'
|
|
||||||
run: echo "OPENCLAW_VITEST_REPORT_DIR=$RUNNER_TEMP/vitest-reports" >> "$GITHUB_ENV"
|
|
||||||
|
|
||||||
- name: Run ${{ matrix.task }} (${{ matrix.runtime }})
|
- name: Run ${{ matrix.task }} (${{ matrix.runtime }})
|
||||||
run: ${{ matrix.command }}
|
run: ${{ matrix.command }}
|
||||||
|
|
||||||
- name: Summarize slowest tests
|
|
||||||
if: matrix.task == 'test'
|
|
||||||
run: |
|
|
||||||
node scripts/vitest-slowest.mjs --dir "$OPENCLAW_VITEST_REPORT_DIR" --top 50 --out "$RUNNER_TEMP/vitest-slowest.md" > /dev/null
|
|
||||||
echo "Slowest test summary written to $RUNNER_TEMP/vitest-slowest.md"
|
|
||||||
|
|
||||||
- name: Upload vitest reports
|
|
||||||
if: matrix.task == 'test'
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
with:
|
|
||||||
name: vitest-reports-${{ runner.os }}-${{ matrix.runtime }}-shard${{ matrix.shard_index }}of${{ matrix.shard_count }}
|
|
||||||
path: |
|
|
||||||
${{ env.OPENCLAW_VITEST_REPORT_DIR }}
|
|
||||||
${{ runner.temp }}/vitest-slowest.md
|
|
||||||
|
|
||||||
# Consolidated macOS job: runs TS tests + Swift lint/build/test sequentially
|
# Consolidated macOS job: runs TS tests + Swift lint/build/test sequentially
|
||||||
# on a single runner. GitHub limits macOS concurrent jobs to 5 per org;
|
# on a single runner. GitHub limits macOS concurrent jobs to 5 per org;
|
||||||
# running 4 separate jobs per PR (as before) starved the queue. One job
|
# running 4 separate jobs per PR (as before) starved the queue. One job
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import { spawn } from "node:child_process";
|
import { spawn } from "node:child_process";
|
||||||
import fs from "node:fs";
|
import fs from "node:fs";
|
||||||
import os from "node:os";
|
import os from "node:os";
|
||||||
import path from "node:path";
|
|
||||||
|
|
||||||
// On Windows, `.cmd` launchers can fail with `spawn EINVAL` when invoked without a shell
|
// On Windows, `.cmd` launchers can fail with `spawn EINVAL` when invoked without a shell
|
||||||
// (especially under GitHub Actions + Git Bash). Use `shell: true` and let the shell resolve pnpm.
|
// (especially under GitHub Actions + Git Bash). Use `shell: true` and let the shell resolve pnpm.
|
||||||
@@ -313,49 +312,9 @@ const maxOldSpaceSizeMb = (() => {
|
|||||||
return null;
|
return null;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
function resolveReportDir() {
|
|
||||||
const raw = process.env.OPENCLAW_VITEST_REPORT_DIR?.trim();
|
|
||||||
if (!raw) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
fs.mkdirSync(raw, { recursive: true });
|
|
||||||
} catch {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return raw;
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildReporterArgs(entry, extraArgs) {
|
|
||||||
const reportDir = resolveReportDir();
|
|
||||||
if (!reportDir) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Vitest supports both `--shard 1/2` and `--shard=1/2`. We use it in the
|
|
||||||
// split-arg form, so we need to read the next arg to avoid overwriting reports.
|
|
||||||
const shardIndex = extraArgs.findIndex((arg) => arg === "--shard");
|
|
||||||
const inlineShardArg = extraArgs.find(
|
|
||||||
(arg) => typeof arg === "string" && arg.startsWith("--shard="),
|
|
||||||
);
|
|
||||||
const shardValue =
|
|
||||||
shardIndex >= 0 && typeof extraArgs[shardIndex + 1] === "string"
|
|
||||||
? extraArgs[shardIndex + 1]
|
|
||||||
: typeof inlineShardArg === "string"
|
|
||||||
? inlineShardArg.slice("--shard=".length)
|
|
||||||
: "";
|
|
||||||
const shardSuffix = shardValue
|
|
||||||
? `-shard${String(shardValue).replaceAll("/", "of").replaceAll(" ", "")}`
|
|
||||||
: "";
|
|
||||||
|
|
||||||
const outputFile = path.join(reportDir, `vitest-${entry.name}${shardSuffix}.json`);
|
|
||||||
return ["--reporter=default", "--reporter=json", "--outputFile", outputFile];
|
|
||||||
}
|
|
||||||
|
|
||||||
const runOnce = (entry, extraArgs = []) =>
|
const runOnce = (entry, extraArgs = []) =>
|
||||||
new Promise((resolve) => {
|
new Promise((resolve) => {
|
||||||
const maxWorkers = maxWorkersForRun(entry.name);
|
const maxWorkers = maxWorkersForRun(entry.name);
|
||||||
const reporterArgs = buildReporterArgs(entry, extraArgs);
|
|
||||||
// vmForks with a single worker has shown cross-file leakage in extension suites.
|
// vmForks with a single worker has shown cross-file leakage in extension suites.
|
||||||
// Fall back to process forks when we intentionally clamp that lane to one worker.
|
// Fall back to process forks when we intentionally clamp that lane to one worker.
|
||||||
const entryArgs =
|
const entryArgs =
|
||||||
@@ -368,11 +327,10 @@ const runOnce = (entry, extraArgs = []) =>
|
|||||||
"--maxWorkers",
|
"--maxWorkers",
|
||||||
String(maxWorkers),
|
String(maxWorkers),
|
||||||
...silentArgs,
|
...silentArgs,
|
||||||
...reporterArgs,
|
|
||||||
...windowsCiArgs,
|
...windowsCiArgs,
|
||||||
...extraArgs,
|
...extraArgs,
|
||||||
]
|
]
|
||||||
: [...entryArgs, ...silentArgs, ...reporterArgs, ...windowsCiArgs, ...extraArgs];
|
: [...entryArgs, ...silentArgs, ...windowsCiArgs, ...extraArgs];
|
||||||
const nodeOptions = process.env.NODE_OPTIONS ?? "";
|
const nodeOptions = process.env.NODE_OPTIONS ?? "";
|
||||||
const nextNodeOptions = WARNING_SUPPRESSION_FLAGS.reduce(
|
const nextNodeOptions = WARNING_SUPPRESSION_FLAGS.reduce(
|
||||||
(acc, flag) => (acc.includes(flag) ? acc : `${acc} ${flag}`.trim()),
|
(acc, flag) => (acc.includes(flag) ? acc : `${acc} ${flag}`.trim()),
|
||||||
|
|||||||
@@ -1,160 +0,0 @@
|
|||||||
import fs from "node:fs";
|
|
||||||
import path from "node:path";
|
|
||||||
|
|
||||||
function parseArgs(argv) {
|
|
||||||
const out = {
|
|
||||||
dir: "",
|
|
||||||
top: 50,
|
|
||||||
outFile: "",
|
|
||||||
};
|
|
||||||
for (let i = 2; i < argv.length; i += 1) {
|
|
||||||
const arg = argv[i];
|
|
||||||
if (arg === "--dir") {
|
|
||||||
out.dir = argv[i + 1] ?? "";
|
|
||||||
i += 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (arg === "--top") {
|
|
||||||
out.top = Number.parseInt(argv[i + 1] ?? "", 10);
|
|
||||||
if (!Number.isFinite(out.top) || out.top <= 0) {
|
|
||||||
out.top = 50;
|
|
||||||
}
|
|
||||||
i += 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (arg === "--out") {
|
|
||||||
out.outFile = argv[i + 1] ?? "";
|
|
||||||
i += 1;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
function readJson(filePath) {
|
|
||||||
const raw = fs.readFileSync(filePath, "utf8");
|
|
||||||
return JSON.parse(raw);
|
|
||||||
}
|
|
||||||
|
|
||||||
function toMs(value) {
|
|
||||||
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
function safeRel(baseDir, filePath) {
|
|
||||||
try {
|
|
||||||
const rel = path.relative(baseDir, filePath);
|
|
||||||
return rel.startsWith("..") ? filePath : rel;
|
|
||||||
} catch {
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function main() {
|
|
||||||
const args = parseArgs(process.argv);
|
|
||||||
const dir = args.dir?.trim();
|
|
||||||
if (!dir) {
|
|
||||||
console.error(
|
|
||||||
"usage: node scripts/vitest-slowest.mjs --dir <reportDir> [--top 50] [--out out.md]",
|
|
||||||
);
|
|
||||||
process.exit(2);
|
|
||||||
}
|
|
||||||
if (!fs.existsSync(dir)) {
|
|
||||||
console.error(`vitest report dir not found: ${dir}`);
|
|
||||||
process.exit(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
const entries = fs
|
|
||||||
.readdirSync(dir)
|
|
||||||
.filter((name) => name.endsWith(".json"))
|
|
||||||
.map((name) => path.join(dir, name));
|
|
||||||
if (entries.length === 0) {
|
|
||||||
console.error(`no vitest json reports in ${dir}`);
|
|
||||||
process.exit(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
const fileRows = [];
|
|
||||||
const testRows = [];
|
|
||||||
|
|
||||||
for (const filePath of entries) {
|
|
||||||
let payload;
|
|
||||||
try {
|
|
||||||
payload = readJson(filePath);
|
|
||||||
} catch (err) {
|
|
||||||
fileRows.push({
|
|
||||||
kind: "report",
|
|
||||||
name: safeRel(dir, filePath),
|
|
||||||
ms: 0,
|
|
||||||
note: `failed to parse: ${String(err)}`,
|
|
||||||
});
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const suiteResults = Array.isArray(payload.testResults) ? payload.testResults : [];
|
|
||||||
for (const suite of suiteResults) {
|
|
||||||
const suiteName = typeof suite?.name === "string" ? suite.name : "(unknown)";
|
|
||||||
const startTime = toMs(suite?.startTime);
|
|
||||||
const endTime = toMs(suite?.endTime);
|
|
||||||
const suiteMs = Math.max(0, endTime - startTime);
|
|
||||||
fileRows.push({
|
|
||||||
kind: "file",
|
|
||||||
name: safeRel(process.cwd(), suiteName),
|
|
||||||
ms: suiteMs,
|
|
||||||
note: safeRel(dir, filePath),
|
|
||||||
});
|
|
||||||
|
|
||||||
const assertions = Array.isArray(suite?.assertionResults) ? suite.assertionResults : [];
|
|
||||||
for (const assertion of assertions) {
|
|
||||||
const title = typeof assertion?.title === "string" ? assertion.title : "(unknown)";
|
|
||||||
const duration = toMs(assertion?.duration);
|
|
||||||
testRows.push({
|
|
||||||
name: `${safeRel(process.cwd(), suiteName)} :: ${title}`,
|
|
||||||
ms: duration,
|
|
||||||
suite: safeRel(process.cwd(), suiteName),
|
|
||||||
title,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fileRows.sort((a, b) => b.ms - a.ms);
|
|
||||||
testRows.sort((a, b) => b.ms - a.ms);
|
|
||||||
|
|
||||||
const topFiles = fileRows.slice(0, args.top);
|
|
||||||
const topTests = testRows.slice(0, args.top);
|
|
||||||
|
|
||||||
const lines = [];
|
|
||||||
lines.push(`# Vitest Slowest (${new Date().toISOString()})`);
|
|
||||||
lines.push("");
|
|
||||||
lines.push(`Reports: ${entries.length}`);
|
|
||||||
lines.push("");
|
|
||||||
lines.push("## Slowest Files");
|
|
||||||
lines.push("");
|
|
||||||
lines.push("| ms | file | report |");
|
|
||||||
lines.push("|---:|:-----|:-------|");
|
|
||||||
for (const row of topFiles) {
|
|
||||||
lines.push(`| ${Math.round(row.ms)} | \`${row.name}\` | \`${row.note}\` |`);
|
|
||||||
}
|
|
||||||
lines.push("");
|
|
||||||
lines.push("## Slowest Tests");
|
|
||||||
lines.push("");
|
|
||||||
lines.push("| ms | test |");
|
|
||||||
lines.push("|---:|:-----|");
|
|
||||||
for (const row of topTests) {
|
|
||||||
lines.push(`| ${Math.round(row.ms)} | \`${row.name}\` |`);
|
|
||||||
}
|
|
||||||
lines.push("");
|
|
||||||
lines.push(
|
|
||||||
`Notes: file times are (endTime-startTime) per suite; test times come from assertion duration (may exclude setup/import).`,
|
|
||||||
);
|
|
||||||
lines.push("");
|
|
||||||
|
|
||||||
const outText = lines.join("\n");
|
|
||||||
if (args.outFile?.trim()) {
|
|
||||||
fs.writeFileSync(args.outFile, outText, "utf8");
|
|
||||||
}
|
|
||||||
process.stdout.write(outText);
|
|
||||||
}
|
|
||||||
|
|
||||||
main();
|
|
||||||
Reference in New Issue
Block a user