firebase-tools 13.0.0 → 13.0.2

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.
Files changed (37) hide show
  1. package/lib/api.js +2 -2
  2. package/lib/commands/{frameworks-backends-create.js → apphosting-backends-create.js} +6 -3
  3. package/lib/commands/{frameworks-backends-delete.js → apphosting-backends-delete.js} +9 -7
  4. package/lib/commands/{frameworks-backends-get.js → apphosting-backends-get.js} +16 -27
  5. package/lib/commands/{frameworks-backends-list.js → apphosting-backends-list.js} +9 -19
  6. package/lib/commands/apphosting-builds-create.js +31 -0
  7. package/lib/commands/apphosting-builds-get.js +18 -0
  8. package/lib/commands/apphosting-rollouts-create.js +26 -0
  9. package/lib/commands/apphosting-rollouts-list.js +18 -0
  10. package/lib/commands/index.js +12 -6
  11. package/lib/deploy/functions/services/firestore.js +11 -1
  12. package/lib/frameworks/angular/index.js +5 -3
  13. package/lib/frameworks/angular/utils.js +19 -2
  14. package/lib/frameworks/astro/index.js +5 -2
  15. package/lib/frameworks/astro/utils.js +3 -2
  16. package/lib/frameworks/constants.js +31 -7
  17. package/lib/frameworks/index.js +12 -7
  18. package/lib/frameworks/next/index.js +24 -8
  19. package/lib/frameworks/next/utils.js +1 -1
  20. package/lib/frameworks/nuxt/index.js +15 -5
  21. package/lib/frameworks/nuxt2/index.js +5 -4
  22. package/lib/frameworks/sveltekit/index.js +2 -1
  23. package/lib/frameworks/utils.js +13 -9
  24. package/lib/frameworks/vite/index.js +19 -5
  25. package/lib/gcp/apphosting.js +89 -0
  26. package/lib/gcp/cloudbuild.js +5 -1
  27. package/lib/hosting/api.js +19 -1
  28. package/lib/init/features/{frameworks → apphosting}/constants.js +1 -2
  29. package/lib/init/features/apphosting/index.js +135 -0
  30. package/lib/init/features/{frameworks → apphosting}/repo.js +53 -28
  31. package/lib/init/features/hosting/index.js +1 -1
  32. package/lib/init/features/index.js +3 -3
  33. package/lib/init/index.js +0 -4
  34. package/lib/utils.js +26 -4
  35. package/package.json +1 -1
  36. package/lib/gcp/frameworks.js +0 -40
  37. package/lib/init/features/frameworks/index.js +0 -116
@@ -1,16 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.listFrameworksConnections = exports.getOrCreateRepository = exports.getOrCreateConnection = exports.createConnection = exports.linkGitHubRepository = exports.parseConnectionName = void 0;
3
+ exports.listAppHostingConnections = exports.getOrCreateRepository = exports.getOrCreateConnection = exports.createConnection = exports.linkGitHubRepository = exports.parseConnectionName = void 0;
4
4
  const clc = require("colorette");
5
5
  const gcb = require("../../../gcp/cloudbuild");
6
+ const rm = require("../../../gcp/resourceManager");
6
7
  const poller = require("../../../operation-poller");
7
8
  const utils = require("../../../utils");
8
9
  const api_1 = require("../../../api");
9
10
  const error_1 = require("../../../error");
10
- const logger_1 = require("../../../logger");
11
11
  const prompt_1 = require("../../../prompt");
12
- const FRAMEWORKS_CONN_PATTERN = /.+\/frameworks-github-conn-.+$/;
13
- const FRAMEWORKS_OAUTH_CONN_NAME = "frameworks-github-oauth";
12
+ const getProjectNumber_1 = require("../../../getProjectNumber");
13
+ const APPHOSTING_CONN_PATTERN = /.+\/apphosting-github-conn-.+$/;
14
+ const APPHOSTING_OAUTH_CONN_NAME = "apphosting-github-oauth";
14
15
  const CONNECTION_NAME_REGEX = /^projects\/(?<projectId>[^\/]+)\/locations\/(?<location>[^\/]+)\/connections\/(?<id>[^\/]+)$/;
