netlify-cli 8.0.13 → 8.1.0-rc.2

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 (184) hide show
  1. package/README.md +12 -13
  2. package/bin/run +38 -2
  3. package/npm-shrinkwrap.json +260 -6244
  4. package/package.json +13 -35
  5. package/src/commands/addons/addons-auth.js +50 -0
  6. package/src/commands/addons/addons-config.js +180 -0
  7. package/src/commands/addons/addons-create.js +131 -0
  8. package/src/commands/addons/addons-delete.js +60 -0
  9. package/src/commands/addons/addons-list.js +62 -0
  10. package/src/commands/addons/addons.js +44 -0
  11. package/src/commands/addons/index.js +3 -24
  12. package/src/commands/api/api.js +75 -0
  13. package/src/commands/api/index.js +5 -0
  14. package/src/commands/base-command.js +509 -0
  15. package/src/commands/build/build.js +58 -0
  16. package/src/commands/build/index.js +3 -61
  17. package/src/commands/completion/completion.js +36 -0
  18. package/src/commands/completion/index.js +5 -0
  19. package/src/commands/{deploy.js → deploy/deploy.js} +295 -275
  20. package/src/commands/deploy/index.js +5 -0
  21. package/src/commands/dev/dev-exec.js +35 -0
  22. package/src/commands/dev/dev-trace.js +47 -0
  23. package/src/commands/dev/dev.js +340 -0
  24. package/src/commands/dev/index.js +3 -335
  25. package/src/commands/env/env-get.js +51 -0
  26. package/src/commands/env/env-import.js +93 -0
  27. package/src/commands/env/env-list.js +63 -0
  28. package/src/commands/env/env-set.js +67 -0
  29. package/src/commands/env/env-unset.js +66 -0
  30. package/src/commands/env/env.js +42 -0
  31. package/src/commands/env/index.js +3 -23
  32. package/src/commands/functions/functions-build.js +59 -0
  33. package/src/commands/functions/{create.js → functions-create.js} +130 -94
  34. package/src/commands/functions/functions-invoke.js +273 -0
  35. package/src/commands/functions/functions-list.js +106 -0
  36. package/src/commands/functions/functions-serve.js +63 -0
  37. package/src/commands/functions/functions.js +47 -0
  38. package/src/commands/functions/index.js +3 -45
  39. package/src/commands/index.js +7 -0
  40. package/src/commands/init/index.js +6 -0
  41. package/src/commands/{init.js → init/init.js} +79 -68
  42. package/src/commands/link/index.js +6 -0
  43. package/src/{utils/link/link-by-prompt.js → commands/link/link.js} +141 -14
  44. package/src/commands/lm/index.js +3 -19
  45. package/src/commands/lm/lm-info.js +42 -0
  46. package/src/commands/lm/lm-install.js +33 -0
  47. package/src/commands/lm/lm-setup.js +106 -0
  48. package/src/commands/lm/lm-uninstall.js +25 -0
  49. package/src/commands/lm/lm.js +34 -0
  50. package/src/commands/login/index.js +6 -0
  51. package/src/commands/login/login.js +55 -0
  52. package/src/commands/logout/index.js +5 -0
  53. package/src/commands/logout/logout.js +43 -0
  54. package/src/commands/main.js +188 -0
  55. package/src/commands/open/index.js +3 -39
  56. package/src/commands/open/open-admin.js +60 -0
  57. package/src/commands/open/open-site.js +53 -0
  58. package/src/commands/open/open.js +38 -0
  59. package/src/commands/sites/index.js +5 -20
  60. package/src/commands/sites/sites-create.js +187 -0
  61. package/src/commands/sites/sites-delete.js +104 -0
  62. package/src/commands/sites/sites-list.js +89 -0
  63. package/src/commands/sites/sites.js +32 -0
  64. package/src/commands/status/index.js +3 -118
  65. package/src/commands/status/status-hooks.js +69 -0
  66. package/src/commands/status/status.js +124 -0
  67. package/src/commands/switch/index.js +5 -0
  68. package/src/commands/switch/switch.js +50 -0
  69. package/src/commands/unlink/index.js +5 -0
  70. package/src/commands/unlink/unlink.js +48 -0
  71. package/src/commands/watch/index.js +5 -0
  72. package/src/commands/watch/watch.js +121 -0
  73. package/src/lib/build.js +21 -7
  74. package/src/lib/exec-fetcher.js +5 -3
  75. package/src/lib/fs.js +54 -36
  76. package/src/lib/functions/background.js +1 -1
  77. package/src/lib/functions/form-submissions-handler.js +2 -1
  78. package/src/lib/functions/local-proxy.js +2 -1
  79. package/src/lib/functions/netlify-function.js +4 -1
  80. package/src/lib/functions/registry.js +4 -6
  81. package/src/lib/functions/runtimes/go/index.js +2 -1
  82. package/src/lib/functions/runtimes/js/builders/netlify-lambda.js +6 -4
  83. package/src/lib/functions/runtimes/js/builders/zisi.js +3 -3
  84. package/src/lib/functions/runtimes/rust/index.js +4 -3
  85. package/src/lib/functions/server.js +2 -3
  86. package/src/lib/functions/synchronous.js +2 -1
  87. package/src/lib/functions/utils.js +2 -3
  88. package/src/lib/functions/watcher.js +1 -0
  89. package/src/lib/http-agent.js +5 -5
  90. package/src/lib/log.js +2 -1
  91. package/src/lib/spinner.js +22 -0
  92. package/src/utils/addons/diffs/index.js +1 -0
  93. package/src/utils/addons/diffs/options.js +3 -1
  94. package/src/utils/addons/prepare.js +13 -6
  95. package/src/utils/addons/prompts.js +2 -1
  96. package/src/utils/addons/render.js +3 -1
  97. package/src/utils/command-helpers.js +116 -43
  98. package/src/utils/create-stream-promise.js +5 -5
  99. package/src/utils/deferred.js +1 -0
  100. package/src/utils/deploy/deploy-site.js +1 -1
  101. package/src/utils/deploy/index.js +4 -0
  102. package/src/utils/detect-server-settings.js +10 -12
  103. package/src/utils/dev.js +18 -10
  104. package/src/utils/dot-env.js +4 -2
  105. package/src/utils/{edge-handlers.js → functions/edge-handlers.js} +8 -7
  106. package/src/utils/functions/functions.js +36 -0
  107. package/src/utils/{get-functions.js → functions/get-functions.js} +2 -1
  108. package/src/utils/functions/index.js +8 -26
  109. package/src/utils/get-global-config.js +3 -2
  110. package/src/utils/get-repo-data.js +1 -0
  111. package/src/utils/gh-auth.js +1 -0
  112. package/src/utils/gitignore.js +7 -5
  113. package/src/utils/headers.js +1 -2
  114. package/src/utils/index.js +42 -0
  115. package/src/utils/init/config-github.js +12 -5
  116. package/src/utils/init/config-manual.js +9 -2
  117. package/src/utils/init/config.js +13 -7
  118. package/src/utils/init/frameworks.js +1 -0
  119. package/src/utils/init/node-version.js +4 -2
  120. package/src/utils/init/plugins.js +2 -4
  121. package/src/utils/init/utils.js +10 -6
  122. package/src/utils/live-tunnel.js +3 -4
  123. package/src/utils/lm/install.js +10 -15
  124. package/src/utils/lm/requirements.js +3 -1
  125. package/src/utils/lm/steps.js +1 -1
  126. package/src/utils/lm/ui.js +7 -3
  127. package/src/utils/open-browser.js +8 -2
  128. package/src/utils/parse-raw-flags.js +4 -4
  129. package/src/utils/proxy.js +6 -5
  130. package/src/utils/read-repo-url.js +1 -0
  131. package/src/utils/redirects.js +3 -5
  132. package/src/utils/rules-proxy.js +2 -1
  133. package/src/utils/state-config.js +1 -1
  134. package/src/utils/telemetry/index.js +2 -113
  135. package/src/utils/telemetry/request.js +3 -1
  136. package/src/utils/telemetry/telemetry.js +117 -0
  137. package/src/utils/telemetry/validation.js +13 -12
  138. package/src/utils/traffic-mesh.js +3 -3
  139. package/oclif.manifest.json +0 -1
  140. package/src/commands/addons/auth.js +0 -42
  141. package/src/commands/addons/config.js +0 -177
  142. package/src/commands/addons/create.js +0 -127
  143. package/src/commands/addons/delete.js +0 -69
  144. package/src/commands/addons/list.js +0 -54
  145. package/src/commands/api.js +0 -84
  146. package/src/commands/dev/exec.js +0 -32
  147. package/src/commands/dev/trace.js +0 -61
  148. package/src/commands/env/get.js +0 -44
  149. package/src/commands/env/import.js +0 -90
  150. package/src/commands/env/list.js +0 -49
  151. package/src/commands/env/set.js +0 -64
  152. package/src/commands/env/unset.js +0 -58
  153. package/src/commands/functions/build.js +0 -60
  154. package/src/commands/functions/invoke.js +0 -277
  155. package/src/commands/functions/list.js +0 -102
  156. package/src/commands/functions/serve.js +0 -70
  157. package/src/commands/link.js +0 -133
  158. package/src/commands/lm/info.js +0 -36
  159. package/src/commands/lm/install.js +0 -30
  160. package/src/commands/lm/setup.js +0 -107
  161. package/src/commands/lm/uninstall.js +0 -17
  162. package/src/commands/login.js +0 -54
  163. package/src/commands/logout.js +0 -37
  164. package/src/commands/open/admin.js +0 -51
  165. package/src/commands/open/site.js +0 -43
  166. package/src/commands/sites/create.js +0 -191
  167. package/src/commands/sites/delete.js +0 -116
  168. package/src/commands/sites/list.js +0 -84
  169. package/src/commands/status/hooks.js +0 -60
  170. package/src/commands/switch.js +0 -44
  171. package/src/commands/unlink.js +0 -38
  172. package/src/commands/watch.js +0 -115
  173. package/src/hooks/init.js +0 -46
  174. package/src/index.js +0 -25
  175. package/src/lib/help.js +0 -26
  176. package/src/utils/chalk.js +0 -16
  177. package/src/utils/check-command-inputs.js +0 -21
  178. package/src/utils/command.js +0 -261
  179. package/src/utils/detect-functions-builder.js +0 -25
  180. package/src/utils/difference.js +0 -4
  181. package/src/utils/header.js +0 -18
  182. package/src/utils/logo.js +0 -11
  183. package/src/utils/show-help.js +0 -5
  184. package/src/utils/telemetry/tracked-command.js +0 -51
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "netlify-cli",
3
3
  "description": "Netlify command line tool",
