firebase-tools 13.7.4 → 13.7.5

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.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.promptLocation = exports.deleteBackendAndPoll = exports.orchestrateRollout = exports.setDefaultTrafficPolicy = exports.createBackend = exports.doSetup = void 0;
3
+ exports.promptLocation = exports.deleteBackendAndPoll = exports.orchestrateRollout = exports.setDefaultTrafficPolicy = exports.createBackend = exports.ensureAppHostingComputeServiceAccount = exports.doSetup = void 0;
4
4
  const repo = require("./repo");
5
5
  const poller = require("../operation-poller");
6
6
  const apphosting = require("../gcp/apphosting");
@@ -30,14 +30,16 @@ async function doSetup(projectId, webAppName, location, serviceAccount, withDevC
30
30
  (0, ensureApiEnabled_1.ensure)(projectId, (0, api_1.secretManagerOrigin)(), "apphosting", true),
31
31
  (0, ensureApiEnabled_1.ensure)(projectId, (0, api_1.cloudRunApiOrigin)(), "apphosting", true),
32
32
  (0, ensureApiEnabled_1.ensure)(projectId, (0, api_1.artifactRegistryDomain)(), "apphosting", true),
33
+ (0, ensureApiEnabled_1.ensure)(projectId, (0, api_1.iamOrigin)(), "apphosting", true),
33
34
  ]);
35
+ (0, utils_1.logBullet)("First we need a few details to create your backend.\n");
36
+ await ensureAppHostingComputeServiceAccount(projectId, serviceAccount);
34
37
  const allowedLocations = (await apphosting.listLocations(projectId)).map((loc) => loc.locationId);
35
38
  if (location) {
36
39
  if (!allowedLocations.includes(location)) {
37
40
  throw new error_1.FirebaseError(`Invalid location ${location}. Valid choices are ${allowedLocations.join(", ")}`);
38
41
  }
39
42
  }
40
- (0, utils_1.logBullet)("First we need a few details to create your backend.\n");
41
43
  location =
42
44
  location || (await promptLocation(projectId, "Select a location to host your backend:\n"));
43
45
  (0, utils_1.logSuccess)(`Location set to ${location}.\n`);
@@ -93,6 +95,25 @@ async function doSetup(projectId, webAppName, location, serviceAccount, withDevC
93
95
  (0, utils_1.logSuccess)(`Your backend is now deployed at:\n\thttps://${backend.uri}`);
94
96
  }
95
97
  exports.doSetup = doSetup;
