@netlify/build 28.0.1-beta → 28.1.0-framework-version-detection

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.
Files changed (259) hide show
  1. package/bin.js +5 -0
  2. package/lib/core/bin.js +66 -0
  3. package/lib/core/build.js +355 -0
  4. package/lib/core/config.js +125 -0
  5. package/lib/core/constants.js +116 -0
  6. package/lib/core/dev.js +27 -0
  7. package/lib/core/dry.js +21 -0
  8. package/lib/core/feature_flags.js +19 -0
  9. package/lib/core/flags.js +201 -0
  10. package/lib/core/lingering.js +68 -0
  11. package/lib/core/main.js +105 -0
  12. package/lib/core/missing_side_file.js +17 -0
  13. package/lib/core/normalize_flags.js +59 -0
  14. package/lib/core/severity.js +21 -0
  15. package/lib/core/types.js +8 -0
  16. package/lib/core/user_node_version.js +32 -0
  17. package/lib/env/changes.js +43 -0
  18. package/lib/env/main.js +14 -0
  19. package/lib/env/metadata.js +68 -0
  20. package/lib/error/api.js +37 -0
  21. package/lib/error/build.js +36 -0
  22. package/{src → lib}/error/cancel.js +5 -6
  23. package/lib/error/colors.js +9 -0
  24. package/lib/error/handle.js +46 -0
  25. package/lib/error/info.js +37 -0
  26. package/lib/error/monitor/location.js +16 -0
  27. package/lib/error/monitor/normalize.js +86 -0
  28. package/lib/error/monitor/print.js +20 -0
  29. package/lib/error/monitor/report.js +120 -0
  30. package/lib/error/monitor/start.js +61 -0
  31. package/lib/error/parse/clean_stack.js +70 -0
  32. package/lib/error/parse/location.js +50 -0
  33. package/lib/error/parse/normalize.js +24 -0
  34. package/lib/error/parse/parse.js +67 -0
  35. package/lib/error/parse/plugin.js +55 -0
  36. package/lib/error/parse/properties.js +16 -0
  37. package/lib/error/parse/serialize_log.js +34 -0
  38. package/lib/error/parse/serialize_status.js +18 -0
  39. package/lib/error/parse/stack.js +34 -0
  40. package/lib/error/type.js +171 -0
  41. package/lib/install/functions.js +20 -0
  42. package/lib/install/local.js +45 -0
  43. package/lib/install/main.js +67 -0
  44. package/lib/install/missing.js +54 -0
  45. package/{src → lib}/log/colors.js +15 -22
  46. package/lib/log/description.js +21 -0
  47. package/lib/log/header.js +14 -0
  48. package/lib/log/header_func.js +13 -0
  49. package/lib/log/logger.js +140 -0
  50. package/lib/log/messages/compatibility.js +120 -0
  51. package/lib/log/messages/config.js +98 -0
  52. package/lib/log/messages/core.js +50 -0
  53. package/lib/log/messages/core_steps.js +75 -0
  54. package/lib/log/messages/dry.js +41 -0
  55. package/lib/log/messages/install.js +25 -0
  56. package/lib/log/messages/ipc.js +29 -0
  57. package/lib/log/messages/mutations.js +62 -0
  58. package/{src → lib}/log/messages/plugins.js +18 -32
  59. package/lib/log/messages/status.js +14 -0
  60. package/lib/log/messages/steps.js +18 -0
  61. package/lib/log/old_version.js +32 -0
  62. package/lib/log/serialize.js +10 -0
  63. package/lib/log/stream.js +68 -0
  64. package/lib/log/theme.js +25 -0
  65. package/lib/plugins/child/diff.js +46 -0
  66. package/lib/plugins/child/error.js +26 -0
  67. package/lib/plugins/child/lazy.js +15 -0
  68. package/lib/plugins/child/load.js +22 -0
  69. package/lib/plugins/child/logic.js +57 -0
  70. package/lib/plugins/child/main.js +37 -0
  71. package/lib/plugins/child/run.js +19 -0
  72. package/lib/plugins/child/status.js +63 -0
  73. package/lib/plugins/child/typescript.js +28 -0
  74. package/lib/plugins/child/utils.js +42 -0
  75. package/lib/plugins/child/validate.js +31 -0
  76. package/lib/plugins/compatibility.js +104 -0
  77. package/{src → lib}/plugins/error.js +31 -35
  78. package/{src → lib}/plugins/events.js +7 -12
  79. package/lib/plugins/expected_version.js +81 -0
  80. package/lib/plugins/ipc.js +120 -0
  81. package/lib/plugins/list.js +73 -0
  82. package/lib/plugins/load.js +50 -0
  83. package/lib/plugins/manifest/check.js +85 -0
  84. package/lib/plugins/manifest/load.js +38 -0
  85. package/lib/plugins/manifest/main.js +17 -0
  86. package/lib/plugins/manifest/path.js +24 -0
  87. package/lib/plugins/manifest/validate.js +91 -0
  88. package/lib/plugins/node_version.js +30 -0
  89. package/lib/plugins/options.js +55 -0
  90. package/lib/plugins/pinned_version.js +83 -0
  91. package/lib/plugins/resolve.js +110 -0
  92. package/lib/plugins/spawn.js +54 -0
  93. package/lib/plugins_core/add.js +35 -0
  94. package/lib/plugins_core/build_command.js +50 -0
  95. package/lib/plugins_core/deploy/buildbot_client.js +87 -0
  96. package/lib/plugins_core/deploy/index.js +49 -0
  97. package/{src → lib}/plugins_core/deploy/manifest.yml +0 -0
  98. package/lib/plugins_core/edge_functions/index.js +79 -0
  99. package/lib/plugins_core/edge_functions/lib/error.js +17 -0
  100. package/lib/plugins_core/edge_functions/lib/internal_manifest.js +50 -0
  101. package/lib/plugins_core/edge_functions/validate_manifest/validate_edge_functions_manifest.js +75 -0
  102. package/lib/plugins_core/functions/error.js +123 -0
  103. package/lib/plugins_core/functions/feature_flags.js +6 -0
  104. package/lib/plugins_core/functions/index.js +114 -0
  105. package/lib/plugins_core/functions/utils.js +45 -0
  106. package/lib/plugins_core/functions/zisi.js +39 -0
  107. package/{src → lib}/plugins_core/functions_install/index.js +8 -11
  108. package/{src → lib}/plugins_core/functions_install/manifest.yml +0 -0
  109. package/lib/plugins_core/list.js +20 -0
  110. package/lib/status/add.js +30 -0
  111. package/lib/status/colors.js +18 -0
  112. package/lib/status/load_error.js +10 -0
  113. package/lib/status/report.js +83 -0
  114. package/lib/status/success.js +14 -0
  115. package/lib/steps/core_step.js +57 -0
  116. package/lib/steps/error.js +65 -0
  117. package/lib/steps/get.js +43 -0
  118. package/lib/steps/plugin.js +55 -0
  119. package/lib/steps/return.js +25 -0
  120. package/lib/steps/run_core_steps.js +126 -0
  121. package/lib/steps/run_step.js +188 -0
  122. package/lib/steps/run_steps.js +96 -0
  123. package/lib/steps/update_config.js +66 -0
  124. package/lib/telemetry/main.js +97 -0
  125. package/lib/time/aggregate.js +120 -0
  126. package/lib/time/main.js +37 -0
  127. package/lib/time/measure.js +18 -0
  128. package/lib/time/report.js +47 -0
  129. package/lib/utils/errors.js +13 -0
  130. package/lib/utils/json.js +15 -0
  131. package/{src → lib}/utils/omit.js +3 -4
  132. package/lib/utils/package.js +22 -0
  133. package/lib/utils/remove_falsy.js +8 -0
  134. package/lib/utils/resolve.js +41 -0
  135. package/lib/utils/runtime.js +5 -0
  136. package/lib/utils/semver.js +28 -0
  137. package/package.json +39 -19
  138. package/types/config/netlify_config.d.ts +4 -4
  139. package/types/netlify_plugin_constants.d.ts +8 -8
  140. package/src/core/bin.js +0 -83
  141. package/src/core/config.js +0 -186
  142. package/src/core/constants.js +0 -156
  143. package/src/core/dry.js +0 -39
  144. package/src/core/feature_flags.js +0 -21
  145. package/src/core/flags.js +0 -194
  146. package/src/core/lingering.js +0 -85
  147. package/src/core/main.js +0 -692
  148. package/src/core/missing_side_file.js +0 -29
  149. package/src/core/normalize_flags.js +0 -69
  150. package/src/core/severity.js +0 -22
  151. package/src/core/user_node_version.js +0 -41
  152. package/src/env/changes.js +0 -52
  153. package/src/env/main.js +0 -19
  154. package/src/env/metadata.js +0 -81
  155. package/src/error/api.js +0 -46
  156. package/src/error/build.js +0 -50
  157. package/src/error/colors.js +0 -11
  158. package/src/error/handle.js +0 -57
  159. package/src/error/info.js +0 -46
  160. package/src/error/monitor/location.js +0 -21
  161. package/src/error/monitor/normalize.js +0 -77
  162. package/src/error/monitor/print.js +0 -42
  163. package/src/error/monitor/report.js +0 -133
  164. package/src/error/monitor/start.js +0 -69
  165. package/src/error/parse/clean_stack.js +0 -87
  166. package/src/error/parse/location.js +0 -58
  167. package/src/error/parse/normalize.js +0 -29
  168. package/src/error/parse/parse.js +0 -97
  169. package/src/error/parse/plugin.js +0 -70
  170. package/src/error/parse/properties.js +0 -23
  171. package/src/error/parse/serialize_log.js +0 -42
  172. package/src/error/parse/serialize_status.js +0 -23
  173. package/src/error/parse/stack.js +0 -43
  174. package/src/error/type.js +0 -182
  175. package/src/install/functions.js +0 -28
  176. package/src/install/local.js +0 -62
  177. package/src/install/main.js +0 -81
  178. package/src/install/missing.js +0 -67
  179. package/src/log/description.js +0 -26
  180. package/src/log/header.js +0 -16
  181. package/src/log/header_func.js +0 -17
  182. package/src/log/logger.js +0 -107
  183. package/src/log/messages/compatibility.js +0 -164
  184. package/src/log/messages/config.js +0 -105
  185. package/src/log/messages/core.js +0 -70
  186. package/src/log/messages/core_steps.js +0 -104
  187. package/src/log/messages/dry.js +0 -63
  188. package/src/log/messages/install.js +0 -20
  189. package/src/log/messages/ipc.js +0 -38
  190. package/src/log/messages/mutations.js +0 -82
  191. package/src/log/messages/status.js +0 -16
  192. package/src/log/messages/steps.js +0 -22
  193. package/src/log/old_version.js +0 -41
  194. package/src/log/serialize.js +0 -13
  195. package/src/log/stream.js +0 -85
  196. package/src/log/theme.js +0 -26
  197. package/src/plugins/child/diff.js +0 -55
  198. package/src/plugins/child/error.js +0 -32
  199. package/src/plugins/child/lazy.js +0 -18
  200. package/src/plugins/child/load.js +0 -29
  201. package/src/plugins/child/logic.js +0 -57
  202. package/src/plugins/child/main.js +0 -51
  203. package/src/plugins/child/run.js +0 -28
  204. package/src/plugins/child/status.js +0 -67
  205. package/src/plugins/child/typescript.js +0 -45
  206. package/src/plugins/child/utils.js +0 -56
  207. package/src/plugins/child/validate.js +0 -34
  208. package/src/plugins/compatibility.js +0 -128
  209. package/src/plugins/expected_version.js +0 -119
  210. package/src/plugins/ipc.js +0 -145
  211. package/src/plugins/list.js +0 -86
  212. package/src/plugins/load.js +0 -70
  213. package/src/plugins/manifest/check.js +0 -106
  214. package/src/plugins/manifest/load.js +0 -41
  215. package/src/plugins/manifest/main.js +0 -22
  216. package/src/plugins/manifest/path.js +0 -31
  217. package/src/plugins/manifest/validate.js +0 -108
  218. package/src/plugins/node_version.js +0 -50
  219. package/src/plugins/options.js +0 -88
  220. package/src/plugins/pinned_version.js +0 -131
  221. package/src/plugins/resolve.js +0 -152
  222. package/src/plugins/spawn.js +0 -66
  223. package/src/plugins_core/add.js +0 -49
  224. package/src/plugins_core/build_command.js +0 -75
  225. package/src/plugins_core/deploy/buildbot_client.js +0 -102
  226. package/src/plugins_core/deploy/index.js +0 -73
  227. package/src/plugins_core/edge_functions/index.js +0 -107
  228. package/src/plugins_core/edge_functions/lib/internal_manifest.js +0 -54
  229. package/src/plugins_core/functions/error.js +0 -163
  230. package/src/plugins_core/functions/feature_flags.js +0 -6
  231. package/src/plugins_core/functions/index.js +0 -160
  232. package/src/plugins_core/functions/utils.js +0 -66
  233. package/src/plugins_core/functions/zisi.js +0 -53
  234. package/src/plugins_core/list.js +0 -27
  235. package/src/status/add.js +0 -36
  236. package/src/status/colors.js +0 -23
  237. package/src/status/load_error.js +0 -11
  238. package/src/status/report.js +0 -128
  239. package/src/status/success.js +0 -18
  240. package/src/steps/core_step.js +0 -90
  241. package/src/steps/error.js +0 -102
  242. package/src/steps/get.js +0 -32
  243. package/src/steps/plugin.js +0 -85
  244. package/src/steps/return.js +0 -52
  245. package/src/steps/run_core_steps.js +0 -194
  246. package/src/steps/run_step.js +0 -300
  247. package/src/steps/run_steps.js +0 -179
  248. package/src/steps/update_config.js +0 -93
  249. package/src/telemetry/main.js +0 -136
  250. package/src/time/aggregate.js +0 -146
  251. package/src/time/main.js +0 -48
  252. package/src/time/measure.js +0 -22
  253. package/src/time/report.js +0 -59
  254. package/src/utils/errors.js +0 -12
  255. package/src/utils/json.js +0 -19
  256. package/src/utils/package.js +0 -23
  257. package/src/utils/remove_falsy.js +0 -10
  258. package/src/utils/resolve.js +0 -46
  259. package/src/utils/semver.js +0 -34