15
16
  function parseConnectionName(name) {
16
17
  const match = name.match(CONNECTION_NAME_REGEX);
@@ -44,14 +45,18 @@ function generateRepositoryId(remoteUri) {
44
45
  }
45
46
  function generateConnectionId() {
46
47
  const randomHash = Math.random().toString(36).slice(6);
47
- return `frameworks-github-conn-${randomHash}`;
48
+ return `apphosting-github-conn-${randomHash}`;
48
49
  }
49
50
  async function linkGitHubRepository(projectId, location) {
50
51
  var _a, _b, _c;
51
- logger_1.logger.info(clc.bold(`\n${clc.yellow("===")} Connect a GitHub repository`));
52
- const existingConns = await listFrameworksConnections(projectId);
52
+ utils.logBullet(clc.bold(`${clc.yellow("===")} Set up a GitHub connection`));
53
+ const existingConns = await listAppHostingConnections(projectId);
53
54
  if (existingConns.length < 1) {
54
- let oauthConn = await getOrCreateConnection(projectId, location, FRAMEWORKS_OAUTH_CONN_NAME);
55
+ const grantSuccess = await promptSecretManagerAdminGrant(projectId);
56
+ if (!grantSuccess) {
57
+ throw new error_1.FirebaseError("Insufficient IAM permissions to create a new connection to GitHub");
58
+ }
59
+ let oauthConn = await getOrCreateConnection(projectId, location, APPHOSTING_OAUTH_CONN_NAME);
55
60
  while (oauthConn.installationState.stage === "PENDING_USER_OAUTH") {
56
61
  oauthConn = await promptConnectionAuth(oauthConn);
57
62
  }
@@ -65,14 +70,14 @@ async function linkGitHubRepository(projectId, location) {
65
70
  }
66
71
  existingConns.push(refreshedConn);
67
72
  }
68
- let { remoteUri, connection } = await promptRepositoryUri(projectId, location, existingConns);
73
+ let { remoteUri, connection } = await promptRepositoryUri(projectId, existingConns);
69
74
  while (remoteUri === "") {
70
75
  await utils.openInBrowser("https://github.com/apps/google-cloud-build/installations/new");
71
76
  await (0, prompt_1.promptOnce)({
72
77
  type: "input",
73
78
  message: "Press ENTER once you have finished configuring your installation's access settings.",
74
79
  });
75
- const selection = await promptRepositoryUri(projectId, location, existingConns);
80
+ const selection = await promptRepositoryUri(projectId, existingConns);
76
81
  remoteUri = selection.remoteUri;
77
82
  connection = selection.connection;
78
83
  }
@@ -82,17 +87,17 @@ async function linkGitHubRepository(projectId, location) {
82
87
  appInstallationId: (_c = connection.githubConfig) === null || _c === void 0 ? void 0 : _c.appInstallationId,
83
88
  });
84
89
  const repo = await getOrCreateRepository(projectId, location, connectionId, remoteUri);
85
- logger_1.logger.info();
86
- utils.logSuccess(`Successfully linked GitHub repository at remote URI:\n ${remoteUri}`);
90
+ utils.logSuccess(`Successfully linked GitHub repository at remote URI`);
91
+ utils.logSuccess(`\t${remoteUri}`);
87
92
  return repo;
88
93
  }
89
94
  exports.linkGitHubRepository = linkGitHubRepository;