98
+ async function ensureAppHostingComputeServiceAccount(projectId, serviceAccount) {
99
+ const sa = serviceAccount || defaultComputeServiceAccountEmail(projectId);
100
+ const name = `projects/${projectId}/serviceAccounts/${sa}`;
101
+ try {
102
+ await iam.testResourceIamPermissions((0, api_1.iamOrigin)(), "v1", name, ["iam.serviceAccounts.actAs"], `projects/${projectId}`);
103
+ }
104
+ catch (err) {
105
+ if (!(err instanceof error_1.FirebaseError)) {
106
+ throw err;
107
+ }
108
+ if (err.status === 404) {
109
+ await provisionDefaultComputeServiceAccount(projectId);
110
+ }
111
+ else if (err.status === 403) {
112
+ throw new error_1.FirebaseError(`Failed to create backend due to missing delegation permissions for ${sa}. Make sure you have the iam.serviceAccounts.actAs permission.`, { original: err });
113
+ }
114
+ }
115
+ }
116
+ exports.ensureAppHostingComputeServiceAccount = ensureAppHostingComputeServiceAccount;
96
117
  async function promptNewBackendId(projectId, location, prompt) {
97
118
  while (true) {
98
119
  const backendId = await (0, prompt_1.promptOnce)(prompt);
@@ -127,33 +148,23 @@ async function createBackend(projectId, location, backendId, repository, service
127
148
  const op = await apphosting.createBackend(projectId, location, backendReqBody, backendId);
128
149
  return await poller.pollOperation(Object.assign(Object.assign({}, apphostingPollerOptions), { pollerName: `create-${projectId}-${location}-${backendId}`, operationResourceName: op.name }));
129
150
  }
130
- try {
131
- return await createBackendAndPoll();
132
- }
133
- catch (err) {
134
- if (err.status === 403) {
135
- if (err.message.includes(defaultServiceAccount)) {
136
- await provisionDefaultComputeServiceAccount(projectId);
137
- return await createBackendAndPoll();
138
- }
139
- else if (serviceAccount && err.message.includes(serviceAccount)) {
140
- throw new error_1.FirebaseError(`Failed to create backend due to missing delegation permissions for ${serviceAccount}. Make sure you have the iam.serviceAccounts.actAs permission.`, { children: [err] });
141
- }
142
- }
143
- throw err;
144
- }
151
+ return await createBackendAndPoll();
145
152
  }
146
153
  exports.createBackend = createBackend;
147
154
  async function provisionDefaultComputeServiceAccount(projectId) {
148
155
  try {
149
- await iam.createServiceAccount(projectId, DEFAULT_COMPUTE_SERVICE_ACCOUNT_NAME, "Firebase App Hosting compute service account", "Default service account used to run builds and deploys for Firebase App Hosting");
156
+ await iam.createServiceAccount(projectId, DEFAULT_COMPUTE_SERVICE_ACCOUNT_NAME, "Default service account used to run builds and deploys for Firebase App Hosting", "Firebase App Hosting compute service account");
150
157
  }
151
158
  catch (err) {
152
159
  if (err.status !== 409) {
153
160
  throw err;
154
161
  }
155
162
  }
156
- await (0, resourceManager_1.addServiceAccountToRoles)(projectId, defaultComputeServiceAccountEmail(projectId), ["roles/firebaseapphosting.computeRunner", "roles/firebase.sdkAdminServiceAgent"], true);
163
+ await (0, resourceManager_1.addServiceAccountToRoles)(projectId, defaultComputeServiceAccountEmail(projectId), [
164
+ "roles/firebaseapphosting.computeRunner",
165
+ "roles/firebase.sdkAdminServiceAgent",
166
+ "roles/developerconnect.tokenAccessor",
167
+ ], true);
157
168
  }
158
169
  async function setDefaultTrafficPolicy(projectId, location, backendId, codebaseBranch) {
159
170
  const traffic = {
@@ -171,8 +182,12 @@ async function setDefaultTrafficPolicy(projectId, location, backendId, codebaseB
171
182
  await poller.pollOperation(Object.assign(Object.assign({}, apphostingPollerOptions), { pollerName: `updateTraffic-${projectId}-${location}-${backendId}`, operationResourceName: op.name }));
172
183
  }
173
184
  exports.setDefaultTrafficPolicy = setDefaultTrafficPolicy;
185
+ function delay(ms) {
186
+ return new Promise((resolve) => setTimeout(resolve, ms));
187
+ }
174
188
  async function orchestrateRollout(projectId, location, backendId, buildInput) {
175
189
  (0, utils_1.logBullet)("Starting a new rollout... this may take a few minutes.");
190
+ await delay(45 * 1000);
176
191
  const buildId = await apphosting.getNextRolloutId(projectId, location, backendId, 1);
177
192
  const buildOp = await apphosting.createBuild(projectId, location, backendId, buildId, buildInput);
178
193
  const rolloutBody = {
@@ -11,7 +11,7 @@ exports.command = new command_1.Command("apphosting:backends:create")
11
11
  .option("-a, --app <webApp>", "specify an existing Firebase web app to associate your App Hosting backend with")
12
12
  .option("-l, --location <location>", "specify the location of the backend", "")
13
13
  .option("-s, --service-account <serviceAccount>", "specify the service account used to run the server", "")
14
- .option("-w, --with-dev-connect", "use the Developer Connect flow insetad of Cloud Build Repositories (testing)", false)
14
+ .option("-w, --with-dev-connect", "use the Developer Connect flow instead of Cloud Build Repositories (testing)", true)
15
15
  .before(apphosting_2.ensureApiEnabled)
16
16
  .before(requireInteractive_1.default)
17
17
  .action(async (options) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "firebase-tools",
3
- "version": "13.7.4",
3
+ "version": "13.7.5",
4
4
  "description": "Command-Line Interface for Firebase",
5
5
  "main": "./lib/index.js",
6
6
  "bin": {