@netlify/build 29.44.0 → 29.45.0
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/lib/core/build.js +1 -0
- package/lib/plugins/load.js +3 -16
- package/lib/plugins/spawn.js +26 -4
- package/lib/plugins/system_log.d.ts +4 -0
- package/lib/plugins/system_log.js +20 -0
- package/package.json +2 -2
package/lib/core/build.js
CHANGED
package/lib/plugins/load.js
CHANGED
|
@@ -3,6 +3,7 @@ import { addErrorInfo } from '../error/info.js';
|
|
|
3
3
|
import { addPluginLoadErrorStatus } from '../status/load_error.js';
|
|
4
4
|
import { measureDuration } from '../time/main.js';
|
|
5
5
|
import { callChild } from './ipc.js';
|
|
6
|
+
import { captureStandardError } from './system_log.js';
|
|
6
7
|
const pSetTimeout = promisify(setTimeout);
|
|
7
8
|
// Retrieve all plugins steps
|
|
8
9
|
// Can use either a module name or a file path to the plugin.
|
|
@@ -44,16 +45,7 @@ const loadAllPlugins = measureDuration(tLoadAllPlugins, 'load_plugins');
|
|
|
44
45
|
const loadPlugin = async function ({ packageName, pluginPackageJson, pluginPackageJson: { version } = {}, pluginPath, inputs, loadedFrom, origin }, { childProcesses, index, packageJson, logs, debug, verbose, netlifyConfig, featureFlags, systemLog }) {
|
|
45
46
|
const { childProcess } = childProcesses[index];
|
|
46
47
|
const loadEvent = 'load';
|
|
47
|
-
|
|
48
|
-
// this to system logs if we fail to load the plugin.
|
|
49
|
-
const bufferedStdErr = [];
|
|
50
|
-
let bufferedStdListener;
|
|
51
|
-
if (featureFlags.netlify_build_plugin_system_log && childProcess.stderr) {
|
|
52
|
-
bufferedStdListener = (data) => {
|
|
53
|
-
bufferedStdErr.push(data.toString().trimEnd());
|
|
54
|
-
};
|
|
55
|
-
childProcess.stderr.on('data', bufferedStdListener);
|
|
56
|
-
}
|
|
48
|
+
const cleanup = captureStandardError(childProcess, systemLog, loadEvent, featureFlags);
|
|
57
49
|
try {
|
|
58
50
|
const { events } = await callChild({
|
|
59
51
|
childProcess,
|
|
@@ -76,9 +68,6 @@ const loadPlugin = async function ({ packageName, pluginPackageJson, pluginPacka
|
|
|
76
68
|
if (featureFlags.netlify_build_plugin_system_log) {
|
|
77
69
|
// Wait for stderr to be flushed.
|
|
78
70
|
await pSetTimeout(0);
|
|
79
|
-
bufferedStdErr.forEach((line) => {
|
|
80
|
-
systemLog(line);
|
|
81
|
-
});
|
|
82
71
|
}
|
|
83
72
|
addErrorInfo(error, {
|
|
84
73
|
plugin: { packageName, pluginPackageJson },
|
|
@@ -88,8 +77,6 @@ const loadPlugin = async function ({ packageName, pluginPackageJson, pluginPacka
|
|
|
88
77
|
throw error;
|
|
89
78
|
}
|
|
90
79
|
finally {
|
|
91
|
-
|
|
92
|
-
childProcess.stderr.removeListener('data', bufferedStdListener);
|
|
93
|
-
}
|
|
80
|
+
cleanup();
|
|
94
81
|
}
|
|
95
82
|
};
|
package/lib/plugins/spawn.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createRequire } from 'module';
|
|
2
2
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
3
|
+
import { promisify } from 'util';
|
|
3
4
|
import { trace } from '@opentelemetry/api';
|
|
4
5
|
import { execaNode } from 'execa';
|
|
5
6
|
import { gte } from 'semver';
|
|
@@ -9,7 +10,9 @@ import { isTrustedPlugin } from '../steps/plugin.js';
|
|
|
9
10
|
import { measureDuration } from '../time/main.js';
|
|
10
11
|
import { callChild, getEventFromChild } from './ipc.js';
|
|
11
12
|
import { getSpawnInfo } from './options.js';
|
|
13
|
+
import { captureStandardError } from './system_log.js';
|
|
12
14
|
const CHILD_MAIN_FILE = fileURLToPath(new URL('child/main.js', import.meta.url));
|
|
15
|
+
const pSetTimeout = promisify(setTimeout);
|
|
13
16
|
const require = createRequire(import.meta.url);
|
|
14
17
|
// Start child processes used by all plugins
|
|
15
18
|
// We fire plugins through child processes so that:
|
|
@@ -17,7 +20,7 @@ const require = createRequire(import.meta.url);
|
|
|
17
20
|
// (for both security and safety reasons)
|
|
18
21
|
// - logs can be buffered which allows manipulating them for log shipping,
|
|
19
22
|
// transforming and parallel plugins
|
|
20
|
-
const tStartPlugins = async function ({ pluginsOptions, buildDir, childEnv, logs, debug, quiet, systemLogFile }) {
|
|
23
|
+
const tStartPlugins = async function ({ pluginsOptions, buildDir, childEnv, logs, debug, quiet, systemLog, systemLogFile, featureFlags, }) {
|
|
21
24
|
if (!quiet) {
|
|
22
25
|
logRuntime(logs, pluginsOptions);
|
|
23
26
|
logLoadingPlugins(logs, pluginsOptions, debug);
|
|
@@ -25,11 +28,21 @@ const tStartPlugins = async function ({ pluginsOptions, buildDir, childEnv, logs
|
|
|
25
28
|
}
|
|
26
29
|
logOutdatedPlugins(logs, pluginsOptions);
|
|
27
30
|
logIncompatiblePlugins(logs, pluginsOptions);
|
|
28
|
-
const childProcesses = await Promise.all(pluginsOptions.map(({ pluginDir, nodePath, nodeVersion, pluginPackageJson }) => startPlugin({
|
|
31
|
+
const childProcesses = await Promise.all(pluginsOptions.map(({ pluginDir, nodePath, nodeVersion, pluginPackageJson }) => startPlugin({
|
|
32
|
+
pluginDir,
|
|
33
|
+
nodePath,
|
|
34
|
+
nodeVersion,
|
|
35
|
+
buildDir,
|
|
36
|
+
childEnv,
|
|
37
|
+
systemLog,
|
|
38
|
+
systemLogFile,
|
|
39
|
+
pluginPackageJson,
|
|
40
|
+
featureFlags,
|
|
41
|
+
})));
|
|
29
42
|
return { childProcesses };
|
|
30
43
|
};
|
|
31
44
|
export const startPlugins = measureDuration(tStartPlugins, 'start_plugins');
|
|
32
|
-
const startPlugin = async function ({ pluginDir, nodeVersion, nodePath, buildDir, childEnv, systemLogFile, pluginPackageJson, }) {
|
|
45
|
+
const startPlugin = async function ({ pluginDir, nodeVersion, nodePath, buildDir, childEnv, systemLog, systemLogFile, pluginPackageJson, featureFlags, }) {
|
|
33
46
|
const ctx = trace.getActiveSpan()?.spanContext();
|
|
34
47
|
// the baggage will be passed to the child process when sending the run event
|
|
35
48
|
const args = [
|
|
@@ -71,15 +84,24 @@ const startPlugin = async function ({ pluginDir, nodeVersion, nodePath, buildDir
|
|
|
71
84
|
? ['pipe', 'pipe', 'pipe', 'ipc', systemLogFile]
|
|
72
85
|
: undefined,
|
|
73
86
|
});
|
|
87
|
+
const readyEvent = 'ready';
|
|
88
|
+
const cleanup = captureStandardError(childProcess, systemLog, readyEvent, featureFlags);
|
|
74
89
|
try {
|
|
75
|
-
await getEventFromChild(childProcess,
|
|
90
|
+
await getEventFromChild(childProcess, readyEvent);
|
|
76
91
|
return { childProcess };
|
|
77
92
|
}
|
|
78
93
|
catch (error) {
|
|
94
|
+
if (featureFlags.netlify_build_plugin_system_log) {
|
|
95
|
+
// Wait for stderr to be flushed.
|
|
96
|
+
await pSetTimeout(0);
|
|
97
|
+
}
|
|
79
98
|
const spawnInfo = getSpawnInfo();
|
|
80
99
|
addErrorInfo(error, spawnInfo);
|
|
81
100
|
throw error;
|
|
82
101
|
}
|
|
102
|
+
finally {
|
|
103
|
+
cleanup();
|
|
104
|
+
}
|
|
83
105
|
};
|
|
84
106
|
// Stop all plugins child processes
|
|
85
107
|
export const stopPlugins = async function ({ childProcesses, logs, verbose, pluginOptions, netlifyConfig, }) {
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { FeatureFlags } from '../core/feature_flags.js';
|
|
2
|
+
import type { SystemLogger } from '../plugins_core/types.js';
|
|
3
|
+
import type { ChildProcess } from './spawn.js';
|
|
4
|
+
export declare const captureStandardError: (childProcess: ChildProcess, systemLog: SystemLogger, eventName: string, featureFlags: FeatureFlags) => () => void;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export const captureStandardError = (childProcess, systemLog, eventName, featureFlags) => {
|
|
2
|
+
if (!featureFlags.netlify_build_plugin_system_log) {
|
|
3
|
+
return () => {
|
|
4
|
+
// no-op
|
|
5
|
+
};
|
|
6
|
+
}
|
|
7
|
+
let receivedChunks = false;
|
|
8
|
+
const listener = (chunk) => {
|
|
9
|
+
if (!receivedChunks) {
|
|
10
|
+
receivedChunks = true;
|
|
11
|
+
systemLog(`Plugin failed to initialize during the "${eventName}" phase`);
|
|
12
|
+
}
|
|
13
|
+
systemLog(chunk.toString().trimEnd());
|
|
14
|
+
};
|
|
15
|
+
childProcess.stderr?.on('data', listener);
|
|
16
|
+
const cleanup = () => {
|
|
17
|
+
childProcess.stderr?.removeListener('data', listener);
|
|
18
|
+
};
|
|
19
|
+
return cleanup;
|
|
20
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/build",
|
|
3
|
-
"version": "29.
|
|
3
|
+
"version": "29.45.0",
|
|
4
4
|
"description": "Netlify build module",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": "./lib/index.js",
|
|
@@ -165,5 +165,5 @@
|
|
|
165
165
|
"engines": {
|
|
166
166
|
"node": "^14.16.0 || >=16.0.0"
|
|
167
167
|
},
|
|
168
|
-
"gitHead": "
|
|
168
|
+
"gitHead": "492b2e3de82bc00b0427eac5a12f847bb72404fa"
|
|
169
169
|
}
|