mirror of
https://github.com/murashit/codex-panel.git
synced 2026-07-22 06:57:10 +00:00
Replace custom parallel runner with concurrently
This commit is contained in:
parent
d87d56b955
commit
c367afc473
5 changed files with 278 additions and 138 deletions
254
package-lock.json
generated
254
package-lock.json
generated
|
|
@ -18,6 +18,7 @@
|
|||
"devDependencies": {
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@types/node": "^25.6.0",
|
||||
"concurrently": "^10.0.3",
|
||||
"esbuild": "^0.28.0",
|
||||
"eslint": "^10.4.1",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
|
|
@ -3572,6 +3573,46 @@
|
|||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz",
|
||||
"integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"string-width": "^7.2.0",
|
||||
"strip-ansi": "^7.1.0",
|
||||
"wrap-ansi": "^9.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui/node_modules/emoji-regex": {
|
||||
"version": "10.6.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
|
||||
"integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cliui/node_modules/string-width": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
|
||||
"integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^10.3.0",
|
||||
"get-east-asian-width": "^1.0.0",
|
||||
"strip-ansi": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
|
|
@ -3606,6 +3647,57 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/concurrently": {
|
||||
"version": "10.0.3",
|
||||
"resolved": "https://registry.npmjs.org/concurrently/-/concurrently-10.0.3.tgz",
|
||||
"integrity": "sha512-hc3LH4UaKWd/bbyDK/IGVa4RB6PtQ3CUYwtrkzqHn+wIG3Hr5fhpRlk0L/gCa8ZE1L/Ufj50Zho69cI5w8SQBA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chalk": "5.6.2",
|
||||
"rxjs": "7.8.2",
|
||||
"shell-quote": "1.8.4",
|
||||
"supports-color": "10.2.2",
|
||||
"tree-kill": "1.2.2",
|
||||
"yargs": "18.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"conc": "dist/bin/index.js",
|
||||
"concurrently": "dist/bin/index.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/concurrently/node_modules/chalk": {
|
||||
"version": "5.6.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz",
|
||||
"integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^12.17.0 || ^14.13 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/chalk?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/concurrently/node_modules/supports-color": {
|
||||
"version": "10.2.2",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz",
|
||||
"integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/convert-source-map": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
|
||||
|
|
@ -5482,6 +5574,16 @@
|
|||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "6.* || 8.* || >= 10.*"
|
||||
}
|
||||
},
|
||||
"node_modules/get-east-asian-width": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz",
|
||||
|
|
@ -8411,6 +8513,16 @@
|
|||
"queue-microtask": "^1.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/rxjs": {
|
||||
"version": "7.8.2",
|
||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
|
||||
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/safe-array-concat": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz",
|
||||
|
|
@ -8595,6 +8707,19 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/shell-quote": {
|
||||
"version": "1.8.4",
|
||||
"resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.4.tgz",
|
||||
"integrity": "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
|
||||
|
|
@ -9377,6 +9502,16 @@
|
|||
"node": ">=20"
|
||||
}
|
||||
},
|
||||
"node_modules/tree-kill": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz",
|
||||
"integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"tree-kill": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/ts-api-utils": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz",
|
||||
|
|
@ -10025,6 +10160,62 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "9.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz",
|
||||
"integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^6.2.1",
|
||||
"string-width": "^7.0.0",
|
||||
"strip-ansi": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi/node_modules/ansi-styles": {
|
||||
"version": "6.2.3",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
|
||||
"integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/wrap-ansi/node_modules/emoji-regex": {
|
||||
"version": "10.6.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
|
||||
"integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/wrap-ansi/node_modules/string-width": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
|
||||
"integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^10.3.0",
|
||||
"get-east-asian-width": "^1.0.0",
|
||||
"strip-ansi": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/write-file-atomic": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-7.0.1.tgz",
|
||||
|
|
@ -10055,6 +10246,16 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||
|
|
@ -10095,6 +10296,59 @@
|
|||
"url": "https://github.com/sponsors/ota-meshi"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "18.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz",
|
||||
"integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cliui": "^9.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"string-width": "^7.2.0",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^22.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^20.19.0 || ^22.12.0 || >=23"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs-parser": {
|
||||
"version": "22.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz",
|
||||
"integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "^20.19.0 || ^22.12.0 || >=23"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs/node_modules/emoji-regex": {
|
||||
"version": "10.6.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
|
||||
"integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/yargs/node_modules/string-width": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
|
||||
"integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^10.3.0",
|
||||
"get-east-asian-width": "^1.0.0",
|
||||
"strip-ansi": "^7.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/yocto-queue": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz",
|
||||
|
|
|
|||
|
|
@ -19,14 +19,14 @@
|
|||
"build": "node esbuild.config.mjs",
|
||||
"build:styles": "node scripts/build-styles.mjs",
|
||||
"build:styles:check": "node scripts/build-styles.mjs --check",
|
||||
"check": "node scripts/check.mjs",
|
||||
"check:ci": "node scripts/check.mjs --ci",
|
||||
"check": "concurrently --group --pad-prefix --names typecheck,test,lint:ts,lint:css,lint:css-usage,lint:deps,lint:unused,format:check,build:styles:check,build \"npm run --silent typecheck\" \"npm run --silent test\" \"npm run --silent lint:ts\" \"npm run --silent lint:css\" \"npm run --silent lint:css-usage\" \"npm run --silent lint:deps\" \"npm run --silent lint:unused\" \"npm run --silent format:check\" \"npm run --silent build:styles:check\" \"npm run --silent build\"",
|
||||
"check:ci": "npm run typecheck:ci && npm run test:ci && npm run lint:ci && npm run format:check:ci && npm run build:styles:check && npm run build",
|
||||
"format": "node scripts/format.mjs",
|
||||
"format:check": "node scripts/format.mjs --check --cache",
|
||||
"format:check:ci": "node scripts/format.mjs --check",
|
||||
"generate:app-server-types": "node scripts/generate-app-server-types.mjs",
|
||||
"lint": "node scripts/run-parallel.mjs lint:ts lint:css lint:css-usage lint:deps lint:unused",
|
||||
"lint:ci": "node scripts/run-parallel.mjs lint:ts:ci lint:css lint:css-usage lint:deps lint:unused",
|
||||
"lint": "concurrently --group --pad-prefix --names lint:ts,lint:css,lint:css-usage,lint:deps,lint:unused \"npm run --silent lint:ts\" \"npm run --silent lint:css\" \"npm run --silent lint:css-usage\" \"npm run --silent lint:deps\" \"npm run --silent lint:unused\"",
|
||||
"lint:ci": "npm run lint:ts:ci && npm run lint:css && npm run lint:css-usage && npm run lint:deps && npm run lint:unused",
|
||||
"lint:css": "stylelint \"src/**/*.css\" --max-warnings=0",
|
||||
"lint:css-usage": "node scripts/lint/check-css-usage.mjs --fail-on-candidates",
|
||||
"lint:deps": "node scripts/lint/check-import-cycles.mjs",
|
||||
|
|
@ -44,6 +44,7 @@
|
|||
"devDependencies": {
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@types/node": "^25.6.0",
|
||||
"concurrently": "^10.0.3",
|
||||
"esbuild": "^0.28.0",
|
||||
"eslint": "^10.4.1",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
import { spawnSync } from "node:child_process";
|
||||
|
||||
const args = new Set(process.argv.slice(2));
|
||||
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
|
||||
const checks = [
|
||||
{ local: "typecheck", ci: "typecheck:ci", localPhase: "parallel" },
|
||||
{ local: "test", ci: "test:ci", localPhase: "parallel" },
|
||||
{ local: "lint", ci: "lint:ci", localPhase: "parallel" },
|
||||
{ local: "format:check", ci: "format:check:ci", localPhase: "parallel" },
|
||||
{ local: "build:styles:check", ci: "build:styles:check", localPhase: "parallel" },
|
||||
{ local: "build", ci: "build", localPhase: "sequential" },
|
||||
];
|
||||
|
||||
for (const arg of args) {
|
||||
if (arg !== "--ci") {
|
||||
console.error("Usage: node scripts/check.mjs [--ci]");
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (args.has("--ci")) {
|
||||
for (const check of checks) {
|
||||
if (check.ci === null) continue;
|
||||
run(npmCommand, ["run", check.ci]);
|
||||
}
|
||||
} else {
|
||||
const parallelScripts = checks.filter((check) => check.localPhase === "parallel").map((check) => check.local);
|
||||
run("node", ["scripts/run-parallel.mjs", ...parallelScripts]);
|
||||
for (const check of checks.filter((check) => check.localPhase === "sequential")) run(npmCommand, ["run", check.local]);
|
||||
}
|
||||
|
||||
function run(command, args) {
|
||||
const result = spawnSync(command, args, {
|
||||
stdio: "inherit",
|
||||
shell: false,
|
||||
});
|
||||
if (result.error) {
|
||||
console.error(`Failed to run ${command} ${args.join(" ")}: ${result.error.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
if (result.status !== 0) process.exit(result.status ?? 1);
|
||||
}
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
import { Buffer } from "node:buffer";
|
||||
import { spawn } from "node:child_process";
|
||||
|
||||
const scripts = process.argv.slice(2);
|
||||
|
||||
if (scripts.length === 0) {
|
||||
console.error("Usage: node scripts/run-parallel.mjs <npm-script> [<npm-script> ...]");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
|
||||
const longestNameLength = Math.max(...scripts.map((script) => script.length));
|
||||
const running = new Set();
|
||||
|
||||
function prefixedOutput(script, text) {
|
||||
const prefix = `[${script.padEnd(longestNameLength)}] `;
|
||||
return text
|
||||
.trimEnd()
|
||||
.split(/\r?\n/)
|
||||
.map((line) => `${prefix}${line}`)
|
||||
.join("\n");
|
||||
}
|
||||
|
||||
function flushOutput(script, output) {
|
||||
const text = Buffer.concat(output).toString();
|
||||
if (!text.trim()) return;
|
||||
process.stdout.write(`${prefixedOutput(script, text)}\n`);
|
||||
}
|
||||
|
||||
function runScript(script) {
|
||||
const startedAt = process.hrtime.bigint();
|
||||
console.log(`[${script.padEnd(longestNameLength)}] started`);
|
||||
|
||||
const child = spawn(npmCommand, ["run", "--silent", script], {
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
});
|
||||
|
||||
running.add(child);
|
||||
const output = [];
|
||||
child.stdout.on("data", (chunk) => output.push(chunk));
|
||||
child.stderr.on("data", (chunk) => output.push(chunk));
|
||||
|
||||
return new Promise((resolve) => {
|
||||
child.on("error", (error) => {
|
||||
running.delete(child);
|
||||
console.error(`[${script.padEnd(longestNameLength)}] failed to start: ${error.message}`);
|
||||
resolve({ script, status: 1, output: "" });
|
||||
});
|
||||
|
||||
child.on("close", (code, signal) => {
|
||||
running.delete(child);
|
||||
flushOutput(script, output);
|
||||
const elapsedMs = Number(process.hrtime.bigint() - startedAt) / 1_000_000;
|
||||
const elapsedSeconds = (elapsedMs / 1000).toFixed(1);
|
||||
|
||||
if (code === 0) {
|
||||
console.log(`[${script.padEnd(longestNameLength)}] passed in ${elapsedSeconds}s`);
|
||||
resolve({ script, status: 0 });
|
||||
} else {
|
||||
const detail = signal ? `signal ${signal}` : `exit ${code ?? 1}`;
|
||||
console.error(`[${script.padEnd(longestNameLength)}] failed with ${detail} after ${elapsedSeconds}s`);
|
||||
resolve({ script, status: code ?? 1 });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function stopRunning(signal) {
|
||||
for (const child of running) {
|
||||
child.kill(signal);
|
||||
}
|
||||
}
|
||||
|
||||
process.on("SIGINT", () => {
|
||||
stopRunning("SIGINT");
|
||||
});
|
||||
|
||||
process.on("SIGTERM", () => {
|
||||
stopRunning("SIGTERM");
|
||||
});
|
||||
|
||||
const results = await Promise.all(scripts.map(runScript));
|
||||
const failed = results.filter((result) => result.status !== 0);
|
||||
|
||||
if (failed.length > 0) {
|
||||
console.error(`Failed checks: ${failed.map((result) => result.script).join(", ")}`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log(`All checks passed: ${scripts.join(", ")}`);
|
||||
|
|
@ -7,20 +7,23 @@ import { describe, expect, it } from "vitest";
|
|||
const repoRoot = process.cwd();
|
||||
|
||||
describe("development scripts", () => {
|
||||
it("propagates CI check failures", async () => {
|
||||
it("propagates check:ci script failures", async () => {
|
||||
const cwd = await tempWorkspace();
|
||||
const scripts = await readPackageScripts();
|
||||
await writeFile(path.join(cwd, "fail.mjs"), "process.exit(7);\n");
|
||||
await writeJson(path.join(cwd, "package.json"), {
|
||||
scripts: {
|
||||
"check:ci": scripts["check:ci"],
|
||||
"typecheck:ci": "node fail.mjs",
|
||||
"test:ci": 'node -e "process.exit(0)"',
|
||||
"lint:ci": 'node -e "process.exit(0)"',
|
||||
"format:check:ci": 'node -e "process.exit(0)"',
|
||||
"build:styles:check": 'node -e "process.exit(0)"',
|
||||
build: 'node -e "process.exit(0)"',
|
||||
},
|
||||
});
|
||||
|
||||
const result = runNodeScript("scripts/check.mjs", ["--ci"], cwd);
|
||||
const result = runNpmScript("check:ci", cwd);
|
||||
|
||||
expect(result.status).toBe(7);
|
||||
});
|
||||
|
|
@ -253,6 +256,20 @@ function runNodeScript(script: string, args: string[] = [], cwd = repoRoot, env:
|
|||
});
|
||||
}
|
||||
|
||||
function runNpmScript(script: string, cwd = repoRoot) {
|
||||
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
|
||||
return spawnSync(npmCommand, ["run", script], {
|
||||
cwd,
|
||||
encoding: "utf8",
|
||||
shell: false,
|
||||
});
|
||||
}
|
||||
|
||||
async function readPackageScripts(): Promise<Record<string, string>> {
|
||||
const packageJson = JSON.parse(await readFile(path.join(repoRoot, "package.json"), "utf8")) as { scripts: Record<string, string> };
|
||||
return packageJson.scripts;
|
||||
}
|
||||
|
||||
async function writeJson(file: string, value: unknown): Promise<void> {
|
||||
await writeFile(file, `${JSON.stringify(value, null, 2)}\n`);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue