netlify-cli 15.1.1 → 15.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "netlify-cli",
3
3
  "description": "Netlify command line tool",
4
- "version": "15.1.1",
4
+ "version": "15.3.0",
5
5
  "author": "Netlify Inc.",
6
6
  "type": "module",
7
7
  "engines": {
@@ -43,15 +43,15 @@
43
43
  },
44
44
  "dependencies": {
45
45
  "@bugsnag/js": "7.20.2",
46
- "@fastify/static": "6.10.1",
47
- "@netlify/build": "29.11.5",
48
- "@netlify/build-info": "7.0.2",
46
+ "@fastify/static": "6.10.2",
47
+ "@netlify/build": "29.11.7",
48
+ "@netlify/build-info": "7.0.3",
49
49
  "@netlify/config": "20.4.3",
50
- "@netlify/edge-bundler": "8.14.2",
51
- "@netlify/framework-info": "9.8.7",
50
+ "@netlify/edge-bundler": "8.15.0",
51
+ "@netlify/framework-info": "9.8.8",
52
52
  "@netlify/local-functions-proxy": "1.1.1",
53
- "@netlify/zip-it-and-ship-it": "9.6.0",
54
- "@octokit/rest": "19.0.8",
53
+ "@netlify/zip-it-and-ship-it": "9.7.0",
54
+ "@octokit/rest": "19.0.11",
55
55
  "@skn0tt/lambda-local": "2.0.3",
56
56
  "ansi-escapes": "6.2.0",
57
57
  "ansi-styles": "6.2.1",
@@ -2,6 +2,9 @@
2
2
  import process from 'process'
3
3
  import { format } from 'util'
4
4
 
5
+ import { Project } from '@netlify/build-info'
6
+ // eslint-disable-next-line import/extensions, n/no-missing-import
7
+ import { NodeFS } from '@netlify/build-info/node'
5
8
  import { resolveConfig } from '@netlify/config'
6
9
  import { Command, Option } from 'commander'
7
10
  import debug from 'debug'
@@ -24,6 +27,7 @@ import {
24
27
  warn,
25
28
  } from '../utils/command-helpers.mjs'
26
29
  import getGlobalConfig from '../utils/get-global-config.mjs'
30
+ import { getSiteByName } from '../utils/get-site.mjs'
27
31
  import openBrowser from '../utils/open-browser.mjs'
28
32
  import StateConfig from '../utils/state-config.mjs'
29
33
  import { identify, track } from '../utils/telemetry/index.mjs'
@@ -440,11 +444,40 @@ export default class BaseCommand extends Command {
440
444
  certificateFile: options.httpProxyCertificateFilename,
441
445
  })
442
446
  const apiOpts = { ...apiUrlOpts, agent }
447
+ const api = new NetlifyAPI(token || '', apiOpts)
448
+
449
+ // If a user passes a site name as an option instead of a site ID to options.site, the siteInfo object
450
+ // will only have the property siteInfo.id. Checking for one of the other properties ensures that we can do
451
+ // a re-call of the api.getSite() that is done in @netlify/config so we have the proper site object in all
452
+ // commands.
453
+ // options.site as a site name (and not just site id) was introduced for the deploy command, so users could
454
+ // deploy by name along with by id
455
+ let siteData = siteInfo
456
+ if (!siteData.url && options.site) {
457
+ siteData = await getSiteByName(api, options.site)
458
+ }
459
+
443
460
  const globalConfig = await getGlobalConfig()
444
461
 
462
+ // Get framework, add to analytics payload for every command, if a framework is set
463
+ const fs = new NodeFS()
464
+ const project = new Project(fs, buildDir)
465
+ const frameworks = await project.detectFrameworks()
466
+
467
+ const frameworkIDs = frameworks?.map((framework) => framework.id)
468
+
469
+ if (frameworkIDs?.length !== 0) {
470
+ this.setAnalyticsPayload({ frameworks: frameworkIDs })
471
+ }
472
+
473
+ this.setAnalyticsPayload({
474
+ packageManager: project.packageManager?.name,
475
+ buildSystem: project.buildSystems.map(({ id }) => id),
476
+ })
477
+
445
478
  actionCommand.netlify = {
446
479
  // api methods
447
- api: new NetlifyAPI(token || '', apiOpts),
480
+ api,
448
481
  apiOpts,
449
482
  repositoryRoot,
450
483
  // current site context
@@ -458,8 +491,8 @@ export default class BaseCommand extends Command {
458
491
  state.set('siteId', id)
459
492
  },
460
493
  },
