@netlify/build 28.0.0-beta → 28.0.0-rc
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/package.json +8 -6
- package/src/core/flags.js +5 -0
- package/src/core/main.js +12 -1
- package/src/error/monitor/normalize.js +23 -4
- package/src/error/monitor/report.js +7 -2
- package/src/error/parse/location.js +6 -2
- package/src/error/type.js +8 -1
- package/src/log/logger.js +35 -0
- package/src/plugins/child/status.js +10 -3
- package/src/plugins_core/edge_functions/index.js +22 -7
- package/src/plugins_core/edge_functions/lib/error.js +21 -0
- package/src/plugins_core/edge_functions/validate_manifest/validate_edge_functions_manifest.js +89 -0
- package/src/status/report.js +11 -2
- package/src/steps/core_step.js +2 -0
- package/src/steps/run_step.js +6 -0
- package/src/steps/run_steps.js +2 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/build",
|
|
3
|
-
"version": "28.0.0-
|
|
3
|
+
"version": "28.0.0-rc",
|
|
4
4
|
"description": "Netlify build module",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": "./src/core/main.js",
|
|
@@ -56,16 +56,18 @@
|
|
|
56
56
|
"license": "MIT",
|
|
57
57
|
"dependencies": {
|
|
58
58
|
"@bugsnag/js": "^7.0.0",
|
|
59
|
-
"@netlify/edge-bundler": "^1.
|
|
59
|
+
"@netlify/edge-bundler": "^1.8.0",
|
|
60
60
|
"@netlify/cache-utils": "^4.0.0",
|
|
61
|
-
"@netlify/config": "^18.1.
|
|
62
|
-
"@netlify/functions-utils": "^4.2.
|
|
61
|
+
"@netlify/config": "^18.1.2",
|
|
62
|
+
"@netlify/functions-utils": "^4.2.2",
|
|
63
63
|
"@netlify/git-utils": "^4.0.0",
|
|
64
|
-
"@netlify/plugins-list": "^6.
|
|
64
|
+
"@netlify/plugins-list": "^6.35.0",
|
|
65
65
|
"@netlify/run-utils": "^4.0.0",
|
|
66
|
-
"@netlify/zip-it-and-ship-it": "
|
|
66
|
+
"@netlify/zip-it-and-ship-it": "5.13.2",
|
|
67
67
|
"@sindresorhus/slugify": "^2.0.0",
|
|
68
68
|
"@types/node": "^16.0.0",
|
|
69
|
+
"ajv": "^8.11.0",
|
|
70
|
+
"ajv-errors": "^3.0.0",
|
|
69
71
|
"ansi-escapes": "^5.0.0",
|
|
70
72
|
"chalk": "^5.0.0",
|
|
71
73
|
"clean-stack": "^4.0.0",
|
package/src/core/flags.js
CHANGED
|
@@ -145,6 +145,11 @@ Default: false`,
|
|
|
145
145
|
describe: 'Print user-facing debugging information',
|
|
146
146
|
hidden: true,
|
|
147
147
|
},
|
|
148
|
+
systemLogFile: {
|
|
149
|
+
type: 'number',
|
|
150
|
+
describe: 'File descriptor to where system logs should be piped',
|
|
151
|
+
hidden: true,
|
|
152
|
+
},
|
|
148
153
|
verbose: {
|
|
149
154
|
boolean: true,
|
|
150
155
|
describe: 'Print internal debugging information',
|
package/src/core/main.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { handleBuildError } from '../error/handle.js'
|
|
3
3
|
import { getErrorInfo } from '../error/info.js'
|
|
4
4
|
import { startErrorMonitor } from '../error/monitor/start.js'
|
|
5
|
-
import { getBufferLogs } from '../log/logger.js'
|
|
5
|
+
import { getBufferLogs, getSystemLogger } from '../log/logger.js'
|
|
6
6
|
import { logBuildStart, logTimer, logBuildSuccess } from '../log/messages/core.js'
|
|
7
7
|
import { loadPlugins } from '../plugins/load.js'
|
|
8
8
|
import { getPluginsOptions } from '../plugins/options.js'
|
|
@@ -57,6 +57,7 @@ export default async function buildSite(flags = {}) {
|
|
|
57
57
|
mode,
|
|
58
58
|
logs,
|
|
59
59
|
debug,
|
|
60
|
+
systemLogFile,
|
|
60
61
|
testOpts,
|
|
61
62
|
statsdOpts,
|
|
62
63
|
dry,
|
|
@@ -80,6 +81,7 @@ export default async function buildSite(flags = {}) {
|
|
|
80
81
|
} = await execBuild({
|
|
81
82
|
...flagsA,
|
|
82
83
|
buildId,
|
|
84
|
+
systemLogFile,
|
|
83
85
|
deployId,
|
|
84
86
|
dry,
|
|
85
87
|
errorMonitor,
|
|
@@ -163,6 +165,7 @@ const tExecBuild = async function ({
|
|
|
163
165
|
baseRelDir,
|
|
164
166
|
env: envOpt,
|
|
165
167
|
debug,
|
|
168
|
+
systemLogFile,
|
|
166
169
|
verbose,
|
|
167
170
|
nodePath,
|
|
168
171
|
functionsDistDir,
|
|
@@ -241,6 +244,7 @@ const tExecBuild = async function ({
|
|
|
241
244
|
mode,
|
|
242
245
|
testOpts,
|
|
243
246
|
})
|
|
247
|
+
const systemLog = getSystemLogger(logs, debug, systemLogFile)
|
|
244
248
|
const pluginsOptions = addCorePlugins({ netlifyConfig, constants })
|
|
245
249
|
// `errorParams` is purposely stateful
|
|
246
250
|
// eslint-disable-next-line fp/no-mutating-assign
|
|
@@ -276,6 +280,7 @@ const tExecBuild = async function ({
|
|
|
276
280
|
errorParams,
|
|
277
281
|
logs,
|
|
278
282
|
debug,
|
|
283
|
+
systemLog,
|
|
279
284
|
verbose,
|
|
280
285
|
timers: timersA,
|
|
281
286
|
sendStatus,
|
|
@@ -325,6 +330,7 @@ const runAndReportBuild = async function ({
|
|
|
325
330
|
errorParams,
|
|
326
331
|
logs,
|
|
327
332
|
debug,
|
|
333
|
+
systemLog,
|
|
328
334
|
verbose,
|
|
329
335
|
timers,
|
|
330
336
|
sendStatus,
|
|
@@ -365,6 +371,7 @@ const runAndReportBuild = async function ({
|
|
|
365
371
|
errorParams,
|
|
366
372
|
logs,
|
|
367
373
|
debug,
|
|
374
|
+
systemLog,
|
|
368
375
|
verbose,
|
|
369
376
|
timers,
|
|
370
377
|
sendStatus,
|
|
@@ -457,6 +464,7 @@ const initAndRunBuild = async function ({
|
|
|
457
464
|
errorParams,
|
|
458
465
|
logs,
|
|
459
466
|
debug,
|
|
467
|
+
systemLog,
|
|
460
468
|
verbose,
|
|
461
469
|
sendStatus,
|
|
462
470
|
saveConfig,
|
|
@@ -528,6 +536,7 @@ const initAndRunBuild = async function ({
|
|
|
528
536
|
errorParams,
|
|
529
537
|
logs,
|
|
530
538
|
debug,
|
|
539
|
+
systemLog,
|
|
531
540
|
verbose,
|
|
532
541
|
saveConfig,
|
|
533
542
|
timers: timersB,
|
|
@@ -581,6 +590,7 @@ const runBuild = async function ({
|
|
|
581
590
|
errorParams,
|
|
582
591
|
logs,
|
|
583
592
|
debug,
|
|
593
|
+
systemLog,
|
|
584
594
|
verbose,
|
|
585
595
|
saveConfig,
|
|
586
596
|
timers,
|
|
@@ -634,6 +644,7 @@ const runBuild = async function ({
|
|
|
634
644
|
configOpts,
|
|
635
645
|
logs,
|
|
636
646
|
debug,
|
|
647
|
+
systemLog,
|
|
637
648
|
verbose,
|
|
638
649
|
saveConfig,
|
|
639
650
|
timers: timersA,
|
|
@@ -3,7 +3,15 @@
|
|
|
3
3
|
// them consistent
|
|
4
4
|
export const normalizeGroupingMessage = function (message, type) {
|
|
5
5
|
const messageA = removeDependenciesLogs(message, type)
|
|
6
|
-
|
|
6
|
+
const messageB = NORMALIZE_REGEXPS.reduce(normalizeMessage, messageA)
|
|
7
|
+
|
|
8
|
+
// If this is a functions bundling error, we'll use additional normalization
|
|
9
|
+
// rules to group errors more aggressively.
|
|
10
|
+
if (type === 'functionsBundling') {
|
|
11
|
+
return FUNCTIONS_BUNDLING_REGEXPS.reduce(normalizeMessage, messageB)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return messageB
|
|
7
15
|
}
|
|
8
16
|
|
|
9
17
|
// Discard debug/info installation information
|
|
@@ -32,9 +40,9 @@ const normalizeMessage = function (message, [regExp, replacement]) {
|
|
|
32
40
|
|
|
33
41
|
const NORMALIZE_REGEXPS = [
|
|
34
42
|
// Base64 URL
|
|
35
|
-
[/(data:[^;]+;base64),[\w
|
|
43
|
+
[/(data:[^;]+;base64),[\w+/-=]+/g, 'dataURI'],
|
|
36
44
|
// File paths
|
|
37
|
-
[/(["'`, ]|^)([^"'`, \n]*[/\\][^"'`, \n]*)(["'`, ]|$)/gm, '$1/file/path
|
|
45
|
+
[/(["'`, ]|^)([^"'`, \n]*[/\\][^"'`, \n]*)(?=["'`, ]|$)/gm, '$1/file/path'],
|
|
38
46
|
// Semantic versions
|
|
39
47
|
[/\d+\.\d+\.\d+(-\d+)?/g, '1.0.0'],
|
|
40
48
|
[/version "[^"]+"/g, 'version "1.0.0"'],
|
|
@@ -45,7 +53,7 @@ const NORMALIZE_REGEXPS = [
|
|
|
45
53
|
// Numbers, e.g. number of issues/problems
|
|
46
54
|
[/\d+/g, '0'],
|
|
47
55
|
// Hexadecimal strings
|
|
48
|
-
[/[\da-fA-F]{6,}/g, 'hex'],
|
|
56
|
+
[/[\da-fA-F-]{6,}/g, 'hex'],
|
|
49
57
|
// On unknown inputs, we print the inputs
|
|
50
58
|
[/(does not accept any inputs but you specified: ).*/, '$1'],
|
|
51
59
|
[/(Unknown inputs for plugin).*/, '$1'],
|
|
@@ -75,3 +83,14 @@ const NORMALIZE_REGEXPS = [
|
|
|
75
83
|
// Multiple empty lines
|
|
76
84
|
[/^\s*$/gm, ''],
|
|
77
85
|
]
|
|
86
|
+
|
|
87
|
+
const FUNCTIONS_BUNDLING_REGEXPS = [
|
|
88
|
+
// String literals and identifiers
|
|
89
|
+
[/"([^"]+)"/g, '""'],
|
|
90
|
+
[/'([^']+)'/g, "''"],
|
|
91
|
+
[/`([^`]+)`/g, '``'],
|
|
92
|
+
|
|
93
|
+
// Rust crates
|
|
94
|
+
[/(?:Downloaded \S+ v[\d.]+\s*)+/gm, 'Downloaded crates'],
|
|
95
|
+
[/(?:Compiling \S+ v[\d.]+\s*)+/gm, 'Compiled crates'],
|
|
96
|
+
]
|
|
@@ -21,7 +21,7 @@ export const reportBuildError = async function ({ error, errorMonitor, childEnv,
|
|
|
21
21
|
const { errorInfo, type, severity, title, group = title } = parseErrorInfo(error)
|
|
22
22
|
const severityA = getSeverity(severity, errorInfo)
|
|
23
23
|
const groupA = getGroup(group, errorInfo)
|
|
24
|
-
const groupingHash = getGroupingHash(groupA, error, type)
|
|
24
|
+
const groupingHash = getGroupingHash(groupA, error, type, errorInfo)
|
|
25
25
|
const metadata = getMetadata(errorInfo, childEnv, groupingHash)
|
|
26
26
|
const app = getApp()
|
|
27
27
|
const eventProps = getEventProps({ severity: severityA, group: groupA, groupingHash, metadata, app })
|
|
@@ -52,7 +52,12 @@ const getGroup = function (group, errorInfo) {
|
|
|
52
52
|
return group(errorInfo)
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
const getGroupingHash = function (group, error, type) {
|
|
55
|
+
const getGroupingHash = function (group, error, type, errorInfo = {}) {
|
|
56
|
+
// If the error has a `normalizedMessage`, we use it as the grouping hash.
|
|
57
|
+
if (errorInfo.normalizedMessage) {
|
|
58
|
+
return errorInfo.normalizedMessage
|
|
59
|
+
}
|
|
60
|
+
|
|
56
61
|
const message = error instanceof Error && typeof error.message === 'string' ? error.message : String(error)
|
|
57
62
|
const messageA = normalizeGroupingMessage(message, type)
|
|
58
63
|
return `${group}\n${messageA}`
|
|
@@ -23,8 +23,12 @@ const getBuildCommandLocation = function ({ buildCommand, buildCommandOrigin })
|
|
|
23
23
|
${buildCommand}`
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
const getFunctionsBundlingLocation = function ({ functionName }) {
|
|
27
|
-
|
|
26
|
+
const getFunctionsBundlingLocation = function ({ functionName, functionType }) {
|
|
27
|
+
if (functionType === 'edge') {
|
|
28
|
+
return 'While bundling edge function'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return `While bundling function "${functionName}"`
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
const getCoreStepLocation = function ({ coreStepName }) {
|
package/src/error/type.js
CHANGED
|
@@ -81,7 +81,14 @@ const TYPES = {
|
|
|
81
81
|
|
|
82
82
|
// User error during Functions bundling
|
|
83
83
|
functionsBundling: {
|
|
84
|
-
title: ({ location: { functionName } }) =>
|
|
84
|
+
title: ({ location: { functionName, functionType } }) => {
|
|
85
|
+
if (functionType === 'edge') {
|
|
86
|
+
return 'Bundling of edge function failed'
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return `Bundling of function "${functionName}" failed`
|
|
90
|
+
},
|
|
91
|
+
group: ({ location: { functionType = 'serverless' } }) => `Bundling of ${functionType} function failed`,
|
|
85
92
|
stackType: 'none',
|
|
86
93
|
locationType: 'functionsBundling',
|
|
87
94
|
severity: 'info',
|
package/src/log/logger.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { createWriteStream } from 'fs'
|
|
2
|
+
|
|
1
3
|
import figures from 'figures'
|
|
2
4
|
import indentString from 'indent-string'
|
|
3
5
|
|
|
@@ -105,3 +107,36 @@ export const logErrorSubHeader = function (logs, string, opts) {
|
|
|
105
107
|
export const logWarningSubHeader = function (logs, string, opts) {
|
|
106
108
|
logSubHeader(logs, string, { color: THEME.warningSubHeader, ...opts })
|
|
107
109
|
}
|
|
110
|
+
|
|
111
|
+
// Combines an array of elements into a single string, separated by a space,
|
|
112
|
+
// and with basic serialization of non-string types
|
|
113
|
+
const reduceLogLines = function (lines) {
|
|
114
|
+
return lines
|
|
115
|
+
.map((input) => {
|
|
116
|
+
if (typeof input === 'object') {
|
|
117
|
+
return JSON.stringify(input)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
return input.toString()
|
|
121
|
+
})
|
|
122
|
+
.join(' ')
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Builds a function for logging data to the system logger (i.e. hidden from
|
|
126
|
+
// the user-facing build logs)
|
|
127
|
+
export const getSystemLogger = function (logs, debug, systemLogFile) {
|
|
128
|
+
// If there's not a file descriptor (or it's set to 0, matching stdout), we
|
|
129
|
+
// send debug lines to the normal logger. The same happens if the `debug`
|
|
130
|
+
// flag is used, since that means we want to print logs to stdout.
|
|
131
|
+
if (!systemLogFile || debug) {
|
|
132
|
+
return (...args) => log(logs, reduceLogLines(args))
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const fileDescriptor = createWriteStream(null, { fd: systemLogFile })
|
|
136
|
+
|
|
137
|
+
fileDescriptor.on('error', () => {
|
|
138
|
+
logError(logs, 'Could not write to system log file')
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
return (...args) => fileDescriptor.write(reduceLogLines(args))
|
|
142
|
+
}
|
|
@@ -6,18 +6,19 @@ import { addErrorInfo } from '../../error/info.js'
|
|
|
6
6
|
// Report status information to the UI
|
|
7
7
|
export const show = function (runState, showArgs) {
|
|
8
8
|
validateShowArgs(showArgs)
|
|
9
|
-
const { title, summary, text } = removeEmptyStrings(showArgs)
|
|
10
|
-
runState.status = { state: 'success', title, summary, text }
|
|
9
|
+
const { title, summary, text, extraData } = removeEmptyStrings(showArgs)
|
|
10
|
+
runState.status = { state: 'success', title, summary, text, extraData }
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
// Validate arguments of `utils.status.show()`
|
|
14
14
|
const validateShowArgs = function (showArgs) {
|
|
15
15
|
try {
|
|
16
16
|
validateShowArgsObject(showArgs)
|
|
17
|
-
const { title, summary, text, ...otherArgs } = showArgs
|
|
17
|
+
const { title, summary, text, extraData, ...otherArgs } = showArgs
|
|
18
18
|
validateShowArgsKeys(otherArgs)
|
|
19
19
|
Object.entries({ title, summary, text }).forEach(validateStringArg)
|
|
20
20
|
validateShowArgsSummary(summary)
|
|
21
|
+
validateShowArgsExtraData(extraData)
|
|
21
22
|
} catch (error) {
|
|
22
23
|
error.message = `utils.status.show() ${error.message}`
|
|
23
24
|
addErrorInfo(error, { type: 'pluginValidation' })
|
|
@@ -54,6 +55,12 @@ const validateShowArgsSummary = function (summary) {
|
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
57
|
|
|
58
|
+
const validateShowArgsExtraData = function (extraData) {
|
|
59
|
+
if (extraData !== undefined && Array.isArray(extraData) === false) {
|
|
60
|
+
throw new TypeError('provided extra data must be an array')
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
57
64
|
const removeEmptyStrings = function (showArgs) {
|
|
58
65
|
return mapObj(showArgs, removeEmptyString)
|
|
59
66
|
}
|
|
@@ -6,12 +6,15 @@ import { pathExists } from 'path-exists'
|
|
|
6
6
|
|
|
7
7
|
import { logFunctionsToBundle } from '../../log/messages/core_steps.js'
|
|
8
8
|
|
|
9
|
+
import { tagBundlingError } from './lib/error.js'
|
|
9
10
|
import { parseManifest } from './lib/internal_manifest.js'
|
|
11
|
+
import { validateEdgeFunctionsManifest } from './validate_manifest/validate_edge_functions_manifest.js'
|
|
10
12
|
|
|
11
13
|
// TODO: Replace this with a custom cache directory.
|
|
12
14
|
const DENO_CLI_CACHE_DIRECTORY = '.netlify/plugins/deno-cli'
|
|
13
15
|
const IMPORT_MAP_FILENAME = 'edge-functions-import-map.json'
|
|
14
16
|
|
|
17
|
+
// eslint-disable-next-line max-statements
|
|
15
18
|
const coreStep = async function ({
|
|
16
19
|
buildDir,
|
|
17
20
|
constants: {
|
|
@@ -21,6 +24,7 @@ const coreStep = async function ({
|
|
|
21
24
|
IS_LOCAL: isRunningLocally,
|
|
22
25
|
},
|
|
23
26
|
debug,
|
|
27
|
+
systemLog,
|
|
24
28
|
featureFlags,
|
|
25
29
|
logs,
|
|
26
30
|
netlifyConfig,
|
|
@@ -45,13 +49,24 @@ const coreStep = async function ({
|
|
|
45
49
|
// Edge Bundler expects the dist directory to exist.
|
|
46
50
|
await fs.mkdir(distPath, { recursive: true })
|
|
47
51
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
52
|
+
try {
|
|
53
|
+
const { manifest } = await bundle(sourcePaths, distPath, declarations, {
|
|
54
|
+
basePath: buildDir,
|
|
55
|
+
cacheDirectory,
|
|
56
|
+
debug,
|
|
57
|
+
distImportMapPath,
|
|
58
|
+
featureFlags,
|
|
59
|
+
importMaps: [importMap].filter(Boolean),
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
systemLog('Edge Functions manifest:', manifest)
|
|
63
|
+
} catch (error) {
|
|
64
|
+
tagBundlingError(error)
|
|
65
|
+
|
|
66
|
+
throw error
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
await validateEdgeFunctionsManifest({ buildDir, constants: { EDGE_FUNCTIONS_DIST: distDirectory } })
|
|
55
70
|
|
|
56
71
|
return {}
|
|
57
72
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { CUSTOM_ERROR_KEY, getErrorInfo, isBuildError } from '../../../error/info.js'
|
|
2
|
+
|
|
3
|
+
// If we have a custom error tagged with `functionsBundling` (which happens if
|
|
4
|
+
// there is an issue with user code), we tag it as coming from an edge function
|
|
5
|
+
// so that we can adjust the downstream error messages accordingly.
|
|
6
|
+
export const tagBundlingError = (error) => {
|
|
7
|
+
if (!isBuildError(error)) {
|
|
8
|
+
return
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const [errorInfo = {}] = getErrorInfo(error)
|
|
12
|
+
|
|
13
|
+
if (errorInfo.type !== 'functionsBundling') {
|
|
14
|
+
return
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
error[CUSTOM_ERROR_KEY].location = {
|
|
18
|
+
...error[CUSTOM_ERROR_KEY].location,
|
|
19
|
+
functionType: 'edge',
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { promises as fs } from 'fs'
|
|
2
|
+
import { join, resolve } from 'path'
|
|
3
|
+
|
|
4
|
+
import Ajv from 'ajv'
|
|
5
|
+
import ajvErrors from 'ajv-errors'
|
|
6
|
+
|
|
7
|
+
import { addErrorInfo } from '../../../error/info.js'
|
|
8
|
+
|
|
9
|
+
const ajv = new Ajv({ allErrors: true })
|
|
10
|
+
ajvErrors(ajv)
|
|
11
|
+
|
|
12
|
+
// regex pattern for manifest route pattern
|
|
13
|
+
// checks if the pattern string starts with ^ and ends with $
|
|
14
|
+
// we define this format in edge-bundler:
|
|
15
|
+
// https://github.com/netlify/edge-bundler/blob/main/src/manifest.ts#L66
|
|
16
|
+
const normalizedPatternRegex = /^\^.*\$$/
|
|
17
|
+
ajv.addFormat('regexPattern', {
|
|
18
|
+
async: true,
|
|
19
|
+
validate: (data) => normalizedPatternRegex.test(data),
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
const bundlesSchema = {
|
|
23
|
+
$async: true,
|
|
24
|
+
type: 'object',
|
|
25
|
+
required: ['asset', 'format'],
|
|
26
|
+
properties: {
|
|
27
|
+
asset: { type: 'string' },
|
|
28
|
+
format: { type: 'string' },
|
|
29
|
+
},
|
|
30
|
+
additionalProperties: false,
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const routesSchema = {
|
|
34
|
+
$async: true,
|
|
35
|
+
type: 'object',
|
|
36
|
+
required: ['function', 'pattern'],
|
|
37
|
+
properties: {
|
|
38
|
+
function: { type: 'string' },
|
|
39
|
+
pattern: { type: 'string', format: 'regexPattern', errorMessage: `must match format ${normalizedPatternRegex}` },
|
|
40
|
+
},
|
|
41
|
+
additionalProperties: false,
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const edgeManifestSchema = {
|
|
45
|
+
$async: true,
|
|
46
|
+
type: 'object',
|
|
47
|
+
required: ['bundles', 'routes', 'bundler_version'],
|
|
48
|
+
properties: {
|
|
49
|
+
bundles: {
|
|
50
|
+
type: 'array',
|
|
51
|
+
items: bundlesSchema,
|
|
52
|
+
},
|
|
53
|
+
routes: {
|
|
54
|
+
type: 'array',
|
|
55
|
+
items: routesSchema,
|
|
56
|
+
},
|
|
57
|
+
bundler_version: { type: 'string' },
|
|
58
|
+
},
|
|
59
|
+
additionalProperties: false,
|
|
60
|
+
errorMessage: "Couldn't validate Edge Functions manifest.json",
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const validateManifest = async (manifestData) => {
|
|
64
|
+
const validate = ajv.compile(edgeManifestSchema)
|
|
65
|
+
|
|
66
|
+
await validate(manifestData)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export const validateEdgeFunctionsManifest = async function ({
|
|
70
|
+
buildDir,
|
|
71
|
+
constants: { EDGE_FUNCTIONS_DIST: distDirectory },
|
|
72
|
+
}) {
|
|
73
|
+
try {
|
|
74
|
+
const edgeFunctionsDistPath = resolve(buildDir, distDirectory)
|
|
75
|
+
const manifestPath = join(edgeFunctionsDistPath, 'manifest.json')
|
|
76
|
+
const data = await fs.readFile(manifestPath)
|
|
77
|
+
const manifestData = JSON.parse(data)
|
|
78
|
+
|
|
79
|
+
await validateManifest(manifestData)
|
|
80
|
+
} catch (error) {
|
|
81
|
+
const isValidationErr = error instanceof Ajv.ValidationError
|
|
82
|
+
const parsedErr = isValidationErr ? error.errors : error
|
|
83
|
+
|
|
84
|
+
addErrorInfo(parsedErr, { type: 'coreStep' })
|
|
85
|
+
throw new Error(isValidationErr ? JSON.stringify(parsedErr, null, 2) : parsedErr)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return {}
|
|
89
|
+
}
|
package/src/status/report.js
CHANGED
|
@@ -104,7 +104,7 @@ const sendApiStatuses = async function ({
|
|
|
104
104
|
|
|
105
105
|
const sendApiStatus = async function ({
|
|
106
106
|
api,
|
|
107
|
-
status: { packageName, version, state, event, title, summary, text },
|
|
107
|
+
status: { packageName, version, state, event, title, summary, text, extraData },
|
|
108
108
|
childEnv,
|
|
109
109
|
mode,
|
|
110
110
|
netlifyConfig,
|
|
@@ -117,7 +117,16 @@ const sendApiStatus = async function ({
|
|
|
117
117
|
try {
|
|
118
118
|
await api.createPluginRun({
|
|
119
119
|
deploy_id: deployId,
|
|
120
|
-
body: {
|
|
120
|
+
body: {
|
|
121
|
+
package: packageName,
|
|
122
|
+
version,
|
|
123
|
+
state,
|
|
124
|
+
reporting_event: event,
|
|
125
|
+
title,
|
|
126
|
+
summary,
|
|
127
|
+
text,
|
|
128
|
+
extra_data: extraData,
|
|
129
|
+
},
|
|
121
130
|
})
|
|
122
131
|
// Bitballoon API randomly fails with 502.
|
|
123
132
|
// Builds should be successful when this API call fails, but we still want
|
package/src/steps/core_step.js
CHANGED
|
@@ -27,6 +27,7 @@ export const fireCoreStep = async function ({
|
|
|
27
27
|
redirectsPath,
|
|
28
28
|
featureFlags,
|
|
29
29
|
debug,
|
|
30
|
+
systemLog,
|
|
30
31
|
saveConfig,
|
|
31
32
|
}) {
|
|
32
33
|
try {
|
|
@@ -54,6 +55,7 @@ export const fireCoreStep = async function ({
|
|
|
54
55
|
redirectsPath,
|
|
55
56
|
featureFlags,
|
|
56
57
|
debug,
|
|
58
|
+
systemLog,
|
|
57
59
|
saveConfig,
|
|
58
60
|
})
|
|
59
61
|
const {
|
package/src/steps/run_step.js
CHANGED
|
@@ -48,6 +48,7 @@ export const runStep = async function ({
|
|
|
48
48
|
redirectsPath,
|
|
49
49
|
logs,
|
|
50
50
|
debug,
|
|
51
|
+
systemLog,
|
|
51
52
|
verbose,
|
|
52
53
|
saveConfig,
|
|
53
54
|
timers,
|
|
@@ -109,6 +110,7 @@ export const runStep = async function ({
|
|
|
109
110
|
error,
|
|
110
111
|
logs,
|
|
111
112
|
debug,
|
|
113
|
+
systemLog,
|
|
112
114
|
verbose,
|
|
113
115
|
saveConfig,
|
|
114
116
|
timers,
|
|
@@ -140,6 +142,7 @@ export const runStep = async function ({
|
|
|
140
142
|
redirectsPath: redirectsPathA,
|
|
141
143
|
logs,
|
|
142
144
|
debug,
|
|
145
|
+
systemLog,
|
|
143
146
|
timers: timersA,
|
|
144
147
|
durationNs,
|
|
145
148
|
testOpts,
|
|
@@ -237,6 +240,7 @@ const tFireStep = function ({
|
|
|
237
240
|
error,
|
|
238
241
|
logs,
|
|
239
242
|
debug,
|
|
243
|
+
systemLog,
|
|
240
244
|
verbose,
|
|
241
245
|
saveConfig,
|
|
242
246
|
errorParams,
|
|
@@ -271,6 +275,7 @@ const tFireStep = function ({
|
|
|
271
275
|
redirectsPath,
|
|
272
276
|
featureFlags,
|
|
273
277
|
debug,
|
|
278
|
+
systemLog,
|
|
274
279
|
saveConfig,
|
|
275
280
|
})
|
|
276
281
|
}
|
|
@@ -294,6 +299,7 @@ const tFireStep = function ({
|
|
|
294
299
|
error,
|
|
295
300
|
logs,
|
|
296
301
|
debug,
|
|
302
|
+
systemLog,
|
|
297
303
|
verbose,
|
|
298
304
|
})
|
|
299
305
|
}
|
package/src/steps/run_steps.js
CHANGED
|
@@ -34,6 +34,7 @@ export const runSteps = async function ({
|
|
|
34
34
|
configOpts,
|
|
35
35
|
logs,
|
|
36
36
|
debug,
|
|
37
|
+
systemLog,
|
|
37
38
|
verbose,
|
|
38
39
|
saveConfig,
|
|
39
40
|
timers,
|
|
@@ -127,6 +128,7 @@ export const runSteps = async function ({
|
|
|
127
128
|
redirectsPath: redirectsPathA,
|
|
128
129
|
logs,
|
|
129
130
|
debug,
|
|
131
|
+
systemLog,
|
|
130
132
|
verbose,
|
|
131
133
|
saveConfig,
|
|
132
134
|
timers: timersA,
|