@netlify/build 27.12.1-beta → 27.13.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/src/core/main.js CHANGED
@@ -1,29 +1,12 @@
1
- /* eslint-disable max-lines, import/max-dependencies */
2
1
  import { handleBuildError } from '../error/handle.js'
3
- import { getErrorInfo } from '../error/info.js'
4
- import { startErrorMonitor } from '../error/monitor/start.js'
5
- import { getBufferLogs, getSystemLogger } from '../log/logger.js'
6
- import { logBuildStart, logTimer, logBuildSuccess } from '../log/messages/core.js'
7
- import { loadPlugins } from '../plugins/load.js'
8
- import { getPluginsOptions } from '../plugins/options.js'
9
- import { pinPlugins } from '../plugins/pinned_version.js'
10
- import { startPlugins, stopPlugins } from '../plugins/spawn.js'
11
- import { addCorePlugins } from '../plugins_core/add.js'
12
- import { reportStatuses } from '../status/report.js'
13
- import { getSteps } from '../steps/get.js'
14
- import { runSteps } from '../steps/run_steps.js'
2
+ import { logTimer, logBuildSuccess } from '../log/messages/core.js'
15
3
  import { trackBuildComplete } from '../telemetry/main.js'
16
- import { initTimers, measureDuration } from '../time/main.js'
17
4
  import { reportTimers } from '../time/report.js'
18
5
 
19
- import { getConfigOpts, loadConfig } from './config.js'
20
- import { getConstants } from './constants.js'
21
- import { doDryRun } from './dry.js'
22
- import { warnOnLingeringProcesses } from './lingering.js'
23
- import { warnOnMissingSideFiles } from './missing_side_file.js'
24
- import { normalizeFlags } from './normalize_flags.js'
6
+ import { execBuild, startBuild } from './build.js'
25
7
  import { getSeverity } from './severity.js'
26
8
 
9
+ export { startDev } from './dev.js'
27
10
  export { runCoreSteps } from '../steps/run_core_steps.js'
28
11
 
