-
Notifications
You must be signed in to change notification settings - Fork 201
/
exec-promise.ts
98 lines (86 loc) · 2.76 KB
/
exec-promise.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import { spawn } from "child_process";
import createLog from "./logger";
const log = createLog();
/**
* Wraps up running a command into a single promise,
* returning the stdout as a string if the command succeeds
* and throwing if it does not.
*
* @param cmd - the command as a string to pass in
*/
export default async function execPromise(
cmd: string,
args: Array<string | undefined | false> = []
) {
const callSite = new Error().stack;
const filteredArgs = args.filter(
(arg): arg is string => typeof arg === "string"
);
return new Promise<string>((completed, reject) => {
const child = spawn(cmd, filteredArgs, {
cwd: process.cwd(),
env: process.env,
shell: true,
});
let allStdout = "";
let allStderr = "";
if (child.stdout) {
if (log.logLevel === "veryVerbose") {
child.stdout.pipe(process.stdout);
}
child.stdout.on("data", async (data: Buffer) => {
const stdout = data.toString();
allStdout += stdout;
});
}
if (child.stderr) {
if (log.logLevel === "veryVerbose") {
child.stderr.pipe(process.stderr);
}
child.stderr.on("data", (data: Buffer) => {
const stderr = data.toString();
allStderr += stderr;
});
}
// This usually occurs during dev-time, when you have the wrong command
child.on("error", (err) => {
reject(
new Error(`Failed to run '${cmd}' - ${err.message} \n\n\n${allStderr}`)
);
});
child.on("exit", (code) => {
// No code, no errors
if (code) {
// The command bailed for whatever reason, print a verbose error message
// with the stdout underneath
let appendedStdErr = "";
appendedStdErr += allStdout.length ? `\n\n${allStdout}` : "";
appendedStdErr += allStderr.length ? `\n\n${allStderr}` : "";
const argList = filteredArgs
.join(", ")
.replace(
new RegExp(`${process.env.GH_TOKEN}`, "g"),
`****${(process.env.GH_TOKEN || "").slice(-4)}`
);
const error = new Error(
`Running command '${cmd}' with args [${argList}] failed${appendedStdErr}`
);
error.stack = (error.stack || "") + callSite;
reject(error);
} else {
// Tools can occasionally print to stderr but not fail, so print that just in case.
if (allStderr.length) {
if (allStderr.includes("Failed to replace env in config")) {
const error = new Error(allStderr);
error.stack = (error.stack || "") + callSite;
reject(error);
} else {
log.log.warn(allStderr);
}
}
// Resolve the string of the whole stdout
completed(allStdout.trim());
}
});
});
}