4
- "version": "8.0.13",
4
+ "version": "8.1.0-rc.2",
5
5
  "author": "Netlify Inc.",
6
6
  "contributors": [
7
7
  "Mathias Biilmann <matt@netlify.com> (https://twitter.com/biilmann)",
@@ -57,7 +57,6 @@
57
57
  "format:fix:prettier": "cross-env-shell prettier --write $npm_package_config_prettier",
58
58
  "test:dev": "run-s test:init:* test:dev:*",
59
59
  "test:ci": "run-s test:init:* test:ci:*",
60
- "test:init:build": "run-s build:*",
61
60
  "test:init:cli-version": "npm run start -- --version",
62
61
  "test:init:cli-help": "npm run start -- --help",
63
62
  "test:init:eleventy-deps": "npm ci --prefix tests/eleventy-site --no-audit",
@@ -66,9 +65,8 @@
66
65
  "test:ci:ava": "nyc -r json ava",
67
66
  "docs": "node ./site/scripts/docs.js",
68
67
  "watch": "nyc --reporter=lcov ava --watch",
69
- "build:manifest": "oclif-dev manifest",
70
- "prepack": "npm run build:manifest && npm prune --prod",
71
- "postpack": "rm -f oclif.manifest.json && npm i",
68
+ "prepack": "npm prune --prod",
69
+ "postpack": "npm i",
72
70
  "site:build": "run-s site:build:*",
73
71
  "site:build:install": "cd site && npm ci --no-audit",
74
72
  "site:build:assets": "cd site && npm run build",
@@ -79,21 +77,14 @@
79
77
  "prettier": "--ignore-path .gitignore --loglevel=warn \"{src,scripts,site,tests,.github}/**/*.{js,md,yml,json,html}\" \"*.{js,yml,json,html}\" \".*.{js,yml,json,html}\" \"!CHANGELOG.md\" \"!npm-shrinkwrap.json\" \"!.github/**/*.md\""
80
78
  },
