@netlify/build 29.28.1 → 29.29.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.
@@ -6,6 +6,8 @@ export type BuildCLIFlags = {
6
6
  siteId: string;
7
7
  /** Netlify API token for authentication */
8
8
  token: string;
9
+ /** Netlify Deploy ID */
10
+ deployId: string;
9
11
  /**
10
12
  * Run in dry mode, i.e. printing steps without executing them
11
13
  * @default false
@@ -41,10 +41,14 @@ const getEventMessage = function (event) {
41
41
  const getApiLocation = function ({ endpoint, parameters }) {
42
42
  return `While calling the Netlify API endpoint '${endpoint}' with:\n${JSON.stringify(parameters, null, 2)}`;
43
43
  };
44
+ const getDeployLocation = function ({ statusCode }) {
45
+ return `At deploy the stage with HTTP status code '${statusCode}'`;
46
+ };
44
47
  const LOCATIONS = {
45
48
  buildCommand: getBuildCommandLocation,
46
49
  functionsBundling: getFunctionsBundlingLocation,
47
50
  coreStep: getCoreStepLocation,
48
51
  buildFail: getBuildFailLocation,
49
52
  api: getApiLocation,
53
+ deploy: getDeployLocation,
50
54
  };
@@ -1,16 +1,13 @@
1
- export function serializeErrorStatus({ fullErrorInfo: { title, message, locationInfo, errorProps, errorMetadata }, state, }: {
2
- fullErrorInfo: {
3
- title: any;
4
- message: any;
5
- locationInfo: any;
6
- errorProps: any;
7
- errorMetadata: any;
8
- };
9
- state: any;
10
- }): {
11
- state: any;
12
- title: any;
13
- summary: any;
1
+ import type { BuildError } from '../types.js';
2
+ type ErrorState = 'failed_build' | 'failed_plugin' | 'canceled_build';
3
+ export declare const serializeErrorStatus: ({ fullErrorInfo: { title, message, locationInfo, errorProps, errorMetadata }, state, }: {
4
+ fullErrorInfo: BuildError;
5
+ state: ErrorState;
6
+ }) => {
7
+ state: ErrorState;
8
+ title: string | (import("../types.js").TitleFunction & string);
9
+ summary: string;
14
10
  text: string | undefined;
15
11
  extraData: any;
16
12
  };
13
+ export {};
@@ -1,4 +1,4 @@
1
- // Serialize an error object to `statuses` properties
1
+ /* Serialize an error object to `statuses` properties */
2
2
  export const serializeErrorStatus = function ({ fullErrorInfo: { title, message, locationInfo, errorProps, errorMetadata }, state, }) {
3
3
  const text = getText({ locationInfo, errorProps });
4
4
  return { state, title, summary: message, text, extraData: errorMetadata };
@@ -52,9 +52,6 @@ declare enum StackType {
52
52
  * not printed
53
53
  */
54
54
  none = "none",
55
- /**
56
- * printed as is
57
- */
58
55
  stack = "stack",
59
56
  /**
60
57
  * printed as is, but taken from `error.message`. Used when `error.stack` is not being correct due to the error being passed between different processes.
@@ -99,7 +96,11 @@ export type APILocation = {
99
96
  parameters?: any;
100
97
  };
101
98
  export declare const isAPILocation: (location?: ErrorLocation) => location is APILocation;
102
- export type ErrorLocation = BuildCommandLocation | FunctionsBundlingLocation | CoreStepLocation | PluginLocation | APILocation;
99
+ export type DeployLocation = {
100
+ statusCode: string;
101
+ };
102
+ export declare const isDeployLocation: (location?: ErrorLocation) => location is DeployLocation;
103
+ export type ErrorLocation = BuildCommandLocation | FunctionsBundlingLocation | CoreStepLocation | PluginLocation | APILocation | DeployLocation;
103
104
  /**
104
105
  * Given a BuildError, extract the relevant trace attributes to add to the on-going Span
105
106
  */
@@ -165,10 +166,13 @@ declare const ErrorTypeMap: {
165
166
  readonly pluginInternal: "pluginInternal";
166
167
  readonly ipc: "ipc";
167
168
  readonly corePlugin: "corePlugin";
169
+ readonly trustedPlugin: "trustedPlugin";
168
170
  readonly coreStep: "coreStep";
169
171
  readonly api: "api";
172
+ readonly deploy: "deploy";
173
+ readonly deployInternal: "deployInternal";
170
174
  readonly exception: "exception";
171
175
  readonly telemetry: "telemetry";
172
176
  };
173
- type ErrorTypes = keyof typeof ErrorTypeMap;
177
+ export type ErrorTypes = keyof typeof ErrorTypeMap;
174
178
  export {};
@@ -33,7 +33,7 @@ var StackType;
33
33
  * not printed
34
34
  */
35
35
  StackType["none"] = "none";
36
- /**
36
+ /*
37
37
  * printed as is
38
38
  */
39
39
  StackType["stack"] = "stack";
@@ -62,6 +62,9 @@ export const isPluginLocation = function (location) {
62
62
  export const isAPILocation = function (location) {
63
63
  return typeof location?.endpoint === 'string';
64
64
  };
65
+ export const isDeployLocation = function (location) {
66
+ return typeof location?.statusCode === 'string';
67
+ };
65
68
  const buildErrorAttributePrefix = 'build.error';
66
69
  const errorLocationToTracingAttributes = function (location) {
67
70
  const locationAttributePrefix = `${buildErrorAttributePrefix}.location`;
@@ -95,6 +98,11 @@ const errorLocationToTracingAttributes = function (location) {
95
98
  [`${locationAttributePrefix}.api.endpoint`]: location.endpoint,
96
99
  };
97
100
  }
101
+ if (isDeployLocation(location)) {
102
+ return {
103
+ [`${locationAttributePrefix}.deploy.status_code`]: location.statusCode,
104
+ };
105
+ }
98
106
  return {};
99
107
  };
100
108
  /**
@@ -141,8 +149,11 @@ const ErrorTypeMap = {
141
149
  pluginInternal: 'pluginInternal',
142
150
  ipc: 'ipc',
143
151
  corePlugin: 'corePlugin',
152
+ trustedPlugin: 'trustedPlugin',
144
153
  coreStep: 'coreStep',
145
154
  api: 'api',
155
+ deploy: 'deploy',
156
+ deployInternal: 'deployInternal',
146
157
  exception: 'exception',
147
158
  telemetry: 'telemetry',
148
159
  };
@@ -293,6 +304,17 @@ const TYPES = {
293
304
  locationType: 'buildFail',
294
305
  severity: 'error',
295
306
  },
307
+ /**
308
+ * Trusted plugin internal error (all of our `@netlify/*` plugins).
309
+ */
310
+ trustedPlugin: {
311
+ title: ({ location: { packageName } }) => `Plugin "${packageName}" internal error`,
312
+ stackType: 'stack',
313
+ showErrorProps: true,
314
+ rawStack: true,
315
+ locationType: 'buildFail',
316
+ severity: 'error',
317
+ },
296
318
  /**
297
319
  * Core step internal error
298
320
  */
@@ -314,6 +336,24 @@ const TYPES = {
314
336
  locationType: 'api',
315
337
  severity: 'error',
316
338
  },
339
+ /**
340
+ * Non-internal errors deploying files or functions
341
+ */
342
+ deploy: {
343
+ title: 'Error deploying',
344
+ stackType: 'none',
345
+ locationType: 'deploy',
346
+ severity: 'info',
347
+ },
348
+ /**
349
+ * Internal errors deploying files or functions
350
+ */
351
+ deployInternal: {
352
+ title: 'Internal error deploying',
353
+ stackType: 'none',
354
+ locationType: 'deploy',
355
+ severity: 'error',
356
+ },
317
357
  /**
318
358
  * `@netlify/build` threw an uncaught exception
319
359
  */
@@ -1,5 +1,5 @@
1
- export const isSoftFailEvent: any;
2
- export const runsAlsoOnBuildFailure: any;
3
- export const runsOnlyOnBuildFailure: any;
4
- export const runsAfterDeploy: any;
5
- export { DEV_EVENTS, EVENTS } from "@netlify/config";
1
+ export { DEV_EVENTS, EVENTS } from '@netlify/config';
2
+ export declare const isSoftFailEvent: any;
3
+ export declare const runsAlsoOnBuildFailure: any;
4
+ export declare const runsOnlyOnBuildFailure: any;
5
+ export declare const runsAfterDeploy: any;
@@ -36,7 +36,9 @@ const startPlugin = async function ({ pluginDir, nodePath, buildDir, childEnv, s
36
36
  execPath: nodePath,
37
37
  env: childEnv,
38
38
  extendEnv: false,
39
- stdio: isTrustedPlugin(pluginPackageJson) && systemLogFile ? ['pipe', 'pipe', 'pipe', 'ipc', systemLogFile] : undefined,
39
+ stdio: isTrustedPlugin(pluginPackageJson?.name) && systemLogFile
40
+ ? ['pipe', 'pipe', 'pipe', 'ipc', systemLogFile]
41
+ : undefined,
40
42
  });
41
43
  try {
42
44
  await getEventFromChild(childProcess, 'ready');
@@ -0,0 +1,26 @@
1
+ export declare const uploadBlobs: {
2
+ event: string;
3
+ coreStep: ({ debug, logs, deployId, buildDir, quiet, constants: { PUBLISH_DIR, SITE_ID, NETLIFY_API_TOKEN, API_URL }, }: {
4
+ debug: any;
5
+ logs: any;
6
+ deployId: any;
7
+ buildDir: any;
8
+ quiet: any;
9
+ constants: {
10
+ PUBLISH_DIR: any;
11
+ SITE_ID: any;
12
+ NETLIFY_API_TOKEN: any;
13
+ API_URL: any;
14
+ };
15
+ }) => Promise<{}>;
16
+ coreStepId: string;
17
+ coreStepName: string;
18
+ coreStepDescription: () => string;
19
+ condition: ({ deployId, buildDir, constants: { PUBLISH_DIR } }: {
20
+ deployId: any;
21
+ buildDir: any;
22
+ constants: {
23
+ PUBLISH_DIR: any;
24
+ };
25
+ }) => Promise<boolean>;
26
+ };
@@ -0,0 +1,61 @@
1
+ import { version as nodeVersion } from 'node:process';
2
+ import { getDeployStore } from '@netlify/blobs';
3
+ import pMap from 'p-map';
4
+ import semver from 'semver';
5
+ import { log, logError } from '../../log/logger.js';
6
+ import { anyBlobsToUpload, getBlobsDir } from '../../utils/blobs.js';
7
+ import { getKeysToUpload, getFileWithMetadata } from './utils.js';
8
+ const coreStep = async function ({ debug, logs, deployId, buildDir, quiet, constants: { PUBLISH_DIR, SITE_ID, NETLIFY_API_TOKEN, API_URL }, }) {
9
+ const storeOpts = {
10
+ siteID: SITE_ID,
11
+ deployID: deployId,
12
+ token: NETLIFY_API_TOKEN,
13
+ apiURL: API_URL,
14
+ };
15
+ if (semver.lt(nodeVersion, '18.0.0')) {
16
+ const nodeFetch = await import('node-fetch');
17
+ storeOpts.fetch = nodeFetch.default;
18
+ }
19
+ const blobStore = getDeployStore(storeOpts);
20
+ const blobsDir = getBlobsDir({ buildDir, publishDir: PUBLISH_DIR });
21
+ const keys = await getKeysToUpload(blobsDir);
22
+ // We checked earlier, but let's be extra safe
23
+ if (keys.length === 0) {
24
+ if (!quiet) {
25
+ log(logs, 'No blobs to upload to deploy store.');
26
+ }
27
+ return {};
28
+ }
29
+ if (!quiet) {
30
+ log(logs, `Uploading ${keys.length} blobs to deploy store...`);
31
+ }
32
+ const uploadBlob = async (key) => {
33
+ if (debug && !quiet) {
34
+ log(logs, `- Uploading blob ${key}`, { indent: true });
35
+ }
36
+ const { data, metadata } = await getFileWithMetadata(blobsDir, key);
37
+ await blobStore.set(key, data, { metadata });
38
+ };
39
+ try {
40
+ await pMap(keys, uploadBlob, { concurrency: 10 });
41
+ }
42
+ catch (err) {
43
+ logError(logs, `Error uploading blobs to deploy store: ${err.message}`);
44
+ throw new Error(`Failed while uploading blobs to deploy store`);
45
+ }
46
+ if (!quiet) {
47
+ log(logs, `Done uploading blobs to deploy store.`);
48
+ }
49
+ return {};
50
+ };
51
+ const deployAndBlobsPresent = async function ({ deployId, buildDir, constants: { PUBLISH_DIR } }) {
52
+ return deployId && (await anyBlobsToUpload({ buildDir, publishDir: PUBLISH_DIR }));
53
+ };
54
+ export const uploadBlobs = {
55
+ event: 'onPostBuild',
56
+ coreStep,
57
+ coreStepId: 'blobs_upload',
58
+ coreStepName: 'Uploading blobs',
59
+ coreStepDescription: () => 'Uploading blobs to deploy store',
60
+ condition: deployAndBlobsPresent,
61
+ };
@@ -0,0 +1,8 @@
1
+ /// <reference types="node" resolution-mode="require"/>
2
+ /** Given output directory, find all file paths to upload excluding metadata files */
3
+ export declare function getKeysToUpload(blobsDir: string): Promise<string[]>;
4
+ /** Read a file and its metadata file from the blobs directory */
5
+ export declare function getFileWithMetadata(blobsDir: string, key: string): Promise<{
6
+ data: Buffer;
7
+ metadata: Record<string, string>;
8
+ }>;
@@ -0,0 +1,46 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { fdir } from 'fdir';
4
+ const METADATA_PREFIX = '$';
5
+ const METADATA_SUFFIX = '.json';
6
+ /** Given output directory, find all file paths to upload excluding metadata files */
7
+ export async function getKeysToUpload(blobsDir) {
8
+ const files = await new fdir()
9
+ .withRelativePaths() // we want the relative path from the blobsDir
10
+ .filter((fpath) => !path.basename(fpath).startsWith(METADATA_PREFIX))
11
+ .crawl(blobsDir)
12
+ .withPromise();
13
+ // normalize the path separators to all use the forward slash
14
+ return files.map((f) => f.split(path.sep).join('/'));
15
+ }
16
+ /** Read a file and its metadata file from the blobs directory */
17
+ export async function getFileWithMetadata(blobsDir, key) {
18
+ const contentPath = path.join(blobsDir, key);
19
+ const dirname = path.dirname(key);
20
+ const basename = path.basename(key);
21
+ const metadataPath = path.join(blobsDir, dirname, `${METADATA_PREFIX}${basename}${METADATA_SUFFIX}`);
22
+ const [data, metadata] = await Promise.all([readFile(contentPath), readMetadata(metadataPath)]).catch((err) => {
23
+ throw new Error(`Failed while reading '${key}' and its metadata: ${err.message}`);
24
+ });
25
+ return { data, metadata };
26
+ }
27
+ async function readMetadata(metadataPath) {
28
+ let metadataFile;
29
+ try {
30
+ metadataFile = await readFile(metadataPath, { encoding: 'utf8' });
31
+ }
32
+ catch (err) {
33
+ if (err.code === 'ENOENT') {
34
+ // no metadata file found, that's ok
35
+ return {};
36
+ }
37
+ throw err;
38
+ }
39
+ try {
40
+ return JSON.parse(metadataFile);
41
+ }
42
+ catch {
43
+ // Normalize the error message
44
+ throw new Error(`Error parsing metadata file '${metadataPath}'`);
45
+ }
46
+ }
@@ -1,12 +1,24 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
- export function createBuildbotClient(buildbotServerSocket: any): net.Socket;
3
- export const connectBuildbotClient: (...args: any[]) => Promise<any>;
4
- export function closeBuildbotClient(client: any): Promise<void>;
5
- export function deploySiteWithBuildbotClient({ client, events, buildDir, repositoryRoot, constants }: {
2
+ import net from 'net';
3
+ /**
4
+ * Creates the Buildbot IPC client we use to initiate the deploy
5
+ */
6
+ export declare const createBuildbotClient: (buildbotServerSocket: string) => net.Socket;
7
+ /**
8
+ * Emits the connect event
9
+ */
10
+ export declare const connectBuildbotClient: (...args: unknown[]) => Promise<void>;
11
+ /**
12
+ * Closes the buildbot client and its connection
13
+ */
14
+ export declare const closeBuildbotClient: (client: net.Socket) => Promise<void>;
15
+ /**
16
+ * Initates the deploy with the given buildbot client
17
+ */
18
+ export declare const deploySiteWithBuildbotClient: ({ client, events, buildDir, repositoryRoot, constants }: {
6
19
  client: any;
7
20
  events: any;
8
21
  buildDir: any;
9
22
  repositoryRoot: any;
10
23
  constants: any;
11
- }): Promise<undefined>;
12
- import net from 'net';
24
+ }) => Promise<undefined>;
@@ -5,80 +5,111 @@ import { pEvent } from 'p-event';
5
5
  import { addErrorInfo } from '../../error/info.js';
6
6
  import { runsAfterDeploy } from '../../plugins/events.js';
7
7
  import { addAsyncErrorMessage } from '../../utils/errors.js';
8
+ /**
9
+ * Actions supported by the deploy server.
10
+ */
11
+ var Action;
12
+ (function (Action) {
13
+ /**
14
+ * Initiate the deploy.
15
+ */
16
+ Action["DeploySite"] = "deploySite";
17
+ /**
18
+ * Initiate the deploy, wait and hand back control to `@netlify/build` once the site is live.
19
+ */
20
+ Action["DeploySiteAndWait"] = "deploySiteAndAwaitLive";
21
+ })(Action || (Action = {}));
22
+ /**
23
+ * Creates the Buildbot IPC client we use to initiate the deploy
24
+ */
8
25
  export const createBuildbotClient = function (buildbotServerSocket) {
9
26
  const connectionOpts = getConnectionOpts(buildbotServerSocket);
10
27
  const client = net.createConnection(connectionOpts);
11
28
  return client;
12
29
  };
13
- // Windows does not support Unix sockets well, so we also support `host:port`
30
+ /**
31
+ * Windows does not support Unix sockets well, so we also support `host:port`
32
+ */
14
33
  const getConnectionOpts = function (buildbotServerSocket) {
15
34
  if (!buildbotServerSocket.includes(':')) {
16
35
  return { path: buildbotServerSocket };
17
36
  }
18
37
  const [host, port] = buildbotServerSocket.split(':');
19
- return { host, port };
38
+ return { host, port: Number(port) };
20
39
  };
21
- const eConnectBuildbotClient = async function (client) {
40
+ /**
41
+ * Emits the connect event
42
+ */
43
+ export const connectBuildbotClient = addAsyncErrorMessage(async (client) => {
22
44
  await pEvent(client, 'connect');
23
- };
24
- export const connectBuildbotClient = addAsyncErrorMessage(eConnectBuildbotClient, 'Could not connect to buildbot');
45
+ }, 'Could not connect to buildbot');
46
+ /**
47
+ * Closes the buildbot client and its connection
48
+ */
25
49
  export const closeBuildbotClient = async function (client) {
26
50
  if (client.destroyed) {
27
51
  return;
28
52
  }
29
53
  await promisify(client.end.bind(client))();
30
54
  };
31
- const cWritePayload = async function (buildbotClient, payload) {
55
+ const writePayload = addAsyncErrorMessage(async (buildbotClient, payload) => {
32
56
  await promisify(buildbotClient.write.bind(buildbotClient))(JSON.stringify(payload));
33
- };
34
- const writePayload = addAsyncErrorMessage(cWritePayload, 'Could not send payload to buildbot');
35
- const cGetNextParsedResponsePromise = async function (buildbotClient) {
57
+ }, 'Could not send payload to buildbot');
58
+ const getNextParsedResponsePromise = addAsyncErrorMessage(async (buildbotClient) => {
36
59
  const data = await pEvent(buildbotClient, 'data');
37
60
  return JSON.parse(data);
38
- };
39
- const getNextParsedResponsePromise = addAsyncErrorMessage(cGetNextParsedResponsePromise, 'Invalid response from buildbot');
61
+ }, 'Invalid response from buildbot');
62
+ /**
63
+ * Initates the deploy with the given buildbot client
64
+ */
40
65
  export const deploySiteWithBuildbotClient = async function ({ client, events, buildDir, repositoryRoot, constants }) {
41
- const action = shouldWaitForPostProcessing(events) ? 'deploySiteAndAwaitLive' : 'deploySite';
66
+ const action = shouldWaitForPostProcessing(events) ? Action.DeploySiteAndWait : Action.DeploySite;
42
67
  const deployDir = getDeployDir({ buildDir, repositoryRoot, constants });
43
68
  const payload = { action, deployDir };
44
- const [{ succeeded, values: { error, error_type: errorType } = {} }] = await Promise.all([
45
- getNextParsedResponsePromise(client),
46
- writePayload(client, payload),
47
- ]);
48
- if (!succeeded) {
49
- return handleDeployError(error, errorType);
69
+ const [response] = await Promise.all([getNextParsedResponsePromise(client), writePayload(client, payload)]);
70
+ if (!response.succeeded) {
71
+ const { error, code, error_type } = response?.values || {};
72
+ return handleDeployError(error, code, error_type);
50
73
  }
51
74
  };
52
- // The file paths in the buildbot are relative to the repository root.
53
- // However, the file paths in Build plugins, including `constants.PUBLISH_DIR`
54
- // are relative to the build directory, which is different when there is a
55
- // base directory. This converts it.
56
- // We need to call `normalize()` in case the publish directory is the
57
- // repository root, so `deployDir` is "." not ""
75
+ /**
76
+ * The file paths in the buildbot are relative to the repository root.
77
+ * However, the file paths in Build plugins, including `constants.PUBLISH_DIR`
78
+ * are relative to the build directory, which is different when there is a
79
+ * base directory. This converts it.
80
+ * We need to call `normalize()` in case the publish directory is the
81
+ * repository root, so `deployDir` is "." not ""
82
+ */
58
83
  const getDeployDir = function ({ buildDir, repositoryRoot, constants: { PUBLISH_DIR } }) {
59
84
  const absolutePublishDir = resolve(buildDir, PUBLISH_DIR);
60
85
  const relativePublishDir = relative(repositoryRoot, absolutePublishDir);
61
86
  const deployDir = normalize(relativePublishDir);
62
87
  return deployDir;
63
88
  };
64
- // We distinguish between user errors and system errors during deploys
65
- const handleDeployError = function (error, errorType) {
66
- const errorIs422 = error !== undefined && error.code === '422';
67
- const errMsg = errorIs422
68
- ? `
69
- File upload failed because of mismatched SHAs.
70
- This can happen when files are changed after the deployment process has started but before they are uploaded.
71
-
72
- Error: ${error}
73
- `
74
- : `Deploy did not succeed: ${error}`;
75
- const errorA = new Error(errMsg);
89
+ /**
90
+ * We distinguish between user errors and system errors during deploys
91
+ */
92
+ const handleDeployError = function (error, errorCode, errorType) {
93
+ if (errorCode !== undefined) {
94
+ const err = new Error(`Deploy did not succeed with HTTP Error ${errorCode}: ${error}`);
95
+ if (errorCode.startsWith('5')) {
96
+ const errorInfo = { type: 'deployInternal', location: { statusCode: errorCode } };
97
+ addErrorInfo(err, errorInfo);
98
+ throw err;
99
+ }
100
+ const errorInfo = { type: 'deploy', location: { statusCode: errorCode } };
101
+ addErrorInfo(err, errorInfo);
102
+ throw err;
103
+ }
104
+ const err = new Error(`Deploy did not succeed: ${error}`);
76
105
  const errorInfo = errorType === 'user' ? { type: 'resolveConfig' } : { type: 'coreStep', location: { coreStepName: 'Deploy site' } };
77
- addErrorInfo(errorA, errorInfo);
78
- throw errorA;
106
+ addErrorInfo(err, errorInfo);
107
+ throw err;
79
108
  };
80
- // We only wait for post-processing (last stage before site deploy) if the build
81
- // has some plugins that do post-deploy logic
109
+ /**
110
+ * We only wait for post-processing (last stage before site deploy) if the build
111
+ * has some plugins that do post-deploy logic
112
+ */
82
113
  const shouldWaitForPostProcessing = function (events) {
83
114
  return events.some(hasPostDeployLogic);
84
115
  };
@@ -0,0 +1,18 @@
1
+ export declare const preCleanup: {
2
+ event: string;
3
+ coreStep: ({ buildDir, constants: { PUBLISH_DIR } }: {
4
+ buildDir: any;
5
+ constants: {
6
+ PUBLISH_DIR: any;
7
+ };
8
+ }) => Promise<{}>;
9
+ coreStepId: string;
10
+ coreStepName: string;
11
+ coreStepDescription: () => string;
12
+ condition: ({ buildDir, constants: { PUBLISH_DIR } }: {
13
+ buildDir: any;
14
+ constants: {
15
+ PUBLISH_DIR: any;
16
+ };
17
+ }) => Promise<boolean>;
18
+ };
@@ -0,0 +1,23 @@
1
+ import { rm } from 'node:fs/promises';
2
+ import { anyBlobsToUpload, getBlobsDir } from '../../utils/blobs.js';
3
+ const coreStep = async function ({ buildDir, constants: { PUBLISH_DIR } }) {
4
+ const blobsDir = getBlobsDir({ buildDir, publishDir: PUBLISH_DIR });
5
+ try {
6
+ await rm(blobsDir, { recursive: true, force: true });
7
+ }
8
+ catch {
9
+ // Ignore errors if it fails, we can continue anyway.
10
+ }
11
+ return {};
12
+ };
13
+ const blobsPresent = async function ({ buildDir, constants: { PUBLISH_DIR } }) {
14
+ return await anyBlobsToUpload({ buildDir, publishDir: PUBLISH_DIR });
15
+ };
16
+ export const preCleanup = {
17
+ event: 'onPreBuild',
18
+ coreStep,
19
+ coreStepId: 'pre_cleanup',
20
+ coreStepName: 'Pre cleanup',
21
+ coreStepDescription: () => 'Cleaning up leftover files from previous builds',
22
+ condition: blobsPresent,
23
+ };
@@ -1,4 +1,4 @@
1
- export declare const fireCoreStep: ({ coreStep, coreStepId, coreStepName, configPath, outputConfigPath, buildDir, repositoryRoot, packagePath, constants, buildbotServerSocket, events, logs, nodePath, childEnv, context, branch, envChanges, errorParams, configOpts, netlifyConfig, configMutations, headersPath, redirectsPath, featureFlags, debug, systemLog, saveConfig, userNodeVersion, explicitSecretKeys, edgeFunctionsBootstrapURL, }: {
1
+ export declare const fireCoreStep: ({ coreStep, coreStepId, coreStepName, configPath, outputConfigPath, buildDir, repositoryRoot, packagePath, constants, buildbotServerSocket, events, logs, quiet, nodePath, childEnv, context, branch, envChanges, errorParams, configOpts, netlifyConfig, configMutations, headersPath, redirectsPath, featureFlags, debug, systemLog, saveConfig, userNodeVersion, explicitSecretKeys, edgeFunctionsBootstrapURL, deployId, }: {
2
2
  coreStep: any;
3
3
  coreStepId: any;
4
4
  coreStepName: any;
@@ -11,6 +11,7 @@ export declare const fireCoreStep: ({ coreStep, coreStepId, coreStepName, config
11
11
  buildbotServerSocket: any;
12
12
  events: any;
13
13
  logs: any;
14
+ quiet: any;
14
15
  nodePath: any;
15
16
  childEnv: any;
16
17
  context: any;
@@ -29,6 +30,7 @@ export declare const fireCoreStep: ({ coreStep, coreStepId, coreStepName, config
29
30
  userNodeVersion: any;
30
31
  explicitSecretKeys: any;
31
32
  edgeFunctionsBootstrapURL: any;
33
+ deployId: any;
32
34
  }) => Promise<{
33
35
  newEnvChanges: any;
34
36
  netlifyConfig: any;
@@ -2,7 +2,7 @@ import { setEnvChanges } from '../env/changes.js';
2
2
  import { addErrorInfo, isBuildError } from '../error/info.js';
3
3
  import { updateNetlifyConfig, listConfigSideFiles } from './update_config.js';
4
4
  // Fire a core step
5
- export const fireCoreStep = async function ({ coreStep, coreStepId, coreStepName, configPath, outputConfigPath, buildDir, repositoryRoot, packagePath, constants, buildbotServerSocket, events, logs, nodePath, childEnv, context, branch, envChanges, errorParams, configOpts, netlifyConfig, configMutations, headersPath, redirectsPath, featureFlags, debug, systemLog, saveConfig, userNodeVersion, explicitSecretKeys, edgeFunctionsBootstrapURL, }) {
5
+ export const fireCoreStep = async function ({ coreStep, coreStepId, coreStepName, configPath, outputConfigPath, buildDir, repositoryRoot, packagePath, constants, buildbotServerSocket, events, logs, quiet, nodePath, childEnv, context, branch, envChanges, errorParams, configOpts, netlifyConfig, configMutations, headersPath, redirectsPath, featureFlags, debug, systemLog, saveConfig, userNodeVersion, explicitSecretKeys, edgeFunctionsBootstrapURL, deployId, }) {
6
6
  try {
7
7
  const configSideFiles = await listConfigSideFiles([headersPath, redirectsPath]);
8
8
  const childEnvA = setEnvChanges(envChanges, { ...childEnv });
@@ -16,6 +16,7 @@ export const fireCoreStep = async function ({ coreStep, coreStepId, coreStepName
16
16
  buildbotServerSocket,
17
17
  events,
18
18
  logs,
19
+ quiet,
19
20
  context,
20
21
  branch,
21
22
  childEnv: childEnvA,
@@ -31,6 +32,7 @@ export const fireCoreStep = async function ({ coreStep, coreStepId, coreStepName
31
32
  userNodeVersion,
32
33
  explicitSecretKeys,
33
34
  edgeFunctionsBootstrapURL,
35
+ deployId,
34
36
  });
35
37
  const { netlifyConfig: netlifyConfigA, configMutations: configMutationsA, headersPath: headersPathA, redirectsPath: redirectsPathA, } = await updateNetlifyConfig({
36
38
  configOpts,
@@ -1,4 +1,14 @@
1
- export function handleStepError({ event, newError, childEnv, mode, api, errorMonitor, deployId, coreStep, netlifyConfig, logs, debug, testOpts, }: {
1
+ import { ErrorTypes } from '../error/types.js';
2
+ /**
3
+ * Handle build command errors and plugin errors:
4
+ * - usually, propagate the error to make the build stop.
5
+ * - `utils.build.cancelBuild()` also cancels the build by calling the API
6
+ * - `utils.build.failPlugin()` or post-deploy errors do not make the build
7
+ * stop, but are still reported, and prevent future events from the same
8
+ * plugin.
9
+ * This also computes error statuses that are sent to the API.
10
+ */
11
+ export declare const handleStepError: ({ event, newError, childEnv, mode, api, errorMonitor, deployId, coreStep, netlifyConfig, logs, debug, testOpts, }: {
2
12
  event: any;
3
13
  newError: any;
4
14
  childEnv: any;
@@ -11,38 +21,36 @@ export function handleStepError({ event, newError, childEnv, mode, api, errorMon
11
21
  logs: any;
12
22
  debug: any;
13
23
  testOpts: any;
14
- }): Promise<{
15
- failedPlugin: any[];
24
+ }) => Promise<{
25
+ failedPlugin: string[];
16
26
  newStatus: {
17
- state: any;
18
- title: any;
19
- summary: any;
27
+ state: "failed_build" | "failed_plugin" | "canceled_build";
28
+ title: string | (import("../error/types.js").TitleFunction & string);
29
+ summary: string;
20
30
  text: string | undefined;
21
31
  extraData: any;
22
32
  };
23
33
  }> | Promise<{
24
34
  newError: any;
25
35
  newStatus: {
26
- state: any;
27
- title: any;
28
- summary: any;
36
+ state: "failed_build" | "failed_plugin" | "canceled_build";
37
+ title: string | (import("../error/types.js").TitleFunction & string);
38
+ summary: string;
29
39
  text: string | undefined;
30
40
  extraData: any;
31
41
  };
32
42
  }> | {
33
43
  newError: any;
34
44
  newStatus: {
35
- state: any;
36
- title: any;
37
- summary: any;
45
+ state: "failed_build" | "failed_plugin" | "canceled_build";
46
+ title: string | (import("../error/types.js").TitleFunction & string);
47
+ summary: string;
38
48
  text: string | undefined;
39
49
  extraData: any;
40
50
  };
41
51
  } | {
42
52
  newError: any;
43
53
  };
44
- export function getPluginErrorType(error: any, loadedFrom: any): {
45
- type?: undefined;
46
- } | {
47
- type: string;
54
+ export declare const getPluginErrorType: (error: Error, loadedFrom: string, packageName?: string) => {
55
+ type?: ErrorTypes;
48
56
  };
@@ -2,15 +2,19 @@ import { cancelBuild } from '../error/cancel.js';
2
2
  import { handleBuildError } from '../error/handle.js';
3
3
  import { getFullErrorInfo, parseErrorInfo } from '../error/parse/parse.js';
4
4
  import { serializeErrorStatus } from '../error/parse/serialize_status.js';
5
+ import { isPluginLocation } from '../error/types.js';
5
6
  import { isSoftFailEvent } from '../plugins/events.js';
6
7
  import { addErrorToActiveSpan, addEventToActiveSpan } from '../tracing/main.js';
7
- // Handle build command errors and plugin errors:
8
- // - usually, propagate the error to make the build stop.
9
- // - `utils.build.cancelBuild()` also cancels the build by calling the API
10
- // - `utils.build.failPlugin()` or post-deploy errors do not make the build
11
- // stop, but are still reported, and prevent future events from the same
12
- // plugin.
13
- // This also computes error statuses that are sent to the API.
8
+ import { isTrustedPlugin } from './plugin.js';
9
+ /**
10
+ * Handle build command errors and plugin errors:
11
+ * - usually, propagate the error to make the build stop.
12
+ * - `utils.build.cancelBuild()` also cancels the build by calling the API
13
+ * - `utils.build.failPlugin()` or post-deploy errors do not make the build
14
+ * stop, but are still reported, and prevent future events from the same
15
+ * plugin.
16
+ * This also computes error statuses that are sent to the API.
17
+ */
14
18
  export const handleStepError = function ({ event, newError, childEnv, mode, api, errorMonitor, deployId, coreStep, netlifyConfig, logs, debug, testOpts, }) {
15
19
  addErrorToActiveSpan(newError);
16
20
  // Core steps do not report error statuses
@@ -18,7 +22,7 @@ export const handleStepError = function ({ event, newError, childEnv, mode, api,
18
22
  return { newError };
19
23
  }
20
24
  const fullErrorInfo = getFullErrorInfo({ error: newError, colors: false, debug });
21
- const { errorInfo: { location: { packageName } = {} }, message, title, type, } = fullErrorInfo;
25
+ const { errorInfo, message, title, type } = fullErrorInfo;
22
26
  if (type === 'failPlugin' || isSoftFailEvent(event)) {
23
27
  return handleFailPlugin({
24
28
  fullErrorInfo,
@@ -36,32 +40,40 @@ export const handleStepError = function ({ event, newError, childEnv, mode, api,
36
40
  const cancellationAttributes = {
37
41
  'build.cancellation.title': title,
38
42
  'build.cancellation.message': message,
39
- 'build.cancellation.packageName': packageName,
40
43
  };
44
+ if (isPluginLocation(errorInfo.location)) {
45
+ cancellationAttributes['build.cancellation.packageName'] = errorInfo.location.packageName;
46
+ }
41
47
  addEventToActiveSpan('build.cancelled', cancellationAttributes);
42
48
  return handleCancelBuild({ fullErrorInfo, newError, api, deployId });
43
49
  }
44
50
  return handleFailBuild({ fullErrorInfo, newError });
45
51
  };
46
- // On `utils.build.failPlugin()` or during `onSuccess` or `onEnd`
47
- const handleFailPlugin = async function ({ fullErrorInfo, fullErrorInfo: { errorInfo: { location: { packageName } = {} }, }, newError, childEnv, mode, errorMonitor, netlifyConfig, logs, debug, testOpts, }) {
52
+ /* On `utils.build.failPlugin()` or during `onSuccess` or `onEnd` */
53
+ const handleFailPlugin = async function ({ fullErrorInfo, newError, childEnv, mode, errorMonitor, netlifyConfig, logs, debug, testOpts, }) {
48
54
  const newStatus = serializeErrorStatus({ fullErrorInfo, state: 'failed_plugin' });
49
55
  await handleBuildError(newError, { errorMonitor, netlifyConfig, childEnv, mode, logs, debug, testOpts });
50
- return { failedPlugin: [packageName], newStatus };
56
+ // TODO we should probably use type guard here, but due to the way we build these errorInfo objects I'm not 100%
57
+ // confident we have all the properties currently required by the type
58
+ const location = fullErrorInfo.errorInfo.location;
59
+ return { failedPlugin: [location.packageName], newStatus };
51
60
  };
52
- // On `utils.build.cancelBuild()`
61
+ /* On `utils.build.cancelBuild()` */
53
62
  const handleCancelBuild = async function ({ fullErrorInfo, newError, api, deployId }) {
54
63
  const newStatus = serializeErrorStatus({ fullErrorInfo, state: 'canceled_build' });
55
64
  await cancelBuild({ api, deployId });
56
65
  return { newError, newStatus };
57
66
  };
58
- // On `utils.build.failBuild()` or uncaught exception
67
+ /* On `utils.build.failBuild()` or uncaught exception */
59
68
  const handleFailBuild = function ({ fullErrorInfo, newError }) {
60
69
  const newStatus = serializeErrorStatus({ fullErrorInfo, state: 'failed_build' });
61
70
  return { newError, newStatus };
62
71
  };
63
- // Unlike community plugins, core plugin bugs should be handled as system errors
64
- export const getPluginErrorType = function (error, loadedFrom) {
72
+ /* Unlike community plugins, core plugin and trusted plugin bugs should be handled as system errors */
73
+ export const getPluginErrorType = function (error, loadedFrom, packageName) {
74
+ if (isTrustedPluginBug(error, packageName)) {
75
+ return { type: 'trustedPlugin' };
76
+ }
65
77
  if (!isCorePluginBug(error, loadedFrom)) {
66
78
  return {};
67
79
  }
@@ -71,3 +83,7 @@ const isCorePluginBug = function (error, loadedFrom) {
71
83
  const { severity } = parseErrorInfo(error);
72
84
  return severity === 'warning' && loadedFrom === 'core';
73
85
  };
86
+ const isTrustedPluginBug = function (error, packageName) {
87
+ const { severity } = parseErrorInfo(error);
88
+ return severity === 'warning' && isTrustedPlugin(packageName);
89
+ };
package/lib/steps/get.js CHANGED
@@ -1,9 +1,11 @@
1
1
  import { getUtils } from '../plugins/child/utils.js';
2
2
  import { DEV_EVENTS, EVENTS } from '../plugins/events.js';
3
+ import { uploadBlobs } from '../plugins_core/blobs_upload/index.js';
3
4
  import { buildCommandCore } from '../plugins_core/build_command.js';
4
5
  import { deploySite } from '../plugins_core/deploy/index.js';
5
6
  import { bundleEdgeFunctions } from '../plugins_core/edge_functions/index.js';
6
7
  import { bundleFunctions } from '../plugins_core/functions/index.js';
8
+ import { preCleanup } from '../plugins_core/pre_cleanup/index.js';
7
9
  import { saveArtifacts } from '../plugins_core/save_artifacts/index.js';
8
10
  import { scanForSecrets } from '../plugins_core/secrets_scanning/index.js';
9
11
  // Get all build steps
@@ -54,7 +56,17 @@ const getEventSteps = function (eventHandlers) {
54
56
  });
55
57
  };
56
58
  const addCoreSteps = function (steps) {
57
- return [buildCommandCore, ...steps, bundleFunctions, bundleEdgeFunctions, scanForSecrets, deploySite, saveArtifacts];
59
+ return [
60
+ preCleanup,
61
+ buildCommandCore,
62
+ ...steps,
63
+ bundleFunctions,
64
+ bundleEdgeFunctions,
65
+ scanForSecrets,
66
+ uploadBlobs,
67
+ deploySite,
68
+ saveArtifacts,
69
+ ];
58
70
  };
59
71
  // Sort plugin steps by event order.
60
72
  const sortSteps = function (steps, events) {
@@ -1,4 +1,4 @@
1
- export function isTrustedPlugin(pluginPackageJson: any): any;
1
+ export function isTrustedPlugin(packageName: any): any;
2
2
  export function firePluginStep({ event, childProcess, packageName, packagePath, pluginPackageJson, loadedFrom, origin, envChanges, errorParams, configOpts, netlifyConfig, configMutations, headersPath, redirectsPath, constants, steps, error, logs, featureFlags, debug, verbose, }: {
3
3
  event: any;
4
4
  childProcess: any;
@@ -5,7 +5,7 @@ import { callChild } from '../plugins/ipc.js';
5
5
  import { getSuccessStatus } from '../status/success.js';
6
6
  import { getPluginErrorType } from './error.js';
7
7
  import { updateNetlifyConfig, listConfigSideFiles } from './update_config.js';
8
- export const isTrustedPlugin = (pluginPackageJson) => pluginPackageJson?.name?.startsWith('@netlify/');
8
+ export const isTrustedPlugin = (packageName) => packageName?.startsWith('@netlify/');
9
9
  // Fire a plugin step
10
10
  export const firePluginStep = async function ({ event, childProcess, packageName, packagePath, pluginPackageJson, loadedFrom, origin, envChanges, errorParams, configOpts, netlifyConfig, configMutations, headersPath, redirectsPath, constants, steps, error, logs, featureFlags, debug, verbose, }) {
11
11
  const listeners = pipePluginOutput(childProcess, logs);
@@ -18,7 +18,7 @@ export const firePluginStep = async function ({ event, childProcess, packageName
18
18
  event,
19
19
  error,
20
20
  envChanges,
21
- featureFlags: isTrustedPlugin(pluginPackageJson) ? featureFlags : undefined,
21
+ featureFlags: isTrustedPlugin(pluginPackageJson?.name) ? featureFlags : undefined,
22
22
  netlifyConfig,
23
23
  constants,
24
24
  },
@@ -49,7 +49,7 @@ export const firePluginStep = async function ({ event, childProcess, packageName
49
49
  };
50
50
  }
51
51
  catch (newError) {
52
- const errorType = getPluginErrorType(newError, loadedFrom);
52
+ const errorType = getPluginErrorType(newError, loadedFrom, packageName);
53
53
  addErrorInfo(newError, {
54
54
  ...errorType,
55
55
  plugin: { pluginPackageJson, packageName },
@@ -24,20 +24,20 @@ export function getStepReturn({ event, packageName, newError, newEnvChanges, new
24
24
  quiet: any;
25
25
  metrics: any;
26
26
  }): Promise<{
27
- failedPlugin: any[];
27
+ failedPlugin: string[];
28
28
  newStatus: {
29
- state: any;
30
- title: any;
31
- summary: any;
29
+ state: "failed_build" | "failed_plugin" | "canceled_build";
30
+ title: string | (import("../error/types.js").TitleFunction & string);
31
+ summary: string;
32
32
  text: string | undefined;
33
33
  extraData: any;
34
34
  };
35
35
  }> | Promise<{
36
36
  newError: any;
37
37
  newStatus: {
38
- state: any;
39
- title: any;
40
- summary: any;
38
+ state: "failed_build" | "failed_plugin" | "canceled_build";
39
+ title: string | (import("../error/types.js").TitleFunction & string);
40
+ summary: string;
41
41
  text: string | undefined;
42
42
  extraData: any;
43
43
  };
@@ -39,7 +39,7 @@ const getBuildSteps = function (buildSteps) {
39
39
  const allSteps = getSteps([]).steps.filter(({ coreStepId }) => buildSteps.includes(coreStepId));
40
40
  return allSteps;
41
41
  };
42
- const executeBuildStep = async function ({ config, packagePath, defaultConfig, cachedConfig, debug, nodePath, functionsDistDir, edgeFunctionsDistDir, errorMonitor, mode, logs, errorParams, featureFlags, buildSteps, repositoryRoot, systemLog, edgeFunctionsBootstrapURL, }) {
42
+ const executeBuildStep = async function ({ config, packagePath, defaultConfig, cachedConfig, debug, nodePath, functionsDistDir, edgeFunctionsDistDir, errorMonitor, mode, logs, errorParams, featureFlags, buildSteps, repositoryRoot, systemLog, edgeFunctionsBootstrapURL, deployId, token, quiet, }) {
43
43
  const configOpts = getConfigOpts({
44
44
  config,
45
45
  defaultConfig,
@@ -53,6 +53,7 @@ const executeBuildStep = async function ({ config, packagePath, defaultConfig, c
53
53
  cachedConfig,
54
54
  debug,
55
55
  logs,
56
+ quiet,
56
57
  nodePath,
57
58
  timers: [],
58
59
  });
@@ -64,6 +65,7 @@ const executeBuildStep = async function ({ config, packagePath, defaultConfig, c
64
65
  netlifyConfig,
65
66
  siteInfo,
66
67
  mode,
68
+ token,
67
69
  });
68
70
  Object.assign(errorParams, { netlifyConfig, siteInfo, childEnv, userNodeVersion });
69
71
  try {
@@ -80,6 +82,8 @@ const executeBuildStep = async function ({ config, packagePath, defaultConfig, c
80
82
  repositoryRoot: repositoryRootA,
81
83
  systemLog,
82
84
  edgeFunctionsBootstrapURL,
85
+ deployId,
86
+ quiet,
83
87
  });
84
88
  return {
85
89
  netlifyConfig: netlifyConfigA,
@@ -101,7 +105,7 @@ const executeBuildStep = async function ({ config, packagePath, defaultConfig, c
101
105
  throw error;
102
106
  }
103
107
  };
104
- const runBuildStep = async function ({ netlifyConfig, buildDir, nodePath, constants, logs, debug, featureFlags, childEnv, buildSteps, repositoryRoot, systemLog, edgeFunctionsBootstrapURL, }) {
108
+ const runBuildStep = async function ({ netlifyConfig, buildDir, nodePath, constants, logs, debug, featureFlags, childEnv, buildSteps, repositoryRoot, systemLog, edgeFunctionsBootstrapURL, deployId, quiet, }) {
105
109
  const { netlifyConfig: netlifyConfigA, configMutations } = await runSteps({
106
110
  steps: getBuildSteps(buildSteps),
107
111
  buildDir,
@@ -116,6 +120,8 @@ const runBuildStep = async function ({ netlifyConfig, buildDir, nodePath, consta
116
120
  repositoryRoot,
117
121
  systemLog,
118
122
  edgeFunctionsBootstrapURL,
123
+ deployId,
124
+ quiet,
119
125
  });
120
126
  return { netlifyConfig: netlifyConfigA, configMutations };
121
127
  };
@@ -40,6 +40,7 @@ export const runStep = async function ({ event, childProcess, packageName, coreS
40
40
  buildDir,
41
41
  saveConfig,
42
42
  explicitSecretKeys,
43
+ deployId,
43
44
  });
44
45
  span.setAttribute('build.execution.step.should_run', shouldRun);
45
46
  if (!shouldRun) {
@@ -77,6 +78,7 @@ export const runStep = async function ({ event, childProcess, packageName, coreS
77
78
  error,
78
79
  logs,
79
80
  debug,
81
+ quiet,
80
82
  systemLog,
81
83
  verbose,
82
84
  saveConfig,
@@ -91,6 +93,7 @@ export const runStep = async function ({ event, childProcess, packageName, coreS
91
93
  userNodeVersion,
92
94
  explicitSecretKeys,
93
95
  edgeFunctionsBootstrapURL,
96
+ deployId,
94
97
  });
95
98
  const newValues = await getStepReturn({
96
99
  event,
@@ -153,7 +156,7 @@ export const runStep = async function ({ event, childProcess, packageName, coreS
153
156
  // or available. However, one might be created by a build plugin, in which case,
154
157
  // those core plugins should be triggered. We use a dynamic `condition()` to
155
158
  // model this behavior.
156
- const shouldRunStep = async function ({ event, packageName, error, packagePath, failedPlugins, netlifyConfig, condition, constants, buildbotServerSocket, buildDir, saveConfig, explicitSecretKeys, }) {
159
+ const shouldRunStep = async function ({ event, packageName, error, packagePath, failedPlugins, netlifyConfig, condition, constants, buildbotServerSocket, buildDir, saveConfig, explicitSecretKeys, deployId, }) {
157
160
  if (failedPlugins.includes(packageName) ||
158
161
  (condition !== undefined &&
159
162
  !(await condition({
@@ -164,6 +167,7 @@ const shouldRunStep = async function ({ event, packageName, error, packagePath,
164
167
  netlifyConfig,
165
168
  saveConfig,
166
169
  explicitSecretKeys,
170
+ deployId,
167
171
  })))) {
168
172
  return false;
169
173
  }
@@ -180,7 +184,7 @@ const getFireStep = function (packageName, coreStepId, event) {
180
184
  const parentTag = normalizeTagName(packageName);
181
185
  return measureDuration(tFireStep, event, { parentTag, category: 'pluginEvent' });
182
186
  };
183
- const tFireStep = function ({ event, childProcess, packageName, pluginPackageJson, loadedFrom, origin, coreStep, coreStepId, coreStepName, configPath, outputConfigPath, buildDir, repositoryRoot, packagePath, nodePath, childEnv, context, branch, envChanges, constants, steps, buildbotServerSocket, events, error, logs, debug, systemLog, verbose, saveConfig, errorParams, configOpts, netlifyConfig, configMutations, headersPath, redirectsPath, featureFlags, userNodeVersion, explicitSecretKeys, edgeFunctionsBootstrapURL, }) {
187
+ const tFireStep = function ({ event, childProcess, packageName, pluginPackageJson, loadedFrom, origin, coreStep, coreStepId, coreStepName, configPath, outputConfigPath, buildDir, repositoryRoot, packagePath, nodePath, childEnv, context, branch, envChanges, constants, steps, buildbotServerSocket, events, error, logs, debug, quiet, systemLog, verbose, saveConfig, errorParams, configOpts, netlifyConfig, configMutations, headersPath, redirectsPath, featureFlags, userNodeVersion, explicitSecretKeys, edgeFunctionsBootstrapURL, deployId, }) {
184
188
  if (coreStep !== undefined) {
185
189
  return fireCoreStep({
186
190
  coreStep,
@@ -195,6 +199,7 @@ const tFireStep = function ({ event, childProcess, packageName, pluginPackageJso
195
199
  buildbotServerSocket,
196
200
  events,
197
201
  logs,
202
+ quiet,
198
203
  nodePath,
199
204
  childEnv,
200
205
  context,
@@ -213,6 +218,7 @@ const tFireStep = function ({ event, childProcess, packageName, pluginPackageJso
213
218
  userNodeVersion,
214
219
  explicitSecretKeys,
215
220
  edgeFunctionsBootstrapURL,
221
+ deployId,
216
222
  });
217
223
  }
218
224
  return firePluginStep({
@@ -0,0 +1,8 @@
1
+ export declare const getBlobsDir: ({ buildDir, publishDir }: {
2
+ buildDir: any;
3
+ publishDir: any;
4
+ }) => string;
5
+ export declare const anyBlobsToUpload: ({ buildDir, publishDir }: {
6
+ buildDir: any;
7
+ publishDir: any;
8
+ }) => Promise<boolean>;
@@ -0,0 +1,11 @@
1
+ import path from 'node:path';
2
+ import { fdir } from 'fdir';
3
+ const BLOBS_PATH = '.netlify/blobs/deploy';
4
+ export const getBlobsDir = function ({ buildDir, publishDir }) {
5
+ return path.resolve(buildDir, publishDir, BLOBS_PATH);
6
+ };
7
+ export const anyBlobsToUpload = async function ({ buildDir, publishDir }) {
8
+ const blobsDir = getBlobsDir({ buildDir, publishDir });
9
+ const { files } = await new fdir().onlyCounts().crawl(blobsDir).withPromise();
10
+ return files > 0;
11
+ };
@@ -1 +1,7 @@
1
- export function addAsyncErrorMessage(asyncFunc: any, message: any): (...args: any[]) => Promise<any>;
1
+ type asyncFunction<T> = (...args: unknown[]) => Promise<T>;
2
+ /**
3
+ * Wrap an async function so it prepends an error message on exceptions.
4
+ * This helps locate errors.
5
+ */
6
+ export declare const addAsyncErrorMessage: <T>(asyncFunc: asyncFunction<T>, message: string) => asyncFunction<T>;
7
+ export {};
@@ -1,5 +1,7 @@
1
- // Wrap an async function so it prepends an error message on exceptions.
2
- // This helps locate errors.
1
+ /**
2
+ * Wrap an async function so it prepends an error message on exceptions.
3
+ * This helps locate errors.
4
+ */
3
5
  export const addAsyncErrorMessage = function (asyncFunc, message) {
4
6
  return async (...args) => {
5
7
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@netlify/build",
3
- "version": "29.28.1",
3
+ "version": "29.29.0",
4
4
  "description": "Netlify build module",
5
5
  "type": "module",
6
6
  "exports": "./lib/index.js",
@@ -66,6 +66,7 @@
66
66
  "dependencies": {
67
67
  "@bugsnag/js": "^7.0.0",
68
68
  "@honeycombio/opentelemetry-node": "^0.5.0",
69
+ "@netlify/blobs": "^6.3.1",
69
70
  "@netlify/cache-utils": "^5.1.5",
70
71
  "@netlify/config": "^20.10.0",
71
72
  "@netlify/edge-bundler": "10.1.3",
@@ -95,11 +96,13 @@
95
96
  "log-process-errors": "^8.0.0",
96
97
  "map-obj": "^5.0.0",
97
98
  "memoize-one": "^6.0.0",
99
+ "node-fetch": "^3.3.2",
98
100
  "os-name": "^5.0.0",
99
101
  "p-event": "^5.0.0",
100
102
  "p-every": "^2.0.0",
101
103
  "p-filter": "^3.0.0",
102
104
  "p-locate": "^6.0.0",
105
+ "p-map": "^6.0.0",
103
106
  "p-reduce": "^3.0.0",
104
107
  "path-exists": "^5.0.0",
105
108
  "path-type": "^5.0.0",
@@ -154,5 +157,5 @@
154
157
  "engines": {
155
158
  "node": "^14.16.0 || >=16.0.0"
156
159
  },
157
- "gitHead": "5aef135bf29606313b5e2547c4c7d77c8ff64d56"
160
+ "gitHead": "e8dbd893dbc701ebbcb1df50133a7c0353bdbc8c"
158
161
  }