[cli] Change vc env pull default output file to .env.local (#9892)

`vc deploy` ignores `.env.local`. To make sure we don't inadvertently
push people's secrets to source control, have all environment pulls
default to writing to `.env.local`.
This commit is contained in:
Dan Stowell
2023-05-22 17:24:38 -05:00
committed by GitHub
parent c52a59809e
commit 1b0d72aba5
11 changed files with 31 additions and 26 deletions

View File

@@ -0,0 +1,5 @@
---
'vercel': major
---
Change `vc env pull` default output file to `.env.local`

View File

@@ -4,7 +4,7 @@
You ran `vercel dev` inside a project that contains a `vercel.json` file with `env` or `build.env` properties that use [Vercel Secrets](https://vercel.com/docs/concepts/projects/environment-variables).
In order to use environment variables in your project locally that have values defined using the Vercel Secrets format (e.g. `@my-secret-value`), you will need to provide the value as an environment variable using a `.env`.
In order to use environment variables in your project locally that have values defined using the Vercel Secrets format (e.g. `@my-secret-value`), you will need to provide the value as an environment variable using a `.env.local`.
We require this to ensure your app works as you intend it to, in the development environment, and to provide you with a way to mirror or separate private environment variables within your applications, for example when connecting to a database.
@@ -12,11 +12,11 @@ Read below for how to address this error.
#### Possible Ways to Fix It
The error message will list environment variables that are required and which file they are required to be included in `.env`.
The error message will list environment variables that are required and which file they are required to be included in `.env.local`.
If the file does not exist yet, please create the file that the error message mentions and insert the missing environment variable into it.
For example, if the error message shows that the environment variable `TEST` is missing from `.env`, then the `.env` file should look like this:
For example, if the error message shows that the environment variable `TEST` is missing from `.env.local`, then the `.env.local` file should look like this:
```
TEST=value

View File

@@ -26,7 +26,7 @@ const help = () => {
ls [environment] [gitbranch] List all variables for the specified Environment
add [name] [environment] [gitbranch] Add an Environment Variable (see examples below)
rm [name] [environment] [gitbranch] Remove an Environment Variable (see examples below)
pull [filename] Pull all Development Environment Variables from the cloud and write to a file [.env]
pull [filename] Pull all Development Environment Variables from the cloud and write to a file [.env.local]
${chalk.dim('Options:')}

View File

@@ -67,7 +67,7 @@ export default async function pull(
}
// handle relative or absolute filename
const [filename = '.env'] = args;
const [filename = '.env.local'] = args;
const fullPath = resolve(cwd, filename);
const skipConfirmation = opts['--yes'];
const gitBranch = opts['--git-branch'];

View File

@@ -751,9 +751,9 @@ test('Deploy `api-env` fixture and test `vercel env` command', async () => {
);
expect(exitCode, formatOutput({ stdout, stderr })).toBe(0);
expect(stderr).toMatch(/Created .env file/gm);
expect(stderr).toMatch(/Created .env.local file/gm);
const contents = fs.readFileSync(path.join(target, '.env'), 'utf8');
const contents = fs.readFileSync(path.join(target, '.env.local'), 'utf8');
expect(contents).toMatch(/^# Created by Vercel CLI\n/);
expect(contents).toMatch(/MY_NEW_ENV_VAR="my plaintext value"/);
expect(contents).toMatch(/MY_STDIN_VAR="{"expect":"quotes"}"/);
@@ -771,12 +771,12 @@ test('Deploy `api-env` fixture and test `vercel env` command', async () => {
);
expect(exitCode, formatOutput({ stdout, stderr })).toBe(0);
expect(stderr).toMatch(/Overwriting existing .env file/gm);
expect(stderr).toMatch(/Updated .env file/gm);
expect(stderr).toMatch(/Overwriting existing .env.local file/gm);
expect(stderr).toMatch(/Updated .env.local file/gm);
}
async function vcEnvPullConfirm() {
fs.writeFileSync(path.join(target, '.env'), 'hahaha');
fs.writeFileSync(path.join(target, '.env.local'), 'hahaha');
const vc = execCli(binaryPath, ['env', 'pull'], {
cwd: target,
@@ -784,7 +784,7 @@ test('Deploy `api-env` fixture and test `vercel env` command', async () => {
await waitForPrompt(
vc,
'Found existing file ".env". Do you want to overwrite?'
'Found existing file ".env.local". Do you want to overwrite?'
);
vc.stdin?.end('y\n');
@@ -904,7 +904,7 @@ test('Deploy `api-env` fixture and test `vercel env` command', async () => {
expect(exitCode, formatOutput({ stdout, stderr })).toBe(0);
const contents = fs.readFileSync(path.join(target, '.env'), 'utf8');
const contents = fs.readFileSync(path.join(target, '.env.local'), 'utf8');
const lines = new Set(contents.split('\n'));
@@ -1024,11 +1024,11 @@ test('Deploy `api-env` fixture and test `vercel env` command', async () => {
await vcEnvPullConfirm();
await vcDeployWithVar();
await vcDevWithEnv();
fs.unlinkSync(path.join(target, '.env'));
fs.unlinkSync(path.join(target, '.env.local'));
await vcDevAndFetchCloudVars();
await enableAutoExposeSystemEnvs();
await vcEnvPullFetchSystemVars();
fs.unlinkSync(path.join(target, '.env'));
fs.unlinkSync(path.join(target, '.env.local'));
await vcDevAndFetchSystemVars();
await vcEnvRemove();
await vcEnvRemoveWithArgs();

View File

@@ -24,10 +24,10 @@ describe('env', () => {
await expect(client.stderr).toOutput(
'Downloading `development` Environment Variables for Project vercel-env-pull'
);
await expect(client.stderr).toOutput('Created .env file');
await expect(client.stderr).toOutput('Created .env.local file');
await expect(exitCodePromise).resolves.toEqual(0);
const rawDevEnv = await fs.readFile(path.join(cwd, '.env'));
const rawDevEnv = await fs.readFile(path.join(cwd, '.env.local'));
// check for development env value
const devFileHasDevEnv = rawDevEnv.toString().includes('SPECIAL_FLAG');
@@ -56,11 +56,11 @@ describe('env', () => {
await expect(client.stderr).toOutput(
'Downloading `preview` Environment Variables for Project vercel-env-pull'
);
await expect(client.stderr).toOutput('Created .env file');
await expect(client.stderr).toOutput('Created .env.local file');
await expect(exitCodePromise).resolves.toEqual(0);
// check for Preview env vars
const rawDevEnv = await fs.readFile(path.join(cwd, '.env'), 'utf8');
const rawDevEnv = await fs.readFile(path.join(cwd, '.env.local'), 'utf8');
expect(rawDevEnv).toContain(
'REDIS_CONNECTION_STRING="redis://abc123@redis.example.com:6379"'
);
@@ -93,11 +93,11 @@ describe('env', () => {
await expect(client.stderr).toOutput(
'Downloading `preview` Environment Variables for Project vercel-env-pull'
);
await expect(client.stderr).toOutput('Created .env file');
await expect(client.stderr).toOutput('Created .env.local file');
await expect(exitCodePromise).resolves.toEqual(0);
// check for Preview env vars
const rawDevEnv = await fs.readFile(path.join(cwd, '.env'), 'utf8');
const rawDevEnv = await fs.readFile(path.join(cwd, '.env.local'), 'utf8');
expect(rawDevEnv).toContain(
'REDIS_CONNECTION_STRING="redis://abc123@redis.example.com:6379"'
);
@@ -159,10 +159,10 @@ describe('env', () => {
await expect(client.stderr).toOutput(
`Downloading \`production\` Environment Variables for Project vercel-env-pull`
);
await expect(client.stderr).toOutput('Created .env file');
await expect(client.stderr).toOutput('Created .env.local file');
await expect(exitCodePromise).resolves.toEqual(0);
const rawProdEnv = await fs.readFile(path.join(cwd, '.env'));
const rawProdEnv = await fs.readFile(path.join(cwd, '.env.local'));
// check for development env value
const envFileHasEnv = rawProdEnv
@@ -261,7 +261,7 @@ describe('env', () => {
await expect(client.stderr).toOutput(
'+ SPECIAL_FLAG (Updated)\n+ NEW_VAR\n- TEST\n'
);
await expect(client.stderr).toOutput('Updated .env file');
await expect(client.stderr).toOutput('Updated .env.local file');
await expect(pullPromise).resolves.toEqual(0);
} finally {
@@ -282,7 +282,7 @@ describe('env', () => {
client.setArgv('env', 'pull', '--yes', '--cwd', cwd);
const pullPromise = env(client);
await expect(client.stderr).toOutput('Updated .env file');
await expect(client.stderr).toOutput('Updated .env.local file');
await expect(pullPromise).resolves.toEqual(0);
});
@@ -299,7 +299,7 @@ describe('env', () => {
client.setArgv('env', 'pull', '--yes', '--cwd', cwd);
const pullPromise = env(client);
await expect(client.stderr).toOutput('> No changes found.');
await expect(client.stderr).toOutput('Updated .env file');
await expect(client.stderr).toOutput('Updated .env.local file');
await expect(pullPromise).resolves.toEqual(0);
});
@@ -335,7 +335,7 @@ describe('env', () => {
'Downloading `development` Environment Variables for Project env-pull-delta'
);
await expect(client.stderr).toOutput('No changes found.\n');
await expect(client.stderr).toOutput('Updated .env file');
await expect(client.stderr).toOutput('Updated .env.local file');
await expect(pullPromise).resolves.toEqual(0);
} finally {