firebase-tools 10.5.0 → 10.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/command.js +4 -4
- package/lib/commands/deploy.js +1 -1
- package/lib/commands/emulators-start.js +7 -2
- package/lib/commands/ext-configure.js +15 -5
- package/lib/commands/ext-export.js +6 -5
- package/lib/commands/ext-install.js +28 -44
- package/lib/commands/ext-update.js +9 -1
- package/lib/commands/functions-delete.js +7 -3
- package/lib/commands/functions-secrets-destroy.js +23 -3
- package/lib/commands/functions-secrets-prune.js +15 -12
- package/lib/commands/functions-secrets-set.js +51 -4
- package/lib/commands/hosting-channel-deploy.js +2 -2
- package/lib/deploy/database/deploy.js +4 -0
- package/lib/deploy/database/index.js +1 -0
- package/lib/deploy/extensions/deploy.js +4 -4
- package/lib/deploy/extensions/deploymentSummary.js +8 -5
- package/lib/deploy/extensions/planner.js +36 -9
- package/lib/deploy/extensions/prepare.js +1 -1
- package/lib/deploy/extensions/secrets.js +2 -2
- package/lib/deploy/extensions/tasks.js +60 -21
- package/lib/deploy/functions/backend.js +37 -6
- package/lib/deploy/functions/build.js +162 -0
- package/lib/deploy/functions/checkIam.js +10 -6
- package/lib/deploy/functions/deploy.js +49 -28
- package/lib/deploy/functions/ensure.js +4 -4
- package/lib/deploy/functions/functionsDeployHelper.js +99 -24
- package/lib/deploy/functions/prepare.js +130 -62
- package/lib/deploy/functions/prepareFunctionsUpload.js +16 -21
- package/lib/deploy/functions/pricing.js +6 -3
- package/lib/deploy/functions/prompts.js +1 -7
- package/lib/deploy/functions/release/fabricator.js +70 -28
- package/lib/deploy/functions/release/index.js +41 -6
- package/lib/deploy/functions/release/planner.js +19 -12
- package/lib/deploy/functions/release/reporter.js +14 -11
- package/lib/deploy/functions/runtimes/discovery/parsing.js +12 -6
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +61 -13
- package/lib/deploy/functions/runtimes/node/index.js +1 -1
- package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +3 -3
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +29 -24
- package/lib/deploy/functions/runtimes/node/versioning.js +2 -2
- package/lib/deploy/functions/services/auth.js +95 -0
- package/lib/deploy/functions/services/index.js +41 -21
- package/lib/deploy/functions/services/storage.js +1 -6
- package/lib/deploy/functions/validate.js +32 -6
- package/lib/deploy/hosting/args.js +2 -0
- package/lib/deploy/hosting/convertConfig.js +39 -8
- package/lib/deploy/hosting/deploy.js +3 -3
- package/lib/deploy/hosting/prepare.js +2 -2
- package/lib/deploy/hosting/release.js +6 -2
- package/lib/deploy/index.js +82 -93
- package/lib/deploy/remoteconfig/deploy.js +4 -0
- package/lib/deploy/remoteconfig/index.js +3 -1
- package/lib/emulator/auth/operations.js +5 -0
- package/lib/emulator/auth/utils.js +3 -25
- package/lib/emulator/controller.js +17 -14
- package/lib/emulator/downloadableEmulators.js +39 -23
- package/lib/emulator/extensions/postinstall.js +41 -0
- package/lib/emulator/extensions/validation.js +2 -2
- package/lib/emulator/extensionsEmulator.js +85 -21
- package/lib/emulator/functionsEmulator.js +88 -10
- package/lib/emulator/functionsEmulatorShared.js +37 -21
- package/lib/emulator/functionsEmulatorShell.js +2 -3
- package/lib/emulator/pubsubEmulator.js +13 -9
- package/lib/emulator/registry.js +34 -12
- package/lib/emulator/storage/apis/firebase.js +13 -8
- package/lib/emulator/storage/apis/gcloud.js +15 -9
- package/lib/emulator/storage/files.js +14 -3
- package/lib/emulator/storage/index.js +9 -1
- package/lib/emulator/storage/metadata.js +18 -8
- package/lib/emulator/storage/rules/manager.js +7 -17
- package/lib/emulator/storage/server.js +38 -12
- package/lib/ensureApiEnabled.js +8 -4
- package/lib/extensions/askUserForParam.js +14 -11
- package/lib/extensions/changelog.js +1 -1
- package/lib/extensions/emulator/optionsHelper.js +9 -10
- package/lib/extensions/emulator/specHelper.js +7 -1
- package/lib/extensions/emulator/triggerHelper.js +11 -14
- package/lib/extensions/extensionsApi.js +2 -1
- package/lib/extensions/extensionsHelper.js +30 -24
- package/lib/extensions/manifest.js +28 -8
- package/lib/extensions/paramHelper.js +19 -13
- package/lib/extensions/provisioningHelper.js +2 -2
- package/lib/extensions/warnings.js +3 -3
- package/lib/functions/env.js +10 -2
- package/lib/functions/events/index.js +7 -0
- package/lib/functions/events/v1.js +6 -0
- package/lib/functions/projectConfig.js +32 -6
- package/lib/functions/runtimeConfigExport.js +10 -6
- package/lib/functions/secrets.js +99 -6
- package/lib/functionsShellCommandAction.js +1 -1
- package/lib/gcp/cloudfunctions.js +44 -18
- package/lib/gcp/cloudfunctionsv2.js +48 -25
- package/lib/gcp/cloudtasks.js +5 -3
- package/lib/gcp/identityPlatform.js +44 -0
- package/lib/gcp/secretManager.js +2 -2
- package/lib/metaprogramming.js +2 -0
- package/lib/previews.js +1 -1
- package/lib/serve/functions.js +16 -19
- package/lib/serve/hosting.js +25 -12
- package/lib/serve/index.js +6 -0
- package/lib/track.js +15 -21
- package/lib/utils.js +30 -1
- package/npm-shrinkwrap.json +44 -2
- package/package.json +4 -1
- package/schema/firebase-config.json +6 -0
|
@@ -9,7 +9,7 @@ const secretManager_1 = require("../../gcp/secretManager");
|
|
|
9
9
|
const previews_1 = require("../../previews");
|
|
10
10
|
const projects_1 = require("../../management/projects");
|
|
11
11
|
const functional_1 = require("../../functional");
|
|
12
|
-
const
|
|
12
|
+
const track_1 = require("../../track");
|
|
13
13
|
const backend = require("./backend");
|
|
14
14
|
const ensureApiEnabled = require("../../ensureApiEnabled");
|
|
15
15
|
const FAQ_URL = "https://firebase.google.com/support/faq#functions-runtime";
|
|
@@ -26,9 +26,9 @@ async function defaultServiceAccount(e) {
|
|
|
26
26
|
}
|
|
27
27
|
exports.defaultServiceAccount = defaultServiceAccount;
|
|
28
28
|
function nodeBillingError(projectId) {
|
|
29
|
-
void track("functions_runtime_notices", "nodejs10_billing_error");
|
|
29
|
+
void (0, track_1.track)("functions_runtime_notices", "nodejs10_billing_error");
|
|
30
30
|
return new error_1.FirebaseError(`Cloud Functions deployment requires the pay-as-you-go (Blaze) billing plan. To upgrade your project, visit the following URL:
|
|
31
|
-
|
|
31
|
+
|
|
32
32
|
https://console.firebase.google.com/project/${projectId}/usage/details
|
|
33
33
|
|
|
34
34
|
For additional information about this requirement, see Firebase FAQs:
|
|
@@ -36,7 +36,7 @@ For additional information about this requirement, see Firebase FAQs:
|
|
|
36
36
|
${FAQ_URL}`, { exit: 1 });
|
|
37
37
|
}
|
|
38
38
|
function nodePermissionError(projectId) {
|
|
39
|
-
void track("functions_runtime_notices", "nodejs10_permission_error");
|
|
39
|
+
void (0, track_1.track)("functions_runtime_notices", "nodejs10_permission_error");
|
|
40
40
|
return new error_1.FirebaseError(`Cloud Functions deployment requires the Cloud Build API to be enabled. The current credentials do not have permission to enable APIs for project ${clc.bold(projectId)}.
|
|
41
41
|
|
|
42
42
|
Please ask a project owner to visit the following URL to enable Cloud Build:
|
|
@@ -1,41 +1,116 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getFunctionLabel = exports.
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
exports.groupEndpointsByCodebase = exports.targetCodebases = exports.getFunctionLabel = exports.getEndpointFilters = exports.parseFunctionSelector = exports.endpointMatchesFilter = exports.endpointMatchesAnyFilter = void 0;
|
|
4
|
+
const backend = require("./backend");
|
|
5
|
+
const projectConfig_1 = require("../../functions/projectConfig");
|
|
6
|
+
function endpointMatchesAnyFilter(endpoint, filters) {
|
|
7
|
+
if (!filters) {
|
|
6
8
|
return true;
|
|
7
9
|
}
|
|
8
|
-
return
|
|
10
|
+
return filters.some((filter) => endpointMatchesFilter(endpoint, filter));
|
|
9
11
|
}
|
|
10
|
-
exports.
|
|
11
|
-
function
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
exports.endpointMatchesAnyFilter = endpointMatchesAnyFilter;
|
|
13
|
+
function endpointMatchesFilter(endpoint, filter) {
|
|
14
|
+
if (endpoint.codebase && filter.codebase) {
|
|
15
|
+
if (endpoint.codebase !== filter.codebase) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
if (!filter.idChunks) {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
const idChunks = endpoint.id.split("-");
|
|
23
|
+
if (idChunks.length < filter.idChunks.length) {
|
|
14
24
|
return false;
|
|
15
25
|
}
|
|
16
|
-
for (let i = 0; i <
|
|
17
|
-
if (
|
|
26
|
+
for (let i = 0; i < filter.idChunks.length; i += 1) {
|
|
27
|
+
if (idChunks[i] !== filter.idChunks[i]) {
|
|
18
28
|
return false;
|
|
19
29
|
}
|
|
20
30
|
}
|
|
21
31
|
return true;
|
|
22
32
|
}
|
|
23
|
-
exports.
|
|
24
|
-
function
|
|
33
|
+
exports.endpointMatchesFilter = endpointMatchesFilter;
|
|
34
|
+
function parseFunctionSelector(selector) {
|
|
35
|
+
const fragments = selector.split(":");
|
|
36
|
+
if (fragments.length < 2) {
|
|
37
|
+
return [
|
|
38
|
+
{ codebase: fragments[0] },
|
|
39
|
+
{ codebase: projectConfig_1.DEFAULT_CODEBASE, idChunks: fragments[0].split(/[-.]/) },
|
|
40
|
+
];
|
|
41
|
+
}
|
|
42
|
+
return [
|
|
43
|
+
{
|
|
44
|
+
codebase: fragments[0],
|
|
45
|
+
idChunks: fragments[1].split(/[-.]/),
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
}
|
|
49
|
+
exports.parseFunctionSelector = parseFunctionSelector;
|
|
50
|
+
function getEndpointFilters(options) {
|
|
25
51
|
if (!options.only) {
|
|
26
|
-
return
|
|
27
|
-
}
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
const selectors = options.only.split(",");
|
|
55
|
+
const filters = [];
|
|
56
|
+
for (let selector of selectors) {
|
|
57
|
+
if (selector.startsWith("functions:")) {
|
|
58
|
+
selector = selector.replace("functions:", "");
|
|
59
|
+
if (selector.length > 0) {
|
|
60
|
+
filters.push(...parseFunctionSelector(selector));
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (filters.length === 0) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
return filters;
|
|
36
68
|
}
|
|
37
|
-
exports.
|
|
69
|
+
exports.getEndpointFilters = getEndpointFilters;
|
|
38
70
|
function getFunctionLabel(fn) {
|
|
39
|
-
|
|
71
|
+
let id = `${fn.id}(${fn.region})`;
|
|
72
|
+
if (fn.codebase && fn.codebase !== projectConfig_1.DEFAULT_CODEBASE) {
|
|
73
|
+
id = `[${fn.codebase}]${id}`;
|
|
74
|
+
}
|
|
75
|
+
return id;
|
|
40
76
|
}
|
|
41
77
|
exports.getFunctionLabel = getFunctionLabel;
|
|
78
|
+
function targetCodebases(config, filters) {
|
|
79
|
+
const codebasesFromConfig = [...new Set(Object.values(config).map((c) => c.codebase))];
|
|
80
|
+
if (!filters) {
|
|
81
|
+
return [...codebasesFromConfig];
|
|
82
|
+
}
|
|
83
|
+
const codebasesFromFilters = [
|
|
84
|
+
...new Set(filters.map((f) => f.codebase).filter((c) => c !== undefined)),
|
|
85
|
+
];
|
|
86
|
+
if (codebasesFromFilters.length === 0) {
|
|
87
|
+
return [...codebasesFromConfig];
|
|
88
|
+
}
|
|
89
|
+
const intersections = [];
|
|
90
|
+
for (const codebase of codebasesFromConfig) {
|
|
91
|
+
if (codebasesFromFilters.includes(codebase)) {
|
|
92
|
+
intersections.push(codebase);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return intersections;
|
|
96
|
+
}
|
|
97
|
+
exports.targetCodebases = targetCodebases;
|
|
98
|
+
function groupEndpointsByCodebase(wantBackends, haveEndpoints) {
|
|
99
|
+
const grouped = {};
|
|
100
|
+
let endpointsToAssign = haveEndpoints;
|
|
101
|
+
for (const codebase of Object.keys(wantBackends)) {
|
|
102
|
+
const names = backend.allEndpoints(wantBackends[codebase]).map((e) => backend.functionName(e));
|
|
103
|
+
grouped[codebase] = backend.of(...endpointsToAssign.filter((e) => names.includes(backend.functionName(e))));
|
|
104
|
+
endpointsToAssign = endpointsToAssign.filter((e) => !names.includes(backend.functionName(e)));
|
|
105
|
+
}
|
|
106
|
+
for (const codebase of Object.keys(wantBackends)) {
|
|
107
|
+
const matchedEndpoints = endpointsToAssign.filter((e) => e.codebase === codebase);
|
|
108
|
+
grouped[codebase] = backend.merge(grouped[codebase], backend.of(...matchedEndpoints));
|
|
109
|
+
const matchedNames = matchedEndpoints.map((e) => backend.functionName(e));
|
|
110
|
+
endpointsToAssign = endpointsToAssign.filter((e) => {
|
|
111
|
+
return !matchedNames.includes(backend.functionName(e));
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
return grouped;
|
|
115
|
+
}
|
|
116
|
+
exports.groupEndpointsByCodebase = groupEndpointsByCodebase;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.inferDetailsFromExisting = exports.prepare = void 0;
|
|
3
|
+
exports.inferBlockingDetails = exports.inferDetailsFromExisting = exports.prepare = void 0;
|
|
4
4
|
const clc = require("cli-color");
|
|
5
5
|
const backend = require("./backend");
|
|
6
6
|
const ensureApiEnabled = require("../../ensureApiEnabled");
|
|
@@ -20,63 +20,127 @@ const triggerRegionHelper_1 = require("./triggerRegionHelper");
|
|
|
20
20
|
const checkIam_1 = require("./checkIam");
|
|
21
21
|
const error_1 = require("../../error");
|
|
22
22
|
const projectConfig_1 = require("../../functions/projectConfig");
|
|
23
|
+
const previews_1 = require("../../previews");
|
|
24
|
+
const v1_1 = require("../../functions/events/v1");
|
|
23
25
|
function hasUserConfig(config) {
|
|
24
26
|
return Object.keys(config).length > 1;
|
|
25
27
|
}
|
|
26
|
-
function hasDotenv(opts) {
|
|
27
|
-
return functionsEnv.hasUserEnvs(opts);
|
|
28
|
-
}
|
|
29
28
|
async function prepare(context, options, payload) {
|
|
30
29
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
31
30
|
const projectNumber = await (0, projectUtils_1.needProjectNumber)(options);
|
|
32
|
-
context.config = (0, projectConfig_1.normalizeAndValidate)(options.config.src.functions)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
31
|
+
context.config = (0, projectConfig_1.normalizeAndValidate)(options.config.src.functions);
|
|
32
|
+
context.filters = (0, functionsDeployHelper_1.getEndpointFilters)(options);
|
|
33
|
+
const codebases = (0, functionsDeployHelper_1.targetCodebases)(context.config, context.filters);
|
|
34
|
+
if (codebases.length === 0) {
|
|
35
|
+
throw new error_1.FirebaseError("No function matches given --only filters. Aborting deployment.");
|
|
36
36
|
}
|
|
37
|
-
const sourceDir = options.config.path(sourceDirName);
|
|
38
|
-
const delegateContext = {
|
|
39
|
-
projectId,
|
|
40
|
-
sourceDir,
|
|
41
|
-
projectDir: options.config.projectDir,
|
|
42
|
-
runtime: context.config.runtime || "",
|
|
43
|
-
};
|
|
44
|
-
const runtimeDelegate = await runtimes.getRuntimeDelegate(delegateContext);
|
|
45
|
-
logger_1.logger.debug(`Validating ${runtimeDelegate.name} source`);
|
|
46
|
-
await runtimeDelegate.validate();
|
|
47
|
-
logger_1.logger.debug(`Building ${runtimeDelegate.name} source`);
|
|
48
|
-
await runtimeDelegate.build();
|
|
49
37
|
const checkAPIsEnabled = await Promise.all([
|
|
50
38
|
ensureApiEnabled.ensure(projectId, "cloudfunctions.googleapis.com", "functions"),
|
|
51
39
|
ensureApiEnabled.check(projectId, "runtimeconfig.googleapis.com", "runtimeconfig", true),
|
|
52
40
|
ensure.cloudBuildEnabled(projectId),
|
|
53
41
|
ensure.maybeEnableAR(projectId),
|
|
54
42
|
]);
|
|
55
|
-
context.runtimeConfigEnabled = checkAPIsEnabled[1];
|
|
56
43
|
context.artifactRegistryEnabled = checkAPIsEnabled[3];
|
|
57
44
|
const firebaseConfig = await functionsConfig.getFirebaseConfig(options);
|
|
58
45
|
context.firebaseConfig = firebaseConfig;
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
};
|
|
66
|
-
const
|
|
67
|
-
|
|
46
|
+
let runtimeConfig = { firebase: firebaseConfig };
|
|
47
|
+
if (checkAPIsEnabled[1]) {
|
|
48
|
+
runtimeConfig = Object.assign(Object.assign({}, runtimeConfig), (await (0, prepareFunctionsUpload_1.getFunctionsConfig)(projectId)));
|
|
49
|
+
}
|
|
50
|
+
context.sources = {};
|
|
51
|
+
const codebaseUsesEnvs = [];
|
|
52
|
+
const wantBackends = {};
|
|
53
|
+
for (const codebase of codebases) {
|
|
54
|
+
(0, utils_1.logLabeledBullet)("functions", `preparing codebase ${clc.bold(codebase)} for deployment`);
|
|
55
|
+
const config = (0, projectConfig_1.configForCodebase)(context.config, codebase);
|
|
56
|
+
const sourceDirName = config.source;
|
|
57
|
+
if (!sourceDirName) {
|
|
58
|
+
throw new error_1.FirebaseError(`No functions code detected at default location (./functions), and no functions source defined in firebase.json`);
|
|
59
|
+
}
|
|
60
|
+
const sourceDir = options.config.path(sourceDirName);
|
|
61
|
+
const delegateContext = {
|
|
62
|
+
projectId,
|
|
63
|
+
sourceDir,
|
|
64
|
+
projectDir: options.config.projectDir,
|
|
65
|
+
runtime: config.runtime || "",
|
|
66
|
+
};
|
|
67
|
+
const runtimeDelegate = await runtimes.getRuntimeDelegate(delegateContext);
|
|
68
|
+
logger_1.logger.debug(`Validating ${runtimeDelegate.name} source`);
|
|
69
|
+
await runtimeDelegate.validate();
|
|
70
|
+
logger_1.logger.debug(`Building ${runtimeDelegate.name} source`);
|
|
71
|
+
await runtimeDelegate.build();
|
|
72
|
+
const firebaseEnvs = functionsEnv.loadFirebaseEnvs(firebaseConfig, projectId);
|
|
73
|
+
const userEnvOpt = {
|
|
74
|
+
functionsSource: sourceDir,
|
|
75
|
+
projectId: projectId,
|
|
76
|
+
projectAlias: options.projectAlias,
|
|
77
|
+
};
|
|
78
|
+
const userEnvs = functionsEnv.loadUserEnvs(userEnvOpt);
|
|
79
|
+
logger_1.logger.debug(`Analyzing ${runtimeDelegate.name} backend spec`);
|
|
80
|
+
const wantBackend = await runtimeDelegate.discoverSpec(runtimeConfig, firebaseEnvs);
|
|
81
|
+
wantBackend.environmentVariables = Object.assign(Object.assign({}, userEnvs), firebaseEnvs);
|
|
82
|
+
for (const endpoint of backend.allEndpoints(wantBackend)) {
|
|
83
|
+
endpoint.environmentVariables = wantBackend.environmentVariables;
|
|
84
|
+
endpoint.codebase = codebase;
|
|
85
|
+
}
|
|
86
|
+
wantBackends[codebase] = wantBackend;
|
|
87
|
+
if (functionsEnv.hasUserEnvs(userEnvOpt)) {
|
|
88
|
+
codebaseUsesEnvs.push(codebase);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
validate.endpointsAreUnique(wantBackends);
|
|
92
|
+
for (const [codebase, wantBackend] of Object.entries(wantBackends)) {
|
|
93
|
+
const config = (0, projectConfig_1.configForCodebase)(context.config, codebase);
|
|
94
|
+
const sourceDirName = config.source;
|
|
95
|
+
const sourceDir = options.config.path(sourceDirName);
|
|
96
|
+
const source = {};
|
|
97
|
+
if (backend.someEndpoint(wantBackend, () => true)) {
|
|
98
|
+
(0, utils_1.logLabeledBullet)("functions", `preparing ${clc.bold(sourceDirName)} directory for uploading...`);
|
|
99
|
+
}
|
|
100
|
+
if (backend.someEndpoint(wantBackend, (e) => e.platform === "gcfv2")) {
|
|
101
|
+
if (!previews_1.previews.functionsv2) {
|
|
102
|
+
throw new error_1.FirebaseError("This version of firebase-tools does not support Google Cloud " +
|
|
103
|
+
"Functions gen 2\n" +
|
|
104
|
+
"If Cloud Functions for Firebase gen 2 is still in alpha, sign up " +
|
|
105
|
+
"for the alpha program at " +
|
|
106
|
+
"https://services.google.com/fb/forms/firebasealphaprogram/\n" +
|
|
107
|
+
"If Cloud Functions for Firebase gen 2 is in beta, get the latest " +
|
|
108
|
+
"version of Firebse Tools with `npm i -g firebase-tools@latest`");
|
|
109
|
+
}
|
|
110
|
+
source.functionsSourceV2 = await (0, prepareFunctionsUpload_1.prepareFunctionsUpload)(sourceDir, config);
|
|
111
|
+
}
|
|
112
|
+
if (backend.someEndpoint(wantBackend, (e) => e.platform === "gcfv1")) {
|
|
113
|
+
source.functionsSourceV1 = await (0, prepareFunctionsUpload_1.prepareFunctionsUpload)(sourceDir, config, runtimeConfig);
|
|
114
|
+
}
|
|
115
|
+
context.sources[codebase] = source;
|
|
116
|
+
}
|
|
117
|
+
payload.functions = {};
|
|
118
|
+
const haveBackends = (0, functionsDeployHelper_1.groupEndpointsByCodebase)(wantBackends, backend.allEndpoints(await backend.existingBackend(context)));
|
|
119
|
+
for (const [codebase, wantBackend] of Object.entries(wantBackends)) {
|
|
120
|
+
const haveBackend = haveBackends[codebase] || Object.assign({}, backend.empty());
|
|
121
|
+
payload.functions[codebase] = { wantBackend, haveBackend };
|
|
122
|
+
}
|
|
123
|
+
for (const [codebase, { wantBackend, haveBackend }] of Object.entries(payload.functions)) {
|
|
124
|
+
inferDetailsFromExisting(wantBackend, haveBackend, codebaseUsesEnvs.includes(codebase));
|
|
125
|
+
await (0, triggerRegionHelper_1.ensureTriggerRegions)(wantBackend);
|
|
126
|
+
validate.endpointsAreValid(wantBackend);
|
|
127
|
+
inferBlockingDetails(wantBackend);
|
|
128
|
+
}
|
|
68
129
|
const tag = hasUserConfig(runtimeConfig)
|
|
69
|
-
?
|
|
130
|
+
? codebaseUsesEnvs.length > 0
|
|
70
131
|
? "mixed"
|
|
71
132
|
: "runtime_config"
|
|
72
|
-
:
|
|
133
|
+
: codebaseUsesEnvs.length > 0
|
|
73
134
|
? "dotenv"
|
|
74
135
|
: "none";
|
|
75
136
|
void (0, track_1.track)("functions_codebase_deploy_env_method", tag);
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
wantBackend
|
|
79
|
-
|
|
137
|
+
const codebaseCnt = Object.keys(payload.functions).length;
|
|
138
|
+
void (0, track_1.track)("functions_codebase_deploy_count", codebaseCnt >= 5 ? "5+" : codebaseCnt.toString());
|
|
139
|
+
const wantBackend = backend.merge(...Object.values(wantBackends));
|
|
140
|
+
const haveBackend = backend.merge(...Object.values(haveBackends));
|
|
141
|
+
await Promise.all(Object.values(wantBackend.requiredAPIs).map(({ api }) => {
|
|
142
|
+
return ensureApiEnabled.ensure(projectId, api, "functions", false);
|
|
143
|
+
}));
|
|
80
144
|
if (backend.someEndpoint(wantBackend, (e) => e.platform === "gcfv2")) {
|
|
81
145
|
const V2_APIS = [
|
|
82
146
|
"artifactregistry.googleapis.com",
|
|
@@ -90,36 +154,13 @@ async function prepare(context, options, payload) {
|
|
|
90
154
|
});
|
|
91
155
|
await Promise.all(enablements);
|
|
92
156
|
}
|
|
93
|
-
if (backend.someEndpoint(wantBackend, () => true)) {
|
|
94
|
-
(0, utils_1.logBullet)(clc.cyan.bold("functions:") +
|
|
95
|
-
" preparing " +
|
|
96
|
-
clc.bold(sourceDirName) +
|
|
97
|
-
" directory for uploading...");
|
|
98
|
-
}
|
|
99
|
-
if (backend.someEndpoint(wantBackend, (e) => e.platform === "gcfv1")) {
|
|
100
|
-
context.functionsSourceV1 = await (0, prepareFunctionsUpload_1.prepareFunctionsUpload)(sourceDir, context.config, runtimeConfig);
|
|
101
|
-
}
|
|
102
|
-
if (backend.someEndpoint(wantBackend, (e) => e.platform === "gcfv2")) {
|
|
103
|
-
context.functionsSourceV2 = await (0, prepareFunctionsUpload_1.prepareFunctionsUpload)(sourceDir, context.config);
|
|
104
|
-
}
|
|
105
|
-
for (const endpoint of backend.allEndpoints(wantBackend)) {
|
|
106
|
-
endpoint.environmentVariables = wantBackend.environmentVariables;
|
|
107
|
-
}
|
|
108
|
-
await Promise.all(Object.values(wantBackend.requiredAPIs).map(({ api }) => {
|
|
109
|
-
return ensureApiEnabled.ensure(projectId, api, "functions", false);
|
|
110
|
-
}));
|
|
111
|
-
validate.endpointsAreValid(wantBackend);
|
|
112
|
-
context.filters = (0, functionsDeployHelper_1.getFilterGroups)(options);
|
|
113
157
|
const matchingBackend = backend.matchingBackend(wantBackend, (endpoint) => {
|
|
114
|
-
return (0, functionsDeployHelper_1.
|
|
158
|
+
return (0, functionsDeployHelper_1.endpointMatchesAnyFilter)(endpoint, context.filters);
|
|
115
159
|
});
|
|
116
|
-
const haveBackend = await backend.existingBackend(context);
|
|
117
|
-
await (0, checkIam_1.ensureServiceAgentRoles)(projectNumber, wantBackend, haveBackend);
|
|
118
|
-
inferDetailsFromExisting(wantBackend, haveBackend, usedDotenv);
|
|
119
|
-
await (0, triggerRegionHelper_1.ensureTriggerRegions)(wantBackend);
|
|
120
160
|
await (0, prompts_1.promptForFailurePolicies)(options, matchingBackend, haveBackend);
|
|
121
161
|
await (0, prompts_1.promptForMinInstances)(options, matchingBackend, haveBackend);
|
|
122
|
-
await backend.checkAvailability(context,
|
|
162
|
+
await backend.checkAvailability(context, matchingBackend);
|
|
163
|
+
await (0, checkIam_1.ensureServiceAgentRoles)(projectNumber, matchingBackend, haveBackend);
|
|
123
164
|
await validate.secretsAreValid(projectId, matchingBackend);
|
|
124
165
|
await ensure.secretAccess(projectId, matchingBackend, haveBackend);
|
|
125
166
|
}
|
|
@@ -155,3 +196,30 @@ function maybeCopyTriggerRegion(wantE, haveE) {
|
|
|
155
196
|
}
|
|
156
197
|
wantE.eventTrigger.region = haveE.eventTrigger.region;
|
|
157
198
|
}
|
|
199
|
+
function inferBlockingDetails(want) {
|
|
200
|
+
var _a, _b, _c;
|
|
201
|
+
const authBlockingEndpoints = backend
|
|
202
|
+
.allEndpoints(want)
|
|
203
|
+
.filter((ep) => backend.isBlockingTriggered(ep) &&
|
|
204
|
+
v1_1.AUTH_BLOCKING_EVENTS.includes(ep.blockingTrigger.eventType));
|
|
205
|
+
if (authBlockingEndpoints.length === 0) {
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
let accessToken = false;
|
|
209
|
+
let idToken = false;
|
|
210
|
+
let refreshToken = false;
|
|
211
|
+
for (const blockingEp of authBlockingEndpoints) {
|
|
212
|
+
accessToken || (accessToken = !!((_a = blockingEp.blockingTrigger.options) === null || _a === void 0 ? void 0 : _a.accessToken));
|
|
213
|
+
idToken || (idToken = !!((_b = blockingEp.blockingTrigger.options) === null || _b === void 0 ? void 0 : _b.idToken));
|
|
214
|
+
refreshToken || (refreshToken = !!((_c = blockingEp.blockingTrigger.options) === null || _c === void 0 ? void 0 : _c.refreshToken));
|
|
215
|
+
}
|
|
216
|
+
for (const blockingEp of authBlockingEndpoints) {
|
|
217
|
+
if (!blockingEp.blockingTrigger.options) {
|
|
218
|
+
blockingEp.blockingTrigger.options = {};
|
|
219
|
+
}
|
|
220
|
+
blockingEp.blockingTrigger.options.accessToken = accessToken;
|
|
221
|
+
blockingEp.blockingTrigger.options.idToken = idToken;
|
|
222
|
+
blockingEp.blockingTrigger.options.refreshToken = refreshToken;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
exports.inferBlockingDetails = inferBlockingDetails;
|
|
@@ -14,31 +14,26 @@ const functionsConfig = require("../../functionsConfig");
|
|
|
14
14
|
const utils = require("../../utils");
|
|
15
15
|
const fsAsync = require("../../fsAsync");
|
|
16
16
|
const CONFIG_DEST_FILE = ".runtimeconfig.json";
|
|
17
|
-
async function getFunctionsConfig(
|
|
17
|
+
async function getFunctionsConfig(projectId) {
|
|
18
18
|
var _a, _b;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
try {
|
|
20
|
+
return await functionsConfig.materializeAll(projectId);
|
|
21
|
+
}
|
|
22
|
+
catch (err) {
|
|
23
|
+
logger_1.logger.debug(err);
|
|
24
|
+
let errorCode = (_b = (_a = err === null || err === void 0 ? void 0 : err.context) === null || _a === void 0 ? void 0 : _a.response) === null || _b === void 0 ? void 0 : _b.statusCode;
|
|
25
|
+
if (!errorCode) {
|
|
26
|
+
logger_1.logger.debug("Got unexpected error from Runtime Config; it has no status code:", err);
|
|
27
|
+
errorCode = 500;
|
|
23
28
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
errorCode = 500;
|
|
30
|
-
}
|
|
31
|
-
if (errorCode === 500 || errorCode === 503) {
|
|
32
|
-
throw new error_1.FirebaseError("Cloud Runtime Config is currently experiencing issues, " +
|
|
33
|
-
"which is preventing your functions from being deployed. " +
|
|
34
|
-
"Please wait a few minutes and then try to deploy your functions again." +
|
|
35
|
-
"\nRun `firebase deploy --except functions` if you want to continue deploying the rest of your project.");
|
|
36
|
-
}
|
|
37
|
-
config = {};
|
|
29
|
+
if (errorCode === 500 || errorCode === 503) {
|
|
30
|
+
throw new error_1.FirebaseError("Cloud Runtime Config is currently experiencing issues, " +
|
|
31
|
+
"which is preventing your functions from being deployed. " +
|
|
32
|
+
"Please wait a few minutes and then try to deploy your functions again." +
|
|
33
|
+
"\nRun `firebase deploy --except functions` if you want to continue deploying the rest of your project.");
|
|
38
34
|
}
|
|
39
35
|
}
|
|
40
|
-
|
|
41
|
-
return config;
|
|
36
|
+
return {};
|
|
42
37
|
}
|
|
43
38
|
exports.getFunctionsConfig = getFunctionsConfig;
|
|
44
39
|
async function pipeAsync(from, to) {
|
|
@@ -93,14 +93,17 @@ exports.V2_FREE_TIER = {
|
|
|
93
93
|
vCpu: 180000,
|
|
94
94
|
egress: 1,
|
|
95
95
|
};
|
|
96
|
+
const VCPU_TO_GHZ = 2.4;
|
|
96
97
|
const MB_TO_GHZ = {
|
|
97
98
|
128: 0.2,
|
|
98
99
|
256: 0.4,
|
|
99
100
|
512: 0.8,
|
|
100
101
|
1024: 1.4,
|
|
101
|
-
2048:
|
|
102
|
-
4096:
|
|
103
|
-
8192:
|
|
102
|
+
2048: 1 * VCPU_TO_GHZ,
|
|
103
|
+
4096: 2 * VCPU_TO_GHZ,
|
|
104
|
+
8192: 2 * VCPU_TO_GHZ,
|
|
105
|
+
16384: 4 * VCPU_TO_GHZ,
|
|
106
|
+
32768: 8 * VCPU_TO_GHZ,
|
|
104
107
|
};
|
|
105
108
|
function canCalculateMinInstanceCost(endpoint) {
|
|
106
109
|
if (!endpoint.minInstances) {
|
|
@@ -136,19 +136,13 @@ async function promptForMinInstances(options, want, have) {
|
|
|
136
136
|
const cost = pricing.monthlyMinInstanceCost(backend.allEndpoints(want)).toFixed(2);
|
|
137
137
|
costLine = `With these options, your minimum bill will be $${cost} in a 30-day month`;
|
|
138
138
|
}
|
|
139
|
-
let cudAnnotation = "";
|
|
140
|
-
if (backend.someEndpoint(want, (fn) => fn.platform === "gcfv2" && !!fn.minInstances)) {
|
|
141
|
-
cudAnnotation =
|
|
142
|
-
"\nThis bill can be lowered with a one year commitment. See https://cloud.google.com/run/cud for more";
|
|
143
|
-
}
|
|
144
139
|
const warnMessage = "The following functions have reserved minimum instances. This will " +
|
|
145
140
|
"reduce the frequency of cold starts but increases the minimum cost. " +
|
|
146
141
|
"You will be charged for the memory allocation and a fraction of the " +
|
|
147
142
|
"CPU allocation of instances while they are idle.\n\n" +
|
|
148
143
|
functionLines +
|
|
149
144
|
"\n\n" +
|
|
150
|
-
costLine
|
|
151
|
-
cudAnnotation;
|
|
145
|
+
costLine;
|
|
152
146
|
utils.logLabeledWarning("functions", warnMessage);
|
|
153
147
|
const proceed = await (0, prompt_1.promptOnce)({
|
|
154
148
|
type: "confirm",
|