firebase-tools 10.4.2 → 10.7.0
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/bin/firebase.js +1 -1
- package/lib/command.js +4 -4
- package/lib/commands/deploy.js +1 -1
- package/lib/commands/emulators-start.js +13 -3
- package/lib/commands/ext-configure.js +15 -5
- package/lib/commands/ext-dev-emulators-start.js +5 -1
- 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 +2 -5
- 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 +17 -6
- package/lib/deploy/functions/build.js +162 -0
- package/lib/deploy/functions/checkIam.js +6 -5
- package/lib/deploy/functions/deploy.js +14 -15
- package/lib/deploy/functions/ensure.js +4 -4
- package/lib/deploy/functions/functionsDeployHelper.js +54 -23
- package/lib/deploy/functions/prepare.js +92 -39
- 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 +44 -5
- package/lib/deploy/functions/release/index.js +31 -6
- package/lib/deploy/functions/release/planner.js +10 -8
- 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 +8 -5
- package/lib/deploy/hosting/args.js +2 -0
- package/lib/deploy/hosting/convertConfig.js +37 -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 +26 -20
- package/lib/emulator/auth/state.js +79 -43
- package/lib/emulator/auth/utils.js +3 -25
- package/lib/emulator/commandUtils.js +72 -2
- package/lib/emulator/controller.js +14 -5
- package/lib/emulator/downloadableEmulators.js +47 -24
- 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 +79 -7
- package/lib/emulator/functionsEmulatorShared.js +36 -21
- package/lib/emulator/registry.js +34 -12
- package/lib/emulator/shared/request.js +19 -0
- package/lib/emulator/storage/apis/firebase.js +32 -35
- package/lib/emulator/storage/apis/gcloud.js +84 -66
- package/lib/emulator/storage/files.js +56 -52
- package/lib/emulator/storage/index.js +23 -3
- package/lib/emulator/storage/metadata.js +18 -8
- package/lib/emulator/storage/rules/manager.js +7 -17
- package/lib/emulator/storage/rules/utils.js +11 -3
- 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 +24 -3
- package/lib/functions/runtimeConfigExport.js +10 -6
- package/lib/functions/secrets.js +99 -6
- package/lib/gcp/cloudfunctions.js +37 -18
- package/lib/gcp/cloudfunctionsv2.js +41 -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/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
- package/lib/emulator/storage/list.js +0 -18
|
@@ -1,40 +1,71 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getFunctionLabel = exports.
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
exports.getFunctionLabel = exports.getEndpointFilters = exports.parseFunctionSelector = exports.endpointMatchesFilter = exports.endpointMatchesAnyFilter = void 0;
|
|
4
|
+
const projectConfig = require("../../functions/projectConfig");
|
|
5
|
+
function endpointMatchesAnyFilter(endpoint, filters) {
|
|
6
|
+
if (!filters) {
|
|
6
7
|
return true;
|
|
7
8
|
}
|
|
8
|
-
return
|
|
9
|
+
return filters.some((filter) => endpointMatchesFilter(endpoint, filter));
|
|
9
10
|
}
|
|
10
|
-
exports.
|
|
11
|
-
function
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
exports.endpointMatchesAnyFilter = endpointMatchesAnyFilter;
|
|
12
|
+
function endpointMatchesFilter(endpoint, filter) {
|
|
13
|
+
if (endpoint.codebase && filter.codebase) {
|
|
14
|
+
if (endpoint.codebase !== filter.codebase) {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
if (!filter.idChunks) {
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
const idChunks = endpoint.id.split("-");
|
|
22
|
+
if (idChunks.length < filter.idChunks.length) {
|
|
14
23
|
return false;
|
|
15
24
|
}
|
|
16
|
-
for (let i = 0; i <
|
|
17
|
-
if (
|
|
25
|
+
for (let i = 0; i < filter.idChunks.length; i += 1) {
|
|
26
|
+
if (idChunks[i] !== filter.idChunks[i]) {
|
|
18
27
|
return false;
|
|
19
28
|
}
|
|
20
29
|
}
|
|
21
30
|
return true;
|
|
22
31
|
}
|
|
23
|
-
exports.
|
|
24
|
-
function
|
|
32
|
+
exports.endpointMatchesFilter = endpointMatchesFilter;
|
|
33
|
+
function parseFunctionSelector(selector) {
|
|
34
|
+
const fragments = selector.split(":");
|
|
35
|
+
if (fragments.length < 2) {
|
|
36
|
+
return [
|
|
37
|
+
{ codebase: fragments[0] },
|
|
38
|
+
{ codebase: projectConfig.DEFAULT_CODEBASE, idChunks: fragments[0].split(/[-.]/) },
|
|
39
|
+
];
|
|
40
|
+
}
|
|
41
|
+
return [
|
|
42
|
+
{
|
|
43
|
+
codebase: fragments[0],
|
|
44
|
+
idChunks: fragments[1].split(/[-.]/),
|
|
45
|
+
},
|
|
46
|
+
];
|
|
47
|
+
}
|
|
48
|
+
exports.parseFunctionSelector = parseFunctionSelector;
|
|
49
|
+
function getEndpointFilters(options) {
|
|
25
50
|
if (!options.only) {
|
|
26
|
-
return
|
|
27
|
-
}
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
const selectors = options.only.split(",");
|
|
54
|
+
const filters = [];
|
|
55
|
+
for (let selector of selectors) {
|
|
56
|
+
if (selector.startsWith("functions:")) {
|
|
57
|
+
selector = selector.replace("functions:", "");
|
|
58
|
+
if (selector.length > 0) {
|
|
59
|
+
filters.push(...parseFunctionSelector(selector));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (filters.length === 0) {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
return filters;
|
|
36
67
|
}
|
|
37
|
-
exports.
|
|
68
|
+
exports.getEndpointFilters = getEndpointFilters;
|
|
38
69
|
function getFunctionLabel(fn) {
|
|
39
70
|
return `${fn.id}(${fn.region})`;
|
|
40
71
|
}
|
|
@@ -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,6 +20,8 @@ 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
|
}
|
|
@@ -30,6 +32,25 @@ async function prepare(context, options, payload) {
|
|
|
30
32
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
31
33
|
const projectNumber = await (0, projectUtils_1.needProjectNumber)(options);
|
|
32
34
|
context.config = (0, projectConfig_1.normalizeAndValidate)(options.config.src.functions)[0];
|
|
35
|
+
context.filters = (0, functionsDeployHelper_1.getEndpointFilters)(options);
|
|
36
|
+
if (context.filters &&
|
|
37
|
+
!context.filters.map((f) => f.codebase).includes(context.config.codebase)) {
|
|
38
|
+
throw new error_1.FirebaseError("No function matches given --only filters. Aborting deployment.");
|
|
39
|
+
}
|
|
40
|
+
const checkAPIsEnabled = await Promise.all([
|
|
41
|
+
ensureApiEnabled.ensure(projectId, "cloudfunctions.googleapis.com", "functions"),
|
|
42
|
+
ensureApiEnabled.check(projectId, "runtimeconfig.googleapis.com", "runtimeconfig", true),
|
|
43
|
+
ensure.cloudBuildEnabled(projectId),
|
|
44
|
+
ensure.maybeEnableAR(projectId),
|
|
45
|
+
]);
|
|
46
|
+
context.artifactRegistryEnabled = checkAPIsEnabled[3];
|
|
47
|
+
const firebaseConfig = await functionsConfig.getFirebaseConfig(options);
|
|
48
|
+
context.firebaseConfig = firebaseConfig;
|
|
49
|
+
let runtimeConfig = { firebase: firebaseConfig };
|
|
50
|
+
if (checkAPIsEnabled[1]) {
|
|
51
|
+
runtimeConfig = Object.assign(Object.assign({}, runtimeConfig), (await (0, prepareFunctionsUpload_1.getFunctionsConfig)(projectId)));
|
|
52
|
+
}
|
|
53
|
+
(0, utils_1.logLabeledBullet)("functions", `preparing codebase ${clc.bold(context.config.codebase)} for deployment`);
|
|
33
54
|
const sourceDirName = context.config.source;
|
|
34
55
|
if (!sourceDirName) {
|
|
35
56
|
throw new error_1.FirebaseError(`No functions code detected at default location (./functions), and no functions source defined in firebase.json`);
|
|
@@ -46,17 +67,6 @@ async function prepare(context, options, payload) {
|
|
|
46
67
|
await runtimeDelegate.validate();
|
|
47
68
|
logger_1.logger.debug(`Building ${runtimeDelegate.name} source`);
|
|
48
69
|
await runtimeDelegate.build();
|
|
49
|
-
const checkAPIsEnabled = await Promise.all([
|
|
50
|
-
ensureApiEnabled.ensure(projectId, "cloudfunctions.googleapis.com", "functions"),
|
|
51
|
-
ensureApiEnabled.check(projectId, "runtimeconfig.googleapis.com", "runtimeconfig", true),
|
|
52
|
-
ensure.cloudBuildEnabled(projectId),
|
|
53
|
-
ensure.maybeEnableAR(projectId),
|
|
54
|
-
]);
|
|
55
|
-
context.runtimeConfigEnabled = checkAPIsEnabled[1];
|
|
56
|
-
context.artifactRegistryEnabled = checkAPIsEnabled[3];
|
|
57
|
-
const firebaseConfig = await functionsConfig.getFirebaseConfig(options);
|
|
58
|
-
context.firebaseConfig = firebaseConfig;
|
|
59
|
-
const runtimeConfig = await (0, prepareFunctionsUpload_1.getFunctionsConfig)(context);
|
|
60
70
|
const firebaseEnvs = functionsEnv.loadFirebaseEnvs(firebaseConfig, projectId);
|
|
61
71
|
const userEnvOpt = {
|
|
62
72
|
functionsSource: sourceDir,
|
|
@@ -76,7 +86,46 @@ async function prepare(context, options, payload) {
|
|
|
76
86
|
logger_1.logger.debug(`Analyzing ${runtimeDelegate.name} backend spec`);
|
|
77
87
|
const wantBackend = await runtimeDelegate.discoverSpec(runtimeConfig, firebaseEnvs);
|
|
78
88
|
wantBackend.environmentVariables = Object.assign(Object.assign({}, userEnvs), firebaseEnvs);
|
|
79
|
-
|
|
89
|
+
for (const endpoint of backend.allEndpoints(wantBackend)) {
|
|
90
|
+
endpoint.environmentVariables = wantBackend.environmentVariables;
|
|
91
|
+
endpoint.codebase = context.config.codebase;
|
|
92
|
+
}
|
|
93
|
+
const source = {};
|
|
94
|
+
if (backend.someEndpoint(wantBackend, () => true)) {
|
|
95
|
+
(0, utils_1.logLabeledBullet)("functions", `preparing ${clc.bold(sourceDirName)} directory for uploading...`);
|
|
96
|
+
}
|
|
97
|
+
if (backend.someEndpoint(wantBackend, (e) => e.platform === "gcfv2")) {
|
|
98
|
+
if (!previews_1.previews.functionsv2) {
|
|
99
|
+
throw new error_1.FirebaseError("This version of firebase-tools does not support Google Cloud " +
|
|
100
|
+
"Functions gen 2\n" +
|
|
101
|
+
"If Cloud Functions for Firebase gen 2 is still in alpha, sign up " +
|
|
102
|
+
"for the alpha program at " +
|
|
103
|
+
"https://services.google.com/fb/forms/firebasealphaprogram/\n" +
|
|
104
|
+
"If Cloud Functions for Firebase gen 2 is in beta, get the latest " +
|
|
105
|
+
"version of Firebse Tools with `npm i -g firebase-tools@latest`");
|
|
106
|
+
}
|
|
107
|
+
source.functionsSourceV2 = await (0, prepareFunctionsUpload_1.prepareFunctionsUpload)(sourceDir, context.config);
|
|
108
|
+
}
|
|
109
|
+
if (backend.someEndpoint(wantBackend, (e) => e.platform === "gcfv1")) {
|
|
110
|
+
source.functionsSourceV1 = await (0, prepareFunctionsUpload_1.prepareFunctionsUpload)(sourceDir, context.config, runtimeConfig);
|
|
111
|
+
}
|
|
112
|
+
context.source = source;
|
|
113
|
+
const wantEndpointNames = backend.allEndpoints(wantBackend).map((e) => backend.functionName(e));
|
|
114
|
+
const haveBackend = backend.matchingBackend(await backend.existingBackend(context), (endpoint) => {
|
|
115
|
+
var _a;
|
|
116
|
+
if (endpoint.codebase === ((_a = context.config) === null || _a === void 0 ? void 0 : _a.codebase)) {
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
return wantEndpointNames.includes(backend.functionName(endpoint));
|
|
120
|
+
});
|
|
121
|
+
inferDetailsFromExisting(wantBackend, haveBackend, usedDotenv);
|
|
122
|
+
await (0, triggerRegionHelper_1.ensureTriggerRegions)(wantBackend);
|
|
123
|
+
validate.endpointsAreValid(wantBackend);
|
|
124
|
+
inferBlockingDetails(wantBackend);
|
|
125
|
+
payload.functions = { wantBackend: wantBackend, haveBackend: haveBackend };
|
|
126
|
+
await Promise.all(Object.values(wantBackend.requiredAPIs).map(({ api }) => {
|
|
127
|
+
return ensureApiEnabled.ensure(projectId, api, "functions", false);
|
|
128
|
+
}));
|
|
80
129
|
if (backend.someEndpoint(wantBackend, (e) => e.platform === "gcfv2")) {
|
|
81
130
|
const V2_APIS = [
|
|
82
131
|
"artifactregistry.googleapis.com",
|
|
@@ -90,36 +139,13 @@ async function prepare(context, options, payload) {
|
|
|
90
139
|
});
|
|
91
140
|
await Promise.all(enablements);
|
|
92
141
|
}
|
|
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
142
|
const matchingBackend = backend.matchingBackend(wantBackend, (endpoint) => {
|
|
114
|
-
return (0, functionsDeployHelper_1.
|
|
143
|
+
return (0, functionsDeployHelper_1.endpointMatchesAnyFilter)(endpoint, context.filters);
|
|
115
144
|
});
|
|
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
145
|
await (0, prompts_1.promptForFailurePolicies)(options, matchingBackend, haveBackend);
|
|
121
146
|
await (0, prompts_1.promptForMinInstances)(options, matchingBackend, haveBackend);
|
|
122
|
-
await backend.checkAvailability(context,
|
|
147
|
+
await backend.checkAvailability(context, matchingBackend);
|
|
148
|
+
await (0, checkIam_1.ensureServiceAgentRoles)(projectNumber, matchingBackend, haveBackend);
|
|
123
149
|
await validate.secretsAreValid(projectId, matchingBackend);
|
|
124
150
|
await ensure.secretAccess(projectId, matchingBackend, haveBackend);
|
|
125
151
|
}
|
|
@@ -155,3 +181,30 @@ function maybeCopyTriggerRegion(wantE, haveE) {
|
|
|
155
181
|
}
|
|
156
182
|
wantE.eventTrigger.region = haveE.eventTrigger.region;
|
|
157
183
|
}
|
|
184
|
+
function inferBlockingDetails(want) {
|
|
185
|
+
var _a, _b, _c;
|
|
186
|
+
const authBlockingEndpoints = backend
|
|
187
|
+
.allEndpoints(want)
|
|
188
|
+
.filter((ep) => backend.isBlockingTriggered(ep) &&
|
|
189
|
+
v1_1.AUTH_BLOCKING_EVENTS.includes(ep.blockingTrigger.eventType));
|
|
190
|
+
if (authBlockingEndpoints.length === 0) {
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
let accessToken = false;
|
|
194
|
+
let idToken = false;
|
|
195
|
+
let refreshToken = false;
|
|
196
|
+
for (const blockingEp of authBlockingEndpoints) {
|
|
197
|
+
accessToken || (accessToken = !!((_a = blockingEp.blockingTrigger.options) === null || _a === void 0 ? void 0 : _a.accessToken));
|
|
198
|
+
idToken || (idToken = !!((_b = blockingEp.blockingTrigger.options) === null || _b === void 0 ? void 0 : _b.idToken));
|
|
199
|
+
refreshToken || (refreshToken = !!((_c = blockingEp.blockingTrigger.options) === null || _c === void 0 ? void 0 : _c.refreshToken));
|
|
200
|
+
}
|
|
201
|
+
for (const blockingEp of authBlockingEndpoints) {
|
|
202
|
+
if (!blockingEp.blockingTrigger.options) {
|
|
203
|
+
blockingEp.blockingTrigger.options = {};
|
|
204
|
+
}
|
|
205
|
+
blockingEp.blockingTrigger.options.accessToken = accessToken;
|
|
206
|
+
blockingEp.blockingTrigger.options.idToken = idToken;
|
|
207
|
+
blockingEp.blockingTrigger.options.refreshToken = refreshToken;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
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",
|
|
@@ -21,6 +21,8 @@ const reporter = require("./reporter");
|
|
|
21
21
|
const run = require("../../../gcp/run");
|
|
22
22
|
const scheduler = require("../../../gcp/cloudscheduler");
|
|
23
23
|
const utils = require("../../../utils");
|
|
24
|
+
const services = require("../services");
|
|
25
|
+
const v1_1 = require("../../../functions/events/v1");
|
|
24
26
|
const gcfV1PollerOptions = {
|
|
25
27
|
apiOrigin: api_1.functionsOrigin,
|
|
26
28
|
apiVersion: gcf.API_VERSION,
|
|
@@ -35,6 +37,7 @@ const gcfV2PollerOptions = {
|
|
|
35
37
|
};
|
|
36
38
|
const DEFAULT_GCFV2_CONCURRENCY = 80;
|
|
37
39
|
const rethrowAs = (endpoint, op) => (err) => {
|
|
40
|
+
logger_1.logger.error(err.message);
|
|
38
41
|
throw new reporter.DeploymentError(endpoint, op, err);
|
|
39
42
|
};
|
|
40
43
|
class Fabricator {
|
|
@@ -124,9 +127,7 @@ class Fabricator {
|
|
|
124
127
|
await this.setTrigger(endpoint);
|
|
125
128
|
}
|
|
126
129
|
async updateEndpoint(update, scraper) {
|
|
127
|
-
|
|
128
|
-
update.endpoint.labels = Object.assign(Object.assign({}, update.endpoint.labels), deploymentTool.labels());
|
|
129
|
-
}
|
|
130
|
+
update.endpoint.labels = Object.assign(Object.assign({}, update.endpoint.labels), deploymentTool.labels());
|
|
130
131
|
if (update.deleteAndRecreate) {
|
|
131
132
|
await this.deleteEndpoint(update.deleteAndRecreate);
|
|
132
133
|
await this.createEndpoint(update.endpoint, scraper);
|
|
@@ -197,6 +198,14 @@ class Fabricator {
|
|
|
197
198
|
.catch(rethrowAs(endpoint, "set invoker"));
|
|
198
199
|
}
|
|
199
200
|
}
|
|
201
|
+
else if (backend.isBlockingTriggered(endpoint) &&
|
|
202
|
+
v1_1.AUTH_BLOCKING_EVENTS.includes(endpoint.blockingTrigger.eventType)) {
|
|
203
|
+
await this.executor
|
|
204
|
+
.run(async () => {
|
|
205
|
+
await gcf.setInvokerCreate(endpoint.project, backend.functionName(endpoint), ["public"]);
|
|
206
|
+
})
|
|
207
|
+
.catch(rethrowAs(endpoint, "set invoker"));
|
|
208
|
+
}
|
|
200
209
|
}
|
|
201
210
|
async createV2Function(endpoint) {
|
|
202
211
|
var _a;
|
|
@@ -204,7 +213,7 @@ class Fabricator {
|
|
|
204
213
|
logger_1.logger.debug("Precondition failed. Cannot create a GCFv2 function without storage");
|
|
205
214
|
throw new Error("Precondition failed");
|
|
206
215
|
}
|
|
207
|
-
const apiFunction = gcfV2.functionFromEndpoint(endpoint, this.storage
|
|
216
|
+
const apiFunction = gcfV2.functionFromEndpoint(endpoint, this.storage);
|
|
208
217
|
const topic = (_a = apiFunction.eventTrigger) === null || _a === void 0 ? void 0 : _a.pubsubTopic;
|
|
209
218
|
if (topic) {
|
|
210
219
|
await this.executor
|
|
@@ -254,6 +263,12 @@ class Fabricator {
|
|
|
254
263
|
.catch(rethrowAs(endpoint, "set invoker"));
|
|
255
264
|
}
|
|
256
265
|
}
|
|
266
|
+
else if (backend.isBlockingTriggered(endpoint) &&
|
|
267
|
+
v1_1.AUTH_BLOCKING_EVENTS.includes(endpoint.blockingTrigger.eventType)) {
|
|
268
|
+
await this.executor
|
|
269
|
+
.run(() => run.setInvokerCreate(endpoint.project, serviceName, ["public"]))
|
|
270
|
+
.catch(rethrowAs(endpoint, "set invoker"));
|
|
271
|
+
}
|
|
257
272
|
const mem = endpoint.availableMemoryMb || backend.DEFAULT_MEMORY;
|
|
258
273
|
if (mem >= backend.MIN_MEMORY_FOR_CONCURRENCY && endpoint.concurrency !== 1) {
|
|
259
274
|
await this.setConcurrency(endpoint, serviceName, endpoint.concurrency || DEFAULT_GCFV2_CONCURRENCY);
|
|
@@ -281,6 +296,10 @@ class Fabricator {
|
|
|
281
296
|
else if (backend.isTaskQueueTriggered(endpoint)) {
|
|
282
297
|
invoker = endpoint.taskQueueTrigger.invoker;
|
|
283
298
|
}
|
|
299
|
+
else if (backend.isBlockingTriggered(endpoint) &&
|
|
300
|
+
v1_1.AUTH_BLOCKING_EVENTS.includes(endpoint.blockingTrigger.eventType)) {
|
|
301
|
+
invoker = ["public"];
|
|
302
|
+
}
|
|
284
303
|
if (invoker) {
|
|
285
304
|
await this.executor
|
|
286
305
|
.run(() => gcf.setInvokerUpdate(endpoint.project, backend.functionName(endpoint), invoker))
|
|
@@ -293,7 +312,7 @@ class Fabricator {
|
|
|
293
312
|
logger_1.logger.debug("Precondition failed. Cannot update a GCFv2 function without storage");
|
|
294
313
|
throw new Error("Precondition failed");
|
|
295
314
|
}
|
|
296
|
-
const apiFunction = gcfV2.functionFromEndpoint(endpoint, this.storage
|
|
315
|
+
const apiFunction = gcfV2.functionFromEndpoint(endpoint, this.storage);
|
|
297
316
|
if ((_a = apiFunction.eventTrigger) === null || _a === void 0 ? void 0 : _a.pubsubTopic) {
|
|
298
317
|
delete apiFunction.eventTrigger.pubsubTopic;
|
|
299
318
|
}
|
|
@@ -312,6 +331,10 @@ class Fabricator {
|
|
|
312
331
|
else if (backend.isTaskQueueTriggered(endpoint)) {
|
|
313
332
|
invoker = endpoint.taskQueueTrigger.invoker;
|
|
314
333
|
}
|
|
334
|
+
else if (backend.isBlockingTriggered(endpoint) &&
|
|
335
|
+
v1_1.AUTH_BLOCKING_EVENTS.includes(endpoint.blockingTrigger.eventType)) {
|
|
336
|
+
invoker = ["public"];
|
|
337
|
+
}
|
|
315
338
|
if (invoker) {
|
|
316
339
|
await this.executor
|
|
317
340
|
.run(() => run.setInvokerUpdate(endpoint.project, serviceName, invoker))
|
|
@@ -371,6 +394,9 @@ class Fabricator {
|
|
|
371
394
|
else if (backend.isTaskQueueTriggered(endpoint)) {
|
|
372
395
|
await this.upsertTaskQueue(endpoint);
|
|
373
396
|
}
|
|
397
|
+
else if (backend.isBlockingTriggered(endpoint)) {
|
|
398
|
+
await this.registerBlockingTrigger(endpoint);
|
|
399
|
+
}
|
|
374
400
|
}
|
|
375
401
|
async deleteTrigger(endpoint) {
|
|
376
402
|
if (backend.isScheduleTriggered(endpoint)) {
|
|
@@ -387,6 +413,9 @@ class Fabricator {
|
|
|
387
413
|
else if (backend.isTaskQueueTriggered(endpoint)) {
|
|
388
414
|
await this.disableTaskQueue(endpoint);
|
|
389
415
|
}
|
|
416
|
+
else if (backend.isBlockingTriggered(endpoint)) {
|
|
417
|
+
await this.unregisterBlockingTrigger(endpoint);
|
|
418
|
+
}
|
|
390
419
|
}
|
|
391
420
|
async upsertScheduleV1(endpoint) {
|
|
392
421
|
const job = scheduler.jobFromEndpoint(endpoint, this.appEngineLocation);
|
|
@@ -408,6 +437,11 @@ class Fabricator {
|
|
|
408
437
|
.catch(rethrowAs(endpoint, "set invoker"));
|
|
409
438
|
}
|
|
410
439
|
}
|
|
440
|
+
async registerBlockingTrigger(endpoint) {
|
|
441
|
+
await this.executor
|
|
442
|
+
.run(() => services.serviceForEndpoint(endpoint).registerTrigger(endpoint))
|
|
443
|
+
.catch(rethrowAs(endpoint, "register blocking trigger"));
|
|
444
|
+
}
|
|
411
445
|
async deleteScheduleV1(endpoint) {
|
|
412
446
|
const job = scheduler.jobFromEndpoint(endpoint, this.appEngineLocation);
|
|
413
447
|
await this.executor
|
|
@@ -429,6 +463,11 @@ class Fabricator {
|
|
|
429
463
|
.run(() => cloudtasks.updateQueue(update))
|
|
430
464
|
.catch(rethrowAs(endpoint, "disable task queue"));
|
|
431
465
|
}
|
|
466
|
+
async unregisterBlockingTrigger(endpoint) {
|
|
467
|
+
await this.executor
|
|
468
|
+
.run(() => services.serviceForEndpoint(endpoint).unregisterTrigger(endpoint))
|
|
469
|
+
.catch(rethrowAs(endpoint, "unregister blocking trigger"));
|
|
470
|
+
}
|
|
432
471
|
logOpStart(op, endpoint) {
|
|
433
472
|
const runtime = (0, runtimes_1.getHumanFriendlyRuntimeName)(endpoint.runtime);
|
|
434
473
|
const label = helper.getFunctionLabel(endpoint);
|
|
@@ -11,14 +11,21 @@ const fabricator = require("./fabricator");
|
|
|
11
11
|
const reporter = require("./reporter");
|
|
12
12
|
const executor = require("./executor");
|
|
13
13
|
const prompts = require("../prompts");
|
|
14
|
+
const secrets = require("../../../functions/secrets");
|
|
14
15
|
const functionsConfig_1 = require("../../../functionsConfig");
|
|
15
16
|
const functionsDeployHelper_1 = require("../functionsDeployHelper");
|
|
16
17
|
const error_1 = require("../../../error");
|
|
18
|
+
const projectUtils_1 = require("../../../projectUtils");
|
|
19
|
+
const utils_1 = require("../../../utils");
|
|
17
20
|
async function release(context, options, payload) {
|
|
18
21
|
if (!context.config) {
|
|
19
22
|
return;
|
|
20
23
|
}
|
|
21
|
-
|
|
24
|
+
if (!payload.functions) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const { wantBackend, haveBackend } = payload.functions;
|
|
28
|
+
const plan = planner.createDeploymentPlan(wantBackend, haveBackend, context.filters);
|
|
22
29
|
const fnsToDelete = Object.values(plan)
|
|
23
30
|
.map((regionalChanges) => regionalChanges.endpointsToDelete)
|
|
24
31
|
.reduce(functional_1.reduceFlat, []);
|
|
@@ -37,15 +44,15 @@ async function release(context, options, payload) {
|
|
|
37
44
|
const fab = new fabricator.Fabricator({
|
|
38
45
|
functionExecutor,
|
|
39
46
|
executor: new executor.QueueExecutor({}),
|
|
40
|
-
sourceUrl: context.sourceUrl,
|
|
41
|
-
storage: context.storage,
|
|
47
|
+
sourceUrl: context.source.sourceUrl,
|
|
48
|
+
storage: context.source.storage,
|
|
42
49
|
appEngineLocation: (0, functionsConfig_1.getAppEngineLocation)(context.firebaseConfig),
|
|
43
50
|
});
|
|
44
51
|
const summary = await fab.applyPlan(plan);
|
|
45
52
|
await reporter.logAndTrackDeployStats(summary);
|
|
46
53
|
reporter.printErrors(summary);
|
|
47
|
-
printTriggerUrls(payload.functions.
|
|
48
|
-
const haveEndpoints = backend.allEndpoints(payload.functions.
|
|
54
|
+
printTriggerUrls(payload.functions.wantBackend);
|
|
55
|
+
const haveEndpoints = backend.allEndpoints(payload.functions.wantBackend);
|
|
49
56
|
const deletedEndpoints = Object.values(plan)
|
|
50
57
|
.map((r) => r.endpointsToDelete)
|
|
51
58
|
.reduce(functional_1.reduceFlat, []);
|
|
@@ -59,6 +66,24 @@ async function release(context, options, payload) {
|
|
|
59
66
|
const opts = allErrors.length === 1 ? { original: allErrors[0] } : { children: allErrors };
|
|
60
67
|
throw new error_1.FirebaseError("There was an error deploying functions", Object.assign(Object.assign({}, opts), { exit: 2 }));
|
|
61
68
|
}
|
|
69
|
+
else {
|
|
70
|
+
if (secrets.of(haveEndpoints).length > 0) {
|
|
71
|
+
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
72
|
+
const projectNumber = await (0, projectUtils_1.needProjectNumber)(options);
|
|
73
|
+
const reloadedBackend = await backend.existingBackend({ projectId });
|
|
74
|
+
const prunedResult = await secrets.pruneAndDestroySecrets({ projectId, projectNumber }, backend.allEndpoints(reloadedBackend));
|
|
75
|
+
if (prunedResult.destroyed.length > 0) {
|
|
76
|
+
(0, utils_1.logLabeledBullet)("functions", `Destroyed unused secret versions: ${prunedResult.destroyed
|
|
77
|
+
.map((s) => `${s.secret}@${s.version}`)
|
|
78
|
+
.join(", ")}`);
|
|
79
|
+
}
|
|
80
|
+
if (prunedResult.erred.length > 0) {
|
|
81
|
+
(0, utils_1.logLabeledWarning)("functions", `Failed to destroy unused secret versions:\n\t${prunedResult.erred
|
|
82
|
+
.map((err) => err.message)
|
|
83
|
+
.join("\n\t")}`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
62
87
|
}
|
|
63
88
|
exports.release = release;
|
|
64
89
|
function printTriggerUrls(results) {
|
|
@@ -68,7 +93,7 @@ function printTriggerUrls(results) {
|
|
|
68
93
|
}
|
|
69
94
|
for (const httpsFunc of httpsFunctions) {
|
|
70
95
|
if (!httpsFunc.uri) {
|
|
71
|
-
logger_1.logger.debug("
|
|
96
|
+
logger_1.logger.debug("Not printing URL for HTTPS function. Typically this means it didn't match a filter or we failed deployment");
|
|
72
97
|
continue;
|
|
73
98
|
}
|
|
74
99
|
logger_1.logger.info(clc.bold("Function URL"), `(${(0, functionsDeployHelper_1.getFunctionLabel)(httpsFunc)}):`, httpsFunc.uri);
|
|
@@ -7,13 +7,13 @@ const error_1 = require("../../../error");
|
|
|
7
7
|
const utils = require("../../../utils");
|
|
8
8
|
const backend = require("../backend");
|
|
9
9
|
const v2events = require("../../../functions/events/v2");
|
|
10
|
-
function calculateChangesets(want, have, keyFn,
|
|
10
|
+
function calculateChangesets(want, have, keyFn, deleteAll) {
|
|
11
11
|
const toCreate = utils.groupBy(Object.keys(want)
|
|
12
12
|
.filter((id) => !have[id])
|
|
13
13
|
.map((id) => want[id]), keyFn);
|
|
14
14
|
const toDelete = utils.groupBy(Object.keys(have)
|
|
15
15
|
.filter((id) => !want[id])
|
|
16
|
-
.filter((id) =>
|
|
16
|
+
.filter((id) => deleteAll || (0, deploymentTool_1.isFirebaseManaged)(have[id].labels || {}))
|
|
17
17
|
.map((id) => have[id]), keyFn);
|
|
18
18
|
const toUpdate = utils.groupBy(Object.keys(want)
|
|
19
19
|
.filter((id) => have[id])
|
|
@@ -48,17 +48,17 @@ function calculateUpdate(want, have) {
|
|
|
48
48
|
return update;
|
|
49
49
|
}
|
|
50
50
|
exports.calculateUpdate = calculateUpdate;
|
|
51
|
-
function createDeploymentPlan(want, have,
|
|
51
|
+
function createDeploymentPlan(want, have, filters, deleteAll) {
|
|
52
52
|
let deployment = {};
|
|
53
53
|
want = backend.matchingBackend(want, (endpoint) => {
|
|
54
|
-
return (0, functionsDeployHelper_1.
|
|
54
|
+
return (0, functionsDeployHelper_1.endpointMatchesAnyFilter)(endpoint, filters);
|
|
55
55
|
});
|
|
56
56
|
have = backend.matchingBackend(have, (endpoint) => {
|
|
57
|
-
return (0, functionsDeployHelper_1.
|
|
57
|
+
return (0, functionsDeployHelper_1.endpointMatchesAnyFilter)(endpoint, filters);
|
|
58
58
|
});
|
|
59
59
|
const regions = new Set([...Object.keys(want.endpoints), ...Object.keys(have.endpoints)]);
|
|
60
60
|
for (const region of regions) {
|
|
61
|
-
const changesets = calculateChangesets(want.endpoints[region] || {}, have.endpoints[region] || {}, (e) => `${e.region}-${e.availableMemoryMb || "default"}`,
|
|
61
|
+
const changesets = calculateChangesets(want.endpoints[region] || {}, have.endpoints[region] || {}, (e) => `${e.region}-${e.availableMemoryMb || "default"}`, deleteAll);
|
|
62
62
|
deployment = Object.assign(Object.assign({}, deployment), changesets);
|
|
63
63
|
}
|
|
64
64
|
if (upgradedToGCFv2WithoutSettingConcurrency(want, have)) {
|
|
@@ -103,7 +103,6 @@ function changedTriggerRegion(want, have) {
|
|
|
103
103
|
}
|
|
104
104
|
exports.changedTriggerRegion = changedTriggerRegion;
|
|
105
105
|
function changedV2PubSubTopic(want, have) {
|
|
106
|
-
var _a, _b;
|
|
107
106
|
if (want.platform !== "gcfv2") {
|
|
108
107
|
return false;
|
|
109
108
|
}
|
|
@@ -122,7 +121,7 @@ function changedV2PubSubTopic(want, have) {
|
|
|
122
121
|
if (have.eventTrigger.eventType !== v2events.PUBSUB_PUBLISH_EVENT) {
|
|
123
122
|
return false;
|
|
124
123
|
}
|
|
125
|
-
return
|
|
124
|
+
return have.eventTrigger.eventFilters.topic !== want.eventTrigger.eventFilters.topic;
|
|
126
125
|
}
|
|
127
126
|
exports.changedV2PubSubTopic = changedV2PubSubTopic;
|
|
128
127
|
function upgradedScheduleFromV1ToV2(want, have) {
|
|
@@ -158,6 +157,9 @@ function checkForIllegalUpdate(want, have) {
|
|
|
158
157
|
else if (backend.isTaskQueueTriggered(e)) {
|
|
159
158
|
return "a task queue";
|
|
160
159
|
}
|
|
160
|
+
else if (backend.isBlockingTriggered(e)) {
|
|
161
|
+
return e.blockingTrigger.eventType;
|
|
162
|
+
}
|
|
161
163
|
throw Error("Functions release planner is not able to handle an unknown trigger type");
|
|
162
164
|
};
|
|
163
165
|
const wantType = triggerType(want);
|