mirror of
https://github.com/zhigang1992/firebase-tools.git
synced 2026-06-13 17:25:43 +08:00
Add support for setting up environment variables for functions using dotenv files. On deploy, Firebase CLI looks for naive dotenv file (`.env`) file or project-specific ones (`.env.<project id>` or `.env.<project alias>`) files, loads environment variables, and injects them on deployed functions. Environment variable set in project-specific dotenv file wins, and you cannot have both `.<project id>` and `<.project alias>` files. Environment variables are also loaded up on Firebase Emulators. Emulator will look for `.env` and `.env.local` files and ignore project-specific dotenv files. We are hiding the feature behind `dotenv` preview flag. We want to get a feeling for the development experience from our users before an official launch + documentations. Also including a small e2e test for env var support. It's meant to run manually by the Firebase team via command `node scripts/test-functions-env.js`.
110 lines
3.3 KiB
JavaScript
Executable File
110 lines
3.3 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
"use strict";
|
|
|
|
/**
|
|
* Integration test for functions env var support. Run:
|
|
* node ./test-functions-env.js <projectId> <region>
|
|
*
|
|
* If parameter ommited:
|
|
* - projectId defaults to `functions-integration-test`
|
|
* - region defaults to `us-central1`
|
|
*/
|
|
|
|
const expect = require("chai").expect;
|
|
const execSync = require("child_process").execSync;
|
|
const fs = require("fs-extra");
|
|
const path = require("path");
|
|
const tmp = require("tmp");
|
|
|
|
const api = require("../lib/api");
|
|
const cloudfunctions = require("../lib/gcp/cloudfunctions");
|
|
const { configstore } = require("../lib/configstore");
|
|
const scopes = require("../lib/scopes");
|
|
|
|
const source = __dirname + "/assets/functions_to_test_minimal.js";
|
|
const functionTarget = "httpsAction";
|
|
const projectId = process.argv[2] || "functions-integration-test";
|
|
const region = process.argv[3] || "us-central1";
|
|
const localFirebase = __dirname + "/../lib/bin/firebase.js";
|
|
const projectDir = __dirname + "/test-project";
|
|
|
|
let tmpDir;
|
|
let functionsSource;
|
|
|
|
function preTest() {
|
|
const dir = tmp.dirSync({ prefix: "envtest_" });
|
|
tmpDir = dir.name;
|
|
functionsSource = tmpDir + "/functions";
|
|
fs.copySync(projectDir, tmpDir);
|
|
execSync("npm install", { cwd: functionsSource, stdio: "ignore", stderr: "ignore" });
|
|
api.setRefreshToken(configstore.get("tokens").refresh_token);
|
|
api.setScopes(scopes.CLOUD_PLATFORM);
|
|
fs.copySync(source, functionsSource + "/index.js");
|
|
execSync(`${localFirebase} --open-sesame dotenv`, { cwd: tmpDir });
|
|
console.log("Done pretest prep.");
|
|
}
|
|
|
|
function postTest() {
|
|
fs.remove(tmpDir);
|
|
execSync(`${localFirebase} functions:delete ${functionTarget} --project=${projectId} -f`);
|
|
console.log("Done post-test cleanup.");
|
|
}
|
|
|
|
async function expectEnvs(envs) {
|
|
const fns = await cloudfunctions.listFunctions(projectId, region);
|
|
const fn = fns.find((fn) => fn.name.includes(functionTarget));
|
|
|
|
const gotEnvs = fn.environmentVariables;
|
|
// Remove system-provided environment variables.
|
|
delete gotEnvs.GCLOUD_PROJECT;
|
|
delete gotEnvs.FIREBASE_CONFIG;
|
|
|
|
expect(gotEnvs).to.be.deep.equals(envs);
|
|
console.log("PASS");
|
|
}
|
|
|
|
async function deployAndCompare(expected) {
|
|
execSync(`${localFirebase} deploy --only functions --project=${projectId}`, { cwd: tmpDir });
|
|
await expectEnvs(expected);
|
|
}
|
|
|
|
async function runTest(description, envFiles, expected) {
|
|
console.log("============================");
|
|
console.log(`Running test: ${description}`);
|
|
|
|
const toCleanup = [];
|
|
for (const [targetFile, data] of Object.entries(envFiles)) {
|
|
const fullPath = path.join(functionsSource, targetFile);
|
|
fs.writeFileSync(fullPath, data);
|
|
toCleanup.push(fullPath);
|
|
}
|
|
try {
|
|
await deployAndCompare(expected);
|
|
} finally {
|
|
for (const f of toCleanup) {
|
|
fs.unlinkSync(f);
|
|
}
|
|
}
|
|
}
|
|
|
|
(async () => {
|
|
try {
|
|
preTest();
|
|
await runTest(
|
|
"Inject environment variables from .env",
|
|
{ ".env": "FOO=foo\nBAR=bar\nCAR=car" },
|
|
{ FOO: "foo", BAR: "bar", CAR: "car" }
|
|
);
|
|
await runTest(
|
|
"Inject environment variables from .env and .env.<project>",
|
|
{ ".env": "FOO=foo\nSOURCE=env", [`.env.${projectId}`]: "SOURCE=env-project" },
|
|
{ FOO: "foo", SOURCE: "env-project" }
|
|
);
|
|
console.log("Success");
|
|
} catch (err) {
|
|
console.log("Error: " + err);
|
|
} finally {
|
|
postTest();
|
|
}
|
|
})();
|