Skip to content

Commit

Permalink
Load project-specific environment variables in the Functions Emulator (
Browse files Browse the repository at this point in the history
…#4273)

Today, Functions Emulator does not load project-specific environment variables. This contradicts the public documentation which states:

> When using a local Cloud Functions emulator, you can override environment variables for your project by setting up a .env.local file. Contents of .env.local take precedence over .env and the project-specific .env file.

https://firebase.google.com/docs/functions/config-env#emulator_support

The patch fixes the bug by making appropriate changes to load project-specific environment variables (either in `.env.projectId` or `.env.projectAlias`) when emulating functions.

Fixes #4239
  • Loading branch information
taeold committed Mar 14, 2022
1 parent f11e998 commit 0c897b3
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 5 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
- Adds --local flag to ext:install, ext:update, ext:configure, and ext:uninstall, to save changes to firebase.json instead of deploying immediately.
- `ext:export` now uses stable ordering for params in .env files (#4256).
- Adds alerting event provider (#4258).
- Fixes bug where project-specific environment variables weren't loaded by the Functions Emulator (#4273).
1 change: 1 addition & 0 deletions src/emulator/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,7 @@ export async function startAll(options: EmulatorOptions, showUI: boolean = true)
host: functionsAddr.host,
port: functionsAddr.port,
debugPort: inspectFunctions,
projectAlias: options.projectAlias,
});
await startEmulator(functionsEmulator);
}
Expand Down
2 changes: 2 additions & 0 deletions src/emulator/functionsEmulator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ export interface FunctionsEmulatorArgs {
debugPort?: number;
remoteEmulators?: { [key: string]: EmulatorInfo };
adminSdkConfig?: AdminSdkConfig;
projectAlias?: string;
}

// FunctionsRuntimeInstance is the handler for a running function invocation
Expand Down Expand Up @@ -944,6 +945,7 @@ export class FunctionsEmulator implements EmulatorInstance {
const projectInfo = {
functionsSource: backend.functionsDir,
projectId: this.args.projectId,
projectAlias: this.args.projectAlias,
isEmulator: true,
};

Expand Down
9 changes: 4 additions & 5 deletions src/functions/env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,13 +196,12 @@ function findEnvfiles(
isEmulator?: boolean
): string[] {
const files: string[] = [".env"];
files.push(`.env.${projectId}`);
if (projectAlias) {
files.push(`.env.${projectAlias}`);
}
if (isEmulator) {
files.push(FUNCTIONS_EMULATOR_DOTENV);
} else {
files.push(`.env.${projectId}`);
if (projectAlias && projectAlias.length) {
files.push(`.env.${projectAlias}`);
}
}

return files
Expand Down
1 change: 1 addition & 0 deletions src/serve/functions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export class FunctionsServer {
projectId,
projectDir: options.config.projectDir,
emulatableBackends: [this.backend],
projectAlias: options.projectAlias,
account,
...partialArgs,
};
Expand Down
56 changes: 56 additions & 0 deletions src/test/functions/env.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,20 @@ FOO=foo
});
});

it("loads envs, preferring ones from .env.<project> for emulators too", () => {
createEnvFiles(tmpdir, {
".env": "FOO=bad\nBAR=bar",
[`.env.${projectInfo.projectId}`]: "FOO=good",
});

expect(
env.loadUserEnvs({ ...projectInfo, functionsSource: tmpdir, isEmulator: true })
).to.be.deep.equal({
FOO: "good",
BAR: "bar",
});
});

it("loads envs, preferring ones from .env.<alias>", () => {
createEnvFiles(tmpdir, {
".env": "FOO=bad\nBAR=bar",
Expand All @@ -340,6 +354,48 @@ FOO=foo
});
});

it("loads envs, preferring ones from .env.<alias> for emulators too", () => {
createEnvFiles(tmpdir, {
".env": "FOO=bad\nBAR=bar",
[`.env.${projectInfo.projectAlias}`]: "FOO=good",
});

expect(
env.loadUserEnvs({ ...projectInfo, functionsSource: tmpdir, isEmulator: true })
).to.be.deep.equal({
FOO: "good",
BAR: "bar",
});
});

it("loads envs ignoring .env.local", () => {
createEnvFiles(tmpdir, {
".env": "FOO=bad\nBAR=bar",
[`.env.${projectInfo.projectId}`]: "FOO=good",
".env.local": "FOO=bad",
});

expect(env.loadUserEnvs({ ...projectInfo, functionsSource: tmpdir })).to.be.deep.equal({
FOO: "good",
BAR: "bar",
});
});

it("loads envs, preferring .env.local for the emulator", () => {
createEnvFiles(tmpdir, {
".env": "FOO=bad\nBAR=bar",
[`.env.${projectInfo.projectId}`]: "FOO=another bad",
".env.local": "FOO=good",
});

expect(
env.loadUserEnvs({ ...projectInfo, functionsSource: tmpdir, isEmulator: true })
).to.be.deep.equal({
FOO: "good",
BAR: "bar",
});
});

it("throws an error if both .env.<project> and .env.<alias> exists", () => {
createEnvFiles(tmpdir, {
".env": "FOO=foo\nBAR=bar",
Expand Down

0 comments on commit 0c897b3

Please sign in to comment.