123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308 |
- "use strict";
- Object.defineProperty(exports, "__esModule", { value: true });
- exports.loadCodebases = exports.resolveCpuAndConcurrency = exports.inferBlockingDetails = exports.updateEndpointTargetedStatus = exports.inferDetailsFromExisting = exports.prepare = exports.EVENTARC_SOURCE_ENV = void 0;
- const clc = require("colorette");
- const backend = require("./backend");
- const build = require("./build");
- const ensureApiEnabled = require("../../ensureApiEnabled");
- const functionsConfig = require("../../functionsConfig");
- const functionsEnv = require("../../functions/env");
- const runtimes = require("./runtimes");
- const validate = require("./validate");
- const ensure = require("./ensure");
- const functionsDeployHelper_1 = require("./functionsDeployHelper");
- const utils_1 = require("../../utils");
- const prepareFunctionsUpload_1 = require("./prepareFunctionsUpload");
- const prompts_1 = require("./prompts");
- const projectUtils_1 = require("../../projectUtils");
- const track_1 = require("../../track");
- const logger_1 = require("../../logger");
- const triggerRegionHelper_1 = require("./triggerRegionHelper");
- const checkIam_1 = require("./checkIam");
- const error_1 = require("../../error");
- const projectConfig_1 = require("../../functions/projectConfig");
- const v1_1 = require("../../functions/events/v1");
- const serviceusage_1 = require("../../gcp/serviceusage");
- const applyHash_1 = require("./cache/applyHash");
- const backend_1 = require("./backend");
- const functional_1 = require("../../functional");
- exports.EVENTARC_SOURCE_ENV = "EVENTARC_CLOUD_EVENT_SOURCE";
- function hasUserConfig(config) {
- return Object.keys(config).length > 1;
- }
- async function prepare(context, options, payload) {
- var _a, _b;
- const projectId = (0, projectUtils_1.needProjectId)(options);
- const projectNumber = await (0, projectUtils_1.needProjectNumber)(options);
- context.config = (0, projectConfig_1.normalizeAndValidate)(options.config.src.functions);
- context.filters = (0, functionsDeployHelper_1.getEndpointFilters)(options);
- const codebases = (0, functionsDeployHelper_1.targetCodebases)(context.config, context.filters);
- if (codebases.length === 0) {
- throw new error_1.FirebaseError("No function matches given --only filters. Aborting deployment.");
- }
- for (const codebase of codebases) {
- (0, utils_1.logLabeledBullet)("functions", `preparing codebase ${clc.bold(codebase)} for deployment`);
- }
- const checkAPIsEnabled = await Promise.all([
- ensureApiEnabled.ensure(projectId, "cloudfunctions.googleapis.com", "functions"),
- ensureApiEnabled.check(projectId, "runtimeconfig.googleapis.com", "runtimeconfig", true),
- ensure.cloudBuildEnabled(projectId),
- ensureApiEnabled.ensure(projectId, "artifactregistry.googleapis.com", "artifactregistry"),
- ]);
- const firebaseConfig = await functionsConfig.getFirebaseConfig(options);
- context.firebaseConfig = firebaseConfig;
- let runtimeConfig = { firebase: firebaseConfig };
- if (checkAPIsEnabled[1]) {
- runtimeConfig = Object.assign(Object.assign({}, runtimeConfig), (await (0, prepareFunctionsUpload_1.getFunctionsConfig)(projectId)));
- }
- const wantBuilds = await loadCodebases(context.config, options, firebaseConfig, runtimeConfig, context.filters);
- const codebaseUsesEnvs = [];
- const wantBackends = {};
- for (const [codebase, wantBuild] of Object.entries(wantBuilds)) {
- const config = (0, projectConfig_1.configForCodebase)(context.config, codebase);
- const firebaseEnvs = functionsEnv.loadFirebaseEnvs(firebaseConfig, projectId);
- const userEnvOpt = {
- functionsSource: options.config.path(config.source),
- projectId: projectId,
- projectAlias: options.projectAlias,
- };
- const userEnvs = functionsEnv.loadUserEnvs(userEnvOpt);
- const envs = Object.assign(Object.assign({}, userEnvs), firebaseEnvs);
- const { backend: wantBackend, envs: resolvedEnvs } = await build.resolveBackend(wantBuild, firebaseConfig, userEnvOpt, userEnvs, options.nonInteractive);
- let hasEnvsFromParams = false;
- wantBackend.environmentVariables = envs;
- for (const envName of Object.keys(resolvedEnvs)) {
- const isList = (_a = resolvedEnvs[envName]) === null || _a === void 0 ? void 0 : _a.legalList;
- const envValue = (_b = resolvedEnvs[envName]) === null || _b === void 0 ? void 0 : _b.toSDK();
- if (envValue &&
- !resolvedEnvs[envName].internal &&
- (!Object.prototype.hasOwnProperty.call(wantBackend.environmentVariables, envName) || isList)) {
- wantBackend.environmentVariables[envName] = envValue;
- hasEnvsFromParams = true;
- }
- }
- for (const endpoint of backend.allEndpoints(wantBackend)) {
- endpoint.environmentVariables = wantBackend.environmentVariables || {};
- let resource;
- if (endpoint.platform === "gcfv1") {
- resource = `projects/${endpoint.project}/locations/${endpoint.region}/functions/${endpoint.id}`;
- }
- else if (endpoint.platform === "gcfv2") {
- resource = `projects/${endpoint.project}/locations/${endpoint.region}/services/${endpoint.id}`;
- }
- else {
- (0, functional_1.assertExhaustive)(endpoint.platform);
- }
- endpoint.environmentVariables[exports.EVENTARC_SOURCE_ENV] = resource;
- endpoint.codebase = codebase;
- }
- wantBackends[codebase] = wantBackend;
- if (functionsEnv.hasUserEnvs(userEnvOpt) || hasEnvsFromParams) {
- codebaseUsesEnvs.push(codebase);
- }
- if (wantBuild.params.length > 0) {
- if (wantBuild.params.every((p) => p.type !== "secret")) {
- void (0, track_1.track)("functions_params_in_build", "env_only");
- }
- else {
- void (0, track_1.track)("functions_params_in_build", "with_secrets");
- }
- }
- else {
- void (0, track_1.track)("functions_params_in_build", "none");
- }
- }
- validate.endpointsAreUnique(wantBackends);
- context.sources = {};
- for (const [codebase, wantBackend] of Object.entries(wantBackends)) {
- const config = (0, projectConfig_1.configForCodebase)(context.config, codebase);
- const sourceDirName = config.source;
- const sourceDir = options.config.path(sourceDirName);
- const source = {};
- if (backend.someEndpoint(wantBackend, () => true)) {
- (0, utils_1.logLabeledBullet)("functions", `preparing ${clc.bold(sourceDirName)} directory for uploading...`);
- }
- if (backend.someEndpoint(wantBackend, (e) => e.platform === "gcfv2")) {
- const packagedSource = await (0, prepareFunctionsUpload_1.prepareFunctionsUpload)(sourceDir, config);
- source.functionsSourceV2 = packagedSource === null || packagedSource === void 0 ? void 0 : packagedSource.pathToSource;
- source.functionsSourceV2Hash = packagedSource === null || packagedSource === void 0 ? void 0 : packagedSource.hash;
- }
- if (backend.someEndpoint(wantBackend, (e) => e.platform === "gcfv1")) {
- const packagedSource = await (0, prepareFunctionsUpload_1.prepareFunctionsUpload)(sourceDir, config, runtimeConfig);
- source.functionsSourceV1 = packagedSource === null || packagedSource === void 0 ? void 0 : packagedSource.pathToSource;
- source.functionsSourceV1Hash = packagedSource === null || packagedSource === void 0 ? void 0 : packagedSource.hash;
- }
- context.sources[codebase] = source;
- }
- payload.functions = {};
- const haveBackends = (0, functionsDeployHelper_1.groupEndpointsByCodebase)(wantBackends, backend.allEndpoints(await backend.existingBackend(context)));
- for (const [codebase, wantBackend] of Object.entries(wantBackends)) {
- const haveBackend = haveBackends[codebase] || backend.empty();
- payload.functions[codebase] = { wantBackend, haveBackend };
- }
- for (const [codebase, { wantBackend, haveBackend }] of Object.entries(payload.functions)) {
- inferDetailsFromExisting(wantBackend, haveBackend, codebaseUsesEnvs.includes(codebase));
- await (0, triggerRegionHelper_1.ensureTriggerRegions)(wantBackend);
- resolveCpuAndConcurrency(wantBackend);
- validate.endpointsAreValid(wantBackend);
- inferBlockingDetails(wantBackend);
- }
- const tag = hasUserConfig(runtimeConfig)
- ? codebaseUsesEnvs.length > 0
- ? "mixed"
- : "runtime_config"
- : codebaseUsesEnvs.length > 0
- ? "dotenv"
- : "none";
- void (0, track_1.track)("functions_codebase_deploy_env_method", tag);
- const codebaseCnt = Object.keys(payload.functions).length;
- void (0, track_1.track)("functions_codebase_deploy_count", codebaseCnt >= 5 ? "5+" : codebaseCnt.toString());
- const wantBackend = backend.merge(...Object.values(wantBackends));
- const haveBackend = backend.merge(...Object.values(haveBackends));
- await Promise.all(Object.values(wantBackend.requiredAPIs).map(({ api }) => {
- return ensureApiEnabled.ensure(projectId, api, "functions", false);
- }));
- if (backend.someEndpoint(wantBackend, (e) => e.platform === "gcfv2")) {
- const V2_APIS = [
- "run.googleapis.com",
- "eventarc.googleapis.com",
- "pubsub.googleapis.com",
- "storage.googleapis.com",
- ];
- const enablements = V2_APIS.map((api) => {
- return ensureApiEnabled.ensure(context.projectId, api, "functions");
- });
- await Promise.all(enablements);
- const services = ["pubsub.googleapis.com", "eventarc.googleapis.com"];
- const generateServiceAccounts = services.map((service) => {
- return (0, serviceusage_1.generateServiceIdentity)(projectNumber, service, "functions");
- });
- await Promise.all(generateServiceAccounts);
- }
- const matchingBackend = backend.matchingBackend(wantBackend, (endpoint) => {
- return (0, functionsDeployHelper_1.endpointMatchesAnyFilter)(endpoint, context.filters);
- });
- await (0, prompts_1.promptForFailurePolicies)(options, matchingBackend, haveBackend);
- await (0, prompts_1.promptForMinInstances)(options, matchingBackend, haveBackend);
- await backend.checkAvailability(context, matchingBackend);
- await (0, checkIam_1.ensureServiceAgentRoles)(projectId, projectNumber, matchingBackend, haveBackend);
- await validate.secretsAreValid(projectId, matchingBackend);
- await ensure.secretAccess(projectId, matchingBackend, haveBackend);
- updateEndpointTargetedStatus(wantBackends, context.filters || []);
- (0, applyHash_1.applyBackendHashToBackends)(wantBackends, context);
- }
- exports.prepare = prepare;
- function inferDetailsFromExisting(want, have, usedDotenv) {
- var _a;
- for (const wantE of backend.allEndpoints(want)) {
- const haveE = (_a = have.endpoints[wantE.region]) === null || _a === void 0 ? void 0 : _a[wantE.id];
- if (!haveE) {
- continue;
- }
- if (!usedDotenv) {
- wantE.environmentVariables = Object.assign(Object.assign({}, haveE.environmentVariables), wantE.environmentVariables);
- }
- if (typeof wantE.availableMemoryMb === "undefined" && haveE.availableMemoryMb) {
- wantE.availableMemoryMb = haveE.availableMemoryMb;
- }
- if (typeof wantE.cpu === "undefined" && haveE.cpu) {
- wantE.cpu = haveE.cpu;
- }
- wantE.securityLevel = haveE.securityLevel ? haveE.securityLevel : "SECURE_ALWAYS";
- maybeCopyTriggerRegion(wantE, haveE);
- }
- }
- exports.inferDetailsFromExisting = inferDetailsFromExisting;
- function maybeCopyTriggerRegion(wantE, haveE) {
- if (!backend.isEventTriggered(wantE) || !backend.isEventTriggered(haveE)) {
- return;
- }
- if (wantE.eventTrigger.region || !haveE.eventTrigger.region) {
- return;
- }
- if (JSON.stringify(haveE.eventTrigger.eventFilters) !==
- JSON.stringify(wantE.eventTrigger.eventFilters)) {
- return;
- }
- wantE.eventTrigger.region = haveE.eventTrigger.region;
- }
- function updateEndpointTargetedStatus(wantBackends, endpointFilters) {
- for (const wantBackend of Object.values(wantBackends)) {
- for (const endpoint of (0, backend_1.allEndpoints)(wantBackend)) {
- endpoint.targetedByOnly = (0, functionsDeployHelper_1.endpointMatchesAnyFilter)(endpoint, endpointFilters);
- }
- }
- }
- exports.updateEndpointTargetedStatus = updateEndpointTargetedStatus;
- function inferBlockingDetails(want) {
- var _a, _b, _c;
- const authBlockingEndpoints = backend
- .allEndpoints(want)
- .filter((ep) => backend.isBlockingTriggered(ep) &&
- v1_1.AUTH_BLOCKING_EVENTS.includes(ep.blockingTrigger.eventType));
- if (authBlockingEndpoints.length === 0) {
- return;
- }
- let accessToken = false;
- let idToken = false;
- let refreshToken = false;
- for (const blockingEp of authBlockingEndpoints) {
- accessToken || (accessToken = !!((_a = blockingEp.blockingTrigger.options) === null || _a === void 0 ? void 0 : _a.accessToken));
- idToken || (idToken = !!((_b = blockingEp.blockingTrigger.options) === null || _b === void 0 ? void 0 : _b.idToken));
- refreshToken || (refreshToken = !!((_c = blockingEp.blockingTrigger.options) === null || _c === void 0 ? void 0 : _c.refreshToken));
- }
- for (const blockingEp of authBlockingEndpoints) {
- if (!blockingEp.blockingTrigger.options) {
- blockingEp.blockingTrigger.options = {};
- }
- blockingEp.blockingTrigger.options.accessToken = accessToken;
- blockingEp.blockingTrigger.options.idToken = idToken;
- blockingEp.blockingTrigger.options.refreshToken = refreshToken;
- }
- }
- exports.inferBlockingDetails = inferBlockingDetails;
- function resolveCpuAndConcurrency(want) {
- for (const e of backend.allEndpoints(want)) {
- if (e.platform === "gcfv1") {
- continue;
- }
- if (e.cpu === "gcf_gen1") {
- e.cpu = backend.memoryToGen1Cpu(e.availableMemoryMb || backend.DEFAULT_MEMORY);
- }
- else if (!e.cpu) {
- e.cpu = backend.memoryToGen2Cpu(e.availableMemoryMb || backend.DEFAULT_MEMORY);
- }
- if (!e.concurrency) {
- e.concurrency = e.cpu >= 1 ? backend.DEFAULT_CONCURRENCY : 1;
- }
- }
- }
- exports.resolveCpuAndConcurrency = resolveCpuAndConcurrency;
- async function loadCodebases(config, options, firebaseConfig, runtimeConfig, filters) {
- const codebases = (0, functionsDeployHelper_1.targetCodebases)(config, filters);
- const projectId = (0, projectUtils_1.needProjectId)(options);
- const wantBuilds = {};
- for (const codebase of codebases) {
- const codebaseConfig = (0, projectConfig_1.configForCodebase)(config, codebase);
- const sourceDirName = codebaseConfig.source;
- if (!sourceDirName) {
- throw new error_1.FirebaseError(`No functions code detected at default location (./functions), and no functions source defined in firebase.json`);
- }
- const sourceDir = options.config.path(sourceDirName);
- const delegateContext = {
- projectId,
- sourceDir,
- projectDir: options.config.projectDir,
- runtime: codebaseConfig.runtime || "",
- };
- const runtimeDelegate = await runtimes.getRuntimeDelegate(delegateContext);
- logger_1.logger.debug(`Validating ${runtimeDelegate.name} source`);
- await runtimeDelegate.validate();
- logger_1.logger.debug(`Building ${runtimeDelegate.name} source`);
- await runtimeDelegate.build();
- const firebaseEnvs = functionsEnv.loadFirebaseEnvs(firebaseConfig, projectId);
- wantBuilds[codebase] = await runtimeDelegate.discoverBuild(runtimeConfig, firebaseEnvs);
- }
- return wantBuilds;
- }
- exports.loadCodebases = loadCodebases;
|