29
12
  /**
@@ -135,526 +118,6 @@ export default async function buildSite(flags = {}) {
135
118
  }
136
119
  }
137
120
 
138
- // Performed on build start. Must be kept small and unlikely to fail since it
139
- // does not have proper error handling. Error handling relies on `errorMonitor`
140
- // being built, which relies itself on flags being normalized.
141
- const startBuild = function (flags) {
142
- const timers = initTimers()
143
-
144
- const logs = getBufferLogs(flags)
145
- logBuildStart(logs)
146
-
147
- const { bugsnagKey, ...flagsA } = normalizeFlags(flags, logs)
148
- const errorMonitor = startErrorMonitor({ flags: flagsA, logs, bugsnagKey })
149
-
150
- return { ...flagsA, errorMonitor, logs, timers }
151
- }
152
-
153
- const tExecBuild = async function ({
154
- config,
155
- defaultConfig,
156
- cachedConfig,
157
- cachedConfigPath,
158
- cwd,
159
- repositoryRoot,
160
- apiHost,
161
- token,
162
- siteId,
163
- context,
164
- branch,
165
- baseRelDir,
166
- env: envOpt,
167
- debug,
168
- systemLogFile,
169
- verbose,
170
- nodePath,
171
- functionsDistDir,
172
- edgeFunctionsDistDir,
173
- cacheDir,
174
- dry,
175
- mode,
176
- offline,
177
- deployId,
178
- buildId,
179
- testOpts,
180
- errorMonitor,
181
- errorParams,
182
- logs,
183
- timers,
184
- buildbotServerSocket,
185
- sendStatus,
186
- saveConfig,
187
- featureFlags,
188
- }) {
189
- const configOpts = getConfigOpts({
190
- config,
191
- defaultConfig,
192
- cwd,
193
- repositoryRoot,
194
- apiHost,
195
- token,
196
- siteId,
197
- context,
198
- branch,
199
- baseRelDir,
200
- envOpt,
201
- mode,
202
- offline,
203
- deployId,
204
- buildId,
205
- testOpts,
206
- featureFlags,
207
- })
208
- const {
209
- netlifyConfig,
210
- configPath,
211
- headersPath,
212
- redirectsPath,
213
- buildDir,
214
- repositoryRoot: repositoryRootA,
215
- packageJson,
216
- userNodeVersion,
217
- childEnv,
218
- context: contextA,
219
- branch: branchA,
220
- token: tokenA,
221
- api,
222
- siteInfo,
223
- timers: timersA,
224
- } = await loadConfig({
225
- configOpts,
226
- cachedConfig,
227
- cachedConfigPath,
228
- envOpt,
229
- debug,
230
- logs,
231
- nodePath,
232
- timers,
233
- })
234
- const constants = await getConstants({
235
- configPath,
236
- buildDir,
237
- functionsDistDir,
238
- edgeFunctionsDistDir,
239
- cacheDir,
240
- netlifyConfig,
241
- siteInfo,
242
- apiHost,
243
- token: tokenA,
244
- mode,
245
- testOpts,
246
- })
247
- const systemLog = getSystemLogger(logs, debug, systemLogFile)
248
- const pluginsOptions = addCorePlugins({ netlifyConfig, constants })
249
- // `errorParams` is purposely stateful
250
- // eslint-disable-next-line fp/no-mutating-assign
251
- Object.assign(errorParams, { netlifyConfig, pluginsOptions, siteInfo, childEnv, userNodeVersion })
252
-
253
- const {
254
- pluginsOptions: pluginsOptionsA,
255
- netlifyConfig: netlifyConfigA,
256
- stepsCount,
257
- timers: timersB,
258
- configMutations,
259
- } = await runAndReportBuild({
260
- pluginsOptions,
261
- netlifyConfig,
262
- configOpts,
263
- siteInfo,
264
- configPath,
265
- headersPath,
266
- redirectsPath,
267
- buildDir,
268
- repositoryRoot: repositoryRootA,
269
- nodePath,
270
- packageJson,
271
- userNodeVersion,
272
- childEnv,
273
- context: contextA,
274
- branch: branchA,
275
- dry,
276
- mode,
277
- api,
278
- errorMonitor,
279
- deployId,
280
- errorParams,
281
- logs,
282
- debug,
283
- systemLog,
284
- verbose,
285
- timers: timersA,
286
- sendStatus,
287
- saveConfig,
288
- testOpts,
289
- buildbotServerSocket,
290
- constants,
291
- featureFlags,
292
- })
293
- return {
294
- pluginsOptions: pluginsOptionsA,
295
- netlifyConfig: netlifyConfigA,
296
- siteInfo,
297
- userNodeVersion,
298
- stepsCount,
299
- timers: timersB,
300
- configMutations,
301
- }
302
- }
303
-
304
- const execBuild = measureDuration(tExecBuild, 'total', { parentTag: 'build_site' })
305
-
306
- // Runs a build then report any plugin statuses
307
- const runAndReportBuild = async function ({
308
- pluginsOptions,
309
- netlifyConfig,
310
- configOpts,
311
- siteInfo,
312
- configPath,
313
- headersPath,
314
- redirectsPath,
315
- buildDir,
316
- repositoryRoot,
317
- nodePath,
318
- packageJson,
319
- userNodeVersion,
320
- childEnv,
321
- context,
322
- branch,
323
- buildbotServerSocket,
324
- constants,
325
- dry,
326
- mode,
327
- api,
328
- errorMonitor,
329
- deployId,
330
- errorParams,
331
- logs,
332
- debug,
333
- systemLog,
334
- verbose,
335
- timers,
336
- sendStatus,
337
- saveConfig,
338
- testOpts,
339
- featureFlags,
340
- }) {
341
- try {
342
- const {
343
- stepsCount,
344
- netlifyConfig: netlifyConfigA,
345
- statuses,
346
- pluginsOptions: pluginsOptionsA,
347
- failedPlugins,
348
- timers: timersA,
349
- configMutations,
350
- } = await initAndRunBuild({
351
- pluginsOptions,
352
- netlifyConfig,
353
- configOpts,
354
- siteInfo,
355
- configPath,
356
- headersPath,
357
- redirectsPath,
358
- buildDir,
359
- repositoryRoot,
360
- nodePath,
361
- packageJson,
362
- userNodeVersion,
363
- childEnv,
364
- context,
365
- branch,
366
- dry,
367
- mode,
368
- api,
369
- errorMonitor,
370
- deployId,
371
- errorParams,
372
- logs,
373
- debug,
374
- systemLog,
375
- verbose,
376
- timers,
377
- sendStatus,
378
- saveConfig,
379
- testOpts,
380
- buildbotServerSocket,
381
- constants,
382
- featureFlags,
383
- })
384
- await Promise.all([
385
- reportStatuses({
386
- statuses,
387
- childEnv,
388
- api,
389
- mode,
390
- pluginsOptions: pluginsOptionsA,
391
- netlifyConfig: netlifyConfigA,
392
- errorMonitor,
393
- deployId,
394
- logs,
395
- debug,
396
- sendStatus,
397
- testOpts,
398
- }),
399
- pinPlugins({
400
- pluginsOptions: pluginsOptionsA,
401
- failedPlugins,
402
- api,
403
- siteInfo,
404
- childEnv,
405
- mode,
406
- netlifyConfig: netlifyConfigA,
407
- errorMonitor,
408
- logs,
409
- debug,
410
- testOpts,
411
- sendStatus,
412
- }),
413
- ])
414
-
415
- return {
416
- pluginsOptions: pluginsOptionsA,
417
- netlifyConfig: netlifyConfigA,
418
- stepsCount,
419
- timers: timersA,
420
- configMutations,
421
- }
422
- } catch (error) {
423
- const [{ statuses }] = getErrorInfo(error)
424
- await reportStatuses({
425
- statuses,
426
- childEnv,
427
- api,
428
- mode,
429
- pluginsOptions,
430
- netlifyConfig,
431
- errorMonitor,
432
- deployId,
433
- logs,
434
- debug,
435
- sendStatus,
436
- testOpts,
437
- })
438
- throw error
439
- }
440
- }
441
-
442
- // Initialize plugin processes then runs a build
443
- const initAndRunBuild = async function ({
444
- pluginsOptions,
445
- netlifyConfig,
446
- configOpts,
447
- siteInfo,
448
- configPath,
449
- headersPath,
450
- redirectsPath,
451
- buildDir,
452
- repositoryRoot,
453
- nodePath,
454
- packageJson,
455
- userNodeVersion,
456
- childEnv,
457
- context,
458
- branch,
459
- dry,
460
- mode,
461
- api,
462
- errorMonitor,
463
- deployId,
464
- errorParams,
465
- logs,
466
- debug,
467
- systemLog,
468
- verbose,
469
- sendStatus,
470
- saveConfig,
471
- timers,
472
- testOpts,
473
- buildbotServerSocket,
474
- constants,
475
- featureFlags,
476
- }) {
477
- const { pluginsOptions: pluginsOptionsA, timers: timersA } = await getPluginsOptions({
478
- pluginsOptions,
479
- netlifyConfig,
480
- siteInfo,
481
- buildDir,
482
- nodePath,
483
- packageJson,
484
- userNodeVersion,
485
- mode,
486
- api,
487
- logs,
488
- debug,
489
- sendStatus,
490
- timers,
491
- testOpts,
492
- featureFlags,
493
- })
494
- // eslint-disable-next-line fp/no-mutation, no-param-reassign
495
- errorParams.pluginsOptions = pluginsOptionsA
496
-
497
- const { childProcesses, timers: timersB } = await startPlugins({
498
- pluginsOptions: pluginsOptionsA,
499
- buildDir,
500
- childEnv,
501
- logs,
502
- debug,
503
- timers: timersA,
504
- })
505
-
506
- try {
507
- const {
508
- stepsCount,
509
- netlifyConfig: netlifyConfigA,
510
- statuses,
511
- failedPlugins,
512
- timers: timersC,
513
- configMutations,
514
- } = await runBuild({
515
- childProcesses,
516
- pluginsOptions: pluginsOptionsA,
517
- netlifyConfig,
518
- configOpts,
519
- packageJson,
520
- configPath,
521
- headersPath,
522
- redirectsPath,
523
- buildDir,
524
- repositoryRoot,
525
- nodePath,
526
- childEnv,
527
- context,
528
- branch,
529
- dry,
530
- buildbotServerSocket,
531
- constants,
532
- mode,
533
- api,
534
- errorMonitor,
535
- deployId,
536
- errorParams,
537
- logs,
538
- debug,
539
- systemLog,
540
- verbose,
541
- saveConfig,
542
- timers: timersB,
543
- testOpts,
544
- featureFlags,
545
- })
546
-
547
- await Promise.all([
548
- warnOnMissingSideFiles({ buildDir, netlifyConfig: netlifyConfigA, logs }),
549
- warnOnLingeringProcesses({ mode, logs, testOpts }),
550
- ])
551
-
552
- return {
553
- stepsCount,
554
- netlifyConfig: netlifyConfigA,
555
- statuses,
556
- pluginsOptions: pluginsOptionsA,
557
- failedPlugins,
558
- timers: timersC,
559
- configMutations,
560
- }
561
- } finally {
562
- stopPlugins(childProcesses)
563
- }
564
- }
565
-
566
- // Load plugin main files, retrieve their event handlers then runs them,
567
- // together with the build command
568
- const runBuild = async function ({
569
- childProcesses,
570
- pluginsOptions,
571
- netlifyConfig,
572
- configOpts,
573
- packageJson,
574
- configPath,
575
- headersPath,
576
- redirectsPath,
577
- buildDir,
578
- repositoryRoot,
579
- nodePath,
580
- childEnv,
581
- context,
582
- branch,
583
- dry,
584
- buildbotServerSocket,
585
- constants,
586
- mode,
587
- api,
588
- errorMonitor,
589
- deployId,
590
- errorParams,
591
- logs,
592
- debug,
593
- systemLog,
594
- verbose,
595
- saveConfig,
596
- timers,
597
- testOpts,
598
- featureFlags,
599
- }) {
600
- const { pluginsSteps, timers: timersA } = await loadPlugins({
601
- pluginsOptions,
602
- childProcesses,
603
- packageJson,
604
- timers,
605
- logs,
606
- debug,
607
- verbose,
608
- })
609
-
610
- const { steps, events } = getSteps(pluginsSteps)
611
-
612
- if (dry) {
613
- await doDryRun({ buildDir, steps, netlifyConfig, constants, buildbotServerSocket, logs })
614
- return { netlifyConfig }
615
- }
616
-
617
- const {
618
- stepsCount,
619
- netlifyConfig: netlifyConfigA,
620
- statuses,
621
- failedPlugins,
622
- timers: timersB,
623
- configMutations,
624
- } = await runSteps({
625
- steps,
626
- buildbotServerSocket,
627
- events,
628
- configPath,
629
- headersPath,
630
- redirectsPath,
631
- buildDir,
632
- repositoryRoot,
633
- nodePath,
634
- childEnv,
635
- context,
636
- branch,
637
- constants,
638
- mode,
639
- api,
640
- errorMonitor,
641
- deployId,
642
- errorParams,
643
- netlifyConfig,
644
- configOpts,
645
- logs,
646
- debug,
647
- systemLog,
648
- verbose,
649
- saveConfig,
650
- timers: timersA,
651
- testOpts,
652
- featureFlags,
653
- })
654
-
655
- return { stepsCount, netlifyConfig: netlifyConfigA, statuses, failedPlugins, timers: timersB, configMutations }
656
- }
657
-
658
121
  // Logs and reports that a build successfully ended
659
122
  const handleBuildSuccess = async function ({ framework, dry, logs, timers, durationNs, statsdOpts }) {
660
123
  if (dry) {
@@ -700,4 +163,3 @@ const telemetryReport = async function ({
700
163
  await handleBuildError(error, errorParams)
701
164
  }
702
165
  }
703
- /* eslint-enable max-lines, import/max-dependencies */
@@ -53,6 +53,7 @@ const getDefaultFlags = function ({ env: envOpt = {} }, combinedEnv) {
53
53
  testOpts: {},
54
54
  featureFlags: DEFAULT_FEATURE_FLAGS,
55
55
  statsd: { port: DEFAULT_STATSD_PORT },
56
+ timeline: 'build',
56
57
  }
