@netlify/build 29.4.89-test → 29.5.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 +12 -1
- package/lib/core/main.js +3 -2
- package/lib/error/report.js +14 -12
- package/lib/plugins_core/functions/index.js +5 -3
- package/lib/plugins_core/functions/zisi.js +10 -1
- package/lib/report/statsd.js +34 -4
- package/lib/time/report.js +18 -15
- package/package.json +6 -5
package/lib/core/build.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { supportedRuntimes } from '@netlify/framework-info';
|
|
1
2
|
import { getErrorInfo } from '../error/info.js';
|
|
2
3
|
import { startErrorMonitor } from '../error/monitor/start.js';
|
|
3
4
|
import { getBufferLogs, getSystemLogger } from '../log/logger.js';
|
|
@@ -30,7 +31,7 @@ export const startBuild = function (flags) {
|
|
|
30
31
|
const errorMonitor = startErrorMonitor({ flags: flagsA, logs, bugsnagKey });
|
|
31
32
|
return { ...flagsA, errorMonitor, logs, timers };
|
|
32
33
|
};
|
|
33
|
-
const tExecBuild = async function ({ config, defaultConfig, cachedConfig, cachedConfigPath, outputConfigPath, cwd, repositoryRoot, apiHost, token, siteId, context, branch, baseRelDir, env: envOpt, debug, systemLogFile, verbose, nodePath, functionsDistDir, edgeFunctionsDistDir, cacheDir, dry, mode, offline, deployId, buildId, testOpts, errorMonitor, errorParams, logs, timers, buildbotServerSocket, sendStatus, saveConfig, featureFlags, timeline, devCommand, quiet, }) {
|
|
34
|
+
const tExecBuild = async function ({ config, defaultConfig, cachedConfig, cachedConfigPath, outputConfigPath, cwd, repositoryRoot, apiHost, token, siteId, context, branch, baseRelDir, env: envOpt, debug, systemLogFile, verbose, nodePath, functionsDistDir, edgeFunctionsDistDir, cacheDir, dry, mode, offline, deployId, buildId, testOpts, errorMonitor, errorParams, logs, timers, buildbotServerSocket, sendStatus, saveConfig, featureFlags, timeline, devCommand, quiet, framework, }) {
|
|
34
35
|
const configOpts = getConfigOpts({
|
|
35
36
|
config,
|
|
36
37
|
defaultConfig,
|
|
@@ -61,6 +62,16 @@ const tExecBuild = async function ({ config, defaultConfig, cachedConfig, cached
|
|
|
61
62
|
timers,
|
|
62
63
|
quiet,
|
|
63
64
|
});
|
|
65
|
+
if (featureFlags.build_automatic_runtime && framework) {
|
|
66
|
+
const runtime = supportedRuntimes[framework];
|
|
67
|
+
if (runtime !== undefined) {
|
|
68
|
+
const skip = childEnv[runtime.skipFlag] === 'true';
|
|
69
|
+
const installed = netlifyConfig.plugins.some((plugin) => plugin.package === runtime.package);
|
|
70
|
+
if (!installed && !skip) {
|
|
71
|
+
netlifyConfig.plugins.push({ package: runtime.package });
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
64
75
|
const constants = await getConstants({
|
|
65
76
|
configPath,
|
|
66
77
|
buildDir,
|
package/lib/core/main.js
CHANGED
|
@@ -31,6 +31,7 @@ export default async function buildSite(flags = {}) {
|
|
|
31
31
|
debug,
|
|
32
32
|
testOpts,
|
|
33
33
|
errorParams,
|
|
34
|
+
framework,
|
|
34
35
|
});
|
|
35
36
|
await handleBuildSuccess({
|
|
36
37
|
framework,
|
|
@@ -74,7 +75,7 @@ export default async function buildSite(flags = {}) {
|
|
|
74
75
|
testOpts,
|
|
75
76
|
errorParams,
|
|
76
77
|
});
|
|
77
|
-
await reportError(
|
|
78
|
+
await reportError(error, statsdOpts, framework);
|
|
78
79
|
return { success, severityCode, logs };
|
|
79
80
|
}
|
|
80
81
|
}
|
|
@@ -85,7 +86,7 @@ const handleBuildSuccess = async function ({ framework, dry, logs, timers, durat
|
|
|
85
86
|
}
|
|
86
87
|
logBuildSuccess(logs);
|
|
87
88
|
logTimer(logs, durationNs, 'Netlify Build', systemLog);
|
|
88
|
-
await reportTimers(
|
|
89
|
+
await reportTimers(timers, statsdOpts, framework);
|
|
89
90
|
};
|
|
90
91
|
// Handles the calls and errors of telemetry reports
|
|
91
92
|
const telemetryReport = async function ({ deployId, buildId, status, stepsCount, pluginsOptions, durationNs, siteInfo, telemetry, userNodeVersion, framework, testOpts, errorParams, }) {
|
package/lib/error/report.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { isNetlifyMaintainedPlugin } from '../plugins/internal.js';
|
|
2
|
-
import { closeClient, normalizeTagName, startClient } from '../report/statsd.js';
|
|
2
|
+
import { closeClient, formatTags, normalizeTagName, startClient, validateStatsDOptions, } from '../report/statsd.js';
|
|
3
3
|
import { getErrorInfo } from './info.js';
|
|
4
4
|
const TOP_PARENT_TAG = 'run_netlify_build';
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Record error rates of the build phase for monitoring.
|
|
7
|
+
* Sends to statsd daemon.
|
|
8
|
+
*/
|
|
9
|
+
export const reportError = async function (error, statsdOpts, framework) {
|
|
10
|
+
if (!validateStatsDOptions(statsdOpts)) {
|
|
9
11
|
return;
|
|
10
12
|
}
|
|
11
13
|
const [errorInfo] = getErrorInfo(error);
|
|
@@ -16,12 +18,12 @@ export const reportError = async function ({ error, statsdOpts: { host, port },
|
|
|
16
18
|
}
|
|
17
19
|
const parent = pluginName ? pluginName : TOP_PARENT_TAG;
|
|
18
20
|
const stage = pluginName ? errorInfo.location?.event : errorInfo.stage;
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
const statsDTags = { stage: stage ?? 'system', parent };
|
|
22
|
+
// Do not add a framework tag if empty string or null/undefined
|
|
23
|
+
if (framework) {
|
|
24
|
+
statsDTags.framework = framework;
|
|
25
|
+
}
|
|
26
|
+
const client = await startClient(statsdOpts);
|
|
27
|
+
client.increment('buildbot.build.stage.error', 1, formatTags(statsDTags));
|
|
26
28
|
await closeClient(client);
|
|
27
29
|
};
|
|
@@ -7,9 +7,11 @@ import { getZipError } from './error.js';
|
|
|
7
7
|
import { getUserAndInternalFunctions, validateFunctionsSrc } from './utils.js';
|
|
8
8
|
import { getZisiParameters } from './zisi.js';
|
|
9
9
|
// Get a list of all unique bundlers in this run
|
|
10
|
-
const getBundlers = (results = []) =>
|
|
10
|
+
const getBundlers = (results = []) =>
|
|
11
|
+
// using a Set to filter duplicates
|
|
12
|
+
new Set(results
|
|
11
13
|
.map((bundle) => (bundle.runtime === "js" /* RuntimeType.JAVASCRIPT */ ? bundle.bundler : null))
|
|
12
|
-
.filter(Boolean))
|
|
14
|
+
.filter(Boolean));
|
|
13
15
|
const zipFunctionsAndLogResults = async ({ buildDir, childEnv, featureFlags, functionsConfig, functionsDist, functionsSrc, internalFunctionsSrc, isRunningLocally, logs, repositoryRoot, }) => {
|
|
14
16
|
const zisiParameters = getZisiParameters({
|
|
15
17
|
buildDir,
|
|
@@ -26,7 +28,7 @@ const zipFunctionsAndLogResults = async ({ buildDir, childEnv, featureFlags, fun
|
|
|
26
28
|
log(logs, '');
|
|
27
29
|
const sourceDirectories = [internalFunctionsSrc, functionsSrc].filter(Boolean);
|
|
28
30
|
const results = await zipItAndShipIt.zipFunctions(sourceDirectories, functionsDist, zisiParameters);
|
|
29
|
-
const bundlers = getBundlers(results);
|
|
31
|
+
const bundlers = Array.from(getBundlers(results));
|
|
30
32
|
logBundleResults({ logs, results });
|
|
31
33
|
return { bundlers };
|
|
32
34
|
}
|
|
@@ -11,7 +11,15 @@ export const getZisiParameters = ({ buildDir, childEnv, featureFlags, functionsC
|
|
|
11
11
|
const zisiFeatureFlags = getZisiFeatureFlags(featureFlags);
|
|
12
12
|
// Only internal functions are allowed to have a json config file
|
|
13
13
|
const configFileDirectories = [resolve(internalFunctionsSrc)];
|
|
14
|
-
return {
|
|
14
|
+
return {
|
|
15
|
+
basePath: buildDir,
|
|
16
|
+
config,
|
|
17
|
+
manifest,
|
|
18
|
+
featureFlags: zisiFeatureFlags,
|
|
19
|
+
repositoryRoot,
|
|
20
|
+
configFileDirectories,
|
|
21
|
+
internalSrcFolder: internalFunctionsSrc,
|
|
22
|
+
};
|
|
15
23
|
};
|
|
16
24
|
// The function configuration keys returned by @netlify/config are not an exact
|
|
17
25
|
// match to the properties that @netlify/zip-it-and-ship-it expects. We do that
|
|
@@ -19,6 +27,7 @@ export const getZisiParameters = ({ buildDir, childEnv, featureFlags, functionsC
|
|
|
19
27
|
export const normalizeFunctionConfig = ({ buildDir, functionConfig = {}, isRunningLocally, nodeVersion }) => ({
|
|
20
28
|
externalNodeModules: functionConfig.external_node_modules,
|
|
21
29
|
includedFiles: functionConfig.included_files,
|
|
30
|
+
name: functionConfig.name,
|
|
22
31
|
includedFilesBasePath: buildDir,
|
|
23
32
|
ignoredNodeModules: functionConfig.ignored_node_modules,
|
|
24
33
|
nodeVersion,
|
package/lib/report/statsd.js
CHANGED
|
@@ -1,17 +1,47 @@
|
|
|
1
1
|
import { promisify } from 'util';
|
|
2
2
|
import slugify from '@sindresorhus/slugify';
|
|
3
3
|
import { StatsD } from 'hot-shots';
|
|
4
|
-
export const
|
|
5
|
-
return
|
|
4
|
+
export const validateStatsDOptions = function (statsdOpts) {
|
|
5
|
+
return !!(statsdOpts && statsdOpts.host && statsdOpts.port);
|
|
6
6
|
};
|
|
7
|
+
/**
|
|
8
|
+
* Start a new StatsD Client and a new UDP socket
|
|
9
|
+
*/
|
|
10
|
+
export const startClient = async function (statsdOpts) {
|
|
11
|
+
const { host, port } = statsdOpts;
|
|
12
|
+
return new StatsD({
|
|
13
|
+
host,
|
|
14
|
+
port,
|
|
15
|
+
// This caches the dns resolution for subsequent sends of metrics for this instance
|
|
16
|
+
// Because we only try to send the metrics on close, this comes only into effect if `bufferFlushInterval` time is exceeded
|
|
17
|
+
cacheDns: true,
|
|
18
|
+
// set the maxBufferSize to infinite and the bufferFlushInterval very high, so that we only
|
|
19
|
+
// send the metrics on close or if more than 10 seconds past by
|
|
20
|
+
maxBufferSize: Infinity,
|
|
21
|
+
bufferFlushInterval: 10_000,
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* Close the StatsD Client
|
|
26
|
+
*
|
|
27
|
+
* UDP packets are buffered and flushed every 10 seconds and
|
|
28
|
+
* closing the client forces all buffered metrics to be flushed.
|
|
29
|
+
*/
|
|
7
30
|
export const closeClient = async function (client) {
|
|
8
31
|
await promisify(client.close.bind(client))();
|
|
9
32
|
};
|
|
10
|
-
|
|
11
|
-
|
|
33
|
+
/**
|
|
34
|
+
* Make sure the timer name does not include special characters.
|
|
35
|
+
* For example, the `packageName` of local plugins includes dots.
|
|
36
|
+
*/
|
|
12
37
|
export const normalizeTagName = function (name) {
|
|
13
38
|
return slugify(name, { separator: '_' });
|
|
14
39
|
};
|
|
40
|
+
/**
|
|
41
|
+
* Formats and flattens the tags as array
|
|
42
|
+
* We do this because we might send the same tag with different values `{ tag: ['a', 'b'] }`
|
|
43
|
+
* which cannot be represented in an flattened object and `hot-shots` also supports tags as array in the format `['tag:a', 'tag:b']`
|
|
44
|
+
*/
|
|
15
45
|
export const formatTags = function (tags) {
|
|
16
46
|
return Object.entries(tags)
|
|
17
47
|
.map(([key, value]) => {
|
package/lib/time/report.js
CHANGED
|
@@ -1,27 +1,30 @@
|
|
|
1
|
-
import { closeClient, formatTags, startClient } from '../report/statsd.js';
|
|
1
|
+
import { closeClient, formatTags, startClient, validateStatsDOptions, } from '../report/statsd.js';
|
|
2
2
|
import { addAggregatedTimers } from './aggregate.js';
|
|
3
3
|
import { roundTimerToMillisecs } from './measure.js';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Record the duration of a build phase, for monitoring.
|
|
6
|
+
* Sends to statsd daemon.
|
|
7
|
+
*/
|
|
8
|
+
export const reportTimers = async function (timers, statsdOpts, framework) {
|
|
9
|
+
if (!validateStatsDOptions(statsdOpts)) {
|
|
8
10
|
return;
|
|
9
11
|
}
|
|
10
|
-
|
|
11
|
-
await sendTimers({ timers: timersA, statsdOpts: { host, port }, framework });
|
|
12
|
+
await sendTimers(addAggregatedTimers(timers), statsdOpts, framework);
|
|
12
13
|
};
|
|
13
|
-
const sendTimers = async function (
|
|
14
|
-
const client = await startClient(
|
|
14
|
+
const sendTimers = async function (timers, statsdOpts, framework) {
|
|
15
|
+
const client = await startClient(statsdOpts);
|
|
15
16
|
timers.forEach((timer) => {
|
|
16
|
-
sendTimer(
|
|
17
|
+
sendTimer(timer, client, framework);
|
|
17
18
|
});
|
|
18
19
|
await closeClient(client);
|
|
19
20
|
};
|
|
20
|
-
const sendTimer = function (
|
|
21
|
+
const sendTimer = function (timer, client, framework) {
|
|
22
|
+
const { metricName, stageTag, parentTag, durationNs, tags } = timer;
|
|
21
23
|
const durationMs = roundTimerToMillisecs(durationNs);
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
const statsDTags = { stage: stageTag, parent: parentTag, ...tags };
|
|
25
|
+
// Do not add a framework tag if empty string or null/undefined
|
|
26
|
+
if (framework) {
|
|
27
|
+
statsDTags.framework = framework;
|
|
25
28
|
}
|
|
26
|
-
client.distribution(metricName, durationMs, formatTags(
|
|
29
|
+
client.distribution(metricName, durationMs, formatTags(statsDTags));
|
|
27
30
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/build",
|
|
3
|
-
"version": "29.
|
|
3
|
+
"version": "29.5.0",
|
|
4
4
|
"description": "Netlify build module",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": "./lib/core/main.js",
|
|
@@ -66,12 +66,12 @@
|
|
|
66
66
|
"@bugsnag/js": "^7.0.0",
|
|
67
67
|
"@netlify/cache-utils": "^5.1.0",
|
|
68
68
|
"@netlify/config": "^20.3.0",
|
|
69
|
-
"@netlify/edge-bundler": "8.
|
|
70
|
-
"@netlify/functions-utils": "^5.1.
|
|
69
|
+
"@netlify/edge-bundler": "8.1.2",
|
|
70
|
+
"@netlify/functions-utils": "^5.1.4",
|
|
71
71
|
"@netlify/git-utils": "^5.1.0",
|
|
72
72
|
"@netlify/plugins-list": "^6.61.0",
|
|
73
73
|
"@netlify/run-utils": "^5.1.0",
|
|
74
|
-
"@netlify/zip-it-and-ship-it": "^8.
|
|
74
|
+
"@netlify/zip-it-and-ship-it": "^8.4.0",
|
|
75
75
|
"@sindresorhus/slugify": "^2.0.0",
|
|
76
76
|
"ansi-escapes": "^5.0.0",
|
|
77
77
|
"chalk": "^5.0.0",
|
|
@@ -147,5 +147,6 @@
|
|
|
147
147
|
"compilerOptions": {
|
|
148
148
|
"module": "commonjs"
|
|
149
149
|
}
|
|
150
|
-
}
|
|
150
|
+
},
|
|
151
|
+
"gitHead": "fb15bd56d47418bc03b2e94fc87de89d3e18a7a9"
|
|
151
152
|
}
|