@netlify/build 27.18.4 → 27.18.6-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 -7
- package/src/core/bin.js +0 -83
- package/src/core/build.js +0 -559
- package/src/core/config.js +0 -186
- package/src/core/constants.js +0 -156
- package/src/core/dev.js +0 -31
- package/src/core/dry.js +0 -39
- package/src/core/feature_flags.js +0 -22
- package/src/core/flags.js +0 -204
- package/src/core/lingering.js +0 -85
- package/src/core/main.js +0 -165
- package/src/core/missing_side_file.js +0 -29
- package/src/core/normalize_flags.js +0 -70
- package/src/core/severity.js +0 -22
- package/src/core/user_node_version.js +0 -41
- package/src/env/changes.js +0 -52
- package/src/env/main.js +0 -19
- package/src/env/metadata.js +0 -81
- package/src/error/api.js +0 -46
- package/src/error/build.js +0 -50
- package/src/error/cancel.js +0 -8
- package/src/error/colors.js +0 -11
- package/src/error/handle.js +0 -57
- package/src/error/info.js +0 -46
- package/src/error/monitor/location.js +0 -21
- package/src/error/monitor/normalize.js +0 -96
- package/src/error/monitor/print.js +0 -42
- package/src/error/monitor/report.js +0 -138
- package/src/error/monitor/start.js +0 -69
- package/src/error/parse/clean_stack.js +0 -87
- package/src/error/parse/location.js +0 -62
- package/src/error/parse/normalize.js +0 -29
- package/src/error/parse/parse.js +0 -97
- package/src/error/parse/plugin.js +0 -70
- package/src/error/parse/properties.js +0 -23
- package/src/error/parse/serialize_log.js +0 -42
- package/src/error/parse/serialize_status.js +0 -23
- package/src/error/parse/stack.js +0 -43
- package/src/error/type.js +0 -189
- package/src/install/functions.js +0 -28
- package/src/install/local.js +0 -62
- package/src/install/main.js +0 -81
- package/src/install/missing.js +0 -67
- package/src/log/colors.js +0 -34
- package/src/log/description.js +0 -26
- package/src/log/header.js +0 -16
- package/src/log/header_func.js +0 -17
- package/src/log/logger.js +0 -161
- package/src/log/messages/compatibility.js +0 -178
- package/src/log/messages/config.js +0 -107
- package/src/log/messages/core.js +0 -70
- package/src/log/messages/core_steps.js +0 -104
- package/src/log/messages/dry.js +0 -63
- package/src/log/messages/install.js +0 -32
- package/src/log/messages/ipc.js +0 -38
- package/src/log/messages/mutations.js +0 -82
- package/src/log/messages/plugins.js +0 -39
- package/src/log/messages/status.js +0 -16
- package/src/log/messages/steps.js +0 -22
- package/src/log/old_version.js +0 -41
- package/src/log/serialize.js +0 -13
- package/src/log/stream.js +0 -85
- package/src/log/theme.js +0 -26
- package/src/plugins/child/diff.js +0 -55
- package/src/plugins/child/error.js +0 -32
- package/src/plugins/child/lazy.js +0 -18
- package/src/plugins/child/load.js +0 -29
- package/src/plugins/child/logic.js +0 -65
- package/src/plugins/child/main.js +0 -51
- package/src/plugins/child/run.js +0 -28
- package/src/plugins/child/status.js +0 -74
- package/src/plugins/child/typescript.js +0 -45
- package/src/plugins/child/utils.js +0 -56
- package/src/plugins/child/validate.js +0 -34
- package/src/plugins/compatibility.js +0 -132
- package/src/plugins/error.js +0 -50
- package/src/plugins/events.js +0 -17
- package/src/plugins/expected_version.js +0 -119
- package/src/plugins/ipc.js +0 -145
- package/src/plugins/list.js +0 -86
- package/src/plugins/load.js +0 -70
- package/src/plugins/manifest/check.js +0 -106
- package/src/plugins/manifest/load.js +0 -41
- package/src/plugins/manifest/main.js +0 -22
- package/src/plugins/manifest/path.js +0 -31
- package/src/plugins/manifest/validate.js +0 -108
- package/src/plugins/node_version.js +0 -50
- package/src/plugins/options.js +0 -88
- package/src/plugins/pinned_version.js +0 -131
- package/src/plugins/resolve.js +0 -152
- package/src/plugins/spawn.js +0 -72
- package/src/plugins_core/add.js +0 -49
- package/src/plugins_core/build_command.js +0 -75
- package/src/plugins_core/deploy/buildbot_client.js +0 -113
- package/src/plugins_core/deploy/index.js +0 -73
- package/src/plugins_core/deploy/manifest.yml +0 -1
- package/src/plugins_core/edge_functions/index.js +0 -123
- package/src/plugins_core/edge_functions/lib/error.js +0 -21
- package/src/plugins_core/edge_functions/lib/internal_manifest.js +0 -60
- package/src/plugins_core/edge_functions/validate_manifest/validate_edge_functions_manifest.js +0 -89
- package/src/plugins_core/functions/error.js +0 -163
- package/src/plugins_core/functions/feature_flags.js +0 -6
- package/src/plugins_core/functions/index.js +0 -161
- package/src/plugins_core/functions/utils.js +0 -66
- package/src/plugins_core/functions/zisi.js +0 -56
- package/src/plugins_core/functions_install/index.js +0 -13
- package/src/plugins_core/functions_install/manifest.yml +0 -1
- package/src/plugins_core/list.js +0 -27
- package/src/status/add.js +0 -36
- package/src/status/colors.js +0 -23
- package/src/status/load_error.js +0 -11
- package/src/status/report.js +0 -137
- package/src/status/success.js +0 -18
- package/src/steps/core_step.js +0 -92
- package/src/steps/error.js +0 -102
- package/src/steps/get.js +0 -51
- package/src/steps/plugin.js +0 -85
- package/src/steps/return.js +0 -52
- package/src/steps/run_core_steps.js +0 -200
- package/src/steps/run_step.js +0 -304
- package/src/steps/run_steps.js +0 -179
- package/src/steps/update_config.js +0 -93
- package/src/telemetry/main.js +0 -136
- package/src/time/aggregate.js +0 -146
- package/src/time/main.js +0 -48
- package/src/time/measure.js +0 -22
- package/src/time/report.js +0 -59
- package/src/utils/errors.js +0 -12
- package/src/utils/json.js +0 -19
- package/src/utils/omit.js +0 -6
- package/src/utils/package.js +0 -23
- package/src/utils/remove_falsy.js +0 -10
- package/src/utils/resolve.js +0 -46
- package/src/utils/runtime.js +0 -5
- package/src/utils/semver.js +0 -34
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import semver from 'semver'
|
|
2
|
-
|
|
3
|
-
import { addErrorInfo } from '../error/info.js'
|
|
4
|
-
import { importJsonFile } from '../utils/json.js'
|
|
5
|
-
import { resolvePath } from '../utils/resolve.js'
|
|
6
|
-
|
|
7
|
-
import { getExpectedVersion } from './compatibility.js'
|
|
8
|
-
import { getPluginsList } from './list.js'
|
|
9
|
-
|
|
10
|
-
// When using plugins in our official list, those are installed in .netlify/plugins/
|
|
11
|
-
// We ensure that the last version that's been approved is always the one being used.
|
|
12
|
-
// We also ensure that the plugin is our official list.
|
|
13
|
-
export const addExpectedVersions = async function ({
|
|
14
|
-
pluginsOptions,
|
|
15
|
-
autoPluginsDir,
|
|
16
|
-
packageJson,
|
|
17
|
-
debug,
|
|
18
|
-
logs,
|
|
19
|
-
buildDir,
|
|
20
|
-
testOpts,
|
|
21
|
-
featureFlags,
|
|
22
|
-
}) {
|
|
23
|
-
if (!pluginsOptions.some(needsExpectedVersion)) {
|
|
24
|
-
return pluginsOptions
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const pluginsList = await getPluginsList({ debug, logs, testOpts })
|
|
28
|
-
return await Promise.all(
|
|
29
|
-
pluginsOptions.map((pluginOptions) =>
|
|
30
|
-
addExpectedVersion({ pluginsList, autoPluginsDir, packageJson, pluginOptions, buildDir, featureFlags }),
|
|
31
|
-
),
|
|
32
|
-
)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Any `pluginOptions` with `expectedVersion` set will be automatically installed
|
|
36
|
-
const addExpectedVersion = async function ({
|
|
37
|
-
pluginsList,
|
|
38
|
-
autoPluginsDir,
|
|
39
|
-
packageJson,
|
|
40
|
-
pluginOptions,
|
|
41
|
-
pluginOptions: { packageName, pluginPath, loadedFrom, nodeVersion, pinnedVersion },
|
|
42
|
-
buildDir,
|
|
43
|
-
featureFlags,
|
|
44
|
-
}) {
|
|
45
|
-
if (!needsExpectedVersion(pluginOptions)) {
|
|
46
|
-
return pluginOptions
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (pluginsList[packageName] === undefined) {
|
|
50
|
-
validateUnlistedPlugin(packageName, loadedFrom)
|
|
51
|
-
return pluginOptions
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const unfilteredVersions = pluginsList[packageName]
|
|
55
|
-
const versions = filterVersions(unfilteredVersions, featureFlags)
|
|
56
|
-
const [{ version: latestVersion, migrationGuide }] = versions
|
|
57
|
-
const [{ version: expectedVersion }, { version: compatibleVersion, compatWarning }] = await Promise.all([
|
|
58
|
-
getExpectedVersion({ versions, nodeVersion, packageJson, buildDir, pinnedVersion }),
|
|
59
|
-
getExpectedVersion({ versions, nodeVersion, packageJson, buildDir }),
|
|
60
|
-
])
|
|
61
|
-
|
|
62
|
-
const isMissing = await isMissingVersion({ autoPluginsDir, packageName, pluginPath, loadedFrom, expectedVersion })
|
|
63
|
-
return {
|
|
64
|
-
...pluginOptions,
|
|
65
|
-
latestVersion,
|
|
66
|
-
expectedVersion,
|
|
67
|
-
compatibleVersion,
|
|
68
|
-
migrationGuide,
|
|
69
|
-
compatWarning,
|
|
70
|
-
isMissing,
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Feature flagged versions are removed unless the feature flag is present.
|
|
75
|
-
// - This is done before conditions are applied since, unlike conditions,
|
|
76
|
-
// users cannot always choose to enable a feature flag.
|
|
77
|
-
const filterVersions = function (unfilteredVersions, featureFlags) {
|
|
78
|
-
return unfilteredVersions.filter(({ featureFlag }) => featureFlag === undefined || featureFlags[featureFlag])
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Checks whether plugin should be installed due to the wrong version being used
|
|
82
|
-
// (either outdated, or mismatching compatibility requirements)
|
|
83
|
-
const isMissingVersion = async function ({ autoPluginsDir, packageName, pluginPath, loadedFrom, expectedVersion }) {
|
|
84
|
-
return (
|
|
85
|
-
// We always respect the versions specified in `package.json`, as opposed
|
|
86
|
-
// to auto-installed plugins
|
|
87
|
-
loadedFrom !== 'package.json' &&
|
|
88
|
-
// Plugin was not previously installed
|
|
89
|
-
(pluginPath === undefined ||
|
|
90
|
-
// Plugin was previously installed but a different version should be used
|
|
91
|
-
!semver.satisfies(await getAutoPluginVersion(packageName, autoPluginsDir), expectedVersion))
|
|
92
|
-
)
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const getAutoPluginVersion = async function (packageName, autoPluginsDir) {
|
|
96
|
-
const packageJsonPath = await resolvePath(`${packageName}/package.json`, autoPluginsDir)
|
|
97
|
-
const { version } = await importJsonFile(packageJsonPath)
|
|
98
|
-
return version
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
const needsExpectedVersion = function ({ loadedFrom }) {
|
|
102
|
-
return loadedFrom === 'auto_install' || loadedFrom === 'package.json'
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Plugins that are not in our official list can only be specified in
|
|
106
|
-
// `netlify.toml` providing they are also installed in the site's package.json.
|
|
107
|
-
// Otherwise, the build should fail.
|
|
108
|
-
const validateUnlistedPlugin = function (packageName, loadedFrom) {
|
|
109
|
-
if (loadedFrom === 'package.json') {
|
|
110
|
-
return
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const error = new Error(
|
|
114
|
-
`Plugins must be installed either in the Netlify App or in "package.json".
|
|
115
|
-
Please run "npm install -D ${packageName}" or "yarn add -D ${packageName}".`,
|
|
116
|
-
)
|
|
117
|
-
addErrorInfo(error, { type: 'resolveConfig' })
|
|
118
|
-
throw error
|
|
119
|
-
}
|
package/src/plugins/ipc.js
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import process from 'process'
|
|
2
|
-
import { promisify } from 'util'
|
|
3
|
-
|
|
4
|
-
import { pEvent } from 'p-event'
|
|
5
|
-
import { v4 as uuidv4 } from 'uuid'
|
|
6
|
-
|
|
7
|
-
import { jsonToError, errorToJson } from '../error/build.js'
|
|
8
|
-
import { addErrorInfo } from '../error/info.js'
|
|
9
|
-
import {
|
|
10
|
-
logSendingEventToChild,
|
|
11
|
-
logSentEventToChild,
|
|
12
|
-
logReceivedEventFromChild,
|
|
13
|
-
logSendingEventToParent,
|
|
14
|
-
} from '../log/messages/ipc.js'
|
|
15
|
-
|
|
16
|
-
// Send event from child to parent process then wait for response
|
|
17
|
-
// We need to fire them in parallel because `process.send()` can be slow
|
|
18
|
-
// to await, i.e. child might send response before parent start listening for it
|
|
19
|
-
export const callChild = async function ({ childProcess, eventName, payload, logs, verbose }) {
|
|
20
|
-
const callId = uuidv4()
|
|
21
|
-
const [response] = await Promise.all([
|
|
22
|
-
getEventFromChild(childProcess, callId),
|
|
23
|
-
sendEventToChild({ childProcess, callId, eventName, payload, logs, verbose }),
|
|
24
|
-
])
|
|
25
|
-
logReceivedEventFromChild(logs, verbose)
|
|
26
|
-
return response
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Receive event from child to parent process
|
|
30
|
-
// Wait for either:
|
|
31
|
-
// - `message` event with a specific `callId`
|
|
32
|
-
// - `message` event with an `error` `callId` indicating an exception in the
|
|
33
|
-
// child process
|
|
34
|
-
// - child process `exit`
|
|
35
|
-
// In the later two cases, we propagate the error.
|
|
36
|
-
// We need to make `p-event` listeners are properly cleaned up too.
|
|
37
|
-
export const getEventFromChild = async function (childProcess, callId) {
|
|
38
|
-
if (childProcessHasExited(childProcess)) {
|
|
39
|
-
throw getChildExitError('Could not receive event from child process because it already exited.')
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const messagePromise = pEvent(childProcess, 'message', { filter: ([actualCallId]) => actualCallId === callId })
|
|
43
|
-
const errorPromise = pEvent(childProcess, 'message', { filter: ([actualCallId]) => actualCallId === 'error' })
|
|
44
|
-
const exitPromise = pEvent(childProcess, 'exit', { multiArgs: true })
|
|
45
|
-
try {
|
|
46
|
-
return await Promise.race([getMessage(messagePromise), getError(errorPromise), getExit(exitPromise)])
|
|
47
|
-
} finally {
|
|
48
|
-
messagePromise.cancel()
|
|
49
|
-
errorPromise.cancel()
|
|
50
|
-
exitPromise.cancel()
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const childProcessHasExited = function (childProcess) {
|
|
55
|
-
return !childProcess.connected || childProcess.signalCode !== null || childProcess.exitCode !== null
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const getMessage = async function (messagePromise) {
|
|
59
|
-
const [, response] = await messagePromise
|
|
60
|
-
return response
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const getError = async function (errorPromise) {
|
|
64
|
-
const [, error] = await errorPromise
|
|
65
|
-
throw jsonToError(error)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
const getExit = async function (exitPromise) {
|
|
69
|
-
const [exitCode, signal] = await exitPromise
|
|
70
|
-
throw getChildExitError(`Plugin exited with exit code ${exitCode} and signal ${signal}.`)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Plugins should not terminate processes explicitly:
|
|
74
|
-
// - It prevents specifying error messages to the end users
|
|
75
|
-
// - It makes it impossible to distinguish between bugs (such as infinite loops) and user errors
|
|
76
|
-
// - It complicates child process orchestration. For example if an async operation
|
|
77
|
-
// of a previous event handler is still running, it would be aborted if another
|
|
78
|
-
// is terminating the process.
|
|
79
|
-
const getChildExitError = function (message) {
|
|
80
|
-
const error = new Error(`${message}\n${EXIT_WARNING}`)
|
|
81
|
-
addErrorInfo(error, { type: 'ipc' })
|
|
82
|
-
return error
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const EXIT_WARNING = `The plugin might have exited due to a bug terminating the process, such as an infinite loop.
|
|
86
|
-
The plugin might also have explicitly terminated the process, for example with process.exit().
|
|
87
|
-
Plugin methods should instead:
|
|
88
|
-
- on success: return
|
|
89
|
-
- on failure: call utils.build.failPlugin() or utils.build.failBuild()`
|
|
90
|
-
|
|
91
|
-
// Send event from parent to child process
|
|
92
|
-
const sendEventToChild = async function ({ childProcess, callId, eventName, payload, logs, verbose }) {
|
|
93
|
-
logSendingEventToChild(logs, verbose)
|
|
94
|
-
|
|
95
|
-
const payloadA = serializePayload(payload)
|
|
96
|
-
await promisify(childProcess.send.bind(childProcess))([callId, eventName, payloadA])
|
|
97
|
-
|
|
98
|
-
logSentEventToChild(logs, verbose)
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Respond to events from parent to child process.
|
|
102
|
-
// This runs forever until `childProcess.kill()` is called.
|
|
103
|
-
// We need to use `new Promise()` and callbacks because this runs forever.
|
|
104
|
-
// eslint-disable-next-line promise/prefer-await-to-callbacks
|
|
105
|
-
export const getEventsFromParent = function (callback) {
|
|
106
|
-
return new Promise((resolve, reject) => {
|
|
107
|
-
process.on('message', async (message) => {
|
|
108
|
-
try {
|
|
109
|
-
const [callId, eventName, payload] = message
|
|
110
|
-
const payloadA = parsePayload(payload)
|
|
111
|
-
// eslint-disable-next-line promise/prefer-await-to-callbacks
|
|
112
|
-
return await callback(callId, eventName, payloadA)
|
|
113
|
-
} catch (error) {
|
|
114
|
-
reject(error)
|
|
115
|
-
}
|
|
116
|
-
})
|
|
117
|
-
})
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// Send event from child to parent process
|
|
121
|
-
export const sendEventToParent = async function (callId, payload, verbose, error) {
|
|
122
|
-
logSendingEventToParent(verbose, error)
|
|
123
|
-
await promisify(process.send.bind(process))([callId, payload])
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
// Error static properties are not serializable through `child_process`
|
|
127
|
-
// (which uses `v8.serialize()` under the hood) so we need to convert from/to
|
|
128
|
-
// plain objects.
|
|
129
|
-
const serializePayload = function ({ error = {}, error: { name } = {}, ...payload }) {
|
|
130
|
-
if (name === undefined) {
|
|
131
|
-
return payload
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const errorA = errorToJson(error)
|
|
135
|
-
return { ...payload, error: errorA }
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const parsePayload = function ({ error = {}, error: { name } = {}, ...payload }) {
|
|
139
|
-
if (name === undefined) {
|
|
140
|
-
return payload
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
const errorA = jsonToError(error)
|
|
144
|
-
return { ...payload, error: errorA }
|
|
145
|
-
}
|
package/src/plugins/list.js
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
import { pluginsUrl, pluginsList as oldPluginsList } from '@netlify/plugins-list'
|
|
2
|
-
import got from 'got'
|
|
3
|
-
import isPlainObj from 'is-plain-obj'
|
|
4
|
-
|
|
5
|
-
import { logPluginsList, logPluginsFetchError } from '../log/messages/plugins.js'
|
|
6
|
-
|
|
7
|
-
import { CONDITIONS } from './compatibility.js'
|
|
8
|
-
|
|
9
|
-
// Retrieve the list of plugins officially vetted by us and displayed in our
|
|
10
|
-
// plugins directory UI.
|
|
11
|
-
// We fetch this list during each build (no caching) because we want new
|
|
12
|
-
// versions of plugins to be available instantly to all users. The time to
|
|
13
|
-
// make this request is somewhat ok (in the 100ms range).
|
|
14
|
-
// We only fetch this plugins list when needed, i.e. we defer it as much as
|
|
15
|
-
// possible.
|
|
16
|
-
export const getPluginsList = async function ({ debug, logs, testOpts: { pluginsListUrl } }) {
|
|
17
|
-
// We try not to mock in integration tests. However, sending a request for
|
|
18
|
-
// each test would be too slow and make tests unreliable.
|
|
19
|
-
if (pluginsListUrl === 'test') {
|
|
20
|
-
return []
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const pluginsListUrlA = pluginsListUrl === undefined ? pluginsUrl : pluginsListUrl
|
|
24
|
-
const pluginsList = await fetchPluginsList({ logs, pluginsListUrl: pluginsListUrlA })
|
|
25
|
-
const pluginsListA = normalizePluginsList(pluginsList)
|
|
26
|
-
logPluginsList({ pluginsList: pluginsListA, debug, logs })
|
|
27
|
-
return pluginsListA
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
const fetchPluginsList = async function ({ logs, pluginsListUrl }) {
|
|
31
|
-
try {
|
|
32
|
-
const { body } = await got(pluginsListUrl, { responseType: 'json', timeout: PLUGINS_LIST_TIMEOUT })
|
|
33
|
-
|
|
34
|
-
if (!isValidPluginsList(body)) {
|
|
35
|
-
throw new Error(`Request succeeded but with an invalid response:\n${JSON.stringify(body, null, 2)}`)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
return body
|
|
39
|
-
// The Netlify Site should be up. This is a fallback.
|
|
40
|
-
// `oldPluginsList` might not contain the latest plugins versions:
|
|
41
|
-
// - We should do `npm publish` as soon as a PR is merged in
|
|
42
|
-
// `netlify/plugins` but it is possible we don't.
|
|
43
|
-
// - Releasing it requires a @netlify/buld release, which requires itself a
|
|
44
|
-
// buildbot release.
|
|
45
|
-
} catch (error) {
|
|
46
|
-
logPluginsFetchError(logs, error.message)
|
|
47
|
-
return oldPluginsList
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// 1 minute HTTP request timeout
|
|
52
|
-
const PLUGINS_LIST_TIMEOUT = 6e4
|
|
53
|
-
|
|
54
|
-
const isValidPluginsList = function (pluginsList) {
|
|
55
|
-
return Array.isArray(pluginsList) && pluginsList.every(isPlainObj)
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
const normalizePluginsList = function (pluginsList) {
|
|
59
|
-
return Object.fromEntries(pluginsList.map(normalizePluginItem))
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// `version` in `plugins.json` is the latest version.
|
|
63
|
-
// A `compatibility` array of objects can be added to specify conditions to
|
|
64
|
-
// apply different versions.
|
|
65
|
-
// `netlify/plugins` ensures that `compatibility`:
|
|
66
|
-
// - Has the proper shape.
|
|
67
|
-
// - Is sorted from the highest to lowest version.
|
|
68
|
-
// - Does not include the latest `version`.
|
|
69
|
-
const normalizePluginItem = function ({ package: packageName, version, compatibility = [] }) {
|
|
70
|
-
const versions = compatibility.length === 0 ? [{ version }] : compatibility
|
|
71
|
-
const versionsA = versions.map(normalizeCompatVersion)
|
|
72
|
-
return [packageName, versionsA]
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
const normalizeCompatVersion = function ({ version, migrationGuide, featureFlag, ...otherProperties }) {
|
|
76
|
-
const conditions = Object.entries(otherProperties).filter(isCondition).map(normalizeCondition)
|
|
77
|
-
return { version, migrationGuide, featureFlag, conditions }
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
const isCondition = function ([type]) {
|
|
81
|
-
return type in CONDITIONS
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const normalizeCondition = function ([type, condition]) {
|
|
85
|
-
return { type, condition }
|
|
86
|
-
}
|
package/src/plugins/load.js
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { addErrorInfo } from '../error/info.js'
|
|
2
|
-
import { addPluginLoadErrorStatus } from '../status/load_error.js'
|
|
3
|
-
import { measureDuration } from '../time/main.js'
|
|
4
|
-
|
|
5
|
-
import { callChild } from './ipc.js'
|
|
6
|
-
|
|
7
|
-
// Retrieve all plugins steps
|
|
8
|
-
// Can use either a module name or a file path to the plugin.
|
|
9
|
-
export const loadPlugins = async function ({
|
|
10
|
-
pluginsOptions,
|
|
11
|
-
childProcesses,
|
|
12
|
-
packageJson,
|
|
13
|
-
timers,
|
|
14
|
-
logs,
|
|
15
|
-
debug,
|
|
16
|
-
verbose,
|
|
17
|
-
}) {
|
|
18
|
-
return pluginsOptions.length === 0
|
|
19
|
-
? { pluginsSteps: [], timers }
|
|
20
|
-
: await loadAllPlugins({ pluginsOptions, childProcesses, packageJson, timers, logs, debug, verbose })
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const tLoadAllPlugins = async function ({ pluginsOptions, childProcesses, packageJson, logs, debug, verbose }) {
|
|
24
|
-
const pluginsSteps = await Promise.all(
|
|
25
|
-
pluginsOptions.map((pluginOptions, index) =>
|
|
26
|
-
loadPlugin(pluginOptions, { childProcesses, index, packageJson, logs, debug, verbose }),
|
|
27
|
-
),
|
|
28
|
-
)
|
|
29
|
-
const pluginsStepsA = pluginsSteps.flat()
|
|
30
|
-
return { pluginsSteps: pluginsStepsA }
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Only performed if there are some plugins
|
|
34
|
-
const loadAllPlugins = measureDuration(tLoadAllPlugins, 'load_plugins')
|
|
35
|
-
|
|
36
|
-
// Retrieve plugin steps for one plugin.
|
|
37
|
-
// Do it by executing the plugin `load` event handler.
|
|
38
|
-
const loadPlugin = async function (
|
|
39
|
-
{ packageName, pluginPackageJson, pluginPackageJson: { version } = {}, pluginPath, inputs, loadedFrom, origin },
|
|
40
|
-
{ childProcesses, index, packageJson, logs, debug, verbose },
|
|
41
|
-
) {
|
|
42
|
-
const { childProcess } = childProcesses[index]
|
|
43
|
-
const loadEvent = 'load'
|
|
44
|
-
|
|
45
|
-
try {
|
|
46
|
-
const { events } = await callChild({
|
|
47
|
-
childProcess,
|
|
48
|
-
eventName: 'load',
|
|
49
|
-
payload: { pluginPath, inputs, packageJson, verbose },
|
|
50
|
-
logs,
|
|
51
|
-
verbose: false,
|
|
52
|
-
})
|
|
53
|
-
const pluginSteps = events.map((event) => ({
|
|
54
|
-
event,
|
|
55
|
-
packageName,
|
|
56
|
-
loadedFrom,
|
|
57
|
-
origin,
|
|
58
|
-
pluginPackageJson,
|
|
59
|
-
childProcess,
|
|
60
|
-
}))
|
|
61
|
-
return pluginSteps
|
|
62
|
-
} catch (error) {
|
|
63
|
-
addErrorInfo(error, {
|
|
64
|
-
plugin: { packageName, pluginPackageJson },
|
|
65
|
-
location: { event: loadEvent, packageName, loadedFrom, origin },
|
|
66
|
-
})
|
|
67
|
-
addPluginLoadErrorStatus({ error, packageName, version, debug })
|
|
68
|
-
throw error
|
|
69
|
-
}
|
|
70
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import { addErrorInfo } from '../../error/info.js'
|
|
2
|
-
import { serializeObject } from '../../log/serialize.js'
|
|
3
|
-
import { THEME } from '../../log/theme.js'
|
|
4
|
-
|
|
5
|
-
// Check that plugin inputs match the validation specified in "manifest.yml"
|
|
6
|
-
// Also assign default values
|
|
7
|
-
export const checkInputs = function ({
|
|
8
|
-
inputs,
|
|
9
|
-
manifest: { inputs: rules = [] },
|
|
10
|
-
packageName,
|
|
11
|
-
pluginPackageJson,
|
|
12
|
-
loadedFrom,
|
|
13
|
-
origin,
|
|
14
|
-
}) {
|
|
15
|
-
try {
|
|
16
|
-
const inputsA = addDefaults(inputs, rules)
|
|
17
|
-
checkRequiredInputs({ inputs: inputsA, rules, packageName, pluginPackageJson, loadedFrom, origin })
|
|
18
|
-
checkUnknownInputs({ inputs: inputsA, rules, packageName, pluginPackageJson, loadedFrom, origin })
|
|
19
|
-
return inputsA
|
|
20
|
-
} catch (error) {
|
|
21
|
-
error.message = `${error.message}
|
|
22
|
-
|
|
23
|
-
${THEME.errorSubHeader('Plugin inputs')}
|
|
24
|
-
${serializeObject(inputs)}`
|
|
25
|
-
throw error
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// Add "inputs[*].default"
|
|
30
|
-
const addDefaults = function (inputs, rules) {
|
|
31
|
-
const defaults = rules.filter(hasDefault).map(getDefault)
|
|
32
|
-
return Object.assign({}, ...defaults, inputs)
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const hasDefault = function (rule) {
|
|
36
|
-
return rule.default !== undefined
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const getDefault = function ({ name, default: defaultValue }) {
|
|
40
|
-
return { [name]: defaultValue }
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
// Check "inputs[*].required"
|
|
44
|
-
const checkRequiredInputs = function ({ inputs, rules, packageName, pluginPackageJson, loadedFrom, origin }) {
|
|
45
|
-
const missingInputs = rules.filter((rule) => isMissingRequired(inputs, rule))
|
|
46
|
-
if (missingInputs.length === 0) {
|
|
47
|
-
return
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const names = missingInputs.map(getName)
|
|
51
|
-
const error = new Error(`Required inputs for plugin "${packageName}": ${names.join(', ')}`)
|
|
52
|
-
addInputError({ error, name: names[0], packageName, pluginPackageJson, loadedFrom, origin })
|
|
53
|
-
throw error
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
const isMissingRequired = function (inputs, { name, required }) {
|
|
57
|
-
return required && inputs[name] === undefined
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
const getName = function ({ name }) {
|
|
61
|
-
return name
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Check each "inputs[*].*" property for a specific input
|
|
65
|
-
const checkUnknownInputs = function ({ inputs, rules, packageName, pluginPackageJson, loadedFrom, origin }) {
|
|
66
|
-
const knownInputs = rules.map(getName)
|
|
67
|
-
const unknownInputs = Object.keys(inputs).filter((name) => !knownInputs.includes(name))
|
|
68
|
-
if (unknownInputs.length === 0) {
|
|
69
|
-
return
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const unknownInputsMessage = getUnknownInputsMessage({ packageName, knownInputs, unknownInputs })
|
|
73
|
-
const error = new Error(`${unknownInputsMessage}
|
|
74
|
-
Check your plugin configuration to be sure that:
|
|
75
|
-
- the input name is spelled correctly
|
|
76
|
-
- the input is included in the plugin's available configuration options
|
|
77
|
-
- the plugin's input requirements have not changed`)
|
|
78
|
-
const [name] = unknownInputs
|
|
79
|
-
addInputError({ error, name, packageName, pluginPackageJson, loadedFrom, origin })
|
|
80
|
-
throw error
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const getUnknownInputsMessage = function ({ packageName, knownInputs, unknownInputs }) {
|
|
84
|
-
const unknownInputsStr = unknownInputs.map(quoteWord).join(', ')
|
|
85
|
-
|
|
86
|
-
if (knownInputs.length === 0) {
|
|
87
|
-
return `Plugin "${packageName}" does not accept any inputs but you specified: ${unknownInputsStr}`
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
const knownInputsStr = knownInputs.map(quoteWord).join(', ')
|
|
91
|
-
return `Unknown inputs for plugin "${packageName}": ${unknownInputsStr}
|
|
92
|
-
Plugin inputs should be one of: ${knownInputsStr}`
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const quoteWord = function (word) {
|
|
96
|
-
return `"${word}"`
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Add error information
|
|
100
|
-
const addInputError = function ({ error, name, packageName, pluginPackageJson, loadedFrom, origin }) {
|
|
101
|
-
addErrorInfo(error, {
|
|
102
|
-
type: 'pluginInput',
|
|
103
|
-
plugin: { packageName, pluginPackageJson },
|
|
104
|
-
location: { event: 'load', packageName, input: name, loadedFrom, origin },
|
|
105
|
-
})
|
|
106
|
-
}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { promises as fs } from 'fs'
|
|
2
|
-
|
|
3
|
-
import { load as loadYaml, JSON_SCHEMA } from 'js-yaml'
|
|
4
|
-
|
|
5
|
-
import { addErrorInfo } from '../../error/info.js'
|
|
6
|
-
|
|
7
|
-
import { validateManifest } from './validate.js'
|
|
8
|
-
|
|
9
|
-
// Load "manifest.yml" using its file path
|
|
10
|
-
export const loadManifest = async function ({ manifestPath, packageName, pluginPackageJson, loadedFrom, origin }) {
|
|
11
|
-
try {
|
|
12
|
-
const rawManifest = await loadRawManifest(manifestPath)
|
|
13
|
-
const manifest = await parseManifest(rawManifest)
|
|
14
|
-
validateManifest(manifest, rawManifest)
|
|
15
|
-
return manifest
|
|
16
|
-
} catch (error) {
|
|
17
|
-
addErrorInfo(error, {
|
|
18
|
-
type: 'pluginValidation',
|
|
19
|
-
plugin: { packageName, pluginPackageJson },
|
|
20
|
-
location: { event: 'load', packageName, loadedFrom, origin },
|
|
21
|
-
})
|
|
22
|
-
throw error
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
const loadRawManifest = async function (manifestPath) {
|
|
27
|
-
try {
|
|
28
|
-
return await fs.readFile(manifestPath, 'utf8')
|
|
29
|
-
} catch (error) {
|
|
30
|
-
error.message = `Could not load plugin's "manifest.yml"\n${error.message}`
|
|
31
|
-
throw error
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
const parseManifest = async function (rawManifest) {
|
|
36
|
-
try {
|
|
37
|
-
return await loadYaml(rawManifest, { schema: JSON_SCHEMA, json: true })
|
|
38
|
-
} catch (error) {
|
|
39
|
-
throw new Error(`Could not parse plugin's "manifest.yml"\n${error.message}`)
|
|
40
|
-
}
|
|
41
|
-
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { addPluginLoadErrorStatus } from '../../status/load_error.js'
|
|
2
|
-
|
|
3
|
-
import { checkInputs } from './check.js'
|
|
4
|
-
import { loadManifest } from './load.js'
|
|
5
|
-
import { getManifestPath } from './path.js'
|
|
6
|
-
|
|
7
|
-
// Load plugin's `manifest.yml`
|
|
8
|
-
export const useManifest = async function (
|
|
9
|
-
{ packageName, loadedFrom, origin, inputs },
|
|
10
|
-
{ pluginDir, packageDir, pluginPackageJson, pluginPackageJson: { version }, debug },
|
|
11
|
-
) {
|
|
12
|
-
const manifestPath = await getManifestPath({ pluginDir, packageDir, packageName })
|
|
13
|
-
|
|
14
|
-
try {
|
|
15
|
-
const manifest = await loadManifest({ manifestPath, packageName, pluginPackageJson, loadedFrom, origin })
|
|
16
|
-
const inputsA = checkInputs({ inputs, manifest, packageName, pluginPackageJson, loadedFrom, origin })
|
|
17
|
-
return { manifest, inputs: inputsA }
|
|
18
|
-
} catch (error) {
|
|
19
|
-
addPluginLoadErrorStatus({ error, packageName, version, debug })
|
|
20
|
-
throw error
|
|
21
|
-
}
|
|
22
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { locatePath } from 'locate-path'
|
|
2
|
-
|
|
3
|
-
import { addErrorInfo } from '../../error/info.js'
|
|
4
|
-
|
|
5
|
-
// Retrieve "manifest.yml" path for a specific plugin
|
|
6
|
-
export const getManifestPath = async function ({ pluginDir, packageDir, packageName }) {
|
|
7
|
-
const dirs = [pluginDir, packageDir]
|
|
8
|
-
.filter(Boolean)
|
|
9
|
-
.flatMap((dir) => MANIFEST_FILENAMES.map((filename) => `${dir}/${filename}`))
|
|
10
|
-
const manifestPath = await locatePath(dirs)
|
|
11
|
-
validateManifestExists(manifestPath, packageName)
|
|
12
|
-
return manifestPath
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
const validateManifestExists = function (manifestPath, packageName) {
|
|
16
|
-
if (manifestPath !== undefined) {
|
|
17
|
-
return
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const error = new Error(
|
|
21
|
-
`The plugin "${packageName}" is missing a "manifest.yml".
|
|
22
|
-
This might mean:
|
|
23
|
-
- The plugin "package" name is misspelled
|
|
24
|
-
- The plugin "package" points to a Node module that is not a Netlify Build plugin
|
|
25
|
-
- If you're developing a plugin, please see the documentation at https://docs.netlify.com/configure-builds/build-plugins/create-plugins/#anatomy-of-a-plugin`,
|
|
26
|
-
)
|
|
27
|
-
addErrorInfo(error, { type: 'resolveConfig' })
|
|
28
|
-
throw error
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
const MANIFEST_FILENAMES = ['manifest.yml', 'manifest.yaml']
|