57
58
  }
58
59
 
@@ -5,9 +5,20 @@ import { getPluginOrigin } from '../description.js'
5
5
  import { logArray, logSubHeader, logWarningArray, logWarningSubHeader } from '../logger.js'
6
6
  import { THEME } from '../theme.js'
7
7
 
8
+ export const logRuntime = (logs, pluginOptions) => {
9
+ const runtimes = pluginOptions.filter(isRuntime)
10
+
11
+ // Once we have more runtimes, this hardcoded check should be removed
12
+ if (runtimes.length > 1) {
13
+ logSubHeader(logs, 'Using Next.js Runtime')
14
+ }
15
+ }
16
+
8
17
  export const logLoadingPlugins = function (logs, pluginsOptions, debug) {
9
18
  const loadingPlugins = pluginsOptions
10
19
  .filter(isNotCorePlugin)
20
+ // We don't want to show runtimes as plugins
21
+ .filter((plugin) => !isRuntime(plugin))
11
22
  .map((pluginOptions) => getPluginDescription(pluginOptions, debug))
12
23
 
13
24
  if (loadingPlugins.length === 0) {
@@ -23,6 +34,11 @@ const isNotCorePlugin = function ({ origin }) {
23
34
  return origin !== 'core'
24
35
  }
25
36
 
37
+ const isRuntime = function ({ packageName }) {
38
+ // Make this a bit more robust in the future
39
+ return ['@netlify/next-runtime'].includes(packageName)
40
+ }
41
+
26
42
  const getPluginDescription = function (
27
43
  {
28
44
  packageName,
@@ -52,6 +52,8 @@ const INTERNAL_FLAGS = [
52
52
  'mode',
53
53
  'apiHost',
54
54
  'cacheDir',
55
+ 'systemLogFile',
56
+ 'timeline',
55
57
  ]
56
58
  const HIDDEN_FLAGS = [...SECURE_FLAGS, ...TEST_FLAGS, ...INTERNAL_FLAGS]
57
59
  const HIDDEN_DEBUG_FLAGS = [...SECURE_FLAGS, ...TEST_FLAGS]
@@ -1,6 +1,6 @@
1
1
  import { addErrorInfo } from '../../error/info.js'
2
2
  import { serializeArray } from '../../log/serialize.js'
3
- import { EVENTS } from '../events.js'
3
+ import { DEV_EVENTS, EVENTS } from '../events.js'
4
4
 
5
5
  // Validate the shape of a plugin return value
6
6
  export const validatePlugin = function (logic) {
@@ -22,7 +22,7 @@ export const validatePlugin = function (logic) {
22
22
 
23
23
  // All other properties are event handlers
24
24
  const validateEventHandler = function (value, propName) {
25
- if (!EVENTS.includes(propName)) {
25
+ if (!EVENTS.includes(propName) && !DEV_EVENTS.includes(propName)) {
26
26
  throw new Error(`Invalid event '${propName}'.
27
27
  Please use a valid event name. One of:
28
28
  ${serializeArray(EVENTS)}`)
@@ -1,4 +1,4 @@
1
- export { EVENTS } from '@netlify/config'
1
+ export { DEV_EVENTS, EVENTS } from '@netlify/config'
2
2
 
3
3
  const isAmongEvents = function (events, event) {
4
4
  return events.includes(event)
@@ -3,7 +3,12 @@ import { fileURLToPath } from 'url'
3
3
  import { execaNode } from 'execa'
4
4
 
5
5
  import { addErrorInfo } from '../error/info.js'
6
- import { logLoadingPlugins, logOutdatedPlugins, logIncompatiblePlugins } from '../log/messages/compatibility.js'
6
+ import {
7
+ logRuntime,
8
+ logLoadingPlugins,
9
+ logOutdatedPlugins,
10
+ logIncompatiblePlugins,
11
+ } from '../log/messages/compatibility.js'
7
12
  import { measureDuration } from '../time/main.js'
8
13
 
9
14
  import { getEventFromChild } from './ipc.js'
@@ -18,6 +23,7 @@ const CHILD_MAIN_FILE = fileURLToPath(new URL('child/main.js', import.meta.url))
18
23
  // - logs can be buffered which allows manipulating them for log shipping,
19
24
  // transforming and parallel plugins
20
25
  const tStartPlugins = async function ({ pluginsOptions, buildDir, childEnv, logs, debug }) {
26
+ logRuntime(logs, pluginsOptions)
21
27
  logLoadingPlugins(logs, pluginsOptions, debug)
22
28
  logOutdatedPlugins(logs, pluginsOptions)
23
29
  logIncompatiblePlugins(logs, pluginsOptions)
@@ -84,7 +84,18 @@ const getDeployDir = function ({ buildDir, repositoryRoot, constants: { PUBLISH_
84
84
 
85
85
  // We distinguish between user errors and system errors during deploys
86
86
  const handleDeployError = function (error, errorType) {
87
- const errorA = new Error(`Deploy did not succeed: ${error}`)
87
+ const errorIs422 = error !== undefined && error.code === '422'
88
+
89
+ const errMsg = errorIs422
90
+ ? `
91
+ File upload failed because of mismatched SHAs.
92
+ This can happen when files are changed after the deployment process has started but before they are uploaded.
93
+
94
+ Error: ${error}
95
+ `
96
+ : `Deploy did not succeed: ${error}`
97
+
98
+ const errorA = new Error(errMsg)
88
99
  const errorInfo =
89
100
  errorType === 'user' ? { type: 'resolveConfig' } : { type: 'coreStep', location: { coreStepName: 'Deploy site' } }
90
101
  addErrorInfo(errorA, errorInfo)