firebase-tools 13.18.0 → 13.19.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/README.md +10 -9
- package/lib/commands/ext-info.js +3 -1
- package/lib/commands/ext-sdk-install.js +88 -0
- package/lib/commands/ext.js +1 -0
- package/lib/commands/index.js +2 -0
- package/lib/dataconnect/ensureApis.js +0 -1
- package/lib/deploy/extensions/deploymentSummary.js +3 -2
- package/lib/deploy/extensions/planner.js +32 -3
- package/lib/deploy/extensions/prepare.js +15 -56
- package/lib/deploy/extensions/release.js +11 -10
- package/lib/deploy/extensions/tasks.js +32 -21
- package/lib/deploy/functions/prepare.js +8 -0
- package/lib/deploy/functions/runtimes/node/index.js +1 -1
- package/lib/emulator/downloadableEmulators.js +9 -9
- package/lib/extensions/extensionsApi.js +3 -2
- package/lib/extensions/extensionsHelper.js +3 -3
- package/lib/extensions/localHelper.js +31 -0
- package/lib/extensions/runtimes/common.js +186 -38
- package/lib/extensions/runtimes/node.js +399 -0
- package/lib/extensions/types.js +10 -14
- package/lib/extensions/warnings.js +5 -2
- package/lib/init/features/dataconnect/index.js +50 -50
- package/package.json +1 -1
- package/templates/init/dataconnect/dataconnect-fdccompatiblemode.yaml +1 -1
package/README.md
CHANGED
|
@@ -117,15 +117,16 @@ Detailed doc is [here](https://firebase.google.com/docs/cli/auth).
|
|
|
117
117
|
|
|
118
118
|
### Extensions Commands
|
|
119
119
|
|
|
120
|
-
| Command
|
|
121
|
-
|
|
|
122
|
-
| **ext**
|
|
123
|
-
| **ext:configure**
|
|
124
|
-
| **ext:info**
|
|
125
|
-
| **ext:install**
|
|
126
|
-
| **ext:
|
|
127
|
-
| **ext:
|
|
128
|
-
| **ext:
|
|
120
|
+
| Command | Description |
|
|
121
|
+
| ------------------- | ------------------------------------------------------------------------------------------- |
|
|
122
|
+
| **ext** | Display information on how to use ext commands and extensions installed to your project. |
|
|
123
|
+
| **ext:configure** | Configure an existing extension instance. |
|
|
124
|
+
| **ext:info** | Display information about an extension by name (extensionName@x.y.z for a specific version) |
|
|
125
|
+
| **ext:install** | Install an extension. |
|
|
126
|
+
| **ext:sdk:install** | Install and SDK for an extension so you can define the extension in a functions codebase. |
|
|
127
|
+
| **ext:list** | List all the extensions that are installed in your Firebase project. |
|
|
128
|
+
| **ext:uninstall** | Uninstall an extension that is installed in your Firebase project by Instance ID. |
|
|
129
|
+
| **ext:update** | Update an existing extension instance to the latest version. |
|
|
129
130
|
|
|
130
131
|
### Cloud Firestore Commands
|
|
131
132
|
|
package/lib/commands/ext-info.js
CHANGED
|
@@ -110,7 +110,9 @@ exports.command = new command_1.Command("ext:info <extensionName>")
|
|
|
110
110
|
else {
|
|
111
111
|
marked_1.marked.use((0, marked_terminal_1.markedTerminal)());
|
|
112
112
|
logger_1.logger.info(await (0, marked_1.marked)(lines.join("\n")));
|
|
113
|
-
utils.logLabeledBullet(extensionsHelper_1.logPrefix, `to install this extension,
|
|
113
|
+
utils.logLabeledBullet(extensionsHelper_1.logPrefix, `to install this extension, run ` +
|
|
114
114
|
clc.bold(`firebase ext:install ${extensionName} --project=YOUR_PROJECT`));
|
|
115
|
+
utils.logLabeledBullet(extensionsHelper_1.logPrefix, `to install an autogenerated SDK for this extension into your functions codebase, run ` +
|
|
116
|
+
clc.bold(`firebase ext:sdk:install ${extensionName} --project=YOUR_PROJECT`));
|
|
115
117
|
}
|
|
116
118
|
});
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.command = void 0;
|
|
4
|
+
const clc = require("colorette");
|
|
5
|
+
const semver = require("semver");
|
|
6
|
+
const checkMinRequiredVersion_1 = require("../checkMinRequiredVersion");
|
|
7
|
+
const command_1 = require("../command");
|
|
8
|
+
const extensionsApi = require("../extensions/extensionsApi");
|
|
9
|
+
const extensionsHelper_1 = require("../extensions/extensionsHelper");
|
|
10
|
+
const localHelper_1 = require("../extensions/localHelper");
|
|
11
|
+
const requirePermissions_1 = require("../requirePermissions");
|
|
12
|
+
const common_1 = require("../extensions/runtimes/common");
|
|
13
|
+
const error_1 = require("../error");
|
|
14
|
+
const displayExtensionInfo_1 = require("../extensions/displayExtensionInfo");
|
|
15
|
+
const refs = require("../extensions/refs");
|
|
16
|
+
const logger_1 = require("../logger");
|
|
17
|
+
const prompt_1 = require("../prompt");
|
|
18
|
+
const utils = require("../utils");
|
|
19
|
+
exports.command = new command_1.Command("ext:sdk:install <extensionName>")
|
|
20
|
+
.description("get an SDK for this extension. The SDK will be put in the 'generated' directory")
|
|
21
|
+
.option(`--codebase <codebase>`, `specifies a codebase to install the SDK into`)
|
|
22
|
+
.option(`--force`, `will overwrite existing sdk files if true`)
|
|
23
|
+
.before(checkMinRequiredVersion_1.checkMinRequiredVersion, "extDevMinVersion")
|
|
24
|
+
.action(async (extensionName, options) => {
|
|
25
|
+
const runtime = await (0, common_1.getCodebaseRuntime)(options);
|
|
26
|
+
if (!runtime.startsWith("nodejs")) {
|
|
27
|
+
throw new error_1.FirebaseError(`Extension SDK generation is currently only supported for NodeJs. We detected the target source to be: ${runtime}`);
|
|
28
|
+
}
|
|
29
|
+
let spec;
|
|
30
|
+
let extensionRef;
|
|
31
|
+
let localPath;
|
|
32
|
+
if ((0, localHelper_1.isLocalExtension)(extensionName)) {
|
|
33
|
+
spec = await (0, localHelper_1.getLocalExtensionSpec)(extensionName);
|
|
34
|
+
spec.systemParams = [];
|
|
35
|
+
localPath = extensionName;
|
|
36
|
+
await (0, displayExtensionInfo_1.displayExtensionVersionInfo)({ spec });
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
await (0, requirePermissions_1.requirePermissions)(options, ["firebaseextensions.sources.get"]);
|
|
40
|
+
await (0, extensionsHelper_1.ensureExtensionsApiEnabled)(options);
|
|
41
|
+
const hasPublisherId = extensionName.split("/").length >= 2;
|
|
42
|
+
if (hasPublisherId) {
|
|
43
|
+
const nameAndVersion = extensionName.split("/")[1];
|
|
44
|
+
if (nameAndVersion.split("@").length < 2) {
|
|
45
|
+
extensionName = extensionName + "@latest";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
const [name, version] = extensionName.split("@");
|
|
50
|
+
extensionName = `firebase/${name}@${version || "latest"}`;
|
|
51
|
+
}
|
|
52
|
+
const ref = refs.parse(extensionName);
|
|
53
|
+
const extension = await extensionsApi.getExtension(refs.toExtensionRef(ref));
|
|
54
|
+
const version = await extensionsApi.getExtensionVersion(extensionName);
|
|
55
|
+
spec = version.spec;
|
|
56
|
+
extensionRef = version.ref;
|
|
57
|
+
await (0, displayExtensionInfo_1.displayExtensionVersionInfo)({
|
|
58
|
+
spec,
|
|
59
|
+
extensionVersion: version,
|
|
60
|
+
latestApprovedVersion: extension.latestApprovedVersion,
|
|
61
|
+
latestVersion: extension.latestVersion,
|
|
62
|
+
});
|
|
63
|
+
if (version.state === "DEPRECATED") {
|
|
64
|
+
throw new error_1.FirebaseError(`Extension version ${clc.bold(extensionName)} is deprecated and cannot be installed. To install an SDK for the ` +
|
|
65
|
+
`latest non-deprecated version, omit the version in the extension ref.`);
|
|
66
|
+
}
|
|
67
|
+
logger_1.logger.info();
|
|
68
|
+
if ((extension.latestApprovedVersion &&
|
|
69
|
+
semver.gt(extension.latestApprovedVersion, version.spec.version)) ||
|
|
70
|
+
(!extension.latestApprovedVersion &&
|
|
71
|
+
extension.latestVersion &&
|
|
72
|
+
semver.gt(extension.latestVersion, version.spec.version))) {
|
|
73
|
+
const latest = extension.latestApprovedVersion || extension.latestVersion;
|
|
74
|
+
logger_1.logger.info(`You are about to install an SDK for extension version ${clc.bold(version.spec.version)} which is older than the latest ${extension.latestApprovedVersion ? "accepted version" : "version"} ${clc.bold(latest)}.`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (!(await (0, prompt_1.confirm)({
|
|
78
|
+
nonInteractive: options.nonInteractive,
|
|
79
|
+
force: options.force,
|
|
80
|
+
default: true,
|
|
81
|
+
}))) {
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
const codeSample = await (0, common_1.writeSDK)(extensionRef, localPath, spec, options);
|
|
85
|
+
logger_1.logger.info();
|
|
86
|
+
utils.logSuccess("Extension SDK installed successfully");
|
|
87
|
+
logger_1.logger.info(codeSample);
|
|
88
|
+
});
|
package/lib/commands/ext.js
CHANGED
package/lib/commands/index.js
CHANGED
|
@@ -83,6 +83,8 @@ function load(client) {
|
|
|
83
83
|
client.ext.list = loadCommand("ext-list");
|
|
84
84
|
client.ext.uninstall = loadCommand("ext-uninstall");
|
|
85
85
|
client.ext.update = loadCommand("ext-update");
|
|
86
|
+
client.ext.sdk = {};
|
|
87
|
+
client.ext.sdk.install = loadCommand("ext-sdk-install");
|
|
86
88
|
client.ext.dev = {};
|
|
87
89
|
client.ext.dev.init = loadCommand("ext-dev-init");
|
|
88
90
|
client.ext.dev.list = loadCommand("ext-dev-list");
|
|
@@ -12,7 +12,6 @@ async function ensureApis(projectId) {
|
|
|
12
12
|
exports.ensureApis = ensureApis;
|
|
13
13
|
async function ensureSparkApis(projectId) {
|
|
14
14
|
const prefix = "dataconnect";
|
|
15
|
-
await (0, ensureApiEnabled_1.ensure)(projectId, api.dataconnectOrigin(), prefix);
|
|
16
15
|
await (0, ensureApiEnabled_1.ensure)(projectId, api.cloudSQLAdminOrigin(), prefix);
|
|
17
16
|
}
|
|
18
17
|
exports.ensureSparkApis = ensureSparkApis;
|
|
@@ -47,10 +47,11 @@ function configuresSummary(toConfigure) {
|
|
|
47
47
|
: "";
|
|
48
48
|
}
|
|
49
49
|
exports.configuresSummary = configuresSummary;
|
|
50
|
-
function deletesSummary(toDelete) {
|
|
50
|
+
function deletesSummary(toDelete, isDynamic) {
|
|
51
51
|
const instancesToDelete = toDelete.map((s) => `\t${(0, exports.humanReadable)(s)}`).join("\n");
|
|
52
|
+
const definedLocation = isDynamic ? "your local source code" : "'firebase.json'";
|
|
52
53
|
return toDelete.length
|
|
53
|
-
? `The following extension instances are not
|
|
54
|
+
? `The following extension instances are found in your project but do not exist in ${definedLocation}:\n${instancesToDelete}\n`
|
|
54
55
|
: "";
|
|
55
56
|
}
|
|
56
57
|
exports.deletesSummary = deletesSummary;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.resolveVersion = exports.want = exports.wantDynamic = exports.have = exports.getExtensionSpec = exports.getExtension = exports.getExtensionVersion = void 0;
|
|
3
|
+
exports.resolveVersion = exports.want = exports.wantDynamic = exports.have = exports.haveDynamic = exports.getExtensionSpec = exports.getExtension = exports.getExtensionVersion = void 0;
|
|
4
4
|
const semver = require("semver");
|
|
5
5
|
const extensionsApi = require("../../extensions/extensionsApi");
|
|
6
6
|
const refs = require("../../extensions/refs");
|
|
@@ -49,9 +49,33 @@ async function getExtensionSpec(i) {
|
|
|
49
49
|
return i.extensionSpec;
|
|
50
50
|
}
|
|
51
51
|
exports.getExtensionSpec = getExtensionSpec;
|
|
52
|
+
async function haveDynamic(projectId) {
|
|
53
|
+
return (await extensionsApi.listInstances(projectId))
|
|
54
|
+
.filter((i) => { var _a; return ((_a = i.labels) === null || _a === void 0 ? void 0 : _a.createdBy) === "SDK"; })
|
|
55
|
+
.map((i) => {
|
|
56
|
+
var _a;
|
|
57
|
+
const dep = {
|
|
58
|
+
instanceId: i.name.split("/").pop(),
|
|
59
|
+
params: i.config.params,
|
|
60
|
+
systemParams: (_a = i.config.systemParams) !== null && _a !== void 0 ? _a : {},
|
|
61
|
+
allowedEventTypes: i.config.allowedEventTypes,
|
|
62
|
+
eventarcChannel: i.config.eventarcChannel,
|
|
63
|
+
etag: i.etag,
|
|
64
|
+
labels: i.labels,
|
|
65
|
+
};
|
|
66
|
+
if (i.config.extensionRef) {
|
|
67
|
+
const ref = refs.parse(i.config.extensionRef);
|
|
68
|
+
dep.ref = ref;
|
|
69
|
+
dep.ref.version = i.config.extensionVersion;
|
|
70
|
+
}
|
|
71
|
+
return dep;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
exports.haveDynamic = haveDynamic;
|
|
52
75
|
async function have(projectId) {
|
|
53
|
-
|
|
54
|
-
|
|
76
|
+
return (await extensionsApi.listInstances(projectId))
|
|
77
|
+
.filter((i) => { var _a; return !(((_a = i.labels) === null || _a === void 0 ? void 0 : _a.createdBy) === "SDK"); })
|
|
78
|
+
.map((i) => {
|
|
55
79
|
var _a;
|
|
56
80
|
const dep = {
|
|
57
81
|
instanceId: i.name.split("/").pop(),
|
|
@@ -61,6 +85,9 @@ async function have(projectId) {
|
|
|
61
85
|
eventarcChannel: i.config.eventarcChannel,
|
|
62
86
|
etag: i.etag,
|
|
63
87
|
};
|
|
88
|
+
if (i.labels) {
|
|
89
|
+
dep.labels = i.labels;
|
|
90
|
+
}
|
|
64
91
|
if (i.config.extensionRef) {
|
|
65
92
|
const ref = refs.parse(i.config.extensionRef);
|
|
66
93
|
dep.ref = ref;
|
|
@@ -97,6 +124,7 @@ async function wantDynamic(args) {
|
|
|
97
124
|
systemParams,
|
|
98
125
|
allowedEventTypes,
|
|
99
126
|
eventarcChannel,
|
|
127
|
+
labels: ext.labels,
|
|
100
128
|
});
|
|
101
129
|
}
|
|
102
130
|
else if (ext.ref) {
|
|
@@ -107,6 +135,7 @@ async function wantDynamic(args) {
|
|
|
107
135
|
systemParams,
|
|
108
136
|
allowedEventTypes,
|
|
109
137
|
eventarcChannel,
|
|
138
|
+
labels: ext.labels,
|
|
110
139
|
});
|
|
111
140
|
}
|
|
112
141
|
}
|
|
@@ -17,20 +17,19 @@ const etags_1 = require("../../extensions/etags");
|
|
|
17
17
|
const v2FunctionHelper_1 = require("./v2FunctionHelper");
|
|
18
18
|
const tos_1 = require("../../extensions/tos");
|
|
19
19
|
const common_1 = require("../../extensions/runtimes/common");
|
|
20
|
-
const projectConfig_1 = require("../../functions/projectConfig");
|
|
21
20
|
const functionsDeployHelper_1 = require("../functions/functionsDeployHelper");
|
|
22
|
-
async function prepareHelper(context, options, payload, wantExtensions,
|
|
21
|
+
async function prepareHelper(context, options, payload, wantExtensions, haveExtensions, isDynamic) {
|
|
23
22
|
var _a, _b;
|
|
24
23
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
25
|
-
context.have = await planner.have(projectId);
|
|
26
24
|
context.want = wantExtensions;
|
|
25
|
+
context.have = haveExtensions;
|
|
27
26
|
const etagsChanged = (0, etags_1.detectEtagChanges)(options.rc, projectId, context.have);
|
|
28
27
|
if (etagsChanged.length) {
|
|
29
28
|
const wantChangedIds = wantExtensions
|
|
30
29
|
.map((e) => e.instanceId)
|
|
31
30
|
.filter((id) => etagsChanged.includes(id));
|
|
32
31
|
if (wantChangedIds.length) {
|
|
33
|
-
(0, warnings_1.outOfBandChangesWarning)(wantChangedIds);
|
|
32
|
+
(0, warnings_1.outOfBandChangesWarning)(wantChangedIds, isDynamic);
|
|
34
33
|
if (!(await prompt.confirm({
|
|
35
34
|
message: `Do you wish to continue deploying these extension instances?`,
|
|
36
35
|
default: false,
|
|
@@ -52,7 +51,7 @@ async function prepareHelper(context, options, payload, wantExtensions, noDelete
|
|
|
52
51
|
payload.instancesToCreate = context.want.filter((i) => { var _a; return !((_a = context.have) === null || _a === void 0 ? void 0 : _a.some(matchesInstanceId(i))); });
|
|
53
52
|
payload.instancesToConfigure = context.want.filter((i) => { var _a; return (_a = context.have) === null || _a === void 0 ? void 0 : _a.some(isConfigure(i)); });
|
|
54
53
|
payload.instancesToUpdate = context.want.filter((i) => { var _a; return (_a = context.have) === null || _a === void 0 ? void 0 : _a.some(isUpdate(i)); });
|
|
55
|
-
payload.instancesToDelete = context.have.filter((i) => { var _a; return !((_a = context.want) === null || _a === void 0 ? void 0 : _a.some(matchesInstanceId(i)))
|
|
54
|
+
payload.instancesToDelete = context.have.filter((i) => { var _a; return !((_a = context.want) === null || _a === void 0 ? void 0 : _a.some(matchesInstanceId(i))); });
|
|
56
55
|
if (await (0, warnings_1.displayWarningsForDeploy)(payload.instancesToCreate)) {
|
|
57
56
|
if (!(await prompt.confirm({
|
|
58
57
|
message: `Do you wish to continue deploying these extension instances?`,
|
|
@@ -64,9 +63,6 @@ async function prepareHelper(context, options, payload, wantExtensions, noDelete
|
|
|
64
63
|
}
|
|
65
64
|
}
|
|
66
65
|
const permissionsNeeded = [];
|
|
67
|
-
if (!isPrimaryCall) {
|
|
68
|
-
payload.instancesToDelete = [];
|
|
69
|
-
}
|
|
70
66
|
if (payload.instancesToCreate.length) {
|
|
71
67
|
permissionsNeeded.push("firebaseextensions.instances.create");
|
|
72
68
|
logger_1.logger.info(deploymentSummary.createsSummary(payload.instancesToCreate));
|
|
@@ -80,9 +76,9 @@ async function prepareHelper(context, options, payload, wantExtensions, noDelete
|
|
|
80
76
|
logger_1.logger.info(deploymentSummary.configuresSummary(payload.instancesToConfigure));
|
|
81
77
|
}
|
|
82
78
|
if (payload.instancesToDelete.length) {
|
|
83
|
-
logger_1.logger.info(deploymentSummary.deletesSummary(payload.instancesToDelete));
|
|
79
|
+
logger_1.logger.info(deploymentSummary.deletesSummary(payload.instancesToDelete, isDynamic));
|
|
84
80
|
if (options.dryRun) {
|
|
85
|
-
logger_1.logger.info("On your next deploy,
|
|
81
|
+
logger_1.logger.info("On your next deploy, you will be asked if you want to delete these instances.");
|
|
86
82
|
logger_1.logger.info("If you deploy --force, they will be deleted.");
|
|
87
83
|
}
|
|
88
84
|
if (!options.dryRun &&
|
|
@@ -114,56 +110,23 @@ async function prepareHelper(context, options, payload, wantExtensions, noDelete
|
|
|
114
110
|
async function prepareDynamicExtensions(context, options, payload, builds) {
|
|
115
111
|
const filters = (0, functionsDeployHelper_1.getEndpointFilters)(options);
|
|
116
112
|
const extensions = (0, common_1.extractExtensionsFromBuilds)(builds, filters);
|
|
117
|
-
const isApiEnabled = await (0, extensionsHelper_1.checkExtensionsApiEnabled)(options);
|
|
118
|
-
if (Object.keys(extensions).length === 0 && !isApiEnabled) {
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
113
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
122
114
|
const projectNumber = await (0, projectUtils_1.needProjectNumber)(options);
|
|
123
|
-
const aliases = (0, projectUtils_1.getAliases)(options, projectId);
|
|
124
|
-
const projectDir = options.config.projectDir;
|
|
125
|
-
const isPrimaryCall = !!options.only && !options.only.split(",").includes("extensions");
|
|
126
115
|
await (0, extensionsHelper_1.ensureExtensionsApiEnabled)(options);
|
|
127
116
|
await (0, requirePermissions_1.requirePermissions)(options, ["firebaseextensions.instances.list"]);
|
|
117
|
+
let haveExtensions = await planner.haveDynamic(projectId);
|
|
118
|
+
haveExtensions = haveExtensions.filter((e) => { var _a; return (0, common_1.extensionMatchesAnyFilter)((_a = e.labels) === null || _a === void 0 ? void 0 : _a.codebase, e.instanceId, filters); });
|
|
119
|
+
if (Object.keys(extensions).length === 0 && haveExtensions.length === 0) {
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
128
122
|
const dynamicWant = await planner.wantDynamic({
|
|
129
123
|
projectId,
|
|
130
124
|
projectNumber,
|
|
131
125
|
extensions,
|
|
132
126
|
});
|
|
133
|
-
|
|
134
|
-
if (isPrimaryCall) {
|
|
135
|
-
const firebaseJsonWant = await planner.want({
|
|
136
|
-
projectId,
|
|
137
|
-
projectNumber,
|
|
138
|
-
aliases,
|
|
139
|
-
projectDir,
|
|
140
|
-
extensions: options.config.get("extensions", {}),
|
|
141
|
-
});
|
|
142
|
-
noDeleteExtensions = noDeleteExtensions.concat(firebaseJsonWant);
|
|
143
|
-
if (hasNonDeployingCodebases(options)) {
|
|
144
|
-
const dynamicAll = await planner.wantDynamic({
|
|
145
|
-
projectId,
|
|
146
|
-
projectNumber,
|
|
147
|
-
extensions: await (0, common_1.extractAllDynamicExtensions)(options),
|
|
148
|
-
});
|
|
149
|
-
noDeleteExtensions = noDeleteExtensions.concat(dynamicAll);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
return prepareHelper(context, options, payload, dynamicWant, noDeleteExtensions, isPrimaryCall);
|
|
127
|
+
return prepareHelper(context, options, payload, dynamicWant, haveExtensions, true);
|
|
153
128
|
}
|
|
154
129
|
exports.prepareDynamicExtensions = prepareDynamicExtensions;
|
|
155
|
-
function hasNonDeployingCodebases(options) {
|
|
156
|
-
const functionFilters = (0, functionsDeployHelper_1.getEndpointFilters)(options);
|
|
157
|
-
if (functionFilters === null || functionFilters === void 0 ? void 0 : functionFilters.length) {
|
|
158
|
-
return true;
|
|
159
|
-
}
|
|
160
|
-
const functionsConfig = (0, projectConfig_1.normalizeAndValidate)(options.config.src.functions);
|
|
161
|
-
const allCodebases = (0, functionsDeployHelper_1.targetCodebases)(functionsConfig);
|
|
162
|
-
const deployingCodebases = (0, functionsDeployHelper_1.targetCodebases)(functionsConfig, functionFilters);
|
|
163
|
-
if (allCodebases.length > deployingCodebases.length) {
|
|
164
|
-
return true;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
130
|
async function prepare(context, options, payload) {
|
|
168
131
|
context.extensionsStartTime = Date.now();
|
|
169
132
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
@@ -172,19 +135,15 @@ async function prepare(context, options, payload) {
|
|
|
172
135
|
const projectDir = options.config.projectDir;
|
|
173
136
|
await (0, extensionsHelper_1.ensureExtensionsApiEnabled)(options);
|
|
174
137
|
await (0, requirePermissions_1.requirePermissions)(options, ["firebaseextensions.instances.list"]);
|
|
175
|
-
const
|
|
138
|
+
const wantExtensions = await planner.want({
|
|
176
139
|
projectId,
|
|
177
140
|
projectNumber,
|
|
178
141
|
aliases,
|
|
179
142
|
projectDir,
|
|
180
143
|
extensions: options.config.get("extensions", {}),
|
|
181
144
|
});
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
projectNumber,
|
|
185
|
-
extensions: await (0, common_1.extractAllDynamicExtensions)(options),
|
|
186
|
-
});
|
|
187
|
-
return prepareHelper(context, options, payload, firebaseJsonWant, dynamicWant, true);
|
|
145
|
+
const haveExtensions = await planner.have(projectId);
|
|
146
|
+
return prepareHelper(context, options, payload, wantExtensions, haveExtensions, false);
|
|
188
147
|
}
|
|
189
148
|
exports.prepare = prepare;
|
|
190
149
|
const matchesInstanceId = (dep) => (test) => {
|
|
@@ -24,20 +24,20 @@ async function release(context, options, payload) {
|
|
|
24
24
|
concurrency: 5,
|
|
25
25
|
handler: tasks.extensionsDeploymentHandler(errorHandler),
|
|
26
26
|
});
|
|
27
|
-
for (const
|
|
28
|
-
const task = tasks.
|
|
27
|
+
for (const inst of (_a = payload.instancesToConfigure) !== null && _a !== void 0 ? _a : []) {
|
|
28
|
+
const task = tasks.configureExtensionInstanceTask(projectId, inst);
|
|
29
29
|
void deploymentQueue.run(task);
|
|
30
30
|
}
|
|
31
|
-
for (const
|
|
32
|
-
const task = tasks.
|
|
31
|
+
for (const inst of (_b = payload.instancesToDelete) !== null && _b !== void 0 ? _b : []) {
|
|
32
|
+
const task = tasks.deleteExtensionInstanceTask(projectId, inst);
|
|
33
33
|
void deploymentQueue.run(task);
|
|
34
34
|
}
|
|
35
|
-
for (const
|
|
36
|
-
const task = tasks.
|
|
35
|
+
for (const inst of (_c = payload.instancesToCreate) !== null && _c !== void 0 ? _c : []) {
|
|
36
|
+
const task = tasks.createExtensionInstanceTask(projectId, inst);
|
|
37
37
|
void deploymentQueue.run(task);
|
|
38
38
|
}
|
|
39
|
-
for (const
|
|
40
|
-
const task = tasks.
|
|
39
|
+
for (const inst of (_d = payload.instancesToUpdate) !== null && _d !== void 0 ? _d : []) {
|
|
40
|
+
const task = tasks.updateExtensionInstanceTask(projectId, inst);
|
|
41
41
|
void deploymentQueue.run(task);
|
|
42
42
|
}
|
|
43
43
|
const deploymentPromise = deploymentQueue.wait();
|
|
@@ -53,8 +53,9 @@ async function release(context, options, payload) {
|
|
|
53
53
|
errors: (_o = errorHandler.errors.length) !== null && _o !== void 0 ? _o : 0,
|
|
54
54
|
interactive: options.nonInteractive ? "false" : "true",
|
|
55
55
|
}, duration);
|
|
56
|
-
const
|
|
57
|
-
|
|
56
|
+
const have = await planner.have(projectId);
|
|
57
|
+
const dynamicHave = await planner.haveDynamic(projectId);
|
|
58
|
+
(0, etags_1.saveEtags)(options.rc, projectId, have.concat(dynamicHave));
|
|
58
59
|
if (errorHandler.hasErrors()) {
|
|
59
60
|
errorHandler.print();
|
|
60
61
|
throw new error_1.FirebaseError(`Extensions deployment failed.`);
|
|
@@ -7,6 +7,7 @@ const extensionsApi = require("../../extensions/extensionsApi");
|
|
|
7
7
|
const extensionsHelper_1 = require("../../extensions/extensionsHelper");
|
|
8
8
|
const refs = require("../../extensions/refs");
|
|
9
9
|
const utils = require("../../utils");
|
|
10
|
+
const types_1 = require("../../extensions/types");
|
|
10
11
|
const isRetryable = (err) => err.status === 429 || err.status === 409;
|
|
11
12
|
function extensionsDeploymentHandler(errorHandler) {
|
|
12
13
|
return async (task) => {
|
|
@@ -27,34 +28,37 @@ function extensionsDeploymentHandler(errorHandler) {
|
|
|
27
28
|
exports.extensionsDeploymentHandler = extensionsDeploymentHandler;
|
|
28
29
|
function createExtensionInstanceTask(projectId, instanceSpec, validateOnly = false) {
|
|
29
30
|
const run = async () => {
|
|
31
|
+
if (!validateOnly) {
|
|
32
|
+
utils.logLabeledBullet("extensions", `Creating ${clc.bold(instanceSpec.instanceId)} extension instance`);
|
|
33
|
+
}
|
|
34
|
+
const createArgs = {
|
|
35
|
+
projectId,
|
|
36
|
+
instanceId: instanceSpec.instanceId,
|
|
37
|
+
params: instanceSpec.params,
|
|
38
|
+
systemParams: instanceSpec.systemParams,
|
|
39
|
+
allowedEventTypes: instanceSpec.allowedEventTypes,
|
|
40
|
+
eventarcChannel: instanceSpec.eventarcChannel,
|
|
41
|
+
validateOnly,
|
|
42
|
+
labels: instanceSpec.labels,
|
|
43
|
+
};
|
|
30
44
|
if (instanceSpec.ref) {
|
|
31
|
-
|
|
32
|
-
projectId,
|
|
33
|
-
instanceId: instanceSpec.instanceId,
|
|
34
|
-
params: instanceSpec.params,
|
|
35
|
-
systemParams: instanceSpec.systemParams,
|
|
36
|
-
extensionVersionRef: refs.toExtensionVersionRef(instanceSpec.ref),
|
|
37
|
-
allowedEventTypes: instanceSpec.allowedEventTypes,
|
|
38
|
-
eventarcChannel: instanceSpec.eventarcChannel,
|
|
39
|
-
validateOnly,
|
|
40
|
-
});
|
|
45
|
+
createArgs.extensionVersionRef = refs.toExtensionVersionRef(instanceSpec.ref);
|
|
41
46
|
}
|
|
42
47
|
else if (instanceSpec.localPath) {
|
|
43
|
-
|
|
44
|
-
await extensionsApi.createInstance({
|
|
45
|
-
projectId,
|
|
46
|
-
instanceId: instanceSpec.instanceId,
|
|
47
|
-
params: instanceSpec.params,
|
|
48
|
-
systemParams: instanceSpec.systemParams,
|
|
49
|
-
extensionSource,
|
|
50
|
-
allowedEventTypes: instanceSpec.allowedEventTypes,
|
|
51
|
-
eventarcChannel: instanceSpec.eventarcChannel,
|
|
52
|
-
validateOnly,
|
|
53
|
-
});
|
|
48
|
+
createArgs.extensionSource = await (0, extensionsHelper_1.createSourceFromLocation)(projectId, instanceSpec.localPath);
|
|
54
49
|
}
|
|
55
50
|
else {
|
|
56
51
|
throw new error_1.FirebaseError(`Tried to create extension instance ${instanceSpec.instanceId} without a ref or a local path. This should never happen.`);
|
|
57
52
|
}
|
|
53
|
+
try {
|
|
54
|
+
await extensionsApi.createInstance(createArgs);
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
if ((0, types_1.isObject)(err) && err.status === 409) {
|
|
58
|
+
throw new error_1.FirebaseError(`Failed to create extension instance. Extension instance ${clc.bold(instanceSpec.instanceId)} already exists.`);
|
|
59
|
+
}
|
|
60
|
+
throw err;
|
|
61
|
+
}
|
|
58
62
|
printSuccess(instanceSpec.instanceId, "create", validateOnly);
|
|
59
63
|
return;
|
|
60
64
|
};
|
|
@@ -67,6 +71,9 @@ function createExtensionInstanceTask(projectId, instanceSpec, validateOnly = fal
|
|
|
67
71
|
exports.createExtensionInstanceTask = createExtensionInstanceTask;
|
|
68
72
|
function updateExtensionInstanceTask(projectId, instanceSpec, validateOnly = false) {
|
|
69
73
|
const run = async () => {
|
|
74
|
+
if (!validateOnly) {
|
|
75
|
+
utils.logLabeledBullet("extensions", `Updating ${clc.bold(instanceSpec.instanceId)} extension instance`);
|
|
76
|
+
}
|
|
70
77
|
if (instanceSpec.ref) {
|
|
71
78
|
await extensionsApi.updateInstanceFromRegistry({
|
|
72
79
|
projectId,
|
|
@@ -109,6 +116,9 @@ function updateExtensionInstanceTask(projectId, instanceSpec, validateOnly = fal
|
|
|
109
116
|
exports.updateExtensionInstanceTask = updateExtensionInstanceTask;
|
|
110
117
|
function configureExtensionInstanceTask(projectId, instanceSpec, validateOnly = false) {
|
|
111
118
|
const run = async () => {
|
|
119
|
+
if (!validateOnly) {
|
|
120
|
+
utils.logLabeledBullet("extensions", `Configuring ${clc.bold(instanceSpec.instanceId)} extension instance`);
|
|
121
|
+
}
|
|
112
122
|
if (instanceSpec.ref) {
|
|
113
123
|
await extensionsApi.configureInstance({
|
|
114
124
|
projectId,
|
|
@@ -139,6 +149,7 @@ function configureExtensionInstanceTask(projectId, instanceSpec, validateOnly =
|
|
|
139
149
|
exports.configureExtensionInstanceTask = configureExtensionInstanceTask;
|
|
140
150
|
function deleteExtensionInstanceTask(projectId, instanceSpec) {
|
|
141
151
|
const run = async () => {
|
|
152
|
+
utils.logLabeledBullet("extensions", `Deleting ${clc.bold(instanceSpec.instanceId)} extension instance`);
|
|
142
153
|
await extensionsApi.deleteInstance(projectId, instanceSpec.instanceId);
|
|
143
154
|
printSuccess(instanceSpec.instanceId, "delete", false);
|
|
144
155
|
return;
|
|
@@ -27,6 +27,7 @@ const serviceusage_1 = require("../../gcp/serviceusage");
|
|
|
27
27
|
const applyHash_1 = require("./cache/applyHash");
|
|
28
28
|
const backend_1 = require("./backend");
|
|
29
29
|
const functional_1 = require("../../functional");
|
|
30
|
+
const prepare_1 = require("../extensions/prepare");
|
|
30
31
|
exports.EVENTARC_SOURCE_ENV = "EVENTARC_CLOUD_EVENT_SOURCE";
|
|
31
32
|
async function prepare(context, options, payload) {
|
|
32
33
|
var _a, _b;
|
|
@@ -55,6 +56,13 @@ async function prepare(context, options, payload) {
|
|
|
55
56
|
}
|
|
56
57
|
context.codebaseDeployEvents = {};
|
|
57
58
|
const wantBuilds = await loadCodebases(context.config, options, firebaseConfig, runtimeConfig, context.filters);
|
|
59
|
+
if (Object.values(wantBuilds).some((b) => b.extensions)) {
|
|
60
|
+
const extContext = {};
|
|
61
|
+
const extPayload = {};
|
|
62
|
+
await (0, prepare_1.prepareDynamicExtensions)(extContext, options, extPayload, wantBuilds);
|
|
63
|
+
context.extensions = extContext;
|
|
64
|
+
payload.extensions = extPayload;
|
|
65
|
+
}
|
|
58
66
|
const codebaseUsesEnvs = [];
|
|
59
67
|
const wantBackends = {};
|
|
60
68
|
for (const [codebase, wantBuild] of Object.entries(wantBuilds)) {
|
|
@@ -18,7 +18,7 @@ const validate = require("./validate");
|
|
|
18
18
|
const versioning = require("./versioning");
|
|
19
19
|
const parseTriggers = require("./parseTriggers");
|
|
20
20
|
const fsutils_1 = require("../../../../fsutils");
|
|
21
|
-
const MIN_FUNCTIONS_SDK_VERSION = "
|
|
21
|
+
const MIN_FUNCTIONS_SDK_VERSION = "5.1.0";
|
|
22
22
|
async function tryCreateDelegate(context) {
|
|
23
23
|
const packageJsonPath = path.join(context.sourceDir, "package.json");
|
|
24
24
|
if (!(await (0, util_1.promisify)(fs.exists)(packageJsonPath))) {
|
|
@@ -46,20 +46,20 @@ const EMULATOR_UPDATE_DETAILS = {
|
|
|
46
46
|
},
|
|
47
47
|
dataconnect: process.platform === "darwin"
|
|
48
48
|
? {
|
|
49
|
-
version: "1.3.
|
|
50
|
-
expectedSize:
|
|
51
|
-
expectedChecksum: "
|
|
49
|
+
version: "1.3.8",
|
|
50
|
+
expectedSize: 25027328,
|
|
51
|
+
expectedChecksum: "903f0e8dd8212fec575dc2eba34be6e7",
|
|
52
52
|
}
|
|
53
53
|
: process.platform === "win32"
|
|
54
54
|
? {
|
|
55
|
-
version: "1.3.
|
|
56
|
-
expectedSize:
|
|
57
|
-
expectedChecksum: "
|
|
55
|
+
version: "1.3.8",
|
|
56
|
+
expectedSize: 25450496,
|
|
57
|
+
expectedChecksum: "e09999deda7301eba06f88face5e1744",
|
|
58
58
|
}
|
|
59
59
|
: {
|
|
60
|
-
version: "1.3.
|
|
61
|
-
expectedSize:
|
|
62
|
-
expectedChecksum: "
|
|
60
|
+
version: "1.3.8",
|
|
61
|
+
expectedSize: 24940696,
|
|
62
|
+
expectedChecksum: "69aeb9755d4ec2e77bdadbc40236b306",
|
|
63
63
|
},
|
|
64
64
|
};
|
|
65
65
|
exports.DownloadDetails = {
|
|
@@ -15,10 +15,11 @@ const extensionsApiClient = new apiv2_1.Client({
|
|
|
15
15
|
urlPrefix: (0, api_1.extensionsOrigin)(),
|
|
16
16
|
apiVersion: EXTENSIONS_API_VERSION,
|
|
17
17
|
});
|
|
18
|
-
async function createInstanceHelper(projectId, instanceId, config, validateOnly = false) {
|
|
18
|
+
async function createInstanceHelper(projectId, instanceId, config, labels, validateOnly = false) {
|
|
19
19
|
const createRes = await extensionsApiClient.post(`/projects/${projectId}/instances/`, {
|
|
20
20
|
name: `projects/${projectId}/instances/${instanceId}`,
|
|
21
21
|
config,
|
|
22
|
+
labels,
|
|
22
23
|
}, {
|
|
23
24
|
queryParams: {
|
|
24
25
|
validateOnly: validateOnly ? "true" : "false",
|
|
@@ -63,7 +64,7 @@ async function createInstance(args) {
|
|
|
63
64
|
if (args.eventarcChannel) {
|
|
64
65
|
config.eventarcChannel = args.eventarcChannel;
|
|
65
66
|
}
|
|
66
|
-
return createInstanceHelper(args.projectId, args.instanceId, config, args.validateOnly);
|
|
67
|
+
return await createInstanceHelper(args.projectId, args.instanceId, config, args.labels, args.validateOnly);
|
|
67
68
|
}
|
|
68
69
|
exports.createInstance = createInstance;
|
|
69
70
|
async function deleteInstance(projectId, instanceId) {
|
|
@@ -7,7 +7,7 @@ var __asyncValues = (this && this.__asyncValues) || function (o) {
|
|
|
7
7
|
function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
|
|
8
8
|
};
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
-
exports.diagnoseAndFixProject = exports.getSourceOrigin = exports.isLocalOrURLPath = exports.isLocalPath = exports.isUrlPath = exports.instanceIdExists = exports.promptForRepeatInstance = exports.promptForOfficialExtension = exports.displayReleaseNotes = exports.getPublisherProjectFromName = exports.createSourceFromLocation = exports.getMissingPublisherError = exports.uploadExtensionVersionFromLocalSource = exports.uploadExtensionVersionFromGitHubSource = exports.unpackExtensionState = exports.getNextVersionByStage = exports.ensureExtensionsPublisherApiEnabled = exports.ensureExtensionsApiEnabled = exports.checkExtensionsApiEnabled = exports.promptForExtensionRoot = exports.promptForValidRepoURI = exports.promptForValidInstanceId = exports.validateSpec = exports.validateCommandLineParams = exports.populateDefaultParams = exports.substituteSecretParams = exports.substituteParams = exports.getFirebaseProjectParams = exports.getDBInstanceFromURL = exports.resourceTypeToNiceName = exports.
|
|
10
|
+
exports.diagnoseAndFixProject = exports.getSourceOrigin = exports.isLocalOrURLPath = exports.isLocalPath = exports.isUrlPath = exports.instanceIdExists = exports.promptForRepeatInstance = exports.promptForOfficialExtension = exports.displayReleaseNotes = exports.getPublisherProjectFromName = exports.createSourceFromLocation = exports.getMissingPublisherError = exports.uploadExtensionVersionFromLocalSource = exports.uploadExtensionVersionFromGitHubSource = exports.unpackExtensionState = exports.getNextVersionByStage = exports.ensureExtensionsPublisherApiEnabled = exports.ensureExtensionsApiEnabled = exports.checkExtensionsApiEnabled = exports.promptForExtensionRoot = exports.promptForValidRepoURI = exports.promptForValidInstanceId = exports.validateSpec = exports.validateCommandLineParams = exports.populateDefaultParams = exports.substituteSecretParams = exports.substituteParams = exports.getFirebaseProjectParams = exports.getDBInstanceFromURL = exports.resourceTypeToNiceName = exports.AUTOPOPULATED_PARAM_PLACEHOLDERS = exports.EXTENSIONS_BUCKET_NAME = exports.URL_REGEX = exports.logPrefix = exports.SourceOrigin = exports.SpecParamType = void 0;
|
|
11
11
|
const clc = require("colorette");
|
|
12
12
|
const ora = require("ora");
|
|
13
13
|
const semver = require("semver");
|
|
@@ -69,7 +69,7 @@ const AUTOPOPULATED_PARAM_NAMES = [
|
|
|
69
69
|
"DATABASE_INSTANCE",
|
|
70
70
|
"DATABASE_URL",
|
|
71
71
|
];
|
|
72
|
-
exports.
|
|
72
|
+
exports.AUTOPOPULATED_PARAM_PLACEHOLDERS = {
|
|
73
73
|
PROJECT_ID: "project-id",
|
|
74
74
|
STORAGE_BUCKET: "project-id.appspot.com",
|
|
75
75
|
EXT_INSTANCE_ID: "extension-id",
|
|
@@ -449,7 +449,7 @@ async function validateExtensionSpec(rootDirectory, extensionId) {
|
|
|
449
449
|
throw new error_1.FirebaseError(`Extension ID '${clc.bold(extensionId)}' does not match the name in extension.yaml '${clc.bold(extensionSpec.name)}'.`);
|
|
450
450
|
}
|
|
451
451
|
const subbedSpec = JSON.parse(JSON.stringify(extensionSpec));
|
|
452
|
-
subbedSpec.params = substituteParams(extensionSpec.params || [], exports.
|
|
452
|
+
subbedSpec.params = substituteParams(extensionSpec.params || [], exports.AUTOPOPULATED_PARAM_PLACEHOLDERS);
|
|
453
453
|
validateSpec(subbedSpec);
|
|
454
454
|
return extensionSpec;
|
|
455
455
|
}
|