@netlify/build 29.0.0-rc → 29.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (266) hide show
  1. package/bin.js +5 -0
  2. package/lib/core/bin.js +66 -0
  3. package/lib/core/build.js +356 -0
  4. package/lib/core/config.js +121 -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 +21 -0
  9. package/lib/core/flags.js +201 -0
  10. package/lib/core/lingering.js +68 -0
  11. package/lib/core/main.js +110 -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/report.js +27 -0
  41. package/lib/error/type.js +177 -0
  42. package/lib/install/functions.js +20 -0
  43. package/lib/install/local.js +45 -0
  44. package/lib/install/main.js +67 -0
  45. package/lib/install/missing.js +54 -0
  46. package/lib/log/colors.js +28 -0
  47. package/lib/log/description.js +21 -0
  48. package/lib/log/header.js +14 -0
  49. package/lib/log/header_func.js +13 -0
  50. package/lib/log/logger.js +140 -0
  51. package/lib/log/messages/compatibility.js +146 -0
  52. package/lib/log/messages/config.js +91 -0
  53. package/lib/log/messages/core.js +51 -0
  54. package/lib/log/messages/core_steps.js +75 -0
  55. package/lib/log/messages/dry.js +41 -0
  56. package/lib/log/messages/install.js +25 -0
  57. package/lib/log/messages/ipc.js +29 -0
  58. package/lib/log/messages/mutations.js +62 -0
  59. package/{src → lib}/log/messages/plugins.js +18 -32
  60. package/lib/log/messages/status.js +14 -0
  61. package/lib/log/messages/steps.js +18 -0
  62. package/lib/log/old_version.js +32 -0
  63. package/lib/log/serialize.js +10 -0
  64. package/lib/log/stream.js +68 -0
  65. package/lib/log/theme.js +27 -0
  66. package/lib/plugins/child/diff.js +46 -0
  67. package/lib/plugins/child/error.js +26 -0
  68. package/lib/plugins/child/lazy.js +15 -0
  69. package/lib/plugins/child/load.js +22 -0
  70. package/lib/plugins/child/logic.js +57 -0
  71. package/lib/plugins/child/main.js +37 -0
  72. package/lib/plugins/child/run.js +19 -0
  73. package/lib/plugins/child/status.js +63 -0
  74. package/lib/plugins/child/typescript.js +28 -0
  75. package/lib/plugins/child/utils.js +42 -0
  76. package/lib/plugins/child/validate.js +31 -0
  77. package/lib/plugins/compatibility.js +104 -0
  78. package/{src → lib}/plugins/error.js +31 -35
  79. package/{src → lib}/plugins/events.js +7 -12
  80. package/lib/plugins/expected_version.js +81 -0
  81. package/lib/plugins/internal.js +10 -0
  82. package/lib/plugins/ipc.js +120 -0
  83. package/lib/plugins/list.js +73 -0
  84. package/lib/plugins/load.js +50 -0
  85. package/lib/plugins/manifest/check.js +85 -0
  86. package/lib/plugins/manifest/load.js +38 -0
  87. package/lib/plugins/manifest/main.js +19 -0
  88. package/lib/plugins/manifest/path.js +24 -0
  89. package/lib/plugins/manifest/validate.js +91 -0
  90. package/lib/plugins/node_version.js +35 -0
  91. package/lib/plugins/options.js +70 -0
  92. package/lib/plugins/pinned_version.js +83 -0
  93. package/lib/plugins/resolve.js +110 -0
  94. package/lib/plugins/spawn.js +58 -0
  95. package/lib/plugins_core/add.js +35 -0
  96. package/lib/plugins_core/build_command.js +50 -0
  97. package/lib/plugins_core/deploy/buildbot_client.js +87 -0
  98. package/lib/plugins_core/deploy/index.js +49 -0
  99. package/{src → lib}/plugins_core/deploy/manifest.yml +0 -0
  100. package/lib/plugins_core/edge_functions/index.js +76 -0
  101. package/{src → lib}/plugins_core/edge_functions/lib/error.js +13 -17
  102. package/lib/plugins_core/edge_functions/validate_manifest/validate_edge_functions_manifest.js +21 -0
  103. package/lib/plugins_core/functions/error.js +123 -0
  104. package/lib/plugins_core/functions/feature_flags.js +6 -0
  105. package/lib/plugins_core/functions/index.js +114 -0
  106. package/lib/plugins_core/functions/utils.js +45 -0
  107. package/lib/plugins_core/functions/zisi.js +39 -0
  108. package/{src → lib}/plugins_core/functions_install/index.js +8 -11
  109. package/{src → lib}/plugins_core/functions_install/manifest.yml +0 -0
  110. package/lib/plugins_core/list.js +20 -0
  111. package/lib/report/statsd.js +31 -0
  112. package/lib/status/add.js +30 -0
  113. package/lib/status/colors.js +18 -0
  114. package/lib/status/load_error.js +10 -0
  115. package/lib/status/report.js +83 -0
  116. package/lib/status/success.js +14 -0
  117. package/lib/steps/core_step.js +59 -0
  118. package/lib/steps/error.js +65 -0
  119. package/lib/steps/get.js +43 -0
  120. package/lib/steps/plugin.js +55 -0
  121. package/lib/steps/return.js +25 -0
  122. package/lib/steps/run_core_steps.js +117 -0
  123. package/lib/steps/run_step.js +190 -0
  124. package/lib/steps/run_steps.js +96 -0
  125. package/lib/steps/update_config.js +66 -0
  126. package/lib/telemetry/main.js +97 -0
  127. package/lib/time/aggregate.js +109 -0
  128. package/lib/time/main.js +31 -0
  129. package/lib/time/measure.js +16 -0
  130. package/lib/time/report.js +24 -0
  131. package/lib/utils/errors.js +13 -0
  132. package/lib/utils/json.js +15 -0
  133. package/lib/utils/omit.js +3 -0
  134. package/lib/utils/package.js +24 -0
  135. package/lib/utils/remove_falsy.js +8 -0
  136. package/lib/utils/resolve.js +41 -0
  137. package/lib/utils/runtime.js +5 -0
  138. package/lib/utils/semver.js +28 -0
  139. package/package.json +41 -24
  140. package/types/config/netlify_config.d.ts +4 -4
  141. package/types/netlify_plugin_constants.d.ts +8 -8
  142. package/src/core/bin.js +0 -83
  143. package/src/core/build.js +0 -554
  144. package/src/core/config.js +0 -186
  145. package/src/core/constants.js +0 -156
  146. package/src/core/dev.js +0 -31
  147. package/src/core/dry.js +0 -39
  148. package/src/core/feature_flags.js +0 -22
  149. package/src/core/flags.js +0 -204
  150. package/src/core/lingering.js +0 -85
  151. package/src/core/main.js +0 -165
  152. package/src/core/missing_side_file.js +0 -29
  153. package/src/core/normalize_flags.js +0 -70
  154. package/src/core/severity.js +0 -22
  155. package/src/core/user_node_version.js +0 -41
  156. package/src/env/changes.js +0 -52
  157. package/src/env/main.js +0 -19
  158. package/src/env/metadata.js +0 -81
  159. package/src/error/api.js +0 -46
  160. package/src/error/build.js +0 -50
  161. package/src/error/colors.js +0 -11
  162. package/src/error/handle.js +0 -57
  163. package/src/error/info.js +0 -46
  164. package/src/error/monitor/location.js +0 -21
  165. package/src/error/monitor/normalize.js +0 -96
  166. package/src/error/monitor/print.js +0 -42
  167. package/src/error/monitor/report.js +0 -138
  168. package/src/error/monitor/start.js +0 -69
  169. package/src/error/parse/clean_stack.js +0 -87
  170. package/src/error/parse/location.js +0 -62
  171. package/src/error/parse/normalize.js +0 -29
  172. package/src/error/parse/parse.js +0 -97
  173. package/src/error/parse/plugin.js +0 -70
  174. package/src/error/parse/properties.js +0 -23
  175. package/src/error/parse/serialize_log.js +0 -42
  176. package/src/error/parse/serialize_status.js +0 -23
  177. package/src/error/parse/stack.js +0 -43
  178. package/src/error/type.js +0 -189
  179. package/src/install/functions.js +0 -28
  180. package/src/install/local.js +0 -62
  181. package/src/install/main.js +0 -81
  182. package/src/install/missing.js +0 -67
  183. package/src/log/colors.js +0 -34
  184. package/src/log/description.js +0 -26
  185. package/src/log/header.js +0 -16
  186. package/src/log/header_func.js +0 -17
  187. package/src/log/logger.js +0 -161
  188. package/src/log/messages/compatibility.js +0 -164
  189. package/src/log/messages/config.js +0 -107
  190. package/src/log/messages/core.js +0 -70
  191. package/src/log/messages/core_steps.js +0 -104
  192. package/src/log/messages/dry.js +0 -63
  193. package/src/log/messages/install.js +0 -20
  194. package/src/log/messages/ipc.js +0 -38
  195. package/src/log/messages/mutations.js +0 -82
  196. package/src/log/messages/status.js +0 -16
  197. package/src/log/messages/steps.js +0 -22
  198. package/src/log/old_version.js +0 -41
  199. package/src/log/serialize.js +0 -13
  200. package/src/log/stream.js +0 -85
  201. package/src/log/theme.js +0 -26
  202. package/src/plugins/child/diff.js +0 -55
  203. package/src/plugins/child/error.js +0 -32
  204. package/src/plugins/child/lazy.js +0 -18
  205. package/src/plugins/child/load.js +0 -29
  206. package/src/plugins/child/logic.js +0 -57
  207. package/src/plugins/child/main.js +0 -51
  208. package/src/plugins/child/run.js +0 -28
  209. package/src/plugins/child/status.js +0 -74
  210. package/src/plugins/child/typescript.js +0 -45
  211. package/src/plugins/child/utils.js +0 -56
  212. package/src/plugins/child/validate.js +0 -34
  213. package/src/plugins/compatibility.js +0 -128
  214. package/src/plugins/expected_version.js +0 -119
  215. package/src/plugins/ipc.js +0 -145
  216. package/src/plugins/list.js +0 -86
  217. package/src/plugins/load.js +0 -70
  218. package/src/plugins/manifest/check.js +0 -106
  219. package/src/plugins/manifest/load.js +0 -41
  220. package/src/plugins/manifest/main.js +0 -22
  221. package/src/plugins/manifest/path.js +0 -31
  222. package/src/plugins/manifest/validate.js +0 -108
  223. package/src/plugins/node_version.js +0 -50
  224. package/src/plugins/options.js +0 -88
  225. package/src/plugins/pinned_version.js +0 -131
  226. package/src/plugins/resolve.js +0 -152
  227. package/src/plugins/spawn.js +0 -66
  228. package/src/plugins_core/add.js +0 -49
  229. package/src/plugins_core/build_command.js +0 -75
  230. package/src/plugins_core/deploy/buildbot_client.js +0 -102
  231. package/src/plugins_core/deploy/index.js +0 -73
  232. package/src/plugins_core/edge_functions/index.js +0 -123
  233. package/src/plugins_core/edge_functions/lib/internal_manifest.js +0 -54
  234. package/src/plugins_core/edge_functions/validate_manifest/validate_edge_functions_manifest.js +0 -89
  235. package/src/plugins_core/functions/error.js +0 -163
  236. package/src/plugins_core/functions/feature_flags.js +0 -6
  237. package/src/plugins_core/functions/index.js +0 -160
  238. package/src/plugins_core/functions/utils.js +0 -66
  239. package/src/plugins_core/functions/zisi.js +0 -53
  240. package/src/plugins_core/list.js +0 -27
  241. package/src/status/add.js +0 -36
  242. package/src/status/colors.js +0 -23
  243. package/src/status/load_error.js +0 -11
  244. package/src/status/report.js +0 -137
  245. package/src/status/success.js +0 -18
  246. package/src/steps/core_step.js +0 -92
  247. package/src/steps/error.js +0 -102
  248. package/src/steps/get.js +0 -51
  249. package/src/steps/plugin.js +0 -85
  250. package/src/steps/return.js +0 -52
  251. package/src/steps/run_core_steps.js +0 -200
  252. package/src/steps/run_step.js +0 -304
  253. package/src/steps/run_steps.js +0 -179
  254. package/src/steps/update_config.js +0 -93
  255. package/src/telemetry/main.js +0 -136
  256. package/src/time/aggregate.js +0 -146
  257. package/src/time/main.js +0 -48
  258. package/src/time/measure.js +0 -22
  259. package/src/time/report.js +0 -59
  260. package/src/utils/errors.js +0 -12
  261. package/src/utils/json.js +0 -19
  262. package/src/utils/omit.js +0 -6
  263. package/src/utils/package.js +0 -23
  264. package/src/utils/remove_falsy.js +0 -10
  265. package/src/utils/resolve.js +0 -46
  266. package/src/utils/semver.js +0 -34