81
79
  "dependencies": {
82
- "@netlify/build": "^20.0.3",
80
+ "@netlify/build": "^20.0.2",
83
81
  "@netlify/config": "^16.0.5",
84
82
  "@netlify/framework-info": "^6.0.0",
85
83
  "@netlify/local-functions-proxy": "^1.1.1",
86
84
  "@netlify/plugin-edge-handlers": "^2.0.0",
87
- "@netlify/plugins-list": "^6.0.1",
85
+ "@netlify/plugins-list": "^5.0.0",
88
86
  "@netlify/routing-local-proxy": "^0.34.1",
89
87
  "@netlify/zip-it-and-ship-it": "5.2.0",
90
- "@oclif/command": "^1.6.1",
91
- "@oclif/config": "^1.15.1",
92
- "@oclif/errors": "^1.3.4",
93
- "@oclif/parser": "^3.8.4",
94
- "@oclif/plugin-help": "^3.0.0",
95
- "@oclif/plugin-not-found": "^1.1.4",
96
- "@oclif/plugin-plugins": "^1.9.3",
97
88
  "@octokit/rest": "^18.0.0",
98
89
  "@sindresorhus/slugify": "^1.1.0",
99
90
  "ansi-styles": "^5.0.0",
@@ -106,6 +97,7 @@
106
97
  "ci-info": "^3.0.0",
107
98
  "clean-deep": "^3.0.2",
108
99
  "cli-ux": "^5.5.1",
100
+ "commander": "^8.3.0",
109
101
  "concordance": "^5.0.0",
110
102
  "configstore": "^5.0.0",
111
103
  "content-type": "^1.0.4",
@@ -140,6 +132,7 @@
140
132
  "inquirer-autocomplete-prompt": "^1.0.1",
141
133
  "is-docker": "^2.0.0",
142
134
  "is-plain-obj": "^3.0.0",
135
+ "is-wsl": "^2.2.0",
143
136
  "isexe": "^2.0.0",
144
137
  "jwt-decode": "^3.0.0",
145
138
  "lambda-local": "^2.0.0",
@@ -154,11 +147,10 @@
154
147
  "multiparty": "^4.2.1",
155
148
  "netlify": "^10.0.0",
156
149
  "netlify-headers-parser": "^5.0.0",
157
- "netlify-redirect-parser": "^13.0.0",
150
+ "netlify-redirect-parser": "^12.0.0",
158
151
  "netlify-redirector": "^0.2.1",
159
152
  "node-fetch": "^2.6.0",
160
153
  "node-version-alias": "^1.0.1",
161
- "oclif-plugin-completion": "^0.6.0",
162
154
  "omit.js": "^2.0.2",
163
155
  "open": "^7.0.0",
164
156
  "ora": "^5.0.0",
@@ -177,9 +169,10 @@
177
169
  "raw-body": "^2.4.1",
178
170
  "read-pkg-up": "^7.0.1",
179
171
  "resolve": "^1.12.0",
180
- "semver": "^7.3.4",
172
+ "semver": "^7.3.5",
181
173
  "source-map-support": "^0.5.19",
182
174
  "static-server": "^2.2.1",
175
+ "string-similarity": "^4.0.4",
183
176
  "strip-ansi-control-characters": "^2.0.0",
184
177
  "tempy": "^1.0.0",
185
178
  "through2-filter": "^3.0.0",
@@ -198,9 +191,8 @@
198
191
  "@commitlint/cli": "^15.0.0",
199
192
  "@commitlint/config-conventional": "^15.0.0",
200
193
  "@netlify/eslint-config-node": "^3.3.11",
201
- "@oclif/dev-cli": "^1.23.1",
202
- "@oclif/test": "^1.2.5",
203
194
  "ava": "^3.15.0",
195
+ "eslint-plugin-local-rules": "file:tools/eslint-rules",
204
196
  "eslint-plugin-sort-destructure-keys": "^1.3.5",
205
197
  "form-data": "^4.0.0",
206
198
  "from2-string": "^1.1.0",
@@ -223,7 +215,9 @@
223
215
  },
