netlify-cli 8.4.3 → 8.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "netlify-cli",
3
3
  "description": "Netlify command line tool",
4
- "version": "8.4.3",
4
+ "version": "8.6.2",
5
5
  "author": "Netlify Inc.",
6
6
  "contributors": [
7
7
  "Mathias Biilmann <matt@netlify.com> (https://twitter.com/biilmann)",
@@ -78,7 +78,7 @@
78
78
  "prettier": "--ignore-path .gitignore --loglevel=warn \"{src,tools,scripts,site,tests,.github}/**/*.{js,md,yml,json,html}\" \"*.{js,yml,json,html}\" \".*.{js,yml,json,html}\" \"!CHANGELOG.md\" \"!npm-shrinkwrap.json\" \"!.github/**/*.md\""
79
79
  },
80
80
  "dependencies": {
81
- "@netlify/build": "^26.0.2",
81
+ "@netlify/build": "^26.1.0",
82
82
  "@netlify/config": "^17.0.2",
83
83
  "@netlify/framework-info": "^7.0.0",
84
84
  "@netlify/local-functions-proxy": "^1.1.1",
@@ -88,6 +88,7 @@
88
88
  "@netlify/zip-it-and-ship-it": "5.3.1",
89
89
  "@octokit/rest": "^18.0.0",
90
90
  "@sindresorhus/slugify": "^1.1.0",
91
+ "ansi-escapes": "^5.0.0",
91
92
  "ansi-styles": "^5.0.0",
92
93
  "ascii-table": "0.0.9",
93
94
  "backoff": "^2.5.0",
@@ -140,6 +141,7 @@
140
141
  "locate-path": "^6.0.0",
141
142
  "lodash": "^4.17.20",
142
143
  "log-symbols": "^4.0.0",
144
+ "log-update": "^5.0.0",
143
145
  "make-dir": "^3.0.0",
144
146
  "memoize-one": "^6.0.0",
145
147
  "minimist": "^1.2.5",
@@ -192,7 +194,7 @@
192
194
  "@babel/preset-react": "^7.12.13",
193
195
  "@commitlint/cli": "^16.0.0",
194
196
  "@commitlint/config-conventional": "^16.0.0",
195
- "@netlify/eslint-config-node": "^4.0.4",
197
+ "@netlify/eslint-config-node": "^4.0.5",
196
198
  "ava": "^3.15.0",
197
199
  "eslint-plugin-sort-destructure-keys": "^1.3.5",
198
200
  "fast-glob": "^3.2.7",
@@ -1,8 +1,22 @@
1
1
  // @ts-check
2
2
  const AsciiTable = require('ascii-table')
3
+ const { isCI } = require('ci-info')
4
+ const inquirer = require('inquirer')
3
5
  const isEmpty = require('lodash/isEmpty')
4
6
 
5
- const { log, logJson } = require('../../utils')
7
+ const { chalk, log, logJson } = require('../../utils')
8
+
9
+ const [logUpdatePromise, ansiEscapesPromise] = [import('log-update'), import('ansi-escapes')]
10
+
11
+ const MASK_LENGTH = 50
12
+ const MASK = '*'.repeat(MASK_LENGTH)
13
+
14
+ const getTable = ({ environment, hideValues }) => {
15
+ const table = new AsciiTable(`Environment variables`)
16
+ table.setHeading('Key', 'Value')
17
+ table.addRowMatrix(Object.entries(environment).map(([key, value]) => [key, hideValues ? MASK : value]))
18
+ return table.toString()
19
+ }
6
20
 
7
21
  /**
8
22
  * The env:list command
@@ -34,17 +48,37 @@ const envList = async (options, command) => {
34
48
  }
35
49
 
36
50
  if (isEmpty(environment)) {
37
- log(`No environment variables set for site ${siteData.name}`)
51
+ log(`No environment variables set for site ${chalk.greenBright(siteData.name)}`)
38
52
  return false
39
53
  }
40
54
 
41
- // List environment variables using a table
42
- log(`site: ${siteData.name}`)
43
- const table = new AsciiTable(`Environment variables`)
55
+ // List environment in a table
56
+ log(`Listing environment variables for site: ${chalk.greenBright(siteData.name)}`)
44
57
 
45
- table.setHeading('Key', 'Value')
46
- table.addRowMatrix(Object.entries(environment))
47
- log(table.toString())
58
+ if (isCI) {
59
+ log(getTable({ environment, hideValues: false }))
60
+ return false
61
+ }
62
+
63
+ const { default: logUpdate } = await logUpdatePromise
64
+
65
+ logUpdate(getTable({ environment, hideValues: true }))
66
+ const { showValues } = await inquirer.prompt([
67
+ {
68
+ type: 'confirm',
69
+ name: 'showValues',
70
+ message: 'Show values?',
71
+ default: false,
72
+ },
73
+ ])
74
+
75
+ if (showValues) {
76
+ const { default: ansiEscapes } = await ansiEscapesPromise
77
+ // since inquirer adds a prompt, we need to account for it when printing the table again
78
+ log(ansiEscapes.eraseLines(3))
79
+ logUpdate(getTable({ environment, hideValues: false }))
80
+ log(`${chalk.cyan('?')} Show values? ${chalk.cyan('Yes')}`)
81
+ }
48
82
  }
49
83
 
50
84
  /**
@@ -0,0 +1,108 @@
1
+ // @ts-check
2
+
3
+ const { isEmpty } = require('lodash')
4
+
5
+ const { chalk, error: logError, log } = require('../../utils')
6
+
7
+ const safeGetSite = async (api, siteId) => {
8
+ try {
9
+ const data = await api.getSite({ siteId })
10
+ return { data }
11
+ } catch (error) {
12
+ return { error }
13
+ }
14
+ }
15
+
16
+ /**
17
+ * The env:migrate command
18
+ * @param {string} siteIdA Site (From)
19
+ * @param {string} siteIdB Site (To)
20
+ * @param {import('commander').OptionValues} options
21
+ * @param {import('../base-command').BaseCommand} command
22
+ * @returns {Promise<boolean>}
23
+ */
24
+ const envMigrate = async (options, command) => {
25
+ const { api, site } = command.netlify
26
+
27
+ if (!site.id && !options.from) {
28
+ log(
29
+ 'Please include the source site Id as the `--from` option, or run `netlify link` to link this folder to a Netlify site',
30
+ )
31
+ return false
32
+ }
33
+
34
+ const siteId = {
35
+ from: options.from || site.id,
36
+ to: options.to,
37
+ }
38
+
39
+ const [{ data: siteFrom, error: errorFrom }, { data: siteTo, error: errorTo }] = await Promise.all([
40
+ safeGetSite(api, siteId.from),
41
+ safeGetSite(api, siteId.to),
42
+ ])
43
+
44
+ if (errorFrom) {
45
+ logError(`Can't find site with id ${chalk.bold(siteId.from)}. Please make sure the site exists.`)
46
+ return false
47
+ }
48
+
49
+ if (errorTo) {
50
+ logError(`Can't find site with id ${chalk.bold(siteId.to)}. Please make sure the site exists.`)
51
+ return false
52
+ }
53
+
54
+ const [
55
+ {
56
+ build_settings: { env: envFrom = {} },
57
+ },
58
+ {
59
+ build_settings: { env: envTo = {} },
60
+ },
61
+ ] = [siteFrom, siteTo]
62
+
63
+ if (isEmpty(envFrom)) {
64
+ log(`${chalk.greenBright(siteFrom.name)} has no environment variables, nothing to migrate`)
65
+ return false
66
+ }
67
+
68
+ // Merge from site A to site B
69
+ const mergedEnv = {
70
+ ...envTo,
71
+ ...envFrom,
72
+ }
73
+
74
+ // Apply environment variable updates
75
+ await api.updateSite({
76
+ siteId: siteId.to,
77
+ body: {
78
+ build_settings: {
79
+ env: mergedEnv,
80
+ },
81
+ },
82
+ })
83
+
84
+ log(
85
+ `Successfully migrated environment variables from ${chalk.greenBright(siteFrom.name)} to ${chalk.greenBright(
86
+ siteTo.name,
87
+ )}`,
88
+ )
89
+ }
90
+
91
+ /**
92
+ * Creates the `netlify env:migrate` command
93
+ * @param {import('../base-command').BaseCommand} program
94
+ * @returns
95
+ */
96
+ const createEnvMigrateCommand = (program) =>
97
+ program
98
+ .command('env:migrate')
99
+ .option('-f, --from <from>', 'Site ID (From)')
100
+ .requiredOption('-t, --to <to>', 'Site ID (To)')
101
+ .description(`Migrate environment variables from one site to another`)
102
+ .addExamples([
103
+ 'netlify env:migrate --to <to-site-id>',
104
+ 'netlify env:migrate --to <to-site-id> --from <from-site-id>',
105
+ ])
106
+ .action(envMigrate)
107
+
108
+ module.exports = { createEnvMigrateCommand }
@@ -2,6 +2,7 @@
2
2
  const { createEnvGetCommand } = require('./env-get')
3
3
  const { createEnvImportCommand } = require('./env-import')
4
4
  const { createEnvListCommand } = require('./env-list')
5
+ const { createEnvMigrateCommand } = require('./env-migrate')
5
6
  const { createEnvSetCommand } = require('./env-set')
6
7
  const { createEnvUnsetCommand } = require('./env-unset')
7
8
 
@@ -25,6 +26,7 @@ const createEnvCommand = (program) => {
25
26
  createEnvListCommand(program)
26
27
  createEnvSetCommand(program)
27
28
  createEnvUnsetCommand(program)
29
+ createEnvMigrateCommand(program)
28
30
 
29
31
  return program
30
32
  .command('env')
@@ -35,6 +37,7 @@ const createEnvCommand = (program) => {
35
37
  'netlify env:set VAR_NAME value',
36
38
  'netlify env:unset VAR_NAME',
37
39
  'netlify env:import fileName',
40
+ 'netlify env:migrate --to <to-site-id>',
38
41
  ])
39
42
  .action(env)
40
43
  }
