netlify-cli 11.2.0 → 11.5.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.
@@ -1,21 +1,21 @@
1
1
  {
2
2
  "name": "netlify-cli",
3
- "version": "11.2.0",
3
+ "version": "11.5.0",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "netlify-cli",
9
- "version": "11.2.0",
9
+ "version": "11.5.0",
10
10
  "hasInstallScript": true,
11
11
  "license": "MIT",
12
12
  "dependencies": {
13
- "@netlify/build": "^27.15.4",
13
+ "@netlify/build": "^27.15.6",
14
14
  "@netlify/config": "^18.2.1",
15
15
  "@netlify/edge-bundler": "^1.13.0",
16
16
  "@netlify/framework-info": "^9.2.0",
17
17
  "@netlify/local-functions-proxy": "^1.1.1",
18
- "@netlify/plugins-list": "^6.39.0",
18
+ "@netlify/plugins-list": "^6.40.0",
19
19
  "@netlify/zip-it-and-ship-it": "^5.13.5",
20
20
  "@octokit/rest": "^18.0.0",
21
21
  "@sindresorhus/slugify": "^1.1.0",
@@ -81,7 +81,7 @@
81
81
  "multiparty": "^4.2.1",
82
82
  "netlify": "^12.0.1",
83
83
  "netlify-headers-parser": "^6.0.2",
84
- "netlify-onegraph-internal": "0.8.7",
84
+ "netlify-onegraph-internal": "0.10.0",
85
85
  "netlify-redirect-parser": "^13.0.5",
86
86
  "netlify-redirector": "^0.2.1",
87
87
  "node-fetch": "^2.6.0",
@@ -1189,9 +1189,9 @@
1189
1189
  "integrity": "sha512-4wMPu9iN3/HL97QblBsBay3E1etIciR84izI3U+4iALY+JHCrI+a2jO0qbAZ/nxKoegypYEaiiqWXylm+/zfrw=="
1190
1190
  },
1191
1191
  "node_modules/@netlify/build": {
1192
- "version": "27.15.4",
1193
- "resolved": "https://registry.npmjs.org/@netlify/build/-/build-27.15.4.tgz",
1194
- "integrity": "sha512-4fNEB3V4DF1HQEQrRfFFRWWRNNlkZEdcyWXz1ekzAwQ6rJYmhUxHV5tJg98AhHTrovXBmlWK1gLF3qLaGGoMFA==",
1192
+ "version": "27.15.6",
1193
+ "resolved": "https://registry.npmjs.org/@netlify/build/-/build-27.15.6.tgz",
1194
+ "integrity": "sha512-ZSah6LDAG0KwWiTUfVfL/kBie7qsUj4cMSl0D7dbTBWSRpGx8MgYjlJHP3U2PgXAgmLcc4NOciGIZD/zL4yJCA==",
1195
1195
  "dependencies": {
1196
1196
  "@bugsnag/js": "^7.0.0",
1197
1197
  "@netlify/cache-utils": "^4.0.0",
@@ -3593,9 +3593,9 @@
3593
3593
  "integrity": "sha512-1n9VvO/9qM7cRB5f7NgSNqeUrovM7j9WVAY7ZQ4LtQuXSquFmO9Fku7WrV3zAUC6v2Y62fxGyJ0fRllYz5uXLw=="
3594
3594
  },
3595
3595
  "node_modules/@netlify/plugins-list": {
3596
- "version": "6.39.0",
3597
- "resolved": "https://registry.npmjs.org/@netlify/plugins-list/-/plugins-list-6.39.0.tgz",
3598
- "integrity": "sha512-f8sMN7XFlQQ63km5vhg5y5+E3DXoWEoAe94YOMGlmzifZCCzPS/bEUVaQ07n+iDspy3dOIN97FHAAu0B2Jpe2Q==",
3596
+ "version": "6.40.0",
3597
+ "resolved": "https://registry.npmjs.org/@netlify/plugins-list/-/plugins-list-6.40.0.tgz",
3598
+ "integrity": "sha512-VDYHEVS/r3eEylUNVwwF0scyV8ISMfxbz6MMl7TEpgArXOS+lYhObNAukrWcUR7aa0zf9C3jwy67zROh0M+ZdQ==",
3599
3599
  "engines": {
3600
3600
  "node": "^12.20.0 || ^14.14.0 || >=16.0.0"
3601
3601
  }
@@ -15963,9 +15963,9 @@
15963
15963
  }
15964
15964
  },
15965
15965
  "node_modules/netlify-onegraph-internal": {
15966
- "version": "0.8.7",
15967
- "resolved": "https://registry.npmjs.org/netlify-onegraph-internal/-/netlify-onegraph-internal-0.8.7.tgz",
15968
- "integrity": "sha512-FDHQes/GP7UjlzAwJ+qwKfhESBo9NQDN9Ed6U+9a5CW5o2j8Lr23P9Ac1MKp7jDP5h0uAq73r9P86J9Kl1yzLQ==",
15966
+ "version": "0.10.0",
15967
+ "resolved": "https://registry.npmjs.org/netlify-onegraph-internal/-/netlify-onegraph-internal-0.10.0.tgz",
15968
+ "integrity": "sha512-Gf6cE1W+q35niIz54xpSLneShpRxlleYL3ZD3D1tjGazuv19q8XBVAAynaAQFzbOk/RPTnu3+Vi/5L7DGACOIg==",
15969
15969
  "dependencies": {
15970
15970
  "graphql": "16.5.0",
15971
15971
  "node-fetch": "^2.6.0",
@@ -22410,15 +22410,15 @@
22410
22410
  "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
22411
22411
  },
22412
22412
  "node_modules/write-file-atomic": {
22413
- "version": "4.0.1",
22414
- "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz",
22415
- "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==",
22413
+ "version": "4.0.2",
22414
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz",
22415
+ "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==",
22416
22416
  "dependencies": {
22417
22417
  "imurmurhash": "^0.1.4",
22418
22418
  "signal-exit": "^3.0.7"
22419
22419
  },
22420
22420
  "engines": {
22421
- "node": "^12.13.0 || ^14.15.0 || >=16"
22421
+ "node": "^12.13.0 || ^14.15.0 || >=16.0.0"
22422
22422
  }
22423
22423
  },
22424
22424
  "node_modules/ws": {
@@ -23374,9 +23374,9 @@
23374
23374
  "integrity": "sha512-4wMPu9iN3/HL97QblBsBay3E1etIciR84izI3U+4iALY+JHCrI+a2jO0qbAZ/nxKoegypYEaiiqWXylm+/zfrw=="
23375
23375
  },
23376
23376
  "@netlify/build": {
23377
- "version": "27.15.4",
23378
- "resolved": "https://registry.npmjs.org/@netlify/build/-/build-27.15.4.tgz",
23379
- "integrity": "sha512-4fNEB3V4DF1HQEQrRfFFRWWRNNlkZEdcyWXz1ekzAwQ6rJYmhUxHV5tJg98AhHTrovXBmlWK1gLF3qLaGGoMFA==",
23377
+ "version": "27.15.6",
23378
+ "resolved": "https://registry.npmjs.org/@netlify/build/-/build-27.15.6.tgz",
23379
+ "integrity": "sha512-ZSah6LDAG0KwWiTUfVfL/kBie7qsUj4cMSl0D7dbTBWSRpGx8MgYjlJHP3U2PgXAgmLcc4NOciGIZD/zL4yJCA==",
23380
23380
  "requires": {
23381
23381
  "@bugsnag/js": "^7.0.0",
23382
23382
  "@netlify/cache-utils": "^4.0.0",
@@ -24766,9 +24766,9 @@
24766
24766
  "integrity": "sha512-1n9VvO/9qM7cRB5f7NgSNqeUrovM7j9WVAY7ZQ4LtQuXSquFmO9Fku7WrV3zAUC6v2Y62fxGyJ0fRllYz5uXLw=="
24767
24767
  },
24768
24768
  "@netlify/plugins-list": {
24769
- "version": "6.39.0",
24770
- "resolved": "https://registry.npmjs.org/@netlify/plugins-list/-/plugins-list-6.39.0.tgz",
24771
- "integrity": "sha512-f8sMN7XFlQQ63km5vhg5y5+E3DXoWEoAe94YOMGlmzifZCCzPS/bEUVaQ07n+iDspy3dOIN97FHAAu0B2Jpe2Q=="
24769
+ "version": "6.40.0",
24770
+ "resolved": "https://registry.npmjs.org/@netlify/plugins-list/-/plugins-list-6.40.0.tgz",
24771
+ "integrity": "sha512-VDYHEVS/r3eEylUNVwwF0scyV8ISMfxbz6MMl7TEpgArXOS+lYhObNAukrWcUR7aa0zf9C3jwy67zROh0M+ZdQ=="
24772
24772
  },
24773
24773
  "@netlify/run-utils": {
24774
24774
  "version": "4.0.1",
@@ -34193,9 +34193,9 @@
34193
34193
  }
34194
34194
  },
34195
34195
  "netlify-onegraph-internal": {
34196
- "version": "0.8.7",
34197
- "resolved": "https://registry.npmjs.org/netlify-onegraph-internal/-/netlify-onegraph-internal-0.8.7.tgz",
34198
- "integrity": "sha512-FDHQes/GP7UjlzAwJ+qwKfhESBo9NQDN9Ed6U+9a5CW5o2j8Lr23P9Ac1MKp7jDP5h0uAq73r9P86J9Kl1yzLQ==",
34196
+ "version": "0.10.0",
34197
+ "resolved": "https://registry.npmjs.org/netlify-onegraph-internal/-/netlify-onegraph-internal-0.10.0.tgz",
34198
+ "integrity": "sha512-Gf6cE1W+q35niIz54xpSLneShpRxlleYL3ZD3D1tjGazuv19q8XBVAAynaAQFzbOk/RPTnu3+Vi/5L7DGACOIg==",
34199
34199
  "requires": {
34200
34200
  "graphql": "16.5.0",
34201
34201
  "node-fetch": "^2.6.0",
@@ -39129,9 +39129,9 @@
39129
39129
  "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
39130
39130
  },
39131
39131
  "write-file-atomic": {
39132
- "version": "4.0.1",
39133
- "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.1.tgz",
39134
- "integrity": "sha512-nSKUxgAbyioruk6hU87QzVbY279oYT6uiwgDoujth2ju4mJ+TZau7SQBhtbTmUyuNYTuXnSyRn66FV0+eCgcrQ==",
39132
+ "version": "4.0.2",
39133
+ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz",
39134
+ "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==",
39135
39135
  "requires": {
39136
39136
  "imurmurhash": "^0.1.4",
39137
39137
  "signal-exit": "^3.0.7"
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "netlify-cli",
3
3
  "description": "Netlify command line tool",
4
- "version": "11.2.0",
4
+ "version": "11.5.0",
5
5
  "author": "Netlify Inc.",
6
6
  "contributors": [
7
7
  "@whitep4nth3r (https://twitter.com/whitep4nth3r)",
@@ -46,6 +46,7 @@
46
46
  "Erez Rokah (https://www.erezro.com)",
47
47
  "Erica Pisani <pisani.erica@gmail.com>",
48
48
  "Evans Hauser (https://twitter.com/evanshauser)",
49
+ "Ewan Valentine <ewan.valentine89@gmail.com> (http://ewanvalentine.io)",
49
50
  "Finn Woelm (https://twitter.com/FinnWoelm)",
50
51
  "Flxbot",
51
52
  "Gavin Henderson <gavin.henderson@hotmail.co.uk> (https://twitter.com/gavinhenderson5)",
@@ -222,12 +223,12 @@
222
223
  "prettier": "--ignore-path .gitignore --loglevel=warn \"{src,tools,scripts,site,tests,.github}/**/*.{mjs,cjs,js,md,yml,json,html}\" \"*.{mjs,cjs,js,yml,json,html}\" \".*.{mjs,cjs,js,yml,json,html}\" \"!CHANGELOG.md\" \"!npm-shrinkwrap.json\" \"!**/*/package-lock.json\" \"!.github/**/*.md\""
223
224
  },
224
225
  "dependencies": {
225
- "@netlify/build": "^27.15.4",
226
+ "@netlify/build": "^27.15.6",
226
227
  "@netlify/config": "^18.2.1",
227
228
  "@netlify/edge-bundler": "^1.13.0",
228
229
  "@netlify/framework-info": "^9.2.0",
229
230
  "@netlify/local-functions-proxy": "^1.1.1",
230
- "@netlify/plugins-list": "^6.39.0",
231
+ "@netlify/plugins-list": "^6.40.0",
231
232
  "@netlify/zip-it-and-ship-it": "^5.13.5",
232
233
  "@octokit/rest": "^18.0.0",
233
234
  "@sindresorhus/slugify": "^1.1.0",
@@ -293,7 +294,7 @@
293
294
  "multiparty": "^4.2.1",
294
295
  "netlify": "^12.0.1",
295
296
  "netlify-headers-parser": "^6.0.2",
296
- "netlify-onegraph-internal": "0.8.7",
297
+ "netlify-onegraph-internal": "0.10.0",
297
298
  "netlify-redirect-parser": "^13.0.5",
298
299
  "netlify-redirector": "^0.2.1",
299
300
  "node-fetch": "^2.6.0",
@@ -2,7 +2,7 @@ const process = require('process')
2
2
 
3
3
  // @ts-check
4
4
  const { getBuildOptions, runBuild } = require('../../lib/build')
5
- const { error, exit, generateNetlifyGraphJWT, getEnvelopeEnv, getToken } = require('../../utils')
5
+ const { error, exit, generateNetlifyGraphJWT, getEnvelopeEnv, getToken, normalizeContext } = require('../../utils')
6
6
 
7
7
  /**
8
8
  * @param {import('../../lib/build').BuildConfig} options
@@ -85,7 +85,12 @@ const createBuildCommand = (program) =>
85
85
  program
86
86
  .command('build')
87
87
  .description('(Beta) Build on your local machine')
88
- .option('--context <context>', 'Specify a build context', process.env.CONTEXT || 'production')
88
+ .option(
89
+ '--context <context>',
90
+ 'Specify a build context or branch (contexts: "production", "deploy-preview", "branch-deploy", "dev")',
91
+ normalizeContext,
92
+ process.env.CONTEXT || 'production',
93
+ )
89
94
  .option('--dry', 'Dry run: show instructions without running them', false)
90
95
  .option('-o, --offline', 'disables any features that require network access', false)
91
96
  .addExamples(['netlify build'])
@@ -410,7 +410,13 @@ const bundleEdgeFunctions = async (options) => {
410
410
  phase: 'start',
411
411
  })
412
412
 
413
- const { severityCode, success } = await runCoreSteps(['edge_functions_bundling'], { ...options, buffer: true })
413
+ const { severityCode, success } = await runCoreSteps(['edge_functions_bundling'], {
414
+ ...options,
415
+ buffer: true,
416
+ featureFlags: {
417
+ edge_functions_produce_eszip: true,
418
+ },
419
+ })
414
420
 
415
421
  if (!success) {
416
422
  statusCb({
@@ -1,7 +1,6 @@
1
- const { Option } = require('commander')
2
1
  const execa = require('execa')
3
2
 
4
- const { getEnvelopeEnv, injectEnvVariables } = require('../../utils')
3
+ const { getEnvelopeEnv, injectEnvVariables, normalizeContext } = require('../../utils')
5
4
 
6
5
  /**
7
6
  * The dev:exec command
@@ -32,10 +31,11 @@ const createDevExecCommand = (program) =>
32
31
  program
33
32
  .command('dev:exec')
34
33
  .argument('<...cmd>', `the command that should be executed`)
35
- .addOption(
36
- new Option('--context <context>', 'Specify a deploy context for environment variables')
37
- .choices(['production', 'deploy-preview', 'branch-deploy', 'dev'])
38
- .default('dev'),
34
+ .option(
35
+ '--context <context>',
36
+ 'Specify a deploy context or branch for environment variables (contexts: "production", "deploy-preview", "branch-deploy", "dev")',
37
+ normalizeContext,
38
+ 'dev',
39
39
  )
40
40
  .description(
41
41
  'Exec command\nRuns a command within the netlify dev environment, e.g. with env variables from any installed addons',
@@ -45,6 +45,7 @@ const {
45
45
  injectEnvVariables,
46
46
  log,
47
47
  normalizeConfig,
48
+ normalizeContext,
48
49
  openBrowser,
49
50
  processOnExit,
50
51
  startLiveTunnel,
@@ -434,6 +435,7 @@ const dev = async (options, command) => {
434
435
  }
435
436
 
436
437
  let { env } = cachedConfig
438
+
437
439
  if (!options.offline && siteInfo.use_envelope) {
438
440
  env = await getEnvelopeEnv({ api, context: options.context, env, siteInfo })
439
441
  }
@@ -683,10 +685,11 @@ const createDevCommand = (program) => {
683
685
  `Local dev server\nThe dev command will run a local dev server with Netlify's proxy and redirect rules`,
684
686
  )
685
687
  .option('-c ,--command <command>', 'command to run')
686
- .addOption(
687
- new Option('--context <context>', 'Specify a deploy context for environment variables')
688
- .choices(['production', 'deploy-preview', 'branch-deploy', 'dev'])
689
- .default('dev'),
688
+ .option(
689
+ '--context <context>',
690
+ 'Specify a deploy context or branch for environment variables (contexts: "production", "deploy-preview", "branch-deploy", "dev")',
691
+ normalizeContext,
692
+ 'dev',
690
693
  )
691
694
  .option('-p ,--port <port>', 'port of netlify dev', (value) => Number.parseInt(value))
692
695
  .option('--targetPort <port>', 'port of target app server', (value) => Number.parseInt(value))
@@ -1,7 +1,7 @@
1
1
  // @ts-check
2
2
  const { Option } = require('commander')
3
3
 
4
- const { chalk, error, getEnvelopeEnv, log, logJson } = require('../../utils')
4
+ const { AVAILABLE_CONTEXTS, chalk, error, getEnvelopeEnv, log, logJson, normalizeContext } = require('../../utils')
5
5
 
6
6
  /**
7
7
  * The env:get command
@@ -42,7 +42,8 @@ const envGet = async (name, options, command) => {
42
42
  }
43
43
 
44
44
  if (!value) {
45
- const withContext = `in the ${chalk.magenta(context)} context`
45
+ const contextType = AVAILABLE_CONTEXTS.includes(context) ? 'context' : 'branch'
46
+ const withContext = `in the ${chalk.magenta(context)} ${contextType}`
46
47
  const withScope = scope === 'any' ? '' : ` and the ${chalk.magenta(scope)} scope`
47
48
  log(`No value set ${withContext}${withScope} for environment variable ${chalk.yellow(name)}`)
48
49
  return false
@@ -60,16 +61,23 @@ const createEnvGetCommand = (program) =>
60
61
  program
61
62
  .command('env:get')
62
63
  .argument('<name>', 'Environment variable name')
63
- .addOption(
64
- new Option('-c, --context <context>', 'Specify a deploy context')
65
- .choices(['production', 'deploy-preview', 'branch-deploy', 'dev'])
66
- .default('dev'),
64
+ .option(
65
+ '-c, --context <context>',
66
+ 'Specify a deploy context or branch (contexts: "production", "deploy-preview", "branch-deploy", "dev")',
67
+ normalizeContext,
68
+ 'dev',
67
69
  )
68
70
  .addOption(
69
71
  new Option('-s, --scope <scope>', 'Specify a scope')
70
72
  .choices(['builds', 'functions', 'post_processing', 'runtime', 'any'])
71
73
  .default('any'),
72
74
  )
75
+ .addExamples([
76
+ 'netlify env:get MY_VAR # get value for MY_VAR in dev context',
77
+ 'netlify env:get MY_VAR --context production',
78
+ 'netlify env:get MY_VAR --context branch:staging',
79
+ 'netlify env:get MY_VAR --scope functions',
80
+ ])
73
81
  .description('Get resolved value of specified environment variable (includes netlify.toml)')
74
82
  .action(async (name, options, command) => {
75
83
  await envGet(name, options, command)
@@ -5,7 +5,16 @@ const { Option } = require('commander')
5
5
  const inquirer = require('inquirer')
6
6
  const isEmpty = require('lodash/isEmpty')
7
7
 
8
- const { chalk, error, getEnvelopeEnv, getHumanReadableScopes, log, logJson } = require('../../utils')
8
+ const {
9
+ AVAILABLE_CONTEXTS,
10
+ chalk,
11
+ error,
12
+ getEnvelopeEnv,
13
+ getHumanReadableScopes,
14
+ log,
15
+ logJson,
16
+ normalizeContext,
17
+ } = require('../../utils')
9
18
 
10
19
  const [logUpdatePromise, ansiEscapesPromise] = [import('log-update'), import('ansi-escapes')]
11
20
 
@@ -77,7 +86,8 @@ const envList = async (options, command) => {
77
86
  }
78
87
 
79
88
  const forSite = `for site ${chalk.green(siteInfo.name)}`
80
- const withContext = isUsingEnvelope ? `in the ${chalk.magenta(options.context)} context` : ''
89
+ const contextType = AVAILABLE_CONTEXTS.includes(context) ? 'context' : 'branch'
90
+ const withContext = isUsingEnvelope ? `in the ${chalk.magenta(options.context)} ${contextType}` : ''
81
91
  const withScope = isUsingEnvelope && scope !== 'any' ? `and ${chalk.yellow(options.scope)} scope` : ''
82
92
  if (isEmpty(environment)) {
83
93
  log(`No environment variables set ${forSite} ${withContext} ${withScope}`)
@@ -122,16 +132,23 @@ const envList = async (options, command) => {
122
132
  const createEnvListCommand = (program) =>
123
133
  program
124
134
  .command('env:list')
125
- .addOption(
126
- new Option('-c, --context <context>', 'Specify a deploy context')
127
- .choices(['production', 'deploy-preview', 'branch-deploy', 'dev'])
128
- .default('dev'),
135
+ .option(
136
+ '-c, --context <context>',
137
+ 'Specify a deploy context or branch (contexts: "production", "deploy-preview", "branch-deploy", "dev")',
138
+ normalizeContext,
139
+ 'dev',
129
140
  )
130
141
  .addOption(
131
142
  new Option('-s, --scope <scope>', 'Specify a scope')
132
143
  .choices(['builds', 'functions', 'post_processing', 'runtime', 'any'])
133
144
  .default('any'),
134
145
  )
146
+ .addExamples([
147
+ 'netlify env:list # list variables with values in the dev context and with any scope',
148
+ 'netlify env:list --context production',
149
+ 'netlify env:list --context branch:staging',
150
+ 'netlify env:list --scope functions',
151
+ ])
135
152
  .description('Lists resolved environment variables for site (includes netlify.toml)')
136
153
  .action(async (options, command) => {
137
154
  await envList(options, command)
@@ -1,9 +1,16 @@
1
1
  // @ts-check
2
2
  const { Option } = require('commander')
3
3
 
4
- const { chalk, error, log, logJson, translateFromEnvelopeToMongo } = require('../../utils')
5
-
6
- const AVAILABLE_SCOPES = ['builds', 'functions', 'runtime', 'post_processing']
4
+ const {
5
+ AVAILABLE_CONTEXTS,
6
+ AVAILABLE_SCOPES,
7
+ chalk,
8
+ error,
9
+ log,
10
+ logJson,
11
+ normalizeContext,
12
+ translateFromEnvelopeToMongo,
13
+ } = require('../../utils')
7
14
 
8
15
  /**
9
16
  * The env:set command
@@ -52,10 +59,11 @@ const envSet = async (key, value, options, command) => {
52
59
  }
53
60
 
54
61
  const withScope = scope ? ` scoped to ${chalk.white(scope)}` : ''
62
+ const contextType = AVAILABLE_CONTEXTS.includes(context || 'all') ? 'context' : 'branch'
55
63
  log(
56
64
  `Set environment variable ${chalk.yellow(`${key}${value ? '=' : ''}${value}`)}${withScope} in the ${chalk.magenta(
57
65
  context || 'all',
58
- )} context`,
66
+ )} ${contextType}`,
59
67
  )
60
68
  }
61
69
 
@@ -93,7 +101,10 @@ const setInEnvelope = async ({ api, context, key, scope, siteInfo, value }) => {
93
101
  const contexts = context || ['all']
94
102
  const scopes = scope || AVAILABLE_SCOPES
95
103
 
96
- let values = contexts.map((ctx) => ({ context: ctx, value }))
104
+ // if the passed context is unknown, it is actually a branch name
105
+ let values = contexts.map((ctx) =>
106
+ AVAILABLE_CONTEXTS.includes(ctx) ? { context: ctx, value } : { context: 'branch', context_parameter: ctx, value },
107
+ )
97
108
 
98
109
  const existing = envelopeVariables.find((envVar) => envVar.key === key)
99
110
 
@@ -144,13 +155,11 @@ const createEnvSetCommand = (program) =>
144
155
  .command('env:set')
145
156
  .argument('<key>', 'Environment variable key')
146
157
  .argument('[value]', 'Value to set to', '')
147
- .addOption(
148
- new Option('-c, --context <context...>', 'Specify a deploy context (default: all contexts)').choices([
149
- 'production',
150
- 'deploy-preview',
151
- 'branch-deploy',
152
- 'dev',
153
- ]),
158
+ .option(
159
+ '-c, --context <context...>',
160
+ 'Specify a deploy context or branch (contexts: "production", "deploy-preview", "branch-deploy", "dev") (default: all contexts)',
161
+ // spread over an array for variadic options
162
+ (context, previous = []) => [...previous, normalizeContext(context)],
154
163
  )
155
164
  .addOption(
156
165
  new Option('-s, --scope <scope...>', 'Specify a scope (default: all scopes)').choices([
@@ -1,9 +1,13 @@
1
- const { Option } = require('commander')
2
-
3
1
  // @ts-check
4
- const { chalk, error, log, logJson, translateFromEnvelopeToMongo } = require('../../utils')
5
-
6
- const AVAILABLE_CONTEXTS = ['production', 'deploy-preview', 'branch-deploy', 'dev']
2
+ const {
3
+ AVAILABLE_CONTEXTS,
4
+ chalk,
5
+ error,
6
+ log,
7
+ logJson,
8
+ normalizeContext,
9
+ translateFromEnvelopeToMongo,
10
+ } = require('../../utils')
7
11
 
8
12
  /**
9
13
  * The env:unset command
@@ -44,7 +48,8 @@ const envUnset = async (key, options, command) => {
44
48
  return false
45
49
  }
46
50
 
47
- log(`Unset environment variable ${chalk.yellow(key)} in the ${chalk.magenta(context || 'all')} context`)
51
+ const contextType = AVAILABLE_CONTEXTS.includes(context || 'all') ? 'context' : 'branch'
52
+ log(`Unset environment variable ${chalk.yellow(key)} in the ${chalk.magenta(context || 'all')} ${contextType}`)
48
53
  }
49
54
 
50
55
  /**
@@ -98,8 +103,10 @@ const unsetInEnvelope = async ({ api, context, key, siteInfo }) => {
98
103
  const params = { accountId, siteId, key }
99
104
  try {
100
105
  if (context) {
101
- // if context(s) are passed, delete the matching contexts, and the `all` context
102
- const values = variable.values.filter((val) => [...contexts, 'all'].includes(val.context))
106
+ // if context(s) are passed, delete the matching contexts / branches, and the `all` context
107
+ const values = variable.values.filter((val) =>
108
+ [...contexts, 'all'].includes(val.context_parameter || val.context),
109
+ )
103
110
  if (values) {
104
111
  await Promise.all(values.map((value) => api.deleteEnvVarValue({ ...params, id: value.id })))
105
112
  // if this was the `all` context, we need to create 3 values in the other contexts
@@ -107,7 +114,9 @@ const unsetInEnvelope = async ({ api, context, key, siteInfo }) => {
107
114
  const newContexts = AVAILABLE_CONTEXTS.filter((ctx) => !context.includes(ctx))
108
115
  const allValue = values[0].value
109
116
  await Promise.all(
110
- newContexts.map((ctx) => api.setEnvVarValue({ ...params, body: { context: ctx, value: allValue } })),
117
+ newContexts
118
+ .filter((ctx) => ctx !== 'all')
119
+ .map((ctx) => api.setEnvVarValue({ ...params, body: { context: ctx, value: allValue } })),
111
120
  )
112
121
  }
113
122
  }
@@ -134,13 +143,11 @@ const createEnvUnsetCommand = (program) =>
134
143
  .command('env:unset')
135
144
  .aliases(['env:delete', 'env:remove'])
136
145
  .argument('<key>', 'Environment variable key')
137
- .addOption(
138
- new Option('-c, --context <context...>', 'Specify a deploy context (default: all contexts)').choices([
139
- 'production',
140
- 'deploy-preview',
141
- 'branch-deploy',
142
- 'dev',
143
- ]),
146
+ .option(
147
+ '-c, --context <context...>',
148
+ 'Specify a deploy context or branch (contexts: "production", "deploy-preview", "branch-deploy", "dev") (default: all contexts)',
149
+ // spread over an array for variadic options
150
+ (context, previous = []) => [...previous, normalizeContext(context)],
144
151
  )
145
152
  .addExamples([
146
153
  'netlify env:unset VAR_NAME # unset in all contexts',
@@ -33,17 +33,18 @@ const graphHandler = async (args, options, command) => {
33
33
  error(`Error parsing schema: ${buildSchemaError}`)
34
34
  }
35
35
 
36
- const userOperationName = args.operationName
36
+ const userOperationNames = args.operationNames
37
37
  const userCodegenId = options.codegen
38
38
 
39
39
  const handlerOptions = options.data ? JSON.parse(options.data) : {}
40
40
 
41
- let operationName = userOperationName
42
- if (!operationName) {
43
- operationName = await autocompleteOperationNames({ netlifyGraphConfig })
41
+ let operationNames = userOperationNames
42
+ if (!operationNames || operationNames.length === 0) {
43
+ const operationName = await autocompleteOperationNames({ netlifyGraphConfig })
44
+ operationNames = [operationName]
44
45
  }
45
46
 
46
- if (!operationName) {
47
+ if (!operationNames || operationNames.length === 0) {
47
48
  error(`No operation name provided`)
48
49
  }
49
50
 
@@ -66,14 +67,17 @@ const graphHandler = async (args, options, command) => {
66
67
  }
67
68
 
68
69
  if (schema) {
69
- generateHandlerByOperationName({
70
- generate: codeGenerator.generateHandler,
71
- logger: log,
72
- netlifyGraphConfig,
73
- schema,
74
- operationName,
75
- handlerOptions,
76
- })
70
+ /* eslint-disable fp/no-loops */
71
+ for (const operationName of operationNames) {
72
+ await generateHandlerByOperationName({
73
+ generate: codeGenerator.generateHandler,
74
+ logger: log,
75
+ netlifyGraphConfig,
76
+ schema,
77
+ operationName,
78
+ handlerOptions,
79
+ })
80
+ }
77
81
  } else {
78
82
  error(`Failed to parse Netlify GraphQL schema`)
79
83
  }
@@ -87,14 +91,14 @@ const graphHandler = async (args, options, command) => {
87
91
  const createGraphHandlerCommand = (program) =>
88
92
  program
89
93
  .command('graph:handler')
90
- .argument('[name]', 'Operation name')
94
+ .argument('[name...]', 'Operation name(s)')
91
95
  .option('-c, --codegen <id>', 'The id of the specific code generator to use')
92
96
  .option("-d, --data '<json>'", 'Optional data to pass along to the code generator')
93
97
  .description(
94
98
  'Generate a handler for a Graph operation given its name. See `graph:operations` for a list of operations.',
95
99
  )
96
- .action(async (operationName, options, command) => {
97
- await graphHandler({ operationName }, options, command)
100
+ .action(async (operationNames, options, command) => {
101
+ await graphHandler({ operationNames }, options, command)
98
102
  })
99
103
 
100
104
  module.exports = { createGraphHandlerCommand }
@@ -16,7 +16,7 @@
16
16
  "license": "MIT",
17
17
  "dependencies": {
18
18
  "apollo-server-lambda": "^2.18.2",
19
- "apollo-datasource-rest": "^0.14.0",
19
+ "apollo-datasource-rest": "^0.15.0",
20
20
  "graphql": "^14.1.1"
21
21
  }
22
22
  }
@@ -26,9 +26,9 @@
26
26
  }
27
27
  },
28
28
  "node_modules/@types/node": {
29
- "version": "14.18.23",
30
- "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.23.tgz",
31
- "integrity": "sha512-MhbCWN18R4GhO8ewQWAFK4TGQdBpXWByukz7cWyJmXhvRuCIaM/oWytGPqVmDzgEnnaIc9ss6HbU5mUi+vyZPA=="
29
+ "version": "14.18.25",
30
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.25.tgz",
31
+ "integrity": "sha512-9pLfceRSrKIsv/MISN6RoFWTIzka36Uk2Uuf5a8cHyDYhEgl5Hm5dXoe621KULeBjt+cFsY18mILsWWtJeG80w=="
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.23",
62
- "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.23.tgz",
63
- "integrity": "sha512-MhbCWN18R4GhO8ewQWAFK4TGQdBpXWByukz7cWyJmXhvRuCIaM/oWytGPqVmDzgEnnaIc9ss6HbU5mUi+vyZPA=="
61
+ "version": "14.18.25",
62
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.25.tgz",
63
+ "integrity": "sha512-9pLfceRSrKIsv/MISN6RoFWTIzka36Uk2Uuf5a8cHyDYhEgl5Hm5dXoe621KULeBjt+cFsY18mILsWWtJeG80w=="
64
64
  },
65
65
  "is-promise": {
66
66
  "version": "4.0.0",
package/src/lib/build.js CHANGED
@@ -35,6 +35,7 @@ const getBuildOptions = ({ cachedConfig, options: { context, cwd, debug, dry, js
35
35
  cwd,
36
36
  featureFlags: {
37
37
  functionsBundlingManifest: true,
38
+ edge_functions_produce_eszip: true,
38
39
  },
39
40
  })
40
41
 
@@ -318,7 +318,7 @@ const refetchAndGenerateFromOneGraph = async (input) => {
318
318
  return
319
319
  }
320
320
 
321
- generateFunctionsFile({
321
+ await generateFunctionsFile({
322
322
  config,
323
323
  logger,
324
324
  netlifyGraphConfig,
@@ -619,7 +619,7 @@ ${JSON.stringify(payload, null, 2)}`)
619
619
  return
620
620
  }
621
621
 
622
- const files = generateHandlerByOperationId({
622
+ const files = await generateHandlerByOperationId({
623
623
  netlifyGraphConfig,
624
624
  schema,
625
625
  operationId: payload.operationId,
@@ -550,9 +550,9 @@ const readGraphQLSchemaFile = (netlifyGraphConfig) => {
550
550
  * @param {string} input.operationsDoc The document containing the operation with operationId and any fragment dependency to use when generating the handler
551
551
  * @param {object} input.handlerOptions The options to use when generating the handler
552
552
  * @param {(message: string) => void=} input.logger A function that if provided will be used to log messages
553
- * @returns {{exportedFiles: CodegenHelpers.ExportedFile[]; operation: GraphQL.OperationDefinitionNode;} | undefined} The generated files
553
+ * @returns {Promise<{exportedFiles: CodegenHelpers.ExportedFile[]; operation: GraphQL.OperationDefinitionNode;} | undefined>} The generated files
554
554
  */
555
- const generateHandlerSourceByOperationId = ({
555
+ const generateHandlerSourceByOperationId = async ({
556
556
  generate,
557
557
  handlerOptions,
558
558
  netlifyGraphConfig,
@@ -571,7 +571,7 @@ const generateHandlerSourceByOperationId = ({
571
571
  operationsDoc,
572
572
  }
573
573
 
574
- const result = NetlifyGraph.generateCustomHandlerSource(generateHandlerPayload)
574
+ const result = await NetlifyGraph.generateCustomHandlerSource(generateHandlerPayload)
575
575
 
576
576
  return result
577
577
  }
@@ -585,15 +585,15 @@ const generateHandlerSourceByOperationId = ({
585
585
  * @param {string} input.operationId The operationId to use when generating the handler
586
586
  * @param {object} input.handlerOptions The options to use when generating the handler
587
587
  * @param {(message: string) => void=} input.logger A function that if provided will be used to log messages
588
- * @returns {Array<{filePath: string, name:string, prettierSuccess: boolean}> | undefined} An array of the generated handler filepaths
588
+ * @returns {Promise<Array<{filePath: string, name:string, prettierSuccess: boolean}> | undefined>} An array of the generated handler filepaths
589
589
  */
590
- const generateHandlerByOperationId = ({ generate, handlerOptions, netlifyGraphConfig, operationId, schema }) => {
590
+ const generateHandlerByOperationId = async ({ generate, handlerOptions, netlifyGraphConfig, operationId, schema }) => {
591
591
  let currentOperationsDoc = readGraphQLOperationsSourceFile(netlifyGraphConfig)
592
592
  if (currentOperationsDoc.trim().length === 0) {
593
593
  currentOperationsDoc = NetlifyGraph.defaultExampleOperationsDoc
594
594
  }
595
595
 
596
- const result = generateHandlerSourceByOperationId({
596
+ const result = await generateHandlerSourceByOperationId({
597
597
  generate,
598
598
  handlerOptions,
599
599
  netlifyGraphConfig,
@@ -669,9 +669,9 @@ const generateHandlerByOperationId = ({ generate, handlerOptions, netlifyGraphCo
669
669
  * @param {string} input.operationName The name of the operation to use when generating the handler
670
670
  * @param {object} input.handlerOptions The options to use when generating the handler
671
671
  * @param {(message: string) => void} input.logger A function that if provided will be used to log messages
672
- * @returns
672
+ * @returns {Promise<void>}
673
673
  */
674
- const generateHandlerByOperationName = ({
674
+ const generateHandlerByOperationName = async ({
675
675
  generate,
676
676
  handlerOptions,
677
677
  logger,
@@ -702,7 +702,7 @@ const generateHandlerByOperationName = ({
702
702
  return
703
703
  }
704
704
 
705
- generateHandlerByOperationId({
705
+ await generateHandlerByOperationId({
706
706
  logger,
707
707
  generate,
708
708
  netlifyGraphConfig,
@@ -1,10 +1,46 @@
1
+ const { error } = require('../command-helpers')
2
+
3
+ const AVAILABLE_CONTEXTS = ['all', 'production', 'deploy-preview', 'branch-deploy', 'dev']
4
+ const AVAILABLE_SCOPES = ['builds', 'functions', 'runtime', 'post_processing']
5
+
6
+ /**
7
+ * @param {string|undefined} context - The deploy context or branch of the environment variable value
8
+ * @returns {Array<string|undefined>} The normalized context or branch name
9
+ */
10
+ const normalizeContext = (context) => {
11
+ if (!context) {
12
+ return context
13
+ }
14
+ const CONTEXT_SYNONYMS = {
15
+ dp: 'deploy-preview',
16
+ prod: 'production',
17
+ }
18
+ context = context.toLowerCase()
19
+ if (context in CONTEXT_SYNONYMS) {
20
+ context = CONTEXT_SYNONYMS[context]
21
+ }
22
+ const forbiddenContexts = AVAILABLE_CONTEXTS.map((ctx) => `branch:${ctx}`)
23
+ if (forbiddenContexts.includes(context)) {
24
+ error(`The context ${context} includes a reserved keyword and is not allowed`)
25
+ }
26
+ context = context.replace(/^branch:/, '')
27
+ return context
28
+ }
29
+
1
30
  /**
2
31
  * Finds a matching environment variable value from a given context
3
32
  * @param {Array<object>} values - An array of environment variable values from Envelope
4
- * @param {enum<dev,branch-deploy,deploy-preview,production>} context - The deploy context of the environment variable value
5
- * @returns {object<context: enum<dev,branch-deploy,deploy-preview,production>, value: string>} The matching environment variable value object
33
+ * @param {string} context - The deploy context or branch of the environment variable value
34
+ * @returns {object<context: enum<dev,branch-deploy,deploy-preview,production,branch>, context_parameter: <string>, value: string>} The matching environment variable value object
6
35
  */
7
- const findValueFromContext = (values, context) => values.find((val) => [context, 'all'].includes(val.context))
36
+ const findValueInValues = (values, context) =>
37
+ values.find((val) => {
38
+ if (!AVAILABLE_CONTEXTS.includes(context)) {
39
+ // the "context" option passed in is actually the name of a branch
40
+ return val.context === 'all' || val.context_parameter === context
41
+ }
42
+ return [context, 'all'].includes(val.context)
43
+ })
8
44
 
9
45
  /**
10
46
  * Finds environment variables that match a given source
@@ -45,7 +81,7 @@ const fetchEnvelopeItems = async function ({ accountId, api, key, siteId }) {
45
81
 
46
82
  /**
47
83
  * Filters and sorts data from Envelope by a given context and/or scope
48
- * @param {enum<dev,branch-deploy,deploy-preview,production>} context - The deploy context of the environment variable value
84
+ * @param {string} context - The deploy context or branch of the environment variable value
49
85
  * @param {Array<object>} envelopeItems - An array of environment variables from the Envelope service
50
86
  * @param {enum<any,builds,functions,runtime,post_processing>} scope - The scope of the environment variables
51
87
  * @param {enum<general,account,addons,ui,configFile>} source - The source of the environment variable
@@ -58,7 +94,8 @@ const fetchEnvelopeItems = async function ({ accountId, api, key, siteId }) {
58
94
  * value: 'bar',
59
95
  * },
60
96
  * BAZ: {
61
- * context: 'dev',
97
+ * context: 'branch',
98
+ * branch: 'staging',
62
99
  * scopes: ['runtime'],
63
100
  * sources: ['account'],
64
101
  * value: 'bang',
@@ -68,18 +105,19 @@ const fetchEnvelopeItems = async function ({ accountId, api, key, siteId }) {
68
105
  const formatEnvelopeData = ({ context = 'dev', envelopeItems = [], scope = 'any', source }) =>
69
106
  envelopeItems
70
107
  // filter by context
71
- .filter(({ values }) => Boolean(findValueFromContext(values, context)))
108
+ .filter(({ values }) => Boolean(findValueInValues(values, context)))
72
109
  // filter by scope
73
110
  .filter(({ scopes }) => (scope === 'any' ? true : scopes.includes(scope)))
74
111
  // sort alphabetically, case insensitive
75
112
  .sort((left, right) => (left.key.toLowerCase() < right.key.toLowerCase() ? -1 : 1))
76
113
  // format the data
77
114
  .reduce((acc, cur) => {
78
- const { context: ctx, value } = findValueFromContext(cur.values, context)
115
+ const { context: ctx, context_parameter: branch, value } = findValueInValues(cur.values, context)
79
116
  return {
80
117
  ...acc,
81
118
  [cur.key]: {
82
119
  context: ctx,
120
+ branch,
83
121
  scopes: cur.scopes,
84
122
  sources: [source],
85
123
  value,
@@ -90,7 +128,7 @@ const formatEnvelopeData = ({ context = 'dev', envelopeItems = [], scope = 'any'
90
128
  /**
91
129
  * Collects env vars from multiple sources and arranges them in the correct order of precedence
92
130
  * @param {object} api - The api singleton object
93
- * @param {enum<dev,branch-deploy,deploy-preview,production>} context - The deploy context of the environment variable
131
+ * @param {string} context - The deploy context or branch of the environment variable
94
132
  * @param {object} env - The dictionary of environment variables
95
133
  * @param {string} key - If present, fetch a single key (case-sensitive)
96
134
  * @param {enum<any,builds,functions,runtime,post_processing>} scope - The scope of the environment variables
@@ -130,7 +168,7 @@ const getEnvelopeEnv = async ({ api, context = 'dev', env, key = '', scope = 'an
130
168
  * @returns {string} A human-readable, comma-separated list of scopes
131
169
  */
132
170
  const getHumanReadableScopes = (scopes) => {
133
- const AVAILABLE_SCOPES = {
171
+ const HUMAN_SCOPES = {
134
172
  builds: 'Builds',
135
173
  functions: 'Functions',
136
174
  post_processing: 'Post processing',
@@ -141,11 +179,11 @@ const getHumanReadableScopes = (scopes) => {
141
179
  // env vars specified in netlify.toml are present in the `builds` and `post_processing` scope
142
180
  return 'Builds, Post processing'
143
181
  }
144
- if (scopes.length === Object.keys(AVAILABLE_SCOPES).length) {
182
+ if (scopes.length === Object.keys(HUMAN_SCOPES).length) {
145
183
  // shorthand instead of listing every available scope
146
184
  return 'All'
147
185
  }
148
- return scopes.map((scope) => AVAILABLE_SCOPES[scope]).join(', ')
186
+ return scopes.map((scope) => HUMAN_SCOPES[scope]).join(', ')
149
187
  }
150
188
 
151
189
  /**
@@ -156,7 +194,7 @@ const getHumanReadableScopes = (scopes) => {
156
194
  const translateFromMongoToEnvelope = (env = {}) => {
157
195
  const envVars = Object.entries(env).map(([key, value]) => ({
158
196
  key,
159
- scopes: ['builds', 'functions', 'runtime', 'post_processing'],
197
+ scopes: AVAILABLE_SCOPES,
160
198
  values: [
161
199
  {
162
200
  context: 'all',
@@ -171,14 +209,14 @@ const translateFromMongoToEnvelope = (env = {}) => {
171
209
  /**
172
210
  * Translates an Envelope env into a Mongo env
173
211
  * @param {Array<object>} envVars - The array of Envelope env vars
174
- * @param {enum<dev,branch-deploy,deploy-preview,production>} context - The deploy context of the environment variable
212
+ * @param {string} context - The deploy context or branch of the environment variable
175
213
  * @returns {object} The env object as compatible with Mongo
176
214
  */
177
215
  const translateFromEnvelopeToMongo = (envVars = [], context = 'dev') =>
178
216
  envVars
179
217
  .sort((left, right) => (left.key.toLowerCase() < right.key.toLowerCase() ? -1 : 1))
180
218
  .reduce((acc, cur) => {
181
- const envVar = cur.values.find((val) => [context, 'all'].includes(val.context))
219
+ const envVar = cur.values.find((val) => [context, 'all'].includes(val.context_parameter || val.context))
182
220
  if (envVar && envVar.value) {
183
221
  return {
184
222
  ...acc,
@@ -189,11 +227,14 @@ const translateFromEnvelopeToMongo = (envVars = [], context = 'dev') =>
189
227
  }, {})
190
228
 
191
229
  module.exports = {
192
- findValueFromContext,
230
+ AVAILABLE_CONTEXTS,
231
+ AVAILABLE_SCOPES,
232
+ findValueInValues,
193
233
  filterEnvBySource,
194
234
  formatEnvelopeData,
195
235
  getEnvelopeEnv,
196
236
  getHumanReadableScopes,
237
+ normalizeContext,
197
238
  translateFromEnvelopeToMongo,
198
239
  translateFromMongoToEnvelope,
199
240
  }