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
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
const { generateCommandsHelp, generateDescriptionHelp, generateExamplesHelp } = require('../../utils')
|
|
4
|
+
|
|
5
|
+
const { createLmInfoCommand } = require('./lm-info')
|
|
6
|
+
const { createLmInstallCommand } = require('./lm-install')
|
|
7
|
+
const { createLmSetupCommand } = require('./lm-setup')
|
|
8
|
+
const { createLmUninstallCommand } = require('./lm-uninstall')
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The lm command
|
|
12
|
+
* @param {import('commander').OptionValues} options
|
|
13
|
+
* @param {import('../base-command').BaseCommand} command
|
|
14
|
+
*/
|
|
15
|
+
const lm = (options, command) => {
|
|
16
|
+
command.help()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Creates the `netlify lm` command
|
|
21
|
+
* @param {import('../base-command').BaseCommand} program
|
|
22
|
+
* @returns
|
|
23
|
+
*/
|
|
24
|
+
const createLmCommand = (program) => {
|
|
25
|
+
createLmInfoCommand(program)
|
|
26
|
+
createLmInstallCommand(program)
|
|
27
|
+
createLmSetupCommand(program)
|
|
28
|
+
createLmUninstallCommand(program)
|
|
29
|
+
|
|
30
|
+
program
|
|
31
|
+
.command('lm')
|
|
32
|
+
.description('Handle Netlify Large Media operations')
|
|
33
|
+
.addHelpCommand('after', generateDescriptionHelp('The lm command will help you manage large media for a site'))
|
|
34
|
+
.addHelpCommand('after', generateExamplesHelp(['netlify lm:info', 'netlify lm:install', 'netlify lm:setup']))
|
|
35
|
+
.addHelpCommand('after', generateCommandsHelp('lm', program))
|
|
36
|
+
.action(lm)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = { createLmCommand }
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
const { chalk, exit, getToken, log } = require('../../utils')
|
|
3
|
+
|
|
4
|
+
const msg = function (location) {
|
|
5
|
+
switch (location) {
|
|
6
|
+
case 'env':
|
|
7
|
+
return 'via process.env.NETLIFY_AUTH_TOKEN set in your terminal session'
|
|
8
|
+
case 'flag':
|
|
9
|
+
return 'via CLI --auth flag'
|
|
10
|
+
case 'config':
|
|
11
|
+
return 'via netlify config on your machine'
|
|
12
|
+
default:
|
|
13
|
+
return ''
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The login command
|
|
19
|
+
* @param {import('commander').OptionValues} options
|
|
20
|
+
* @param {import('../base-command').BaseCommand} command
|
|
21
|
+
*/
|
|
22
|
+
const login = async (options, command) => {
|
|
23
|
+
const [accessToken, location] = await getToken()
|
|
24
|
+
|
|
25
|
+
command.setAnalyticsPayload({ new: options.new })
|
|
26
|
+
|
|
27
|
+
if (accessToken && !options.new) {
|
|
28
|
+
log(`Already logged in ${msg(location)}`)
|
|
29
|
+
log()
|
|
30
|
+
log(`Run ${chalk.cyanBright('netlify status')} for account details`)
|
|
31
|
+
log()
|
|
32
|
+
log(`To see all available commands run: ${chalk.cyanBright('netlify help')}`)
|
|
33
|
+
log()
|
|
34
|
+
return exit()
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
await command.expensivelyAuthenticate()
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Creates the `netlify login` command
|
|
42
|
+
* @param {import('../base-command').BaseCommand} program
|
|
43
|
+
* @returns
|
|
44
|
+
*/
|
|
45
|
+
const createLoginCommand = (program) =>
|
|
46
|
+
program
|
|
47
|
+
.command('login')
|
|
48
|
+
.description('Login to your Netlify account')
|
|
49
|
+
.option('--new', 'Login to new Netlify account')
|
|
50
|
+
.action(login)
|
|
51
|
+
|
|
52
|
+
module.exports = { createLoginCommand, login }
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
const { exit, getToken, log, track } = require('../../utils')
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The logout command
|
|
6
|
+
* @param {import('commander').OptionValues} options
|
|
7
|
+
* @param {import('../base-command').BaseCommand} command
|
|
8
|
+
*/
|
|
9
|
+
const logout = async (options, command) => {
|
|
10
|
+
const [accessToken, location] = await getToken()
|
|
11
|
+
|
|
12
|
+
if (!accessToken) {
|
|
13
|
+
log(`Already logged out`)
|
|
14
|
+
log()
|
|
15
|
+
log('To login run "netlify login"')
|
|
16
|
+
exit()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
await track('user_logout')
|
|
20
|
+
|
|
21
|
+
// unset userID without deleting key
|
|
22
|
+
command.netlify.globalConfig.set('userId', null)
|
|
23
|
+
|
|
24
|
+
if (location === 'env') {
|
|
25
|
+
log('The "process.env.NETLIFY_AUTH_TOKEN" is still set in your terminal session')
|
|
26
|
+
log()
|
|
27
|
+
log('To logout completely, unset the environment variable')
|
|
28
|
+
log()
|
|
29
|
+
exit()
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
log(`Logging you out of Netlify. Come back soon!`)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Creates the `netlify logout` command
|
|
37
|
+
* @param {import('../base-command').BaseCommand} program
|
|
38
|
+
* @returns
|
|
39
|
+
*/
|
|
40
|
+
const createLogoutCommand = (program) =>
|
|
41
|
+
program.command('logout', { hidden: true }).description('Logout of your Netlify account').action(logout)
|
|
42
|
+
|
|
43
|
+
module.exports = { createLogoutCommand, logout }
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
const process = require('process')
|
|
3
|
+
|
|
4
|
+
const inquirer = require('inquirer')
|
|
5
|
+
const { findBestMatch } = require('string-similarity')
|
|
6
|
+
|
|
7
|
+
const { NETLIFY_CYAN, USER_AGENT, chalk, error, execa, exit, getGlobalConfig, log, track, warn } = require('../utils')
|
|
8
|
+
|
|
9
|
+
const SUGGESTION_TIMEOUT = 1e4
|
|
10
|
+
|
|
11
|
+
const getVersionPage = async () => {
|
|
12
|
+
// performance optimization - load envinfo on demand
|
|
13
|
+
// eslint-disable-next-line node/global-require
|
|
14
|
+
const envinfo = require('envinfo')
|
|
15
|
+
const data = await envinfo.run({
|
|
16
|
+
System: ['OS', 'CPU'],
|
|
17
|
+
Binaries: ['Node', 'Yarn', 'npm'],
|
|
18
|
+
Browsers: ['Chrome', 'Edge', 'Firefox', 'Safari'],
|
|
19
|
+
npmGlobalPackages: ['netlify-cli'],
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
return `
|
|
23
|
+
────────────────────┐
|
|
24
|
+
Environment Info │
|
|
25
|
+
────────────────────┘
|
|
26
|
+
${data}
|
|
27
|
+
${USER_AGENT}
|
|
28
|
+
`
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The main CLI command without any command (root action)
|
|
33
|
+
* @param {import('commander').OptionValues} options
|
|
34
|
+
* @param {import('./base-command').BaseCommand} command
|
|
35
|
+
*/
|
|
36
|
+
const mainCommand = async function (options, command) {
|
|
37
|
+
const globalConfig = await getGlobalConfig()
|
|
38
|
+
|
|
39
|
+
if (options.telemetryDisable) {
|
|
40
|
+
globalConfig.set('telemetryDisabled', true)
|
|
41
|
+
console.log('Netlify telemetry has been disabled')
|
|
42
|
+
console.log('You can renable it anytime with the --telemetry-enable flag')
|
|
43
|
+
exit()
|
|
44
|
+
}
|
|
45
|
+
if (options.telemetryEnable) {
|
|
46
|
+
globalConfig.set('telemetryDisabled', false)
|
|
47
|
+
console.log('Netlify telemetry has been enabled')
|
|
48
|
+
console.log('You can disable it anytime with the --telemetry-disable flag')
|
|
49
|
+
await track('user_telemetryEnabled')
|
|
50
|
+
exit()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (command.args[0] === 'version') {
|
|
54
|
+
const versionPage = await getVersionPage()
|
|
55
|
+
log(versionPage)
|
|
56
|
+
exit()
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
warn(`${chalk.yellow(command.args[0])} is not a ${command.name()} command.`)
|
|
60
|
+
|
|
61
|
+
const allCommands = command.commands.map((cmd) => cmd.name())
|
|
62
|
+
const {
|
|
63
|
+
bestMatch: { target: suggestion },
|
|
64
|
+
} = findBestMatch(command.args[0], allCommands)
|
|
65
|
+
|
|
66
|
+
const applySuggestion = await new Promise((resolve) => {
|
|
67
|
+
const prompt = inquirer.prompt({
|
|
68
|
+
type: 'confirm',
|
|
69
|
+
name: 'suggestion',
|
|
70
|
+
message: `Did you mean ${chalk.blue(suggestion)}`,
|
|
71
|
+
default: false,
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
setTimeout(() => {
|
|
75
|
+
// @ts-ignore
|
|
76
|
+
prompt.ui.close()
|
|
77
|
+
resolve(false)
|
|
78
|
+
}, SUGGESTION_TIMEOUT)
|
|
79
|
+
|
|
80
|
+
// eslint-disable-next-line promise/catch-or-return
|
|
81
|
+
prompt.then((value) => resolve(value))
|
|
82
|
+
})
|
|
83
|
+
// create new log line
|
|
84
|
+
log()
|
|
85
|
+
|
|
86
|
+
if (!applySuggestion) {
|
|
87
|
+
error(`Run ${NETLIFY_CYAN(`${command.name()} help`)} for a list of available commands.`)
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
await execa(process.argv[0], [process.argv[1], suggestion], { stdio: 'inherit' })
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Creates the `netlify functions:create` command
|
|
95
|
+
* @param {import('./base-command').BaseCommand} program
|
|
96
|
+
* @returns
|
|
97
|
+
*/
|
|
98
|
+
const createMainCommand = async (program) =>
|
|
99
|
+
program
|
|
100
|
+
.version(await getVersionPage(), '-v, --version')
|
|
101
|
+
.showSuggestionAfterError(true)
|
|
102
|
+
.option('--telemetry-disable', 'Disable telemetry')
|
|
103
|
+
.option('--telemetry-enable', 'Enables telemetry')
|
|
104
|
+
.configureHelp({
|
|
105
|
+
// TODO: Add custom formater to have same visual styling
|
|
106
|
+
// formatHelp: (cmd, helper) => {
|
|
107
|
+
// console.log(cmd, helper);
|
|
108
|
+
// const longestFlag = Math.max(...cmd.options.map((option) => option.flags.length)) + 1;
|
|
109
|
+
// const table = cmd.options.map(({flags, description}) => ` ${flags}${new Array(longestFlag-flags.length).fill().join(' ')} {grey ${description}} `).join('\n')
|
|
110
|
+
// return chalk`{bold OPTIONS}
|
|
111
|
+
// ${table}
|
|
112
|
+
// `
|
|
113
|
+
// }
|
|
114
|
+
})
|
|
115
|
+
.action(mainCommand)
|
|
116
|
+
|
|
117
|
+
module.exports = { createMainCommand }
|
|
@@ -1,41 +1,5 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { createOpenCommand } = require('./open')
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const showHelp = require('../../utils/show-help')
|
|
6
|
-
|
|
7
|
-
const OpenAdminCommand = require('./admin')
|
|
8
|
-
const OpenSiteCommand = require('./site')
|
|
9
|
-
|
|
10
|
-
class OpenCommand extends Command {
|
|
11
|
-
async run() {
|
|
12
|
-
const { args, flags } = this.parse(OpenCommand)
|
|
13
|
-
|
|
14
|
-
// Show help on empty sub command
|
|
15
|
-
if (isEmptyCommand(flags, args)) {
|
|
16
|
-
showHelp(this.id)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
if (flags.site) {
|
|
20
|
-
await OpenSiteCommand.run()
|
|
21
|
-
}
|
|
22
|
-
// Default open netlify admin
|
|
23
|
-
await OpenAdminCommand.run()
|
|
24
|
-
}
|
|
3
|
+
module.exports = {
|
|
4
|
+
createOpenCommand,
|
|
25
5
|
}
|
|
26
|
-
|
|
27
|
-
OpenCommand.flags = {
|
|
28
|
-
...OpenCommand.flags,
|
|
29
|
-
site: flagsLib.boolean({
|
|
30
|
-
description: 'Open site',
|
|
31
|
-
}),
|
|
32
|
-
admin: flagsLib.boolean({
|
|
33
|
-
description: 'Open Netlify site',
|
|
34
|
-
}),
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
OpenCommand.description = `Open settings for the site linked to the current folder`
|
|
38
|
-
|
|
39
|
-
OpenCommand.examples = ['netlify open --site', 'netlify open --admin', 'netlify open:admin', 'netlify open:site']
|
|
40
|
-
|
|
41
|
-
module.exports = OpenCommand
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const { error, exit, log, openBrowser, warn } = require('../../utils')
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The open:admin command
|
|
5
|
+
* @param {import('commander').OptionValues} options
|
|
6
|
+
* @param {import('../base-command').BaseCommand} command
|
|
7
|
+
*/
|
|
8
|
+
const openAdmin = async (options, command) => {
|
|
9
|
+
const { api, site } = command.netlify
|
|
10
|
+
|
|
11
|
+
await command.authenticate()
|
|
12
|
+
|
|
13
|
+
const siteId = site.id
|
|
14
|
+
|
|
15
|
+
if (!siteId) {
|
|
16
|
+
warn(`No Site ID found in current directory.
|
|
17
|
+
Run \`netlify link\` to connect to this folder to a site`)
|
|
18
|
+
return false
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let siteData
|
|
22
|
+
try {
|
|
23
|
+
siteData = await api.getSite({ siteId })
|
|
24
|
+
log(`Opening "${siteData.name}" site admin UI:`)
|
|
25
|
+
log(`> ${siteData.admin_url}`)
|
|
26
|
+
} catch (error_) {
|
|
27
|
+
// unauthorized
|
|
28
|
+
if (error_.status === 401) {
|
|
29
|
+
warn(`Log in with a different account or re-link to a site you have permission for`)
|
|
30
|
+
error(`Not authorized to view the currently linked site (${siteId})`)
|
|
31
|
+
}
|
|
32
|
+
// site not found
|
|
33
|
+
if (error_.status === 404) {
|
|
34
|
+
log()
|
|
35
|
+
log('Please double check this ID and verify you are logged in with the correct account')
|
|
36
|
+
log()
|
|
37
|
+
log('To fix this, run `netlify unlink` then `netlify link` to reconnect to the correct site ID')
|
|
38
|
+
log()
|
|
39
|
+
error(`Site "${siteId}" not found in account`)
|
|
40
|
+
}
|
|
41
|
+
error(error_)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
await openBrowser({ url: siteData.admin_url })
|
|
45
|
+
exit()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Creates the `netlify open:admin` command
|
|
50
|
+
* @param {import('../base-command').BaseCommand} program
|
|
51
|
+
* @returns
|
|
52
|
+
*/
|
|
53
|
+
const createOpenAdminCommand = (program) =>
|
|
54
|
+
program.command('open:admin').description('Opens current site admin UI in Netlify').action(openAdmin)
|
|
55
|
+
|
|
56
|
+
module.exports = { createOpenAdminCommand, openAdmin }
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
const { error, exit, log, openBrowser, warn } = require('../../utils')
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The open:site command
|
|
5
|
+
* @param {import('commander').OptionValues} options
|
|
6
|
+
* @param {import('../base-command').BaseCommand} command
|
|
7
|
+
*/
|
|
8
|
+
const openSite = async (options, command) => {
|
|
9
|
+
const { api, site } = command.netlify
|
|
10
|
+
|
|
11
|
+
await command.authenticate()
|
|
12
|
+
|
|
13
|
+
const siteId = site.id
|
|
14
|
+
|
|
15
|
+
if (!siteId) {
|
|
16
|
+
warn(`No Site ID found in current directory.
|
|
17
|
+
Run \`netlify link\` to connect to this folder to a site`)
|
|
18
|
+
return false
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
let siteData
|
|
22
|
+
let url
|
|
23
|
+
try {
|
|
24
|
+
siteData = await api.getSite({ siteId })
|
|
25
|
+
url = siteData.ssl_url || siteData.url
|
|
26
|
+
log(`Opening "${siteData.name}" site url:`)
|
|
27
|
+
log(`> ${url}`)
|
|
28
|
+
} catch (error_) {
|
|
29
|
+
// unauthorized
|
|
30
|
+
if (error_.status === 401) {
|
|
31
|
+
warn(`Log in with a different account or re-link to a site you have permission for`)
|
|
32
|
+
error(`Not authorized to view the currently linked site (${siteId})`)
|
|
33
|
+
}
|
|
34
|
+
error(error_)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
await openBrowser({ url })
|
|
38
|
+
exit()
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Creates the `netlify open:site` command
|
|
43
|
+
* @param {import('../base-command').BaseCommand} program
|
|
44
|
+
* @returns
|
|
45
|
+
*/
|
|
46
|
+
const createOpenSiteCommand = (program) =>
|
|
47
|
+
program.command('open:site').description('Opens current site url in browser').action(openSite)
|
|
48
|
+
|
|
49
|
+
module.exports = { createOpenSiteCommand, openSite }
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const { generateCommandsHelp, generateExamplesHelp } = require('../../utils')
|
|
2
|
+
|
|
3
|
+
const { createOpenAdminCommand, openAdmin } = require('./open-admin')
|
|
4
|
+
const { createOpenSiteCommand, openSite } = require('./open-site')
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The open command
|
|
8
|
+
* @param {import('commander').OptionValues} options
|
|
9
|
+
* @param {import('../base-command').BaseCommand} command
|
|
10
|
+
*/
|
|
11
|
+
const open = async (options, command) => {
|
|
12
|
+
if (!options.site || !options.admin) {
|
|
13
|
+
command.help()
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (options.site) {
|
|
17
|
+
await openSite(options, command)
|
|
18
|
+
}
|
|
19
|
+
// Default open netlify admin
|
|
20
|
+
await openAdmin(options, command)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Creates the `netlify open` command
|
|
25
|
+
* @param {import('../base-command').BaseCommand} program
|
|
26
|
+
* @returns
|
|
27
|
+
*/
|
|
28
|
+
const createOpenCommand = (program) => {
|
|
29
|
+
createOpenAdminCommand(program)
|
|
30
|
+
createOpenSiteCommand(program)
|
|
31
|
+
|
|
32
|
+
return program
|
|
33
|
+
.command('open')
|
|
34
|
+
.description('Open settings for the site linked to the current folder')
|
|
35
|
+
.addHelpText(
|
|
36
|
+
'after',
|
|
37
|
+
generateExamplesHelp(['netlify open --site', 'netlify open --admin', 'netlify open:admin', 'netlify open:site']),
|
|
38
|
+
)
|
|
39
|
+
.addHelpText('after', generateCommandsHelp('open', program))
|
|
40
|
+
.action(open)
|
|
41
|
+
}
|
|
42
|
+
module.exports = { createOpenCommand }
|
|
@@ -1,22 +1,7 @@
|
|
|
1
|
-
const {
|
|
2
|
-
const
|
|
3
|
-
const { TrackedCommand } = require('../../utils/telemetry/tracked-command')
|
|
1
|
+
const { createSitesCommand } = require('./sites')
|
|
2
|
+
const { sitesCreate } = require('./sites-create')
|
|
4
3
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
// Show help on empty sub command
|
|
10
|
-
if (isEmptyCommand(flags, args)) {
|
|
11
|
-
showHelp(this.id)
|
|
12
|
-
}
|
|
13
|
-
}
|
|
4
|
+
module.exports = {
|
|
5
|
+
createSitesCommand,
|
|
6
|
+
sitesCreate,
|
|
14
7
|
}
|
|
15
|
-
|
|
16
|
-
SitesCommand.description = `Handle various site operations
|
|
17
|
-
The sites command will help you manage all your sites
|
|
18
|
-
`
|
|
19
|
-
|
|
20
|
-
SitesCommand.examples = ['netlify sites:create --name my-new-site', 'netlify sites:list']
|
|
21
|
-
|
|
22
|
-
module.exports = SitesCommand
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
3
|
+
const slugify = require('@sindresorhus/slugify')
|
|
4
|
+
const inquirer = require('inquirer')
|
|
5
|
+
const pick = require('lodash/pick')
|
|
6
|
+
const sample = require('lodash/sample')
|
|
7
|
+
const prettyjson = require('prettyjson')
|
|
8
|
+
const { v4: uuidv4 } = require('uuid')
|
|
9
|
+
|
|
10
|
+
const { chalk, error, getRepoData, log, logJson, track, warn } = require('../../utils')
|
|
11
|
+
const { configureRepo } = require('../../utils/init/config')
|
|
12
|
+
|
|
13
|
+
const SITE_NAME_SUGGESTION_SUFFIX_LENGTH = 5
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* The sites:create command
|
|
17
|
+
* @param {import('commander').OptionValues} options
|
|
18
|
+
* @param {import('../base-command').BaseCommand} command
|
|
19
|
+
*/
|
|
20
|
+
const sitesCreate = async (options, command) => {
|
|
21
|
+
const { api } = command.netlify
|
|
22
|
+
|
|
23
|
+
await command.authenticate()
|
|
24
|
+
|
|
25
|
+
const accounts = await api.listAccountsForUser()
|
|
26
|
+
|
|
27
|
+
let { accountSlug } = options
|
|
28
|
+
if (!accountSlug) {
|
|
29
|
+
const { accountSlug: accountSlugInput } = await inquirer.prompt([
|
|
30
|
+
{
|
|
31
|
+
type: 'list',
|
|
32
|
+
name: 'accountSlug',
|
|
33
|
+
message: 'Team:',
|
|
34
|
+
choices: accounts.map((account) => ({
|
|
35
|
+
value: account.slug,
|
|
36
|
+
name: account.name,
|
|
37
|
+
})),
|
|
38
|
+
},
|
|
39
|
+
])
|
|
40
|
+
accountSlug = accountSlugInput
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const { name: nameFlag } = options
|
|
44
|
+
let user
|
|
45
|
+
let site
|
|
46
|
+
|
|
47
|
+
// Allow the user to reenter site name if selected one isn't available
|
|
48
|
+
const inputSiteName = async (name) => {
|
|
49
|
+
if (!user) user = await api.getCurrentUser()
|
|
50
|
+
|
|
51
|
+
if (!name) {
|
|
52
|
+
let { slug } = user
|
|
53
|
+
let suffix = ''
|
|
54
|
+
|
|
55
|
+
// If the user doesn't have a slug, we'll compute one. Because `full_name` is not guaranteed to be unique, we
|
|
56
|
+
// append a short randomly-generated ID to reduce the likelihood of a conflict.
|
|
57
|
+
if (!slug) {
|
|
58
|
+
slug = slugify(user.full_name || user.email)
|
|
59
|
+
suffix = `-${uuidv4().slice(0, SITE_NAME_SUGGESTION_SUFFIX_LENGTH)}`
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const suggestions = [
|
|
63
|
+
`super-cool-site-by-${slug}${suffix}`,
|
|
64
|
+
`the-awesome-${slug}-site${suffix}`,
|
|
65
|
+
`${slug}-makes-great-sites${suffix}`,
|
|
66
|
+
`netlify-thinks-${slug}-is-great${suffix}`,
|
|
67
|
+
`the-great-${slug}-site${suffix}`,
|
|
68
|
+
`isnt-${slug}-awesome${suffix}`,
|
|
69
|
+
]
|
|
70
|
+
const siteSuggestion = sample(suggestions)
|
|
71
|
+
|
|
72
|
+
console.log(
|
|
73
|
+
`Choose a unique site name (e.g. ${siteSuggestion}.netlify.app) or leave it blank for a random name. You can update the site name later.`,
|
|
74
|
+
)
|
|
75
|
+
const { name: nameInput } = await inquirer.prompt([
|
|
76
|
+
{
|
|
77
|
+
type: 'input',
|
|
78
|
+
name: 'name',
|
|
79
|
+
message: 'Site name (optional):',
|
|
80
|
+
filter: (val) => (val === '' ? undefined : val),
|
|
81
|
+
validate: (input) => /^[a-zA-Z\d-]+$/.test(input) || 'Only alphanumeric characters and hyphens are allowed',
|
|
82
|
+
},
|
|
83
|
+
])
|
|
84
|
+
name = nameInput
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const body = {}
|
|
88
|
+
if (typeof name === 'string') {
|
|
89
|
+
body.name = name.trim()
|
|
90
|
+
}
|
|
91
|
+
try {
|
|
92
|
+
site = await api.createSiteInTeam({
|
|
93
|
+
accountSlug,
|
|
94
|
+
body,
|
|
95
|
+
})
|
|
96
|
+
} catch (error_) {
|
|
97
|
+
if (error_.status === 422) {
|
|
98
|
+
warn(`${name}.netlify.app already exists. Please try a different slug.`)
|
|
99
|
+
await inputSiteName()
|
|
100
|
+
} else {
|
|
101
|
+
error(`createSiteInTeam error: ${error_.status}: ${error_.message}`)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
await inputSiteName(nameFlag)
|
|
106
|
+
|
|
107
|
+
log()
|
|
108
|
+
log(chalk.greenBright.bold.underline(`Site Created`))
|
|
109
|
+
log()
|
|
110
|
+
|
|
111
|
+
const siteUrl = site.ssl_url || site.url
|
|
112
|
+
log(
|
|
113
|
+
prettyjson.render({
|
|
114
|
+
'Admin URL': site.admin_url,
|
|
115
|
+
URL: siteUrl,
|
|
116
|
+
'Site ID': site.id,
|
|
117
|
+
}),
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
track('sites_created', {
|
|
121
|
+
siteId: site.id,
|
|
122
|
+
adminUrl: site.admin_url,
|
|
123
|
+
siteUrl,
|
|
124
|
+
})
|
|
125
|
+
|
|
126
|
+
if (options.withCi) {
|
|
127
|
+
log('Configuring CI')
|
|
128
|
+
const repoData = await getRepoData()
|
|
129
|
+
await configureRepo({ context: this, siteId: site.id, repoData, manual: options.manual })
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (options.json) {
|
|
133
|
+
logJson(
|
|
134
|
+
pick(site, [
|
|
135
|
+
'id',
|
|
136
|
+
'state',
|
|
137
|
+
'plan',
|
|
138
|
+
'name',
|
|
139
|
+
'custom_domain',
|
|
140
|
+
'domain_aliases',
|
|
141
|
+
'url',
|
|
142
|
+
'ssl_url',
|
|
143
|
+
'admin_url',
|
|
144
|
+
'screenshot_url',
|
|
145
|
+
'created_at',
|
|
146
|
+
'updated_at',
|
|
147
|
+
'user_id',
|
|
148
|
+
'ssl',
|
|
149
|
+
'force_ssl',
|
|
150
|
+
'managed_dns',
|
|
151
|
+
'deploy_url',
|
|
152
|
+
'account_name',
|
|
153
|
+
'account_slug',
|
|
154
|
+
'git_provider',
|
|
155
|
+
'deploy_hook',
|
|
156
|
+
'capabilities',
|
|
157
|
+
'id_domain',
|
|
158
|
+
]),
|
|
159
|
+
)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return site
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Creates the `netlify sites:create` command
|
|
167
|
+
* @param {import('../base-command').BaseCommand} program
|
|
168
|
+
* @returns
|
|
169
|
+
*/
|
|
170
|
+
const createSitesCreateCommand = (program) =>
|
|
171
|
+
program
|
|
172
|
+
.command('sites:create')
|
|
173
|
+
.description('Create an empty site (advanced)')
|
|
174
|
+
.option('-n, --name [name]', 'name of site')
|
|
175
|
+
.option('-a, --account-slug [slug]', 'account slug to create the site under')
|
|
176
|
+
.option('-c, --with-ci', 'initialize CI hooks during site creation')
|
|
177
|
+
.option('-m, --manual', 'force manual CI setup. Used --with-ci flag')
|
|
178
|
+
.addHelpText(
|
|
179
|
+
'after',
|
|
180
|
+
`Create a blank site that isn't associated with any git remote. Does not link to the current working directory.`,
|
|
181
|
+
)
|
|
182
|
+
.action(sitesCreate)
|
|
183
|
+
|
|
184
|
+
module.exports = { createSitesCreateCommand, sitesCreate }
|