netlify-cli 11.0.0 → 11.1.0-rc.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,18 +1,18 @@
1
1
  {
2
2
  "name": "netlify-cli",
3
- "version": "11.0.0",
3
+ "version": "11.1.0-rc.0",
4
4
  "lockfileVersion": 2,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "netlify-cli",
9
- "version": "11.0.0",
9
+ "version": "11.1.0-rc.0",
10
10
  "hasInstallScript": true,
11
11
  "license": "MIT",
12
12
  "dependencies": {
13
13
  "@netlify/build": "^27.14.0",
14
14
  "@netlify/config": "^18.2.0",
15
- "@netlify/edge-bundler": "^1.12.1",
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
18
  "@netlify/plugins-list": "^6.39.0",
@@ -2343,9 +2343,9 @@
2343
2343
  }
2344
2344
  },
2345
2345
  "node_modules/@netlify/edge-bundler": {
2346
- "version": "1.12.1",
2347
- "resolved": "https://registry.npmjs.org/@netlify/edge-bundler/-/edge-bundler-1.12.1.tgz",
2348
- "integrity": "sha512-yROvOGpapj79wJIIjtuGX/p82gZt2K8on13cTg1tfCGRrGOvE+RNSKi5XuAXpocceyDJXnEyETXsc0mdpMMdhg==",
2346
+ "version": "1.13.0",
2347
+ "resolved": "https://registry.npmjs.org/@netlify/edge-bundler/-/edge-bundler-1.13.0.tgz",
2348
+ "integrity": "sha512-5LDNouZP2tUt3m6NyKkEgor9PycIEq7wxUgrRSpiUcZVV7CNU/CUxxpXJb11/wEFq2bWZp3/xqzxqbR7vpqFNg==",
2349
2349
  "dependencies": {
2350
2350
  "common-path-prefix": "^3.0.0",
2351
2351
  "del": "^6.0.0",
@@ -2354,6 +2354,7 @@
2354
2354
  "glob-to-regexp": "^0.4.1",
2355
2355
  "node-fetch": "^3.1.1",
2356
2356
  "node-stream-zip": "^1.15.0",
2357
+ "p-retry": "^5.1.1",
2357
2358
  "p-wait-for": "^4.1.0",
2358
2359
  "path-key": "^4.0.0",
2359
2360
  "semver": "^7.3.5",
@@ -4353,6 +4354,11 @@
4353
4354
  "@types/node": "*"
4354
4355
  }
4355
4356
  },
4357
+ "node_modules/@types/retry": {
4358
+ "version": "0.12.1",
4359
+ "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz",
4360
+ "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g=="
4361
+ },
4356
4362
  "node_modules/@types/semver": {
4357
4363
  "version": "7.3.9",
4358
4364
  "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.9.tgz",
@@ -17355,6 +17361,21 @@
17355
17361
  "url": "https://github.com/sponsors/sindresorhus"
17356
17362
  }
17357
17363
  },
17364
+ "node_modules/p-retry": {
17365
+ "version": "5.1.1",
17366
+ "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-5.1.1.tgz",
17367
+ "integrity": "sha512-i69WkEU5ZAL8mrmdmVviWwU+DN+IUF8f4sSJThoJ3z5A7Nn5iuO5ROX3Boye0u+uYQLOSfgFl7SuFZCjlAVbQA==",
17368
+ "dependencies": {
17369
+ "@types/retry": "0.12.1",
17370
+ "retry": "^0.13.1"
17371
+ },
17372
+ "engines": {
17373
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
17374
+ },
17375
+ "funding": {
17376
+ "url": "https://github.com/sponsors/sindresorhus"
17377
+ }
17378
+ },
17358
17379
  "node_modules/p-timeout": {
17359
17380
  "version": "4.1.0",
17360
17381
  "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-4.1.0.tgz",
@@ -19173,6 +19194,14 @@
19173
19194
  "node": ">=0.12"
19174
19195
  }
19175
19196
  },
