firebase-tools 14.2.2 → 14.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/api.js +4 -2
- package/lib/apphosting/backend.js +12 -23
- package/lib/apphosting/config.js +9 -20
- package/lib/apphosting/githubConnections.js +65 -99
- package/lib/apphosting/repo.js +22 -36
- package/lib/apphosting/secrets/dialogs.js +2 -3
- package/lib/apphosting/utils.js +1 -3
- package/lib/auth.js +1 -4
- package/lib/commands/apphosting-backends-delete.js +5 -5
- package/lib/commands/apphosting-secrets-set.js +2 -6
- package/lib/commands/apps-create.js +2 -3
- package/lib/commands/apps-sdkconfig.js +2 -7
- package/lib/commands/database-import.js +4 -6
- package/lib/commands/database-remove.js +4 -6
- package/lib/commands/database-set.js +6 -6
- package/lib/commands/database-update.js +5 -5
- package/lib/commands/dataconnect-sql-shell.js +4 -6
- package/lib/commands/ext-dev-deprecate.js +1 -0
- package/lib/commands/ext-dev-init.js +3 -12
- package/lib/commands/ext-dev-register.js +2 -4
- package/lib/commands/ext-dev-undeprecate.js +1 -2
- package/lib/commands/ext-dev-usage.js +1 -3
- package/lib/commands/ext-export.js +1 -2
- package/lib/commands/ext-install.js +1 -0
- package/lib/commands/ext-sdk-install.js +1 -0
- package/lib/commands/ext-update.js +1 -0
- package/lib/commands/firestore-backups-delete.js +1 -2
- package/lib/commands/firestore-backups-schedules-delete.js +1 -2
- package/lib/commands/firestore-databases-delete.js +1 -5
- package/lib/commands/firestore-delete.js +6 -6
- package/lib/commands/functions-artifacts-setpolicy.js +12 -2
- package/lib/commands/functions-config-export.js +5 -9
- package/lib/commands/functions-delete.js +5 -5
- package/lib/commands/functions-deletegcfartifacts.js +4 -4
- package/lib/commands/functions-secrets-destroy.js +8 -10
- package/lib/commands/functions-secrets-prune.js +12 -13
- package/lib/commands/functions-secrets-set.js +11 -15
- package/lib/commands/hosting-channel-create.js +1 -2
- package/lib/commands/hosting-channel-delete.js +4 -4
- package/lib/commands/hosting-channel-open.js +2 -3
- package/lib/commands/hosting-disable.js +5 -5
- package/lib/commands/hosting-sites-delete.js +4 -4
- package/lib/commands/init.js +41 -58
- package/lib/commands/login.js +1 -5
- package/lib/commands/logout.js +2 -3
- package/lib/commands/open.js +1 -2
- package/lib/commands/projects-create.js +1 -2
- package/lib/commands/remoteconfig-rollback.js +5 -5
- package/lib/commands/use.js +110 -110
- package/lib/config.js +1 -2
- package/lib/dataconnect/build.js +2 -4
- package/lib/dataconnect/client.js +20 -1
- package/lib/dataconnect/dataplaneClient.js +16 -1
- package/lib/dataconnect/schemaMigration.js +1 -6
- package/lib/dataconnect/types.js +5 -1
- package/lib/deploy/functions/params.js +10 -17
- package/lib/deploy/functions/prompts.js +6 -28
- package/lib/emulator/commandUtils.js +4 -13
- package/lib/emulator/controller.js +1 -2
- package/lib/emulator/downloadableEmulators.js +12 -12
- package/lib/emulator/initEmulators.js +9 -20
- package/lib/ensureApiEnabled.js +11 -1
- package/lib/extensions/askUserForEventsConfig.js +6 -15
- package/lib/extensions/askUserForParam.js +23 -52
- package/lib/extensions/checkProjectBilling.js +3 -9
- package/lib/extensions/diagnose.js +3 -6
- package/lib/extensions/extensionsHelper.js +17 -27
- package/lib/extensions/manifest.js +1 -2
- package/lib/extensions/tos.js +10 -2
- package/lib/extensions/utils.js +1 -10
- package/lib/frameworks/index.js +1 -2
- package/lib/frameworks/next/index.js +7 -4
- package/lib/frameworks/vite/index.js +1 -2
- package/lib/functions/secrets.js +14 -15
- package/lib/gcp/auth.js +29 -1
- package/lib/gcp/storage.js +19 -1
- package/lib/gif/fdcExperience.js +45 -0
- package/lib/hosting/interactive.js +2 -3
- package/lib/init/features/account.js +2 -4
- package/lib/init/features/database.js +11 -20
- package/lib/init/features/dataconnect/index.js +7 -14
- package/lib/init/features/dataconnect/sdk.js +15 -22
- package/lib/init/features/emulators.js +19 -41
- package/lib/init/features/firestore/index.js +2 -6
- package/lib/init/features/firestore/indexes.js +18 -31
- package/lib/init/features/firestore/rules.js +18 -31
- package/lib/init/features/functions/index.js +9 -16
- package/lib/init/features/functions/javascript.js +16 -30
- package/lib/init/features/functions/npm-dependencies.js +4 -8
- package/lib/init/features/functions/python.js +1 -3
- package/lib/init/features/functions/typescript.js +24 -43
- package/lib/init/features/genkit/index.js +23 -38
- package/lib/init/features/hosting/github.js +20 -51
- package/lib/init/features/hosting/index.js +36 -57
- package/lib/init/features/project.js +6 -16
- package/lib/init/features/remoteconfig.js +2 -8
- package/lib/init/features/storage.js +1 -3
- package/lib/management/apps.js +19 -44
- package/lib/management/projects.js +17 -28
- package/lib/mcp/index.js +13 -11
- package/lib/mcp/tools/auth/{disable_auth_user.js → disable_user.js} +3 -3
- package/lib/mcp/tools/auth/{get_auth_user.js → get_user.js} +4 -4
- package/lib/mcp/tools/auth/index.js +5 -4
- package/lib/mcp/tools/auth/{set_auth_claims.js → set_claims.js} +3 -3
- package/lib/mcp/tools/auth/set_sms_region_policy.js +36 -0
- package/lib/mcp/tools/core/consult_assistant.js +27 -0
- package/lib/mcp/tools/core/index.js +5 -3
- package/lib/mcp/tools/dataconnect/converter.js +50 -0
- package/lib/mcp/tools/dataconnect/execute_graphql.js +32 -0
- package/lib/mcp/tools/dataconnect/execute_graphql_read.js +32 -0
- package/lib/mcp/tools/dataconnect/execute_mutation.js +50 -0
- package/lib/mcp/tools/dataconnect/execute_query.js +50 -0
- package/lib/mcp/tools/dataconnect/generate_operation.js +33 -0
- package/lib/mcp/tools/dataconnect/generate_schema.js +25 -0
- package/lib/mcp/tools/dataconnect/get_connector.js +31 -0
- package/lib/mcp/tools/dataconnect/get_schema.js +31 -0
- package/lib/mcp/tools/dataconnect/index.js +20 -2
- package/lib/mcp/tools/dataconnect/{list_dataconnect_services.js → list_services.js} +4 -4
- package/lib/mcp/tools/{core/get_firebase_directory.js → directory/get_project_directory.js} +5 -5
- package/lib/mcp/tools/directory/index.js +6 -0
- package/lib/mcp/tools/{core/set_firebase_directory.js → directory/set_project_directory.js} +3 -3
- package/lib/mcp/tools/firestore/get_documents.js +2 -2
- package/lib/mcp/tools/firestore/{get_firestore_rules.js → get_rules.js} +6 -6
- package/lib/mcp/tools/firestore/index.js +2 -2
- package/lib/mcp/tools/index.js +26 -8
- package/lib/mcp/tools/storage/get_download_url.js +31 -0
- package/lib/mcp/tools/storage/get_rules.js +26 -0
- package/lib/mcp/tools/storage/index.js +6 -0
- package/lib/mcp/types.js +1 -1
- package/lib/prompt.js +78 -65
- package/lib/requireTosAcceptance.js +4 -0
- package/lib/rulesDeploy.js +10 -15
- package/lib/track.js +1 -34
- package/lib/utils.js +27 -5
- package/package.json +2 -3
- package/lib/mcp/tools/project/index.js +0 -7
- /package/lib/mcp/tools/{project → core}/get_project.js +0 -0
- /package/lib/mcp/tools/{project → core}/get_sdk_config.js +0 -0
- /package/lib/mcp/tools/{project → core}/list_apps.js +0 -0
package/lib/api.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
exports.setScopes = exports.getScopes = exports.vertexAIOrigin = exports.cloudSQLAdminOrigin = exports.dataConnectLocalConnString = exports.dataconnectP4SADomain = exports.dataconnectOrigin = exports.githubClientSecret = exports.githubClientId = exports.computeOrigin = exports.secretManagerOrigin = exports.githubApiOrigin = exports.githubOrigin = exports.serviceUsageOrigin = void 0;
|
|
3
|
+
exports.hostingApiOrigin = exports.firebaseStorageOrigin = exports.storageOrigin = exports.runtimeconfigOrigin = exports.rulesOrigin = exports.resourceManagerOrigin = exports.remoteConfigApiOrigin = exports.rtdbMetadataOrigin = exports.rtdbManagementOrigin = exports.realtimeOrigin = exports.extensionsTOSOrigin = exports.extensionsPublisherOrigin = exports.extensionsOrigin = exports.iamOrigin = exports.identityOrigin = exports.hostingOrigin = exports.googleOrigin = exports.pubsubOrigin = exports.cloudTasksOrigin = exports.cloudschedulerOrigin = exports.cloudCompanionOrigin = exports.cloudbuildOrigin = exports.functionsDefaultRegion = exports.runOrigin = exports.functionsV2Origin = exports.functionsOrigin = exports.firestoreOrigin = exports.firestoreOriginOrEmulator = exports.firedataOrigin = exports.firebaseExtensionsRegistryOrigin = exports.firebaseApiOrigin = exports.eventarcOrigin = exports.dynamicLinksKey = exports.dynamicLinksOrigin = exports.consoleOrigin = exports.authOrigin = exports.apphostingGitHubAppInstallationURL = exports.apphostingP4SADomain = exports.apphostingOrigin = exports.appDistributionOrigin = exports.artifactRegistryDomain = exports.developerConnectP4SADomain = exports.developerConnectOrigin = exports.containerRegistryDomain = exports.cloudMonitoringOrigin = exports.cloudloggingOrigin = exports.cloudbillingOrigin = exports.clientSecret = exports.clientId = exports.authProxyOrigin = void 0;
|
|
4
|
+
exports.setScopes = exports.getScopes = exports.vertexAIOrigin = exports.cloudSQLAdminOrigin = exports.dataConnectLocalConnString = exports.dataconnectP4SADomain = exports.dataconnectOrigin = exports.githubClientSecret = exports.githubClientId = exports.computeOrigin = exports.secretManagerOrigin = exports.githubApiOrigin = exports.githubOrigin = exports.serviceUsageOrigin = exports.cloudRunApiOrigin = void 0;
|
|
5
5
|
const constants_1 = require("./emulator/constants");
|
|
6
6
|
const logger_1 = require("./logger");
|
|
7
7
|
const scopes = require("./scopes");
|
|
@@ -70,6 +70,8 @@ const functionsDefaultRegion = () => utils.envOverride("FIREBASE_FUNCTIONS_DEFAU
|
|
|
70
70
|
exports.functionsDefaultRegion = functionsDefaultRegion;
|
|
71
71
|
const cloudbuildOrigin = () => utils.envOverride("FIREBASE_CLOUDBUILD_URL", "https://cloudbuild.googleapis.com");
|
|
72
72
|
exports.cloudbuildOrigin = cloudbuildOrigin;
|
|
73
|
+
const cloudCompanionOrigin = () => utils.envOverride("CLOUD_COMPANION_URL", "https://cloudaicompanion.googleapis.com");
|
|
74
|
+
exports.cloudCompanionOrigin = cloudCompanionOrigin;
|
|
73
75
|
const cloudschedulerOrigin = () => utils.envOverride("FIREBASE_CLOUDSCHEDULER_URL", "https://cloudscheduler.googleapis.com");
|
|
74
76
|
exports.cloudschedulerOrigin = cloudschedulerOrigin;
|
|
75
77
|
const cloudTasksOrigin = () => utils.envOverride("FIREBASE_CLOUD_TAKS_URL", "https://cloudtasks.googleapis.com");
|
|
@@ -62,21 +62,14 @@ async function doSetup(projectId, webAppName, serviceAccount) {
|
|
|
62
62
|
await ensureAppHostingComputeServiceAccount(projectId, serviceAccount);
|
|
63
63
|
const location = await promptLocation(projectId, "Select a primary region to host your backend:\n");
|
|
64
64
|
const gitRepositoryLink = await githubConnections.linkGitHubRepository(projectId, location);
|
|
65
|
-
const rootDir = await (0, prompt_1.
|
|
66
|
-
name: "rootDir",
|
|
67
|
-
type: "input",
|
|
65
|
+
const rootDir = await (0, prompt_1.input)({
|
|
68
66
|
default: "/",
|
|
69
67
|
message: "Specify your app's root directory relative to your repository",
|
|
70
68
|
});
|
|
71
69
|
const branch = await githubConnections.promptGitHubBranch(gitRepositoryLink);
|
|
72
70
|
(0, utils_1.logSuccess)(`Repo linked successfully!\n`);
|
|
73
71
|
(0, utils_1.logBullet)(`${clc.yellow("===")} Set up your backend`);
|
|
74
|
-
const backendId = await promptNewBackendId(projectId, location
|
|
75
|
-
name: "backendId",
|
|
76
|
-
type: "input",
|
|
77
|
-
default: "my-web-app",
|
|
78
|
-
message: "Provide a name for your backend [1-30 characters]",
|
|
79
|
-
});
|
|
72
|
+
const backendId = await promptNewBackendId(projectId, location);
|
|
80
73
|
(0, utils_1.logSuccess)(`Name set to ${backendId}\n`);
|
|
81
74
|
const webApp = await app_1.webApps.getOrCreateWebApp(projectId, webAppName, backendId);
|
|
82
75
|
if (!webApp) {
|
|
@@ -86,9 +79,7 @@ async function doSetup(projectId, webAppName, serviceAccount) {
|
|
|
86
79
|
const backend = await createBackend(projectId, location, backendId, gitRepositoryLink, serviceAccount, webApp === null || webApp === void 0 ? void 0 : webApp.id, rootDir);
|
|
87
80
|
createBackendSpinner.succeed(`Successfully created backend!\n\t${backend.name}\n`);
|
|
88
81
|
await setDefaultTrafficPolicy(projectId, location, backendId, branch);
|
|
89
|
-
const confirmRollout = await (0, prompt_1.
|
|
90
|
-
type: "confirm",
|
|
91
|
-
name: "rollout",
|
|
82
|
+
const confirmRollout = await (0, prompt_1.confirm)({
|
|
92
83
|
default: true,
|
|
93
84
|
message: "Do you want to deploy now?",
|
|
94
85
|
});
|
|
@@ -158,9 +149,13 @@ async function ensureAppHostingComputeServiceAccount(projectId, serviceAccount)
|
|
|
158
149
|
}
|
|
159
150
|
}
|
|
160
151
|
exports.ensureAppHostingComputeServiceAccount = ensureAppHostingComputeServiceAccount;
|
|
161
|
-
async function promptNewBackendId(projectId, location
|
|
152
|
+
async function promptNewBackendId(projectId, location) {
|
|
162
153
|
while (true) {
|
|
163
|
-
const backendId = await (0, prompt_1.
|
|
154
|
+
const backendId = await (0, prompt_1.input)({
|
|
155
|
+
default: "my-web-app",
|
|
156
|
+
message: "Provide a name for your backend [1-30 characters]",
|
|
157
|
+
validate: (s) => s.length >= 1 && s.length <= 30,
|
|
158
|
+
});
|
|
164
159
|
try {
|
|
165
160
|
await apphosting.getBackend(projectId, location, backendId);
|
|
166
161
|
}
|
|
@@ -230,9 +225,7 @@ async function promptLocation(projectId, prompt = "Please select a location:") {
|
|
|
230
225
|
if (allowedLocations.length === 1) {
|
|
231
226
|
return allowedLocations[0];
|
|
232
227
|
}
|
|
233
|
-
const location = (await (0, prompt_1.
|
|
234
|
-
name: "location",
|
|
235
|
-
type: "list",
|
|
228
|
+
const location = (await (0, prompt_1.select)({
|
|
236
229
|
default: constants_1.DEFAULT_LOCATION,
|
|
237
230
|
message: prompt,
|
|
238
231
|
choices: allowedLocations,
|
|
@@ -273,9 +266,7 @@ async function chooseBackends(projectId, backendId, chooseBackendPrompt, force)
|
|
|
273
266
|
const { location, id } = apphosting.parseBackendName(backend.name);
|
|
274
267
|
backendsByDisplay.set(`${id}(${location})`, backend);
|
|
275
268
|
});
|
|
276
|
-
const chosenBackendDisplays = await (0, prompt_1.
|
|
277
|
-
name: "backend",
|
|
278
|
-
type: "checkbox",
|
|
269
|
+
const chosenBackendDisplays = await (0, prompt_1.checkbox)({
|
|
279
270
|
message: chooseBackendPrompt,
|
|
280
271
|
choices: Array.from(backendsByDisplay.keys(), (name) => {
|
|
281
272
|
return {
|
|
@@ -313,9 +304,7 @@ async function getBackendForAmbiguousLocation(projectId, backendId, locationDisa
|
|
|
313
304
|
}
|
|
314
305
|
const backendsByLocation = new Map();
|
|
315
306
|
backends.forEach((backend) => backendsByLocation.set(apphosting.parseBackendName(backend.name).location, backend));
|
|
316
|
-
const location = await (0, prompt_1.
|
|
317
|
-
name: "location",
|
|
318
|
-
type: "list",
|
|
307
|
+
const location = await (0, prompt_1.select)({
|
|
319
308
|
message: locationDisambugationPrompt,
|
|
320
309
|
choices: [...backendsByLocation.keys()],
|
|
321
310
|
});
|
package/lib/apphosting/config.js
CHANGED
|
@@ -113,7 +113,7 @@ async function maybeAddSecretToYaml(secretName, fileName = exports.APPHOSTING_BA
|
|
|
113
113
|
return;
|
|
114
114
|
}
|
|
115
115
|
if (!path) {
|
|
116
|
-
path = await prompt.
|
|
116
|
+
path = await prompt.input({
|
|
117
117
|
message: `It looks like you don't have an ${fileName} yet. Where would you like to store it?`,
|
|
118
118
|
default: process.cwd(),
|
|
119
119
|
});
|
|
@@ -127,8 +127,8 @@ async function maybeAddSecretToYaml(secretName, fileName = exports.APPHOSTING_BA
|
|
|
127
127
|
dynamicDispatch.store(path, projectYaml);
|
|
128
128
|
}
|
|
129
129
|
exports.maybeAddSecretToYaml = maybeAddSecretToYaml;
|
|
130
|
-
async function maybeGenerateEmulatorYaml(projectId,
|
|
131
|
-
const basePath = dynamicDispatch.discoverBackendRoot(
|
|
130
|
+
async function maybeGenerateEmulatorYaml(projectId, backendRoot) {
|
|
131
|
+
const basePath = dynamicDispatch.discoverBackendRoot(backendRoot) || backendRoot;
|
|
132
132
|
if (fs.fileExistsSync((0, path_1.join)(basePath, exports.APPHOSTING_EMULATORS_YAML_FILE))) {
|
|
133
133
|
logger_1.logger.debug("apphosting.emulator.yaml already exists, skipping generation and secrets access prompt");
|
|
134
134
|
return null;
|
|
@@ -174,12 +174,9 @@ async function overrideChosenEnv(projectId, env) {
|
|
|
174
174
|
if (!names.length) {
|
|
175
175
|
return {};
|
|
176
176
|
}
|
|
177
|
-
const toOverwrite = await prompt.
|
|
178
|
-
type: "checkbox",
|
|
177
|
+
const toOverwrite = await prompt.checkbox({
|
|
179
178
|
message: "Which environment variables would you like to override?",
|
|
180
|
-
choices: names
|
|
181
|
-
return { name };
|
|
182
|
-
}),
|
|
179
|
+
choices: names,
|
|
183
180
|
});
|
|
184
181
|
if (!projectId && toOverwrite.some((name) => "secret" in env[name])) {
|
|
185
182
|
throw new error_1.FirebaseError(`Need a project ID to overwrite a secret. Either use ${clc.bold("firebase use")} or pass the ${clc.bold("--project")} flag`);
|
|
@@ -187,24 +184,19 @@ async function overrideChosenEnv(projectId, env) {
|
|
|
187
184
|
const newEnv = {};
|
|
188
185
|
for (const name of toOverwrite) {
|
|
189
186
|
if ("value" in env[name]) {
|
|
190
|
-
const newValue = await prompt.
|
|
191
|
-
type: "input",
|
|
192
|
-
message: `What new value would you like for plaintext ${name}?`,
|
|
193
|
-
});
|
|
187
|
+
const newValue = await prompt.input(`What new value would you like for plaintext ${name}?`);
|
|
194
188
|
newEnv[name] = { variable: name, value: newValue };
|
|
195
189
|
continue;
|
|
196
190
|
}
|
|
197
191
|
let secretRef;
|
|
198
192
|
let action = "pick-new";
|
|
199
193
|
while (action === "pick-new") {
|
|
200
|
-
secretRef = await prompt.
|
|
201
|
-
type: "input",
|
|
194
|
+
secretRef = await prompt.input({
|
|
202
195
|
message: `What would you like to name the secret reference for ${name}?`,
|
|
203
196
|
default: suggestedTestKeyName(name),
|
|
204
197
|
});
|
|
205
198
|
if (await csm.secretExists(projectId, secretRef)) {
|
|
206
|
-
action = await prompt.
|
|
207
|
-
type: "list",
|
|
199
|
+
action = await prompt.select({
|
|
208
200
|
message: "This secret reference already exists, would you like to reuse it or create a new one?",
|
|
209
201
|
choices: [
|
|
210
202
|
{ name: "Reuse it", value: "reuse" },
|
|
@@ -220,10 +212,7 @@ async function overrideChosenEnv(projectId, env) {
|
|
|
220
212
|
if (action === "reuse") {
|
|
221
213
|
continue;
|
|
222
214
|
}
|
|
223
|
-
const secretValue = await prompt.
|
|
224
|
-
type: "password",
|
|
225
|
-
message: `What new value would you like for secret ${name} [input is hidden]?`,
|
|
226
|
-
});
|
|
215
|
+
const secretValue = await prompt.password(`What new value would you like for secret ${name} [input is hidden]?`);
|
|
227
216
|
await csm.createSecret(projectId, secretRef, { [csm.FIREBASE_MANAGED]: "apphosting" });
|
|
228
217
|
await csm.addVersion(projectId, secretRef, secretValue);
|
|
229
218
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getGitHubCommit = exports.getGitHubBranch = exports.fetchRepositoryCloneUris = exports.listAppHostingConnections = exports.getOrCreateRepository = exports.getOrCreateConnection = exports.createConnection = exports.ensureSecretManagerAdminGrant = exports.promptGitHubBranch = exports.getOrCreateOauthConnection = exports.listValidInstallations = exports.promptGitHubInstallation = exports.getConnectionForInstallation = exports.linkGitHubRepository = exports.
|
|
3
|
+
exports.getGitHubCommit = exports.getGitHubBranch = exports.fetchRepositoryCloneUris = exports.listAppHostingConnections = exports.getOrCreateRepository = exports.getOrCreateConnection = exports.createConnection = exports.ensureSecretManagerAdminGrant = exports.promptGitHubBranch = exports.getOrCreateOauthConnection = exports.listValidInstallations = exports.promptGitHubInstallation = exports.getConnectionForInstallation = exports.linkGitHubRepository = exports.getOrCreateFullyInstalledGithubConnection = exports.generateConnectionId = exports.generateRepositoryId = exports.extractRepoSlugFromUri = exports.parseConnectionName = void 0;
|
|
4
4
|
const clc = require("colorette");
|
|
5
5
|
const devConnect = require("../gcp/devConnect");
|
|
6
6
|
const rm = require("../gcp/resourceManager");
|
|
@@ -11,11 +11,9 @@ const prompt_1 = require("../prompt");
|
|
|
11
11
|
const getProjectNumber_1 = require("../getProjectNumber");
|
|
12
12
|
const api_1 = require("../api");
|
|
13
13
|
const fuzzy = require("fuzzy");
|
|
14
|
-
const inquirer = require("inquirer");
|
|
15
14
|
const apiv2_1 = require("../apiv2");
|
|
16
15
|
const githubApiClient = new apiv2_1.Client({ urlPrefix: (0, api_1.githubApiOrigin)(), auth: false });
|
|
17
16
|
const APPHOSTING_CONN_PATTERN = /.+\/apphosting-github-conn-.+$/;
|
|
18
|
-
const APPHOSTING_OAUTH_CONN_NAME = "firebase-app-hosting-github-oauth";
|
|
19
17
|
const CONNECTION_NAME_REGEX = /^projects\/(?<projectId>[^\/]+)\/locations\/(?<location>[^\/]+)\/connections\/(?<id>[^\/]+)$/;
|
|
20
18
|
function parseConnectionName(name) {
|
|
21
19
|
const match = CONNECTION_NAME_REGEX.exec(name);
|
|
@@ -49,13 +47,14 @@ function generateRepositoryId(remoteUri) {
|
|
|
49
47
|
return (_a = extractRepoSlugFromUri(remoteUri)) === null || _a === void 0 ? void 0 : _a.replaceAll("/", "-");
|
|
50
48
|
}
|
|
51
49
|
exports.generateRepositoryId = generateRepositoryId;
|
|
52
|
-
|
|
50
|
+
const generateConnectionId = () => {
|
|
53
51
|
const randomHash = Math.random().toString(36).slice(6);
|
|
54
52
|
return `apphosting-github-conn-${randomHash}`;
|
|
55
|
-
}
|
|
53
|
+
};
|
|
54
|
+
exports.generateConnectionId = generateConnectionId;
|
|
56
55
|
const ADD_ACCOUNT_CHOICE = "@ADD_ACCOUNT";
|
|
57
56
|
const MANAGE_INSTALLATION_CHOICE = "@MANAGE_INSTALLATION";
|
|
58
|
-
async function
|
|
57
|
+
async function getOrCreateFullyInstalledGithubConnection(projectId, location, createConnectionId) {
|
|
59
58
|
utils.logBullet(clc.bold(`${clc.yellow("===")} Import a GitHub repository`));
|
|
60
59
|
if (createConnectionId) {
|
|
61
60
|
try {
|
|
@@ -76,10 +75,7 @@ async function getOrCreateGithubConnectionWithSentinel(projectId, location, crea
|
|
|
76
75
|
const apphostingGitHubInstallationURL = (0, api_1.apphostingGitHubAppInstallationURL)();
|
|
77
76
|
utils.logBullet(apphostingGitHubInstallationURL);
|
|
78
77
|
await utils.openInBrowser(apphostingGitHubInstallationURL);
|
|
79
|
-
await (0, prompt_1.
|
|
80
|
-
type: "input",
|
|
81
|
-
message: "Press Enter once you have installed or configured the Firebase App Hosting GitHub app to access your GitHub repo.",
|
|
82
|
-
});
|
|
78
|
+
await (0, prompt_1.input)("Press Enter once you have installed or configured the Firebase App Hosting GitHub app to access your GitHub repo.");
|
|
83
79
|
installationId = await promptGitHubInstallation(projectId, location, oauthConn);
|
|
84
80
|
}
|
|
85
81
|
const connectionMatchingInstallation = await getConnectionForInstallation(projectId, location, installationId);
|
|
@@ -91,15 +87,15 @@ async function getOrCreateGithubConnectionWithSentinel(projectId, location, crea
|
|
|
91
87
|
}
|
|
92
88
|
}
|
|
93
89
|
if (!createConnectionId) {
|
|
94
|
-
createConnectionId = generateConnectionId();
|
|
90
|
+
createConnectionId = (0, exports.generateConnectionId)();
|
|
95
91
|
}
|
|
96
92
|
const connection = await createFullyInstalledConnection(projectId, location, createConnectionId, oauthConn, installationId);
|
|
97
93
|
return connection;
|
|
98
94
|
}
|
|
99
|
-
exports.
|
|
95
|
+
exports.getOrCreateFullyInstalledGithubConnection = getOrCreateFullyInstalledGithubConnection;
|
|
100
96
|
async function linkGitHubRepository(projectId, location, createConnectionId) {
|
|
101
97
|
var _a, _b;
|
|
102
|
-
const connection = await
|
|
98
|
+
const connection = await getOrCreateFullyInstalledGithubConnection(projectId, location, createConnectionId);
|
|
103
99
|
let repoCloneUri;
|
|
104
100
|
do {
|
|
105
101
|
if (repoCloneUri === MANAGE_INSTALLATION_CHOICE) {
|
|
@@ -127,10 +123,7 @@ async function createFullyInstalledConnection(projectId, location, connectionId,
|
|
|
127
123
|
const targetUri = conn.installationState.actionUri;
|
|
128
124
|
utils.logBullet(targetUri);
|
|
129
125
|
await utils.openInBrowser(targetUri);
|
|
130
|
-
await (0, prompt_1.
|
|
131
|
-
type: "input",
|
|
132
|
-
message: "Press Enter once you have installed or configured the Firebase App Hosting GitHub app to access your GitHub repo.",
|
|
133
|
-
});
|
|
126
|
+
await (0, prompt_1.input)("Press Enter once you have installed or configured the Firebase App Hosting GitHub app to access your GitHub repo.");
|
|
134
127
|
conn = await devConnect.getConnection(projectId, location, connectionId);
|
|
135
128
|
}
|
|
136
129
|
return conn;
|
|
@@ -144,10 +137,7 @@ async function manageInstallation(connection) {
|
|
|
144
137
|
}
|
|
145
138
|
utils.logBullet(targetUri);
|
|
146
139
|
await utils.openInBrowser(targetUri);
|
|
147
|
-
await (0, prompt_1.
|
|
148
|
-
type: "input",
|
|
149
|
-
message: "Press Enter once you have installed or configured the Firebase App Hosting GitHub app to access your GitHub repo.",
|
|
150
|
-
});
|
|
140
|
+
await (0, prompt_1.input)("Press Enter once you have installed or configured the Firebase App Hosting GitHub app to access your GitHub repo.");
|
|
151
141
|
}
|
|
152
142
|
async function getConnectionForInstallation(projectId, location, installationId) {
|
|
153
143
|
const connections = await listAppHostingConnections(projectId, location);
|
|
@@ -164,30 +154,26 @@ async function getConnectionForInstallation(projectId, location, installationId)
|
|
|
164
154
|
exports.getConnectionForInstallation = getConnectionForInstallation;
|
|
165
155
|
async function promptGitHubInstallation(projectId, location, connection) {
|
|
166
156
|
const installations = await listValidInstallations(projectId, location, connection);
|
|
167
|
-
const installationName = await (0, prompt_1.
|
|
168
|
-
type: "autocomplete",
|
|
169
|
-
name: "installation",
|
|
157
|
+
const installationName = await (0, prompt_1.search)({
|
|
170
158
|
message: "Which GitHub account do you want to use?",
|
|
171
|
-
source: (
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
]));
|
|
190
|
-
},
|
|
159
|
+
source: (input = "") => [
|
|
160
|
+
new prompt_1.Separator(),
|
|
161
|
+
{
|
|
162
|
+
name: "Missing an account? Select this option to add a GitHub account",
|
|
163
|
+
value: ADD_ACCOUNT_CHOICE,
|
|
164
|
+
},
|
|
165
|
+
new prompt_1.Separator(),
|
|
166
|
+
...fuzzy
|
|
167
|
+
.filter(input, installations, {
|
|
168
|
+
extract: (installation) => installation.name || "",
|
|
169
|
+
})
|
|
170
|
+
.map((result) => {
|
|
171
|
+
return {
|
|
172
|
+
name: result.original.name || "",
|
|
173
|
+
value: result.original.id,
|
|
174
|
+
};
|
|
175
|
+
}),
|
|
176
|
+
],
|
|
191
177
|
});
|
|
192
178
|
return installationName;
|
|
193
179
|
}
|
|
@@ -206,26 +192,17 @@ async function listValidInstallations(projectId, location, connection) {
|
|
|
206
192
|
exports.listValidInstallations = listValidInstallations;
|
|
207
193
|
async function getOrCreateOauthConnection(projectId, location) {
|
|
208
194
|
let conn;
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
catch (err) {
|
|
213
|
-
if (err.status === 404) {
|
|
214
|
-
await ensureSecretManagerAdminGrant(projectId);
|
|
215
|
-
conn = await createConnection(projectId, location, APPHOSTING_OAUTH_CONN_NAME);
|
|
216
|
-
}
|
|
217
|
-
else {
|
|
218
|
-
throw err;
|
|
219
|
-
}
|
|
195
|
+
const completedConnections = await listAppHostingConnections(projectId, location);
|
|
196
|
+
if (completedConnections.length > 0) {
|
|
197
|
+
return completedConnections[0];
|
|
220
198
|
}
|
|
199
|
+
await ensureSecretManagerAdminGrant(projectId);
|
|
200
|
+
conn = await createConnection(projectId, location, (0, exports.generateConnectionId)());
|
|
221
201
|
while (conn.installationState.stage === "PENDING_USER_OAUTH") {
|
|
222
202
|
utils.logBullet("Please authorize the Firebase GitHub app by visiting this url:");
|
|
223
203
|
const { url, cleanup } = await utils.openInBrowserPopup(conn.installationState.actionUri, "Authorize the GitHub app");
|
|
224
204
|
utils.logBullet(`\t${url}`);
|
|
225
|
-
await (0, prompt_1.
|
|
226
|
-
type: "input",
|
|
227
|
-
message: "Press Enter once you have authorized the GitHub App.",
|
|
228
|
-
});
|
|
205
|
+
await (0, prompt_1.input)("Press Enter once you have authorized the GitHub App.");
|
|
229
206
|
cleanup();
|
|
230
207
|
const { projectId, location, id } = parseConnectionName(conn.name);
|
|
231
208
|
conn = await devConnect.getConnection(projectId, location, id);
|
|
@@ -236,49 +213,41 @@ async function getOrCreateOauthConnection(projectId, location) {
|
|
|
236
213
|
exports.getOrCreateOauthConnection = getOrCreateOauthConnection;
|
|
237
214
|
async function promptCloneUri(projectId, connection) {
|
|
238
215
|
const cloneUris = await fetchRepositoryCloneUris(projectId, connection);
|
|
239
|
-
const cloneUri = await (0, prompt_1.
|
|
240
|
-
type: "autocomplete",
|
|
241
|
-
name: "cloneUri",
|
|
216
|
+
const cloneUri = await (0, prompt_1.search)({
|
|
242
217
|
message: "Which GitHub repo do you want to deploy?",
|
|
243
|
-
source: (
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
]));
|
|
262
|
-
},
|
|
218
|
+
source: (input = "") => [
|
|
219
|
+
new prompt_1.Separator(),
|
|
220
|
+
{
|
|
221
|
+
name: "Missing a repo? Select this option to configure your GitHub connection settings",
|
|
222
|
+
value: MANAGE_INSTALLATION_CHOICE,
|
|
223
|
+
},
|
|
224
|
+
new prompt_1.Separator(),
|
|
225
|
+
...fuzzy
|
|
226
|
+
.filter(input, cloneUris, {
|
|
227
|
+
extract: (uri) => extractRepoSlugFromUri(uri) || "",
|
|
228
|
+
})
|
|
229
|
+
.map((result) => {
|
|
230
|
+
return {
|
|
231
|
+
name: extractRepoSlugFromUri(result.original) || "",
|
|
232
|
+
value: result.original,
|
|
233
|
+
};
|
|
234
|
+
}),
|
|
235
|
+
],
|
|
263
236
|
});
|
|
264
237
|
return cloneUri;
|
|
265
238
|
}
|
|
266
239
|
async function promptGitHubBranch(repoLink) {
|
|
267
240
|
const branches = await devConnect.listAllBranches(repoLink.name);
|
|
268
|
-
const branch = await (0, prompt_1.
|
|
269
|
-
type: "autocomplete",
|
|
270
|
-
name: "branch",
|
|
241
|
+
const branch = await (0, prompt_1.search)({
|
|
271
242
|
message: "Pick a branch for continuous deployment",
|
|
272
|
-
source: (
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
]));
|
|
281
|
-
},
|
|
243
|
+
source: (input = "") => [
|
|
244
|
+
...fuzzy.filter(input, Array.from(branches)).map((result) => {
|
|
245
|
+
return {
|
|
246
|
+
name: result.original,
|
|
247
|
+
value: result.original,
|
|
248
|
+
};
|
|
249
|
+
}),
|
|
250
|
+
],
|
|
282
251
|
});
|
|
283
252
|
return branch;
|
|
284
253
|
}
|
|
@@ -292,10 +261,7 @@ async function ensureSecretManagerAdminGrant(projectId) {
|
|
|
292
261
|
return;
|
|
293
262
|
}
|
|
294
263
|
utils.logBullet("To create a new GitHub connection, Secret Manager Admin role (roles/secretmanager.admin) is required on the Developer Connect Service Agent.");
|
|
295
|
-
const grant = await (0, prompt_1.
|
|
296
|
-
type: "confirm",
|
|
297
|
-
message: "Grant the required role to the Developer Connect Service Agent?",
|
|
298
|
-
});
|
|
264
|
+
const grant = await (0, prompt_1.confirm)("Grant the required role to the Developer Connect Service Agent?");
|
|
299
265
|
if (!grant) {
|
|
300
266
|
utils.logBullet("You, or your project administrator, should run the following command to grant the required role:\n\n" +
|
|
301
267
|
"You, or your project adminstrator, can run the following command to grant the required role manually:\n\n" +
|
package/lib/apphosting/repo.js
CHANGED
|
@@ -11,7 +11,6 @@ const error_1 = require("../error");
|
|
|
11
11
|
const prompt_1 = require("../prompt");
|
|
12
12
|
const getProjectNumber_1 = require("../getProjectNumber");
|
|
13
13
|
const fuzzy = require("fuzzy");
|
|
14
|
-
const inquirer = require("inquirer");
|
|
15
14
|
const APPHOSTING_CONN_PATTERN = /.+\/apphosting-github-conn-.+$/;
|
|
16
15
|
const APPHOSTING_OAUTH_CONN_NAME = "apphosting-github-oauth";
|
|
17
16
|
const CONNECTION_NAME_REGEX = /^projects\/(?<projectId>[^\/]+)\/locations\/(?<location>[^\/]+)\/connections\/(?<id>[^\/]+)$/;
|
|
@@ -89,10 +88,7 @@ async function createFullyInstalledConnection(projectId, location, connectionId,
|
|
|
89
88
|
const targetUri = conn.installationState.actionUri;
|
|
90
89
|
utils.logBullet(targetUri);
|
|
91
90
|
await utils.openInBrowser(targetUri);
|
|
92
|
-
await (0, prompt_1.
|
|
93
|
-
type: "input",
|
|
94
|
-
message: "Press Enter once you have installed or configured the Cloud Build GitHub app to access your GitHub repo.",
|
|
95
|
-
});
|
|
91
|
+
await (0, prompt_1.input)("Press Enter once you have installed or configured the Cloud Build GitHub app to access your GitHub repo.");
|
|
96
92
|
conn = await gcb.getConnection(projectId, location, connectionId);
|
|
97
93
|
}
|
|
98
94
|
return conn;
|
|
@@ -116,10 +112,7 @@ async function getOrCreateOauthConnection(projectId, location) {
|
|
|
116
112
|
utils.logBullet("Sign in to GitHub and authorize Cloud Build GitHub app:");
|
|
117
113
|
const { url, cleanup } = await utils.openInBrowserPopup(conn.installationState.actionUri, "Authorize the GitHub app");
|
|
118
114
|
utils.logBullet(`\t${url}`);
|
|
119
|
-
await (0, prompt_1.
|
|
120
|
-
type: "input",
|
|
121
|
-
message: "Press Enter once you have authorized the app",
|
|
122
|
-
});
|
|
115
|
+
await (0, prompt_1.input)("Press Enter once you have authorized the app");
|
|
123
116
|
cleanup();
|
|
124
117
|
const { projectId, location, id } = parseConnectionName(conn.name);
|
|
125
118
|
conn = await gcb.getConnection(projectId, location, id);
|
|
@@ -129,30 +122,26 @@ async function getOrCreateOauthConnection(projectId, location) {
|
|
|
129
122
|
exports.getOrCreateOauthConnection = getOrCreateOauthConnection;
|
|
130
123
|
async function promptRepositoryUri(projectId, connections) {
|
|
131
124
|
const { repos, remoteUriToConnection } = await fetchAllRepositories(projectId, connections);
|
|
132
|
-
const remoteUri = await (0, prompt_1.
|
|
133
|
-
type: "autocomplete",
|
|
134
|
-
name: "remoteUri",
|
|
125
|
+
const remoteUri = await (0, prompt_1.search)({
|
|
135
126
|
message: "Which GitHub repo do you want to deploy?",
|
|
136
|
-
source: (
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
]));
|
|
155
|
-
},
|
|
127
|
+
source: (input) => [
|
|
128
|
+
new prompt_1.Separator(),
|
|
129
|
+
{
|
|
130
|
+
name: "Missing a repo? Select this option to configure your GitHub connection settings",
|
|
131
|
+
value: ADD_CONN_CHOICE,
|
|
132
|
+
},
|
|
133
|
+
new prompt_1.Separator(),
|
|
134
|
+
...fuzzy
|
|
135
|
+
.filter(input !== null && input !== void 0 ? input : "", repos, {
|
|
136
|
+
extract: (repo) => extractRepoSlugFromUri(repo.remoteUri) || "",
|
|
137
|
+
})
|
|
138
|
+
.map((result) => {
|
|
139
|
+
return {
|
|
140
|
+
name: extractRepoSlugFromUri(result.original.remoteUri) || "",
|
|
141
|
+
value: result.original.remoteUri,
|
|
142
|
+
};
|
|
143
|
+
}),
|
|
144
|
+
],
|
|
156
145
|
});
|
|
157
146
|
return { remoteUri, connection: remoteUriToConnection[remoteUri] };
|
|
158
147
|
}
|
|
@@ -164,10 +153,7 @@ async function ensureSecretManagerAdminGrant(projectId) {
|
|
|
164
153
|
return;
|
|
165
154
|
}
|
|
166
155
|
utils.logBullet("To create a new GitHub connection, Secret Manager Admin role (roles/secretmanager.admin) is required on the Cloud Build Service Agent.");
|
|
167
|
-
const grant = await (0, prompt_1.
|
|
168
|
-
type: "confirm",
|
|
169
|
-
message: "Grant the required role to the Cloud Build Service Agent?",
|
|
170
|
-
});
|
|
156
|
+
const grant = await (0, prompt_1.confirm)("Grant the required role to the Cloud Build Service Agent?");
|
|
171
157
|
if (!grant) {
|
|
172
158
|
utils.logBullet("You, or your project administrator, should run the following command to grant the required role:\n\n" +
|
|
173
159
|
"You, or your project adminstrator, can run the following command to grant the required role manually:\n\n" +
|
|
@@ -125,8 +125,7 @@ async function selectBackendServiceAccounts(projectNumber, projectId, options) {
|
|
|
125
125
|
accum.add(row.runServiceAccount);
|
|
126
126
|
return accum;
|
|
127
127
|
}, new Set());
|
|
128
|
-
const chosen = await prompt.
|
|
129
|
-
type: "checkbox",
|
|
128
|
+
const chosen = await prompt.checkbox({
|
|
130
129
|
message: "Which service accounts would you like to grant access? " +
|
|
131
130
|
"Press Space to select accounts, then Enter to confirm your choices.",
|
|
132
131
|
choices: [...allAccounts.values()].sort(),
|
|
@@ -157,7 +156,7 @@ async function envVarForSecret(secret, trimTestPrefix = false) {
|
|
|
157
156
|
}
|
|
158
157
|
}
|
|
159
158
|
do {
|
|
160
|
-
const test = await prompt.
|
|
159
|
+
const test = await prompt.input({
|
|
161
160
|
message: "What environment variable name would you like to use?",
|
|
162
161
|
default: upper,
|
|
163
162
|
});
|
package/lib/apphosting/utils.js
CHANGED
|
@@ -30,9 +30,7 @@ async function promptForAppHostingYaml(apphostingFileNameToPathMap, promptMessag
|
|
|
30
30
|
value: apphostingFileNameToPathMap.get(fileName),
|
|
31
31
|
};
|
|
32
32
|
});
|
|
33
|
-
const fileToExportPath = await prompt.
|
|
34
|
-
name: "apphosting-yaml",
|
|
35
|
-
type: "list",
|
|
33
|
+
const fileToExportPath = await prompt.select({
|
|
36
34
|
message: promptMessage,
|
|
37
35
|
choices: listOptions,
|
|
38
36
|
});
|
package/lib/auth.js
CHANGED
|
@@ -299,10 +299,7 @@ async function loginRemotely() {
|
|
|
299
299
|
logger_1.logger.info();
|
|
300
300
|
logger_1.logger.info("3. Paste or enter the authorization code below once you have it:");
|
|
301
301
|
logger_1.logger.info();
|
|
302
|
-
const code = await (0, prompt_1.
|
|
303
|
-
type: "input",
|
|
304
|
-
message: "Enter authorization code:",
|
|
305
|
-
});
|
|
302
|
+
const code = await (0, prompt_1.input)({ message: "Enter authorization code:" });
|
|
306
303
|
try {
|
|
307
304
|
const tokens = await getTokensFromAuthorizationCode(code, `${(0, api_1.authProxyOrigin)()}/complete`, codeVerifier);
|
|
308
305
|
void (0, track_1.trackGA4)("login", { method: "google_remote" });
|
|
@@ -21,12 +21,12 @@ exports.command = new command_1.Command("apphosting:backends:delete <backend>")
|
|
|
21
21
|
const backends = await (0, backend_1.chooseBackends)(projectId, backendId, "Please select the backends you'd like to delete:", options.force);
|
|
22
22
|
utils.logWarning("You are about to permanently delete these backend(s):");
|
|
23
23
|
(0, apphosting_backends_list_1.printBackendsTable)(backends);
|
|
24
|
-
const confirmDeletion = await (0, prompt_1.
|
|
25
|
-
type: "confirm",
|
|
26
|
-
name: "force",
|
|
27
|
-
default: false,
|
|
24
|
+
const confirmDeletion = await (0, prompt_1.confirm)({
|
|
28
25
|
message: "Are you sure?",
|
|
29
|
-
|
|
26
|
+
default: false,
|
|
27
|
+
force: options.force,
|
|
28
|
+
nonInteractive: options.nonInteractive,
|
|
29
|
+
});
|
|
30
30
|
if (!confirmDeletion) {
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
@@ -46,9 +46,7 @@ exports.command = new command_1.Command("apphosting:secrets:set <secretName>")
|
|
|
46
46
|
if (!created) {
|
|
47
47
|
return;
|
|
48
48
|
}
|
|
49
|
-
const type = await prompt.
|
|
50
|
-
type: "list",
|
|
51
|
-
name: "type",
|
|
49
|
+
const type = await prompt.select({
|
|
52
50
|
message: "Is this secret for production or only local testing?",
|
|
53
51
|
choices: [
|
|
54
52
|
{ name: "Production", value: "production" },
|
|
@@ -56,9 +54,7 @@ exports.command = new command_1.Command("apphosting:secrets:set <secretName>")
|
|
|
56
54
|
],
|
|
57
55
|
});
|
|
58
56
|
if (type === "local") {
|
|
59
|
-
const emailList = await prompt.
|
|
60
|
-
type: "input",
|
|
61
|
-
name: "emails",
|
|
57
|
+
const emailList = await prompt.input({
|
|
62
58
|
message: "Please enter a comma separated list of user or groups who should have access to this secret:",
|
|
63
59
|
});
|
|
64
60
|
if (emailList.length) {
|