461
- // Site information retrieved using the API
462
- siteInfo,
494
+ // Site information retrieved using the API (api.getSite())
495
+ siteInfo: siteData,
463
496
  // Configuration from netlify.[toml/yml]
464
497
  config: normalizedConfig,
465
498
  // Used to avoid calling @netlify/config again
@@ -7,6 +7,7 @@ import { runCoreSteps } from '@netlify/build'
7
7
  import { restoreConfig, updateConfig } from '@netlify/config'
8
8
  import { Option } from 'commander'
9
9
  import inquirer from 'inquirer'
10
+ import isEmpty from 'lodash/isEmpty.js'
10
11
  import isObject from 'lodash/isObject.js'
11
12
  import prettyjson from 'prettyjson'
12
13
 
@@ -488,7 +489,7 @@ const printResults = ({ deployToProduction, json, results, runBuildCommand }) =>
488
489
  * @param {import('../base-command.mjs').default} command
489
490
  */
490
491
  const deploy = async (options, command) => {
491
- const { api, site } = command.netlify
492
+ const { api, site, siteInfo } = command.netlify
492
493
  const alias = options.alias || options.branch
493
494
 
494
495
  command.setAnalyticsPayload({ open: options.open, prod: options.prod, json: options.json, alias: Boolean(alias) })
@@ -503,35 +504,12 @@ const deploy = async (options, command) => {
503
504
 
504
505
  await command.authenticate(options.auth)
505
506
 
506
- let siteId = options.site || site.id
507
+ let siteId = site.id || options.site
507
508
 
508
509
  let siteData = {}
509
- if (siteId) {
510
- try {
511
- const [{ siteError, siteFoundById }, sites] = await Promise.all([
512
- api
513
- .getSite({ siteId })
514
- .then((data) => ({ siteFoundById: data }))
515
- .catch((error_) => ({ siteError: error_ })),
516
- api.listSites({ name: options.site, filter: 'all' }),
517
- ])
518
- const siteFoundByName = sites.find((filteredSite) => filteredSite.name === options.site)
519
- if (siteFoundById) {
520
- siteData = siteFoundById
521
- } else if (siteFoundByName) {
522
- siteData = siteFoundByName
523
- siteId = siteFoundByName.id
524
- } else {
525
- throw siteError
526
- }
527
- } catch (error_) {
528
- // TODO specifically handle known cases (e.g. no account access)
529
- if (error_.status === 404) {
530
- error('Site not found')
531
- } else {
532
- error(error_.message)
533
- }
534
- }
510
+ if (siteId && !isEmpty(siteInfo)) {
511
+ siteData = siteInfo
512
+ siteId = siteData.id
535
513
  } else {
536
514
  log("This folder isn't linked to a site yet")
537
515
  const NEW_SITE = '+ Create & configure a new site'
@@ -123,7 +123,7 @@ const dev = async (options, command) => {
123
123
  exit(1)
124
124
  }
125
125
 
126
- command.setAnalyticsPayload({ projectType: settings.framework || 'custom', live: options.live })
126
+ command.setAnalyticsPayload({ live: options.live })
127
127
 
128
128
  const liveTunnelUrl = await handleLiveTunnel({ options, site, api, settings })
129
129
  const url = liveTunnelUrl || getProxyUrl(settings)
@@ -1,8 +1,9 @@
1
1
  // @ts-check
2
2
  import AsciiTable from 'ascii-table'
3
3
 
4
- import { error, exit, log, logJson, warn } from '../../utils/command-helpers.mjs'
4
+ import { exit, log, logJson } from '../../utils/command-helpers.mjs'
5
5
  import { getFunctions, getFunctionsDir } from '../../utils/functions/index.mjs'
6
+ import requiresSiteInfo from '../../utils/hooks/requires-site-info.mjs'
6
7
 
7
8
  const normalizeFunction = function (deployedFunctions, { name, urlPath: url }) {
8
9
  const isDeployed = deployedFunctions.some((deployedFunction) => deployedFunction.n === name)
@@ -15,31 +16,9 @@ const normalizeFunction = function (deployedFunctions, { name, urlPath: url }) {
15
16
  * @param {import('../base-command.mjs').default} command
16
17
  */
17
18
  const functionsList = async (options, command) => {
18
- const { api, config, site } = command.netlify
19
+ const { config, siteInfo } = command.netlify
19
20
 
20
- // get deployed site details
21
- // copied from `netlify status`
22
- const siteId = site.id
23
- if (!siteId) {
24
- warn('Did you run `netlify link` yet?')
25
- error(`You don't appear to be in a folder that is linked to a site`)
26
- }
27
- let siteData
28
- try {
29
- siteData = await api.getSite({ siteId })
30
- } catch (error_) {
31
- // unauthorized
32
- if (error_.status === 401) {
33
- warn(`Log in with a different account or re-link to a site you have permission for`)
34
- error(`Not authorized to view the currently linked site (${siteId})`)
35
- }
36
- // missing
37
- if (error_.status === 404) {
38
- error(`The site this folder is linked to can't be found`)
39
- }
40
- error(error_)
41
- }
42
- const deploy = siteData.published_deploy || {}
21
+ const deploy = siteInfo.published_deploy || {}
43
22
  const deployedFunctions = deploy.available_functions || []
44
23
 
45
24
  const functionsDir = getFunctionsDir({ options, config })
@@ -91,4 +70,5 @@ NOT the same as listing the functions that have been deployed. For that info you
91
70
  )
92
71
  .option('-f, --functions <dir>', 'Specify a functions directory to list')
93
72
  .option('--json', 'Output function data as JSON')
73
+ .hook('preAction', requiresSiteInfo)
94
74
  .action(functionsList)
@@ -1,6 +1,7 @@
1
1
  // @ts-check
2
2
  import { Option } from 'commander'
3
3
  import inquirer from 'inquirer'
4
+ import isEmpty from 'lodash/isEmpty.js'
4
5
 
5
6
  import { listSites } from '../../lib/api.mjs'
6
7
  import { chalk, error, exit, log } from '../../utils/command-helpers.mjs'
@@ -250,28 +251,23 @@ export const link = async (options, command) => {
250
251
  api,
251
252
  repositoryRoot,
252
253
  site: { id: siteId },
254
+ siteInfo,
253
255
  state,
254
256
  } = command.netlify
255
257
 
256
- let siteData
257
- try {
258
- // @ts-ignore types from API are wrong they cannot recognize `getSite` of API
259
- siteData = await api.getSite({ siteId })
260
- } catch {
261
- // silent api error
262
- }
258
+ let siteData = siteInfo
263
259
 
264
260
  // Add .netlify to .gitignore file
265
261
  await ensureNetlifyIgnore(repositoryRoot)
266
262
 
267
263
  // Site id is incorrect
268
- if (siteId && !siteData) {
264
+ if (siteId && isEmpty(siteData)) {
269
265
  log(`"${siteId}" was not found in your Netlify account.`)
270
266
  log(`Please double check your siteID and which account you are logged into via \`netlify status\`.`)
271
267
  return exit()
272
268
  }
273
269
 
274
- if (siteData) {
270
+ if (!isEmpty(siteInfo)) {
275
271
  // If already linked to site. exit and prompt for unlink
276
272
  log(`Site already linked to "${siteData.name}"`)
277
273
  log(`Admin url: ${siteData.admin_url}`)
@@ -1,4 +1,5 @@
1
- import { error, exit, log, warn } from '../../utils/command-helpers.mjs'
1
+ import { exit, log } from '../../utils/command-helpers.mjs'
2
+ import requiresSiteInfo from '../../utils/hooks/requires-site-info.mjs'
2
3
  import openBrowser from '../../utils/open-browser.mjs'
3
4
 
4
5
  /**
@@ -7,42 +8,14 @@ import openBrowser from '../../utils/open-browser.mjs'
7
8
  * @param {import('../base-command.mjs').default} command
8
9
  */
9
10
  export const openAdmin = async (options, command) => {
10
- const { api, site } = command.netlify
11
+ const { siteInfo } = command.netlify
11
12
 
12
13
  await command.authenticate()
13
14
 
14
- const siteId = site.id
15
+ log(`Opening "${siteInfo.name}" site admin UI:`)
16
+ log(`> ${siteInfo.admin_url}`)
15
17
 
16
- if (!siteId) {
17
- warn(`No Site ID found in current directory.
18
- Run \`netlify link\` to connect to this folder to a site`)
19
- return false
20
- }
21
-
22
- let siteData
23
- try {
24
- siteData = await api.getSite({ siteId })
25
- log(`Opening "${siteData.name}" site admin UI:`)
26
- log(`> ${siteData.admin_url}`)
27
- } catch (error_) {
28
- // unauthorized
29
- if (error_.status === 401) {
30
- warn(`Log in with a different account or re-link to a site you have permission for`)
31
- error(`Not authorized to view the currently linked site (${siteId})`)
32
- }
33
- // site not found
34
- if (error_.status === 404) {
35
- log()
36
- log('Please double check this ID and verify you are logged in with the correct account')
37
- log()
38
- log('To fix this, run `netlify unlink` then `netlify link` to reconnect to the correct site ID')
39
- log()
40
- error(`Site "${siteId}" not found in account`)
41
- }
42
- error(error_)
43
- }
44
-
45
- await openBrowser({ url: siteData.admin_url })
18
+ await openBrowser({ url: siteInfo.admin_url })
46
19
  exit()
47
20
  }
48
21
 
@@ -56,4 +29,5 @@ export const createOpenAdminCommand = (program) =>
56
29
  .command('open:admin')
57
30
  .description('Opens current site admin UI in Netlify')
58
31
  .addExamples(['netlify open:admin'])
32
+ .hook('preAction', requiresSiteInfo)
59
33
  .action(openAdmin)
@@ -1,4 +1,5 @@
1
- import { error, exit, log, warn } from '../../utils/command-helpers.mjs'
1
+ import { exit, log } from '../../utils/command-helpers.mjs'
2
+ import requiresSiteInfo from '../../utils/hooks/requires-site-info.mjs'
2
3
  import openBrowser from '../../utils/open-browser.mjs'
3
4
 
4
5
  /**
@@ -7,33 +8,13 @@ import openBrowser from '../../utils/open-browser.mjs'
7
8
  * @param {import('../base-command.mjs').default} command
8
9
  */
9
10
  export const openSite = async (options, command) => {
10
- const { api, site } = command.netlify
11
+ const { siteInfo } = command.netlify
11
12
 
12
13
  await command.authenticate()
13
14
 
14
- const siteId = site.id
15
-
16
- if (!siteId) {
17
- warn(`No Site ID found in current directory.
18
- Run \`netlify link\` to connect to this folder to a site`)
19
- return false
20
- }
21
-
22
- let siteData
23
- let url
24
- try {
25
- siteData = await api.getSite({ siteId })
26
- url = siteData.ssl_url || siteData.url
27
- log(`Opening "${siteData.name}" site url:`)
28
- log(`> ${url}`)
29
- } catch (error_) {
30
- // unauthorized
31
- if (error_.status === 401) {
32
- warn(`Log in with a different account or re-link to a site you have permission for`)
33
- error(`Not authorized to view the currently linked site (${siteId})`)
34
- }
35
- error(error_)
36
- }
15
+ const url = siteInfo.ssl_url || siteInfo.url
16
+ log(`Opening "${siteInfo.name}" site url:`)
17
+ log(`> ${url}`)
37
18
 
38
19
  await openBrowser({ url })
39
20
  exit()
@@ -49,4 +30,5 @@ export const createOpenSiteCommand = (program) =>
49
30
  .command('open:site')
50
31
  .description('Opens current site url in browser')
51
32
  .addExamples(['netlify open:site'])
33
+ .hook('preAction', requiresSiteInfo)
52
34
  .action(openSite)
@@ -80,7 +80,7 @@ const serve = async (options, command) => {
80
80
  exit(1)
81
81
  }
82
82
 
83
- command.setAnalyticsPayload({ projectType: settings.framework || 'custom', live: options.live })
83
+ command.setAnalyticsPayload({ live: options.live })
84
84
 
85
85
  log(`${NETLIFYDEVLOG} Building site for production`)
86
86
  log(
@@ -1,7 +1,8 @@
1
1
  // @ts-check
2
2
  import prettyjson from 'prettyjson'
3
3
 
4
- import { error, log, warn } from '../../utils/command-helpers.mjs'
4
+ import { log } from '../../utils/command-helpers.mjs'
5
+ import requiresSiteInfo from '../../utils/hooks/requires-site-info.mjs'
5
6
 
6
7
  /**
7
8
  * The status:hooks command
@@ -9,35 +10,13 @@ import { error, log, warn } from '../../utils/command-helpers.mjs'
9
10
  * @param {import('../base-command.mjs').default} command
10
11
  */
11
12
  const statusHooks = async (options, command) => {
12
- const { api, site } = command.netlify
13
+ const { api, siteInfo } = command.netlify
13
14
 
14
15
  await command.authenticate()
15
16
 
16
- const siteId = site.id
17
- if (!siteId) {
18
- warn('Did you run `netlify link` yet?')
19
- error(`You don't appear to be in a folder that is linked to a site`)
20
- }
21
-
22
- let siteData
23
- try {
24
- siteData = await api.getSite({ siteId })
25
- } catch (error_) {
26
- // unauthorized
27
- if (error_.status === 401) {
28
- warn(`Log in with a different account or re-link to a site you have permission for`)
29
- error(`Not authorized to view the currently linked site (${siteId})`)
30
- }
31
- // missing
32
- if (error_.status === 404) {
33
- error(`The site this folder is linked to can't be found`)
34
- }
35
- error(error_)
36
- }
37
-
38
- const ntlHooks = await api.listHooksBySiteId({ siteId: siteData.id })
17
+ const ntlHooks = await api.listHooksBySiteId({ siteId: siteInfo.id })
39
18
  const data = {
40
- site: siteData.name,
19
+ site: siteInfo.name,
41
20
  hooks: {},
42
21
  }
43
22
  ntlHooks.forEach((hook) => {
@@ -47,8 +26,8 @@ const statusHooks = async (options, command) => {
47
26
  id: hook.id,
48
27
  disabled: hook.disabled,
49
28
  }
50
- if (siteData.build_settings?.repo_url) {
51
- data.hooks[hook.id].repo_url = siteData.build_settings.repo_url
29
+ if (siteInfo.build_settings?.repo_url) {
30
+ data.hooks[hook.id].repo_url = siteInfo.build_settings.repo_url
52
31
  }
53
32
  })
54
33
  log(`─────────────────┐
@@ -63,4 +42,8 @@ Site Hook Status │
63
42
  * @returns
64
43
  */
65
44
  export const createStatusHooksCommand = (program) =>
66
- program.command('status:hooks').description('Print hook information of the linked site').action(statusHooks)
45
+ program
46
+ .command('status:hooks')
47
+ .description('Print hook information of the linked site')
48
+ .hook('preAction', requiresSiteInfo)
49
+ .action(statusHooks)
@@ -8,7 +8,7 @@ import { track } from '../../utils/telemetry/index.mjs'
8
8
  * @param {import('../base-command.mjs').default} command
9
9
  */
10
10
  const unlink = async (options, command) => {
11
- const { site, state } = command.netlify
11
+ const { site, siteInfo, state } = command.netlify
12
12
  const siteId = site.id
13
13
 
14
14
  if (!siteId) {
@@ -16,13 +16,7 @@ const unlink = async (options, command) => {
16
16
  return exit()
17
17
  }
18
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 {
24
- // ignore errors if we can't get the site
25
- }
19
+ const siteData = siteInfo
26
20
 
27
21
  state.delete('siteId')
28
22
 
@@ -13,9 +13,9 @@
13
13
  }
14
14
  },
15
15
  "node_modules/node-fetch": {
16
- "version": "2.6.9",
17
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz",
18
- "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==",
16
+ "version": "2.6.11",
17
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz",
18
+ "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==",
19
19
  "dependencies": {
20
20
  "whatwg-url": "^5.0.0"
21
21
  },
@@ -53,9 +53,9 @@
53
53
  },
54
54
  "dependencies": {
55
55
  "node-fetch": {
56
- "version": "2.6.9",
57
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz",
58
- "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==",
56
+ "version": "2.6.11",
57
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz",
58
+ "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==",
59
59
  "requires": {
60
60
  "whatwg-url": "^5.0.0"
61
61
  }
@@ -13,13 +13,13 @@
13
13
  "uuid": "^9.0.0"
14
14
  },
15
15
  "engines": {
16
- "node": "^14.16.0 || >=16.0.0"
16
+ "node": "^14.18.0 || >=16.0.0"
17
17
  }
18
18
  },
19
19
  "node_modules/node-fetch": {
20
- "version": "2.6.9",
21
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz",
22
- "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==",
20
+ "version": "2.6.11",
21
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz",
22
+ "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==",
23
23
  "dependencies": {
24
24
  "whatwg-url": "^5.0.0"
25
25
  },
@@ -65,9 +65,9 @@
65
65
  },
66
66
  "dependencies": {
67
67
  "node-fetch": {
68
- "version": "2.6.9",
69
- "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz",
70
- "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==",
68
+ "version": "2.6.11",
69
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.11.tgz",
70
+ "integrity": "sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w==",
71
71
  "requires": {
72
72
  "whatwg-url": "^5.0.0"
73
73
  }
@@ -0,0 +1,16 @@
1
+ import { error } from './command-helpers.mjs'
2
+
3
+ export const getSiteByName = async (api, siteName) => {
4
+ try {
5
+ const sites = await api.listSites({ name: siteName, filter: 'all' })
6
+ const siteFoundByName = sites.find((filteredSite) => filteredSite.name === siteName)
7
+
8
+ if (!siteFoundByName) {
9
+ throw Error
10
+ }
11
+
12
+ return siteFoundByName
13
+ } catch {
14
+ error('Site not found. Please rerun "netlify link"')
15
+ }
16
+ }
@@ -0,0 +1,29 @@
1
+ import { error, warn } from '../command-helpers.mjs'
2
+ /**
3
+ * A preAction hook that errors out if siteInfo is an empty object
4
+ * @param {*} command
5
+ */
6
+ const requiresSiteInfo = async (command) => {
7
+ const { api, site } = command.netlify
8
+ const siteId = site.id
9
+ if (!siteId) {
10
+ warn('Did you run `netlify link` yet?')
11
+ return error(`You don't appear to be in a folder that is linked to a site`)
12
+ }
13
+ try {
14
+ await api.getSite({ siteId })
15
+ } catch (error_) {
16
+ // unauthorized
17
+ if (error_.status === 401) {
18
+ warn(`Log in with a different account or re-link to a site you have permission for`)
19
+ return error(`Not authorized to view the currently linked site (${siteId})`)
20
+ }
21
+ // missing
22
+ if (error_.status === 404) {
23
+ return error(`The site this folder is linked to can't be found`)
24
+ }
25
+ return error(error_)
26
+ }
27
+ }
28
+
29
+ export default requiresSiteInfo