firebase-tools 10.2.2 → 10.3.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/commands/ext-configure.js +58 -4
- package/lib/commands/ext-export.js +4 -9
- package/lib/commands/ext-install.js +63 -4
- package/lib/commands/ext-uninstall.js +9 -0
- package/lib/commands/ext-update.js +55 -2
- package/lib/config.js +6 -3
- package/lib/deploy/extensions/planner.js +6 -6
- package/lib/deploy/functions/backend.js +10 -1
- package/lib/deploy/functions/checkIam.js +4 -4
- package/lib/deploy/functions/prepare.js +2 -1
- package/lib/deploy/functions/release/fabricator.js +4 -4
- package/lib/deploy/functions/release/planner.js +34 -20
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +6 -1
- package/lib/deploy/functions/runtimes/node/index.js +27 -0
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +24 -8
- package/lib/deploy/functions/services/firebaseAlerts.js +30 -0
- package/lib/deploy/functions/services/index.js +9 -1
- package/lib/deploy/functions/services/storage.js +10 -4
- package/lib/deploy/functions/triggerRegionHelper.js +1 -1
- package/lib/emulator/constants.js +1 -0
- package/lib/emulator/controller.js +9 -7
- package/lib/emulator/extensions/validation.js +37 -2
- package/lib/emulator/extensionsEmulator.js +44 -9
- package/lib/emulator/functionsEmulator.js +13 -8
- package/lib/emulator/functionsEmulatorShared.js +17 -10
- package/lib/emulator/storage/apis/firebase.js +312 -335
- package/lib/emulator/storage/apis/gcloud.js +238 -113
- package/lib/emulator/storage/crc.js +5 -1
- package/lib/emulator/storage/errors.js +9 -0
- package/lib/emulator/storage/files.js +161 -304
- package/lib/emulator/storage/index.js +27 -73
- package/lib/emulator/storage/metadata.js +63 -49
- package/lib/emulator/storage/multipart.js +62 -0
- package/lib/emulator/storage/persistence.js +78 -0
- package/lib/emulator/storage/rules/config.js +33 -0
- package/lib/emulator/storage/rules/manager.js +81 -0
- package/lib/emulator/storage/rules/utils.js +48 -0
- package/lib/emulator/storage/server.js +2 -2
- package/lib/emulator/storage/upload.js +106 -0
- package/lib/extensions/emulator/optionsHelper.js +35 -3
- package/lib/extensions/extensionsHelper.js +19 -10
- package/lib/extensions/manifest.js +109 -13
- package/lib/extensions/paramHelper.js +5 -4
- package/lib/functions/env.js +4 -6
- package/lib/functions/events/v2.js +11 -0
- package/lib/gcp/cloudfunctions.js +18 -6
- package/lib/gcp/cloudfunctionsv2.js +30 -12
- package/lib/gcp/resourceManager.js +4 -4
- package/lib/serve/functions.js +2 -1
- package/lib/utils.js +14 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/lib/deploy/extensions/params.js +0 -42
- package/lib/deploy/functions/eventTypes.js +0 -10
|
@@ -15,6 +15,9 @@ const paramHelper = require("../extensions/paramHelper");
|
|
|
15
15
|
const requirePermissions_1 = require("../requirePermissions");
|
|
16
16
|
const utils = require("../utils");
|
|
17
17
|
const logger_1 = require("../logger");
|
|
18
|
+
const refs = require("../extensions/refs");
|
|
19
|
+
const manifest = require("../extensions/manifest");
|
|
20
|
+
const functional_1 = require("../functional");
|
|
18
21
|
marked.setOptions({
|
|
19
22
|
renderer: new TerminalRenderer(),
|
|
20
23
|
});
|
|
@@ -22,6 +25,7 @@ exports.default = new command_1.Command("ext:configure <extensionInstanceId>")
|
|
|
22
25
|
.description("configure an existing extension instance")
|
|
23
26
|
.withForce()
|
|
24
27
|
.option("--params <paramsFile>", "path of params file with .env format.")
|
|
28
|
+
.option("--local", "save to firebase.json rather than directly install to a Firebase project")
|
|
25
29
|
.before(requirePermissions_1.requirePermissions, [
|
|
26
30
|
"firebaseextensions.instances.update",
|
|
27
31
|
"firebaseextensions.instances.get",
|
|
@@ -29,9 +33,46 @@ exports.default = new command_1.Command("ext:configure <extensionInstanceId>")
|
|
|
29
33
|
.before(checkMinRequiredVersion_1.checkMinRequiredVersion, "extMinVersion")
|
|
30
34
|
.before(extensionsHelper_1.diagnoseAndFixProject)
|
|
31
35
|
.action(async (instanceId, options) => {
|
|
36
|
+
var _a;
|
|
37
|
+
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
38
|
+
if (options.local) {
|
|
39
|
+
if (options.nonInteractive) {
|
|
40
|
+
throw new error_1.FirebaseError(`Command not supported in non-interactive mode, edit ./extensions/${instanceId}.env directly instead`);
|
|
41
|
+
}
|
|
42
|
+
const config = manifest.loadConfig(options);
|
|
43
|
+
const targetRef = manifest.getInstanceRef(instanceId, config);
|
|
44
|
+
const extensionVersion = await extensionsApi.getExtensionVersion(refs.toExtensionVersionRef(targetRef));
|
|
45
|
+
const oldParamValues = manifest.readInstanceParam({
|
|
46
|
+
instanceId,
|
|
47
|
+
projectDir: config.projectDir,
|
|
48
|
+
});
|
|
49
|
+
const [immutableParams, tbdParams] = (0, functional_1.partition)(extensionVersion.spec.params, (param) => { var _a; return (_a = param.immutable) !== null && _a !== void 0 ? _a : false; });
|
|
50
|
+
infoImmutableParams(immutableParams, oldParamValues);
|
|
51
|
+
paramHelper.setNewDefaults(tbdParams, oldParamValues);
|
|
52
|
+
const mutableParamsValues = await paramHelper.getParams({
|
|
53
|
+
projectId,
|
|
54
|
+
paramSpecs: tbdParams,
|
|
55
|
+
nonInteractive: false,
|
|
56
|
+
paramsEnvPath: ((_a = options.params) !== null && _a !== void 0 ? _a : ""),
|
|
57
|
+
instanceId,
|
|
58
|
+
reconfiguring: true,
|
|
59
|
+
});
|
|
60
|
+
const newParamValues = Object.assign(Object.assign({}, oldParamValues), mutableParamsValues);
|
|
61
|
+
await manifest.writeToManifest([
|
|
62
|
+
{
|
|
63
|
+
instanceId,
|
|
64
|
+
ref: targetRef,
|
|
65
|
+
params: newParamValues,
|
|
66
|
+
},
|
|
67
|
+
], config, {
|
|
68
|
+
nonInteractive: false,
|
|
69
|
+
force: true,
|
|
70
|
+
});
|
|
71
|
+
manifest.showPreviewWarning();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
32
74
|
const spinner = ora(`Configuring ${clc.bold(instanceId)}. This usually takes 3 to 5 minutes...`);
|
|
33
75
|
try {
|
|
34
|
-
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
35
76
|
let existingInstance;
|
|
36
77
|
try {
|
|
37
78
|
existingInstance = await extensionsApi.getInstance(projectId, instanceId);
|
|
@@ -45,9 +86,7 @@ exports.default = new command_1.Command("ext:configure <extensionInstanceId>")
|
|
|
45
86
|
throw err;
|
|
46
87
|
}
|
|
47
88
|
const paramSpecWithNewDefaults = paramHelper.getParamsWithCurrentValuesAsDefaults(existingInstance);
|
|
48
|
-
const immutableParams = _.remove(paramSpecWithNewDefaults, (param) =>
|
|
49
|
-
return param.immutable || param.param === "LOCATION";
|
|
50
|
-
});
|
|
89
|
+
const immutableParams = _.remove(paramSpecWithNewDefaults, (param) => param.immutable);
|
|
51
90
|
const params = await paramHelper.getParams({
|
|
52
91
|
projectId,
|
|
53
92
|
paramSpecs: paramSpecWithNewDefaults,
|
|
@@ -74,6 +113,7 @@ exports.default = new command_1.Command("ext:configure <extensionInstanceId>")
|
|
|
74
113
|
spinner.stop();
|
|
75
114
|
utils.logLabeledSuccess(extensionsHelper_1.logPrefix, `successfully configured ${clc.bold(instanceId)}.`);
|
|
76
115
|
utils.logLabeledBullet(extensionsHelper_1.logPrefix, marked(`You can view your reconfigured instance in the Firebase console: ${utils.consoleUrl(projectId, `/extensions/instances/${instanceId}?tab=config`)}`));
|
|
116
|
+
manifest.showDeprecationWarning();
|
|
77
117
|
return res;
|
|
78
118
|
}
|
|
79
119
|
catch (err) {
|
|
@@ -88,3 +128,17 @@ exports.default = new command_1.Command("ext:configure <extensionInstanceId>")
|
|
|
88
128
|
throw err;
|
|
89
129
|
}
|
|
90
130
|
});
|
|
131
|
+
function infoImmutableParams(immutableParams, paramValues) {
|
|
132
|
+
if (!immutableParams.length) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const plural = immutableParams.length > 1;
|
|
136
|
+
utils.logLabeledWarning(extensionsHelper_1.logPrefix, marked(`The following param${plural ? "s are" : " is"} immutable and won't be changed:`));
|
|
137
|
+
for (const { param } of immutableParams) {
|
|
138
|
+
logger_1.logger.info(`param: ${param}, value: ${paramValues[param]}`);
|
|
139
|
+
}
|
|
140
|
+
logger_1.logger.info((plural
|
|
141
|
+
? "To set different values for these params"
|
|
142
|
+
: "To set a different value for this param") +
|
|
143
|
+
", uninstall the extension, then install a new instance of this extension.");
|
|
144
|
+
}
|
|
@@ -2,12 +2,10 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const checkMinRequiredVersion_1 = require("../checkMinRequiredVersion");
|
|
4
4
|
const command_1 = require("../command");
|
|
5
|
-
const config_1 = require("../config");
|
|
6
5
|
const planner = require("../deploy/extensions/planner");
|
|
7
|
-
const error_1 = require("../error");
|
|
8
6
|
const export_1 = require("../extensions/export");
|
|
9
7
|
const extensionsHelper_1 = require("../extensions/extensionsHelper");
|
|
10
|
-
const
|
|
8
|
+
const manifest = require("../extensions/manifest");
|
|
11
9
|
const functional_1 = require("../functional");
|
|
12
10
|
const getProjectNumber_1 = require("../getProjectNumber");
|
|
13
11
|
const logger_1 = require("../logger");
|
|
@@ -43,12 +41,9 @@ module.exports = new command_1.Command("ext:export")
|
|
|
43
41
|
logger_1.logger.info("Exiting. No changes made.");
|
|
44
42
|
return;
|
|
45
43
|
}
|
|
46
|
-
const existingConfig =
|
|
47
|
-
|
|
48
|
-
throw new error_1.FirebaseError("Not currently in a Firebase directory. Please run `firebase init` to create a Firebase directory.");
|
|
49
|
-
}
|
|
50
|
-
await (0, manifest_1.writeToManifest)(withRef, existingConfig, {
|
|
44
|
+
const existingConfig = manifest.loadConfig(options);
|
|
45
|
+
await manifest.writeToManifest(withRef, existingConfig, {
|
|
51
46
|
nonInteractive: options.nonInteractive,
|
|
52
47
|
force: options.force,
|
|
53
|
-
});
|
|
48
|
+
}, true);
|
|
54
49
|
});
|
|
@@ -27,6 +27,7 @@ const utils = require("../utils");
|
|
|
27
27
|
const track_1 = require("../track");
|
|
28
28
|
const logger_1 = require("../logger");
|
|
29
29
|
const previews_1 = require("../previews");
|
|
30
|
+
const manifest = require("../extensions/manifest");
|
|
30
31
|
marked.setOptions({
|
|
31
32
|
renderer: new TerminalRenderer(),
|
|
32
33
|
});
|
|
@@ -38,13 +39,15 @@ exports.default = new command_1.Command("ext:install [extensionName]")
|
|
|
38
39
|
"or run with `-i` to see all available extensions.")
|
|
39
40
|
.withForce()
|
|
40
41
|
.option("--params <paramsFile>", "name of params variables file with .env format.")
|
|
42
|
+
.option("--local", "save to firebase.json rather than directly install to a Firebase project")
|
|
41
43
|
.before(requirePermissions_1.requirePermissions, ["firebaseextensions.instances.create"])
|
|
42
44
|
.before(extensionsHelper_1.ensureExtensionsApiEnabled)
|
|
43
45
|
.before(checkMinRequiredVersion_1.checkMinRequiredVersion, "extMinVersion")
|
|
44
46
|
.before(extensionsHelper_1.diagnoseAndFixProject)
|
|
45
47
|
.action(async (extensionName, options) => {
|
|
48
|
+
var _a;
|
|
46
49
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
47
|
-
const paramsEnvPath = options.params;
|
|
50
|
+
const paramsEnvPath = ((_a = options.params) !== null && _a !== void 0 ? _a : "");
|
|
48
51
|
let learnMore = false;
|
|
49
52
|
if (!extensionName) {
|
|
50
53
|
if (options.interactive) {
|
|
@@ -59,12 +62,18 @@ exports.default = new command_1.Command("ext:install [extensionName]")
|
|
|
59
62
|
}
|
|
60
63
|
let source;
|
|
61
64
|
let extVersion;
|
|
65
|
+
if ((0, extensionsHelper_1.isUrlPath)(extensionName)) {
|
|
66
|
+
void (0, track_1.track)("Extension Install", "Install by url path", options.interactive ? 1 : 0);
|
|
67
|
+
}
|
|
62
68
|
if ((0, extensionsHelper_1.isLocalOrURLPath)(extensionName)) {
|
|
63
|
-
(0, track_1.track)("Extension Install", "Install by Source", options.interactive ? 1 : 0);
|
|
69
|
+
void (0, track_1.track)("Extension Install", "Install by Source", options.interactive ? 1 : 0);
|
|
70
|
+
if (options.local) {
|
|
71
|
+
throw new error_1.FirebaseError("Installing a local source locally is not supported yet, please use ext:dev:emulator commands");
|
|
72
|
+
}
|
|
64
73
|
source = await infoInstallBySource(projectId, extensionName);
|
|
65
74
|
}
|
|
66
75
|
else {
|
|
67
|
-
(0, track_1.track)("Extension Install", "Install by Extension Ref", options.interactive ? 1 : 0);
|
|
76
|
+
void (0, track_1.track)("Extension Install", "Install by Extension Ref", options.interactive ? 1 : 0);
|
|
68
77
|
extVersion = await infoInstallByReference(extensionName, options.interactive);
|
|
69
78
|
}
|
|
70
79
|
if (!(await (0, extensionsHelper_1.confirm)({
|
|
@@ -86,6 +95,27 @@ exports.default = new command_1.Command("ext:install [extensionName]")
|
|
|
86
95
|
`${spec.description}\n` +
|
|
87
96
|
`View details: https://firebase.google.com/products/extensions/${spec.name}\n`);
|
|
88
97
|
}
|
|
98
|
+
if (options.local) {
|
|
99
|
+
try {
|
|
100
|
+
return installToManifest({
|
|
101
|
+
paramsEnvPath,
|
|
102
|
+
projectId,
|
|
103
|
+
extensionName,
|
|
104
|
+
source,
|
|
105
|
+
extVersion,
|
|
106
|
+
nonInteractive: options.nonInteractive,
|
|
107
|
+
force: options.force,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
if (!(err instanceof error_1.FirebaseError)) {
|
|
112
|
+
throw new error_1.FirebaseError(`Error occurred saving the extension to manifest: ${err.message}`, {
|
|
113
|
+
original: err,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
throw err;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
89
119
|
try {
|
|
90
120
|
return installExtension({
|
|
91
121
|
paramsEnvPath,
|
|
@@ -126,7 +156,7 @@ async function infoInstallByReference(extensionName, interactive) {
|
|
|
126
156
|
const ref = refs.parse(extensionName);
|
|
127
157
|
const extension = await extensionsApi.getExtension(refs.toExtensionRef(ref));
|
|
128
158
|
if (!ref.version) {
|
|
129
|
-
(0, track_1.track)("Extension Install", "Install by Extension Version Ref", interactive ? 1 : 0);
|
|
159
|
+
void (0, track_1.track)("Extension Install", "Install by Extension Version Ref", interactive ? 1 : 0);
|
|
130
160
|
extensionName = `${extensionName}@latest`;
|
|
131
161
|
}
|
|
132
162
|
const extVersion = await extensionsApi.getExtensionVersion(extensionName);
|
|
@@ -134,6 +164,34 @@ async function infoInstallByReference(extensionName, interactive) {
|
|
|
134
164
|
await (0, warnings_1.displayWarningPrompts)(ref.publisherId, extension.registryLaunchStage, extVersion);
|
|
135
165
|
return extVersion;
|
|
136
166
|
}
|
|
167
|
+
async function installToManifest(options) {
|
|
168
|
+
const { projectId, extensionName, extVersion, paramsEnvPath, nonInteractive, force } = options;
|
|
169
|
+
const spec = extVersion === null || extVersion === void 0 ? void 0 : extVersion.spec;
|
|
170
|
+
if (!spec) {
|
|
171
|
+
throw new error_1.FirebaseError(`Could not find the extension.yaml for ${extensionName}. Please make sure this is a valid extension and try again.`);
|
|
172
|
+
}
|
|
173
|
+
const config = manifest.loadConfig(options);
|
|
174
|
+
let instanceId = spec.name;
|
|
175
|
+
while (manifest.instanceExists(instanceId, config)) {
|
|
176
|
+
instanceId = await (0, extensionsHelper_1.promptForValidInstanceId)(`${spec.name}-${(0, utils_1.getRandomString)(4)}`);
|
|
177
|
+
}
|
|
178
|
+
const params = await paramHelper.getParams({
|
|
179
|
+
projectId,
|
|
180
|
+
paramSpecs: spec.params,
|
|
181
|
+
nonInteractive,
|
|
182
|
+
paramsEnvPath,
|
|
183
|
+
instanceId,
|
|
184
|
+
});
|
|
185
|
+
const ref = refs.parse(extVersion.ref);
|
|
186
|
+
await manifest.writeToManifest([
|
|
187
|
+
{
|
|
188
|
+
instanceId,
|
|
189
|
+
ref,
|
|
190
|
+
params,
|
|
191
|
+
},
|
|
192
|
+
], config, { nonInteractive, force: force !== null && force !== void 0 ? force : false });
|
|
193
|
+
manifest.showPreviewWarning();
|
|
194
|
+
}
|
|
137
195
|
async function installExtension(options) {
|
|
138
196
|
const { projectId, extensionName, source, extVersion, paramsEnvPath, nonInteractive, force } = options;
|
|
139
197
|
const spec = (source === null || source === void 0 ? void 0 : source.spec) || (extVersion === null || extVersion === void 0 ? void 0 : extVersion.spec);
|
|
@@ -253,6 +311,7 @@ async function installExtension(options) {
|
|
|
253
311
|
`which may include some required post-installation tasks: ${utils.consoleUrl(projectId, `/extensions/instances/${instanceId}?tab=usage`)}`));
|
|
254
312
|
logger_1.logger.info(marked("You can run `firebase ext` to view available Firebase Extensions commands, " +
|
|
255
313
|
"including those to update, reconfigure, or delete your installed extension."));
|
|
314
|
+
manifest.showDeprecationWarning();
|
|
256
315
|
}
|
|
257
316
|
catch (err) {
|
|
258
317
|
if (spinner.isSpinning) {
|
|
@@ -16,17 +16,25 @@ const prompt_1 = require("../prompt");
|
|
|
16
16
|
const requirePermissions_1 = require("../requirePermissions");
|
|
17
17
|
const utils = require("../utils");
|
|
18
18
|
const logger_1 = require("../logger");
|
|
19
|
+
const manifest = require("../extensions/manifest");
|
|
19
20
|
marked.setOptions({
|
|
20
21
|
renderer: new TerminalRenderer(),
|
|
21
22
|
});
|
|
22
23
|
exports.default = new command_1.Command("ext:uninstall <extensionInstanceId>")
|
|
23
24
|
.description("uninstall an extension that is installed in your Firebase project by instance ID")
|
|
24
25
|
.withForce()
|
|
26
|
+
.option("--local", "remove from firebase.json rather than directly uninstall from a Firebase project")
|
|
25
27
|
.before(requirePermissions_1.requirePermissions, ["firebaseextensions.instances.delete"])
|
|
26
28
|
.before(extensionsHelper_1.ensureExtensionsApiEnabled)
|
|
27
29
|
.before(checkMinRequiredVersion_1.checkMinRequiredVersion, "extMinVersion")
|
|
28
30
|
.before(extensionsHelper_1.diagnoseAndFixProject)
|
|
29
31
|
.action(async (instanceId, options) => {
|
|
32
|
+
if (options.local) {
|
|
33
|
+
const config = manifest.loadConfig(options);
|
|
34
|
+
manifest.removeFromManifest(instanceId, config);
|
|
35
|
+
manifest.showPreviewWarning();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
30
38
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
31
39
|
let instance;
|
|
32
40
|
try {
|
|
@@ -93,6 +101,7 @@ exports.default = new command_1.Command("ext:uninstall <extensionInstanceId>")
|
|
|
93
101
|
return utils.reject(`Error occurred uninstalling extension ${instanceId}`, { original: err });
|
|
94
102
|
}
|
|
95
103
|
utils.logLabeledSuccess(extensionsHelper_1.logPrefix, `uninstalled ${clc.bold(instanceId)}`);
|
|
104
|
+
manifest.showDeprecationWarning();
|
|
96
105
|
});
|
|
97
106
|
function consoleUninstallOnly(projectId, instanceId) {
|
|
98
107
|
const instanceURL = `https://console.firebase.google.com/project/${projectId}/extensions/instances/${instanceId}`;
|
|
@@ -22,6 +22,7 @@ const projectUtils_1 = require("../projectUtils");
|
|
|
22
22
|
const requirePermissions_1 = require("../requirePermissions");
|
|
23
23
|
const utils = require("../utils");
|
|
24
24
|
const previews_1 = require("../previews");
|
|
25
|
+
const manifest = require("../extensions/manifest");
|
|
25
26
|
marked.setOptions({
|
|
26
27
|
renderer: new TerminalRenderer(),
|
|
27
28
|
});
|
|
@@ -38,10 +39,61 @@ exports.default = new command_1.Command("ext:update <extensionInstanceId> [updat
|
|
|
38
39
|
.before(extensionsHelper_1.diagnoseAndFixProject)
|
|
39
40
|
.withForce()
|
|
40
41
|
.option("--params <paramsFile>", "name of params variables file with .env format.")
|
|
42
|
+
.option("--local", "save the update to firebase.json rather than directly update an existing Extension instance on a Firebase project")
|
|
41
43
|
.action(async (instanceId, updateSource, options) => {
|
|
44
|
+
var _a, _b;
|
|
45
|
+
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
46
|
+
if (options.local) {
|
|
47
|
+
const config = manifest.loadConfig(options);
|
|
48
|
+
const oldRef = manifest.getInstanceRef(instanceId, config);
|
|
49
|
+
const oldExtensionVersion = await extensionsApi.getExtensionVersion(refs.toExtensionVersionRef(oldRef));
|
|
50
|
+
updateSource = (0, updateHelper_1.inferUpdateSource)(updateSource, refs.toExtensionRef(oldRef));
|
|
51
|
+
const newSourceOrigin = (0, extensionsHelper_1.getSourceOrigin)(updateSource);
|
|
52
|
+
if (![extensionsHelper_1.SourceOrigin.PUBLISHED_EXTENSION, extensionsHelper_1.SourceOrigin.PUBLISHED_EXTENSION_VERSION].includes(newSourceOrigin)) {
|
|
53
|
+
throw new error_1.FirebaseError(`Only updating to a published extension version is allowed`);
|
|
54
|
+
}
|
|
55
|
+
const newExtensionVersion = await extensionsApi.getExtensionVersion(updateSource);
|
|
56
|
+
if (oldExtensionVersion.ref === newExtensionVersion.ref) {
|
|
57
|
+
utils.logLabeledBullet(extensionsHelper_1.logPrefix, `${clc.bold(instanceId)} is already up to date. Its version is ${clc.bold(newExtensionVersion.ref)}.`);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
utils.logLabeledBullet(extensionsHelper_1.logPrefix, `Updating ${clc.bold(instanceId)} from version ${clc.bold(oldExtensionVersion.ref)} to version ${clc.bold(newExtensionVersion.ref)}.`);
|
|
61
|
+
if (!(await (0, extensionsHelper_1.confirm)({
|
|
62
|
+
nonInteractive: options.nonInteractive,
|
|
63
|
+
force: options.force,
|
|
64
|
+
default: false,
|
|
65
|
+
}))) {
|
|
66
|
+
utils.logLabeledBullet(extensionsHelper_1.logPrefix, "Update aborted.");
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const oldParamValues = manifest.readInstanceParam({
|
|
70
|
+
instanceId,
|
|
71
|
+
projectDir: config.projectDir,
|
|
72
|
+
});
|
|
73
|
+
const newParams = await paramHelper.getParamsForUpdate({
|
|
74
|
+
spec: oldExtensionVersion.spec,
|
|
75
|
+
newSpec: newExtensionVersion.spec,
|
|
76
|
+
currentParams: oldParamValues,
|
|
77
|
+
projectId,
|
|
78
|
+
paramsEnvPath: ((_a = options.params) !== null && _a !== void 0 ? _a : ""),
|
|
79
|
+
nonInteractive: options.nonInteractive,
|
|
80
|
+
instanceId,
|
|
81
|
+
});
|
|
82
|
+
await manifest.writeToManifest([
|
|
83
|
+
{
|
|
84
|
+
instanceId,
|
|
85
|
+
ref: refs.parse(newExtensionVersion.ref),
|
|
86
|
+
params: newParams,
|
|
87
|
+
},
|
|
88
|
+
], config, {
|
|
89
|
+
nonInteractive: options.nonInteractive,
|
|
90
|
+
force: true,
|
|
91
|
+
});
|
|
92
|
+
manifest.showPreviewWarning();
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
42
95
|
const spinner = ora(`Updating ${clc.bold(instanceId)}. This usually takes 3 to 5 minutes...`);
|
|
43
96
|
try {
|
|
44
|
-
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
45
97
|
let existingInstance;
|
|
46
98
|
try {
|
|
47
99
|
existingInstance = await extensionsApi.getInstance(projectId, instanceId);
|
|
@@ -148,7 +200,7 @@ exports.default = new command_1.Command("ext:update <extensionInstanceId> [updat
|
|
|
148
200
|
newSpec,
|
|
149
201
|
currentParams: existingParams,
|
|
150
202
|
projectId,
|
|
151
|
-
paramsEnvPath: options.params,
|
|
203
|
+
paramsEnvPath: ((_b = options.params) !== null && _b !== void 0 ? _b : ""),
|
|
152
204
|
nonInteractive: options.nonInteractive,
|
|
153
205
|
instanceId,
|
|
154
206
|
});
|
|
@@ -170,6 +222,7 @@ exports.default = new command_1.Command("ext:update <extensionInstanceId> [updat
|
|
|
170
222
|
spinner.stop();
|
|
171
223
|
utils.logLabeledSuccess(extensionsHelper_1.logPrefix, `successfully updated ${clc.bold(instanceId)}.`);
|
|
172
224
|
utils.logLabeledBullet(extensionsHelper_1.logPrefix, marked(`You can view your updated instance in the Firebase console: ${utils.consoleUrl(projectId, `/extensions/instances/${instanceId}?tab=usage`)}`));
|
|
225
|
+
manifest.showDeprecationWarning();
|
|
173
226
|
}
|
|
174
227
|
catch (err) {
|
|
175
228
|
if (spinner.isSpinning) {
|
package/lib/config.js
CHANGED
|
@@ -17,12 +17,12 @@ const logger_1 = require("./logger");
|
|
|
17
17
|
const loadCJSON = require("./loadCJSON");
|
|
18
18
|
const parseBoltRules = require("./parseBoltRules");
|
|
19
19
|
class Config {
|
|
20
|
-
constructor(src, options) {
|
|
20
|
+
constructor(src, options = {}) {
|
|
21
21
|
this.data = {};
|
|
22
22
|
this.defaults = {};
|
|
23
23
|
this.notes = {};
|
|
24
|
-
this.options = options
|
|
25
|
-
this.projectDir = options.projectDir || (0, detectProjectRoot_1.detectProjectRoot)(options);
|
|
24
|
+
this.options = options;
|
|
25
|
+
this.projectDir = this.options.projectDir || (0, detectProjectRoot_1.detectProjectRoot)(this.options);
|
|
26
26
|
this._src = src;
|
|
27
27
|
if (this._src.firebase) {
|
|
28
28
|
this.defaults.project = this._src.firebase;
|
|
@@ -144,6 +144,9 @@ class Config {
|
|
|
144
144
|
fs.ensureFileSync(this.path(p));
|
|
145
145
|
fs.writeFileSync(this.path(p), content, "utf8");
|
|
146
146
|
}
|
|
147
|
+
deleteProjectFile(p) {
|
|
148
|
+
fs.removeSync(this.path(p));
|
|
149
|
+
}
|
|
147
150
|
askWriteProjectFile(p, content, force) {
|
|
148
151
|
const writeTo = this.path(p);
|
|
149
152
|
let next;
|
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.resolveVersion = exports.want = exports.have = exports.getExtension = exports.getExtensionVersion = void 0;
|
|
4
4
|
const semver = require("semver");
|
|
5
|
-
const error_1 = require("../../error");
|
|
6
5
|
const extensionsApi = require("../../extensions/extensionsApi");
|
|
7
|
-
const extensionsHelper_1 = require("../../extensions/extensionsHelper");
|
|
8
6
|
const refs = require("../../extensions/refs");
|
|
9
|
-
const
|
|
7
|
+
const error_1 = require("../../error");
|
|
8
|
+
const extensionsHelper_1 = require("../../extensions/extensionsHelper");
|
|
10
9
|
const logger_1 = require("../../logger");
|
|
10
|
+
const manifest_1 = require("../../extensions/manifest");
|
|
11
11
|
async function getExtensionVersion(i) {
|
|
12
12
|
if (!i.extensionVersion) {
|
|
13
13
|
if (!i.ref) {
|
|
@@ -52,15 +52,15 @@ async function want(args) {
|
|
|
52
52
|
const instanceId = e[0];
|
|
53
53
|
const ref = refs.parse(e[1]);
|
|
54
54
|
ref.version = await resolveVersion(ref);
|
|
55
|
-
const params = (0,
|
|
55
|
+
const params = (0, manifest_1.readInstanceParam)({
|
|
56
56
|
projectDir: args.projectDir,
|
|
57
57
|
instanceId,
|
|
58
58
|
projectId: args.projectId,
|
|
59
59
|
projectNumber: args.projectNumber,
|
|
60
60
|
aliases: args.aliases,
|
|
61
|
-
checkLocal: args.
|
|
61
|
+
checkLocal: args.emulatorMode,
|
|
62
62
|
});
|
|
63
|
-
const autoPopulatedParams = await (0, extensionsHelper_1.getFirebaseProjectParams)(args.projectId);
|
|
63
|
+
const autoPopulatedParams = await (0, extensionsHelper_1.getFirebaseProjectParams)(args.projectId, args.emulatorMode);
|
|
64
64
|
const subbedParams = (0, extensionsHelper_1.substituteParams)(params, autoPopulatedParams);
|
|
65
65
|
instanceSpecs.push({
|
|
66
66
|
instanceId,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.compareFunctions = exports.missingEndpoint = exports.hasEndpoint = exports.regionalEndpoints = exports.matchingBackend = exports.findEndpoint = exports.someEndpoint = exports.allEndpoints = exports.checkAvailability = exports.existingBackend = exports.scheduleIdForFunction = exports.functionName = exports.isEmptyBackend = exports.of = exports.empty = exports.isTaskQueueTriggered = exports.isScheduleTriggered = exports.isEventTriggered = exports.isCallableTriggered = exports.isHttpsTriggered = exports.SCHEDULED_FUNCTION_LABEL = exports.MIN_MEMORY_FOR_CONCURRENCY = exports.DEFAULT_MEMORY = exports.memoryOptionDisplayName = exports.endpointTriggerType = void 0;
|
|
3
|
+
exports.compareFunctions = exports.findEventFilter = exports.missingEndpoint = exports.hasEndpoint = exports.regionalEndpoints = exports.matchingBackend = exports.findEndpoint = exports.someEndpoint = exports.allEndpoints = exports.checkAvailability = exports.existingBackend = exports.scheduleIdForFunction = exports.functionName = exports.isEmptyBackend = exports.of = exports.empty = exports.isTaskQueueTriggered = exports.isScheduleTriggered = exports.isEventTriggered = exports.isCallableTriggered = exports.isHttpsTriggered = exports.secretVersionName = exports.SCHEDULED_FUNCTION_LABEL = exports.MIN_MEMORY_FOR_CONCURRENCY = exports.DEFAULT_MEMORY = exports.memoryOptionDisplayName = exports.endpointTriggerType = void 0;
|
|
4
4
|
const gcf = require("../../gcp/cloudfunctions");
|
|
5
5
|
const gcfV2 = require("../../gcp/cloudfunctionsv2");
|
|
6
6
|
const utils = require("../../utils");
|
|
@@ -42,6 +42,11 @@ exports.memoryOptionDisplayName = memoryOptionDisplayName;
|
|
|
42
42
|
exports.DEFAULT_MEMORY = 256;
|
|
43
43
|
exports.MIN_MEMORY_FOR_CONCURRENCY = 2048;
|
|
44
44
|
exports.SCHEDULED_FUNCTION_LABEL = Object.freeze({ deployment: "firebase-schedule" });
|
|
45
|
+
function secretVersionName(s) {
|
|
46
|
+
var _a;
|
|
47
|
+
return `projects/${s.projectId}/secrets/${s.secret}/versions/${(_a = s.version) !== null && _a !== void 0 ? _a : "latest"}`;
|
|
48
|
+
}
|
|
49
|
+
exports.secretVersionName = secretVersionName;
|
|
45
50
|
function isHttpsTriggered(triggered) {
|
|
46
51
|
return {}.hasOwnProperty.call(triggered, "httpsTrigger");
|
|
47
52
|
}
|
|
@@ -225,6 +230,10 @@ const missingEndpoint = (backend) => (endpoint) => {
|
|
|
225
230
|
return !(0, exports.hasEndpoint)(backend)(endpoint);
|
|
226
231
|
};
|
|
227
232
|
exports.missingEndpoint = missingEndpoint;
|
|
233
|
+
function findEventFilter(endpoint, attribute) {
|
|
234
|
+
return endpoint.eventTrigger.eventFilters.find((ef) => ef.attribute === attribute);
|
|
235
|
+
}
|
|
236
|
+
exports.findEventFilter = findEventFilter;
|
|
228
237
|
function compareFunctions(left, right) {
|
|
229
238
|
if (left.platform !== right.platform) {
|
|
230
239
|
return right.platform < left.platform ? -1 : 1;
|
|
@@ -87,7 +87,7 @@ function mergeBindings(policy, allRequiredBindings) {
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
exports.mergeBindings = mergeBindings;
|
|
90
|
-
async function ensureServiceAgentRoles(
|
|
90
|
+
async function ensureServiceAgentRoles(projectNumber, want, have) {
|
|
91
91
|
const wantServices = backend.allEndpoints(want).reduce(reduceEventsToServices, []);
|
|
92
92
|
const haveServices = backend.allEndpoints(have).reduce(reduceEventsToServices, []);
|
|
93
93
|
const newServices = wantServices.filter((wantS) => !haveServices.find((haveS) => wantS.name === haveS.name));
|
|
@@ -96,7 +96,7 @@ async function ensureServiceAgentRoles(projectId, want, have) {
|
|
|
96
96
|
}
|
|
97
97
|
let policy;
|
|
98
98
|
try {
|
|
99
|
-
policy = await (0, resourceManager_1.getIamPolicy)(
|
|
99
|
+
policy = await (0, resourceManager_1.getIamPolicy)(projectNumber);
|
|
100
100
|
}
|
|
101
101
|
catch (err) {
|
|
102
102
|
utils.logLabeledBullet("functions", "Could not verify the necessary IAM configuration for the following newly-integrated services: " +
|
|
@@ -105,11 +105,11 @@ async function ensureServiceAgentRoles(projectId, want, have) {
|
|
|
105
105
|
return;
|
|
106
106
|
}
|
|
107
107
|
const findRequiredBindings = [];
|
|
108
|
-
newServices.forEach((service) => findRequiredBindings.push(service.requiredProjectBindings(
|
|
108
|
+
newServices.forEach((service) => findRequiredBindings.push(service.requiredProjectBindings(projectNumber, policy)));
|
|
109
109
|
const allRequiredBindings = await Promise.all(findRequiredBindings);
|
|
110
110
|
mergeBindings(policy, allRequiredBindings);
|
|
111
111
|
try {
|
|
112
|
-
await (0, resourceManager_1.setIamPolicy)(
|
|
112
|
+
await (0, resourceManager_1.setIamPolicy)(projectNumber, policy, "bindings");
|
|
113
113
|
}
|
|
114
114
|
catch (err) {
|
|
115
115
|
throw new error_1.FirebaseError("We failed to modify the IAM policy for the project. The functions " +
|
|
@@ -27,6 +27,7 @@ function hasDotenv(opts) {
|
|
|
27
27
|
}
|
|
28
28
|
async function prepare(context, options, payload) {
|
|
29
29
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
30
|
+
const projectNumber = await (0, projectUtils_1.needProjectNumber)(options);
|
|
30
31
|
const sourceDirName = options.config.get("functions.source");
|
|
31
32
|
if (!sourceDirName) {
|
|
32
33
|
throw new error_1.FirebaseError(`No functions code detected at default location (./functions), and no functions.source defined in firebase.json`);
|
|
@@ -111,7 +112,7 @@ async function prepare(context, options, payload) {
|
|
|
111
112
|
return (0, functionsDeployHelper_1.functionMatchesAnyGroup)(endpoint, context.filters);
|
|
112
113
|
});
|
|
113
114
|
const haveBackend = await backend.existingBackend(context);
|
|
114
|
-
await (0, checkIam_1.ensureServiceAgentRoles)(
|
|
115
|
+
await (0, checkIam_1.ensureServiceAgentRoles)(projectNumber, wantBackend, haveBackend);
|
|
115
116
|
inferDetailsFromExisting(wantBackend, haveBackend, usedDotenv);
|
|
116
117
|
await (0, triggerRegionHelper_1.ensureTriggerRegions)(wantBackend);
|
|
117
118
|
await (0, prompts_1.promptForFailurePolicies)(options, matchingBackend, haveBackend);
|
|
@@ -51,12 +51,12 @@ class Fabricator {
|
|
|
51
51
|
totalTime: 0,
|
|
52
52
|
results: [],
|
|
53
53
|
};
|
|
54
|
-
const
|
|
55
|
-
const results = await this.
|
|
54
|
+
const deployChangesets = Object.values(plan).map(async (changes) => {
|
|
55
|
+
const results = await this.applyChangeset(changes);
|
|
56
56
|
summary.results.push(...results);
|
|
57
57
|
return;
|
|
58
58
|
});
|
|
59
|
-
const promiseResults = await utils.allSettled(
|
|
59
|
+
const promiseResults = await utils.allSettled(deployChangesets);
|
|
60
60
|
const errs = promiseResults
|
|
61
61
|
.filter((r) => r.status === "rejected")
|
|
62
62
|
.map((r) => r.reason);
|
|
@@ -66,7 +66,7 @@ class Fabricator {
|
|
|
66
66
|
summary.totalTime = timer.stop();
|
|
67
67
|
return summary;
|
|
68
68
|
}
|
|
69
|
-
async
|
|
69
|
+
async applyChangeset(changes) {
|
|
70
70
|
const deployResults = [];
|
|
71
71
|
const handle = async (op, endpoint, fn) => {
|
|
72
72
|
const timer = new timer_1.Timer();
|