@@ -0,0 +1,41 @@
1
+ import figures from 'figures';
2
+ import { logMessage, logSubHeader } from '../logger.js';
3
+ import { THEME } from '../theme.js';
4
+ export const logDryRunStart = function ({ logs, eventWidth, stepsCount }) {
5
+ const columnWidth = getDryColumnWidth(eventWidth, stepsCount);
6
+ const line = '─'.repeat(columnWidth);
7
+ const secondLine = '─'.repeat(columnWidth);
8
+ logSubHeader(logs, 'Netlify Build Commands');
9
+ logMessage(logs, `For more information on build events see the docs https://github.com/netlify/build
10
+
11
+ Running \`netlify build\` will execute this build flow
12
+
13
+ ${THEME.header(`┌─${line}─┬─${secondLine}─┐
14
+ │ ${DRY_HEADER_NAMES[0].padEnd(columnWidth)} │ ${DRY_HEADER_NAMES[1].padEnd(columnWidth)} │
15
+ └─${line}─┴─${secondLine}─┘`)}`);
16
+ };
17
+ export const logDryRunStep = function ({ logs, step: { event, packageName, coreStepDescription }, index, netlifyConfig, eventWidth, stepsCount, }) {
18
+ const columnWidth = getDryColumnWidth(eventWidth, stepsCount);
19
+ const fullName = getFullName(coreStepDescription, netlifyConfig, packageName);
20
+ const line = '─'.repeat(columnWidth);
21
+ const countText = `${index + 1}. `;
22
+ const downArrow = stepsCount === index + 1 ? ' ' : ` ${figures.arrowDown}`;
23
+ const eventWidthA = columnWidth - countText.length - downArrow.length;
24
+ logMessage(logs, `${THEME.header(`┌─${line}─┐`)}
25
+ ${THEME.header(`│ ${countText}${event.padEnd(eventWidthA)}${downArrow} │`)} ${fullName}
26
+ ${THEME.header(`└─${line}─┘ `)}`);
27
+ };
28
+ const getFullName = function (coreStepDescription, netlifyConfig, packageName) {
29
+ return coreStepDescription === undefined
30
+ ? `Plugin ${THEME.highlightWords(packageName)}`
31
+ : coreStepDescription({ netlifyConfig });
32
+ };
33
+ const getDryColumnWidth = function (eventWidth, stepsCount) {
34
+ const symbolsWidth = `${stepsCount}`.length + COLUMN_EXTRA_WIDTH;
35
+ return Math.max(eventWidth + symbolsWidth, DRY_HEADER_NAMES[1].length);
36
+ };
37
+ const COLUMN_EXTRA_WIDTH = 4;
38
+ const DRY_HEADER_NAMES = ['Event', 'Location'];
39
+ export const logDryRunEnd = function (logs) {
40
+ logMessage(logs, `\nIf this looks good to you, run \`netlify build\` to execute the build\n`);
41
+ };
@@ -0,0 +1,25 @@
1
+ import { isRuntime } from '../../utils/runtime.js';
2
+ import { log, logArray, logSubHeader } from '../logger.js';
3
+ export const logInstallMissingPlugins = function (logs, packages) {
4
+ const runtimes = packages.filter((pkg) => isRuntime(pkg));
5
+ const plugins = packages.filter((pkg) => !isRuntime(pkg));
6
+ if (plugins.length !== 0) {
7
+ logSubHeader(logs, 'Installing plugins');
8
+ logArray(logs, packages);
9
+ }
10
+ if (runtimes.length !== 0) {
11
+ const [nextRuntime] = runtimes;
12
+ logSubHeader(logs, `Using Next.js Runtime - v${nextRuntime.pluginPackageJson.version}`);
13
+ }
14
+ };
15
+ export const logInstallLocalPluginsDeps = function (logs, localPluginsOptions) {
16
+ const packages = localPluginsOptions.map(getPackageName);
17
+ logSubHeader(logs, 'Installing local plugins dependencies');
18
+ logArray(logs, packages);
19
+ };
20
+ export const logInstallFunctionDependencies = function () {
21
+ log(undefined, 'Installing functions dependencies');
22
+ };
23
+ const getPackageName = function ({ packageName }) {
24
+ return packageName;
25
+ };
@@ -0,0 +1,29 @@
1
+ import { log } from '../logger.js';
2
+ const logVerbose = function (logs, verbose, message) {
3
+ if (!verbose) {
4
+ return;
5
+ }
6
+ log(logs, message);
7
+ };
8
+ export const logSendingEventToChild = function (logs, verbose) {
9
+ logVerbose(logs, verbose, 'Step starting.');
10
+ };
11
+ export const logSentEventToChild = function (logs, verbose) {
12
+ logVerbose(logs, verbose, 'Step started.');
13
+ };
14
+ export const logPluginMethodStart = function (verbose) {
15
+ logVerbose(undefined, verbose, 'Plugin logic started.');
16
+ };
17
+ export const logPluginMethodEnd = function (verbose) {
18
+ logVerbose(undefined, verbose, 'Plugin logic ended.');
19
+ };
20
+ export const logSendingEventToParent = function (verbose, error) {
21
+ const message = error instanceof Error ? `Step erroring.\n${error.stack}` : 'Stop closing.';
22
+ logVerbose(undefined, verbose, message);
23
+ };
24
+ export const logReceivedEventFromChild = function (logs, verbose) {
25
+ logVerbose(logs, verbose, 'Step ended.');
26
+ };
27
+ export const logStepCompleted = function (logs, verbose) {
28
+ logVerbose(logs, verbose, 'Step completed.');
29
+ };
@@ -0,0 +1,62 @@
1
+ import { promises as fs } from 'fs';
2
+ import { inspect } from 'util';
3
+ import { pathExists } from 'path-exists';
4
+ import { log, logMessage, logSubHeader } from '../logger.js';
5
+ export const logConfigMutations = function (logs, newConfigMutations, debug) {
6
+ const configMutationsToLog = debug ? newConfigMutations : newConfigMutations.filter(shouldLogConfigMutation);
7
+ configMutationsToLog.forEach(({ keysString, value }) => {
8
+ logConfigMutation(logs, keysString, value);
9
+ });
10
+ };
11
+ // Some configuration mutations are only logged in debug mode
12
+ const shouldLogConfigMutation = function ({ keysString }) {
13
+ return !HIDDEN_PROPS.some((hiddenProp) => keysString.startsWith(hiddenProp));
14
+ };
15
+ // `functions` is an object which can have thousands of properties, one per
16
+ // function file. This can be very verbose, especially for plugins which create
17
+ // many function files like Essential Next.js
18
+ const HIDDEN_PROPS = ['functions'];
19
+ const logConfigMutation = function (logs, keysString, value) {
20
+ const newValue = shouldHideConfigValue(keysString) ? '' : ` to ${inspect(value, { colors: false })}`;
21
+ log(logs, `Netlify configuration property "${keysString}" value changed${newValue}.`);
22
+ };
23
+ const shouldHideConfigValue = function (keysString) {
24
+ return SECRET_PROPS.some((secretProp) => keysString.startsWith(secretProp));
25
+ };
26
+ const SECRET_PROPS = ['build.environment'];
27
+ export const logConfigOnUpload = async function ({ logs, configPath, debug }) {
28
+ if (!debug) {
29
+ return;
30
+ }
31
+ logSubHeader(logs, 'Uploaded config');
32
+ if (!(await pathExists(configPath))) {
33
+ logMessage(logs, 'No netlify.toml');
34
+ return;
35
+ }
36
+ const configContents = await fs.readFile(configPath, 'utf8');
37
+ logMessage(logs, configContents.trim());
38
+ };
39
+ export const logHeadersOnUpload = async function ({ logs, headersPath, debug }) {
40
+ if (!debug) {
41
+ return;
42
+ }
43
+ logSubHeader(logs, 'Uploaded headers');
44
+ if (!(await pathExists(headersPath))) {
45
+ logMessage(logs, 'No headers');
46
+ return;
47
+ }
48
+ const headersContents = await fs.readFile(headersPath, 'utf8');
49
+ logMessage(logs, headersContents.trim());
50
+ };
51
+ export const logRedirectsOnUpload = async function ({ logs, redirectsPath, debug }) {
52
+ if (!debug) {
53
+ return;
54
+ }
55
+ logSubHeader(logs, 'Uploaded redirects');
56
+ if (!(await pathExists(redirectsPath))) {
57
+ logMessage(logs, 'No redirects\n');
58
+ return;
59
+ }
60
+ const redirectsContents = await fs.readFile(redirectsPath, 'utf8');
61
+ logMessage(logs, `${redirectsContents.trim()}\n`);
62
+ };
@@ -1,39 +1,25 @@
1
- import { log, logArray, logWarning, logSubHeader } from '../logger.js'
2
-
1
+ import { log, logArray, logWarning, logSubHeader } from '../logger.js';
3
2
  export const logPluginsFetchError = function (logs, message) {
4
- logWarning(
5
- logs,
6
- `
3
+ logWarning(logs, `
7
4
  Warning: could not fetch latest plugins list. Plugins versions might not be the latest.
8
- ${message}`,
9
- )
10
- }
11
-
5
+ ${message}`);
6
+ };
12
7
  export const logPluginsList = function ({ pluginsList, debug, logs }) {
13
- if (!debug) {
14
- return
15
- }
16
-
17
- // eslint-disable-next-line fp/no-mutating-methods
18
- const pluginsListArray = Object.entries(pluginsList).map(getPluginsListItem).sort()
19
-
20
- logSubHeader(logs, 'Available plugins')
21
- logArray(logs, pluginsListArray)
22
- }
23
-
8
+ if (!debug) {
9
+ return;
10
+ }
11
+ const pluginsListArray = Object.entries(pluginsList).map(getPluginsListItem).sort();
12
+ logSubHeader(logs, 'Available plugins');
13
+ logArray(logs, pluginsListArray);
14
+ };
24
15
  const getPluginsListItem = function ([packageName, versions]) {
25
- return `${packageName}@${versions[0].version}`
26
- }
27
-
16
+ return `${packageName}@${versions[0].version}`;
17
+ };
28
18
  export const logFailPluginWarning = function (methodName, event) {
29
- logWarning(
30
- undefined,
31
- `Plugin error: since "${event}" happens after deploy, the build has already succeeded and cannot fail anymore. This plugin should either:
19
+ logWarning(undefined, `Plugin error: since "${event}" happens after deploy, the build has already succeeded and cannot fail anymore. This plugin should either:
32
20
  - use utils.build.failPlugin() instead of utils.build.${methodName}() to clarify that the plugin failed, but not the build.
33
- - use "onPostBuild" instead of "${event}" if the plugin failure should make the build fail too. Please note that "onPostBuild" (unlike "${event}") happens before deploy.`,
34
- )
35
- }
36
-
21
+ - use "onPostBuild" instead of "${event}" if the plugin failure should make the build fail too. Please note that "onPostBuild" (unlike "${event}") happens before deploy.`);
22
+ };
37
23
  export const logDeploySuccess = function (logs) {
38
- log(logs, 'Site deploy was successfully initiated')
39
- }
24
+ log(logs, 'Site deploy was successfully initiated');
25
+ };
@@ -0,0 +1,14 @@
1
+ import { logMessage, logHeader, logSubHeader } from '../logger.js';
2
+ import { THEME } from '../theme.js';
3
+ export const logStatuses = function (logs, statuses) {
4
+ logHeader(logs, 'Summary');
5
+ statuses.forEach((status) => {
6
+ logStatus(logs, status);
7
+ });
8
+ };
9
+ const logStatus = function (logs, { packageName, title = `Plugin ${packageName} ran successfully`, summary, text }) {
10
+ const titleA = title.includes(packageName) ? title : `${packageName}: ${title}`;
11
+ const body = text === undefined ? summary : `${summary}\n${THEME.dimWords(text)}`;
12
+ logSubHeader(logs, titleA);
13
+ logMessage(logs, body);
14
+ };
@@ -0,0 +1,18 @@
1
+ import { getLogHeaderFunc } from '../header_func.js';
2
+ import { log, logMessage } from '../logger.js';
3
+ import { THEME } from '../theme.js';
4
+ export const logStepStart = function ({ logs, event, packageName, coreStepDescription, index, error, netlifyConfig }) {
5
+ const description = getDescription({ coreStepDescription, netlifyConfig, packageName, event });
6
+ const logHeaderFunc = getLogHeaderFunc(error);
7
+ logHeaderFunc(logs, `${index + 1}. ${description}`);
8
+ logMessage(logs, '');
9
+ };
10
+ const getDescription = function ({ coreStepDescription, netlifyConfig, packageName, event }) {
11
+ return coreStepDescription === undefined ? `${packageName} (${event} event)` : coreStepDescription({ netlifyConfig });
12
+ };
13
+ export const logBuildCommandStart = function (logs, buildCommand) {
14
+ log(logs, THEME.highlightWords(`$ ${buildCommand}`));
15
+ };
16
+ export const logStepSuccess = function (logs) {
17
+ logMessage(logs, '');
18
+ };
@@ -0,0 +1,32 @@
1
+ import { stdout } from 'process';
2
+ import UpdateNotifier from 'update-notifier';
3
+ import { ROOT_PACKAGE_JSON } from '../utils/json.js';
4
+ // Many build errors happen in local builds that do not use the latest version
5
+ // of `@netlify/build`. We print a warning message on those.
6
+ // We only print this when Netlify CLI has been used. Programmatic usage might
7
+ // come from a deep dependency calling `@netlify/build` and user might not be
8
+ // able to take any upgrade action, making the message noisy.
9
+ export const logOldCliVersionError = function ({ mode, testOpts }) {
10
+ if (mode !== 'cli') {
11
+ return;
12
+ }
13
+ const corePackageJson = getCorePackageJson(testOpts);
14
+ UpdateNotifier({ pkg: corePackageJson, updateCheckInterval: 1 }).notify({
15
+ message: OLD_VERSION_MESSAGE,
16
+ shouldNotifyInNpmScript: true,
17
+ });
18
+ };
19
+ const getCorePackageJson = function (testOpts) {
20
+ // TODO: Find a way to test this without injecting code in the `src/`
21
+ if (testOpts.oldCliLogs) {
22
+ // `update-notifier` does not do anything if not in a TTY.
23
+ // In tests, we need to monkey patch this
24
+ // Mutation is required due to how `stdout.isTTY` works
25
+ stdout.isTTY = true;
26
+ return { ...ROOT_PACKAGE_JSON, version: '0.0.1' };
27
+ }
28
+ return ROOT_PACKAGE_JSON;
29
+ };
30
+ const OLD_VERSION_MESSAGE = `Please update netlify-cli to its latest version.
31
+ If netlify-cli is already the latest version,
32
+ please update your dependencies lock file instead.`;
@@ -0,0 +1,10 @@
1
+ import { dump } from 'js-yaml';
2
+ export const serializeObject = function (object) {
3
+ return dump(object, { noRefs: true, sortKeys: true, lineWidth: Number.POSITIVE_INFINITY }).trimEnd();
4
+ };
5
+ export const serializeArray = function (array) {
6
+ return array.map(addDash).join('\n');
7
+ };
8
+ const addDash = function (string) {
9
+ return ` - ${string}`;
10
+ };
@@ -0,0 +1,68 @@
1
+ import { stdout, stderr } from 'process';
2
+ import { promisify } from 'util';
3
+ // TODO: replace with `timers/promises` after dropping Node < 15.0.0
4
+ const pSetTimeout = promisify(setTimeout);
5
+ // We try to use `stdio: inherit` because it keeps `stdout/stderr` as `TTY`,
6
+ // which solves many problems. However we can only do it in build.command.
7
+ // Plugins have several events, so need to be switch on and off instead.
8
+ // In buffer mode (`logs` not `undefined`), `pipe` is necessary.
9
+ export const getBuildCommandStdio = function (logs) {
10
+ if (logs !== undefined) {
11
+ return 'pipe';
12
+ }
13
+ return 'inherit';
14
+ };
15
+ // Add build command output
16
+ export const handleBuildCommandOutput = function ({ stdout: commandStdout, stderr: commandStderr }, logs) {
17
+ if (logs === undefined) {
18
+ return;
19
+ }
20
+ pushBuildCommandOutput(commandStdout, logs.stdout);
21
+ pushBuildCommandOutput(commandStderr, logs.stderr);
22
+ };
23
+ const pushBuildCommandOutput = function (output, logsArray) {
24
+ if (output === '') {
25
+ return;
26
+ }
27
+ logsArray.push(output);
28
+ };
29
+ // Start plugin step output
30
+ export const pipePluginOutput = function (childProcess, logs) {
31
+ if (logs === undefined) {
32
+ return streamOutput(childProcess);
33
+ }
34
+ return pushOutputToLogs(childProcess, logs);
35
+ };
36
+ // Stop streaming/buffering plugin step output
37
+ export const unpipePluginOutput = async function (childProcess, logs, listeners) {
38
+ // Let `childProcess` `stdout` and `stderr` flush before stopping redirecting
39
+ await pSetTimeout(0);
40
+ if (logs === undefined) {
41
+ return unstreamOutput(childProcess);
42
+ }
43
+ unpushOutputToLogs(childProcess, logs, listeners);
44
+ };
45
+ // Usually, we stream stdout/stderr because it is more efficient
46
+ const streamOutput = function (childProcess) {
47
+ childProcess.stdout.pipe(stdout);
48
+ childProcess.stderr.pipe(stderr);
49
+ };
50
+ const unstreamOutput = function (childProcess) {
51
+ childProcess.stdout.unpipe(stdout);
52
+ childProcess.stderr.unpipe(stderr);
53
+ };
54
+ // In tests, we push to the `logs` array instead
55
+ const pushOutputToLogs = function (childProcess, logs) {
56
+ const stdoutListener = logsListener.bind(null, logs.stdout);
57
+ const stderrListener = logsListener.bind(null, logs.stderr);
58
+ childProcess.stdout.on('data', stdoutListener);
59
+ childProcess.stderr.on('data', stderrListener);
60
+ return { stdoutListener, stderrListener };
61
+ };
62
+ const logsListener = function (logs, chunk) {
63
+ logs.push(chunk.toString().trimEnd());
64
+ };
65
+ const unpushOutputToLogs = function (childProcess, logs, { stdoutListener, stderrListener }) {
66
+ childProcess.stdout.removeListener('data', stdoutListener);
67
+ childProcess.stderr.removeListener('data', stderrListener);
68
+ };
@@ -0,0 +1,27 @@
1
+ import chalk from 'chalk';
2
+ /**
3
+ * Color theme. Please use this instead of requiring chalk directly,
4
+ * to ensure consistent colors.
5
+ */
6
+ export const THEME = {
7
+ // Main headers
8
+ header: chalk.cyanBright.bold,
9
+ // Single lines used as sub-headers
10
+ subHeader: chalk.cyan.bold,
11
+ // One of several words that should be highlighted inside a line
12
+ highlightWords: chalk.cyan,
13
+ // Same for errors
14
+ errorHeader: chalk.redBright.bold,
15
+ errorSubHeader: chalk.red.bold,
16
+ errorLine: chalk.redBright,
17
+ errorHighlightWords: chalk.redBright.bold,
18
+ // Same for warnings
19
+ warningHeader: chalk.yellowBright.bold,
20
+ warningSubHeader: chalk.yellow.bold,
21
+ warningLine: chalk.yellowBright,
22
+ warningHighlightWords: chalk.yellowBright.bold,
23
+ // One of several words that should be dimmed inside a line
24
+ dimWords: chalk.gray,
25
+ // No colors
26
+ none: (string) => string,
27
+ };
@@ -0,0 +1,46 @@
1
+ import { isDeepStrictEqual } from 'util';
2
+ import isPlainObj from 'is-plain-obj';
3
+ import rfdc from 'rfdc';
4
+ const clone = rfdc();
5
+ // Copy `netlifyConfig` so we can compare before/after mutating it
6
+ export const cloneNetlifyConfig = function (netlifyConfig) {
7
+ return clone(netlifyConfig);
8
+ };
9
+ // Diff `netlifyConfig` before and after mutating it to retrieve an array of
10
+ // `configMutations` objects.
11
+ // We need to keep track of the changes on `netlifyConfig` so they can be
12
+ // processed later to:
13
+ // - Warn plugin authors when mutating read-only properties
14
+ // - Apply the change to `netlifyConfig` in the parent process so it can
15
+ // run `@netlify/config` to normalize and validate the new values
16
+ // `configMutations` is passed to parent process as JSON
17
+ export const getConfigMutations = function (netlifyConfig, netlifyConfigCopy, event) {
18
+ const configMutations = diffObjects(netlifyConfig, netlifyConfigCopy, []);
19
+ return configMutations.map((configMutation) => getConfigMutation(configMutation, event));
20
+ };
21
+ // We only recurse over plain objects, not arrays. Which means array properties
22
+ // can only be modified all at once.
23
+ const diffObjects = function (objA, objB, parentKeys) {
24
+ const allKeys = [...new Set([...Object.keys(objA), ...Object.keys(objB)])];
25
+ return allKeys.flatMap((key) => {
26
+ const valueA = objA[key];
27
+ const valueB = objB[key];
28
+ const keys = [...parentKeys, key];
29
+ if (isPlainObj(valueA) && isPlainObj(valueB)) {
30
+ return diffObjects(valueA, valueB, keys);
31
+ }
32
+ if (isDeepStrictEqual(valueA, valueB)) {
33
+ return [];
34
+ }
35
+ return [{ keys, value: valueB }];
36
+ });
37
+ };
38
+ const getConfigMutation = function ({ keys, value }, event) {
39
+ const serializedKeys = keys.map(String);
40
+ return {
41
+ keys: serializedKeys,
42
+ keysString: serializedKeys.join('.'),
43
+ value,
44
+ event,
45
+ };
46
+ };
@@ -0,0 +1,26 @@
1
+ import logProcessErrors from 'log-process-errors';
2
+ import { errorToJson } from '../../error/build.js';
3
+ import { addDefaultErrorInfo, isBuildError } from '../../error/info.js';
4
+ import { normalizeError } from '../../error/parse/normalize.js';
5
+ import { sendEventToParent } from '../ipc.js';
6
+ // Handle any top-level error and communicate it back to parent
7
+ export const handleError = async function (error, verbose) {
8
+ const errorA = normalizeError(error);
9
+ addDefaultErrorInfo(errorA, { type: 'pluginInternal' });
10
+ const errorPayload = errorToJson(errorA);
11
+ await sendEventToParent('error', errorPayload, verbose, errorA);
12
+ };
13
+ // On uncaught exceptions and unhandled rejections, print the stack trace.
14
+ // Also, prevent child processes from crashing on uncaught exceptions.
15
+ export const handleProcessErrors = function () {
16
+ logProcessErrors({ log: handleProcessError, exitOn: [] });
17
+ };
18
+ const handleProcessError = async function (error, level, originalError) {
19
+ if (level !== 'error') {
20
+ console[level](error);
21
+ return;
22
+ }
23
+ // Do not use log-process-errors prettification with errors thrown by `utils.build.*`
24
+ const errorA = isBuildError(originalError) ? originalError : error;
25
+ await handleError(errorA);
26
+ };
@@ -0,0 +1,15 @@
1
+ import memoizeOne from 'memoize-one';
2
+ // Add a `object[propName]` whose value is the return value of `getFunc()`, but
3
+ // is only retrieved when accessed.
4
+ export const addLazyProp = function (object, propName, getFunc) {
5
+ const mGetFunc = memoizeOne(getFunc, returnTrue);
6
+ // Mutation is required due to the usage of `Object.defineProperty()`
7
+ Object.defineProperty(object, propName, {
8
+ get: mGetFunc,
9
+ enumerable: true,
10
+ configurable: true,
11
+ });
12
+ };
13
+ const returnTrue = function () {
14
+ return true;
15
+ };
@@ -0,0 +1,22 @@
1
+ import filterObj from 'filter-obj';
2
+ import { getLogic } from './logic.js';
3
+ import { registerTypeScript } from './typescript.js';
4
+ import { validatePlugin } from './validate.js';
5
+ // Load context passed to every plugin method.
6
+ // This also requires the plugin file and fire its top-level function.
7
+ // This also validates the plugin.
8
+ // Do it when parent requests it using the `load` event.
9
+ // Also figure out the list of plugin steps. This is also passed to the parent.
10
+ export const load = async function ({ pluginPath, inputs, packageJson, verbose }) {
11
+ const tsNodeService = registerTypeScript(pluginPath);
12
+ const logic = await getLogic({ pluginPath, inputs, tsNodeService });
13
+ validatePlugin(logic);
14
+ const methods = filterObj(logic, isEventHandler);
15
+ const events = Object.keys(methods);
16
+ // Context passed to every event handler
17
+ const context = { methods, inputs, packageJson, verbose };
18
+ return { events, context };
19
+ };
20
+ const isEventHandler = function (event, value) {
21
+ return typeof value === 'function';
22
+ };
@@ -0,0 +1,57 @@
1
+ import { createRequire } from 'module';
2
+ import { pathToFileURL } from 'url';
3
+ import { ROOT_PACKAGE_JSON } from '../../utils/json.js';
4
+ import { DEV_EVENTS, EVENTS } from '../events.js';
5
+ import { addTsErrorInfo } from './typescript.js';
6
+ const require = createRequire(import.meta.url);
7
+ // Require the plugin file and fire its top-level function.
8
+ // The returned object is the `logic` which includes all event handlers.
9
+ export const getLogic = async function ({ pluginPath, inputs, tsNodeService }) {
10
+ const logic = await importLogic(pluginPath, tsNodeService);
11
+ const logicA = loadLogic({ logic, inputs });
12
+ return logicA;
13
+ };
14
+ const importLogic = async function (pluginPath, tsNodeService) {
15
+ try {
16
+ // `ts-node` is not available programmatically for pure ES modules yet,
17
+ // which is currently making it impossible for local plugins to use both
18
+ // pure ES modules and TypeScript.
19
+ if (tsNodeService !== undefined) {
20
+ return require(pluginPath);
21
+ }
22
+ // `pluginPath` is an absolute file path but `import()` needs URLs.
23
+ // Converting those with `pathToFileURL()` is needed especially on Windows
24
+ // where the drive letter would not work with `import()`.
25
+ const returnValue = await import(pathToFileURL(pluginPath));
26
+ // Plugins should use named exports, but we still support default exports
27
+ // for backward compatibility with CommonJS
28
+ return returnValue.default === undefined ? returnValue : returnValue.default;
29
+ }
30
+ catch (error) {
31
+ addTsErrorInfo(error, tsNodeService);
32
+ // We must change `error.stack` instead of `error.message` because some
33
+ // errors thrown from `import()` access `error.stack` before throwing.
34
+ // `error.stack` is lazily instantiated by Node.js, so changing
35
+ // `error.message` afterwards would not modify `error.stack`. Therefore, the
36
+ // resulting stack trace, which is printed in the build logs, would not
37
+ // include the additional message prefix.
38
+ error.stack = `Could not import plugin:\n${error.stack}`;
39
+ throw error;
40
+ }
41
+ };
42
+ const loadLogic = function ({ logic, inputs }) {
43
+ if (typeof logic !== 'function') {
44
+ return logic;
45
+ }
46
+ const metadata = {
47
+ events: new Set([...DEV_EVENTS, ...EVENTS]),
48
+ version: ROOT_PACKAGE_JSON.version,
49
+ };
50
+ try {
51
+ return logic(inputs, metadata);
52
+ }
53
+ catch (error) {
54
+ error.message = `Could not load plugin:\n${error.message}`;
55
+ throw error;
56
+ }
57
+ };
@@ -0,0 +1,37 @@
1
+ import { setInspectColors } from '../../log/colors.js';
2
+ import { sendEventToParent, getEventsFromParent } from '../ipc.js';
3
+ import { handleProcessErrors, handleError } from './error.js';
4
+ import { load } from './load.js';
5
+ import { run } from './run.js';
6
+ // Boot plugin child process.
7
+ const bootPlugin = async function () {
8
+ const state = { context: { verbose: false } };
9
+ try {
10
+ handleProcessErrors();
11
+ setInspectColors();
12
+ // We need to fire them in parallel because `process.send()` can be slow
13
+ // to await, i.e. parent might send `load` event before child `ready` event
14
+ // returns.
15
+ await Promise.all([handleEvents(state), sendEventToParent('ready', {}, false)]);
16
+ }
17
+ catch (error) {
18
+ await handleError(error, state.context.verbose);
19
+ }
20
+ };
21
+ // Wait for events from parent to perform plugin methods
22
+ const handleEvents = async function (state) {
23
+ await getEventsFromParent((callId, eventName, payload) => handleEvent({ callId, eventName, payload, state }));
24
+ };
25
+ // Each event can pass `context` information to the next event
26
+ const handleEvent = async function ({ callId, eventName, payload, state, state: { context: { verbose }, }, }) {
27
+ try {
28
+ const { context, ...response } = await EVENTS[eventName](payload, state.context);
29
+ state.context = { ...state.context, ...context };
30
+ await sendEventToParent(callId, response, verbose);
31
+ }
32
+ catch (error) {
33
+ await handleError(error, verbose);
34
+ }
35
+ };
36
+ const EVENTS = { load, run };
37
+ bootPlugin();
@@ -0,0 +1,19 @@
1
+ import { getNewEnvChanges, setEnvChanges } from '../../env/changes.js';
2
+ import { logPluginMethodStart, logPluginMethodEnd } from '../../log/messages/ipc.js';
3
+ import { cloneNetlifyConfig, getConfigMutations } from './diff.js';
4
+ import { getUtils } from './utils.js';
5
+ // Run a specific plugin event handler
6
+ export const run = async function ({ event, error, constants, envChanges, netlifyConfig }, { methods, inputs, packageJson, verbose }) {
7
+ const method = methods[event];
8
+ const runState = {};
9
+ const utils = getUtils({ event, constants, runState });
10
+ const netlifyConfigCopy = cloneNetlifyConfig(netlifyConfig);
11
+ const runOptions = { utils, constants, inputs, netlifyConfig: netlifyConfigCopy, packageJson, error };
12
+ const envBefore = setEnvChanges(envChanges);
13
+ logPluginMethodStart(verbose);
14
+ await method(runOptions);
15
+ logPluginMethodEnd(verbose);
16
+ const newEnvChanges = getNewEnvChanges(envBefore, netlifyConfig, netlifyConfigCopy);
17
+ const configMutations = getConfigMutations(netlifyConfig, netlifyConfigCopy, event);
18
+ return { ...runState, newEnvChanges, configMutations };
19
+ };