19197
+ "node_modules/retry": {
19198
+ "version": "0.13.1",
19199
+ "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
19200
+ "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==",
19201
+ "engines": {
19202
+ "node": ">= 4"
19203
+ }
19204
+ },
19176
19205
  "node_modules/reusify": {
19177
19206
  "version": "1.0.4",
19178
19207
  "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
@@ -24046,9 +24075,9 @@
24046
24075
  }
24047
24076
  },
24048
24077
  "@netlify/edge-bundler": {
24049
- "version": "1.12.1",
24050
- "resolved": "https://registry.npmjs.org/@netlify/edge-bundler/-/edge-bundler-1.12.1.tgz",
24051
- "integrity": "sha512-yROvOGpapj79wJIIjtuGX/p82gZt2K8on13cTg1tfCGRrGOvE+RNSKi5XuAXpocceyDJXnEyETXsc0mdpMMdhg==",
24078
+ "version": "1.13.0",
24079
+ "resolved": "https://registry.npmjs.org/@netlify/edge-bundler/-/edge-bundler-1.13.0.tgz",
24080
+ "integrity": "sha512-5LDNouZP2tUt3m6NyKkEgor9PycIEq7wxUgrRSpiUcZVV7CNU/CUxxpXJb11/wEFq2bWZp3/xqzxqbR7vpqFNg==",
24052
24081
  "requires": {
24053
24082
  "common-path-prefix": "^3.0.0",
24054
24083
  "del": "^6.0.0",
@@ -24057,6 +24086,7 @@
24057
24086
  "glob-to-regexp": "^0.4.1",
24058
24087
  "node-fetch": "^3.1.1",
24059
24088
  "node-stream-zip": "^1.15.0",
24089
+ "p-retry": "^5.1.1",
24060
24090
  "p-wait-for": "^4.1.0",
24061
24091
  "path-key": "^4.0.0",
24062
24092
  "semver": "^7.3.5",
@@ -25377,6 +25407,11 @@
25377
25407
  "@types/node": "*"
25378
25408
  }
25379
25409
  },
25410
+ "@types/retry": {
25411
+ "version": "0.12.1",
25412
+ "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz",
25413
+ "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g=="
25414
+ },
25380
25415
  "@types/semver": {
25381
25416
  "version": "7.3.9",
25382
25417
  "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.9.tgz",
@@ -35173,6 +35208,15 @@
35173
35208
  "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-3.0.0.tgz",
35174
35209
  "integrity": "sha512-xsrIUgI0Kn6iyDYm9StOpOeK29XM1aboGji26+QEortiFST1hGZaUQOLhtEbqHErPpGW/aSz6allwK2qcptp0Q=="
35175
35210
  },
35211
+ "p-retry": {
35212
+ "version": "5.1.1",
35213
+ "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-5.1.1.tgz",
35214
+ "integrity": "sha512-i69WkEU5ZAL8mrmdmVviWwU+DN+IUF8f4sSJThoJ3z5A7Nn5iuO5ROX3Boye0u+uYQLOSfgFl7SuFZCjlAVbQA==",
35215
+ "requires": {
35216
+ "@types/retry": "0.12.1",
35217
+ "retry": "^0.13.1"
35218
+ }
35219
+ },
35176
35220
  "p-timeout": {
35177
35221
  "version": "4.1.0",
35178
35222
  "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-4.1.0.tgz",
@@ -36530,6 +36574,11 @@
36530
36574
  "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
36531
36575
  "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg=="
36532
36576
  },
