@netlify/build 29.7.2 → 29.8.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 CHANGED
@@ -89,7 +89,7 @@ const tExecBuild = async function ({ config, defaultConfig, cachedConfig, cached
89
89
  const pluginsOptions = addCorePlugins({ netlifyConfig, constants });
90
90
  // `errorParams` is purposely stateful
91
91
  Object.assign(errorParams, { netlifyConfig, pluginsOptions, siteInfo, childEnv, userNodeVersion });
92
- const { pluginsOptions: pluginsOptionsA, netlifyConfig: netlifyConfigA, stepsCount, timers: timersB, configMutations, } = await runAndReportBuild({
92
+ const { pluginsOptions: pluginsOptionsA, netlifyConfig: netlifyConfigA, stepsCount, timers: timersB, configMutations, metrics, } = await runAndReportBuild({
93
93
  pluginsOptions,
94
94
  netlifyConfig,
95
95
  configOpts,
@@ -135,13 +135,14 @@ const tExecBuild = async function ({ config, defaultConfig, cachedConfig, cached
135
135
  stepsCount,
136
136
  timers: timersB,
137
137
  configMutations,
138
+ metrics,
138
139
  };
139
140
  };
140
141
  export const execBuild = measureDuration(tExecBuild, 'total', { parentTag: 'build_site' });
141
142
  // Runs a build then report any plugin statuses
142
143
  export const runAndReportBuild = async function ({ pluginsOptions, netlifyConfig, configOpts, siteInfo, configPath, outputConfigPath, headersPath, redirectsPath, buildDir, repositoryRoot, nodePath, packageJson, userNodeVersion, childEnv, context, branch, buildbotServerSocket, constants, dry, mode, api, errorMonitor, deployId, errorParams, logs, debug, systemLog, verbose, timers, sendStatus, saveConfig, testOpts, featureFlags, timeline, devCommand, quiet, }) {
143
144
  try {
144
- const { stepsCount, netlifyConfig: netlifyConfigA, statuses, pluginsOptions: pluginsOptionsA, failedPlugins, timers: timersA, configMutations, } = await initAndRunBuild({
145
+ const { stepsCount, netlifyConfig: netlifyConfigA, statuses, pluginsOptions: pluginsOptionsA, failedPlugins, timers: timersA, configMutations, metrics, } = await initAndRunBuild({
145
146
  pluginsOptions,
146
147
  netlifyConfig,
147
148
  configOpts,
@@ -215,6 +216,7 @@ export const runAndReportBuild = async function ({ pluginsOptions, netlifyConfig
215
216
  stepsCount,
216
217
  timers: timersA,
217
218
  configMutations,
219
+ metrics,
218
220
  };
219
221
  }
220
222
  catch (error) {
@@ -267,7 +269,7 @@ const initAndRunBuild = async function ({ pluginsOptions, netlifyConfig, configO
267
269
  quiet,
268
270
  });
269
271
  try {
270
- const { stepsCount, netlifyConfig: netlifyConfigA, statuses, failedPlugins, timers: timersC, configMutations, } = await runBuild({
272
+ const { stepsCount, netlifyConfig: netlifyConfigA, statuses, failedPlugins, timers: timersC, configMutations, metrics, } = await runBuild({
271
273
  childProcesses,
272
274
  pluginsOptions: pluginsOptionsA,
273
275
  netlifyConfig,
@@ -315,6 +317,7 @@ const initAndRunBuild = async function ({ pluginsOptions, netlifyConfig, configO
315
317
  failedPlugins,
316
318
  timers: timersC,
317
319
  configMutations,
320
+ metrics,
318
321
  };
319
322
  }
320
323
  finally {
@@ -343,7 +346,7 @@ const runBuild = async function ({ childProcesses, pluginsOptions, netlifyConfig
343
346
  await doDryRun({ buildDir, steps, netlifyConfig, constants, buildbotServerSocket, logs });
344
347
  return { netlifyConfig };
345
348
  }
346
- const { stepsCount, netlifyConfig: netlifyConfigA, statuses, failedPlugins, timers: timersB, configMutations, } = await runSteps({
349
+ const { stepsCount, netlifyConfig: netlifyConfigA, statuses, failedPlugins, timers: timersB, configMutations, metrics, } = await runSteps({
347
350
  steps,
348
351
  buildbotServerSocket,
349
352
  events,
@@ -375,5 +378,13 @@ const runBuild = async function ({ childProcesses, pluginsOptions, netlifyConfig
375
378
  featureFlags,
376
379
  quiet,
377
380
  });
378
- return { stepsCount, netlifyConfig: netlifyConfigA, statuses, failedPlugins, timers: timersB, configMutations };
381
+ return {
382
+ stepsCount,
383
+ netlifyConfig: netlifyConfigA,
384
+ statuses,
385
+ failedPlugins,
386
+ timers: timersB,
387
+ configMutations,
388
+ metrics,
389
+ };
379
390
  };
package/lib/core/main.js CHANGED
@@ -5,6 +5,7 @@ import { logTimer, logBuildSuccess } from '../log/messages/core.js';
5
5
  import { trackBuildComplete } from '../telemetry/main.js';
6
6
  import { reportTimers } from '../time/report.js';
7
7
  import { execBuild, startBuild } from './build.js';
8
+ import { reportMetrics } from './report_metrics.js';
8
9
  import { getSeverity } from './severity.js';
9
10
  export { startDev } from './dev.js';
10
11
  export { runCoreSteps } from '../steps/run_core_steps.js';
@@ -19,7 +20,7 @@ export default async function buildSite(flags = {}) {
19
20
  const errorParams = { errorMonitor, mode, logs, debug, testOpts };
20
21
  const systemLog = getSystemLogger(logs, debug, systemLogFile);
21
22
  try {
22
- const { pluginsOptions, netlifyConfig: netlifyConfigA, siteInfo, userNodeVersion, stepsCount, timers, durationNs, configMutations, } = await execBuild({
23
+ const { pluginsOptions, netlifyConfig: netlifyConfigA, siteInfo, userNodeVersion, stepsCount, timers, durationNs, configMutations, metrics, } = await execBuild({
23
24
  ...flagsA,
24
25
  buildId,
25
26
  systemLogFile,
@@ -41,6 +42,7 @@ export default async function buildSite(flags = {}) {
41
42
  durationNs,
42
43
  statsdOpts,
43
44
  systemLog,
45
+ metrics,
44
46
  });
45
47
  const { success, severityCode, status } = getSeverity('success');
46
48
  await telemetryReport({
@@ -80,13 +82,14 @@ export default async function buildSite(flags = {}) {
80
82
  }
81
83
  }
82
84
  // Logs and reports that a build successfully ended
83
- const handleBuildSuccess = async function ({ framework, dry, logs, timers, durationNs, statsdOpts, systemLog }) {
85
+ const handleBuildSuccess = async function ({ framework, dry, logs, timers, durationNs, statsdOpts, systemLog, metrics, }) {
84
86
  if (dry) {
85
87
  return;
86
88
  }
87
89
  logBuildSuccess(logs);
88
90
  logTimer(logs, durationNs, 'Netlify Build', systemLog);
89
91
  await reportTimers(timers, statsdOpts, framework);
92
+ await reportMetrics(statsdOpts, metrics);
90
93
  };
91
94
  // Handles the calls and errors of telemetry reports
92
95
  const telemetryReport = async function ({ deployId, buildId, status, stepsCount, pluginsOptions, durationNs, siteInfo, telemetry, userNodeVersion, framework, testOpts, errorParams, }) {
@@ -0,0 +1,17 @@
1
+ import { closeClient, formatTags, startClient, validateStatsDOptions } from '../report/statsd.js';
2
+ /**
3
+ * Record number of functions build and differentiate between autogenerated and user generated.
4
+ * Sends to statsd daemon.
5
+ */
6
+ export const reportMetrics = async function (statsdOpts, metrics) {
7
+ if (!validateStatsDOptions(statsdOpts) || metrics.length === 0) {
8
+ return;
9
+ }
10
+ const client = await startClient(statsdOpts);
11
+ metrics.forEach((metric) => {
12
+ if (typeof client[metric.type] === 'function') {
13
+ client[metric.type](metric.name, metric.value, formatTags(metric.tags));
14
+ }
15
+ });
16
+ await closeClient(client);
17
+ };
@@ -43,14 +43,30 @@ const coreStep = async function ({ buildDir, constants: { EDGE_FUNCTIONS_DIST: d
43
43
  systemLogger: featureFlags.edge_functions_system_logger ? systemLog : undefined,
44
44
  internalSrcFolder: internalSrcPath,
45
45
  });
46
+ const metrics = getMetrics(manifest);
46
47
  systemLog('Edge Functions manifest:', manifest);
48
+ await validateEdgeFunctionsManifest(manifest, featureFlags);
49
+ return { metrics };
47
50
  }
48
51
  catch (error) {
49
52
  tagBundlingError(error);
50
53
  throw error;
51
54
  }
52
- await validateEdgeFunctionsManifest({ buildDir, constants: { EDGE_FUNCTIONS_DIST: distDirectory }, featureFlags });
53
- return {};
55
+ };
56
+ const getMetrics = (manifest) => {
57
+ const numGenEfs = Object.values(manifest.function_config).filter((config) => config.generator).length;
58
+ const allRoutes = [...manifest.routes, ...manifest.post_cache_routes];
59
+ const totalEfs = [];
60
+ allRoutes.forEach((route) => {
61
+ if (!totalEfs.some((func) => func === route.function)) {
62
+ totalEfs.push(route.function);
63
+ }
64
+ });
65
+ const numUserEfs = totalEfs.length - numGenEfs;
66
+ return [
67
+ { type: 'increment', name: 'buildbot.build.functions', value: numGenEfs, tags: { type: 'edge:generated' } },
68
+ { type: 'increment', name: 'buildbot.build.functions', value: numUserEfs, tags: { type: 'edge:user' } },
69
+ ];
54
70
  };
55
71
  // We run this core step if at least one of the functions directories (the
56
72
  // one configured by the user or the internal one) exists. We use a dynamic
@@ -1,15 +1,8 @@
1
- import { promises as fs } from 'fs';
2
- import { join, resolve } from 'path';
3
1
  import { ManifestValidationError, validateManifest } from '@netlify/edge-bundler';
4
2
  import { tagBundlingError } from '../lib/error.js';
5
- export const validateEdgeFunctionsManifest = async function ({ buildDir, constants: { EDGE_FUNCTIONS_DIST: distDirectory }, featureFlags, }) {
6
- const edgeFunctionsDistPath = resolve(buildDir, distDirectory);
7
- const manifestPath = join(edgeFunctionsDistPath, 'manifest.json');
8
- const data = await fs.readFile(manifestPath);
9
- // @ts-expect-error TypeScript is not aware that parse can handle Buffer
10
- const manifestData = JSON.parse(data);
3
+ export const validateEdgeFunctionsManifest = async function (manifest, featureFlags) {
11
4
  try {
12
- validateManifest(manifestData, featureFlags);
5
+ validateManifest(manifest, featureFlags);
13
6
  }
14
7
  catch (error) {
15
8
  if (error instanceof ManifestValidationError) {
@@ -6,7 +6,7 @@ export const fireCoreStep = async function ({ coreStep, coreStepId, coreStepName
6
6
  try {
7
7
  const configSideFiles = await listConfigSideFiles([headersPath, redirectsPath]);
8
8
  const childEnvA = setEnvChanges(envChanges, { ...childEnv });
9
- const { newEnvChanges = {}, configMutations: newConfigMutations = [], tags, } = await coreStep({
9
+ const { newEnvChanges = {}, configMutations: newConfigMutations = [], tags, metrics, } = await coreStep({
10
10
  configPath,
11
11
  outputConfigPath,
12
12
  buildDir,
@@ -47,6 +47,7 @@ export const fireCoreStep = async function ({ coreStep, coreStepId, coreStepName
47
47
  headersPath: headersPathA,
48
48
  redirectsPath: redirectsPathA,
49
49
  tags,
50
+ metrics,
50
51
  };
51
52
  }
52
53
  catch (newError) {
@@ -2,7 +2,7 @@ import { logTimer } from '../log/messages/core.js';
2
2
  import { logStepSuccess } from '../log/messages/steps.js';
3
3
  import { handleStepError } from './error.js';
4
4
  // Retrieve the return value of a step
5
- export const getStepReturn = function ({ event, packageName, newError, newEnvChanges, newStatus, coreStep, coreStepName: timerName = `${packageName} ${event}`, childEnv, mode, api, errorMonitor, deployId, netlifyConfig, configMutations, headersPath, redirectsPath, logs, debug, timers, durationNs, testOpts, systemLog, quiet, }) {
5
+ export const getStepReturn = function ({ event, packageName, newError, newEnvChanges, newStatus, coreStep, coreStepName: timerName = `${packageName} ${event}`, childEnv, mode, api, errorMonitor, deployId, netlifyConfig, configMutations, headersPath, redirectsPath, logs, debug, timers, durationNs, testOpts, systemLog, quiet, metrics, }) {
6
6
  if (newError !== undefined) {
7
7
  return handleStepError({
8
8
  event,
@@ -23,5 +23,5 @@ export const getStepReturn = function ({ event, packageName, newError, newEnvCha
23
23
  logStepSuccess(logs);
24
24
  logTimer(logs, durationNs, timerName, systemLog);
25
25
  }
26
- return { newEnvChanges, netlifyConfig, configMutations, headersPath, redirectsPath, newStatus, timers };
26
+ return { newEnvChanges, netlifyConfig, configMutations, headersPath, redirectsPath, newStatus, timers, metrics };
27
27
  };
@@ -27,7 +27,7 @@ export const runStep = async function ({ event, childProcess, packageName, coreS
27
27
  logStepStart({ logs, event, packageName, coreStepDescription, index, error, netlifyConfig });
28
28
  }
29
29
  const fireStep = getFireStep(packageName, coreStepId, event);
30
- const { newEnvChanges, netlifyConfig: netlifyConfigA = netlifyConfig, configMutations: configMutationsA = configMutations, headersPath: headersPathA = headersPath, redirectsPath: redirectsPathA = redirectsPath, newError, newStatus, timers: timersA, durationNs, } = await fireStep({
30
+ const { newEnvChanges, netlifyConfig: netlifyConfigA = netlifyConfig, configMutations: configMutationsA = configMutations, headersPath: headersPathA = headersPath, redirectsPath: redirectsPathA = redirectsPath, newError, newStatus, timers: timersA, durationNs, metrics, } = await fireStep({
31
31
  event,
32
32
  childProcess,
33
33
  packageName,
@@ -89,6 +89,7 @@ export const runStep = async function ({ event, childProcess, packageName, coreS
89
89
  testOpts,
90
90
  systemLog,
91
91
  quiet,
92
+ metrics,
92
93
  });
93
94
  return { ...newValues, newIndex: index + 1 };
94
95
  };
@@ -8,8 +8,8 @@ import { runStep } from './run_step.js';
8
8
  // If an error arises, runs `onError` events.
9
9
  // Runs `onEnd` events at the end, whether an error was thrown or not.
10
10
  export const runSteps = async function ({ steps, buildbotServerSocket, events, configPath, outputConfigPath, headersPath, redirectsPath, buildDir, repositoryRoot, nodePath, childEnv, context, branch, constants, mode, api, errorMonitor, deployId, errorParams, netlifyConfig, configOpts, logs, debug, systemLog, verbose, saveConfig, timers, testOpts, featureFlags, quiet, }) {
11
- const { index: stepsCount, error: errorA, netlifyConfig: netlifyConfigC, statuses: statusesB, failedPlugins: failedPluginsA, timers: timersC, configMutations: configMutationsB, } = await pReduce(steps, async ({ index, error, failedPlugins, envChanges, netlifyConfig: netlifyConfigA, configMutations, headersPath: headersPathA, redirectsPath: redirectsPathA, statuses, timers: timersA, }, { event, childProcess, packageName, coreStep, coreStepId, coreStepName, coreStepDescription, pluginPackageJson, loadedFrom, origin, condition, }) => {
12
- const { newIndex = index, newError = error, failedPlugin = [], newEnvChanges = {}, netlifyConfig: netlifyConfigB = netlifyConfigA, configMutations: configMutationsA = configMutations, headersPath: headersPathB = headersPathA, redirectsPath: redirectsPathB = redirectsPathA, newStatus, timers: timersB = timersA, } = await runStep({
11
+ const { index: stepsCount, error: errorA, netlifyConfig: netlifyConfigC, statuses: statusesB, failedPlugins: failedPluginsA, timers: timersC, configMutations: configMutationsB, metrics: metricsC, } = await pReduce(steps, async ({ index, error, failedPlugins, envChanges, netlifyConfig: netlifyConfigA, configMutations, headersPath: headersPathA, redirectsPath: redirectsPathA, statuses, timers: timersA, metrics: metricsA, }, { event, childProcess, packageName, coreStep, coreStepId, coreStepName, coreStepDescription, pluginPackageJson, loadedFrom, origin, condition, }) => {
12
+ const { newIndex = index, newError = error, failedPlugin = [], newEnvChanges = {}, netlifyConfig: netlifyConfigB = netlifyConfigA, configMutations: configMutationsA = configMutations, headersPath: headersPathB = headersPathA, redirectsPath: redirectsPathB = redirectsPathA, newStatus, timers: timersB = timersA, metrics: metricsB = metricsA, } = await runStep({
13
13
  event,
14
14
  childProcess,
15
15
  packageName,
@@ -69,6 +69,7 @@ export const runSteps = async function ({ steps, buildbotServerSocket, events, c
69
69
  redirectsPath: redirectsPathB,
70
70
  statuses: statusesA,
71
71
  timers: timersB,
72
+ metrics: metricsB,
72
73
  };
73
74
  }, {
74
75
  index: 0,
@@ -80,6 +81,7 @@ export const runSteps = async function ({ steps, buildbotServerSocket, events, c
80
81
  redirectsPath,
81
82
  statuses: [],
82
83
  timers,
84
+ metrics: [],
83
85
  });
84
86
  // Instead of throwing any build failure right away, we wait for `onError`,
85
87
  // etc. to complete. This is why we are throwing only now.
@@ -94,5 +96,6 @@ export const runSteps = async function ({ steps, buildbotServerSocket, events, c
94
96
  failedPlugins: failedPluginsA,
95
97
  timers: timersC,
96
98
  configMutations: configMutationsB,
99
+ metrics: metricsC,
97
100
  };
98
101
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/build",
3
- "version": "29.7.2",
3
+ "version": "29.8.0",
4
4
  "description": "Netlify build module",
5
5
  "type": "module",
6
6
  "exports": "./lib/core/main.js",
@@ -147,5 +147,5 @@
147
147
  "module": "commonjs"
148
148
  }
149
149
  },
150
- "gitHead": "7081ca94e87250bbcadbdf9a550b3d478b86c313"
150
+ "gitHead": "693a17e7e5eea9a519c9fba30beaecf1f6ac515d"
151
151
  }