@@ -7,7 +7,7 @@ version = "0.1.0"
7
7
 
8
8
  [dependencies]
9
9
  aws_lambda_events = "0.5.0"
10
- http = "0.2.5"
10
+ http = "0.2.6"
11
11
  lambda_runtime = "0.4.1"
12
12
  log = "0.4.14"
13
13
  simple_logger = "1.16.0"
@@ -10,7 +10,7 @@
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
12
  "@netlify/functions": "^0.10.0",
13
- "@types/node": "^14.18.3",
13
+ "@types/node": "^14.18.4",
14
14
  "typescript": "^4.0.0"
15
15
  }
16
16
  },
@@ -26,9 +26,9 @@
26
26
  }
27
27
  },
28
28
  "node_modules/@types/node": {
29
- "version": "14.18.3",
30
- "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.3.tgz",
31
- "integrity": "sha512-GtTH2crF4MtOIrrAa+jgTV9JX/PfoUCYr6MiZw7O/dkZu5b6gm5dc1nAL0jwGo4ortSBBtGyeVaxdC8X6V+pLg=="
29
+ "version": "14.18.4",
30
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.4.tgz",
31
+ "integrity": "sha512-swe3lD4izOJWHuxvsZdDFRq6S9i6koJsXOnQKYekhSO5JTizMVirUFgY/bUsaOJQj8oSD4oxmRYPBM/0b6jpdw=="
32
32
  },