224
216
  "ava": {
225
217
  "files": [
218
+ "site/**/*.test.js",
226
219
  "src/**/*.test.js",
220
+ "tools/**/*.test.js",
227
221
  "tests/*.test.js"
228
222
  ],
229
223
  "cache": true,
@@ -233,22 +227,6 @@
233
227
  "tap": false,
234
228
  "timeout": "5m"
235
229
  },
236
- "oclif": {
237
- "bin": "netlify",
238
- "commands": "./src/commands",
239
- "helpClass": "./src/lib/help",
240
- "plugins": [
241
- "@oclif/plugin-not-found",
242
- "@oclif/plugin-plugins",
243
- "@oclif/plugin-help",
244
- "oclif-plugin-completion"
245
- ],
246
- "hooks": {
247
- "init": [
248
- "./src/hooks/init"
249
- ]
250
- }
251
- },
252
230
  "husky": {
253
231
  "hooks": {
254
232
  "commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
@@ -0,0 +1,50 @@
1
+ // @ts-check
2
+
3
+ const { exit, log, openBrowser } = require('../../utils')
4
+ const { ADDON_VALIDATION, prepareAddonCommand } = require('../../utils/addons/prepare')
5
+
6
+ /**
7
+ * The addons:auth command
8
+ * @param {string} addonName
9
+ * @param {import('commander').OptionValues} options
10
+ * @param {import('../base-command').BaseCommand} command
11
+ * @returns {Promise<boolean>}
12
+ */
13
+ const addonsAuth = async (addonName, options, command) => {
14
+ const { addon } = await prepareAddonCommand({
15
+ command,
16
+ addonName,
17
+ // @ts-ignore when migrating to typescript this should be a const enum
18
+ validation: ADDON_VALIDATION.EXISTS,
19
+ })
20
+
21
+ if (!addon.auth_url) {
22
+ log(`No Admin URL found for the "${addonName} add-on"`)
23
+ return false
24
+ }
25
+
26
+ log()
27
+ log(`Opening ${addonName} add-on admin URL:`)
28
+ log()
29
+ log(addon.auth_url)
30
+ log()
31
+ await openBrowser({ url: addon.auth_url })
32
+ exit()
33
+ }
34
+
35
+ /**
36
+ * Creates the `netlify addons:auth` command
37
+ * @param {import('../base-command').BaseCommand} program
38
+ * @returns
39
+ */
40
+ const createAddonsAuthCommand = (program) =>
41
+ program
42
+ .command('addons:auth')
43
+ .alias('addon:auth')
44
+ .argument('<name>', 'Add-on slug')
45
+ .description('Login to add-on provider')
46
+ .action(async (addonName, options, command) => {
47
+ await addonsAuth(addonName, options, command)
48
+ })
49
+
50
+ module.exports = { createAddonsAuthCommand }
@@ -0,0 +1,180 @@
1
+ // @ts-check
2
+ const inquirer = require('inquirer')
3
+ const isEmpty = require('lodash/isEmpty')
4
+
5
+ const { chalk, error, log, parseRawFlags } = require('../../utils')
6
+ const compare = require('../../utils/addons/compare')
7
+ const diffValues = require('../../utils/addons/diffs')
8
+ const { ADDON_VALIDATION, prepareAddonCommand } = require('../../utils/addons/prepare')
9
+ const generatePrompts = require('../../utils/addons/prompts')
10
+ const render = require('../../utils/addons/render')
11
+ const { missingConfigValues, requiredConfigValues, updateConfigValues } = require('../../utils/addons/validation')
12
+
13
+ const update = async function ({ addonName, api, currentConfig, instanceId, newConfig, siteId }) {
14
+ const codeDiff = diffValues(currentConfig, newConfig)
15
+ if (!codeDiff) {
16
+ log('No changes, exiting early')
17
+ return false
18
+ }
19
+ log()
20
+ const msg = `Updating ${addonName} add-on config values...`
21
+ log(`${chalk.white.bold(msg)}`)
22
+ log()
23
+ log(`${codeDiff}\n`)
24
+ log()
25
+
26
+ try {
27
+ await api.updateServiceInstance({
28
+ siteId,
29
+ addon: addonName,
30
+ instanceId,
31
+ body: { config: newConfig },
32
+ })
33
+ log(`Add-on "${addonName}" successfully updated`)
34
+ } catch (error_) {
35
+ error(error_.message)
36
+ }
37
+ }
38
+
39
+ /**
40
+ * The addons:config command
41
+ * @param {string} addonName
42
+ * @param {import('commander').OptionValues} options
43
+ * @param {import('../base-command').BaseCommand} command
44
+ * @returns {Promise<boolean>}
45
+ */
46
+ const addonsConfig = async (addonName, options, command) => {
47
+ const { addon, manifest, siteData } = await prepareAddonCommand({
48
+ command,
49
+ addonName,
50
+ // @ts-ignore
51
+ validation: ADDON_VALIDATION.EXISTS,
52
+ })
53
+
54
+ const { api, site } = command.netlify
55
+ const siteId = site.id
56
+
57
+ const hasConfig = !isEmpty(manifest.config)
58
+ // Parse flags
59
+ const rawFlags = parseRawFlags(command.args)
60
+ // Get Existing Config
61
+ const currentConfig = addon.config || {}
62
+
63
+ const words = `Current "${addonName} add-on" Settings:`
64
+ log(` ${chalk.yellowBright.bold(words)}`)
65
+ if (hasConfig) {
66
+ if (!rawFlags.silent) {
67
+ render.configValues(addonName, manifest.config, currentConfig)
68
+ }
69
+ } else {
70
+ // For addons without manifest. TODO remove once we enforce manifests
71
+ Object.keys(currentConfig).forEach((key) => {
72
+ log(`${key} - ${currentConfig[key]}`)
73
+ })
74
+ }
75
+
76
+ if (hasConfig) {
77
+ const required = requiredConfigValues(manifest.config)
78
+ const missingValues = missingConfigValues(required, rawFlags)
79
+
80
+ /* Config set by command line flags */
81
+ if (rawFlags && missingValues.length === 0) {
82
+ const newConfig = updateConfigValues(manifest.config, currentConfig, rawFlags)
83
+
84
+ await update({
85
+ addonName,
86
+ currentConfig,
87
+ newConfig,
88
+ siteId,
89
+ instanceId: addon.id,
90
+ api,
91
+ })
92
+ return false
93
+ }
94
+
95
+ const updatePrompt = await inquirer.prompt([
96
+ {
97
+ type: 'confirm',
98
+ name: 'updateNow',
99
+ message: `Do you want to update config values?`,
100
+ default: false,
101
+ },
102
+ ])
103
+ if (!updatePrompt.updateNow) {
104
+ log('Sounds good! Exiting configuration...')
105
+ return false
106
+ }
107
+ log()
108
+ log(` - Hit ${chalk.white.bold('enter')} to keep the existing value in (parentheses)`)
109
+ log(` - Hit ${chalk.white.bold('down arrow')} to remove the value`)
110
+ log(` - Hit ${chalk.white.bold('ctrl + C')} to cancel & exit configuration`)
111
+ log()
112
+ log(` You will need to verify the changed before we push them to your live site!`)
113
+ log()
114
+ const prompts = generatePrompts({
115
+ config: manifest.config,
116
+ configValues: currentConfig,
117
+ })
118
+ const userInput = await inquirer.prompt(prompts)
119
+ // Merge user input with the flags specified
120
+ const newConfig = updateConfigValues(manifest.config, currentConfig, userInput)
121
+
122
+ const diffs = compare(currentConfig, newConfig)
123
+ // log('compare', diffs)
124
+ if (diffs.isEqual) {
125
+ log(`No changes. exiting early`)
126
+ return false
127
+ }
128
+ log()
129
+ log(`${chalk.yellowBright.bold.underline('Confirm your updates:')}`)
130
+ log()
131
+ diffs.keys.forEach((key) => {
132
+ const { newValue, oldValue } = diffs.diffs[key]
133
+ const oldVal = oldValue || 'NO VALUE'
134
+ log(`${chalk.cyan(key)} changed from ${chalk.whiteBright(oldVal)} to ${chalk.green(newValue)}`)
135
+ })
136
+ log()
137
+
138
+ const confirmPrompt = await inquirer.prompt([
139
+ {
140
+ type: 'confirm',
141
+ name: 'confirmChange',
142
+ message: `Do you want to publish the updated "${addonName} add-on" settings for ${chalk.cyan(siteData.name)}?`,
143
+ default: false,
144
+ },
145
+ ])
146
+
147
+ if (!confirmPrompt.confirmChange) {
148
+ log('Canceling changes... You are good to go!')
149
+ return false
150
+ }
151
+
152
+ await update({
153
+ addonName,
154
+ currentConfig,
155
+ newConfig,
156
+ siteId,
157
+ instanceId: addon.id,
158
+ api,
159
+ })
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Creates the `netlify addons:config` command
165
+ * @param {import('../base-command').BaseCommand} program
166
+ * @returns
167
+ */
168
+ const createAddonsConfigCommand = (program) =>
169
+ program
170
+ .command('addons:config')
171
+ .alias('addon:config')
172
+ .argument('<name>', 'Add-on namespace')
173
+ .description('Configure add-on settings')
174
+ // allow for any flags. Handy for variadic configuration options
175
+ .allowUnknownOption(true)
176
+ .action(async (addonName, options, command) => {
177
+ await addonsConfig(addonName, options, command)
178
+ })
179
+
180
+ module.exports = { createAddonsConfigCommand }
@@ -0,0 +1,131 @@
1
+ // @ts-check
2
+ const inquirer = require('inquirer')
3
+ const isEmpty = require('lodash/isEmpty')
4
+
5
+ const { chalk, error, log, parseRawFlags } = require('../../utils')
6
+ const { ADDON_VALIDATION, prepareAddonCommand } = require('../../utils/addons/prepare')
7
+ const generatePrompts = require('../../utils/addons/prompts')
8
+ const render = require('../../utils/addons/render')
9
+ const { missingConfigValues, requiredConfigValues, updateConfigValues } = require('../../utils/addons/validation')
10
+
11
+ const createAddon = async ({ addonName, api, config, siteData, siteId }) => {
12
+ try {
13
+ const response = await api.createServiceInstance({
14
+ siteId,
15
+ addon: addonName,
16
+ body: { config },
17
+ })
18
+ log(`Add-on "${addonName}" created for ${siteData.name}`)
19
+ if (response.config && response.config.message) {
20
+ log()
21
+ log(`${response.config.message}`)
22
+ }
23
+ } catch (error_) {
24
+ error(error_.message)
25
+ }
26
+ }
27
+
28
+ /**
29
+ * The addons:create command
30
+ * @param {string} addonName
31
+ * @param {import('commander').OptionValues} options
32
+ * @param {import('../base-command').BaseCommand} command
33
+ * @returns {Promise<boolean>}
34
+ */
35
+ const addonsCreate = async (addonName, options, command) => {
36
+ const { manifest, siteData } = await prepareAddonCommand({
37
+ command,
38
+ addonName,
39
+ // @ts-ignore
40
+ validation: ADDON_VALIDATION.NOT_EXISTS,
41
+ })
42
+
43
+ const { api, site } = command.netlify
44
+ const siteId = site.id
45
+
46
+ // GET flags from `raw` data
47
+ const rawFlags = parseRawFlags(command.args)
48
+ const hasConfig = !isEmpty(manifest.config)
49
+
50
+ let configValues = rawFlags
51
+
52
+ if (hasConfig) {
53
+ const required = requiredConfigValues(manifest.config)
54
+ const missingValues = missingConfigValues(required, rawFlags)
55
+ log(`Starting the setup for "${addonName} add-on"`)
56
+ log()
57
+
58
+ if (Object.keys(rawFlags).length !== 0) {
59
+ const newConfig = updateConfigValues(manifest.config, {}, rawFlags)
60
+
61
+ if (missingValues.length !== 0) {
62
+ /* Warn user of missing required values */
63
+ log(`${chalk.redBright.underline.bold(`Error: Missing required configuration for "${addonName} add-on"`)}`)
64
+ log()
65
+ render.missingValues(missingValues, manifest)
66
+ log()
67
+ const msg = `netlify addons:create ${addonName}`
68
+ log(`Please supply the configuration values as CLI flags`)
69
+ log()
70
+ log(`Alternatively, you can run ${chalk.cyan(msg)} with no flags to walk through the setup steps`)
71
+ log()
72
+ return false
73
+ }
74
+
75
+ await createAddon({ api, siteId, addonName, config: newConfig, siteData })
76
+
77
+ return false
78
+ }
79
+
80
+ const words = `The ${addonName} add-on has the following configurable options:`
81
+ log(` ${chalk.yellowBright.bold(words)}`)
82
+ render.configValues(addonName, manifest.config)
83
+ log()
84
+ log(` ${chalk.greenBright.bold('Lets configure those!')}`)
85
+
86
+ log()
87
+ log(` - Hit ${chalk.white.bold('enter')} to confirm value or set empty value`)
88
+ log(` - Hit ${chalk.white.bold('ctrl + C')} to cancel & exit configuration`)
89
+ log()
90
+
91
+ const prompts = generatePrompts({
92
+ config: manifest.config,
93
+ configValues: rawFlags,
94
+ })
95
+
96
+ const userInput = await inquirer.prompt(prompts)
97
+ // Merge user input with the flags specified
98
+ configValues = updateConfigValues(manifest.config, rawFlags, userInput)
99
+ const missingRequiredValues = missingConfigValues(required, configValues)
100
+ if (missingRequiredValues && missingRequiredValues.length !== 0) {
101
+ missingRequiredValues.forEach((val) => {
102
+ log(`Missing required value "${val}". Please run the command again`)
103
+ })
104
+ return false
105
+ }
106
+ }
107
+
108
+ await createAddon({ api, siteId, addonName, config: configValues, siteData })
109
+ }
110
+
111
+ /**
112
+ * Creates the `netlify addons:create` command
113
+ * @param {import('../base-command').BaseCommand} program
114
+ * @returns
115
+ */
116
+ const createAddonsCreateCommand = (program) =>
117
+ program
118
+ .command('addons:create')
119
+ .alias('addon:create')
120
+ .argument('<name>', 'Add-on namespace')
121
+ .description(
122
+ `Add an add-on extension to your site
123
+ Add-ons are a way to extend the functionality of your Netlify site`,
124
+ )
125
+ // allow for any flags. Handy for variadic configuration options
126
+ .allowUnknownOption(true)
127
+ .action(async (addonName, options, command) => {
128
+ await addonsCreate(addonName, options, command)
129
+ })
130
+
131
+ module.exports = { createAddonsCreateCommand }
@@ -0,0 +1,60 @@
1
+ // @ts-check
2
+ const inquirer = require('inquirer')
3
+
4
+ const { error, exit, log } = require('../../utils')
5
+ const { ADDON_VALIDATION, prepareAddonCommand } = require('../../utils/addons/prepare')
6
+
7
+ /**
8
+ * The addons:delete command
9
+ * @param {string} addonName
10
+ * @param {import('commander').OptionValues} options
11
+ * @param {import('../base-command').BaseCommand} command
12
+ */
13
+ const addonsDelete = async (addonName, options, command) => {
14
+ const { addon } = await prepareAddonCommand({
15
+ command,
16
+ addonName,
17
+ // @ts-ignore.
18
+ validation: ADDON_VALIDATION.EXISTS,
19
+ })
20
+ if (!options.force && !options.f) {
21
+ const { wantsToDelete } = await inquirer.prompt({
22
+ type: 'confirm',
23
+ name: 'wantsToDelete',
24
+ message: `Are you sure you want to delete the ${addonName} add-on? (to skip this prompt, pass a --force flag)`,
25
+ default: false,
26
+ })
27
+ if (!wantsToDelete) {
28
+ exit()
29
+ }
30
+ }
31
+
32
+ try {
33
+ await command.netlify.api.deleteServiceInstance({
34
+ siteId: command.netlify.site.id,
35
+ addon: addonName,
36
+ instanceId: addon.id,
37
+ })
38
+ log(`Addon "${addonName}" deleted`)
39
+ } catch (error_) {
40
+ error(error_.message)
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Creates the `netlify addons:delete` command
46
+ * @param {import('../base-command').BaseCommand} program
47
+ * @returns
48
+ */
49
+ const createAddonsDeleteCommand = (program) =>
50
+ program
51
+ .command('addons:delete')
52
+ .alias('addon:delete')
53
+ .argument('<name>', 'Add-on namespace')
54
+ .description(
55
+ `Remove an add-on extension to your site\nAdd-ons are a way to extend the functionality of your Netlify site`,
56
+ )
57
+ .option('-f, --force', 'delete without prompting (useful for CI)')
58
+ .action(addonsDelete)
59
+
60
+ module.exports = { createAddonsDeleteCommand }
@@ -0,0 +1,62 @@
1
+ // @ts-check
2
+
3
+ const AsciiTable = require('ascii-table')
4
+
5
+ const { log, logJson } = require('../../utils')
6
+ const { prepareAddonCommand } = require('../../utils/addons/prepare')
7
+
8
+ /**
9
+ * The addons:list command
10
+ * @param {import('commander').OptionValues} options
11
+ * @param {import('../base-command').BaseCommand} command
12
+ * @returns {Promise<boolean>}
13
+ */
14
+ const addonsList = async (options, command) => {
15
+ const { addons, siteData } = await prepareAddonCommand({ command })
16
+ // Return json response for piping commands
17
+ if (options.json) {
18
+ logJson(addons)
19
+ return false
20
+ }
21
+
22
+ if (!addons || addons.length === 0) {
23
+ log(`No addons currently installed for ${siteData.name}`)
24
+ log(`> Run \`netlify addons:create addon-namespace\` to install an addon`)
25
+ return false
26
+ }
27
+
28
+ const addonData = addons.map((addon) => ({
29
+ namespace: addon.service_path.replace('/.netlify/', ''),
30
+ name: addon.service_name,
31
+ id: addon.id,
32
+ }))
33
+
34
+ // Build a table out of addons
35
+ log(`site: ${siteData.name}`)
36
+ const table = new AsciiTable(`Currently Installed addons`)
37
+
38
+ table.setHeading('NameSpace', 'Name', 'Instance Id')
39
+
40
+ addonData.forEach(({ id, name, namespace }) => {
41
+ table.addRow(namespace, name, id)
42
+ })
43
+ // Log da addons
44
+ log(table.toString())
45
+ }
46
+
47
+ /**
48
+ * Creates the `netlify addons:list` command
49
+ * @param {import('../base-command').BaseCommand} program
50
+ * @returns
51
+ */
52
+ const createAddonsListCommand = (program) =>
53
+ program
54
+ .command('addons:list')
55
+ .alias('addon:list')
56
+ .description(`List currently installed add-ons for site`)
57
+ .option('--json', 'Output add-on data as JSON')
58
+ .action(async (options, command) => {
59
+ await addonsList(options, command)
60
+ })
61
+
62
+ module.exports = { createAddonsListCommand }
@@ -0,0 +1,44 @@
1
+ // @ts-check
2
+
3
+ const { createAddonsAuthCommand } = require('./addons-auth')
4
+ const { createAddonsConfigCommand } = require('./addons-config')
5
+ const { createAddonsCreateCommand } = require('./addons-create')
6
+ const { createAddonsDeleteCommand } = require('./addons-delete')
7
+ const { createAddonsListCommand } = require('./addons-list')
8
+
9
+ /**
10
+ * The addons command
11
+ * @param {import('commander').OptionValues} options
12
+ * @param {import('../base-command').BaseCommand} command
13
+ */
14
+ const addons = (options, command) => {
15
+ command.help()
16
+ }
17
+
18
+ /**
19
+ * Creates the `netlify addons` command
20
+ * @param {import('../base-command').BaseCommand} program
21
+ * @returns
22
+ */
23
+ const createAddonsCommand = (program) => {
24
+ createAddonsAuthCommand(program)
25
+ createAddonsConfigCommand(program)
26
+ createAddonsCreateCommand(program)
27
+ createAddonsDeleteCommand(program)
28
+ createAddonsListCommand(program)
29
+
30
+ return program
31
+ .command('addons')
32
+ .alias('addon')
33
+ .description('(Beta) Manage Netlify Add-ons')
34
+ .noHelpOptions()
35
+ .addExamples([
36
+ 'netlify addons:create addon-xyz',
37
+ 'netlify addons:list',
38
+ 'netlify addons:config addon-xyz',
39
+ 'netlify addons:delete addon-xyz',
40
+ 'netlify addons:auth addon-xyz',
41
+ ])
42
+ .action(addons)
43
+ }
44
+ module.exports = { createAddonsCommand }
@@ -1,26 +1,5 @@
1
- const { isEmptyCommand } = require('../../utils/check-command-inputs')
2
- const showHelp = require('../../utils/show-help')
3
- const { TrackedCommand } = require('../../utils/telemetry/tracked-command')
1
+ const { createAddonsCommand } = require('./addons')
4
2
 
5
- class AddonsCommand extends TrackedCommand {
6
- run() {
7
- const { args, flags } = this.parse(AddonsCommand)
8
-
9
- // Show help on empty sub command
10
- if (isEmptyCommand(flags, args)) {
11
- showHelp(this.id)
12
- }
13
- }
3
+ module.exports = {
4
+ createAddonsCommand,
14
5
  }
15
-
16
- AddonsCommand.description = `(Beta) Manage Netlify Add-ons`
17
- AddonsCommand.aliases = ['addon']
18
- AddonsCommand.examples = [
19
- 'netlify addons:create addon-xyz',
20
- 'netlify addons:list',
21
- 'netlify addons:config addon-xyz',
22
- 'netlify addons:delete addon-xyz',
23
- 'netlify addons:auth addon-xyz',
24
- ]
25
-
26
- module.exports = AddonsCommand