90
- async function promptRepositoryUri(projectId, location, connections) {
95
+ async function promptRepositoryUri(projectId, connections) {
91
96
  const remoteUriToConnection = {};
92
97
  for (const conn of connections) {
93
- const { id } = parseConnectionName(conn.name);
98
+ const { location, id } = parseConnectionName(conn.name);
94
99
  const resp = await gcb.fetchLinkableRepositories(projectId, location, id);
95
- if (resp.repositories && resp.repositories.length > 1) {
100
+ if (resp.repositories && resp.repositories.length > 0) {
96
101
  for (const repo of resp.repositories) {
97
102
  remoteUriToConnection[repo.remoteUri] = conn;
98
103
  }
@@ -113,11 +118,35 @@ async function promptRepositoryUri(projectId, location, connections) {
113
118
  });
114
119
  return { remoteUri, connection: remoteUriToConnection[remoteUri] };
115
120
  }
121
+ async function promptSecretManagerAdminGrant(projectId) {
122
+ const projectNumber = await (0, getProjectNumber_1.getProjectNumber)({ projectId });
123
+ const cbsaEmail = gcb.serviceAgentEmail(projectNumber);
124
+ const alreadyGranted = await rm.serviceAccountHasRoles(projectId, cbsaEmail, ["roles/secretmanager.admin"], true);
125
+ if (alreadyGranted) {
126
+ return true;
127
+ }
128
+ utils.logBullet("To create a new GitHub connection, Secret Manager Admin role (roles/secretmanager.admin) is required on the Cloud Build Service Agent.");
129
+ const grant = await (0, prompt_1.promptOnce)({
130
+ type: "confirm",
131
+ message: "Grant the required role to the Cloud Build Service Agent?",
132
+ });
133
+ if (!grant) {
134
+ utils.logBullet("You, or your project administrator, should run the following command to grant the required role:\n\n" +
135
+ "You, or your project adminstrator, can run the following command to grant the required role manually:\n\n" +
136
+ `\tgcloud projects add-iam-policy-binding ${projectId} \\\n` +
137
+ `\t --member="serviceAccount:${cbsaEmail} \\\n` +
138
+ `\t --role="roles/secretmanager.admin\n`);
139
+ return false;
140
+ }
141
+ await rm.addServiceAccountToRoles(projectId, cbsaEmail, ["roles/secretmanager.admin"], true);
142
+ utils.logSuccess("Successfully granted the required role to the Cloud Build Service Agent!");
143
+ return true;
144
+ }
116
145
  async function promptConnectionAuth(conn) {
117
- logger_1.logger.info("You must authorize the Cloud Build GitHub app.");
118
- logger_1.logger.info();
119
- logger_1.logger.info("First, sign in to GitHub and authorize Cloud Build GitHub app:");
120
- const cleanup = await utils.openInBrowserPopup(conn.installationState.actionUri, "Authorize the GitHub app");
146
+ utils.logBullet("You must authorize the Cloud Build GitHub app.");
147
+ utils.logBullet("Sign in to GitHub and authorize Cloud Build GitHub app:");
148
+ const { url, cleanup } = await utils.openInBrowserPopup(conn.installationState.actionUri, "Authorize the GitHub app");
149
+ utils.logBullet(`\t${url}`);
121
150
  await (0, prompt_1.promptOnce)({
122
151
  type: "input",
123
152
  message: "Press Enter once you have authorized the app",
@@ -127,9 +156,9 @@ async function promptConnectionAuth(conn) {
127
156
  return await gcb.getConnection(projectId, location, id);
128
157
  }
129
158
  async function promptAppInstall(conn) {
130
- logger_1.logger.info("Now, install the Cloud Build GitHub app:");
159
+ utils.logBullet("Install the Cloud Build GitHub app to enable access to GitHub repositories");
131
160
  const targetUri = conn.installationState.actionUri.replace("install_v2", "direct_install_v2");
132
- logger_1.logger.info(targetUri);
161
+ utils.logBullet(targetUri);
133
162
  await utils.openInBrowser(targetUri);
134
163
  await (0, prompt_1.promptOnce)({
135
164
  type: "input",
@@ -168,10 +197,6 @@ async function getOrCreateRepository(projectId, location, connectionId, remoteUr
168
197
  let repo;
169
198
  try {
170
199
  repo = await gcb.getRepository(projectId, location, connectionId, repositoryId);
171
- const repoSlug = extractRepoSlugFromUri(repo.remoteUri);
172
- if (repoSlug) {
173
- throw new error_1.FirebaseError(`${repoSlug} has already been linked.`);
174
- }
175
200
  }
176
201
  catch (err) {
177
202
  if (err.status === 404) {
@@ -185,10 +210,10 @@ async function getOrCreateRepository(projectId, location, connectionId, remoteUr
185
210
  return repo;
186
211
  }
187
212
  exports.getOrCreateRepository = getOrCreateRepository;
188
- async function listFrameworksConnections(projectId) {
213
+ async function listAppHostingConnections(projectId) {
189
214
  const conns = await gcb.listConnections(projectId, "-");
190
- return conns.filter((conn) => FRAMEWORKS_CONN_PATTERN.test(conn.name) &&
215
+ return conns.filter((conn) => APPHOSTING_CONN_PATTERN.test(conn.name) &&
191
216
  conn.installationState.stage === "COMPLETE" &&
192
217
  !conn.disabled);
193
218
  }
194
- exports.listFrameworksConnections = listFrameworksConnections;
219
+ exports.listAppHostingConnections = listAppHostingConnections;
@@ -124,7 +124,7 @@ async function doSetup(setup, config, options) {
124
124
  type: "list",
125
125
  message: "In which region would you like to host server-side content, if applicable?",
126
126
  default: constants_1.DEFAULT_REGION,
127
- choices: constants_1.ALLOWED_SSR_REGIONS,
127
+ choices: constants_1.ALLOWED_SSR_REGIONS.filter((region) => region.recommended),
128
128
  }, setup.hosting);
129
129
  setup.config.hosting = {
130
130
  source: setup.hosting.source,
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.frameworks = exports.hostingGithub = exports.remoteconfig = exports.project = exports.extensions = exports.emulators = exports.storage = exports.hosting = exports.functions = exports.firestore = exports.database = exports.account = void 0;
3
+ exports.apphosting = exports.hostingGithub = exports.remoteconfig = exports.project = exports.extensions = exports.emulators = exports.storage = exports.hosting = exports.functions = exports.firestore = exports.database = exports.account = void 0;
4
4
  var account_1 = require("./account");
5
5
  Object.defineProperty(exports, "account", { enumerable: true, get: function () { return account_1.doSetup; } });
6
6
  var database_1 = require("./database");
@@ -23,5 +23,5 @@ var remoteconfig_1 = require("./remoteconfig");
23
23
  Object.defineProperty(exports, "remoteconfig", { enumerable: true, get: function () { return remoteconfig_1.doSetup; } });
24
24
  var github_1 = require("./hosting/github");
25
25
  Object.defineProperty(exports, "hostingGithub", { enumerable: true, get: function () { return github_1.initGitHub; } });
26
- var frameworks_1 = require("./frameworks");
27
- Object.defineProperty(exports, "frameworks", { enumerable: true, get: function () { return frameworks_1.doSetup; } });
26
+ var apphosting_1 = require("./apphosting");
27
+ Object.defineProperty(exports, "apphosting", { enumerable: true, get: function () { return apphosting_1.doSetup; } });
package/lib/init/index.js CHANGED
@@ -6,7 +6,6 @@ const clc = require("colorette");
6
6
  const error_1 = require("../error");
7
7
  const logger_1 = require("../logger");
8
8
  const features = require("./features");
9
- const experiments_1 = require("../experiments");
10
9
  const featureFns = new Map([
11
10
  ["account", features.account],
12
11
  ["database", features.database],
@@ -20,9 +19,6 @@ const featureFns = new Map([
20
19
  ["remoteconfig", features.remoteconfig],
21
20
  ["hosting:github", features.hostingGithub],
22
21
  ]);
23
- if ((0, experiments_1.isEnabled)("internalframeworks")) {
24
- featureFns.set("internalframeworks", features.frameworks);
25
- }
26
22
  async function init(setup, config, options) {
27
23
  var _a;
28
24
  const nextFeature = (_a = setup.features) === null || _a === void 0 ? void 0 : _a.shift();
package/lib/utils.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.openInBrowserPopup = exports.openInBrowser = exports.connectableHostname = exports.randomInt = exports.debounce = exports.last = exports.cloneDeep = exports.groupBy = exports.assertIsStringOrUndefined = exports.assertIsNumber = exports.assertIsString = exports.thirtyDaysFromNow = exports.isRunningInWSL = exports.isVSCodeExtension = exports.isCloudEnvironment = exports.datetimeString = exports.createDestroyer = exports.promiseWithSpinner = exports.setupLoggers = exports.tryParse = exports.tryStringify = exports.promiseProps = exports.withTimeout = exports.promiseWhile = exports.promiseAllSettled = exports.getFunctionsEventProvider = exports.endpoint = exports.makeActiveProject = exports.streamToString = exports.stringToStream = exports.explainStdin = exports.allSettled = exports.reject = exports.logLabeledError = exports.logLabeledWarning = exports.logWarning = exports.logLabeledBullet = exports.logBullet = exports.logLabeledSuccess = exports.logSuccess = exports.addSubdomain = exports.addDatabaseNamespace = exports.getDatabaseViewDataUrl = exports.getDatabaseUrl = exports.envOverride = exports.getInheritedOption = exports.consoleUrl = exports.envOverrides = void 0;
3
+ exports.generateId = exports.getHostnameFromUrl = exports.openInBrowserPopup = exports.openInBrowser = exports.connectableHostname = exports.randomInt = exports.debounce = exports.last = exports.cloneDeep = exports.groupBy = exports.assertIsStringOrUndefined = exports.assertIsNumber = exports.assertIsString = exports.thirtyDaysFromNow = exports.isRunningInWSL = exports.isVSCodeExtension = exports.isCloudEnvironment = exports.datetimeString = exports.createDestroyer = exports.promiseWithSpinner = exports.setupLoggers = exports.tryParse = exports.tryStringify = exports.promiseProps = exports.withTimeout = exports.promiseWhile = exports.promiseAllSettled = exports.getFunctionsEventProvider = exports.endpoint = exports.makeActiveProject = exports.streamToString = exports.stringToStream = exports.explainStdin = exports.allSettled = exports.reject = exports.logLabeledError = exports.logLabeledWarning = exports.logWarning = exports.logLabeledBullet = exports.logBullet = exports.logLabeledSuccess = exports.logSuccess = exports.addSubdomain = exports.addDatabaseNamespace = exports.getDatabaseViewDataUrl = exports.getDatabaseUrl = exports.envOverride = exports.getInheritedOption = exports.consoleUrl = exports.envOverrides = void 0;
4
4
  const fs = require("node:fs");
5
5
  const path = require("node:path");
6
6
  const _ = require("lodash");
@@ -506,10 +506,32 @@ async function openInBrowserPopup(url, buttonText) {
506
506
  });
507
507
  server.listen(port);
508
508
  const popupPageUri = `http://localhost:${port}`;
509
- logger_1.logger.info(popupPageUri);
510
509
  await openInBrowser(popupPageUri);
511
- return () => {
512
- server.close();
510
+ return {
511
+ url: popupPageUri,
512
+ cleanup: () => {
513
+ server.close();
514
+ },
513
515
  };
514
516
  }
515
517
  exports.openInBrowserPopup = openInBrowserPopup;
518
+ function getHostnameFromUrl(url) {
519
+ try {
520
+ return new URL(url).hostname;
521
+ }
522
+ catch (e) {
523
+ return null;
524
+ }
525
+ }
526
+ exports.getHostnameFromUrl = getHostnameFromUrl;
527
+ function generateId(n = 6) {
528
+ const letters = "abcdefghijklmnopqrstuvwxyz";
529
+ const allChars = "01234567890-abcdefghijklmnopqrstuvwxyz";
530
+ let id = letters[Math.floor(Math.random() * letters.length)];
531
+ for (let i = 1; i < n; i++) {
532
+ const idx = Math.floor(Math.random() * allChars.length);
533
+ id += allChars[idx];
534
+ }
535
+ return id;
536
+ }
537
+ exports.generateId = generateId;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-tools",
3
- "version": "13.0.0",
3
+ "version": "13.0.2",
4
4
  "description": "Command-Line Interface for Firebase",
5
5
  "main": "./lib/index.js",
6
6
  "bin": {
@@ -1,40 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createBuild = exports.deleteBackend = exports.listBackends = exports.getBackend = exports.createBackend = exports.API_VERSION = void 0;
4
- const apiv2_1 = require("../apiv2");
5
- const api_1 = require("../api");
6
- exports.API_VERSION = "v1alpha";
7
- const client = new apiv2_1.Client({
8
- urlPrefix: api_1.frameworksOrigin,
9
- auth: true,
10
- apiVersion: exports.API_VERSION,
11
- });
12
- async function createBackend(projectId, location, backendReqBoby, backendId) {
13
- const res = await client.post(`projects/${projectId}/locations/${location}/backends`, backendReqBoby, { queryParams: { backendId } });
14
- return res.body;
15
- }
16
- exports.createBackend = createBackend;
17
- async function getBackend(projectId, location, backendId) {
18
- const name = `projects/${projectId}/locations/${location}/backends/${backendId}`;
19
- const res = await client.get(name);
20
- return res.body;
21
- }
22
- exports.getBackend = getBackend;
23
- async function listBackends(projectId, location) {
24
- const name = `projects/${projectId}/locations/${location}/backends`;
25
- const res = await client.get(name);
26
- return res.body;
27
- }
28
- exports.listBackends = listBackends;
29
- async function deleteBackend(projectId, location, backendId) {
30
- const name = `projects/${projectId}/locations/${location}/backends/${backendId}`;
31
- const res = await client.delete(name);
32
- return res.body;
33
- }
34
- exports.deleteBackend = deleteBackend;
35
- async function createBuild(projectId, location, backendId, buildInput) {
36
- const buildId = buildInput.name;
37
- const res = await client.post(`projects/${projectId}/locations/${location}/backends/${backendId}/builds`, buildInput, { queryParams: { buildId } });
38
- return res.body;
39
- }
40
- exports.createBuild = createBuild;
@@ -1,116 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createBackend = exports.getOrCreateBackend = exports.doSetup = void 0;
4
- const clc = require("colorette");
5
- const utils = require("../../../utils");
6
- const repo = require("./repo");
7
- const poller = require("../../../operation-poller");
8
- const gcp = require("../../../gcp/frameworks");
9
- const api_1 = require("../../../api");
10
- const frameworks_1 = require("../../../gcp/frameworks");
11
- const error_1 = require("../../../error");
12
- const logger_1 = require("../../../logger");
13
- const prompt_1 = require("../../../prompt");
14
- const constants_1 = require("./constants");
15
- const frameworksPollerOptions = {
16
- apiOrigin: api_1.frameworksOrigin,
17
- apiVersion: frameworks_1.API_VERSION,
18
- masterTimeout: 25 * 60 * 1000,
19
- maxBackoff: 10000,
20
- };
21
- async function doSetup(setup, projectId) {
22
- setup.frameworks = {};
23
- utils.logBullet("First we need a few details to create your backend.");
24
- await (0, prompt_1.promptOnce)({
25
- name: "serviceName",
26
- type: "input",
27
- default: "acme-inc-web",
28
- message: "Create a name for your backend [1-30 characters]",
29
- }, setup.frameworks);
30
- await (0, prompt_1.promptOnce)({
31
- name: "region",
32
- type: "list",
33
- default: constants_1.DEFAULT_REGION,
34
- message: "Please select a region " +
35
- `(${clc.yellow("info")}: Your region determines where your backend is located):\n`,
36
- choices: constants_1.ALLOWED_REGIONS,
37
- }, setup.frameworks);
38
- utils.logSuccess(`Region set to ${setup.frameworks.region}.`);
39
- const backend = await getOrCreateBackend(projectId, setup);
40
- if (backend) {
41
- logger_1.logger.info();
42
- utils.logSuccess(`Successfully created backend:\n ${backend.name}`);
43
- logger_1.logger.info();
44
- utils.logSuccess(`Your site is being deployed at:\n https://${backend.uri}`);
45
- logger_1.logger.info();
46
- utils.logSuccess(`View the rollout status by running:\n firebase backends:get --backend=${backend.name}`);
47
- logger_1.logger.info();
48
- }
49
- }
50
- exports.doSetup = doSetup;
51
- function toBackend(cloudBuildConnRepo) {
52
- return {
53
- codebase: {
54
- repository: `${cloudBuildConnRepo.name}`,
55
- rootDirectory: "/",
56
- },
57
- labels: {},
58
- };
59
- }
60
- async function getOrCreateBackend(projectId, setup) {
61
- const location = setup.frameworks.region;
62
- try {
63
- return await getExistingBackend(projectId, setup, location);
64
- }
65
- catch (err) {
66
- if (err.status === 404) {
67
- const cloudBuildConnRepo = await repo.linkGitHubRepository(projectId, location);
68
- logger_1.logger.info();
69
- await (0, prompt_1.promptOnce)({
70
- name: "branchName",
71
- type: "input",
72
- default: "main",
73
- message: "Which branch do you want to deploy?",
74
- }, setup.frameworks);
75
- const backendDetails = toBackend(cloudBuildConnRepo);
76
- logger_1.logger.info(clc.bold(`\n${clc.white("===")} Creating your backend`));
77
- return await createBackend(projectId, location, backendDetails, setup.frameworks.serviceName);
78
- }
79
- else {
80
- throw new error_1.FirebaseError(`Failed to get or create a backend using the given initialization details: ${err}`);
81
- }
82
- }
83
- return undefined;
84
- }
85
- exports.getOrCreateBackend = getOrCreateBackend;
86
- async function getExistingBackend(projectId, setup, location) {
87
- let backend = await gcp.getBackend(projectId, location, setup.frameworks.serviceName);
88
- while (backend) {
89
- setup.frameworks.serviceName = undefined;
90
- await (0, prompt_1.promptOnce)({
91
- name: "existingBackend",
92
- type: "confirm",
93
- default: true,
94
- message: "A backend already exists for the given serviceName, do you want to use existing backend? (yes/no)",
95
- }, setup.frameworks);
96
- if (setup.frameworks.existingBackend) {
97
- logger_1.logger.info("Using the existing backend.");
98
- return backend;
99
- }
100
- await (0, prompt_1.promptOnce)({
101
- name: "serviceName",
102
- type: "input",
103
- default: "acme-inc-web",
104
- message: "Please enter a new service name [1-30 characters]",
105
- }, setup.frameworks);
106
- backend = await gcp.getBackend(projectId, location, setup.frameworks.serviceName);
107
- setup.frameworks.existingBackend = undefined;
108
- }
109
- return backend;
110
- }
111
- async function createBackend(projectId, location, backendReqBoby, backendId) {
112
- const op = await gcp.createBackend(projectId, location, backendReqBoby, backendId);
113
- const backend = await poller.pollOperation(Object.assign(Object.assign({}, frameworksPollerOptions), { pollerName: `create-${projectId}-${location}-${backendId}`, operationResourceName: op.name }));
114
- return backend;
115
- }
116
- exports.createBackend = createBackend;