33
33
  "node_modules/is-promise": {
34
34
  "version": "4.0.0",
@@ -58,9 +58,9 @@
58
58
  }
59
59
  },
60
60
  "@types/node": {
61
- "version": "14.18.3",
62
- "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.3.tgz",
63
- "integrity": "sha512-GtTH2crF4MtOIrrAa+jgTV9JX/PfoUCYr6MiZw7O/dkZu5b6gm5dc1nAL0jwGo4ortSBBtGyeVaxdC8X6V+pLg=="
61
+ "version": "14.18.4",
62
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.4.tgz",
63
+ "integrity": "sha512-swe3lD4izOJWHuxvsZdDFRq6S9i6koJsXOnQKYekhSO5JTizMVirUFgY/bUsaOJQj8oSD4oxmRYPBM/0b6jpdw=="
64
64
  },
65
65
  "is-promise": {
66
66
  "version": "4.0.0",
@@ -105,7 +105,7 @@ const retryUpload = (uploadFn, maxRetry) =>
105
105
  reject(lastError)
106
106
  })
107
107
 
108
- tryUpload(0, 0)
108
+ tryUpload()
109
109
  })
110
110
 
111
111
  module.exports = { uploadFiles }
@@ -73,7 +73,7 @@ const createRewriter = async function ({ configPath, distDir, jwtRoleClaim, jwtS
73
73
  const cookieValues = cookie.parse(req.headers.cookie || '')
74
74
  const headers = {
75
75
  'x-language': cookieValues.nf_lang || getLanguage(req.headers),
76
- 'x-country': cookieValues.nf_country || getCountry(req),
76
+ 'x-country': cookieValues.nf_country || getCountry(),
77
77
  ...req.headers,
78
78
  }
79
79