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.
Files changed (183) hide show
  1. package/bin/run +81 -3
  2. package/npm-shrinkwrap.json +305 -2105
  3. package/package.json +10 -33
  4. package/src/commands/addons/addons-auth.js +50 -0
  5. package/src/commands/addons/addons-config.js +180 -0
  6. package/src/commands/addons/addons-create.js +129 -0
  7. package/src/commands/addons/addons-delete.js +59 -0
  8. package/src/commands/addons/addons-list.js +62 -0
  9. package/src/commands/addons/addons.js +49 -0
  10. package/src/commands/addons/index.js +3 -24
  11. package/src/commands/api/api.js +83 -0
  12. package/src/commands/api/index.js +5 -0
  13. package/src/commands/base-command.js +322 -0
  14. package/src/commands/build/build.js +58 -0
  15. package/src/commands/build/index.js +3 -61
  16. package/src/commands/completion/completion.js +18 -0
  17. package/src/commands/completion/index.js +5 -0
  18. package/src/commands/{deploy.js → deploy/deploy.js} +306 -278
  19. package/src/commands/deploy/index.js +5 -0
  20. package/src/commands/dev/dev-exec.js +39 -0
  21. package/src/commands/dev/dev-trace.js +50 -0
  22. package/src/commands/dev/dev.js +349 -0
  23. package/src/commands/dev/index.js +3 -335
  24. package/src/commands/env/env-get.js +51 -0
  25. package/src/commands/env/env-import.js +93 -0
  26. package/src/commands/env/env-list.js +63 -0
  27. package/src/commands/env/env-set.js +67 -0
  28. package/src/commands/env/env-unset.js +66 -0
  29. package/src/commands/env/env.js +47 -0
  30. package/src/commands/env/index.js +3 -23
  31. package/src/commands/functions/functions-build.js +59 -0
  32. package/src/commands/functions/{create.js → functions-create.js} +133 -94
  33. package/src/commands/functions/functions-invoke.js +276 -0
  34. package/src/commands/functions/functions-list.js +107 -0
  35. package/src/commands/functions/functions-serve.js +63 -0
  36. package/src/commands/functions/functions.js +53 -0
  37. package/src/commands/functions/index.js +3 -45
  38. package/src/commands/index.js +5 -0
  39. package/src/commands/init/index.js +6 -0
  40. package/src/commands/{init.js → init/init.js} +79 -68
  41. package/src/commands/link/index.js +6 -0
  42. package/src/{utils/link/link-by-prompt.js → commands/link/link.js} +153 -14
  43. package/src/commands/lm/index.js +3 -19
  44. package/src/commands/lm/lm-info.js +42 -0
  45. package/src/commands/lm/lm-install.js +36 -0
  46. package/src/commands/lm/lm-setup.js +106 -0
  47. package/src/commands/lm/lm-uninstall.js +25 -0
  48. package/src/commands/lm/lm.js +39 -0
  49. package/src/commands/login/index.js +6 -0
  50. package/src/commands/login/login.js +52 -0
  51. package/src/commands/logout/index.js +5 -0
  52. package/src/commands/logout/logout.js +43 -0
  53. package/src/commands/main.js +117 -0
  54. package/src/commands/open/index.js +3 -39
  55. package/src/commands/open/open-admin.js +56 -0
  56. package/src/commands/open/open-site.js +49 -0
  57. package/src/commands/open/open.js +42 -0
  58. package/src/commands/sites/index.js +5 -20
  59. package/src/commands/sites/sites-create.js +184 -0
  60. package/src/commands/sites/sites-delete.js +108 -0
  61. package/src/commands/sites/sites-list.js +89 -0
  62. package/src/commands/sites/sites.js +36 -0
  63. package/src/commands/status/index.js +3 -118
  64. package/src/commands/status/status-hooks.js +73 -0
  65. package/src/commands/status/status.js +125 -0
  66. package/src/commands/switch/index.js +5 -0
  67. package/src/commands/switch/switch.js +50 -0
  68. package/src/commands/unlink/index.js +5 -0
  69. package/src/commands/unlink/unlink.js +48 -0
  70. package/src/commands/watch/index.js +5 -0
  71. package/src/commands/watch/watch.js +121 -0
  72. package/src/lib/build.js +21 -7
  73. package/src/lib/exec-fetcher.js +5 -3
  74. package/src/lib/fs.js +54 -36
  75. package/src/lib/functions/background.js +1 -1
  76. package/src/lib/functions/form-submissions-handler.js +2 -1
  77. package/src/lib/functions/local-proxy.js +2 -1
  78. package/src/lib/functions/netlify-function.js +4 -1
  79. package/src/lib/functions/registry.js +4 -6
  80. package/src/lib/functions/runtimes/go/index.js +2 -1
  81. package/src/lib/functions/runtimes/js/builders/netlify-lambda.js +6 -4
  82. package/src/lib/functions/runtimes/js/builders/zisi.js +3 -3
  83. package/src/lib/functions/runtimes/rust/index.js +4 -3
  84. package/src/lib/functions/server.js +2 -3
  85. package/src/lib/functions/synchronous.js +2 -1
  86. package/src/lib/functions/utils.js +2 -3
  87. package/src/lib/functions/watcher.js +1 -0
  88. package/src/lib/http-agent.js +3 -5
  89. package/src/lib/log.js +2 -1
  90. package/src/lib/spinner.js +22 -0
  91. package/src/utils/addons/diffs/index.js +1 -0
  92. package/src/utils/addons/diffs/options.js +3 -1
  93. package/src/utils/addons/prepare.js +13 -6
  94. package/src/utils/addons/prompts.js +2 -1
  95. package/src/utils/addons/render.js +3 -1
  96. package/src/utils/command-helpers.js +156 -43
  97. package/src/utils/create-stream-promise.js +5 -5
  98. package/src/utils/deferred.js +1 -0
  99. package/src/utils/deploy/deploy-site.js +1 -1
  100. package/src/utils/deploy/index.js +4 -0
  101. package/src/utils/detect-server-settings.js +10 -12
  102. package/src/utils/dev.js +18 -10
  103. package/src/utils/dot-env.js +4 -2
  104. package/src/utils/{edge-handlers.js → functions/edge-handlers.js} +8 -7
  105. package/src/utils/functions/functions.js +36 -0
  106. package/src/utils/{get-functions.js → functions/get-functions.js} +2 -1
  107. package/src/utils/functions/index.js +8 -26
  108. package/src/utils/get-global-config.js +3 -2
  109. package/src/utils/get-repo-data.js +1 -0
  110. package/src/utils/gh-auth.js +1 -0
  111. package/src/utils/gitignore.js +7 -5
  112. package/src/utils/header.js +2 -2
  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 +1 -0
  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 +2 -2
  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 -262
  179. package/src/utils/detect-functions-builder.js +0 -25
  180. package/src/utils/difference.js +0 -4
  181. package/src/utils/logo.js +0 -11
  182. package/src/utils/show-help.js +0 -5
  183. package/src/utils/telemetry/tracked-command.js +0 -51
