@netlify/build 29.23.5 → 29.24.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.
@@ -209,6 +209,11 @@ export const FLAGS: {
209
209
  describe: string;
210
210
  hidden: boolean;
211
211
  };
212
+ 'tracing.baggageFilePath': {
213
+ string: boolean;
214
+ describe: string;
215
+ hidden: boolean;
216
+ };
212
217
  offline: {
213
218
  boolean: boolean;
214
219
  describe: string;
package/lib/core/flags.js CHANGED
@@ -242,6 +242,11 @@ Default: false`,
242
242
  describe: 'Trace flags containing the trace settings for the given trace ID',
243
243
  hidden: true,
244
244
  },
245
+ 'tracing.baggageFilePath': {
246
+ string: true,
247
+ describe: '',
248
+ hidden: true,
249
+ },
245
250
  offline: {
246
251
  boolean: true,
247
252
  describe: `Do not send requests to the Netlify API to retrieve site settings.
@@ -63,6 +63,7 @@ const getDefaultFlags = function ({ env: envOpt = {} }, combinedEnv) {
63
63
  sampleRate: 1,
64
64
  httpProtocol: DEFAULT_OTEL_ENDPOINT_PROTOCOL,
65
65
  port: DEFAULT_OTEL_TRACING_PORT,
66
+ baggageFilePath: '',
66
67
  },
67
68
  timeline: 'build',
68
69
  quiet: false,
@@ -80,4 +80,5 @@ export type TracingOptions = {
80
80
  traceId: string;
81
81
  traceFlags: number;
82
82
  parentSpanId: string;
83
+ baggageFilePath: string;
83
84
  };
@@ -1,6 +1,7 @@
1
1
  import { resolve } from 'path';
2
2
  import { RUNTIME, zipFunctions } from '@netlify/zip-it-and-ship-it';
3
3
  import { pathExists } from 'path-exists';
4
+ import { addErrorInfo } from '../../error/info.js';
4
5
  import { log } from '../../log/logger.js';
5
6
  import { logBundleResults, logFunctionsNonExistingDir, logFunctionsToBundle } from '../../log/messages/core_steps.js';
6
7
  import { getZipError } from './error.js';
@@ -12,6 +13,38 @@ const getBundlers = (results = []) =>
12
13
  new Set(results
13
14
  .map((bundle) => (bundle.runtime === RUNTIME.JAVASCRIPT ? bundle.bundler : null))
14
15
  .filter(Boolean));
16
+ // see https://docs.netlify.com/functions/trigger-on-events/#available-triggers
17
+ const eventTriggeredFunctions = new Set([
18
+ 'deploy-building',
19
+ 'deploy-succeeded',
20
+ 'deploy-failed',
21
+ 'deploy-deleted',
22
+ 'deploy-locked',
23
+ 'deploy-unlocked',
24
+ 'submission-created',
25
+ 'split-test-activated',
26
+ 'split-test-deactivated',
27
+ 'split-test-modified',
28
+ 'identity-validate',
29
+ 'identity-signup',
30
+ 'identity-login',
31
+ ]);
32
+ const validateCustomRoutes = function (functions) {
33
+ for (const { routes, name, schedule } of functions) {
34
+ if (!routes || routes.length === 0)
35
+ continue;
36
+ if (schedule) {
37
+ const error = new Error(`Scheduled functions must not specify a custom path. Please remove the "path" configuration. Learn more about scheduled functions at https://ntl.fyi/custom-path-scheduled-functions.`);
38
+ addErrorInfo(error, { type: 'resolveConfig' });
39
+ throw error;
40
+ }
41
+ if (eventTriggeredFunctions.has(name.toLowerCase().replace('-background', ''))) {
42
+ const error = new Error(`Event-triggered functions must not specify a custom path. Please remove the "path" configuration or pick a different name for the function. Learn more about event-triggered functions at https://ntl.fyi/custom-path-event-triggered-functions.`);
43
+ addErrorInfo(error, { type: 'resolveConfig' });
44
+ throw error;
45
+ }
46
+ }
47
+ };
15
48
  const zipFunctionsAndLogResults = async ({ buildDir, childEnv, featureFlags, functionsConfig, functionsDist, functionsSrc, internalFunctionsSrc, isRunningLocally, logs, repositoryRoot, userNodeVersion, systemLog, }) => {
16
49
  const zisiParameters = getZisiParameters({
17
50
  buildDir,
@@ -30,6 +63,7 @@ const zipFunctionsAndLogResults = async ({ buildDir, childEnv, featureFlags, fun
30
63
  log(logs, '');
31
64
  const sourceDirectories = [internalFunctionsSrc, functionsSrc].filter(Boolean);
32
65
  const results = await zipItAndShipIt.zipFunctions(sourceDirectories, functionsDist, zisiParameters);
66
+ validateCustomRoutes(results);
33
67
  const bundlers = Array.from(getBundlers(results));
34
68
  logBundleResults({ logs, results });
35
69
  return { bundlers };
@@ -3,12 +3,13 @@ import type { TracingOptions } from '../core/types.js';
3
3
  export declare const startTracing: (options: TracingOptions, logger: (...args: any[]) => void) => import("@opentelemetry/api").Context | undefined;
4
4
  /** Stops the tracing service if there's one running. This will flush any ongoing events */
5
5
  export declare const stopTracing: () => Promise<void>;
6
- /** Sets attributes to be propagated across child spans under the current context */
6
+ /** Sets attributes to be propagated across child spans under the current active context */
7
7
  export declare const setMultiSpanAttributes: (attributes: {
8
8
  [key: string]: string;
9
9
  }) => import("@opentelemetry/api").Context;
10
10
  /** Add error information to the current active span (if any) */
11
11
  export declare const addErrorToActiveSpan: (error: Error) => void;
12
+ export declare const loadBaggageFromFile: (baggageFilePath: string) => import("@opentelemetry/api").Context;
12
13
  /** Attributes used for the root span of our execution */
13
14
  export type RootExecutionAttributes = {
14
15
  'build.id': string;
@@ -1,5 +1,7 @@
1
+ import { readFileSync } from 'node:fs';
1
2
  import { HoneycombSDK } from '@honeycombio/opentelemetry-node';
2
3
  import { context, trace, propagation, SpanStatusCode, diag, DiagLogLevel } from '@opentelemetry/api';
4
+ import { parseKeyPairsIntoRecord } from '@opentelemetry/core/build/src/baggage/utils.js';
3
5
  import { ROOT_PACKAGE_JSON } from '../utils/json.js';
4
6
  let sdk;
5
7
  /** Given a simple logging function return a `DiagLogger`. Used to setup our system logger as the diag logger.*/
@@ -36,14 +38,17 @@ export const startTracing = function (options, logger) {
36
38
  // in case there's a default console logger already registered (it would log a msg to it)
37
39
  diag.setLogger(getOtelLogger(logger), { logLevel: DiagLogLevel.INFO, suppressOverrideMessage: true });
38
40
  sdk.start();
41
+ // Loads the contents of the passed baggageFilePath into the baggage
42
+ const baggageCtx = loadBaggageFromFile(options.baggageFilePath);
39
43
  // Sets the current trace ID and span ID based on the options received
40
44
  // this is used as a way to propagate trace context from Buildbot
41
- return trace.setSpanContext(context.active(), {
45
+ const ctx = trace.setSpanContext(baggageCtx, {
42
46
  traceId: options.traceId,
43
47
  spanId: options.parentSpanId,
44
48
  traceFlags: options.traceFlags,
45
49
  isRemote: true,
46
50
  });
51
+ return ctx;
47
52
  };
48
53
  /** Stops the tracing service if there's one running. This will flush any ongoing events */
49
54
  export const stopTracing = async function () {
@@ -59,12 +64,13 @@ export const stopTracing = async function () {
59
64
  diag.error(e);
60
65
  }
61
66
  };
62
- /** Sets attributes to be propagated across child spans under the current context */
67
+ /** Sets attributes to be propagated across child spans under the current active context */
63
68
  export const setMultiSpanAttributes = function (attributes) {
64
69
  const currentBaggage = propagation.getBaggage(context.active());
70
+ // Create a baggage if there's none
65
71
  let baggage = currentBaggage === undefined ? propagation.createBaggage() : currentBaggage;
66
- Object.entries(attributes).forEach((entry) => {
67
- baggage = baggage.setEntry(entry[0], { value: entry[1] });
72
+ Object.entries(attributes).forEach(([key, value]) => {
73
+ baggage = baggage.setEntry(key, { value });
68
74
  });
69
75
  return propagation.setBaggage(context.active(), baggage);
70
76
  };
@@ -79,3 +85,20 @@ export const addErrorToActiveSpan = function (error) {
79
85
  message: error.message,
80
86
  });
81
87
  };
88
+ //** Loads the baggage attributes from a baggabe file which follows W3C Baggage specification */
89
+ export const loadBaggageFromFile = function (baggageFilePath) {
90
+ if (baggageFilePath.length === 0) {
91
+ diag.warn('Empty baggage file path provided, no context loaded');
92
+ return context.active();
93
+ }
94
+ let baggageString;
95
+ try {
96
+ baggageString = readFileSync(baggageFilePath, 'utf-8');
97
+ }
98
+ catch (error) {
99
+ diag.error(error);
100
+ return context.active();
101
+ }
102
+ const parsedBaggage = parseKeyPairsIntoRecord(baggageString);
103
+ return setMultiSpanAttributes(parsedBaggage);
104
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/build",
3
- "version": "29.23.5",
3
+ "version": "29.24.0",
4
4
  "description": "Netlify build module",
5
5
  "type": "module",
6
6
  "exports": "./lib/index.js",
@@ -76,6 +76,7 @@
76
76
  "@netlify/run-utils": "^5.1.1",
77
77
  "@netlify/zip-it-and-ship-it": "9.25.4",
78
78
  "@opentelemetry/api": "^1.4.1",
79
+ "@opentelemetry/core": "^1.17.1",
79
80
  "@sindresorhus/slugify": "^2.0.0",
80
81
  "ansi-escapes": "^6.0.0",
81
82
  "chalk": "^5.0.0",
@@ -145,5 +146,5 @@
145
146
  "engines": {
146
147
  "node": "^14.16.0 || >=16.0.0"
147
148
  },
148
- "gitHead": "db107b34adafddf6972b671687f584ee795befe9"
149
+ "gitHead": "d2322081693fa4fea32710d5551d5cf33b92ee33"
149
150
  }