firebase-tools
Version:
Command-Line Interface for Firebase
207 lines (206 loc) • 8.38 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getBaseParamBindings = getBaseParamBindings;
exports.buildBindingOptionsWithBaseValue = buildBindingOptionsWithBaseValue;
exports.setNewDefaults = setNewDefaults;
exports.getParams = getParams;
exports.getParamsForUpdate = getParamsForUpdate;
exports.promptForNewParams = promptForNewParams;
exports.readEnvFile = readEnvFile;
exports.isSystemParam = isSystemParam;
exports.partitionParams = partitionParams;
exports.populateDefaultParams = populateDefaultParams;
const path = require("path");
const clc = require("colorette");
const fs = require("fs-extra");
const error_1 = require("../error");
const logger_1 = require("../logger");
const extensionsHelper_1 = require("./extensionsHelper");
const askUserForParam = require("./askUserForParam");
const askUserForParam_1 = require("./askUserForParam");
const env = require("../functions/env");
const NONINTERACTIVE_ERROR_MESSAGE = "As of firebase-tools@11, `ext:install`, `ext:update` and `ext:configure` are interactive only commands. " +
"To deploy an extension noninteractively, use an extensions manifest and `firebase deploy --only extensions`. " +
"See https://firebase.google.com/docs/extensions/manifest for more details";
function getBaseParamBindings(params) {
let ret = {};
for (const [k, v] of Object.entries(params)) {
ret = {
...ret,
...{ [k]: v.baseValue },
};
}
return ret;
}
function buildBindingOptionsWithBaseValue(baseParams) {
let paramOptions = {};
for (const [k, v] of Object.entries(baseParams)) {
paramOptions = {
...paramOptions,
...{ [k]: { baseValue: v } },
};
}
return paramOptions;
}
function setNewDefaults(params, newDefaults) {
for (const param of params) {
if (newDefaults[param.param]) {
param.default = newDefaults[param.param];
}
else if (param.param === `firebaseextensions.v1beta.function/location` &&
newDefaults["LOCATION"]) {
param.default = newDefaults["LOCATION"];
}
}
return params;
}
async function getParams(args) {
let params;
if (args.nonInteractive) {
throw new error_1.FirebaseError(NONINTERACTIVE_ERROR_MESSAGE);
}
else {
const firebaseProjectParams = await (0, extensionsHelper_1.getFirebaseProjectParams)(args.projectId);
params = await askUserForParam.ask({
projectId: args.projectId,
instanceId: args.instanceId,
paramSpecs: args.paramSpecs,
firebaseProjectParams,
reconfiguring: !!args.reconfiguring,
});
}
return params;
}
async function getParamsForUpdate(args) {
let params;
if (args.nonInteractive) {
throw new error_1.FirebaseError(NONINTERACTIVE_ERROR_MESSAGE);
}
else {
params = await promptForNewParams({
spec: args.spec,
newSpec: args.newSpec,
currentParams: args.currentParams,
projectId: args.projectId,
instanceId: args.instanceId,
});
}
return params;
}
async function promptForNewParams(args) {
const newParamBindingOptions = buildBindingOptionsWithBaseValue(args.currentParams);
const allOldParams = (args.spec.params ?? []).concat(args.spec.systemParams ?? []);
const allNewParams = (args.newSpec.params ?? []).concat(args.newSpec.systemParams ?? []);
if (allOldParams.some((p) => p.param === "LOCATION") &&
allNewParams.some((p) => p.param === "firebaseextensions.v1beta.function/location") &&
!!args.currentParams["LOCATION"]) {
newParamBindingOptions["firebaseextensions.v1beta.function/location"] = {
baseValue: args.currentParams["LOCATION"],
};
delete newParamBindingOptions["LOCATION"];
}
for (const newP of allNewParams) {
if (!newP.required && newParamBindingOptions[newP.param] === undefined) {
newParamBindingOptions[newP.param] = {
baseValue: newP.default ?? "",
};
}
}
const unassignedOldParams = allOldParams.filter((oldP) => {
if (oldP.param === "LOCATION" &&
allNewParams.some((p) => p.param === "firebaseextensions.v1beta.function/location")) {
return false;
}
return !allNewParams.some((newP) => newP.param === oldP.param);
});
if (unassignedOldParams.length) {
logger_1.logger.info("The following params will no longer be used:");
for (const param of unassignedOldParams) {
if (args.currentParams[param.param] !== undefined) {
logger_1.logger.info(clc.red(`- ${param.param}: ${args.currentParams[param.param]}`));
}
delete newParamBindingOptions[param.param];
}
}
const hasLocationSpec = allNewParams.some((p) => p.param === "firebaseextensions.v1beta.function/location");
const locationIsSet = !!newParamBindingOptions["firebaseextensions.v1beta.function/location"]?.baseValue ||
!!args.currentParams["firebaseextensions.v1beta.function/location"] ||
!!args.currentParams["LOCATION"];
const locationNotSet = hasLocationSpec && !locationIsSet;
const triggerAdvancedSystemParams = unassignedOldParams.length > 0 || locationNotSet;
const paramsToPrompt = [];
for (const newP of allNewParams) {
const oldP = allOldParams.find((p) => p.param === newP.param);
const currentVal = newParamBindingOptions[newP.param]?.baseValue;
const isSystem = isSystemParam(newP.param) ||
(args.newSpec.systemParams ?? []).some((p) => p.param === newP.param);
if (!oldP && !isSystem) {
paramsToPrompt.push(newP);
continue;
}
if (oldP && oldP.type !== newP.type) {
paramsToPrompt.push(newP);
continue;
}
if (currentVal !== undefined && currentVal !== "" && !(0, askUserForParam_1.checkResponse)(currentVal, newP)) {
paramsToPrompt.push(newP);
continue;
}
if (newP.required && (currentVal === undefined || currentVal === "")) {
paramsToPrompt.push(newP);
continue;
}
if (triggerAdvancedSystemParams && (isSystem || newP.advanced)) {
paramsToPrompt.push(newP);
continue;
}
}
let uniqueParamsToPrompt = paramsToPrompt.filter((p, index, self) => index === self.findIndex((tp) => tp.param === p.param));
if (uniqueParamsToPrompt.length) {
const firebaseProjectParams = await (0, extensionsHelper_1.getFirebaseProjectParams)(args.projectId);
uniqueParamsToPrompt = (0, extensionsHelper_1.substituteParams)(uniqueParamsToPrompt, firebaseProjectParams);
logger_1.logger.info("To update this instance, configure the following parameters:");
for (const param of uniqueParamsToPrompt) {
const chosenValue = await askUserForParam.askForParam({
projectId: args.projectId,
instanceId: args.instanceId,
paramSpec: param,
reconfiguring: false,
});
newParamBindingOptions[param.param] = chosenValue;
}
}
return newParamBindingOptions;
}
function readEnvFile(envPath) {
const buf = fs.readFileSync(path.resolve(envPath), "utf8");
const result = env.parse(buf.toString().trim());
if (result.errors.length) {
throw new error_1.FirebaseError(`Error while parsing ${envPath} - unable to parse following lines:\n${result.errors.join("\n")}`);
}
return result.envs;
}
function isSystemParam(paramName) {
const regex = /^firebaseextensions\.[a-zA-Z0-9\.]*\//;
return regex.test(paramName);
}
function partitionParams(params) {
const userParams = {};
const systemParams = {};
for (const [key, value] of Object.entries(params)) {
if (isSystemParam(key)) {
systemParams[key] = value;
}
else {
userParams[key] = value;
}
}
return { params: userParams, systemParams };
}
function populateDefaultParams(params, spec) {
const ret = { ...params };
for (const p of spec.params) {
ret[p.param] = ret[p.param] ?? p.default;
}
return ret;
}