Skip to content

Commit

Permalink
feat: support branch values for environment variable contexts (#4977)
Browse files Browse the repository at this point in the history
* feat: support branch values in env:list

* feat: support branch values in env:get

* feat: support branch values for contexts in build and dev

* feat: support branch values for contexts in env:set

* feat: support branch values for contexts in env:unset

* test: fix some tests

* fix: remove cruft

* docs: npm run docs

* chore: update logs to print either `context` or `branch` correctly

* test: update tests

* fix: fix example help text in `env:get --help`

* fix: fix netlify/pillar-workflow#818

* fix: fix netlify/pillar-workflow#815

* fix: fix netlify/pillar-workflow#816 and fix netlify/pillar-workflow#817

* docs: addressing uma's feedback

* chore: update contributors field

Co-authored-by: jasonbarry <jasonbarry@users.noreply.github.com>
  • Loading branch information
jasonbarry and jasonbarry committed Aug 22, 2022
1 parent 2c337b0 commit f434f57
Show file tree
Hide file tree
Showing 13 changed files with 220 additions and 81 deletions.
2 changes: 1 addition & 1 deletion docs/commands/build.md
Expand Up @@ -15,7 +15,7 @@ netlify build

**Flags**

- `context` (*string*) - Specify a build context
- `context` (*string*) - Specify a build context or branch (contexts: "production", "deploy-preview", "branch-deploy", "dev")
- `dry` (*boolean*) - Dry run: show instructions without running them
- `offline` (*boolean*) - disables any features that require network access
- `debug` (*boolean*) - Print debugging information
Expand Down
4 changes: 2 additions & 2 deletions docs/commands/dev.md
Expand Up @@ -18,7 +18,7 @@ netlify dev
**Flags**

- `command` (*string*) - command to run
- `context` (*production | deploy-preview | branch-deploy | dev*) - Specify a deploy context for environment variables
- `context` (*string*) - Specify a deploy context or branch for environment variables (contexts: "production", "deploy-preview", "branch-deploy", "dev")
- `country` (*string*) - Two-letter country code (https://ntl.fyi/country-codes) to use as mock geolocation (enables --geo=mock automatically)
- `dir` (*string*) - dir with static files
- `edgeInspect` (*string*) - enable the V8 Inspector Protocol for Edge Functions, with an optional address in the host:port format
Expand Down Expand Up @@ -74,7 +74,7 @@ netlify dev:exec

**Flags**

- `context` (*production | deploy-preview | branch-deploy | dev*) - Specify a deploy context for environment variables
- `context` (*string*) - Specify a deploy context or branch for environment variables (contexts: "production", "deploy-preview", "branch-deploy", "dev")
- `debug` (*boolean*) - Print debugging information
- `httpProxy` (*string*) - Proxy server address to route requests through.
- `httpProxyCertificateFilename` (*string*) - Certificate file to use when connecting using a proxy server
Expand Down
26 changes: 22 additions & 4 deletions docs/commands/env.md
Expand Up @@ -84,12 +84,21 @@ netlify env:get

**Flags**

- `context` (*production | deploy-preview | branch-deploy | dev*) - Specify a deploy context
- `context` (*string*) - Specify a deploy context or branch (contexts: "production", "deploy-preview", "branch-deploy", "dev")
- `scope` (*builds | functions | post_processing | runtime | any*) - Specify a scope
- `debug` (*boolean*) - Print debugging information
- `httpProxy` (*string*) - Proxy server address to route requests through.
- `httpProxyCertificateFilename` (*string*) - Certificate file to use when connecting using a proxy server

**Examples**

```bash
netlify env:get MY_VAR # get value for MY_VAR in dev context
netlify env:get MY_VAR --context production
netlify env:get MY_VAR --context branch:staging
netlify env:get MY_VAR --scope functions
```

---
## `env:import`

Expand Down Expand Up @@ -125,12 +134,21 @@ netlify env:list

**Flags**

- `context` (*production | deploy-preview | branch-deploy | dev*) - Specify a deploy context
- `context` (*string*) - Specify a deploy context or branch (contexts: "production", "deploy-preview", "branch-deploy", "dev")
- `scope` (*builds | functions | post_processing | runtime | any*) - Specify a scope
- `debug` (*boolean*) - Print debugging information
- `httpProxy` (*string*) - Proxy server address to route requests through.
- `httpProxyCertificateFilename` (*string*) - Certificate file to use when connecting using a proxy server

**Examples**

```bash
netlify env:list # list variables with values in the dev context and with any scope
netlify env:list --context production
netlify env:list --context branch:staging
netlify env:list --scope functions
```

---
## `env:set`

Expand All @@ -149,7 +167,7 @@ netlify env:set

**Flags**

- `context` (*production | deploy-preview | branch-deploy | dev*) - Specify a deploy context (default: all contexts)
- `context` (*string*) - Specify a deploy context or branch (contexts: "production", "deploy-preview", "branch-deploy", "dev") (default: all contexts)
- `scope` (*builds | functions | post_processing | runtime*) - Specify a scope (default: all scopes)
- `debug` (*boolean*) - Print debugging information
- `httpProxy` (*string*) - Proxy server address to route requests through.
Expand Down Expand Up @@ -182,7 +200,7 @@ netlify env:unset

**Flags**

- `context` (*production | deploy-preview | branch-deploy | dev*) - Specify a deploy context (default: all contexts)
- `context` (*string*) - Specify a deploy context or branch (contexts: "production", "deploy-preview", "branch-deploy", "dev") (default: all contexts)
- `debug` (*boolean*) - Print debugging information
- `httpProxy` (*string*) - Proxy server address to route requests through.
- `httpProxyCertificateFilename` (*string*) - Certificate file to use when connecting using a proxy server
Expand Down
1 change: 1 addition & 0 deletions package.json
Expand Up @@ -46,6 +46,7 @@
"Erez Rokah (https://www.erezro.com)",
"Erica Pisani <pisani.erica@gmail.com>",
"Evans Hauser (https://twitter.com/evanshauser)",
"Ewan Valentine <ewan.valentine89@gmail.com> (http://ewanvalentine.io)",
"Finn Woelm (https://twitter.com/FinnWoelm)",
"Flxbot",
"Gavin Henderson <gavin.henderson@hotmail.co.uk> (https://twitter.com/gavinhenderson5)",
Expand Down
9 changes: 7 additions & 2 deletions src/commands/build/build.js
Expand Up @@ -2,7 +2,7 @@ const process = require('process')

// @ts-check
const { getBuildOptions, runBuild } = require('../../lib/build')
const { error, exit, generateNetlifyGraphJWT, getEnvelopeEnv, getToken } = require('../../utils')
const { error, exit, generateNetlifyGraphJWT, getEnvelopeEnv, getToken, normalizeContext } = require('../../utils')

/**
* @param {import('../../lib/build').BuildConfig} options
Expand Down Expand Up @@ -85,7 +85,12 @@ const createBuildCommand = (program) =>
program
.command('build')
.description('(Beta) Build on your local machine')
.option('--context <context>', 'Specify a build context', process.env.CONTEXT || 'production')
.option(
'--context <context>',
'Specify a build context or branch (contexts: "production", "deploy-preview", "branch-deploy", "dev")',
normalizeContext,
process.env.CONTEXT || 'production',
)
.option('--dry', 'Dry run: show instructions without running them', false)
.option('-o, --offline', 'disables any features that require network access', false)
.addExamples(['netlify build'])
Expand Down
12 changes: 6 additions & 6 deletions src/commands/dev/dev-exec.js
@@ -1,7 +1,6 @@
const { Option } = require('commander')
const execa = require('execa')

const { getEnvelopeEnv, injectEnvVariables } = require('../../utils')
const { getEnvelopeEnv, injectEnvVariables, normalizeContext } = require('../../utils')

/**
* The dev:exec command
Expand Down Expand Up @@ -32,10 +31,11 @@ const createDevExecCommand = (program) =>
program
.command('dev:exec')
.argument('<...cmd>', `the command that should be executed`)
.addOption(
new Option('--context <context>', 'Specify a deploy context for environment variables')
.choices(['production', 'deploy-preview', 'branch-deploy', 'dev'])
.default('dev'),
.option(
'--context <context>',
'Specify a deploy context or branch for environment variables (contexts: "production", "deploy-preview", "branch-deploy", "dev")',
normalizeContext,
'dev',
)
.description(
'Exec command\nRuns a command within the netlify dev environment, e.g. with env variables from any installed addons',
Expand Down
10 changes: 6 additions & 4 deletions src/commands/dev/dev.js
Expand Up @@ -45,6 +45,7 @@ const {
injectEnvVariables,
log,
normalizeConfig,
normalizeContext,
openBrowser,
processOnExit,
startLiveTunnel,
Expand Down Expand Up @@ -684,10 +685,11 @@ const createDevCommand = (program) => {
`Local dev server\nThe dev command will run a local dev server with Netlify's proxy and redirect rules`,
)
.option('-c ,--command <command>', 'command to run')
.addOption(
new Option('--context <context>', 'Specify a deploy context for environment variables')
.choices(['production', 'deploy-preview', 'branch-deploy', 'dev'])
.default('dev'),
.option(
'--context <context>',
'Specify a deploy context or branch for environment variables (contexts: "production", "deploy-preview", "branch-deploy", "dev")',
normalizeContext,
'dev',
)
.option('-p ,--port <port>', 'port of netlify dev', (value) => Number.parseInt(value))
.option('--targetPort <port>', 'port of target app server', (value) => Number.parseInt(value))
Expand Down
20 changes: 14 additions & 6 deletions src/commands/env/env-get.js
@@ -1,7 +1,7 @@
// @ts-check
const { Option } = require('commander')

const { chalk, error, getEnvelopeEnv, log, logJson } = require('../../utils')
const { AVAILABLE_CONTEXTS, chalk, error, getEnvelopeEnv, log, logJson, normalizeContext } = require('../../utils')

/**
* The env:get command
Expand Down Expand Up @@ -42,7 +42,8 @@ const envGet = async (name, options, command) => {
}

if (!value) {
const withContext = `in the ${chalk.magenta(context)} context`
const contextType = AVAILABLE_CONTEXTS.includes(context) ? 'context' : 'branch'
const withContext = `in the ${chalk.magenta(context)} ${contextType}`
const withScope = scope === 'any' ? '' : ` and the ${chalk.magenta(scope)} scope`
log(`No value set ${withContext}${withScope} for environment variable ${chalk.yellow(name)}`)
return false
Expand All @@ -60,16 +61,23 @@ const createEnvGetCommand = (program) =>
program
.command('env:get')
.argument('<name>', 'Environment variable name')
.addOption(
new Option('-c, --context <context>', 'Specify a deploy context')
.choices(['production', 'deploy-preview', 'branch-deploy', 'dev'])
.default('dev'),
.option(
'-c, --context <context>',
'Specify a deploy context or branch (contexts: "production", "deploy-preview", "branch-deploy", "dev")',
normalizeContext,
'dev',
)
.addOption(
new Option('-s, --scope <scope>', 'Specify a scope')
.choices(['builds', 'functions', 'post_processing', 'runtime', 'any'])
.default('any'),
)
.addExamples([
'netlify env:get MY_VAR # get value for MY_VAR in dev context',
'netlify env:get MY_VAR --context production',
'netlify env:get MY_VAR --context branch:staging',
'netlify env:get MY_VAR --scope functions',
])
.description('Get resolved value of specified environment variable (includes netlify.toml)')
.action(async (name, options, command) => {
await envGet(name, options, command)
Expand Down
29 changes: 23 additions & 6 deletions src/commands/env/env-list.js
Expand Up @@ -5,7 +5,16 @@ const { Option } = require('commander')
const inquirer = require('inquirer')
const isEmpty = require('lodash/isEmpty')

const { chalk, error, getEnvelopeEnv, getHumanReadableScopes, log, logJson } = require('../../utils')
const {
AVAILABLE_CONTEXTS,
chalk,
error,
getEnvelopeEnv,
getHumanReadableScopes,
log,
logJson,
normalizeContext,
} = require('../../utils')

const [logUpdatePromise, ansiEscapesPromise] = [import('log-update'), import('ansi-escapes')]

Expand Down Expand Up @@ -77,7 +86,8 @@ const envList = async (options, command) => {
}

const forSite = `for site ${chalk.green(siteInfo.name)}`
const withContext = isUsingEnvelope ? `in the ${chalk.magenta(options.context)} context` : ''
const contextType = AVAILABLE_CONTEXTS.includes(context) ? 'context' : 'branch'
const withContext = isUsingEnvelope ? `in the ${chalk.magenta(options.context)} ${contextType}` : ''
const withScope = isUsingEnvelope && scope !== 'any' ? `and ${chalk.yellow(options.scope)} scope` : ''
if (isEmpty(environment)) {
log(`No environment variables set ${forSite} ${withContext} ${withScope}`)
Expand Down Expand Up @@ -122,16 +132,23 @@ const envList = async (options, command) => {
const createEnvListCommand = (program) =>
program
.command('env:list')
.addOption(
new Option('-c, --context <context>', 'Specify a deploy context')
.choices(['production', 'deploy-preview', 'branch-deploy', 'dev'])
.default('dev'),
.option(
'-c, --context <context>',
'Specify a deploy context or branch (contexts: "production", "deploy-preview", "branch-deploy", "dev")',
normalizeContext,
'dev',
)
.addOption(
new Option('-s, --scope <scope>', 'Specify a scope')
.choices(['builds', 'functions', 'post_processing', 'runtime', 'any'])
.default('any'),
)
.addExamples([
'netlify env:list # list variables with values in the dev context and with any scope',
'netlify env:list --context production',
'netlify env:list --context branch:staging',
'netlify env:list --scope functions',
])
.description('Lists resolved environment variables for site (includes netlify.toml)')
.action(async (options, command) => {
await envList(options, command)
Expand Down
33 changes: 21 additions & 12 deletions src/commands/env/env-set.js
@@ -1,9 +1,16 @@
// @ts-check
const { Option } = require('commander')

const { chalk, error, log, logJson, translateFromEnvelopeToMongo } = require('../../utils')

const AVAILABLE_SCOPES = ['builds', 'functions', 'runtime', 'post_processing']
const {
AVAILABLE_CONTEXTS,
AVAILABLE_SCOPES,
chalk,
error,
log,
logJson,
normalizeContext,
translateFromEnvelopeToMongo,
} = require('../../utils')

/**
* The env:set command
Expand Down Expand Up @@ -52,10 +59,11 @@ const envSet = async (key, value, options, command) => {
}

const withScope = scope ? ` scoped to ${chalk.white(scope)}` : ''
const contextType = AVAILABLE_CONTEXTS.includes(context || 'all') ? 'context' : 'branch'
log(
`Set environment variable ${chalk.yellow(`${key}${value ? '=' : ''}${value}`)}${withScope} in the ${chalk.magenta(
context || 'all',
)} context`,
)} ${contextType}`,
)
}

Expand Down Expand Up @@ -93,7 +101,10 @@ const setInEnvelope = async ({ api, context, key, scope, siteInfo, value }) => {
const contexts = context || ['all']
const scopes = scope || AVAILABLE_SCOPES

let values = contexts.map((ctx) => ({ context: ctx, value }))
// if the passed context is unknown, it is actually a branch name
let values = contexts.map((ctx) =>
AVAILABLE_CONTEXTS.includes(ctx) ? { context: ctx, value } : { context: 'branch', context_parameter: ctx, value },
)

const existing = envelopeVariables.find((envVar) => envVar.key === key)

Expand Down Expand Up @@ -144,13 +155,11 @@ const createEnvSetCommand = (program) =>
.command('env:set')
.argument('<key>', 'Environment variable key')
.argument('[value]', 'Value to set to', '')
.addOption(
new Option('-c, --context <context...>', 'Specify a deploy context (default: all contexts)').choices([
'production',
'deploy-preview',
'branch-deploy',
'dev',
]),
.option(
'-c, --context <context...>',
'Specify a deploy context or branch (contexts: "production", "deploy-preview", "branch-deploy", "dev") (default: all contexts)',
// spread over an array for variadic options
(context, previous = []) => [...previous, normalizeContext(context)],
)
.addOption(
new Option('-s, --scope <scope...>', 'Specify a scope (default: all scopes)').choices([
Expand Down

1 comment on commit f434f57

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📊 Benchmark results

Package size: 222 MB

Please sign in to comment.