@journeyapps/cloudcode-build-agent 0.0.0-dev.1377dae → 0.0.0-dev.2b3e822
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/builder.d.ts +1 -15
- package/dist/builder.js +55 -58
- package/dist/builder.js.map +1 -1
- package/dist/cli.js +2 -7
- package/dist/cli.js.map +1 -1
- package/dist/defs.js +25 -14
- package/dist/defs.js.map +1 -1
- package/dist/detect_tasks.d.ts +5 -6
- package/dist/detect_tasks.js +4 -2
- package/dist/detect_tasks.js.map +1 -1
- package/dist/installer.d.ts +0 -5
- package/dist/installer.js +26 -34
- package/dist/installer.js.map +1 -1
- package/dist/run.d.ts +9 -3
- package/dist/run.js +81 -10
- package/dist/run.js.map +1 -1
- package/package.json +2 -1
- package/src/builder.ts +63 -87
- package/src/cli.ts +2 -7
- package/src/defs.ts +26 -15
- package/src/detect_tasks.ts +5 -12
- package/src/installer.ts +29 -33
- package/src/run.ts +104 -15
- package/tsconfig.json +2 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/spawn-stream.d.ts +0 -15
- package/dist/spawn-stream.js +0 -59
- package/dist/spawn-stream.js.map +0 -1
- package/src/spawn-stream.ts +0 -73
package/src/builder.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import * as path from 'node:path';
|
|
2
2
|
import * as jetpack from 'fs-jetpack';
|
|
3
3
|
import * as semver from 'semver';
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
import { detectTasks, DetectedTask } from './detect_tasks';
|
|
4
|
+
import * as utils from './installer';
|
|
5
|
+
import { detectTasks } from './detect_tasks';
|
|
7
6
|
import { runCommand } from './run';
|
|
8
7
|
|
|
9
8
|
import * as _ from 'lodash';
|
|
@@ -15,104 +14,81 @@ export type GeneralTaskConfig = {
|
|
|
15
14
|
backend_url: string;
|
|
16
15
|
};
|
|
17
16
|
|
|
18
|
-
export
|
|
19
|
-
only
|
|
20
|
-
custom_node_installation_path?: string;
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
type ToolPaths = { bin_path: string; node_bin: string; npm_bin: string };
|
|
17
|
+
export async function buildTasks(project_path: string, dest: string, config: GeneralTaskConfig, only?: string) {
|
|
18
|
+
const tasks = await detectTasks(project_path, only);
|
|
24
19
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
dest: string,
|
|
28
|
-
config: GeneralTaskConfig,
|
|
29
|
-
options?: BuildOptions
|
|
30
|
-
) {
|
|
31
|
-
const tasks = await detectTasks(project_path, options?.only);
|
|
20
|
+
const required_node_versions = _.compact(tasks.map((t) => t.required_node_version));
|
|
21
|
+
const install_node_versions = _.uniq(required_node_versions);
|
|
32
22
|
|
|
23
|
+
// FIXME: Maybe refactor this section into an ensureNodeVersion (or something) that returns the relevant toolpaths?
|
|
24
|
+
const tool_paths: Record<string, { bin_path: string; node_bin: string; npm_bin: string }> = {};
|
|
33
25
|
// Use the version of nodejs that's running this script as the default.
|
|
34
26
|
const default_tool_paths = {
|
|
35
27
|
bin_path: path.dirname(process.execPath),
|
|
36
28
|
node_bin: process.execPath,
|
|
37
29
|
npm_bin: path.join(path.dirname(process.execPath), 'npm')
|
|
38
30
|
};
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
);
|
|
49
|
-
|
|
31
|
+
tool_paths[process.version] = default_tool_paths;
|
|
32
|
+
|
|
33
|
+
for (const required_node_version of install_node_versions) {
|
|
34
|
+
// FIXME: put this in another directory to avoid leaking into the builder
|
|
35
|
+
const custom_node_path = path.resolve(`node-${semver.major(required_node_version)}`);
|
|
36
|
+
|
|
37
|
+
if (!jetpack.exists(path.join(custom_node_path, 'bin/node'))) {
|
|
38
|
+
console.debug(`installing to ${custom_node_path}`);
|
|
39
|
+
await jetpack.dirAsync(custom_node_path);
|
|
40
|
+
await utils.downloadAndInstallNode(required_node_version, custom_node_path);
|
|
41
|
+
} else {
|
|
42
|
+
console.debug(`already installed in ${custom_node_path}`);
|
|
50
43
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
await buildTask(task, project_path, dest, config, {
|
|
54
|
-
node_version,
|
|
55
|
-
...(custom_tool_paths ?? default_tool_paths)
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export async function buildTask(
|
|
61
|
-
task: DetectedTask,
|
|
62
|
-
project_path: string,
|
|
63
|
-
dest: string,
|
|
64
|
-
config: GeneralTaskConfig,
|
|
65
|
-
node_context: { node_version: string } & ToolPaths
|
|
66
|
-
) {
|
|
67
|
-
const builder_package = task.builder_package;
|
|
68
|
-
const builder_script = task.builder_script;
|
|
69
|
-
const { bin_path, node_bin, npm_bin } = node_context;
|
|
70
|
-
const builder_bin = path.resolve(bin_path, builder_script);
|
|
71
|
-
|
|
72
|
-
if (!jetpack.exists(node_bin)) {
|
|
73
|
-
throw new Error(`Node binary not found: ${node_bin}`);
|
|
44
|
+
tool_paths[required_node_version] = utils.nodePaths(custom_node_path);
|
|
74
45
|
}
|
|
46
|
+
console.debug('----');
|
|
75
47
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
48
|
+
for (const task of tasks) {
|
|
49
|
+
const debug = require('debug')(`${task.task_name}`);
|
|
50
|
+
const node_version = task.required_node_version ?? process.version;
|
|
51
|
+
const builder_package = task.builder_package;
|
|
52
|
+
const builder_script = task.builder_script;
|
|
53
|
+
const { bin_path, node_bin, npm_bin } = tool_paths[node_version];
|
|
54
|
+
const builder_bin = path.resolve(bin_path, builder_script);
|
|
79
55
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
env: process.env
|
|
83
|
-
});
|
|
84
|
-
for await (let event of stream1) {
|
|
85
|
-
const log = event.stdout ?? event.stderr;
|
|
86
|
-
if (log) {
|
|
87
|
-
console.log(`[${task.task_name} - install]`, log.trimRight());
|
|
56
|
+
if (!jetpack.exists(node_bin)) {
|
|
57
|
+
throw new Error(`Node binary not found: ${node_bin}`);
|
|
88
58
|
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (!jetpack.exists(builder_bin)) {
|
|
92
|
-
console.error(`[${task.task_name}] ${builder_bin} not found`);
|
|
93
|
-
throw new Error(`Builder script not found for task ${task.task_name}`);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const builder_args: string[] = [];
|
|
97
|
-
builder_args.push(builder_bin);
|
|
98
|
-
builder_args.push('--src', project_path);
|
|
99
|
-
builder_args.push(`--out`, path.join(dest, task.task_name));
|
|
100
|
-
builder_args.push(`--zip`, path.join(dest, `${task.task_name}.zip`));
|
|
101
|
-
builder_args.push(`--task`, `${task.task_name}`);
|
|
102
|
-
builder_args.push(`--appId`, config.app_id);
|
|
103
|
-
builder_args.push(`--env`, config.env);
|
|
104
|
-
builder_args.push(`--backendId`, config.backend_id);
|
|
105
|
-
builder_args.push(`--backendUrl`, config.backend_url);
|
|
106
|
-
builder_args.push(`--runInstallScripts`, 'true');
|
|
107
|
-
|
|
108
|
-
console.debug(`[${task.task_name}] Trying: ${node_bin} ${builder_args.join(' ')}`);
|
|
109
59
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
60
|
+
// console.debug(`[${task.task_name}] Installing builder script "${builder_package}" for node ${node_version}`);
|
|
61
|
+
debug(`Installing builder script "${builder_package}" for node ${node_version}`);
|
|
62
|
+
// TODO: This may need to be replaced with the something like the spawn-stream stuff in build-agent? OR what to do with the stdout/stderr and errorhandling?
|
|
63
|
+
await runCommand(
|
|
64
|
+
node_bin,
|
|
65
|
+
[npm_bin, '--global', 'install', builder_package],
|
|
66
|
+
{ cwd: project_path },
|
|
67
|
+
{ task_name: task.task_name }
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
if (!jetpack.exists(builder_bin)) {
|
|
71
|
+
console.error(`[${task.task_name}] ${builder_bin} not found`);
|
|
72
|
+
throw new Error(`Builder script not found for task ${task.task_name}`);
|
|
116
73
|
}
|
|
74
|
+
|
|
75
|
+
const builder_args: string[] = [];
|
|
76
|
+
// --src ./ --out ./dist/echo --task echo --appId 'appid' --env 'testing' --backendId 'backendid' --backendUrl 'http://run.journeyapps.test'
|
|
77
|
+
builder_args.push(builder_bin);
|
|
78
|
+
builder_args.push('--src', project_path);
|
|
79
|
+
builder_args.push(`--out`, path.join(dest, task.task_name));
|
|
80
|
+
builder_args.push(`--zip`, path.join(dest, `${task.task_name}.zip`));
|
|
81
|
+
builder_args.push(`--task`, `${task.task_name}`);
|
|
82
|
+
builder_args.push(`--appId`, config.app_id);
|
|
83
|
+
builder_args.push(`--env`, config.env);
|
|
84
|
+
builder_args.push(`--backendId`, config.backend_id);
|
|
85
|
+
builder_args.push(`--backendUrl`, config.backend_url);
|
|
86
|
+
// builder_args.push(`--runInstallScripts`, 'true'); // TODO: handle this from feature flags somehow
|
|
87
|
+
|
|
88
|
+
// console.debug(`[${task.task_name}] Trying: ${node_bin} ${builder_args.join(' ')}`);
|
|
89
|
+
debug(`Trying: ${node_bin} ${builder_args.join(' ')}`);
|
|
90
|
+
|
|
91
|
+
await runCommand(node_bin, builder_args, { cwd: project_path }, { task_name: task.task_name });
|
|
92
|
+
console.debug('----');
|
|
117
93
|
}
|
|
118
94
|
}
|
package/src/cli.ts
CHANGED
|
@@ -5,8 +5,7 @@ import * as yargs from 'yargs';
|
|
|
5
5
|
import { buildTasks } from './';
|
|
6
6
|
|
|
7
7
|
const DEFAULT_SRC_PATH = './';
|
|
8
|
-
const DEFAULT_OUT_PATH = './dist
|
|
9
|
-
const DEFAULT_TMP_PATH = '/tmp/cloudcode-build-agent/node';
|
|
8
|
+
const DEFAULT_OUT_PATH = './dist';
|
|
10
9
|
|
|
11
10
|
yargs
|
|
12
11
|
.command(
|
|
@@ -18,7 +17,6 @@ yargs
|
|
|
18
17
|
.option('only', { string: true })
|
|
19
18
|
.option('path', { default: DEFAULT_SRC_PATH })
|
|
20
19
|
.option('out', { default: DEFAULT_OUT_PATH })
|
|
21
|
-
.option('node_work_dir', { default: DEFAULT_TMP_PATH })
|
|
22
20
|
// TODO: investigate yargs.config() for reading task config blob from a file. But how to ensure required args?
|
|
23
21
|
.option('appId', { string: true, demandOption: true, describe: "CloudCode's reference id" })
|
|
24
22
|
.option('env', { string: true, demandOption: true })
|
|
@@ -33,10 +31,7 @@ yargs
|
|
|
33
31
|
backend_id: argv.backendId,
|
|
34
32
|
backend_url: argv.backendUrl
|
|
35
33
|
};
|
|
36
|
-
await buildTasks(argv.path, argv.out, config,
|
|
37
|
-
only: argv.only,
|
|
38
|
-
custom_node_installation_path: argv.node_work_dir
|
|
39
|
-
});
|
|
34
|
+
await buildTasks(argv.path, argv.out, config, argv.only);
|
|
40
35
|
})
|
|
41
36
|
)
|
|
42
37
|
.option('verbose', {
|
package/src/defs.ts
CHANGED
|
@@ -1,34 +1,45 @@
|
|
|
1
1
|
// TODO: maybe publish (some of) this from the CC service?
|
|
2
2
|
export const SUPPORTED_VERSIONS = [
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
{
|
|
4
|
+
// proposed
|
|
5
|
+
version: '1.13.0',
|
|
6
|
+
node: '16.19.1',
|
|
7
|
+
builder_package: '@journeyapps/cloudcode-build@1.13.0',
|
|
8
|
+
builder_script: 'cloudcode-build'
|
|
9
|
+
},
|
|
10
10
|
{
|
|
11
11
|
version: '1.12.0',
|
|
12
|
-
node: '16.19.1', // FIXME: maybe the very specific node version here is too brittle?
|
|
13
|
-
builder_package: '@journeyapps/cloudcode-build-legacy@1.12.0'
|
|
12
|
+
node: '16.19.1', // FIXME: maybe the very specific node version here is too brittle?
|
|
13
|
+
// builder_package: '@journeyapps/cloudcode-build-legacy@1.12.0'
|
|
14
|
+
// DEV HACK:
|
|
15
|
+
builder_package: '~/src/journey-cloudcode/packages/cloudcode-build-legacy',
|
|
14
16
|
builder_script: 'cloudcode-build-legacy'
|
|
15
17
|
},
|
|
16
18
|
{
|
|
17
19
|
version: '1.11.2',
|
|
18
|
-
node: '14.21.3',
|
|
19
|
-
builder_package: '@journeyapps/cloudcode-build-legacy@1.12.0'
|
|
20
|
+
// node: '14.21.3',
|
|
21
|
+
// builder_package: '@journeyapps/cloudcode-build-legacy@1.12.0'
|
|
22
|
+
// DEV HACK:
|
|
23
|
+
node: '16.19.1', // because local dev on darwin/arm64 and there's no darwin-arm64 builds for node14 available.
|
|
24
|
+
builder_package: '~/src/journey-cloudcode/packages/cloudcode-build-legacy',
|
|
20
25
|
builder_script: 'cloudcode-build-legacy'
|
|
21
26
|
},
|
|
22
27
|
{
|
|
23
28
|
version: '1.11.1',
|
|
24
|
-
node: '14.21.3',
|
|
25
|
-
builder_package: '@journeyapps/cloudcode-build-legacy@1.12.0'
|
|
29
|
+
// node: '14.21.3',
|
|
30
|
+
// builder_package: '@journeyapps/cloudcode-build-legacy@1.12.0'
|
|
31
|
+
// DEV HACK:
|
|
32
|
+
node: '16.19.1', // because local dev on darwin/arm64 and there's no darwin-arm64 builds for node14 available.
|
|
33
|
+
builder_package: '~/src/journey-cloudcode/packages/cloudcode-build-legacy',
|
|
26
34
|
builder_script: 'cloudcode-build-legacy'
|
|
27
35
|
},
|
|
28
36
|
{
|
|
29
37
|
version: '1.11.0',
|
|
30
|
-
node: '14.21.3',
|
|
31
|
-
builder_package: '@journeyapps/cloudcode-build-legacy@1.12.0'
|
|
38
|
+
// node: '14.21.3',
|
|
39
|
+
// builder_package: '@journeyapps/cloudcode-build-legacy@1.12.0'
|
|
40
|
+
// DEV HACK:
|
|
41
|
+
node: '16.19.1', // because local dev on darwin/arm64 and there's no darwin-arm64 builds for node14 available.
|
|
42
|
+
builder_package: '~/src/journey-cloudcode/packages/cloudcode-build-legacy',
|
|
32
43
|
builder_script: 'cloudcode-build-legacy'
|
|
33
44
|
}
|
|
34
45
|
];
|
package/src/detect_tasks.ts
CHANGED
|
@@ -4,6 +4,7 @@ import * as jetpack from 'fs-jetpack';
|
|
|
4
4
|
import * as semver from 'semver';
|
|
5
5
|
import * as defs from './defs';
|
|
6
6
|
|
|
7
|
+
// TODO: validations for cloudcode specific keys and structure?
|
|
7
8
|
async function readPackage(path: string) {
|
|
8
9
|
try {
|
|
9
10
|
const content = await fs.promises.readFile(path, { encoding: 'utf-8' });
|
|
@@ -16,16 +17,7 @@ async function readPackage(path: string) {
|
|
|
16
17
|
}
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
export
|
|
20
|
-
pkg_path: string;
|
|
21
|
-
task_name: string;
|
|
22
|
-
task_version: string;
|
|
23
|
-
required_node_version?: string;
|
|
24
|
-
builder_package: string;
|
|
25
|
-
builder_script: string;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
export async function detectTasks(project_path: string, only?: string): Promise<DetectedTask[]> {
|
|
20
|
+
export async function detectTasks(project_path: string, only?: string) {
|
|
29
21
|
const package_files = await jetpack.findAsync(path.join(project_path, 'cloudcode'), { matching: '**/package.json' });
|
|
30
22
|
const filtered_package_files = package_files.filter((pkg_path) => {
|
|
31
23
|
// FIXME: this is kinda clunky.
|
|
@@ -63,8 +55,9 @@ export async function detectTasks(project_path: string, only?: string): Promise<
|
|
|
63
55
|
|
|
64
56
|
const running_node_version = process.versions.node;
|
|
65
57
|
let required_node_version;
|
|
66
|
-
if (matching?.node && semver.major(matching.node) !== semver.major(running_node_version)) {
|
|
67
|
-
|
|
58
|
+
// if (matching?.node && semver.major(matching.node) !== semver.major(running_node_version)) {
|
|
59
|
+
if (matching?.node && semver.parse(matching.node) !== semver.parse(running_node_version)) {
|
|
60
|
+
console.debug(`Task requires different node version: v${matching.node}`);
|
|
68
61
|
|
|
69
62
|
required_node_version = matching.node;
|
|
70
63
|
}
|
package/src/installer.ts
CHANGED
|
@@ -1,22 +1,10 @@
|
|
|
1
|
-
import * as jetpack from 'fs-jetpack';
|
|
2
|
-
import * as path from 'node:path';
|
|
3
|
-
import * as URL from 'node:url';
|
|
4
1
|
import fetch from 'node-fetch';
|
|
2
|
+
import * as path from 'node:path';
|
|
5
3
|
import * as fs from 'node:fs';
|
|
6
4
|
import * as os from 'node:os';
|
|
5
|
+
import * as URL from 'node:url';
|
|
7
6
|
import * as tar from 'tar';
|
|
8
7
|
|
|
9
|
-
export async function ensureCustomNodeVersion(node_version: string, install_path: string) {
|
|
10
|
-
if (!jetpack.exists(path.join(install_path, 'bin/node'))) {
|
|
11
|
-
console.debug(`[node ${node_version}] Installing to ${install_path}`);
|
|
12
|
-
await jetpack.dirAsync(install_path);
|
|
13
|
-
await downloadAndInstallNode(node_version, install_path);
|
|
14
|
-
} else {
|
|
15
|
-
console.debug(`[node ${node_version}] Already installed in ${install_path}`);
|
|
16
|
-
}
|
|
17
|
-
return nodePaths(install_path);
|
|
18
|
-
}
|
|
19
|
-
|
|
20
8
|
/* Basically this, but for different dirs.
|
|
21
9
|
curl https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-${PLATFORM}64.tar.gz -L | tar -xzC /node-dedicated && \
|
|
22
10
|
mv /node-dedicated/node-v${NODE_VERSION}-linux-${PLATFORM}64/bin/node /node-dedicated/node
|
|
@@ -24,11 +12,17 @@ export async function ensureCustomNodeVersion(node_version: string, install_path
|
|
|
24
12
|
// TODO: feature to find the latest minor and patch for a given major version?
|
|
25
13
|
export async function downloadAndInstallNode(node_version: string, destination: string) {
|
|
26
14
|
// eg. https://nodejs.org/dist/v18.14.2/node-v18.14.2-linux-x64.tar.xz
|
|
15
|
+
|
|
16
|
+
// const PLATFORM = 'x';
|
|
17
|
+
// const node_download_url = `https://nodejs.org/dist/v${node_version}/node-v${node_version}-linux-${PLATFORM}64.tar.gz`;
|
|
18
|
+
|
|
19
|
+
// TODO: this is just for dev for now. Find a better fix.
|
|
27
20
|
const ARCH = os.arch();
|
|
28
21
|
const PLATFORM = os.platform();
|
|
29
22
|
const node_download_url = `https://nodejs.org/dist/v${node_version}/node-v${node_version}-${PLATFORM}-${ARCH}.tar.gz`;
|
|
30
23
|
|
|
31
24
|
await downloadAndExtractTarball(node_download_url, destination);
|
|
25
|
+
// TODO: move binaries into local bin path?
|
|
32
26
|
return nodePaths(destination);
|
|
33
27
|
}
|
|
34
28
|
|
|
@@ -61,12 +55,15 @@ export async function downloadAndExtractTarball(url: string, dest: string) {
|
|
|
61
55
|
throw new Error(`Failed to download: ${errorBody}`);
|
|
62
56
|
}
|
|
63
57
|
|
|
58
|
+
// FIXME: replace with webstreams? but according to the types package webstreams aren't available in node 16?!??
|
|
64
59
|
const file = fs.createWriteStream(download); // Sink the download stream into a file, so it can be extracted.
|
|
65
60
|
response.body.pipe(file);
|
|
66
61
|
|
|
67
62
|
file.on('finish', async () => {
|
|
68
63
|
try {
|
|
69
|
-
console.
|
|
64
|
+
console.log('Extracting...', download);
|
|
65
|
+
|
|
66
|
+
// const comp = fs.createReadStream(download);
|
|
70
67
|
|
|
71
68
|
tar.extract({
|
|
72
69
|
cwd: tmpdir,
|
|
@@ -82,29 +79,28 @@ export async function downloadAndExtractTarball(url: string, dest: string) {
|
|
|
82
79
|
// fs.rmSync(dist, { recursive: true });
|
|
83
80
|
// }
|
|
84
81
|
if (fs.existsSync(uncomp)) {
|
|
85
|
-
console.
|
|
82
|
+
console.log(`Moving extracted files from ${uncomp} to ${dist}`);
|
|
86
83
|
fs.renameSync(uncomp, dist);
|
|
87
84
|
} else {
|
|
88
|
-
console.
|
|
85
|
+
console.log(`Can't find extract dir ${uncomp}`);
|
|
89
86
|
}
|
|
90
87
|
|
|
88
|
+
// FIXME: this seems to sometimes cause errors
|
|
91
89
|
/*
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
path: '/var/folders/kc/h6m4zpmd23v13s63mygvkslm0000gn/T/node-v16.19.1-darwin-arm64.tar.gz'
|
|
107
|
-
```
|
|
90
|
+
----
|
|
91
|
+
node:events:505
|
|
92
|
+
throw er; // Unhandled 'error' event
|
|
93
|
+
^
|
|
94
|
+
|
|
95
|
+
Error: ENOENT: no such file or directory, open '/var/folders/kc/h6m4zpmd23v13s63mygvkslm0000gn/T/node-v16.19.1-darwin-arm64.tar.gz'
|
|
96
|
+
Emitted 'error' event on ReadStream instance at:
|
|
97
|
+
at emitErrorNT (node:internal/streams/destroy:157:8)
|
|
98
|
+
at emitErrorCloseNT (node:internal/streams/destroy:122:3)
|
|
99
|
+
at processTicksAndRejections (node:internal/process/task_queues:83:21) {
|
|
100
|
+
errno: -2,
|
|
101
|
+
code: 'ENOENT',
|
|
102
|
+
syscall: 'open',
|
|
103
|
+
path: '/var/folders/kc/h6m4zpmd23v13s63mygvkslm0000gn/T/node-v16.19.1-darwin-arm64.tar.gz'
|
|
108
104
|
*/
|
|
109
105
|
// fs.unlinkSync(file.path);
|
|
110
106
|
|
package/src/run.ts
CHANGED
|
@@ -1,23 +1,112 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { SpawnOptions } from 'child_process';
|
|
1
|
+
import { spawn, Options } from 'child-process-promise';
|
|
2
|
+
import type { SpawnOptions } from 'child_process';
|
|
3
3
|
|
|
4
|
-
export async function
|
|
4
|
+
export async function runCommand(
|
|
5
5
|
command: string,
|
|
6
|
-
|
|
7
|
-
options
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
commandArgs: string[],
|
|
7
|
+
options: RunCommandOpts = {},
|
|
8
|
+
context: { task_name: string }
|
|
9
|
+
) {
|
|
10
|
+
const debug = require('debug')(`${context.task_name} build`);
|
|
11
|
+
const errors: string[] = [];
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
const defaultLogLine = (isStderr: boolean, line: string, childProcess: any) => {
|
|
14
|
+
if (isStderr) {
|
|
15
|
+
if (line.startsWith('warning package.json: No license field')) {
|
|
16
|
+
// This is a noisy yarn warning, ignore it.
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
errors.push(line);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
let result;
|
|
23
|
+
try {
|
|
24
|
+
result = await spawnPromise(command, commandArgs, { logLine: defaultLogLine, ...options }, context);
|
|
25
|
+
} catch (err) {
|
|
26
|
+
if (errors.length > 0) {
|
|
27
|
+
// Handled below
|
|
28
|
+
} else {
|
|
29
|
+
// Exit code without any logged errors.
|
|
30
|
+
throw err;
|
|
17
31
|
}
|
|
18
32
|
}
|
|
19
33
|
|
|
20
|
-
if (
|
|
21
|
-
|
|
34
|
+
if (result) {
|
|
35
|
+
debug('exit code:', result.code);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (errors.length > 0) {
|
|
39
|
+
// We consider this a failure, regardless of exit code.
|
|
40
|
+
// In general, we expect errors to be accompanied by an error code of 1 (and vice versa),
|
|
41
|
+
// but we do not depend on that behaviour.
|
|
42
|
+
throw new Error('Error: ' + errors.join('\n'));
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (result?.code === 0) {
|
|
46
|
+
return result;
|
|
47
|
+
} else {
|
|
48
|
+
throw new Error(`Error code '${result?.code}' while running command`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
type RunCommandOpts = {
|
|
53
|
+
logPrefix?: string;
|
|
54
|
+
} & Readonly<Options & SpawnOptions>;
|
|
55
|
+
|
|
56
|
+
type MySpawnOpts = RunCommandOpts & { receivedLines?: string; logLine?: Function };
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Run a command and log the output. Ported from stack-versioned
|
|
60
|
+
*/
|
|
61
|
+
async function spawnPromise(
|
|
62
|
+
command: string,
|
|
63
|
+
commandArgs: string[],
|
|
64
|
+
options: MySpawnOpts = {},
|
|
65
|
+
context: { task_name: string }
|
|
66
|
+
) {
|
|
67
|
+
const debug = require('debug')(`${context.task_name} build`);
|
|
68
|
+
let logPrefix = options.logPrefix || '';
|
|
69
|
+
delete options.logPrefix;
|
|
70
|
+
if (logPrefix) {
|
|
71
|
+
logPrefix += ' ';
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const logLine = options.logLine;
|
|
75
|
+
delete options.receivedLines;
|
|
76
|
+
|
|
77
|
+
let logBuffer = '';
|
|
78
|
+
const log = (isStderr: boolean, data: any) => {
|
|
79
|
+
data = data.toString();
|
|
80
|
+
|
|
81
|
+
let trimmed = data.replace(/[\n|\r|\r\n]$/, '');
|
|
82
|
+
if (trimmed.length == data.length) {
|
|
83
|
+
logBuffer += trimmed;
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (logBuffer.length > 0) {
|
|
88
|
+
trimmed = logBuffer + trimmed;
|
|
89
|
+
logBuffer = '';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
trimmed.split('\n').forEach((line: string) => {
|
|
93
|
+
debug(`${logPrefix}${line}`);
|
|
94
|
+
if (logLine) {
|
|
95
|
+
logLine(isStderr, line, spawnPromise.childProcess);
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
debug(`${logPrefix}(${options.cwd || '.'}) \$ ${commandArgs.join(' ')}`);
|
|
101
|
+
let spawnPromise = spawn(command, commandArgs, options);
|
|
102
|
+
|
|
103
|
+
spawnPromise.childProcess.stdout!.on('data', log.bind(null, false));
|
|
104
|
+
spawnPromise.childProcess.stderr!.on('data', log.bind(null, true));
|
|
105
|
+
|
|
106
|
+
try {
|
|
107
|
+
return await spawnPromise;
|
|
108
|
+
} finally {
|
|
109
|
+
spawnPromise.childProcess.stdout!.removeAllListeners('data');
|
|
110
|
+
spawnPromise.childProcess.stderr!.removeAllListeners('data');
|
|
22
111
|
}
|
|
23
112
|
}
|