mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-11-03 18:50:30 +08:00
Update execa
The execa update allows us two simplify two things 1. Output collection in a log file with a prefix can be done through `stdout` and `stderr` options of `execa`. 2. We don’t need to ensure that all subprocesses are killed when the main process exits. `execa` takes care of this
This commit is contained in:
Generated
+199
-28
@@ -49,7 +49,7 @@
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-no-only-tests": "^3.1.0",
|
||||
"eslint-plugin-svelte": "^2.35.1",
|
||||
"execa": "^8.0.1",
|
||||
"execa": "^9.0.0",
|
||||
"get-port": "^7.1.0",
|
||||
"happy-dom": "^14.3.8",
|
||||
"prettier": "^3.2.5",
|
||||
@@ -908,6 +908,12 @@
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@sec-ant/readable-stream": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz",
|
||||
"integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@sideway/address": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz",
|
||||
@@ -935,6 +941,18 @@
|
||||
"integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@sindresorhus/merge-streams": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz",
|
||||
"integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/@sinonjs/commons": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz",
|
||||
@@ -2430,23 +2448,26 @@
|
||||
}
|
||||
},
|
||||
"node_modules/execa": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz",
|
||||
"integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==",
|
||||
"version": "9.1.0",
|
||||
"resolved": "https://registry.npmjs.org/execa/-/execa-9.1.0.tgz",
|
||||
"integrity": "sha512-lSgHc4Elo2m6bUDhc3Hl/VxvUDJdQWI40RZ4KMY9bKRc+hgMOT7II/JjbNDhI8VnMtrCb7U/fhpJIkLORZozWw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@sindresorhus/merge-streams": "^4.0.0",
|
||||
"cross-spawn": "^7.0.3",
|
||||
"get-stream": "^8.0.1",
|
||||
"human-signals": "^5.0.0",
|
||||
"is-stream": "^3.0.0",
|
||||
"merge-stream": "^2.0.0",
|
||||
"npm-run-path": "^5.1.0",
|
||||
"onetime": "^6.0.0",
|
||||
"figures": "^6.1.0",
|
||||
"get-stream": "^9.0.0",
|
||||
"human-signals": "^7.0.0",
|
||||
"is-plain-obj": "^4.1.0",
|
||||
"is-stream": "^4.0.1",
|
||||
"npm-run-path": "^5.2.0",
|
||||
"pretty-ms": "^9.0.0",
|
||||
"signal-exit": "^4.1.0",
|
||||
"strip-final-newline": "^3.0.0"
|
||||
"strip-final-newline": "^4.0.0",
|
||||
"yoctocolors": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.17"
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sindresorhus/execa?sponsor=1"
|
||||
@@ -2518,6 +2539,21 @@
|
||||
"reusify": "^1.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/figures": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz",
|
||||
"integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-unicode-supported": "^2.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/file-entry-cache": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
||||
@@ -2675,12 +2711,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/get-stream": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
|
||||
"integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==",
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz",
|
||||
"integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@sec-ant/readable-stream": "^0.4.1",
|
||||
"is-stream": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
@@ -2957,12 +2997,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/human-signals": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
|
||||
"integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==",
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-7.0.0.tgz",
|
||||
"integrity": "sha512-74kytxOUSvNbjrT9KisAbaTZ/eJwD/LrbM/kh5j0IhPuJzwuA19dWvniFGwBzN9rVjg+O/e+F310PjObDXS+9Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=16.17.0"
|
||||
"node": ">=18.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
@@ -3107,6 +3147,18 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/is-plain-obj": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
|
||||
"integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/is-reference": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz",
|
||||
@@ -3116,12 +3168,24 @@
|
||||
}
|
||||
},
|
||||
"node_modules/is-stream": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
|
||||
"integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz",
|
||||
"integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/is-unicode-supported": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.0.0.tgz",
|
||||
"integrity": "sha512-FRdAyx5lusK1iHG0TWpVtk9+1i+GjrzRffhDg4ovQ7mcidMQ6mj+MhKPmvh7Xwyv5gIS06ns49CA7Sqg7lC22Q==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
@@ -3810,6 +3874,18 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/parse-ms": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz",
|
||||
"integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/parse5": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
|
||||
@@ -4115,6 +4191,21 @@
|
||||
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pretty-ms": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.0.0.tgz",
|
||||
"integrity": "sha512-E9e9HJ9R9NasGOgPaPE8VMeiPKAyWR5jcFpNnwIejslIhWqdqOrb2wShBsncMPUb+BcCd2OPYfh7p2W6oemTng==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"parse-ms": "^4.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/property-information": {
|
||||
"version": "6.4.1",
|
||||
"resolved": "https://registry.npmjs.org/property-information/-/property-information-6.4.1.tgz",
|
||||
@@ -4494,12 +4585,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/strip-final-newline": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
|
||||
"integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz",
|
||||
"integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
@@ -5153,6 +5244,74 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vitest/node_modules/execa": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz",
|
||||
"integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"cross-spawn": "^7.0.3",
|
||||
"get-stream": "^8.0.1",
|
||||
"human-signals": "^5.0.0",
|
||||
"is-stream": "^3.0.0",
|
||||
"merge-stream": "^2.0.0",
|
||||
"npm-run-path": "^5.1.0",
|
||||
"onetime": "^6.0.0",
|
||||
"signal-exit": "^4.1.0",
|
||||
"strip-final-newline": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sindresorhus/execa?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/vitest/node_modules/get-stream": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
|
||||
"integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/vitest/node_modules/human-signals": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz",
|
||||
"integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=16.17.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vitest/node_modules/is-stream": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
|
||||
"integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/vitest/node_modules/strip-final-newline": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz",
|
||||
"integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/vscode-oniguruma": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-2.0.1.tgz",
|
||||
@@ -5273,6 +5432,18 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/yoctocolors": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.0.2.tgz",
|
||||
"integrity": "sha512-Ct97huExsu7cWeEjmrXlofevF8CvzUglJ4iGUet5B8xn1oumtAZBpHU4GzYuoE6PVqcZ5hghtBrSlhwHuR1Jmw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "3.22.4",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.22.4.tgz",
|
||||
|
||||
+1
-1
@@ -36,7 +36,7 @@
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-no-only-tests": "^3.1.0",
|
||||
"eslint-plugin-svelte": "^2.35.1",
|
||||
"execa": "^8.0.1",
|
||||
"execa": "^9.0.0",
|
||||
"get-port": "^7.1.0",
|
||||
"happy-dom": "^14.3.8",
|
||||
"prettier": "^3.2.5",
|
||||
|
||||
@@ -6,8 +6,8 @@ import * as Path from "node:path";
|
||||
import assert from "node:assert";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { test as base, expect } from "@playwright/test";
|
||||
import { execa } from "execa";
|
||||
|
||||
import * as Process from "./process.js";
|
||||
import * as issue from "@tests/support/cobs/issue.js";
|
||||
import * as logLabel from "@tests/support/logPrefix.js";
|
||||
import * as patch from "@tests/support/cobs/patch.js";
|
||||
@@ -190,7 +190,7 @@ export async function createSourceBrowsingFixture(
|
||||
const projectName = "source-browsing";
|
||||
const sourceBrowsingDir = Path.join(tmpDir, "repos", projectName);
|
||||
await Fs.mkdir(sourceBrowsingDir, { recursive: true });
|
||||
await Process.spawn("tar", [
|
||||
await execa("tar", [
|
||||
"-xf",
|
||||
Path.join(fixturesDir, `repos/${projectName}.tar.bz2`),
|
||||
"-C",
|
||||
@@ -568,7 +568,7 @@ export async function createCobsFixture(peer: RadiclePeer) {
|
||||
|
||||
export async function createMarkdownFixture(peer: RadiclePeer) {
|
||||
await Fs.mkdir(Path.join(tmpDir, "repos", "markdown"));
|
||||
await Process.spawn("tar", [
|
||||
await execa("tar", [
|
||||
"-xf",
|
||||
Path.join(fixturesDir, "repos", "markdown.tar.bz2"),
|
||||
"-C",
|
||||
|
||||
@@ -13,7 +13,6 @@ import {
|
||||
gitOptions,
|
||||
} from "@tests/support/fixtures.js";
|
||||
import { createPeerManager } from "@tests/support/peerManager.js";
|
||||
import { killAllProcesses } from "@tests/support/process.js";
|
||||
|
||||
export default async function globalSetup(): Promise<() => void> {
|
||||
try {
|
||||
@@ -78,6 +77,5 @@ export default async function globalSetup(): Promise<() => void> {
|
||||
|
||||
return async () => {
|
||||
await peerManager.shutdown();
|
||||
killAllProcesses();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
import type { BaseUrl } from "@httpd-client";
|
||||
import type { ExecaChildProcess, Options as ExecaOptions } from "execa";
|
||||
|
||||
import type * as Execa from "execa";
|
||||
import { execa } from "execa";
|
||||
import * as Fs from "node:fs/promises";
|
||||
import * as Os from "node:os";
|
||||
import * as Path from "node:path";
|
||||
@@ -10,10 +10,7 @@ import * as Util from "node:util";
|
||||
import getPort from "get-port";
|
||||
import matches from "lodash/matches.js";
|
||||
import waitOn from "wait-on";
|
||||
import { execa } from "execa";
|
||||
import * as readline from "node:readline/promises";
|
||||
|
||||
import * as Process from "./process.js";
|
||||
import { randomTag } from "@tests/support/support.js";
|
||||
import { sleep } from "@app/lib/sleep.js";
|
||||
import { array, literal, number, object, string, union, z } from "zod";
|
||||
@@ -151,13 +148,20 @@ export const NodeConfigSchema = object({
|
||||
|
||||
export interface NodeConfig extends z.infer<typeof NodeConfigSchema> {}
|
||||
|
||||
// Options passed to `RadiclePeer#rad` and `RadiclePeer#git` that control how
|
||||
// the process is spawned.
|
||||
interface SpawnOptions extends ExecaOptions {
|
||||
// Sets the prefix for the commands output in the logs. If `null`, does not
|
||||
// log any output. Defaults to `<peer name> <binary name>`.
|
||||
logPrefix?: string | null;
|
||||
}
|
||||
// Specialize the return type of `execa()` to guarantee that `stdout` and
|
||||
// `stderr` are strings.
|
||||
type SpawnResult = Execa.ResultPromise<
|
||||
SpawnOptions & {
|
||||
stdout: (line: unknown) => AsyncGenerator<string, void, void>;
|
||||
stderr: (line: unknown) => AsyncGenerator<string, void, void>;
|
||||
encoding: "utf8";
|
||||
}
|
||||
>;
|
||||
|
||||
type SpawnOptions = Omit<
|
||||
Execa.Options,
|
||||
"stdin" | "stdout" | "stderr" | "lines" | "encoding"
|
||||
>;
|
||||
|
||||
export class RadiclePeer {
|
||||
public checkoutPath: string;
|
||||
@@ -171,10 +175,10 @@ export class RadiclePeer {
|
||||
#gitOptions?: Record<string, string>;
|
||||
#listenSocketAddr?: string;
|
||||
#httpdBaseUrl?: BaseUrl;
|
||||
#nodeProcess?: ExecaChildProcess;
|
||||
#nodeProcess?: SpawnResult;
|
||||
// Name for easy identification. Used on file system and in logs.
|
||||
#name: string;
|
||||
#childProcesses: ExecaChildProcess[] = [];
|
||||
#childProcesses: SpawnResult[] = [];
|
||||
|
||||
private constructor(props: {
|
||||
checkoutPath: string;
|
||||
@@ -296,7 +300,6 @@ export class RadiclePeer {
|
||||
|
||||
const { stdout } = this.rad(["node", "events"], {
|
||||
cwd: this.#radHome,
|
||||
logPrefix: null,
|
||||
});
|
||||
|
||||
if (!stdout) {
|
||||
@@ -327,6 +330,8 @@ export class RadiclePeer {
|
||||
}
|
||||
|
||||
public async stopNode() {
|
||||
// Don’t leak unhandled rejections when forcefully killing the process
|
||||
this.#nodeProcess?.catch(() => {});
|
||||
this.#nodeProcess?.kill("SIGTERM");
|
||||
|
||||
await waitOn({
|
||||
@@ -343,7 +348,11 @@ export class RadiclePeer {
|
||||
public async shutdown() {
|
||||
// We don’t care about proper cleanup. We just want to make sure that no
|
||||
// processes are running anymore.
|
||||
this.#childProcesses.forEach(p => p.kill("SIGKILL"));
|
||||
this.#childProcesses.forEach(p => {
|
||||
// Don’t leak unhandled rejections when forcefully killing the process
|
||||
p.catch(() => {});
|
||||
p.kill("SIGKILL");
|
||||
});
|
||||
}
|
||||
|
||||
public get address(): string {
|
||||
@@ -373,11 +382,11 @@ export class RadiclePeer {
|
||||
return this.#httpdBaseUrl;
|
||||
}
|
||||
|
||||
public git(args: string[] = [], opts?: SpawnOptions): ExecaChildProcess {
|
||||
public git(args: string[] = [], opts?: SpawnOptions): SpawnResult {
|
||||
return this.spawn("git", args, { ...opts });
|
||||
}
|
||||
|
||||
public rad(args: string[] = [], opts?: SpawnOptions): ExecaChildProcess {
|
||||
public rad(args: string[] = [], opts?: SpawnOptions): SpawnResult {
|
||||
return this.spawn("rad", args, { ...opts });
|
||||
}
|
||||
|
||||
@@ -385,8 +394,18 @@ export class RadiclePeer {
|
||||
cmd: string,
|
||||
args: string[] = [],
|
||||
opts?: SpawnOptions,
|
||||
): ExecaChildProcess {
|
||||
opts = {
|
||||
): SpawnResult {
|
||||
const prefix = logPrefix(`${this.#name} ${cmd}`);
|
||||
const outputLog = this.#outputLog;
|
||||
|
||||
function* logWithPrefix(line: unknown) {
|
||||
if (typeof line === "string") {
|
||||
outputLog.write(`${prefix} ${line}\n`, "utf8");
|
||||
}
|
||||
yield line;
|
||||
}
|
||||
|
||||
const childProcess = execa(cmd, args, {
|
||||
...opts,
|
||||
env: {
|
||||
GIT_CONFIG_GLOBAL: "/dev/null",
|
||||
@@ -399,17 +418,12 @@ export class RadiclePeer {
|
||||
...opts?.env,
|
||||
...this.#gitOptions,
|
||||
},
|
||||
};
|
||||
const childProcess = Process.spawn(cmd, args, opts);
|
||||
this.#childProcesses.push(childProcess);
|
||||
encoding: "utf8",
|
||||
stdout: logWithPrefix,
|
||||
stderr: logWithPrefix,
|
||||
});
|
||||
|
||||
if (opts.logPrefix !== null) {
|
||||
void Process.prefixOutput(
|
||||
childProcess,
|
||||
opts.logPrefix || `${this.#name} ${cmd}`,
|
||||
this.#outputLog,
|
||||
);
|
||||
}
|
||||
this.#childProcesses.push(childProcess);
|
||||
|
||||
return childProcess;
|
||||
}
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
import type { ExecaChildProcess, Options } from "execa";
|
||||
|
||||
import * as Stream from "node:stream";
|
||||
import { StringDecoder } from "string_decoder";
|
||||
import { execa } from "execa";
|
||||
|
||||
import { logPrefix } from "./logPrefix.js";
|
||||
|
||||
// Processes that should be SIGKILLed when the Node process shutsdown.
|
||||
// We add all proxy and node instances that we spawn to this list.
|
||||
const processes: ExecaChildProcess[] = [];
|
||||
|
||||
process.on("exit", killAllProcesses);
|
||||
process.on("SIGINT", killAllProcesses);
|
||||
process.on("SIGTERM", killAllProcesses);
|
||||
|
||||
// Kill all processes with SIGKILL
|
||||
export function killAllProcesses(): void {
|
||||
for (const process of processes) {
|
||||
if (process.exitCode === null) {
|
||||
process.kill("SIGKILL");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Spawn a process with `execa` and register it.
|
||||
//
|
||||
// The process will be killed by `killAllProcesses`.
|
||||
export function spawn(
|
||||
bin: string,
|
||||
args: string[],
|
||||
options?: Options,
|
||||
): ExecaChildProcess {
|
||||
const child = execa(bin, args, options);
|
||||
processes.push(child);
|
||||
return child;
|
||||
}
|
||||
|
||||
// Forwards piped `stdout` and `stderr` of a child process to `output`
|
||||
// and prefixes it with the given label. The prefix is colored.
|
||||
export function prefixOutput(
|
||||
childProcess: ExecaChildProcess,
|
||||
label: string,
|
||||
output: Stream.Writable,
|
||||
): ExecaChildProcess {
|
||||
const pref = logPrefix(label);
|
||||
if (childProcess.stdout) {
|
||||
const stdoutPrefix = new LinePrefix(pref);
|
||||
childProcess.stdout.pipe(stdoutPrefix).pipe(output, { end: false });
|
||||
}
|
||||
if (childProcess.stderr) {
|
||||
const stderrPrefix = new LinePrefix(pref);
|
||||
childProcess.stderr.pipe(stderrPrefix).pipe(output, { end: false });
|
||||
}
|
||||
|
||||
return childProcess;
|
||||
}
|
||||
|
||||
// A transform that prefixes each line from the source with the given
|
||||
// string and pushes it to the sink.
|
||||
class LinePrefix extends Stream.Transform {
|
||||
private buffer: string = "";
|
||||
private stringDecoder = new StringDecoder();
|
||||
|
||||
public constructor(private prefix: string) {
|
||||
super();
|
||||
}
|
||||
|
||||
public _transform(data: Buffer, _encoding: string, next: () => void): void {
|
||||
const str = this.buffer + this.stringDecoder.write(data);
|
||||
const lines = str.split(/\r?\n/);
|
||||
this.buffer = lines.pop() || "";
|
||||
lines.forEach(line => this.push(`${this.prefix}${line}\n`));
|
||||
next();
|
||||
}
|
||||
|
||||
public _flush(done: () => void): void {
|
||||
const rest = `${this.buffer}${this.stringDecoder.end()}`;
|
||||
if (rest) {
|
||||
this.push(`${this.prefix}${rest}\n`);
|
||||
}
|
||||
done();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { Locator, Page } from "@playwright/test";
|
||||
import type { RadiclePeer } from "@tests/support/peerManager";
|
||||
import type { ExecaReturnValue } from "execa";
|
||||
|
||||
import * as Path from "node:path";
|
||||
import { expect } from "@playwright/test";
|
||||
@@ -52,7 +51,7 @@ export async function createProject(
|
||||
return { rid, projectFolder, defaultBranch };
|
||||
}
|
||||
|
||||
export function extractPatchId(cmdOutput: ExecaReturnValue<string>) {
|
||||
export function extractPatchId(cmdOutput: { stderr: string }) {
|
||||
const match = cmdOutput.stderr.match(/[0-9a-f]{40}/);
|
||||
if (match) {
|
||||
return match[0];
|
||||
|
||||
Reference in New Issue
Block a user