@@ -1,128 +0,0 @@
1
- import pEvery from 'p-every'
2
- import pLocate from 'p-locate'
3
- import semver from 'semver'
4
-
5
- import { importJsonFile } from '../utils/json.js'
6
- import { resolvePath } from '../utils/resolve.js'
7
-
8
- // Retrieve the `expectedVersion` of a plugin:
9
- // - This is the version which should be run
10
- // - This takes version pinning into account
11
- // - If this does not match the currently cached version, it is installed first
12
- // This is also used to retrieve the `compatibleVersion` of a plugin
13
- // - This is the most recent version compatible with this site
14
- // - This is the same logic except it does not use version pinning
15
- // - This is only used to print a warning message when the `compatibleVersion`
16
- // is older than the currently used version.
17
- export const getExpectedVersion = async function ({ versions, nodeVersion, packageJson, buildDir, pinnedVersion }) {
18
- const { version, conditions } = await getCompatibleEntry({
19
- versions,
20
- nodeVersion,
21
- packageJson,
22
- buildDir,
23
- pinnedVersion,
24
- })
25
- const compatWarning = getCompatWarning(conditions)
26
- return { version, compatWarning }
27
- }
28
-
29
- // This function finds the right `compatibility` entry to use with the plugin.
30
- // - `compatibitlity` entries are meant for backward compatibility
31
- // Plugins should define each major version in `compatibility`.
32
- // - The entries are sorted from most to least recent version.
33
- // - After their first successful run, plugins are pinned by their major
34
- // version which is passed as `pinnedVersion` to the next builds.
35
- // When the plugin does not have a `pinnedVersion`, we use the most recent
36
- // `compatibility` entry whith a successful condition.
37
- // When the plugin has a `pinnedVersion`, we do not use the `compatibility`
38
- // conditions. Instead, we just use the most recent entry with a `version`
39
- // matching `pinnedVersion`.
40
- // When no `compatibility` entry matches, we use:
41
- // - If there is a `pinnedVersion`, use it unless `latestVersion` matches it
42
- // - Otherwise, use `latestVersion`
43
- const getCompatibleEntry = async function ({ versions, nodeVersion, packageJson, buildDir, pinnedVersion }) {
44
- if (pinnedVersion !== undefined) {
45
- return versions.find(({ version }) => semver.satisfies(version, pinnedVersion)) || { version: pinnedVersion }
46
- }
47
-
48
- const versionsWithConditions = versions.filter(hasConditions)
49
- const compatibleEntry = await pLocate(versionsWithConditions, ({ conditions }) =>
50
- matchesCompatField({ conditions, nodeVersion, packageJson, buildDir }),
51
- )
52
- return compatibleEntry || { version: versions[0].version }
53
- }
54
-
55
- // Ignore entries without conditions. Those are used to specify breaking
56
- // changes, i.e. meant to be used for version pinning instead.
57
- const hasConditions = function ({ conditions }) {
58
- return conditions.length !== 0
59
- }
60
-
61
- const matchesCompatField = async function ({ conditions, nodeVersion, packageJson, buildDir }) {
62
- return await pEvery(conditions, ({ type, condition }) =>
63
- CONDITIONS[type].test(condition, { nodeVersion, packageJson, buildDir }),
64
- )
65
- }
66
-
67
- // Retrieve warning message shown when using an older version with `compatibility`
68
- const getCompatWarning = function (conditions = []) {
69
- return conditions.map(getConditionWarning).join(', ')
70
- }
71
-
72
- const getConditionWarning = function ({ type, condition }) {
73
- return CONDITIONS[type].warning(condition)
74
- }
75
-
76
- // Plugins can use `compatibility.{version}.nodeVersion: 'allowedNodeVersion'`
77
- // to deliver different plugin versions based on the Node.js version
78
- const nodeVersionTest = function (allowedNodeVersion, { nodeVersion }) {
79
- return semver.satisfies(nodeVersion, allowedNodeVersion)
80
- }
81
-
82
- const nodeVersionWarning = function (allowedNodeVersion) {
83
- return `Node.js ${allowedNodeVersion}`
84
- }
85
-
86
- const siteDependenciesTest = async function (
87
- allowedSiteDependencies,
88
- { packageJson: { devDependencies, dependencies }, buildDir },
89
- ) {
90
- const siteDependencies = { ...devDependencies, ...dependencies }
91
- return await pEvery(Object.entries(allowedSiteDependencies), ([dependencyName, allowedVersion]) =>
92
- siteDependencyTest({ dependencyName, allowedVersion, siteDependencies, buildDir }),
93
- )
94
- }
95
-
96
- const siteDependencyTest = async function ({ dependencyName, allowedVersion, siteDependencies, buildDir }) {
97
- const siteDependency = siteDependencies[dependencyName]
98
- if (typeof siteDependency !== 'string') {
99
- return false
100
- }
101
-
102
- // if this is a valid version we can apply the rule directly
103
- if (semver.clean(siteDependency) !== null) {
104
- return semver.satisfies(siteDependency, allowedVersion)
105
- }
106
-
107
- try {
108
- // if this is a range we need to get the exact version
109
- const packageJsonPath = await resolvePath(`${dependencyName}/package.json`, buildDir)
110
- const { version } = await importJsonFile(packageJsonPath)
111
- return semver.satisfies(version, allowedVersion)
112
- } catch {
113
- return false
114
- }
115
- }
116
-
117
- const siteDependenciesWarning = function (allowedSiteDependencies) {
118
- return Object.entries(allowedSiteDependencies).map(siteDependencyWarning).join(',')
119
- }
120
-
121
- const siteDependencyWarning = function ([dependencyName, allowedVersion]) {
122
- return `${dependencyName}@${allowedVersion}`
123
- }
124
-
125
- export const CONDITIONS = {
126
- nodeVersion: { test: nodeVersionTest, warning: nodeVersionWarning },
127
- siteDependencies: { test: siteDependenciesTest, warning: siteDependenciesWarning },
128
- }
@@ -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
- }
@@ -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
- }
@@ -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
- }
@@ -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
- }