@@ -0,0 +1,108 @@
1
+ // @ts-check
2
+ const inquirer = require('inquirer')
3
+
4
+ const { chalk, error, exit, generateDescriptionHelp, generateExamplesHelp, log } = require('../../utils')
5
+
6
+ /**
7
+ * The sites:delete command
8
+ * @param {string} siteId
9
+ * @param {import('commander').OptionValues} options
10
+ * @param {import('../base-command').BaseCommand} command
11
+ */
12
+ const sitesDelete = async (siteId, options, command) => {
13
+ command.setAnalyticsPayload({ force: options.force })
14
+
15
+ const { api, site } = command.netlify
16
+ const cwdSiteId = site.id
17
+
18
+ // 1. Prompt user for verification
19
+ await command.authenticate(options.auth)
20
+
21
+ let siteData
22
+ try {
23
+ siteData = await api.getSite({ siteId })
24
+ } catch (error_) {
25
+ if (error_.status === 404) {
26
+ error(`No site with id ${siteId} found. Please verify the siteId & try again.`)
27
+ }
28
+ }
29
+
30
+ if (!siteData) {
31
+ error(`Unable to process site`)
32
+ }
33
+
34
+ const noForce = options.force !== true
35
+
36
+ /* Verify the user wants to delete the site */
37
+ if (noForce) {
38
+ log(`${chalk.redBright('Warning')}: You are about to permanently delete "${chalk.bold(siteData.name)}"`)
39
+ log(` Verify this siteID "${siteId}" supplied is correct and proceed.`)
40
+ log(' To skip this prompt, pass a --force flag to the delete command')
41
+ log()
42
+ log(`${chalk.bold('Be careful here. There is no undo!')}`)
43
+ log()
44
+ const { wantsToDelete } = await inquirer.prompt({
45
+ type: 'confirm',
46
+ name: 'wantsToDelete',
47
+ message: `WARNING: Are you sure you want to delete the "${siteData.name}" site?`,
48
+ default: false,
49
+ })
50
+ log()
51
+ if (!wantsToDelete) {
52
+ exit()
53
+ }
54
+ }
55
+
56
+ /* Validation logic if siteId passed in does not match current site ID */
57
+ if (noForce && cwdSiteId && cwdSiteId !== siteId) {
58
+ log(`${chalk.redBright('Warning')}: The siteId supplied does not match the current working directory siteId`)
59
+ log()
60
+ log(`Supplied: "${siteId}"`)
61
+ log(`Current Site: "${cwdSiteId}"`)
62
+ log()
63
+ log(`Verify this siteID "${siteId}" supplied is correct and proceed.`)
64
+ log('To skip this prompt, pass a --force flag to the delete command')
65
+ const { wantsToDelete } = await inquirer.prompt({
66
+ type: 'confirm',
67
+ name: 'wantsToDelete',
68
+ message: `Verify & Proceed with deletion of site "${siteId}"?`,
69
+ default: false,
70
+ })
71
+ if (!wantsToDelete) {
72
+ exit()
73
+ }
74
+ }
75
+
76
+ log(`Deleting site "${siteId}"...`)
77
+
78
+ try {
79
+ await api.deleteSite({ site_id: siteId })
80
+ } catch (error_) {
81
+ if (error_.status === 404) {
82
+ error(`No site with id ${siteId} found. Please verify the siteId & try again.`)
83
+ } else {
84
+ error(`Delete Site error: ${error_.status}: ${error_.message}`)
85
+ }
86
+ }
87
+ log(`Site "${siteId}" successfully deleted!`)
88
+ }
89
+
90
+ /**
91
+ * Creates the `netlify sites:delete` command
92
+ * @param {import('../base-command').BaseCommand} program
93
+ * @returns
94
+ */
95
+ const createSitesDeleteCommand = (program) =>
96
+ program
97
+ .command('sites:delete')
98
+ .description('Delete a site')
99
+ .argument('<siteId>', 'Site ID to delete.')
100
+ .option('-f, --force', 'delete without prompting (useful for CI)')
101
+ .addHelpText(
102
+ 'after',
103
+ generateDescriptionHelp('This command will permanently delete the site on Netlify. Use with caution.'),
104
+ )
105
+ .addHelpText('after', generateExamplesHelp(['netlify sites:delete 1234-3262-1211']))
106
+ .action(sitesDelete)
107
+
108
+ module.exports = { createSitesDeleteCommand }
@@ -0,0 +1,89 @@
1
+ // @ts-check
2
+
3
+ const { cli } = require('cli-ux')
4
+
5
+ const { listSites } = require('../../lib/api')
6
+ const { chalk, log, logJson } = require('../../utils')
7
+
8
+ /**
9
+ * The sites:list command
10
+ * @param {import('commander').OptionValues} options
11
+ * @param {import('../base-command').BaseCommand} command
12
+ * @returns {Promise<{ id: any; name: any; ssl_url: any; account_name: any; }|boolean>}
13
+ */
14
+ const sitesList = async (options, command) => {
15
+ const { api } = command.netlify
16
+ if (!options.json) {
17
+ cli.action.start('Loading your sites')
18
+ }
19
+ await command.authenticate()
20
+
21
+ const sites = await listSites({ api, options: { filter: 'all' } })
22
+ if (!options.json) {
23
+ cli.action.stop()
24
+ }
25
+
26
+ if (sites && sites.length !== 0) {
27
+ const logSites = sites.map((site) => {
28
+ const siteInfo = {
29
+ id: site.id,
30
+ name: site.name,
31
+ ssl_url: site.ssl_url,
32
+ account_name: site.account_name,
33
+ }
34
+
35
+ if (site.build_settings && site.build_settings.repo_url) {
36
+ siteInfo.repo_url = site.build_settings.repo_url
37
+ }
38
+
39
+ return siteInfo
40
+ })
41
+
42
+ // Json response for piping commands
43
+ if (options.json) {
44
+ const redactedSites = sites.map((site) => {
45
+ if (site && site.build_settings) {
46
+ delete site.build_settings.env
47
+ }
48
+ return site
49
+ })
50
+ logJson(redactedSites)
51
+ return false
52
+ }
53
+
54
+ log(`
55
+ ────────────────────────────┐
56
+ Current Netlify Sites │
57
+ ────────────────────────────┘
58
+
59
+ Count: ${logSites.length}
60
+ `)
61
+
62
+ logSites.forEach((logSite) => {
63
+ log(`${chalk.greenBright(logSite.name)} - ${logSite.id}`)
64
+ log(` ${chalk.whiteBright.bold('url:')} ${chalk.yellowBright(logSite.ssl_url)}`)
65
+ if (logSite.repo_url) {
66
+ log(` ${chalk.whiteBright.bold('repo:')} ${chalk.white(logSite.repo_url)}`)
67
+ }
68
+ if (logSite.account_name) {
69
+ log(` ${chalk.whiteBright.bold('account:')} ${chalk.white(logSite.account_name)}`)
70
+ }
71
+ log(`─────────────────────────────────────────────────`)
72
+ })
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Creates the `netlify sites:list` command
78
+ * @param {import('../base-command').BaseCommand} program
79
+ */
80
+ const createSitesListCommand = (program) =>
81
+ program
82
+ .command('sites:list')
83
+ .description('List all sites you have access to')
84
+ .option('--json', 'Output site data as JSON')
85
+ .action(async (options, command) => {
86
+ await sitesList(options, command)
87
+ })
88
+
89
+ module.exports = { createSitesListCommand }
@@ -0,0 +1,36 @@
1
+ // @ts-check
2
+ const { generateCommandsHelp, generateDescriptionHelp, generateExamplesHelp } = require('../../utils')
3
+
4
+ const { createSitesCreateCommand } = require('./sites-create')
5
+ const { createSitesDeleteCommand } = require('./sites-delete')
6
+ const { createSitesListCommand } = require('./sites-list')
7
+
8
+ /**
9
+ * The sites command
10
+ * @param {import('commander').OptionValues} options
11
+ * @param {import('../base-command').BaseCommand} command
12
+ */
13
+ const sites = (options, command) => {
14
+ command.help()
15
+ }
16
+
17
+ /**
18
+ * Creates the `netlify sites` command
19
+ * @param {import('../base-command').BaseCommand} program
20
+ * @returns
21
+ */
22
+ const createSitesCommand = (program) => {
23
+ createSitesCreateCommand(program)
24
+ createSitesListCommand(program)
25
+ createSitesDeleteCommand(program)
26
+
27
+ return program
28
+ .command('sites')
29
+ .description('Handle various site operations')
30
+ .addHelpText('after', generateDescriptionHelp('The sites command will help you manage all your sites'))
31
+ .addHelpText('after', generateExamplesHelp(['netlify sites:create --name my-new-site', 'netlify sites:list']))
32
+ .addHelpText('after', generateCommandsHelp('sites', program))
33
+ .action(sites)
34
+ }
35
+
36
+ module.exports = { createSitesCommand }
@@ -1,120 +1,5 @@
1
- const { flags: flagsLib } = require('@oclif/command')
2
- const chalk = require('chalk')
3
- const clean = require('clean-deep')
4
- const prettyjson = require('prettyjson')
1
+ const { createStatusCommand } = require('./status')
5
2
 
6
- const Command = require('../../utils/command')
7
- const { error, exit, getToken, log, logJson, warn } = require('../../utils/command-helpers')
8
-
9
- class StatusCommand extends Command {
10
- async run() {
11
- const { api, globalConfig, site } = this.netlify
12
- const { flags } = this.parse(StatusCommand)
13
-
14
- const current = globalConfig.get('userId')
15
- const [accessToken] = await getToken()
16
-
17
- if (!accessToken) {
18
- log(`Not logged in. Please log in to see site status.`)
19
- log()
20
- log('Login with "netlify login" command')
21
- exit()
22
- }
23
-
24
- const siteId = site.id
25
-
26
- log(`──────────────────────┐
27
- Current Netlify User │
28
- ──────────────────────┘`)
29
-
30
- let accounts
31
- let user
32
-
33
- try {
34
- ;[accounts, user] = await Promise.all([api.listAccountsForUser(), api.getCurrentUser()])
35
- } catch (error_) {
36
- if (error_.status === 401) {
37
- error(
38
- 'Your session has expired. Please try to re-authenticate by running `netlify logout` and `netlify login`.',
39
- )
40
- }
41
- }
42
-
43
- const ghuser = this.netlify.globalConfig.get(`users.${current}.auth.github.user`)
44
- const accountData = {
45
- Name: user.full_name,
46
- Email: user.email,
47
- GitHub: ghuser,
48
- }
49
- const teamsData = {}
50
-
51
- accounts.forEach((team) => {
52
- teamsData[team.name] = team.roles_allowed.join(' ')
53
- })
54
-
55
- accountData.Teams = teamsData
56
-
57
- const cleanAccountData = clean(accountData)
58
-
59
- log(prettyjson.render(cleanAccountData))
60
-
61
- if (!siteId) {
62
- warn('Did you run `netlify link` yet?')
63
- error(`You don't appear to be in a folder that is linked to a site`)
64
- }
65
- let siteData
66
- try {
67
- siteData = await api.getSite({ siteId })
68
- } catch (error_) {
69
- // unauthorized
70
- if (error_.status === 401) {
71
- warn(`Log in with a different account or re-link to a site you have permission for`)
72
- error(`Not authorized to view the currently linked site (${siteId})`)
73
- }
74
- // missing
75
- if (error_.status === 404) {
76
- error(`The site this folder is linked to can't be found`)
77
- }
78
- error(error_)
79
- }
80
-
81
- // Json only logs out if --json flag is passed
82
- if (flags.json) {
83
- logJson({
84
- account: cleanAccountData,
85
- siteData: {
86
- 'site-name': `${siteData.name}`,
87
- 'config-path': site.configPath,
88
- 'admin-url': siteData.admin_url,
89
- 'site-url': siteData.ssl_url || siteData.url,
90
- 'site-id': siteData.id,
91
- },
92
- })
93
- }
94
-
95
- log(`────────────────────┐
96
- Netlify Site Info │
97
- ────────────────────┘`)
98
- log(
99
- prettyjson.render({
100
- 'Current site': `${siteData.name}`,
101
- 'Netlify TOML': site.configPath,
102
- 'Admin URL': chalk.magentaBright(siteData.admin_url),
103
- 'Site URL': chalk.cyanBright(siteData.ssl_url || siteData.url),
104
- 'Site Id': chalk.yellowBright(siteData.id),
105
- }),
106
- )
107
- log()
108
- }
3
+ module.exports = {
4
+ createStatusCommand,
109
5
  }
110
-
111
- StatusCommand.description = `Print status information`
112
-
113
- StatusCommand.flags = {
114
- verbose: flagsLib.boolean({
115
- description: 'Output system info',
116
- }),
117
- ...StatusCommand.flags,
118
- }
119
-
120
- module.exports = StatusCommand
@@ -0,0 +1,73 @@
1
+ // @ts-check
2
+ const { get } = require('dot-prop')
3
+ const prettyjson = require('prettyjson')
4
+
5
+ const { error, log, warn } = require('../../utils')
6
+
7
+ /**
8
+ * The status:hooks command
9
+ * @param {import('commander').OptionValues} options
10
+ * @param {import('../base-command').BaseCommand} command
11
+ */
12
+ const statusHooks = async (options, command) => {
13
+ const { api, site } = command.netlify
14
+
15
+ await command.authenticate()
16
+
17
+ const siteId = site.id
18
+ if (!siteId) {
19
+ warn('Did you run `netlify link` yet?')
20
+ error(`You don't appear to be in a folder that is linked to a site`)
21
+ }
22
+
23
+ let siteData
24
+ try {
25
+ siteData = await api.getSite({ siteId })
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
+ // missing
33
+ if (error_.status === 404) {
34
+ error(`The site this folder is linked to can't be found`)
35
+ }
36
+ error(error_)
37
+ }
38
+
39
+ const ntlHooks = await api.listHooksBySiteId({ siteId: siteData.id })
40
+ const data = {
41
+ site: siteData.name,
42
+ hooks: {},
43
+ }
44
+ ntlHooks.forEach((hook) => {
45
+ data.hooks[hook.id] = {
46
+ type: hook.type,
47
+ event: hook.event,
48
+ id: hook.id,
49
+ disabled: hook.disabled,
50
+ }
51
+ if (get(siteData, 'build_settings.repo_url')) {
52
+ data.hooks[hook.id].repo_url = get(siteData, 'build_settings.repo_url')
53
+ }
54
+ })
55
+ log(`─────────────────┐
56
+ Site Hook Status │
57
+ ─────────────────┘`)
58
+ log(prettyjson.render(data))
59
+ }
60
+
61
+ /**
62
+ * Creates the `netlify status:hooks` command
63
+ * @param {import('../base-command').BaseCommand} program
64
+ * @returns
65
+ */
66
+ const createStatusHooksCommand = (program) =>
67
+ program
68
+ .command('status:hooks')
69
+ .description('Print hook information of the linked site')
70
+ .option('--verbose', 'Output system info', false)
71
+ .action(statusHooks)
72
+
73
+ module.exports = { createStatusHooksCommand }
@@ -0,0 +1,125 @@
1
+ // @ts-check
2
+ const clean = require('clean-deep')
3
+ const prettyjson = require('prettyjson')
4
+
5
+ const { chalk, error, exit, generateCommandsHelp, getToken, log, logJson, warn } = require('../../utils')
6
+
7
+ const { createStatusHooksCommand } = require('./status-hooks')
8
+
9
+ /**
10
+ * The status command
11
+ * @param {import('commander').OptionValues} options
12
+ * @param {import('../base-command').BaseCommand} command
13
+ */
14
+ const status = async (options, command) => {
15
+ const { api, globalConfig, site } = command.netlify
16
+ const current = globalConfig.get('userId')
17
+ const [accessToken] = await getToken()
18
+
19
+ if (!accessToken) {
20
+ log(`Not logged in. Please log in to see site status.`)
21
+ log()
22
+ log('Login with "netlify login" command')
23
+ exit()
24
+ }
25
+
26
+ const siteId = site.id
27
+
28
+ log(`──────────────────────┐
29
+ Current Netlify User │
30
+ ──────────────────────┘`)
31
+
32
+ let accounts
33
+ let user
34
+
35
+ try {
36
+ ;[accounts, user] = await Promise.all([api.listAccountsForUser(), api.getCurrentUser()])
37
+ } catch (error_) {
38
+ if (error_.status === 401) {
39
+ error('Your session has expired. Please try to re-authenticate by running `netlify logout` and `netlify login`.')
40
+ }
41
+ }
42
+
43
+ const ghuser = command.netlify.globalConfig.get(`users.${current}.auth.github.user`)
44
+ const accountData = {
45
+ Name: user.full_name,
46
+ Email: user.email,
47
+ GitHub: ghuser,
48
+ }
49
+ const teamsData = {}
50
+
51
+ accounts.forEach((team) => {
52
+ teamsData[team.name] = team.roles_allowed.join(' ')
53
+ })
54
+
55
+ accountData.Teams = teamsData
56
+
57
+ const cleanAccountData = clean(accountData)
58
+
59
+ log(prettyjson.render(cleanAccountData))
60
+
61
+ if (!siteId) {
62
+ warn('Did you run `netlify link` yet?')
63
+ error(`You don't appear to be in a folder that is linked to a site`)
64
+ }
65
+ let siteData
66
+ try {
67
+ siteData = await api.getSite({ siteId })
68
+ } catch (error_) {
69
+ // unauthorized
70
+ if (error_.status === 401) {
71
+ warn(`Log in with a different account or re-link to a site you have permission for`)
72
+ error(`Not authorized to view the currently linked site (${siteId})`)
73
+ }
74
+ // missing
75
+ if (error_.status === 404) {
76
+ error(`The site this folder is linked to can't be found`)
77
+ }
78
+ error(error_)
79
+ }
80
+
81
+ // Json only logs out if --json flag is passed
82
+ if (options.json) {
83
+ logJson({
84
+ account: cleanAccountData,
85
+ siteData: {
86
+ 'site-name': `${siteData.name}`,
87
+ 'config-path': site.configPath,
88
+ 'admin-url': siteData.admin_url,
89
+ 'site-url': siteData.ssl_url || siteData.url,
90
+ 'site-id': siteData.id,
91
+ },
92
+ })
93
+ }
94
+
95
+ log(`────────────────────┐
96
+ Netlify Site Info │
97
+ ────────────────────┘`)
98
+ log(
99
+ prettyjson.render({
100
+ 'Current site': `${siteData.name}`,
101
+ 'Netlify TOML': site.configPath,
102
+ 'Admin URL': chalk.magentaBright(siteData.admin_url),
103
+ 'Site URL': chalk.cyanBright(siteData.ssl_url || siteData.url),
104
+ 'Site Id': chalk.yellowBright(siteData.id),
105
+ }),
106
+ )
107
+ log()
108
+ }
109
+
110
+ /**
111
+ * Creates the `netlify status` command
112
+ * @param {import('../base-command').BaseCommand} program
113
+ * @returns
114
+ */
115
+ const createStatusCommand = (program) => {
116
+ createStatusHooksCommand(program)
117
+
118
+ return program
119
+ .command('status')
120
+ .description('Print status information')
121
+ .option('--verbose', 'Output system info')
122
+ .addHelpText('after', generateCommandsHelp('status', program))
123
+ .action(status)
124
+ }
125
+ module.exports = { createStatusCommand }
@@ -0,0 +1,5 @@
1
+ const { createSwitchCommand } = require('./switch')
2
+
3
+ module.exports = {
4
+ createSwitchCommand,
5
+ }
@@ -0,0 +1,50 @@
1
+ // @ts-check
2
+ const inquirer = require('inquirer')
3
+
4
+ const { chalk, log } = require('../../utils')
5
+ const { login } = require('../login')
6
+
7
+ const LOGIN_NEW = 'I would like to login to a new account'
8
+
9
+ /**
10
+ * The switch command
11
+ * @param {import('commander').OptionValues} options
12
+ * @param {import('../base-command').BaseCommand} command
13
+ */
14
+ const switchCommand = async (options, command) => {
15
+ const availableUsersChoices = Object.values(command.netlify.globalConfig.get('users')).reduce(
16
+ (prev, current) =>
17
+ Object.assign(prev, { [current.id]: current.name ? `${current.name} (${current.email})` : current.email }),
18
+ {},
19
+ )
20
+
21
+ const { accountSwitchChoice } = await inquirer.prompt([
22
+ {
23
+ type: 'list',
24
+ name: 'accountSwitchChoice',
25
+ message: 'Please select the account you want to use:',
26
+ choices: [...Object.entries(availableUsersChoices).map(([, val]) => val), LOGIN_NEW],
27
+ },
28
+ ])
29
+
30
+ if (accountSwitchChoice === LOGIN_NEW) {
31
+ await login({ new: true }, command)
32
+ } else {
33
+ const selectedAccount = Object.entries(availableUsersChoices).find(
34
+ ([, availableUsersChoice]) => availableUsersChoice === accountSwitchChoice,
35
+ )
36
+ command.netlify.globalConfig.set('userId', selectedAccount[0])
37
+ log('')
38
+ log(`You're now using ${chalk.bold(selectedAccount[1])}.`)
39
+ }
40
+ }
41
+
42
+ /**
43
+ * Creates the `netlify switch` command
44
+ * @param {import('../base-command').BaseCommand} program
45
+ * @returns
46
+ */
47
+ const createSwitchCommand = (program) =>
48
+ program.command('switch').description('Switch your active Netlify account').action(switchCommand)
49
+
50
+ module.exports = { createSwitchCommand }
@@ -0,0 +1,5 @@
1
+ const { createUnlinkCommand } = require('./unlink')
2
+
3
+ module.exports = {
4
+ createUnlinkCommand,
5
+ }
@@ -0,0 +1,48 @@
1
+ // @ts-check
2
+
3
+ const { exit, log, track } = require('../../utils')
4
+
5
+ /**
6
+ * The unlink command
7
+ * @param {import('commander').OptionValues} options
8
+ * @param {import('../base-command').BaseCommand} command
9
+ */
10
+ const unlink = async (options, command) => {
11
+ const { site, state } = command.netlify
12
+ const siteId = site.id
13
+
14
+ if (!siteId) {
15
+ log(`Folder is not linked to a Netlify site. Run 'netlify link' to link it`)
16
+ return exit()
17
+ }
18
+
19
+ let siteData = {}
20
+ try {
21
+ // @ts-ignore types from API are wrong they cannot recognize `getSite` of API
22
+ siteData = await command.netlify.api.getSite({ siteId })
23
+ } catch (error) {
24
+ // ignore errors if we can't get the site
25
+ }
26
+
27
+ state.delete('siteId')
28
+
29
+ await track('sites_unlinked', {
30
+ siteId: siteData.id || siteId,
31
+ })
32
+
33
+ if (site) {
34
+ log(`Unlinked ${site.configPath} from ${siteData ? siteData.name : siteId}`)
35
+ } else {
36
+ log('Unlinked site')
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Creates the `netlify unlink` command
42
+ * @param {import('../base-command').BaseCommand} program
43
+ * @returns
44
+ */
45
+ const createUnlinkCommand = (program) =>
46
+ program.command('unlink').description('Unlink a local folder from a Netlify site').action(unlink)
47
+
48
+ module.exports = { createUnlinkCommand }
@@ -0,0 +1,5 @@
1
+ const { createWatchCommand } = require('./watch')
2
+
3
+ module.exports = {
4
+ createWatchCommand,
5
+ }