36577
+ "retry": {
36578
+ "version": "0.13.1",
36579
+ "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
36580
+ "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="
36581
+ },
36533
36582
  "reusify": {
36534
36583
  "version": "1.0.4",
36535
36584
  "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
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.0.0",
4
+ "version": "11.1.0-rc.0",
5
5
  "author": "Netlify Inc.",
6
6
  "contributors": [
7
7
  "@whitep4nth3r (https://twitter.com/whitep4nth3r)",
@@ -224,7 +224,7 @@
224
224
  "dependencies": {
225
225
  "@netlify/build": "^27.14.0",
226
226
  "@netlify/config": "^18.2.0",
227
- "@netlify/edge-bundler": "^1.12.1",
227
+ "@netlify/edge-bundler": "^1.13.0",
228
228
  "@netlify/framework-info": "^9.2.0",
229
229
  "@netlify/local-functions-proxy": "^1.1.1",
230
230
  "@netlify/plugins-list": "^6.39.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'])
@@ -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',
@@ -44,6 +44,7 @@ const {
44
44
  injectEnvVariables,
45
45
  log,
46
46
  normalizeConfig,
47
+ normalizeContext,
47
48
  openBrowser,
48
49
  processOnExit,
49
50
  startLiveTunnel,
@@ -675,10 +676,11 @@ const createDevCommand = (program) => {
675
676
  `Local dev server\nThe dev command will run a local dev server with Netlify's proxy and redirect rules`,
676
677
  )
677
678
  .option('-c ,--command <command>', 'command to run')
678
- .addOption(
679
- new Option('--context <context>', 'Specify a deploy context for environment variables')
680
- .choices(['production', 'deploy-preview', 'branch-deploy', 'dev'])
681
- .default('dev'),
679
+ .option(
680
+ '--context <context>',
681
+ 'Specify a deploy context or branch for environment variables (contexts: "production", "deploy-preview", "branch-deploy", "dev")',
682
+ normalizeContext,
683
+ 'dev',
682
684
  )
683
685
  .option('-p ,--port <port>', 'port of netlify dev', (value) => Number.parseInt(value))
684
686
  .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 { chalk, error, getEnvelopeEnv, log, logJson, normalizeContext } = require('../../utils')
5
5
 
6
6
  /**
7
7
  * The env:get command
@@ -60,16 +60,23 @@ const createEnvGetCommand = (program) =>
60
60
  program
61
61
  .command('env:get')
62
62
  .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'),
63
+ .option(
64
+ '-c, --context <context>',
65
+ 'Specify a deploy context or branch (contexts: "production", "deploy-preview", "branch-deploy", "dev")',
66
+ normalizeContext,
67
+ 'dev',
67
68
  )
68
69
  .addOption(
69
70
  new Option('-s, --scope <scope>', 'Specify a scope')
70
71
  .choices(['builds', 'functions', 'post_processing', 'runtime', 'any'])
71
72
  .default('any'),
72
73
  )
74
+ .addExamples([
75
+ 'netlify env:get MY_VAR # get value for MY_VAR in dev context',
76
+ 'netlify env:get --context production',
77
+ 'netlify env:get --context branch:staging',
78
+ 'netlify env:get --scope functions',
79
+ ])
73
80
  .description('Get resolved value of specified environment variable (includes netlify.toml)')
74
81
  .action(async (name, options, command) => {
75
82
  await envGet(name, options, command)
@@ -5,7 +5,7 @@ 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 { chalk, error, getEnvelopeEnv, getHumanReadableScopes, log, logJson, normalizeContext } = require('../../utils')
9
9
 
10
10
  const [logUpdatePromise, ansiEscapesPromise] = [import('log-update'), import('ansi-escapes')]
11
11
 
@@ -122,16 +122,23 @@ const envList = async (options, command) => {
122
122
  const createEnvListCommand = (program) =>
123
123
  program
124
124
  .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'),
125
+ .option(
126
+ '-c, --context <context>',
127
+ 'Specify a deploy context or branch (contexts: "production", "deploy-preview", "branch-deploy", "dev")',
128
+ normalizeContext,
129
+ 'dev',
129
130
  )
130
131
  .addOption(
131
132
  new Option('-s, --scope <scope>', 'Specify a scope')
132
133
  .choices(['builds', 'functions', 'post_processing', 'runtime', 'any'])
133
134
  .default('any'),
134
135
  )
136
+ .addExamples([
137
+ 'netlify env:list # list dev context and any scope',
138
+ 'netlify env:list --context production',
139
+ 'netlify env:list --context branch:staging',
140
+ 'netlify env:list --scope functions',
141
+ ])
135
142
  .description('Lists resolved environment variables for site (includes netlify.toml)')
136
143
  .action(async (options, command) => {
137
144
  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
@@ -93,7 +100,10 @@ const setInEnvelope = async ({ api, context, key, scope, siteInfo, value }) => {
93
100
  const contexts = context || ['all']
94
101
  const scopes = scope || AVAILABLE_SCOPES
95
102
 
96
- let values = contexts.map((ctx) => ({ context: ctx, value }))
103
+ // if the passed context is unknown, it is actually a branch name
104
+ let values = contexts.map((ctx) =>
105
+ AVAILABLE_CONTEXTS.includes(ctx) ? { context: ctx, value } : { context: 'branch', context_parameter: ctx, value },
106
+ )
97
107
 
98
108
  const existing = envelopeVariables.find((envVar) => envVar.key === key)
99
109
 
@@ -144,13 +154,11 @@ const createEnvSetCommand = (program) =>
144
154
  .command('env:set')
145
155
  .argument('<key>', 'Environment variable key')
146
156
  .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
- ]),
157
+ .option(
158
+ '-c, --context <context...>',
159
+ 'Specify a deploy context or branch (contexts: "production", "deploy-preview", "branch-deploy", "dev") (default: all contexts)',
160
+ // spread over an array for variadic options
161
+ (context, previous = []) => [...previous, normalizeContext(context)],
154
162
  )
155
163
  .addOption(
156
164
  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
@@ -98,8 +102,10 @@ const unsetInEnvelope = async ({ api, context, key, siteInfo }) => {
98
102
  const params = { accountId, siteId, key }
99
103
  try {
100
104
  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))
105
+ // if context(s) are passed, delete the matching contexts / branches, and the `all` context
106
+ const values = variable.values.filter((val) =>
107
+ [...contexts, 'all'].includes(val.context_parameter || val.context),
108
+ )
103
109
  if (values) {
104
110
  await Promise.all(values.map((value) => api.deleteEnvVarValue({ ...params, id: value.id })))
105
111
  // if this was the `all` context, we need to create 3 values in the other contexts
@@ -107,7 +113,9 @@ const unsetInEnvelope = async ({ api, context, key, siteInfo }) => {
107
113
  const newContexts = AVAILABLE_CONTEXTS.filter((ctx) => !context.includes(ctx))
108
114
  const allValue = values[0].value
109
115
  await Promise.all(
110
- newContexts.map((ctx) => api.setEnvVarValue({ ...params, body: { context: ctx, value: allValue } })),
116
+ newContexts
117
+ .filter((ctx) => ctx !== 'all')
118
+ .map((ctx) => api.setEnvVarValue({ ...params, body: { context: ctx, value: allValue } })),
111
119
  )
112
120
  }
113
121
  }
@@ -134,13 +142,11 @@ const createEnvUnsetCommand = (program) =>
134
142
  .command('env:unset')
135
143
  .aliases(['env:delete', 'env:remove'])
136
144
  .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
- ]),
145
+ .option(
146
+ '-c, --context <context...>',
147
+ 'Specify a deploy context or branch (contexts: "production", "deploy-preview", "branch-deploy", "dev") (default: all contexts)',
148
+ // spread over an array for variadic options
149
+ (context, previous = []) => [...previous, normalizeContext(context)],
144
150
  )
145
151
  .addExamples([
146
152
  'netlify env:unset VAR_NAME # unset in all contexts',
@@ -1,10 +1,39 @@
1
+ const AVAILABLE_CONTEXTS = ['all', 'production', 'deploy-preview', 'branch-deploy', 'dev']
2
+ const AVAILABLE_SCOPES = ['builds', 'functions', 'runtime', 'post_processing']
3
+
4
+ /**
5
+ * @param {string|undefined} context - The deploy context or branch of the environment variable value
6
+ * @returns {Array<string|undefined>} The normalized context or branch name
7
+ */
8
+ const normalizeContext = (context) => {
9
+ if (!context) {
10
+ return context
11
+ }
12
+ const CONTEXT_SYNONYMS = {
13
+ dp: 'deploy-preview',
14
+ prod: 'production',
15
+ }
16
+ context = context.replace(/^branch:/, '')
17
+ if (CONTEXT_SYNONYMS[context]) {
18
+ context = CONTEXT_SYNONYMS[context]
19
+ }
20
+ return context
21
+ }
22
+
1
23
  /**
2
24
  * Finds a matching environment variable value from a given context
3
25
  * @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
26
+ * @param {string} context - The deploy context or branch of the environment variable value
27
+ * @returns {object<context: enum<dev,branch-deploy,deploy-preview,production,branch>, context_parameter: <string>, value: string>} The matching environment variable value object
6
28
  */
7
- const findValueFromContext = (values, context) => values.find((val) => [context, 'all'].includes(val.context))
29
+ const findValueInValues = (values, context) =>
30
+ values.find((val) => {
31
+ if (!AVAILABLE_CONTEXTS.includes(context)) {
32
+ // the "context" option passed in is actually the name of a branch
33
+ return ['branch', 'all'].includes(val.context) && val.context_parameter === context
34
+ }
35
+ return [context, 'all'].includes(val.context)
36
+ })
8
37
 
9
38
  /**
10
39
  * Finds environment variables that match a given source
@@ -45,7 +74,7 @@ const fetchEnvelopeItems = async function ({ accountId, api, key, siteId }) {
45
74
 
46
75
  /**
47
76
  * 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
77
+ * @param {string} context - The deploy context or branch of the environment variable value
49
78
  * @param {Array<object>} envelopeItems - An array of environment variables from the Envelope service
50
79
  * @param {enum<any,builds,functions,runtime,post_processing>} scope - The scope of the environment variables
51
80
  * @param {enum<general,account,addons,ui,configFile>} source - The source of the environment variable
@@ -58,7 +87,8 @@ const fetchEnvelopeItems = async function ({ accountId, api, key, siteId }) {
58
87
  * value: 'bar',
59
88
  * },
60
89
  * BAZ: {
61
- * context: 'dev',
90
+ * context: 'branch',
91
+ * branch: 'staging',
62
92
  * scopes: ['runtime'],
63
93
  * sources: ['account'],
64
94
  * value: 'bang',
@@ -68,18 +98,19 @@ const fetchEnvelopeItems = async function ({ accountId, api, key, siteId }) {
68
98
  const formatEnvelopeData = ({ context = 'dev', envelopeItems = [], scope = 'any', source }) =>
69
99
  envelopeItems
70
100
  // filter by context
71
- .filter(({ values }) => Boolean(findValueFromContext(values, context)))
101
+ .filter(({ values }) => Boolean(findValueInValues(values, context)))
72
102
  // filter by scope
73
103
  .filter(({ scopes }) => (scope === 'any' ? true : scopes.includes(scope)))
74
104
  // sort alphabetically, case insensitive
75
105
  .sort((left, right) => (left.key.toLowerCase() < right.key.toLowerCase() ? -1 : 1))
76
106
  // format the data
77
107
  .reduce((acc, cur) => {
78
- const { context: ctx, value } = findValueFromContext(cur.values, context)
108
+ const { context: ctx, context_parameter: branch, value } = findValueInValues(cur.values, context)
79
109
  return {
80
110
  ...acc,
81
111
  [cur.key]: {
82
112
  context: ctx,
113
+ branch,
83
114
  scopes: cur.scopes,
84
115
  sources: [source],
85
116
  value,
@@ -90,7 +121,7 @@ const formatEnvelopeData = ({ context = 'dev', envelopeItems = [], scope = 'any'
90
121
  /**
91
122
  * Collects env vars from multiple sources and arranges them in the correct order of precedence
92
123
  * @param {object} api - The api singleton object
93
- * @param {enum<dev,branch-deploy,deploy-preview,production>} context - The deploy context of the environment variable
124
+ * @param {string} context - The deploy context or branch of the environment variable
94
125
  * @param {object} env - The dictionary of environment variables
95
126
  * @param {string} key - If present, fetch a single key (case-sensitive)
96
127
  * @param {enum<any,builds,functions,runtime,post_processing>} scope - The scope of the environment variables
@@ -130,7 +161,7 @@ const getEnvelopeEnv = async ({ api, context = 'dev', env, key = '', scope = 'an
130
161
  * @returns {string} A human-readable, comma-separated list of scopes
131
162
  */
132
163
  const getHumanReadableScopes = (scopes) => {
133
- const AVAILABLE_SCOPES = {
164
+ const HUMAN_SCOPES = {
134
165
  builds: 'Builds',
135
166
  functions: 'Functions',
136
167
  post_processing: 'Post processing',
@@ -141,11 +172,11 @@ const getHumanReadableScopes = (scopes) => {
141
172
  // env vars specified in netlify.toml are present in the `builds` and `post_processing` scope
142
173
  return 'Builds, Post processing'
143
174
  }
144
- if (scopes.length === Object.keys(AVAILABLE_SCOPES).length) {
175
+ if (scopes.length === Object.keys(HUMAN_SCOPES).length) {
145
176
  // shorthand instead of listing every available scope
146
177
  return 'All'
147
178
  }
148
- return scopes.map((scope) => AVAILABLE_SCOPES[scope]).join(', ')
179
+ return scopes.map((scope) => HUMAN_SCOPES[scope]).join(', ')
149
180
  }
150
181
 
151
182
  /**
@@ -156,7 +187,7 @@ const getHumanReadableScopes = (scopes) => {
156
187
  const translateFromMongoToEnvelope = (env = {}) => {
157
188
  const envVars = Object.entries(env).map(([key, value]) => ({
158
189
  key,
159
- scopes: ['builds', 'functions', 'runtime', 'post_processing'],
190
+ scopes: AVAILABLE_SCOPES,
160
191
  values: [
161
192
  {
162
193
  context: 'all',
@@ -171,14 +202,14 @@ const translateFromMongoToEnvelope = (env = {}) => {
171
202
  /**
172
203
  * Translates an Envelope env into a Mongo env
173
204
  * @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
205
+ * @param {string} context - The deploy context or branch of the environment variable
175
206
  * @returns {object} The env object as compatible with Mongo
176
207
  */
177
208
  const translateFromEnvelopeToMongo = (envVars = [], context = 'dev') =>
178
209
  envVars
179
210
  .sort((left, right) => (left.key.toLowerCase() < right.key.toLowerCase() ? -1 : 1))
180
211
  .reduce((acc, cur) => {
181
- const envVar = cur.values.find((val) => [context, 'all'].includes(val.context))
212
+ const envVar = cur.values.find((val) => [context, 'all'].includes(val.context_parameter || val.context))
182
213
  if (envVar && envVar.value) {
183
214
  return {
184
215
  ...acc,
@@ -189,11 +220,14 @@ const translateFromEnvelopeToMongo = (envVars = [], context = 'dev') =>
189
220
  }, {})
190
221
 
191
222
  module.exports = {
192
- findValueFromContext,
223
+ AVAILABLE_CONTEXTS,
224
+ AVAILABLE_SCOPES,
225
+ findValueInValues,
193
226
  filterEnvBySource,
194
227
  formatEnvelopeData,
195
228
  getEnvelopeEnv,
196
229
  getHumanReadableScopes,
230
+ normalizeContext,
197
231
  translateFromEnvelopeToMongo,
198
232
  translateFromMongoToEnvelope,
199
233
  }