firebase-tools 9.18.0 → 9.22.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/CHANGELOG.md +3 -6
- package/lib/api.js +3 -0
- package/lib/apiv2.js +8 -5
- package/lib/command.js +1 -1
- package/lib/commands/crashlytics-symbols-upload.js +146 -0
- package/lib/commands/deploy.js +9 -1
- package/lib/commands/ext-configure.js +9 -2
- package/lib/commands/ext-dev-deprecate.js +63 -0
- package/lib/commands/ext-dev-extension-delete.js +2 -1
- package/lib/commands/ext-dev-publish.js +10 -4
- package/lib/commands/ext-dev-undeprecate.js +56 -0
- package/lib/commands/ext-dev-unpublish.js +12 -4
- package/lib/commands/ext-export.js +44 -0
- package/lib/commands/ext-install.js +50 -13
- package/lib/commands/ext-uninstall.js +6 -0
- package/lib/commands/ext-update.js +60 -18
- package/lib/commands/functions-config-export.js +115 -0
- package/lib/commands/functions-delete.js +47 -25
- package/lib/commands/functions-list.js +12 -12
- package/lib/commands/index.js +9 -0
- package/lib/commands/init.js +3 -0
- package/lib/config.js +3 -2
- package/lib/deploy/extensions/args.js +2 -0
- package/lib/deploy/extensions/deploy.js +49 -0
- package/lib/deploy/extensions/deploymentSummary.js +52 -0
- package/lib/deploy/extensions/errors.js +31 -0
- package/lib/deploy/extensions/index.js +8 -0
- package/lib/deploy/extensions/planner.js +95 -0
- package/lib/deploy/extensions/prepare.js +103 -0
- package/lib/deploy/extensions/release.js +43 -0
- package/lib/deploy/extensions/secrets.js +150 -0
- package/lib/deploy/extensions/tasks.js +98 -0
- package/lib/deploy/extensions/validate.js +17 -0
- package/lib/deploy/functions/backend.js +93 -115
- package/lib/deploy/functions/checkIam.js +8 -8
- package/lib/deploy/functions/containerCleaner.js +82 -22
- package/lib/deploy/functions/deploy.js +4 -10
- package/lib/deploy/functions/functionsDeployHelper.js +3 -68
- package/lib/deploy/functions/prepare.js +62 -27
- package/lib/deploy/functions/pricing.js +17 -17
- package/lib/deploy/functions/prompts.js +22 -21
- package/lib/deploy/functions/release/executor.js +39 -0
- package/lib/deploy/functions/release/fabricator.js +422 -0
- package/lib/deploy/functions/release/index.js +73 -0
- package/lib/deploy/functions/release/planner.js +162 -0
- package/lib/deploy/functions/release/reporter.js +165 -0
- package/lib/deploy/functions/release/sourceTokenScraper.js +28 -0
- package/lib/deploy/functions/release/timer.js +14 -0
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +129 -126
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +41 -45
- package/lib/deploy/functions/triggerRegionHelper.js +40 -0
- package/lib/deploy/functions/validate.js +1 -24
- package/lib/deploy/index.js +1 -0
- package/lib/downloadUtils.js +37 -0
- package/lib/emulator/auth/apiSpec.js +1788 -403
- package/lib/emulator/auth/handlers.js +6 -5
- package/lib/emulator/auth/operations.js +439 -40
- package/lib/emulator/auth/server.js +32 -11
- package/lib/emulator/auth/state.js +205 -5
- package/lib/emulator/auth/widget_ui.js +2 -2
- package/lib/emulator/download.js +2 -31
- package/lib/emulator/downloadableEmulators.js +7 -7
- package/lib/emulator/emulatorLogger.js +0 -3
- package/lib/emulator/events/types.js +16 -0
- package/lib/emulator/functionsEmulator.js +120 -21
- package/lib/emulator/functionsEmulatorRuntime.js +46 -121
- package/lib/emulator/functionsEmulatorShared.js +51 -7
- package/lib/emulator/functionsEmulatorShell.js +1 -1
- package/lib/emulator/pubsubEmulator.js +61 -40
- package/lib/emulator/storage/cloudFunctions.js +37 -7
- package/lib/extensions/askUserForConsent.js +14 -1
- package/lib/extensions/askUserForParam.js +81 -4
- package/lib/extensions/billingMigrationHelper.js +1 -11
- package/lib/extensions/changelog.js +2 -1
- package/lib/extensions/checkProjectBilling.js +7 -7
- package/lib/extensions/displayExtensionInfo.js +35 -33
- package/lib/extensions/emulator/optionsHelper.js +3 -3
- package/lib/extensions/emulator/triggerHelper.js +2 -32
- package/lib/extensions/export.js +107 -0
- package/lib/extensions/extensionsApi.js +149 -97
- package/lib/extensions/extensionsHelper.js +36 -32
- package/lib/extensions/listExtensions.js +16 -11
- package/lib/extensions/paramHelper.js +73 -40
- package/lib/extensions/provisioningHelper.js +16 -3
- package/lib/extensions/refs.js +67 -0
- package/lib/extensions/secretsUtils.js +59 -0
- package/lib/extensions/updateHelper.js +33 -47
- package/lib/extensions/versionHelper.js +14 -0
- package/lib/extensions/warnings.js +33 -1
- package/lib/functional.js +64 -0
- package/lib/functions/env.js +26 -13
- package/lib/functions/runtimeConfigExport.js +137 -0
- package/lib/gcp/artifactregistry.js +16 -0
- package/lib/gcp/cloudfunctions.js +65 -35
- package/lib/gcp/cloudfunctionsv2.js +56 -43
- package/lib/gcp/cloudscheduler.js +22 -16
- package/lib/gcp/cloudtasks.js +143 -0
- package/lib/gcp/docker.js +7 -1
- package/lib/gcp/proto.js +2 -2
- package/lib/gcp/pubsub.js +1 -9
- package/lib/gcp/secretManager.js +132 -0
- package/lib/gcp/storage.js +16 -0
- package/lib/previews.js +1 -1
- package/lib/requireInteractive.js +12 -0
- package/lib/utils.js +30 -1
- package/package.json +6 -4
- package/schema/firebase-config.json +9 -0
- package/lib/deploy/functions/deploymentPlanner.js +0 -113
- package/lib/deploy/functions/deploymentTimer.js +0 -23
- package/lib/deploy/functions/errorHandler.js +0 -75
- package/lib/deploy/functions/release.js +0 -116
- package/lib/deploy/functions/tasks.js +0 -324
- package/lib/functions/listFunctions.js +0 -10
- package/lib/functionsDelete.js +0 -60
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
- `ext:
|
|
2
|
-
- Fixes
|
|
3
|
-
-
|
|
4
|
-
- Adds a command (`functions:list`) for listing all functions in the Firebase project.
|
|
5
|
-
- Uses public v1 AppDistribution API.
|
|
6
|
-
- Adds `appdistribution:testers:add` and `appdistribution:testers:remove` commands.
|
|
1
|
+
- Adds `firebase ext:export` command, and adds `extensions` to `firebase deploy`. See https://firebase.google.com/docs/extensions/reuse-project-config for more infomation on how to manage your extensions with these commands.
|
|
2
|
+
- Fixes issue where `init` would crash with multiple Hosting items selected (#3742).
|
|
3
|
+
- Adds a command (`crashlytics:symbols:upload`) to upload native symbol files, used in Android NDK crash symbolication.
|
package/lib/api.js
CHANGED
|
@@ -72,6 +72,7 @@ var api = {
|
|
|
72
72
|
cloudbillingOrigin: utils.envOverride("FIREBASE_CLOUDBILLING_URL", "https://cloudbilling.googleapis.com"),
|
|
73
73
|
cloudloggingOrigin: utils.envOverride("FIREBASE_CLOUDLOGGING_URL", "https://logging.googleapis.com"),
|
|
74
74
|
containerRegistryDomain: utils.envOverride("CONTAINER_REGISTRY_DOMAIN", "gcr.io"),
|
|
75
|
+
artifactRegistryDomain: utils.envOverride("ARTIFACT_REGISTRY_DOMAIN", "https://artifactregistry.googleapis.com"),
|
|
75
76
|
appDistributionOrigin: utils.envOverride("FIREBASE_APP_DISTRIBUTION_URL", "https://firebaseappdistribution.googleapis.com"),
|
|
76
77
|
appengineOrigin: utils.envOverride("FIREBASE_APPENGINE_URL", "https://appengine.googleapis.com"),
|
|
77
78
|
authOrigin: utils.envOverride("FIREBASE_AUTH_URL", "https://accounts.google.com"),
|
|
@@ -95,6 +96,7 @@ var api = {
|
|
|
95
96
|
functionsUploadRegion: utils.envOverride("FIREBASE_FUNCTIONS_UPLOAD_REGION", "us-central1"),
|
|
96
97
|
functionsDefaultRegion: utils.envOverride("FIREBASE_FUNCTIONS_DEFAULT_REGION", "us-central1"),
|
|
97
98
|
cloudschedulerOrigin: utils.envOverride("FIREBASE_CLOUDSCHEDULER_URL", "https://cloudscheduler.googleapis.com"),
|
|
99
|
+
cloudTasksOrigin: utils.envOverride("FIREBASE_CLOUD_TAKS_URL", "https://cloudtasks.googleapis.com"),
|
|
98
100
|
pubsubOrigin: utils.envOverride("FIREBASE_PUBSUB_URL", "https://pubsub.googleapis.com"),
|
|
99
101
|
googleOrigin: utils.envOverride("FIREBASE_TOKEN_URL", utils.envOverride("FIREBASE_GOOGLE_URL", "https://www.googleapis.com")),
|
|
100
102
|
hostingOrigin: utils.envOverride("FIREBASE_HOSTING_URL", "https://web.app"),
|
|
@@ -115,6 +117,7 @@ var api = {
|
|
|
115
117
|
serviceUsageOrigin: utils.envOverride("FIREBASE_SERVICE_USAGE_URL", "https://serviceusage.googleapis.com"),
|
|
116
118
|
githubOrigin: utils.envOverride("GITHUB_URL", "https://github.com"),
|
|
117
119
|
githubApiOrigin: utils.envOverride("GITHUB_API_URL", "https://api.github.com"),
|
|
120
|
+
secretManagerOrigin: utils.envOverride("CLOUD_SECRET_MANAGER_URL", "https://secretmanager.googleapis.com"),
|
|
118
121
|
githubClientId: utils.envOverride("GITHUB_CLIENT_ID", "89cf50f02ac6aaed3484"),
|
|
119
122
|
githubClientSecret: utils.envOverride("GITHUB_CLIENT_SECRET", "3330d14abc895d9a74d5f17cd7a00711fa2c5bf0"),
|
|
120
123
|
setRefreshToken: function (token) {
|
package/lib/apiv2.js
CHANGED
|
@@ -12,7 +12,7 @@ const error_1 = require("./error");
|
|
|
12
12
|
const logger_1 = require("./logger");
|
|
13
13
|
const responseToError = require("./responseToError");
|
|
14
14
|
const pkg = require("../package.json");
|
|
15
|
-
const CLI_VERSION = pkg.
|
|
15
|
+
const CLI_VERSION = pkg.version;
|
|
16
16
|
let accessToken = "";
|
|
17
17
|
let refreshToken = "";
|
|
18
18
|
function setRefreshToken(token = "") {
|
|
@@ -118,8 +118,10 @@ class Client {
|
|
|
118
118
|
reqOptions.headers.set("User-Agent", `FirebaseCLI/${CLI_VERSION}`);
|
|
119
119
|
}
|
|
120
120
|
reqOptions.headers.set("X-Client-Version", `FirebaseCLI/${CLI_VERSION}`);
|
|
121
|
-
if (reqOptions.
|
|
122
|
-
reqOptions.
|
|
121
|
+
if (!reqOptions.headers.has("Content-Type")) {
|
|
122
|
+
if (reqOptions.responseType === "json") {
|
|
123
|
+
reqOptions.headers.set("Content-Type", "application/json");
|
|
124
|
+
}
|
|
123
125
|
}
|
|
124
126
|
return reqOptions;
|
|
125
127
|
}
|
|
@@ -217,11 +219,12 @@ class Client {
|
|
|
217
219
|
}
|
|
218
220
|
let body;
|
|
219
221
|
if (options.responseType === "json") {
|
|
220
|
-
|
|
222
|
+
const text = await res.text();
|
|
223
|
+
if (!text.length) {
|
|
221
224
|
body = undefined;
|
|
222
225
|
}
|
|
223
226
|
else {
|
|
224
|
-
body =
|
|
227
|
+
body = JSON.parse(text);
|
|
225
228
|
}
|
|
226
229
|
}
|
|
227
230
|
else if (options.responseType === "stream") {
|
package/lib/command.js
CHANGED
|
@@ -131,12 +131,12 @@ class Command {
|
|
|
131
131
|
}
|
|
132
132
|
const account = utils_1.getInheritedOption(options, "account");
|
|
133
133
|
options.account = account;
|
|
134
|
+
options.projectRoot = detectProjectRoot_1.detectProjectRoot(options);
|
|
134
135
|
const projectRoot = options.projectRoot;
|
|
135
136
|
const activeAccount = auth_1.selectAccount(account, projectRoot);
|
|
136
137
|
if (activeAccount) {
|
|
137
138
|
auth_1.setActiveAccount(options, activeAccount);
|
|
138
139
|
}
|
|
139
|
-
options.projectRoot = detectProjectRoot_1.detectProjectRoot(options);
|
|
140
140
|
this.applyRC(options);
|
|
141
141
|
if (options.project) {
|
|
142
142
|
await this.resolveProjectIdentifiers(options);
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const fs = require("fs-extra");
|
|
4
|
+
const os = require("os");
|
|
5
|
+
const path = require("path");
|
|
6
|
+
const spawn = require("cross-spawn");
|
|
7
|
+
const uuid = require("uuid");
|
|
8
|
+
const command_1 = require("../command");
|
|
9
|
+
const downloadUtils = require("../downloadUtils");
|
|
10
|
+
const error_1 = require("../error");
|
|
11
|
+
const logger_1 = require("../logger");
|
|
12
|
+
const rimraf = require("rimraf");
|
|
13
|
+
const utils = require("../utils");
|
|
14
|
+
var SymbolGenerator;
|
|
15
|
+
(function (SymbolGenerator) {
|
|
16
|
+
SymbolGenerator["breakpad"] = "breakpad";
|
|
17
|
+
SymbolGenerator["csym"] = "csym";
|
|
18
|
+
})(SymbolGenerator || (SymbolGenerator = {}));
|
|
19
|
+
const SYMBOL_CACHE_ROOT_DIR = process.env.FIREBASE_CRASHLYTICS_CACHE_PATH || os.tmpdir();
|
|
20
|
+
const JAR_CACHE_DIR = process.env.FIREBASE_CRASHLYTICS_BUILDTOOLS_PATH ||
|
|
21
|
+
path.join(os.homedir(), ".cache", "firebase", "crashlytics", "buildtools");
|
|
22
|
+
const JAR_VERSION = "2.8.0";
|
|
23
|
+
const JAR_URL = `https://dl.google.com/android/maven2/com/google/firebase/firebase-crashlytics-buildtools/${JAR_VERSION}/firebase-crashlytics-buildtools-${JAR_VERSION}.jar`;
|
|
24
|
+
exports.default = new command_1.Command("crashlytics:symbols:upload <symbolFiles...>")
|
|
25
|
+
.description("Upload symbols for native code, to symbolicate stack traces.")
|
|
26
|
+
.option("--app <appID>", "the app id of your Firebase app")
|
|
27
|
+
.option("--generator [breakpad|csym]", "the symbol generator being used, defaults to breakpad.")
|
|
28
|
+
.option("--dry-run", "generate symbols without uploading them")
|
|
29
|
+
.option("--debug", "print debug output and logging from the underlying uploader tool")
|
|
30
|
+
.action(async (symbolFiles, options) => {
|
|
31
|
+
const app = getGoogleAppID(options) || "";
|
|
32
|
+
const generator = getSymbolGenerator(options);
|
|
33
|
+
const dryRun = !!options.dryRun;
|
|
34
|
+
const debug = !!options.debug;
|
|
35
|
+
let jarFile = await downloadBuiltoolsJar();
|
|
36
|
+
if (process.env.LOCAL_JAR) {
|
|
37
|
+
jarFile = process.env.LOCAL_JAR;
|
|
38
|
+
}
|
|
39
|
+
const jarOptions = {
|
|
40
|
+
jarFile,
|
|
41
|
+
app,
|
|
42
|
+
generator,
|
|
43
|
+
cachePath: path.join(SYMBOL_CACHE_ROOT_DIR, `crashlytics-${uuid.v4()}`, "nativeSymbols", app.replace(/:/g, "-"), generator),
|
|
44
|
+
symbolFile: "",
|
|
45
|
+
generate: true,
|
|
46
|
+
};
|
|
47
|
+
for (const symbolFile of symbolFiles) {
|
|
48
|
+
utils.logBullet(`Generating symbols for ${symbolFile}`);
|
|
49
|
+
const generateArgs = buildArgs(Object.assign(Object.assign({}, jarOptions), { symbolFile }));
|
|
50
|
+
const output = runJar(generateArgs, debug);
|
|
51
|
+
if (output.length > 0) {
|
|
52
|
+
utils.logBullet(output);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
utils.logBullet(`Generated symbols for ${symbolFile}`);
|
|
56
|
+
utils.logBullet(`Output Path: ${jarOptions.cachePath}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (dryRun) {
|
|
60
|
+
utils.logBullet("Skipping upload because --dry-run was passed");
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
utils.logBullet(`Uploading all generated symbols`);
|
|
64
|
+
const uploadArgs = buildArgs(Object.assign(Object.assign({}, jarOptions), { generate: false }));
|
|
65
|
+
const output = runJar(uploadArgs, debug);
|
|
66
|
+
if (output.length > 0) {
|
|
67
|
+
utils.logBullet(output);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
utils.logBullet("Successfully uploaded all symbols");
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
function getGoogleAppID(options) {
|
|
74
|
+
if (!options.app) {
|
|
75
|
+
throw new error_1.FirebaseError("set the --app option to a valid Firebase app id and try again");
|
|
76
|
+
}
|
|
77
|
+
return options.app;
|
|
78
|
+
}
|
|
79
|
+
function getSymbolGenerator(options) {
|
|
80
|
+
if (!options.generator) {
|
|
81
|
+
return SymbolGenerator.breakpad;
|
|
82
|
+
}
|
|
83
|
+
if (!Object.values(SymbolGenerator).includes(options.generator)) {
|
|
84
|
+
throw new error_1.FirebaseError('--symbol-generator should be set to either "breakpad" or "csym"');
|
|
85
|
+
}
|
|
86
|
+
return options.generator;
|
|
87
|
+
}
|
|
88
|
+
async function downloadBuiltoolsJar() {
|
|
89
|
+
const jarPath = path.join(JAR_CACHE_DIR, `crashlytics-buildtools-${JAR_VERSION}.jar`);
|
|
90
|
+
if (fs.existsSync(jarPath)) {
|
|
91
|
+
logger_1.logger.debug(`Buildtools Jar already downloaded at ${jarPath}`);
|
|
92
|
+
return jarPath;
|
|
93
|
+
}
|
|
94
|
+
if (fs.existsSync(JAR_CACHE_DIR)) {
|
|
95
|
+
logger_1.logger.debug(`Deleting Jar cache at ${JAR_CACHE_DIR} because the CLI was run with a newer Jar version`);
|
|
96
|
+
rimraf.sync(JAR_CACHE_DIR);
|
|
97
|
+
}
|
|
98
|
+
utils.logBullet("Downloading buildtools.jar to " + jarPath);
|
|
99
|
+
utils.logBullet("For open source licenses used by this command, look in the META-INF directory in the buildtools.jar file");
|
|
100
|
+
const tmpfile = await downloadUtils.downloadToTmp(JAR_URL);
|
|
101
|
+
fs.mkdirSync(JAR_CACHE_DIR, { recursive: true });
|
|
102
|
+
fs.copySync(tmpfile, jarPath);
|
|
103
|
+
return jarPath;
|
|
104
|
+
}
|
|
105
|
+
function buildArgs(options) {
|
|
106
|
+
const baseArgs = [
|
|
107
|
+
"-jar",
|
|
108
|
+
options.jarFile,
|
|
109
|
+
`-symbolGenerator=${options.generator}`,
|
|
110
|
+
`-symbolFileCacheDir=${options.cachePath}`,
|
|
111
|
+
"-verbose",
|
|
112
|
+
];
|
|
113
|
+
if (options.generate) {
|
|
114
|
+
return baseArgs.concat(["-generateNativeSymbols", `-unstrippedLibrary=${options.symbolFile}`]);
|
|
115
|
+
}
|
|
116
|
+
return baseArgs.concat([
|
|
117
|
+
"-uploadNativeSymbols",
|
|
118
|
+
`-googleAppId=${options.app}`,
|
|
119
|
+
]);
|
|
120
|
+
}
|
|
121
|
+
function runJar(args, debug) {
|
|
122
|
+
var _a, _b, _c;
|
|
123
|
+
const outputs = spawn.sync("java", args, {
|
|
124
|
+
stdio: debug ? "inherit" : "pipe",
|
|
125
|
+
});
|
|
126
|
+
if (outputs.status || 0 > 0) {
|
|
127
|
+
if (!debug) {
|
|
128
|
+
utils.logWarning(((_a = outputs.stdout) === null || _a === void 0 ? void 0 : _a.toString()) || "An unknown error occurred");
|
|
129
|
+
}
|
|
130
|
+
throw new error_1.FirebaseError("Failed to upload symbols");
|
|
131
|
+
}
|
|
132
|
+
if (!debug) {
|
|
133
|
+
let logRegex = /(Generated symbol file.*$)/m;
|
|
134
|
+
let matched = (((_b = outputs.stdout) === null || _b === void 0 ? void 0 : _b.toString()) || "").match(logRegex);
|
|
135
|
+
if (matched) {
|
|
136
|
+
return matched[1];
|
|
137
|
+
}
|
|
138
|
+
logRegex = /(Crashlytics symbol file uploaded successfully.*$)/m;
|
|
139
|
+
matched = (((_c = outputs.stdout) === null || _c === void 0 ? void 0 : _c.toString()) || "").match(logRegex);
|
|
140
|
+
if (matched) {
|
|
141
|
+
return matched[1];
|
|
142
|
+
}
|
|
143
|
+
return "";
|
|
144
|
+
}
|
|
145
|
+
return "";
|
|
146
|
+
}
|
package/lib/commands/deploy.js
CHANGED
|
@@ -9,7 +9,15 @@ const deploy = require("../deploy");
|
|
|
9
9
|
const requireConfig = require("../requireConfig");
|
|
10
10
|
const { filterTargets } = require("../filterTargets");
|
|
11
11
|
const { requireHostingSite } = require("../requireHostingSite");
|
|
12
|
-
const VALID_TARGETS = [
|
|
12
|
+
const VALID_TARGETS = [
|
|
13
|
+
"database",
|
|
14
|
+
"storage",
|
|
15
|
+
"firestore",
|
|
16
|
+
"functions",
|
|
17
|
+
"hosting",
|
|
18
|
+
"remoteconfig",
|
|
19
|
+
"extensions",
|
|
20
|
+
];
|
|
13
21
|
const TARGET_PERMISSIONS = {
|
|
14
22
|
database: ["firebasedatabase.instances.update"],
|
|
15
23
|
hosting: ["firebasehosting.sites.update"],
|
|
@@ -47,7 +47,14 @@ exports.default = new command_1.Command("ext:configure <extensionInstanceId>")
|
|
|
47
47
|
const immutableParams = _.remove(paramSpecWithNewDefaults, (param) => {
|
|
48
48
|
return param.immutable || param.param === "LOCATION";
|
|
49
49
|
});
|
|
50
|
-
const params = await paramHelper.getParams(
|
|
50
|
+
const params = await paramHelper.getParams({
|
|
51
|
+
projectId,
|
|
52
|
+
paramSpecs: paramSpecWithNewDefaults,
|
|
53
|
+
nonInteractive: options.nonInteractive,
|
|
54
|
+
paramsEnvPath: options.params,
|
|
55
|
+
instanceId,
|
|
56
|
+
reconfiguring: true,
|
|
57
|
+
});
|
|
51
58
|
if (immutableParams.length) {
|
|
52
59
|
const plural = immutableParams.length > 1;
|
|
53
60
|
logger_1.logger.info(`The following param${plural ? "s are" : " is"} immutable:`);
|
|
@@ -62,7 +69,7 @@ exports.default = new command_1.Command("ext:configure <extensionInstanceId>")
|
|
|
62
69
|
", uninstall the extension, then install a new instance of this extension.");
|
|
63
70
|
}
|
|
64
71
|
spinner.start();
|
|
65
|
-
const res = await extensionsApi.configureInstance(projectId, instanceId, params);
|
|
72
|
+
const res = await extensionsApi.configureInstance({ projectId, instanceId, params });
|
|
66
73
|
spinner.stop();
|
|
67
74
|
utils.logLabeledSuccess(extensionsHelper_1.logPrefix, `successfully configured ${clc.bold(instanceId)}.`);
|
|
68
75
|
utils.logLabeledBullet(extensionsHelper_1.logPrefix, marked(`You can view your reconfigured instance in the Firebase console: ${utils.consoleUrl(projectId, `/extensions/instances/${instanceId}?tab=config`)}`));
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const clc = require("cli-color");
|
|
4
|
+
const semver = require("semver");
|
|
5
|
+
const refs = require("../extensions/refs");
|
|
6
|
+
const utils = require("../utils");
|
|
7
|
+
const command_1 = require("../command");
|
|
8
|
+
const prompt_1 = require("../prompt");
|
|
9
|
+
const extensionsHelper_1 = require("../extensions/extensionsHelper");
|
|
10
|
+
const extensionsApi_1 = require("../extensions/extensionsApi");
|
|
11
|
+
const versionHelper_1 = require("../extensions/versionHelper");
|
|
12
|
+
const requireAuth_1 = require("../requireAuth");
|
|
13
|
+
const error_1 = require("../error");
|
|
14
|
+
exports.default = new command_1.Command("ext:dev:deprecate <extensionRef> <versionPredicate>")
|
|
15
|
+
.description("deprecate extension versions that match the version predicate")
|
|
16
|
+
.option("-m, --message <deprecationMessage>", "deprecation message")
|
|
17
|
+
.option("-f, --force", "override deprecation message for existing deprecated extension versions that match")
|
|
18
|
+
.before(requireAuth_1.requireAuth)
|
|
19
|
+
.before(extensionsHelper_1.ensureExtensionsApiEnabled)
|
|
20
|
+
.action(async (extensionRef, versionPredicate, options) => {
|
|
21
|
+
const { publisherId, extensionId, version } = refs.parse(extensionRef);
|
|
22
|
+
if (version) {
|
|
23
|
+
throw new error_1.FirebaseError(`The input extension reference must be of the format ${clc.bold("<publisherId>/<extensionId>")}. Version should be supplied in the version predicate argument.`);
|
|
24
|
+
}
|
|
25
|
+
if (!publisherId || !extensionId) {
|
|
26
|
+
throw new error_1.FirebaseError(`Error parsing publisher ID and extension ID from extension reference '${clc.bold(extensionRef)}'. Please use the format '${clc.bold("<publisherId>/<extensionId>")}'.`);
|
|
27
|
+
}
|
|
28
|
+
const { comparator, targetSemVer } = versionHelper_1.parseVersionPredicate(versionPredicate);
|
|
29
|
+
const filter = `id${comparator}"${targetSemVer}"`;
|
|
30
|
+
const extensionVersions = await extensionsApi_1.listExtensionVersions(extensionRef, filter);
|
|
31
|
+
const filteredExtensionVersions = extensionVersions
|
|
32
|
+
.sort((ev1, ev2) => {
|
|
33
|
+
return -semver.compare(ev1.spec.version, ev2.spec.version);
|
|
34
|
+
})
|
|
35
|
+
.filter((extensionVersion) => {
|
|
36
|
+
if (extensionVersion.state === "DEPRECATED" && !options.force) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
const message = extensionVersion.state === "DEPRECATED" ? ", will overwrite deprecation message" : "";
|
|
40
|
+
utils.logLabeledBullet(extensionVersion.ref, extensionVersion.state + message);
|
|
41
|
+
return true;
|
|
42
|
+
});
|
|
43
|
+
if (filteredExtensionVersions.length > 0) {
|
|
44
|
+
if (!options.force) {
|
|
45
|
+
const confirmMessage = "You are about to deprecate these extension version(s). Do you wish to continue?";
|
|
46
|
+
const consent = await prompt_1.promptOnce({
|
|
47
|
+
type: "confirm",
|
|
48
|
+
message: confirmMessage,
|
|
49
|
+
default: false,
|
|
50
|
+
});
|
|
51
|
+
if (!consent) {
|
|
52
|
+
throw new error_1.FirebaseError("Deprecation canceled.");
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
throw new error_1.FirebaseError("No extension versions matched the version predicate.");
|
|
58
|
+
}
|
|
59
|
+
await utils.allSettled(filteredExtensionVersions.map(async (extensionVersion) => {
|
|
60
|
+
await extensionsApi_1.deprecateExtensionVersion(extensionVersion.ref, options.deprecationMessage);
|
|
61
|
+
}));
|
|
62
|
+
utils.logLabeledSuccess(extensionsHelper_1.logPrefix, "successfully deprecated extension version(s).");
|
|
63
|
+
});
|
|
@@ -5,6 +5,7 @@ const clc = require("cli-color");
|
|
|
5
5
|
const command_1 = require("../command");
|
|
6
6
|
const extensionsHelper_1 = require("../extensions/extensionsHelper");
|
|
7
7
|
const extensionsApi_1 = require("../extensions/extensionsApi");
|
|
8
|
+
const refs = require("../extensions/refs");
|
|
8
9
|
const prompt_1 = require("../prompt");
|
|
9
10
|
const requireAuth_1 = require("../requireAuth");
|
|
10
11
|
const error_1 = require("../error");
|
|
@@ -16,7 +17,7 @@ module.exports = new command_1.Command("ext:dev:delete <extensionRef>")
|
|
|
16
17
|
.before(requireAuth_1.requireAuth)
|
|
17
18
|
.before(checkMinRequiredVersion_1.checkMinRequiredVersion, "extDevMinVersion")
|
|
18
19
|
.action(async (extensionRef) => {
|
|
19
|
-
const { publisherId, extensionId, version } =
|
|
20
|
+
const { publisherId, extensionId, version } = refs.parse(extensionRef);
|
|
20
21
|
if (version) {
|
|
21
22
|
throw new error_1.FirebaseError(`Deleting a single version is not currently supported. You can only delete ${clc.bold("ALL versions")} of an extension. To delete all versions, please remove the version from the reference.`);
|
|
22
23
|
}
|
|
@@ -5,7 +5,7 @@ const marked = require("marked");
|
|
|
5
5
|
const TerminalRenderer = require("marked-terminal");
|
|
6
6
|
const command_1 = require("../command");
|
|
7
7
|
const extensionsHelper_1 = require("../extensions/extensionsHelper");
|
|
8
|
-
const
|
|
8
|
+
const refs = require("../extensions/refs");
|
|
9
9
|
const localHelper_1 = require("../extensions/localHelper");
|
|
10
10
|
const publishHelpers_1 = require("../extensions/publishHelpers");
|
|
11
11
|
const requireAuth_1 = require("../requireAuth");
|
|
@@ -21,8 +21,8 @@ exports.default = new command_1.Command("ext:dev:publish <extensionRef>")
|
|
|
21
21
|
"create the extension. If you have previously published a version of this extension, this version must " +
|
|
22
22
|
"be greater than previous versions.")
|
|
23
23
|
.before(requireAuth_1.requireAuth)
|
|
24
|
-
.action(async (extensionRef) => {
|
|
25
|
-
const { publisherId, extensionId, version } =
|
|
24
|
+
.action(async (extensionRef, options) => {
|
|
25
|
+
const { publisherId, extensionId, version } = refs.parse(extensionRef);
|
|
26
26
|
if (version) {
|
|
27
27
|
throw new error_1.FirebaseError(`The input extension reference must be of the format ${clc.bold("<publisherId>/<extensionId>")}. Version should not be supplied and will be inferred directly from extension.yaml. Please increment the version in extension.yaml if you would like to bump/specify a version.`);
|
|
28
28
|
}
|
|
@@ -30,7 +30,13 @@ exports.default = new command_1.Command("ext:dev:publish <extensionRef>")
|
|
|
30
30
|
throw new error_1.FirebaseError(`Error parsing publisher ID and extension ID from extension reference '${clc.bold(extensionRef)}'. Please use the format '${clc.bold("<publisherId>/<extensionId>")}'.`);
|
|
31
31
|
}
|
|
32
32
|
const extensionYamlDirectory = localHelper_1.findExtensionYaml(process.cwd());
|
|
33
|
-
const res = await extensionsHelper_1.publishExtensionVersionFromLocalSource(
|
|
33
|
+
const res = await extensionsHelper_1.publishExtensionVersionFromLocalSource({
|
|
34
|
+
publisherId,
|
|
35
|
+
extensionId,
|
|
36
|
+
rootDirectory: extensionYamlDirectory,
|
|
37
|
+
nonInteractive: options.nonInteractive,
|
|
38
|
+
force: options.force,
|
|
39
|
+
});
|
|
34
40
|
if (res) {
|
|
35
41
|
utils.logLabeledBullet(extensionsHelper_1.logPrefix, marked(`[Install Link](${publishHelpers_1.consoleInstallLink(res.ref)})`));
|
|
36
42
|
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const clc = require("cli-color");
|
|
4
|
+
const semver = require("semver");
|
|
5
|
+
const refs = require("../extensions/refs");
|
|
6
|
+
const utils = require("../utils");
|
|
7
|
+
const command_1 = require("../command");
|
|
8
|
+
const prompt_1 = require("../prompt");
|
|
9
|
+
const extensionsHelper_1 = require("../extensions/extensionsHelper");
|
|
10
|
+
const extensionsApi_1 = require("../extensions/extensionsApi");
|
|
11
|
+
const versionHelper_1 = require("../extensions/versionHelper");
|
|
12
|
+
const requireAuth_1 = require("../requireAuth");
|
|
13
|
+
const error_1 = require("../error");
|
|
14
|
+
exports.default = new command_1.Command("ext:dev:undeprecate <extensionRef> <versionPredicate>")
|
|
15
|
+
.description("undeprecate extension versions that match the version predicate")
|
|
16
|
+
.before(requireAuth_1.requireAuth)
|
|
17
|
+
.before(extensionsHelper_1.ensureExtensionsApiEnabled)
|
|
18
|
+
.action(async (extensionRef, versionPredicate, options) => {
|
|
19
|
+
const { publisherId, extensionId, version } = refs.parse(extensionRef);
|
|
20
|
+
if (version) {
|
|
21
|
+
throw new error_1.FirebaseError(`The input extension reference must be of the format ${clc.bold("<publisherId>/<extensionId>")}. Version should be supplied in the version predicate argument.`);
|
|
22
|
+
}
|
|
23
|
+
if (!publisherId || !extensionId) {
|
|
24
|
+
throw new error_1.FirebaseError(`Error parsing publisher ID and extension ID from extension reference '${clc.bold(extensionRef)}'. Please use the format '${clc.bold("<publisherId>/<extensionId>")}'.`);
|
|
25
|
+
}
|
|
26
|
+
const { comparator, targetSemVer } = versionHelper_1.parseVersionPredicate(versionPredicate);
|
|
27
|
+
const filter = `id${comparator}"${targetSemVer}"`;
|
|
28
|
+
const extensionVersions = await extensionsApi_1.listExtensionVersions(extensionRef, filter);
|
|
29
|
+
extensionVersions
|
|
30
|
+
.sort((ev1, ev2) => {
|
|
31
|
+
return -semver.compare(ev1.spec.version, ev2.spec.version);
|
|
32
|
+
})
|
|
33
|
+
.forEach((extensionVersion) => {
|
|
34
|
+
utils.logLabeledBullet(extensionVersion.ref, extensionVersion.state);
|
|
35
|
+
});
|
|
36
|
+
if (extensionVersions.length > 0) {
|
|
37
|
+
if (!options.force) {
|
|
38
|
+
const confirmMessage = "You are about to undeprecate these extension version(s). Do you wish to continue?";
|
|
39
|
+
const consent = await prompt_1.promptOnce({
|
|
40
|
+
type: "confirm",
|
|
41
|
+
message: confirmMessage,
|
|
42
|
+
default: false,
|
|
43
|
+
});
|
|
44
|
+
if (!consent) {
|
|
45
|
+
throw new error_1.FirebaseError("Undeprecation canceled.");
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
throw new error_1.FirebaseError("No extension versions matched the version predicate.");
|
|
51
|
+
}
|
|
52
|
+
await utils.allSettled(extensionVersions.map(async (extensionVersion) => {
|
|
53
|
+
await extensionsApi_1.undeprecateExtensionVersion(extensionVersion.ref);
|
|
54
|
+
}));
|
|
55
|
+
utils.logLabeledSuccess(extensionsHelper_1.logPrefix, "successfully undeprecated extension version(s).");
|
|
56
|
+
});
|
|
@@ -4,6 +4,7 @@ const command_1 = require("../command");
|
|
|
4
4
|
const extensionsHelper_1 = require("../extensions/extensionsHelper");
|
|
5
5
|
const extensionsApi_1 = require("../extensions/extensionsApi");
|
|
6
6
|
const utils = require("../utils");
|
|
7
|
+
const refs = require("../extensions/refs");
|
|
7
8
|
const prompt_1 = require("../prompt");
|
|
8
9
|
const clc = require("cli-color");
|
|
9
10
|
const requireAuth_1 = require("../requireAuth");
|
|
@@ -11,26 +12,33 @@ const error_1 = require("../error");
|
|
|
11
12
|
const checkMinRequiredVersion_1 = require("../checkMinRequiredVersion");
|
|
12
13
|
module.exports = new command_1.Command("ext:dev:unpublish <extensionRef>")
|
|
13
14
|
.description("unpublish an extension")
|
|
15
|
+
.withForce()
|
|
14
16
|
.help("use this command to unpublish an extension, and make it unavailable for developers to install or reconfigure. " +
|
|
15
17
|
"Specify the extension you want to unpublish using the format '<publisherId>/<extensionId>.")
|
|
16
18
|
.before(requireAuth_1.requireAuth)
|
|
17
19
|
.before(checkMinRequiredVersion_1.checkMinRequiredVersion, "extDevMinVersion")
|
|
18
|
-
.action(async (extensionRef) => {
|
|
19
|
-
const { publisherId, extensionId, version } =
|
|
20
|
+
.action(async (extensionRef, options) => {
|
|
21
|
+
const { publisherId, extensionId, version } = refs.parse(extensionRef);
|
|
20
22
|
utils.logLabeledWarning(extensionsHelper_1.logPrefix, "If you unpublish this extension, developers won't be able to install it. For developers who currently have this extension installed, it will continue to run and will appear as unpublished when listed in the Firebase console or Firebase CLI.");
|
|
21
23
|
utils.logLabeledWarning("This is a permanent action", `Once unpublished, you may never use the extension name '${clc.bold(extensionId)}' again.`);
|
|
22
24
|
if (version) {
|
|
23
25
|
throw new error_1.FirebaseError(`Unpublishing a single version is not currently supported. You can only unpublish ${clc.bold("ALL versions")} of an extension. To unpublish all versions, please remove the version from the reference.`);
|
|
24
26
|
}
|
|
25
27
|
await extensionsApi_1.getExtension(extensionRef);
|
|
26
|
-
const consent = await comfirmUnpublish(publisherId, extensionId);
|
|
28
|
+
const consent = await comfirmUnpublish(publisherId, extensionId, options);
|
|
27
29
|
if (!consent) {
|
|
28
30
|
throw new error_1.FirebaseError("unpublishing cancelled.");
|
|
29
31
|
}
|
|
30
32
|
await extensionsApi_1.unpublishExtension(extensionRef);
|
|
31
33
|
utils.logLabeledSuccess(extensionsHelper_1.logPrefix, "successfully unpublished all versions of this extension.");
|
|
32
34
|
});
|
|
33
|
-
async function comfirmUnpublish(publisherId, extensionId) {
|
|
35
|
+
async function comfirmUnpublish(publisherId, extensionId, options) {
|
|
36
|
+
if (options.nonInteractive && !options.force) {
|
|
37
|
+
throw new error_1.FirebaseError("Pass the --force flag to use this command in non-interactive mode");
|
|
38
|
+
}
|
|
39
|
+
if (options.nonInteractive && options.force) {
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
34
42
|
const message = `You are about to unpublish ALL versions of ${clc.green(`${publisherId}/${extensionId}`)}.\nDo you wish to continue? `;
|
|
35
43
|
return prompt_1.promptOnce({
|
|
36
44
|
type: "confirm",
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const checkMinRequiredVersion_1 = require("../checkMinRequiredVersion");
|
|
4
|
+
const command_1 = require("../command");
|
|
5
|
+
const planner = require("../deploy/extensions/planner");
|
|
6
|
+
const export_1 = require("../extensions/export");
|
|
7
|
+
const extensionsHelper_1 = require("../extensions/extensionsHelper");
|
|
8
|
+
const functional_1 = require("../functional");
|
|
9
|
+
const getProjectNumber_1 = require("../getProjectNumber");
|
|
10
|
+
const logger_1 = require("../logger");
|
|
11
|
+
const projectUtils_1 = require("../projectUtils");
|
|
12
|
+
const prompt_1 = require("../prompt");
|
|
13
|
+
const requirePermissions_1 = require("../requirePermissions");
|
|
14
|
+
module.exports = new command_1.Command("ext:export")
|
|
15
|
+
.description("export all Extension instances installed on a project to a local Firebase directory")
|
|
16
|
+
.before(requirePermissions_1.requirePermissions, ["firebaseextensions.instances.list"])
|
|
17
|
+
.before(extensionsHelper_1.ensureExtensionsApiEnabled)
|
|
18
|
+
.before(checkMinRequiredVersion_1.checkMinRequiredVersion, "extMinVersion")
|
|
19
|
+
.withForce()
|
|
20
|
+
.action(async (options) => {
|
|
21
|
+
const projectId = projectUtils_1.needProjectId(options);
|
|
22
|
+
const projectNumber = await getProjectNumber_1.getProjectNumber(options);
|
|
23
|
+
const have = await Promise.all((await planner.have(projectId)).map(async (i) => {
|
|
24
|
+
const subbed = await export_1.setSecretParamsToLatest(i);
|
|
25
|
+
return export_1.parameterizeProject(projectId, projectNumber, subbed);
|
|
26
|
+
}));
|
|
27
|
+
if (have.length == 0) {
|
|
28
|
+
logger_1.logger.info(`No extension instances installed on ${projectId}, so there is nothing to export.`);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const [withRef, withoutRef] = functional_1.partition(have, (s) => !!s.ref);
|
|
32
|
+
export_1.displayExportInfo(withRef, withoutRef);
|
|
33
|
+
if (!options.nonInteractive &&
|
|
34
|
+
!options.force &&
|
|
35
|
+
!(await prompt_1.promptOnce({
|
|
36
|
+
message: "Do you wish to add these Extension instances to firebase.json?",
|
|
37
|
+
type: "confirm",
|
|
38
|
+
default: true,
|
|
39
|
+
}))) {
|
|
40
|
+
logger_1.logger.info("Exiting. No changes made.");
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
await export_1.writeFiles(withRef, options);
|
|
44
|
+
});
|