Skip to content

Commit 807f57a

Browse files
Berliozchristhompsongoogle
authored andcommitted
Make FirebaseConfig properties available as internal parameters (#4970)
1 parent 0020354 commit 807f57a

File tree

6 files changed

+212
-35
lines changed

6 files changed

+212
-35
lines changed

src/deploy/functions/build.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { previews } from "../../previews";
66
import { FirebaseError } from "../../error";
77
import { assertExhaustive, mapObject, nullsafeVisitor } from "../../functional";
88
import { UserEnvsOpts, writeUserEnvs } from "../../functions/env";
9+
import { FirebaseConfig } from "./args";
910

1011
/* The union of a customer-controlled deployment and potentially deploy-time defined parameters */
1112
export interface Build {
@@ -274,24 +275,24 @@ export type Endpoint = Triggered & {
274275
*/
275276
export async function resolveBackend(
276277
build: Build,
278+
firebaseConfig: FirebaseConfig,
277279
userEnvOpt: UserEnvsOpts,
278280
userEnvs: Record<string, string>,
279281
nonInteractive?: boolean
280282
): Promise<{ backend: backend.Backend; envs: Record<string, params.ParamValue> }> {
281-
const projectId = userEnvOpt.projectId;
282283
let paramValues: Record<string, params.ParamValue> = {};
283284
if (previews.functionsparams) {
284285
paramValues = await params.resolveParams(
285286
build.params,
286-
projectId,
287+
firebaseConfig,
287288
envWithTypes(build.params, userEnvs),
288289
nonInteractive
289290
);
290291

291292
const toWrite: Record<string, string> = {};
292293
for (const paramName of Object.keys(paramValues)) {
293294
const paramValue = paramValues[paramName];
294-
if (Object.prototype.hasOwnProperty.call(userEnvs, paramName) || paramValue.secret) {
295+
if (Object.prototype.hasOwnProperty.call(userEnvs, paramName) || paramValue.internal) {
295296
continue;
296297
}
297298
toWrite[paramName] = paramValue.toString();

src/deploy/functions/params.ts

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { assertExhaustive, partition } from "../../functional";
66
import * as secretManager from "../../gcp/secretManager";
77
import { listBuckets } from "../../gcp/storage";
88
import { isCelExpression, resolveExpression } from "./cel";
9+
import { FirebaseConfig } from "./args";
910

1011
// A convinience type containing options for Prompt's select
1112
interface ListItem {
@@ -104,12 +105,21 @@ type ParamBase<T extends string | number | boolean> = {
104105
input?: ParamInput<T>;
105106
};
106107

108+
/**
109+
* Determines whether an Input field value can be coerced to TextInput.
110+
*/
107111
export function isTextInput<T>(input: ParamInput<T>): input is TextInput<T> {
108112
return {}.hasOwnProperty.call(input, "text");
109113
}
114+
/**
115+
* Determines whether an Input field value can be coerced to SelectInput.
116+
*/
110117
export function isSelectInput<T>(input: ParamInput<T>): input is SelectInput<T> {
111118
return {}.hasOwnProperty.call(input, "select");
112119
}
120+
/**
121+
* Determines whether an Input field value can be coerced to ResourceInput.
122+
*/
113123
export function isResourceInput<T>(input: ParamInput<T>): input is ResourceInput {
114124
return {}.hasOwnProperty.call(input, "resource");
115125
}
@@ -199,7 +209,7 @@ export class ParamValue {
199209

200210
constructor(
201211
private readonly rawValue: string,
202-
readonly secret: boolean,
212+
readonly internal: boolean,
203213
types: { string?: boolean; boolean?: boolean; number?: boolean }
204214
) {
205215
this.legalString = types.string || false;
@@ -236,8 +246,7 @@ function resolveDefaultCEL(
236246
): RawParamValue {
237247
const deps = dependenciesCEL(expr);
238248
const allDepsFound = deps.every((dep) => !!currentEnv[dep]);
239-
const dependsOnSecret = deps.some((dep) => currentEnv[dep].secret);
240-
if (!allDepsFound || dependsOnSecret) {
249+
if (!allDepsFound) {
241250
throw new FirebaseError(
242251
"Build specified parameter with un-resolvable default value " +
243252
expr +
@@ -288,11 +297,11 @@ function canSatisfyParam(param: Param, value: RawParamValue): boolean {
288297
*/
289298
export async function resolveParams(
290299
params: Param[],
291-
projectId: string,
300+
firebaseConfig: FirebaseConfig,
292301
userEnvs: Record<string, ParamValue>,
293302
nonInteractive?: boolean
294303
): Promise<Record<string, ParamValue>> {
295-
const paramValues: Record<string, ParamValue> = {};
304+
const paramValues: Record<string, ParamValue> = populateDefaultParams(firebaseConfig);
296305

297306
// TODO(vsfan@): should we ever reject param values from .env files based on the appearance of the string?
298307
const [resolved, outstanding] = partition(params, (param) => {
@@ -304,7 +313,7 @@ export async function resolveParams(
304313

305314
const [needSecret, needPrompt] = partition(outstanding, (param) => param.type === "secret");
306315
for (const param of needSecret) {
307-
await handleSecret(param as SecretParam, projectId);
316+
await handleSecret(param as SecretParam, firebaseConfig.projectId);
308317
}
309318

310319
if (nonInteractive && needPrompt.length > 0) {
@@ -326,12 +335,41 @@ export async function resolveParams(
326335
"Parameter " + param.name + " has default value " + paramDefault + " of wrong type"
327336
);
328337
}
329-
paramValues[param.name] = await promptParam(param, projectId, paramDefault);
338+
paramValues[param.name] = await promptParam(param, firebaseConfig.projectId, paramDefault);
330339
}
331340

332341
return paramValues;
333342
}
334343

344+
function populateDefaultParams(config: FirebaseConfig): Record<string, ParamValue> {
345+
const defaultParams: Record<string, ParamValue> = {};
346+
if (config.databaseURL !== "") {
347+
defaultParams["DATABASE_URL"] = new ParamValue(config.databaseURL, true, {
348+
string: true,
349+
boolean: false,
350+
number: false,
351+
});
352+
}
353+
defaultParams["PROJECT_ID"] = new ParamValue(config.projectId, true, {
354+
string: true,
355+
boolean: false,
356+
number: false,
357+
});
358+
defaultParams["GCLOUD_PROJECT"] = new ParamValue(config.projectId, true, {
359+
string: true,
360+
boolean: false,
361+
number: false,
362+
});
363+
if (config.storageBucket !== "") {
364+
defaultParams["STORAGE_BUCKET"] = new ParamValue(config.storageBucket, true, {
365+
string: true,
366+
boolean: false,
367+
number: false,
368+
});
369+
}
370+
return defaultParams;
371+
}
372+
335373
/**
336374
* Handles a SecretParam by checking for the presence of a corresponding secret
337375
* in Cloud Secrets Manager. If not present, we currently ask the user to

src/deploy/functions/prepare.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ export async function prepare(
118118
const wantBuild: build.Build = await runtimeDelegate.discoverBuild(runtimeConfig, firebaseEnvs);
119119
const { backend: wantBackend, envs: resolvedEnvs } = await build.resolveBackend(
120120
wantBuild,
121+
firebaseConfig,
121122
userEnvOpt,
122123
userEnvs,
123124
options.nonInteractive
@@ -129,6 +130,7 @@ export async function prepare(
129130
const envValue = resolvedEnvs[envName]?.toString();
130131
if (
131132
envValue &&
133+
!resolvedEnvs[envName].internal &&
132134
!Object.prototype.hasOwnProperty.call(wantBackend.environmentVariables, envName)
133135
) {
134136
wantBackend.environmentVariables[envName] = envValue;

src/emulator/functionsEmulator.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -455,10 +455,11 @@ export class FunctionsEmulator implements EmulatorInstance {
455455
await runtimeDelegate.build();
456456
logger.debug(`Analyzing ${runtimeDelegate.name} backend spec`);
457457
// Don't include user envs when parsing triggers, but we need some of the options for handling params
458+
const firebaseConfig = this.getFirebaseConfig();
458459
const environment = {
459460
...this.getSystemEnvs(),
460461
...this.getEmulatorEnvs(),
461-
FIREBASE_CONFIG: this.getFirebaseConfig(),
462+
FIREBASE_CONFIG: firebaseConfig,
462463
...emulatableBackend.env,
463464
};
464465
const userEnvOpt: functionsEnv.UserEnvsOpts = {
@@ -467,7 +468,12 @@ export class FunctionsEmulator implements EmulatorInstance {
467468
projectAlias: this.args.projectAlias,
468469
};
469470
const discoveredBuild = await runtimeDelegate.discoverBuild(runtimeConfig, environment);
470-
const resolution = await resolveBackend(discoveredBuild, userEnvOpt, environment);
471+
const resolution = await resolveBackend(
472+
discoveredBuild,
473+
JSON.parse(firebaseConfig),
474+
userEnvOpt,
475+
environment
476+
);
471477
const discoveredBackend = resolution.backend;
472478
const endpoints = backend.allEndpoints(discoveredBackend);
473479
prepareEndpoints(endpoints);

0 commit comments

Comments
 (0)