netlify-cli 8.0.7 → 8.1.0-rc
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/run +81 -3
- package/npm-shrinkwrap.json +305 -2105
- package/package.json +10 -33
- package/src/commands/addons/addons-auth.js +50 -0
- package/src/commands/addons/addons-config.js +180 -0
- package/src/commands/addons/addons-create.js +129 -0
- package/src/commands/addons/addons-delete.js +59 -0
- package/src/commands/addons/addons-list.js +62 -0
- package/src/commands/addons/addons.js +49 -0
- package/src/commands/addons/index.js +3 -24
- package/src/commands/api/api.js +83 -0
- package/src/commands/api/index.js +5 -0
- package/src/commands/base-command.js +322 -0
- package/src/commands/build/build.js +58 -0
- package/src/commands/build/index.js +3 -61
- package/src/commands/completion/completion.js +18 -0
- package/src/commands/completion/index.js +5 -0
- package/src/commands/{deploy.js → deploy/deploy.js} +306 -278
- package/src/commands/deploy/index.js +5 -0
- package/src/commands/dev/dev-exec.js +39 -0
- package/src/commands/dev/dev-trace.js +50 -0
- package/src/commands/dev/dev.js +349 -0
- package/src/commands/dev/index.js +3 -335
- package/src/commands/env/env-get.js +51 -0
- package/src/commands/env/env-import.js +93 -0
- package/src/commands/env/env-list.js +63 -0
- package/src/commands/env/env-set.js +67 -0
- package/src/commands/env/env-unset.js +66 -0
- package/src/commands/env/env.js +47 -0
- package/src/commands/env/index.js +3 -23
- package/src/commands/functions/functions-build.js +59 -0
- package/src/commands/functions/{create.js → functions-create.js} +133 -94
- package/src/commands/functions/functions-invoke.js +276 -0
- package/src/commands/functions/functions-list.js +107 -0
- package/src/commands/functions/functions-serve.js +63 -0
- package/src/commands/functions/functions.js +53 -0
- package/src/commands/functions/index.js +3 -45
- package/src/commands/index.js +5 -0
- package/src/commands/init/index.js +6 -0
- package/src/commands/{init.js → init/init.js} +79 -68
- package/src/commands/link/index.js +6 -0
- package/src/{utils/link/link-by-prompt.js → commands/link/link.js} +153 -14
- package/src/commands/lm/index.js +3 -19
- package/src/commands/lm/lm-info.js +42 -0
- package/src/commands/lm/lm-install.js +36 -0
- package/src/commands/lm/lm-setup.js +106 -0
- package/src/commands/lm/lm-uninstall.js +25 -0
- package/src/commands/lm/lm.js +39 -0
- package/src/commands/login/index.js +6 -0
- package/src/commands/login/login.js +52 -0
- package/src/commands/logout/index.js +5 -0
- package/src/commands/logout/logout.js +43 -0
- package/src/commands/main.js +117 -0
- package/src/commands/open/index.js +3 -39
- package/src/commands/open/open-admin.js +56 -0
- package/src/commands/open/open-site.js +49 -0
- package/src/commands/open/open.js +42 -0
- package/src/commands/sites/index.js +5 -20
- package/src/commands/sites/sites-create.js +184 -0
- package/src/commands/sites/sites-delete.js +108 -0
- package/src/commands/sites/sites-list.js +89 -0
- package/src/commands/sites/sites.js +36 -0
- package/src/commands/status/index.js +3 -118
- package/src/commands/status/status-hooks.js +73 -0
- package/src/commands/status/status.js +125 -0
- package/src/commands/switch/index.js +5 -0
- package/src/commands/switch/switch.js +50 -0
- package/src/commands/unlink/index.js +5 -0
- package/src/commands/unlink/unlink.js +48 -0
- package/src/commands/watch/index.js +5 -0
- package/src/commands/watch/watch.js +121 -0
- package/src/lib/build.js +21 -7
- package/src/lib/exec-fetcher.js +5 -3
- package/src/lib/fs.js +54 -36
- package/src/lib/functions/background.js +1 -1
- package/src/lib/functions/form-submissions-handler.js +2 -1
- package/src/lib/functions/local-proxy.js +2 -1
- package/src/lib/functions/netlify-function.js +4 -1
- package/src/lib/functions/registry.js +4 -6
- package/src/lib/functions/runtimes/go/index.js +2 -1
- package/src/lib/functions/runtimes/js/builders/netlify-lambda.js +6 -4
- package/src/lib/functions/runtimes/js/builders/zisi.js +3 -3
- package/src/lib/functions/runtimes/rust/index.js +4 -3
- package/src/lib/functions/server.js +2 -3
- package/src/lib/functions/synchronous.js +2 -1
- package/src/lib/functions/utils.js +2 -3
- package/src/lib/functions/watcher.js +1 -0
- package/src/lib/http-agent.js +3 -5
- package/src/lib/log.js +2 -1
- package/src/lib/spinner.js +22 -0
- package/src/utils/addons/diffs/index.js +1 -0
- package/src/utils/addons/diffs/options.js +3 -1
- package/src/utils/addons/prepare.js +13 -6
- package/src/utils/addons/prompts.js +2 -1
- package/src/utils/addons/render.js +3 -1
- package/src/utils/command-helpers.js +156 -43
- package/src/utils/create-stream-promise.js +5 -5
- package/src/utils/deferred.js +1 -0
- package/src/utils/deploy/deploy-site.js +1 -1
- package/src/utils/deploy/index.js +4 -0
- package/src/utils/detect-server-settings.js +10 -12
- package/src/utils/dev.js +18 -10
- package/src/utils/dot-env.js +4 -2
- package/src/utils/{edge-handlers.js → functions/edge-handlers.js} +8 -7
- package/src/utils/functions/functions.js +36 -0
- package/src/utils/{get-functions.js → functions/get-functions.js} +2 -1
- package/src/utils/functions/index.js +8 -26
- package/src/utils/get-global-config.js +3 -2
- package/src/utils/get-repo-data.js +1 -0
- package/src/utils/gh-auth.js +1 -0
- package/src/utils/gitignore.js +7 -5
- package/src/utils/header.js +2 -2
- package/src/utils/headers.js +1 -2
- package/src/utils/index.js +42 -0
- package/src/utils/init/config-github.js +12 -5
- package/src/utils/init/config-manual.js +9 -2
- package/src/utils/init/config.js +13 -7
- package/src/utils/init/frameworks.js +1 -0
- package/src/utils/init/node-version.js +4 -2
- package/src/utils/init/plugins.js +1 -0
- package/src/utils/init/utils.js +10 -6
- package/src/utils/live-tunnel.js +3 -4
- package/src/utils/lm/install.js +10 -15
- package/src/utils/lm/requirements.js +3 -1
- package/src/utils/lm/steps.js +1 -1
- package/src/utils/lm/ui.js +7 -3
- package/src/utils/open-browser.js +8 -2
- package/src/utils/parse-raw-flags.js +4 -4
- package/src/utils/proxy.js +6 -5
- package/src/utils/read-repo-url.js +1 -0
- package/src/utils/redirects.js +2 -2
- package/src/utils/rules-proxy.js +2 -1
- package/src/utils/state-config.js +1 -1
- package/src/utils/telemetry/index.js +2 -113
- package/src/utils/telemetry/request.js +3 -1
- package/src/utils/telemetry/telemetry.js +117 -0
- package/src/utils/telemetry/validation.js +13 -12
- package/src/utils/traffic-mesh.js +3 -3
- package/oclif.manifest.json +0 -1
- package/src/commands/addons/auth.js +0 -42
- package/src/commands/addons/config.js +0 -177
- package/src/commands/addons/create.js +0 -127
- package/src/commands/addons/delete.js +0 -69
- package/src/commands/addons/list.js +0 -54
- package/src/commands/api.js +0 -84
- package/src/commands/dev/exec.js +0 -32
- package/src/commands/dev/trace.js +0 -61
- package/src/commands/env/get.js +0 -44
- package/src/commands/env/import.js +0 -90
- package/src/commands/env/list.js +0 -49
- package/src/commands/env/set.js +0 -64
- package/src/commands/env/unset.js +0 -58
- package/src/commands/functions/build.js +0 -60
- package/src/commands/functions/invoke.js +0 -277
- package/src/commands/functions/list.js +0 -102
- package/src/commands/functions/serve.js +0 -70
- package/src/commands/link.js +0 -133
- package/src/commands/lm/info.js +0 -36
- package/src/commands/lm/install.js +0 -30
- package/src/commands/lm/setup.js +0 -107
- package/src/commands/lm/uninstall.js +0 -17
- package/src/commands/login.js +0 -54
- package/src/commands/logout.js +0 -37
- package/src/commands/open/admin.js +0 -51
- package/src/commands/open/site.js +0 -43
- package/src/commands/sites/create.js +0 -191
- package/src/commands/sites/delete.js +0 -116
- package/src/commands/sites/list.js +0 -84
- package/src/commands/status/hooks.js +0 -60
- package/src/commands/switch.js +0 -44
- package/src/commands/unlink.js +0 -38
- package/src/commands/watch.js +0 -115
- package/src/hooks/init.js +0 -46
- package/src/index.js +0 -25
- package/src/lib/help.js +0 -26
- package/src/utils/chalk.js +0 -16
- package/src/utils/check-command-inputs.js +0 -21
- package/src/utils/command.js +0 -262
- package/src/utils/detect-functions-builder.js +0 -25
- package/src/utils/difference.js +0 -4
- package/src/utils/logo.js +0 -11
- package/src/utils/show-help.js +0 -5
- package/src/utils/telemetry/tracked-command.js +0 -51
|
@@ -1,30 +1,40 @@
|
|
|
1
|
-
|
|
2
|
-
const
|
|
1
|
+
// @ts-check
|
|
2
|
+
const { stat } = require('fs').promises
|
|
3
|
+
const { basename, resolve } = require('path')
|
|
4
|
+
const { cwd, env } = require('process')
|
|
3
5
|
|
|
4
6
|
const { restoreConfig, updateConfig } = require('@netlify/config')
|
|
5
|
-
const { flags: flagsLib } = require('@oclif/command')
|
|
6
|
-
const chalk = require('chalk')
|
|
7
7
|
const { get } = require('dot-prop')
|
|
8
8
|
const inquirer = require('inquirer')
|
|
9
9
|
const isObject = require('lodash/isObject')
|
|
10
10
|
const prettyjson = require('prettyjson')
|
|
11
11
|
|
|
12
|
-
const { cancelDeploy } = require('
|
|
13
|
-
const { getBuildOptions, runBuild } = require('
|
|
14
|
-
const {
|
|
15
|
-
const {
|
|
16
|
-
const {
|
|
17
|
-
const {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
12
|
+
const { cancelDeploy } = require('../../lib/api')
|
|
13
|
+
const { getBuildOptions, runBuild } = require('../../lib/build')
|
|
14
|
+
const { normalizeFunctionsConfig } = require('../../lib/functions/config')
|
|
15
|
+
const { getLogMessage } = require('../../lib/log')
|
|
16
|
+
const { startSpinner, stopSpinner } = require('../../lib/spinner')
|
|
17
|
+
const {
|
|
18
|
+
NETLIFYDEV,
|
|
19
|
+
NETLIFYDEVERR,
|
|
20
|
+
NETLIFYDEVLOG,
|
|
21
|
+
chalk,
|
|
22
|
+
deployEdgeHandlers,
|
|
23
|
+
deploySite,
|
|
24
|
+
error,
|
|
25
|
+
exit,
|
|
26
|
+
generateDescriptionHelp,
|
|
27
|
+
generateExamplesHelp,
|
|
28
|
+
getFunctionsManifestPath,
|
|
29
|
+
getInternalFunctionsDir,
|
|
30
|
+
getToken,
|
|
31
|
+
log,
|
|
32
|
+
logJson,
|
|
33
|
+
openBrowser,
|
|
34
|
+
warn,
|
|
35
|
+
} = require('../../utils')
|
|
36
|
+
const { link } = require('../link')
|
|
37
|
+
const { sitesCreate } = require('../sites')
|
|
28
38
|
|
|
29
39
|
const DEFAULT_DEPLOY_TIMEOUT = 1.2e6
|
|
30
40
|
|
|
@@ -43,26 +53,35 @@ const triggerDeploy = async ({ api, siteData, siteId }) => {
|
|
|
43
53
|
}
|
|
44
54
|
}
|
|
45
55
|
|
|
46
|
-
|
|
56
|
+
/**
|
|
57
|
+
* g
|
|
58
|
+
* @param {object} config
|
|
59
|
+
* @param {object} config.config
|
|
60
|
+
* @param {import('commander').OptionValues} config.options
|
|
61
|
+
* @param {object} config.site
|
|
62
|
+
* @param {object} config.siteData
|
|
63
|
+
* @returns {Promise<string>}
|
|
64
|
+
*/
|
|
65
|
+
const getDeployFolder = async ({ config, options, site, siteData }) => {
|
|
47
66
|
let deployFolder
|
|
48
|
-
if (
|
|
49
|
-
deployFolder =
|
|
67
|
+
if (options.dir) {
|
|
68
|
+
deployFolder = resolve(cwd(), options.dir)
|
|
50
69
|
} else if (get(config, 'build.publish')) {
|
|
51
|
-
deployFolder =
|
|
70
|
+
deployFolder = resolve(site.root, get(config, 'build.publish'))
|
|
52
71
|
} else if (get(siteData, 'build_settings.dir')) {
|
|
53
|
-
deployFolder =
|
|
72
|
+
deployFolder = resolve(site.root, get(siteData, 'build_settings.dir'))
|
|
54
73
|
}
|
|
55
74
|
|
|
56
75
|
if (!deployFolder) {
|
|
57
76
|
log('Please provide a publish directory (e.g. "public" or "dist" or "."):')
|
|
58
|
-
log(
|
|
77
|
+
log(cwd())
|
|
59
78
|
const { promptPath } = await inquirer.prompt([
|
|
60
79
|
{
|
|
61
80
|
type: 'input',
|
|
62
81
|
name: 'promptPath',
|
|
63
82
|
message: 'Publish directory',
|
|
64
83
|
default: '.',
|
|
65
|
-
filter: (input) =>
|
|
84
|
+
filter: (input) => resolve(cwd(), input),
|
|
66
85
|
},
|
|
67
86
|
])
|
|
68
87
|
deployFolder = promptPath
|
|
@@ -72,9 +91,10 @@ const getDeployFolder = async ({ config, flags, site, siteData }) => {
|
|
|
72
91
|
}
|
|
73
92
|
|
|
74
93
|
const validateDeployFolder = async ({ deployFolder }) => {
|
|
75
|
-
|
|
94
|
+
/** @type {import('fs').Stats} */
|
|
95
|
+
let stats
|
|
76
96
|
try {
|
|
77
|
-
|
|
97
|
+
stats = await stat(deployFolder)
|
|
78
98
|
} catch (error_) {
|
|
79
99
|
if (error_.code === 'ENOENT') {
|
|
80
100
|
return error(`No such directory ${deployFolder}! Did you forget to run a build?`)
|
|
@@ -87,33 +107,43 @@ const validateDeployFolder = async ({ deployFolder }) => {
|
|
|
87
107
|
throw error_
|
|
88
108
|
}
|
|
89
109
|
|
|
90
|
-
if (!
|
|
110
|
+
if (!stats.isDirectory()) {
|
|
91
111
|
return error('Deploy target must be a path to a directory')
|
|
92
112
|
}
|
|
93
|
-
return
|
|
113
|
+
return stats
|
|
94
114
|
}
|
|
95
115
|
|
|
96
|
-
|
|
116
|
+
/**
|
|
117
|
+
* get the functions directory
|
|
118
|
+
* @param {object} config
|
|
119
|
+
* @param {object} config.config
|
|
120
|
+
* @param {import('commander').OptionValues} config.options
|
|
121
|
+
* @param {object} config.site
|
|
122
|
+
* @param {object} config.siteData
|
|
123
|
+
* @returns {string}
|
|
124
|
+
*/
|
|
125
|
+
const getFunctionsFolder = ({ config, options, site, siteData }) => {
|
|
97
126
|
let functionsFolder
|
|
98
127
|
// Support "functions" and "Functions"
|
|
99
128
|
const funcConfig = config.functionsDirectory
|
|
100
|
-
if (
|
|
101
|
-
functionsFolder =
|
|
129
|
+
if (options.functions) {
|
|
130
|
+
functionsFolder = resolve(cwd(), options.functions)
|
|
102
131
|
} else if (funcConfig) {
|
|
103
|
-
functionsFolder =
|
|
132
|
+
functionsFolder = resolve(site.root, funcConfig)
|
|
104
133
|
} else if (get(siteData, 'build_settings.functions_dir')) {
|
|
105
|
-
functionsFolder =
|
|
134
|
+
functionsFolder = resolve(site.root, get(siteData, 'build_settings.functions_dir'))
|
|
106
135
|
}
|
|
107
136
|
return functionsFolder
|
|
108
137
|
}
|
|
109
138
|
|
|
110
139
|
const validateFunctionsFolder = async ({ functionsFolder }) => {
|
|
111
|
-
|
|
140
|
+
/** @type {import('fs').Stats} */
|
|
141
|
+
let stats
|
|
112
142
|
if (functionsFolder) {
|
|
113
143
|
// we used to hard error if functions folder is specified but doesn't exist
|
|
114
144
|
// but this was too strict for onboarding. we can just log a warning.
|
|
115
145
|
try {
|
|
116
|
-
|
|
146
|
+
stats = await stat(functionsFolder)
|
|
117
147
|
} catch (error_) {
|
|
118
148
|
if (error_.code === 'ENOENT') {
|
|
119
149
|
log(
|
|
@@ -127,11 +157,11 @@ const validateFunctionsFolder = async ({ functionsFolder }) => {
|
|
|
127
157
|
}
|
|
128
158
|
}
|
|
129
159
|
|
|
130
|
-
if (
|
|
160
|
+
if (stats && !stats.isDirectory()) {
|
|
131
161
|
error('Functions folder must be a path to a directory')
|
|
132
162
|
}
|
|
133
163
|
|
|
134
|
-
return
|
|
164
|
+
return stats
|
|
135
165
|
}
|
|
136
166
|
|
|
137
167
|
const validateFolders = async ({ deployFolder, functionsFolder }) => {
|
|
@@ -154,12 +184,12 @@ const getDeployFilesFilter = ({ deployFolder, site }) => {
|
|
|
154
184
|
return true
|
|
155
185
|
}
|
|
156
186
|
|
|
157
|
-
const
|
|
187
|
+
const base = basename(filename)
|
|
158
188
|
const skipFile =
|
|
159
|
-
(skipNodeModules &&
|
|
160
|
-
(
|
|
161
|
-
|
|
162
|
-
|
|
189
|
+
(skipNodeModules && base === 'node_modules') ||
|
|
190
|
+
(base.startsWith('.') && base !== '.well-known') ||
|
|
191
|
+
base.startsWith('__MACOSX') ||
|
|
192
|
+
base.includes('/.')
|
|
163
193
|
|
|
164
194
|
return !skipFile
|
|
165
195
|
}
|
|
@@ -226,18 +256,50 @@ const reportDeployError = ({ error_, failAndExit }) => {
|
|
|
226
256
|
}
|
|
227
257
|
}
|
|
228
258
|
|
|
259
|
+
const deployProgressCb = function () {
|
|
260
|
+
/**
|
|
261
|
+
* @type {Record<string, import('ora').Ora>}
|
|
262
|
+
*/
|
|
263
|
+
const events = {}
|
|
264
|
+
return (event) => {
|
|
265
|
+
switch (event.phase) {
|
|
266
|
+
case 'start': {
|
|
267
|
+
events[event.type] = startSpinner({
|
|
268
|
+
text: event.msg,
|
|
269
|
+
})
|
|
270
|
+
return
|
|
271
|
+
}
|
|
272
|
+
case 'progress': {
|
|
273
|
+
const spinner = events[event.type]
|
|
274
|
+
if (spinner) {
|
|
275
|
+
spinner.text = event.msg
|
|
276
|
+
}
|
|
277
|
+
return
|
|
278
|
+
}
|
|
279
|
+
case 'stop':
|
|
280
|
+
default: {
|
|
281
|
+
stopSpinner({ spinner: events[event.type], text: event.msg })
|
|
282
|
+
delete events[event.type]
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
229
288
|
const runDeploy = async ({
|
|
230
289
|
alias,
|
|
231
290
|
api,
|
|
232
291
|
configPath,
|
|
233
292
|
deployFolder,
|
|
293
|
+
deployTimeout,
|
|
234
294
|
deployToProduction,
|
|
235
|
-
flags,
|
|
236
295
|
functionsConfig,
|
|
237
296
|
functionsFolder,
|
|
297
|
+
silent,
|
|
238
298
|
site,
|
|
239
299
|
siteData,
|
|
240
300
|
siteId,
|
|
301
|
+
skipFunctionsCache,
|
|
302
|
+
title,
|
|
241
303
|
}) => {
|
|
242
304
|
let results
|
|
243
305
|
let deployId
|
|
@@ -249,11 +311,9 @@ const runDeploy = async ({
|
|
|
249
311
|
}
|
|
250
312
|
|
|
251
313
|
const draft = !deployToProduction && !alias
|
|
252
|
-
const title = flags.message
|
|
253
314
|
results = await api.createSiteDeploy({ siteId, title, body: { draft, branch: alias } })
|
|
254
315
|
deployId = results.id
|
|
255
316
|
|
|
256
|
-
const silent = flags.json || flags.silent
|
|
257
317
|
await deployEdgeHandlers({
|
|
258
318
|
site,
|
|
259
319
|
deployId,
|
|
@@ -266,15 +326,15 @@ const runDeploy = async ({
|
|
|
266
326
|
// functions from the rightmost directories. In this case, we want user
|
|
267
327
|
// functions to take precedence over internal functions.
|
|
268
328
|
const functionDirectories = [internalFunctionsFolder, functionsFolder].filter(Boolean)
|
|
269
|
-
const skipFunctionsCache = flags['skip-functions-cache'] === true
|
|
270
329
|
const manifestPath = skipFunctionsCache ? null : await getFunctionsManifestPath({ base: site.root })
|
|
271
330
|
|
|
331
|
+
// @ts-ignore
|
|
272
332
|
results = await deploySite(api, siteId, deployFolder, {
|
|
273
333
|
configPath,
|
|
274
334
|
fnDir: functionDirectories,
|
|
275
335
|
functionsConfig,
|
|
276
336
|
statusCb: silent ? () => {} : deployProgressCb(),
|
|
277
|
-
deployTimeout
|
|
337
|
+
deployTimeout,
|
|
278
338
|
syncFileLimit: SYNC_FILE_LIMIT,
|
|
279
339
|
// pass an existing deployId to update
|
|
280
340
|
deployId,
|
|
@@ -304,24 +364,40 @@ const runDeploy = async ({
|
|
|
304
364
|
}
|
|
305
365
|
}
|
|
306
366
|
|
|
307
|
-
|
|
308
|
-
|
|
367
|
+
/**
|
|
368
|
+
*
|
|
369
|
+
* @param {object} config
|
|
370
|
+
* @param {*} config.cachedConfig
|
|
371
|
+
* @param {import('commander').OptionValues} config.options The options of the command
|
|
372
|
+
* @returns
|
|
373
|
+
*/
|
|
374
|
+
const handleBuild = async ({ cachedConfig, options }) => {
|
|
375
|
+
if (!options.build) {
|
|
309
376
|
return {}
|
|
310
377
|
}
|
|
311
378
|
const [token] = await getToken()
|
|
312
|
-
const
|
|
313
|
-
|
|
379
|
+
const resolvedOptions = await getBuildOptions({
|
|
380
|
+
cachedConfig,
|
|
314
381
|
token,
|
|
315
|
-
|
|
382
|
+
options,
|
|
316
383
|
})
|
|
317
|
-
const { configMutations, exitCode, newConfig } = await runBuild(
|
|
384
|
+
const { configMutations, exitCode, newConfig } = await runBuild(resolvedOptions)
|
|
318
385
|
if (exitCode !== 0) {
|
|
319
386
|
exit(exitCode)
|
|
320
387
|
}
|
|
321
388
|
return { newConfig, configMutations }
|
|
322
389
|
}
|
|
323
390
|
|
|
324
|
-
|
|
391
|
+
/**
|
|
392
|
+
*
|
|
393
|
+
* @param {object} config
|
|
394
|
+
* @param {boolean} config.deployToProduction
|
|
395
|
+
* @param {boolean} config.json If the result should be printed as json message
|
|
396
|
+
* @param {boolean} config.runBuildCommand If the build command should be run
|
|
397
|
+
* @param {object} config.results
|
|
398
|
+
* @returns {void}
|
|
399
|
+
*/
|
|
400
|
+
const printResults = ({ deployToProduction, json, results, runBuildCommand }) => {
|
|
325
401
|
const msgData = {
|
|
326
402
|
Logs: `${results.logsUrl}`,
|
|
327
403
|
'Unique Deploy URL': results.deployUrl,
|
|
@@ -338,7 +414,7 @@ const printResults = ({ deployToProduction, flags, results }) => {
|
|
|
338
414
|
log()
|
|
339
415
|
|
|
340
416
|
// Json response for piping commands
|
|
341
|
-
if (
|
|
417
|
+
if (json) {
|
|
342
418
|
const jsonData = {
|
|
343
419
|
name: results.name,
|
|
344
420
|
site_id: results.site_id,
|
|
@@ -359,133 +435,181 @@ const printResults = ({ deployToProduction, flags, results }) => {
|
|
|
359
435
|
if (!deployToProduction) {
|
|
360
436
|
log()
|
|
361
437
|
log('If everything looks good on your draft URL, deploy it to your main site URL with the --prod flag.')
|
|
362
|
-
log(`${chalk.cyanBright.bold(`netlify deploy${
|
|
438
|
+
log(`${chalk.cyanBright.bold(`netlify deploy${runBuildCommand ? ' --build' : ''} --prod`)}`)
|
|
363
439
|
log()
|
|
364
440
|
}
|
|
365
441
|
}
|
|
366
442
|
}
|
|
367
443
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
444
|
+
/**
|
|
445
|
+
* The deploy command
|
|
446
|
+
* @param {import('commander').OptionValues} options
|
|
447
|
+
* @param {import('../base-command').BaseCommand} command
|
|
448
|
+
*/
|
|
449
|
+
const deploy = async (options, command) => {
|
|
450
|
+
const { api, site } = command.netlify
|
|
451
|
+
const alias = options.alias || options.branch
|
|
373
452
|
|
|
374
|
-
|
|
453
|
+
command.setAnalyticsPayload({ open: options.open, prod: options.prod, json: options.json, alias: Boolean(alias) })
|
|
375
454
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
455
|
+
if (options.branch) {
|
|
456
|
+
warn('--branch flag has been renamed to --alias and will be removed in future versions')
|
|
457
|
+
}
|
|
379
458
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
} else {
|
|
396
|
-
log("This folder isn't linked to a site yet")
|
|
397
|
-
const NEW_SITE = '+ Create & configure a new site'
|
|
398
|
-
const EXISTING_SITE = 'Link this directory to an existing site'
|
|
399
|
-
|
|
400
|
-
const initializeOpts = [EXISTING_SITE, NEW_SITE]
|
|
401
|
-
|
|
402
|
-
const { initChoice } = await inquirer.prompt([
|
|
403
|
-
{
|
|
404
|
-
type: 'list',
|
|
405
|
-
name: 'initChoice',
|
|
406
|
-
message: 'What would you like to do?',
|
|
407
|
-
choices: initializeOpts,
|
|
408
|
-
},
|
|
409
|
-
])
|
|
410
|
-
// create site or search for one
|
|
411
|
-
if (initChoice === NEW_SITE) {
|
|
412
|
-
// run site:create command
|
|
413
|
-
siteData = await SitesCreateCommand.run([])
|
|
414
|
-
site.id = siteData.id
|
|
415
|
-
siteId = site.id
|
|
416
|
-
} else if (initChoice === EXISTING_SITE) {
|
|
417
|
-
// run link command
|
|
418
|
-
siteData = await LinkCommand.run([], false)
|
|
419
|
-
site.id = siteData.id
|
|
420
|
-
siteId = site.id
|
|
459
|
+
await command.authenticate(options.auth)
|
|
460
|
+
|
|
461
|
+
let siteId = options.site || site.id
|
|
462
|
+
let siteData = {}
|
|
463
|
+
if (siteId) {
|
|
464
|
+
try {
|
|
465
|
+
siteData = await api.getSite({ siteId })
|
|
466
|
+
} catch (error_) {
|
|
467
|
+
// TODO specifically handle known cases (e.g. no account access)
|
|
468
|
+
if (error_.status === 404) {
|
|
469
|
+
error('Site not found')
|
|
470
|
+
} else {
|
|
471
|
+
error(error_.message)
|
|
421
472
|
}
|
|
422
473
|
}
|
|
474
|
+
} else {
|
|
475
|
+
log("This folder isn't linked to a site yet")
|
|
476
|
+
const NEW_SITE = '+ Create & configure a new site'
|
|
477
|
+
const EXISTING_SITE = 'Link this directory to an existing site'
|
|
423
478
|
|
|
424
|
-
const
|
|
479
|
+
const initializeOpts = [EXISTING_SITE, NEW_SITE]
|
|
425
480
|
|
|
426
|
-
|
|
427
|
-
|
|
481
|
+
const { initChoice } = await inquirer.prompt([
|
|
482
|
+
{
|
|
483
|
+
type: 'list',
|
|
484
|
+
name: 'initChoice',
|
|
485
|
+
message: 'What would you like to do?',
|
|
486
|
+
choices: initializeOpts,
|
|
487
|
+
},
|
|
488
|
+
])
|
|
489
|
+
// create site or search for one
|
|
490
|
+
if (initChoice === NEW_SITE) {
|
|
491
|
+
siteData = await sitesCreate({}, command)
|
|
492
|
+
site.id = siteData.id
|
|
493
|
+
siteId = site.id
|
|
494
|
+
} else if (initChoice === EXISTING_SITE) {
|
|
495
|
+
siteData = await link({}, command)
|
|
496
|
+
site.id = siteData.id
|
|
497
|
+
siteId = site.id
|
|
428
498
|
}
|
|
499
|
+
}
|
|
429
500
|
|
|
430
|
-
|
|
431
|
-
const config = newConfig || this.netlify.config
|
|
432
|
-
|
|
433
|
-
const deployFolder = await getDeployFolder({ flags, config, site, siteData })
|
|
434
|
-
const functionsFolder = getFunctionsFolder({ flags, config, site, siteData })
|
|
435
|
-
const { configPath } = site
|
|
436
|
-
|
|
437
|
-
log(
|
|
438
|
-
prettyjson.render({
|
|
439
|
-
'Deploy path': deployFolder,
|
|
440
|
-
'Functions path': functionsFolder,
|
|
441
|
-
'Configuration path': configPath,
|
|
442
|
-
}),
|
|
443
|
-
)
|
|
501
|
+
const deployToProduction = options.prod || (options.prodIfUnlocked && !siteData.published_deploy.locked)
|
|
444
502
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
})
|
|
449
|
-
const functionsConfig = normalizeFunctionsConfig({ functionsConfig: config.functions, projectRoot: site.root })
|
|
503
|
+
if (options.trigger) {
|
|
504
|
+
return triggerDeploy({ api, siteId, siteData })
|
|
505
|
+
}
|
|
450
506
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
507
|
+
const { newConfig, configMutations = [] } = await handleBuild({
|
|
508
|
+
cachedConfig: command.netlify.cachedConfig,
|
|
509
|
+
options,
|
|
510
|
+
})
|
|
511
|
+
const config = newConfig || command.netlify.config
|
|
512
|
+
|
|
513
|
+
const deployFolder = await getDeployFolder({ options, config, site, siteData })
|
|
514
|
+
const functionsFolder = getFunctionsFolder({ options, config, site, siteData })
|
|
515
|
+
const { configPath } = site
|
|
516
|
+
|
|
517
|
+
log(
|
|
518
|
+
prettyjson.render({
|
|
519
|
+
'Deploy path': deployFolder,
|
|
520
|
+
'Functions path': functionsFolder,
|
|
521
|
+
'Configuration path': configPath,
|
|
522
|
+
}),
|
|
523
|
+
)
|
|
524
|
+
|
|
525
|
+
const { functionsFolderStat } = await validateFolders({
|
|
526
|
+
deployFolder,
|
|
527
|
+
functionsFolder,
|
|
528
|
+
})
|
|
529
|
+
const functionsConfig = normalizeFunctionsConfig({ functionsConfig: config.functions, projectRoot: site.root })
|
|
530
|
+
|
|
531
|
+
const redirectsPath = `${deployFolder}/_redirects`
|
|
532
|
+
// @ts-ignore
|
|
533
|
+
await updateConfig(configMutations, {
|
|
534
|
+
buildDir: deployFolder,
|
|
535
|
+
configPath,
|
|
536
|
+
redirectsPath,
|
|
537
|
+
context: command.netlify.cachedConfig.context,
|
|
538
|
+
branch: command.netlify.cachedConfig.branch,
|
|
539
|
+
})
|
|
540
|
+
const results = await runDeploy({
|
|
541
|
+
alias,
|
|
542
|
+
api,
|
|
543
|
+
configPath,
|
|
544
|
+
deployFolder,
|
|
545
|
+
deployTimeout: options.timeout * SEC_TO_MILLISEC || DEFAULT_DEPLOY_TIMEOUT,
|
|
546
|
+
deployToProduction,
|
|
547
|
+
functionsConfig,
|
|
548
|
+
// pass undefined functionsFolder if doesn't exist
|
|
549
|
+
functionsFolder: functionsFolderStat && functionsFolder,
|
|
550
|
+
silent: options.json || options.silent,
|
|
551
|
+
site,
|
|
552
|
+
siteData,
|
|
553
|
+
siteId,
|
|
554
|
+
skipFunctionsCache: options.skipFunctionsCache,
|
|
555
|
+
title: options.message,
|
|
556
|
+
})
|
|
473
557
|
|
|
474
|
-
|
|
558
|
+
// @ts-ignore
|
|
559
|
+
await restoreConfig(configMutations, { buildDir: deployFolder, configPath, redirectsPath })
|
|
475
560
|
|
|
476
|
-
|
|
561
|
+
printResults({
|
|
562
|
+
runBuildCommand: options.build,
|
|
563
|
+
json: options.json,
|
|
564
|
+
results,
|
|
565
|
+
deployToProduction,
|
|
566
|
+
})
|
|
477
567
|
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
}
|
|
568
|
+
if (options.open) {
|
|
569
|
+
const urlToOpen = deployToProduction ? results.siteUrl : results.deployUrl
|
|
570
|
+
await openBrowser({ url: urlToOpen })
|
|
571
|
+
exit()
|
|
483
572
|
}
|
|
484
573
|
}
|
|
485
574
|
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
575
|
+
/**
|
|
576
|
+
* Creates the `netlify deploy` command
|
|
577
|
+
* @param {import('../base-command').BaseCommand} program
|
|
578
|
+
* @returns
|
|
579
|
+
*/
|
|
580
|
+
const createDeployCommand = (program) =>
|
|
581
|
+
program
|
|
582
|
+
.command('deploy')
|
|
583
|
+
.description('Create a new deploy from the contents of a folder')
|
|
584
|
+
.option('-d, --dir <path>', 'Specify a folder to deploy')
|
|
585
|
+
.option('-f, --functions', 'Specify a functions folder to deploy')
|
|
586
|
+
.option('-p, --prod', 'Deploy to production', false)
|
|
587
|
+
.option('--prodIfUnlocked', 'Deploy to production if unlocked, create a draft otherwise', false)
|
|
588
|
+
.option(
|
|
589
|
+
'--alias <name>',
|
|
590
|
+
'Specifies the alias for deployment, the string at the beginning of the deploy subdomain. Useful for creating predictable deployment URLs. Avoid setting an alias string to the same value as a deployed branch. `alias` doesn’t create a branch deploy and can’t be used in conjunction with the branch subdomain feature. Maximum 37 characters.',
|
|
591
|
+
)
|
|
592
|
+
.option(
|
|
593
|
+
'-b, --branch <name>',
|
|
594
|
+
'Serves the same functionality as --alias. Deprecated and will be removed in future versions',
|
|
595
|
+
)
|
|
596
|
+
.option('-o, --open', 'Open site after deploy', false)
|
|
597
|
+
.option('-m, --message <message>', 'A short message to include in the deploy log')
|
|
598
|
+
.option('-a, --auth <token>', 'Netlify auth token to deploy with', env.NETLIFY_AUTH_TOKEN)
|
|
599
|
+
.option('-s, --site <id>', 'A site ID to deploy to', env.NETLIFY_SITE_ID)
|
|
600
|
+
.option('--json', 'Output deployment data as JSON')
|
|
601
|
+
.option('--timeout <number>', 'Timeout to wait for deployment to finish', (value) => Number.parseInt(value))
|
|
602
|
+
.option('--trigger', 'Trigger a new build of your site on Netlify without uploading local files')
|
|
603
|
+
.option('--build', 'Run build command before deploying')
|
|
604
|
+
.option(
|
|
605
|
+
'--skip-functions-cache',
|
|
606
|
+
'Ignore any functions created as part of a previous `build` or `deploy` commands, forcing them to be bundled again as part of the deployment',
|
|
607
|
+
false,
|
|
608
|
+
)
|
|
609
|
+
.addHelpText(
|
|
610
|
+
'after',
|
|
611
|
+
generateDescriptionHelp(
|
|
612
|
+
`Deploys from the build settings found in the netlify.toml file, or settings from the API.
|
|
489
613
|
|
|
490
614
|
The following environment variables can be used to override configuration file lookups and prompts:
|
|
491
615
|
|
|
@@ -547,121 +671,25 @@ Function entry points are determined by the file name and name of the folder the
|
|
|
547
671
|
functions/
|
|
548
672
|
├── aFolderlessFunctionEntrypoint.js
|
|
549
673
|
└── functionName/
|
|
550
|
-
|
|
551
|
-
|
|
674
|
+
├── notTheEntryPoint.js
|
|
675
|
+
└── functionName.js
|
|
552
676
|
\`\`\`
|
|
553
677
|
|
|
554
|
-
Support for package.json's main field, and intrinsic index.js entrypoints are coming soon
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
description: 'Specify a folder to deploy',
|
|
571
|
-
}),
|
|
572
|
-
functions: flagsLib.string({
|
|
573
|
-
char: 'f',
|
|
574
|
-
description: 'Specify a functions folder to deploy',
|
|
575
|
-
}),
|
|
576
|
-
prod: flagsLib.boolean({
|
|
577
|
-
char: 'p',
|
|
578
|
-
description: 'Deploy to production',
|
|
579
|
-
default: false,
|
|
580
|
-
exclusive: ['alias', 'branch', 'prodIfUnlocked'],
|
|
581
|
-
}),
|
|
582
|
-
prodIfUnlocked: flagsLib.boolean({
|
|
583
|
-
description: 'Deploy to production if unlocked, create a draft otherwise',
|
|
584
|
-
default: false,
|
|
585
|
-
exclusive: ['alias', 'branch', 'prod'],
|
|
586
|
-
}),
|
|
587
|
-
alias: flagsLib.string({
|
|
588
|
-
description:
|
|
589
|
-
'Specifies the alias for deployment, the string at the beginning of the deploy subdomain. Useful for creating predictable deployment URLs. Avoid setting an alias string to the same value as a deployed branch. `alias` doesn’t create a branch deploy and can’t be used in conjunction with the branch subdomain feature. Maximum 37 characters.',
|
|
590
|
-
}),
|
|
591
|
-
branch: flagsLib.string({
|
|
592
|
-
char: 'b',
|
|
593
|
-
description: 'Serves the same functionality as --alias. Deprecated and will be removed in future versions',
|
|
594
|
-
}),
|
|
595
|
-
open: flagsLib.boolean({
|
|
596
|
-
char: 'o',
|
|
597
|
-
description: 'Open site after deploy',
|
|
598
|
-
default: false,
|
|
599
|
-
}),
|
|
600
|
-
message: flagsLib.string({
|
|
601
|
-
char: 'm',
|
|
602
|
-
description: 'A short message to include in the deploy log',
|
|
603
|
-
}),
|
|
604
|
-
auth: flagsLib.string({
|
|
605
|
-
char: 'a',
|
|
606
|
-
description: 'Netlify auth token to deploy with',
|
|
607
|
-
env: 'NETLIFY_AUTH_TOKEN',
|
|
608
|
-
}),
|
|
609
|
-
site: flagsLib.string({
|
|
610
|
-
char: 's',
|
|
611
|
-
description: 'A site ID to deploy to',
|
|
612
|
-
env: 'NETLIFY_SITE_ID',
|
|
613
|
-
}),
|
|
614
|
-
json: flagsLib.boolean({
|
|
615
|
-
description: 'Output deployment data as JSON',
|
|
616
|
-
}),
|
|
617
|
-
timeout: flagsLib.integer({
|
|
618
|
-
description: 'Timeout to wait for deployment to finish',
|
|
619
|
-
}),
|
|
620
|
-
trigger: flagsLib.boolean({
|
|
621
|
-
description: 'Trigger a new build of your site on Netlify without uploading local files',
|
|
622
|
-
exclusive: ['build'],
|
|
623
|
-
}),
|
|
624
|
-
build: flagsLib.boolean({
|
|
625
|
-
description: 'Run build command before deploying',
|
|
626
|
-
}),
|
|
627
|
-
'skip-functions-cache': flagsLib.boolean({
|
|
628
|
-
description:
|
|
629
|
-
'Ignore any functions created as part of a previous `build` or `deploy` commands, forcing them to be bundled again as part of the deployment',
|
|
630
|
-
default: false,
|
|
631
|
-
}),
|
|
632
|
-
...DeployCommand.flags,
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
const deployProgressCb = function () {
|
|
636
|
-
const events = {}
|
|
637
|
-
// event: {
|
|
638
|
-
// type: name-of-step
|
|
639
|
-
// msg: msg to print
|
|
640
|
-
// phase: [start, progress, stop]
|
|
641
|
-
// }
|
|
642
|
-
//
|
|
643
|
-
return (event) => {
|
|
644
|
-
switch (event.phase) {
|
|
645
|
-
case 'start': {
|
|
646
|
-
events[event.type] = startSpinner({
|
|
647
|
-
text: event.msg,
|
|
648
|
-
})
|
|
649
|
-
return
|
|
650
|
-
}
|
|
651
|
-
case 'progress': {
|
|
652
|
-
const spinner = events[event.type]
|
|
653
|
-
if (spinner) {
|
|
654
|
-
spinner.text = event.msg
|
|
655
|
-
}
|
|
656
|
-
return
|
|
657
|
-
}
|
|
658
|
-
case 'stop':
|
|
659
|
-
default: {
|
|
660
|
-
stopSpinner({ spinner: events[event.type], text: event.msg })
|
|
661
|
-
delete events[event.type]
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
}
|
|
678
|
+
Support for package.json's main field, and intrinsic index.js entrypoints are coming soon.`,
|
|
679
|
+
),
|
|
680
|
+
)
|
|
681
|
+
.addHelpText(
|
|
682
|
+
'after',
|
|
683
|
+
generateExamplesHelp([
|
|
684
|
+
'netlify deploy',
|
|
685
|
+
'netlify deploy --prod',
|
|
686
|
+
'netlify deploy --prod --open',
|
|
687
|
+
'netlify deploy --prodIfUnlocked',
|
|
688
|
+
'netlify deploy --message "A message with an $ENV_VAR"',
|
|
689
|
+
'netlify deploy --auth $NETLIFY_AUTH_TOKEN',
|
|
690
|
+
'netlify deploy --trigger',
|
|
691
|
+
]),
|
|
692
|
+
)
|
|
693
|
+
.action(deploy)
|
|
666
694
|
|
|
667
|
-
module.exports =
|
|
695
|
+
module.exports = { createDeployCommand }
|