firebase-tools 13.7.3 → 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.
- package/lib/api.js +10 -8
- package/lib/apphosting/constants.js +2 -2
- package/lib/apphosting/githubConnections.js +1 -1
- package/lib/apphosting/index.js +44 -32
- package/lib/apphosting/repo.js +1 -1
- package/lib/apphosting/secrets/index.js +7 -1
- package/lib/commands/apphosting-backends-create.js +2 -2
- package/lib/commands/apphosting-backends-delete.js +4 -15
- package/lib/commands/apphosting-backends-list.js +2 -3
- package/lib/commands/apphosting-secrets-access.js +1 -1
- package/lib/commands/apphosting-secrets-grantaccess.js +5 -5
- package/lib/commands/apphosting-secrets-set.js +1 -1
- package/lib/emulator/downloadableEmulators.js +15 -5
- package/lib/frameworks/next/index.js +3 -3
- package/lib/frameworks/next/utils.js +1 -0
- package/lib/functions/python.js +4 -3
- package/lib/gcp/apphosting.js +6 -1
- package/lib/gcp/devConnect.js +1 -1
- package/package.json +1 -1
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.githubClientSecret = exports.githubClientId = exports.computeOrigin = exports.secretManagerOrigin = exports.githubApiOrigin = void 0;
|
|
3
|
+
exports.serviceUsageOrigin = exports.cloudRunApiOrigin = 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.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.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.githubClientSecret = exports.githubClientId = exports.computeOrigin = exports.secretManagerOrigin = exports.githubApiOrigin = exports.githubOrigin = void 0;
|
|
5
5
|
const constants_1 = require("./emulator/constants");
|
|
6
6
|
const logger_1 = require("./logger");
|
|
7
7
|
const scopes = require("./scopes");
|
|
@@ -21,10 +21,18 @@ const cloudMonitoringOrigin = () => utils.envOverride("CLOUD_MONITORING_URL", "h
|
|
|
21
21
|
exports.cloudMonitoringOrigin = cloudMonitoringOrigin;
|
|
22
22
|
const containerRegistryDomain = () => utils.envOverride("CONTAINER_REGISTRY_DOMAIN", "gcr.io");
|
|
23
23
|
exports.containerRegistryDomain = containerRegistryDomain;
|
|
24
|
+
const developerConnectOrigin = () => utils.envOverride("DEVELOPERCONNECT_URL", "https://developerconnect.googleapis.com");
|
|
25
|
+
exports.developerConnectOrigin = developerConnectOrigin;
|
|
26
|
+
const developerConnectP4SADomain = () => utils.envOverride("DEVELOPERCONNECT_P4SA_DOMAIN", "gcp-sa-devconnect.iam.gserviceaccount.com");
|
|
27
|
+
exports.developerConnectP4SADomain = developerConnectP4SADomain;
|
|
24
28
|
const artifactRegistryDomain = () => utils.envOverride("ARTIFACT_REGISTRY_DOMAIN", "https://artifactregistry.googleapis.com");
|
|
25
29
|
exports.artifactRegistryDomain = artifactRegistryDomain;
|
|
26
30
|
const appDistributionOrigin = () => utils.envOverride("FIREBASE_APP_DISTRIBUTION_URL", "https://firebaseappdistribution.googleapis.com");
|
|
27
31
|
exports.appDistributionOrigin = appDistributionOrigin;
|
|
32
|
+
const apphostingOrigin = () => utils.envOverride("FIREBASE_APPHOSTING_URL", "https://firebaseapphosting.googleapis.com");
|
|
33
|
+
exports.apphostingOrigin = apphostingOrigin;
|
|
34
|
+
const apphostingP4SADomain = () => utils.envOverride("FIREBASE_APPHOSTING_P4SA_DOMAIN", "gcp-sa-firebaseapphosting.iam.gserviceaccount.com");
|
|
35
|
+
exports.apphostingP4SADomain = apphostingP4SADomain;
|
|
28
36
|
const authOrigin = () => utils.envOverride("FIREBASE_AUTH_URL", "https://accounts.google.com");
|
|
29
37
|
exports.authOrigin = authOrigin;
|
|
30
38
|
const consoleOrigin = () => utils.envOverride("FIREBASE_CONSOLE_URL", "https://console.firebase.google.com");
|
|
@@ -60,10 +68,6 @@ const functionsDefaultRegion = () => utils.envOverride("FIREBASE_FUNCTIONS_DEFAU
|
|
|
60
68
|
exports.functionsDefaultRegion = functionsDefaultRegion;
|
|
61
69
|
const cloudbuildOrigin = () => utils.envOverride("FIREBASE_CLOUDBUILD_URL", "https://cloudbuild.googleapis.com");
|
|
62
70
|
exports.cloudbuildOrigin = cloudbuildOrigin;
|
|
63
|
-
const developerConnectOrigin = () => utils.envOverride("FIREBASE_DEVELOPERCONNECT_URL", "https://developerconnect.googleapis.com");
|
|
64
|
-
exports.developerConnectOrigin = developerConnectOrigin;
|
|
65
|
-
const developerConnectP4SAOrigin = () => utils.envOverride("FIREBASE_DEVELOPERCONNECT_P4SA_URL", "gcp-sa-devconnect.iam.gserviceaccount.com");
|
|
66
|
-
exports.developerConnectP4SAOrigin = developerConnectP4SAOrigin;
|
|
67
71
|
const cloudschedulerOrigin = () => utils.envOverride("FIREBASE_CLOUDSCHEDULER_URL", "https://cloudscheduler.googleapis.com");
|
|
68
72
|
exports.cloudschedulerOrigin = cloudschedulerOrigin;
|
|
69
73
|
const cloudTasksOrigin = () => utils.envOverride("FIREBASE_CLOUD_TAKS_URL", "https://cloudtasks.googleapis.com");
|
|
@@ -108,8 +112,6 @@ const cloudRunApiOrigin = () => utils.envOverride("CLOUD_RUN_API_URL", "https://
|
|
|
108
112
|
exports.cloudRunApiOrigin = cloudRunApiOrigin;
|
|
109
113
|
const serviceUsageOrigin = () => utils.envOverride("FIREBASE_SERVICE_USAGE_URL", "https://serviceusage.googleapis.com");
|
|
110
114
|
exports.serviceUsageOrigin = serviceUsageOrigin;
|
|
111
|
-
const apphostingOrigin = () => utils.envOverride("APPHOSTING_URL", "https://firebaseapphosting.googleapis.com");
|
|
112
|
-
exports.apphostingOrigin = apphostingOrigin;
|
|
113
115
|
const githubOrigin = () => utils.envOverride("GITHUB_URL", "https://github.com");
|
|
114
116
|
exports.githubOrigin = githubOrigin;
|
|
115
117
|
const githubApiOrigin = () => utils.envOverride("GITHUB_API_URL", "https://api.github.com");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ALLOWED_DEPLOY_METHODS = exports.DEFAULT_DEPLOY_METHOD = exports.
|
|
4
|
-
exports.
|
|
3
|
+
exports.ALLOWED_DEPLOY_METHODS = exports.DEFAULT_DEPLOY_METHOD = exports.DEFAULT_LOCATION = void 0;
|
|
4
|
+
exports.DEFAULT_LOCATION = "us-central1";
|
|
5
5
|
exports.DEFAULT_DEPLOY_METHOD = "github";
|
|
6
6
|
exports.ALLOWED_DEPLOY_METHODS = [{ name: "Deploy using github", value: "github" }];
|
|
@@ -89,7 +89,7 @@ async function createFullyInstalledConnection(projectId, location, connectionId,
|
|
|
89
89
|
});
|
|
90
90
|
while (conn.installationState.stage !== "COMPLETE") {
|
|
91
91
|
utils.logBullet("Install the Firebase GitHub app to enable access to GitHub repositories");
|
|
92
|
-
const targetUri = conn.installationState.actionUri
|
|
92
|
+
const targetUri = conn.installationState.actionUri;
|
|
93
93
|
utils.logBullet(targetUri);
|
|
94
94
|
await utils.openInBrowser(targetUri);
|
|
95
95
|
await (0, prompt_1.promptOnce)({
|
package/lib/apphosting/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
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,24 +30,19 @@ 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
|
-
location ||
|
|
43
|
-
|
|
44
|
-
name: "region",
|
|
45
|
-
type: "list",
|
|
46
|
-
default: constants_1.DEFAULT_REGION,
|
|
47
|
-
message: "Select a region to host your backend:\n",
|
|
48
|
-
choices: allowedLocations.map((loc) => ({ value: loc })),
|
|
49
|
-
}));
|
|
50
|
-
(0, utils_1.logSuccess)(`Region set to ${location}.\n`);
|
|
44
|
+
location || (await promptLocation(projectId, "Select a location to host your backend:\n"));
|
|
45
|
+
(0, utils_1.logSuccess)(`Location set to ${location}.\n`);
|
|
51
46
|
const backendId = await promptNewBackendId(projectId, location, {
|
|
52
47
|
name: "backendId",
|
|
53
48
|
type: "input",
|
|
@@ -100,6 +95,25 @@ async function doSetup(projectId, webAppName, location, serviceAccount, withDevC
|
|
|
100
95
|
(0, utils_1.logSuccess)(`Your backend is now deployed at:\n\thttps://${backend.uri}`);
|
|
101
96
|
}
|
|
102
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;
|
|
103
117
|
async function promptNewBackendId(projectId, location, prompt) {
|
|
104
118
|
while (true) {
|
|
105
119
|
const backendId = await (0, prompt_1.promptOnce)(prompt);
|
|
@@ -130,31 +144,16 @@ async function createBackend(projectId, location, backendId, repository, service
|
|
|
130
144
|
serviceAccount: serviceAccount || defaultServiceAccount,
|
|
131
145
|
appId: webAppId,
|
|
132
146
|
};
|
|
133
|
-
delete backendReqBody.serviceAccount;
|
|
134
147
|
async function createBackendAndPoll() {
|
|
135
148
|
const op = await apphosting.createBackend(projectId, location, backendReqBody, backendId);
|
|
136
149
|
return await poller.pollOperation(Object.assign(Object.assign({}, apphostingPollerOptions), { pollerName: `create-${projectId}-${location}-${backendId}`, operationResourceName: op.name }));
|
|
137
150
|
}
|
|
138
|
-
|
|
139
|
-
return await createBackendAndPoll();
|
|
140
|
-
}
|
|
141
|
-
catch (err) {
|
|
142
|
-
if (err.status === 403) {
|
|
143
|
-
if (err.message.includes(defaultServiceAccount)) {
|
|
144
|
-
await provisionDefaultComputeServiceAccount(projectId);
|
|
145
|
-
return await createBackendAndPoll();
|
|
146
|
-
}
|
|
147
|
-
else if (serviceAccount && err.message.includes(serviceAccount)) {
|
|
148
|
-
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] });
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
throw err;
|
|
152
|
-
}
|
|
151
|
+
return await createBackendAndPoll();
|
|
153
152
|
}
|
|
154
153
|
exports.createBackend = createBackend;
|
|
155
154
|
async function provisionDefaultComputeServiceAccount(projectId) {
|
|
156
155
|
try {
|
|
157
|
-
await iam.createServiceAccount(projectId, DEFAULT_COMPUTE_SERVICE_ACCOUNT_NAME, "
|
|
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");
|
|
158
157
|
}
|
|
159
158
|
catch (err) {
|
|
160
159
|
if (err.status !== 409) {
|
|
@@ -162,11 +161,9 @@ async function provisionDefaultComputeServiceAccount(projectId) {
|
|
|
162
161
|
}
|
|
163
162
|
}
|
|
164
163
|
await (0, resourceManager_1.addServiceAccountToRoles)(projectId, defaultComputeServiceAccountEmail(projectId), [
|
|
165
|
-
"roles/firebaseapphosting.
|
|
166
|
-
"roles/artifactregistry.createOnPushWriter",
|
|
167
|
-
"roles/logging.logWriter",
|
|
168
|
-
"roles/storage.objectAdmin",
|
|
164
|
+
"roles/firebaseapphosting.computeRunner",
|
|
169
165
|
"roles/firebase.sdkAdminServiceAgent",
|
|
166
|
+
"roles/developerconnect.tokenAccessor",
|
|
170
167
|
], true);
|
|
171
168
|
}
|
|
172
169
|
async function setDefaultTrafficPolicy(projectId, location, backendId, codebaseBranch) {
|
|
@@ -185,8 +182,12 @@ async function setDefaultTrafficPolicy(projectId, location, backendId, codebaseB
|
|
|
185
182
|
await poller.pollOperation(Object.assign(Object.assign({}, apphostingPollerOptions), { pollerName: `updateTraffic-${projectId}-${location}-${backendId}`, operationResourceName: op.name }));
|
|
186
183
|
}
|
|
187
184
|
exports.setDefaultTrafficPolicy = setDefaultTrafficPolicy;
|
|
185
|
+
function delay(ms) {
|
|
186
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
187
|
+
}
|
|
188
188
|
async function orchestrateRollout(projectId, location, backendId, buildInput) {
|
|
189
189
|
(0, utils_1.logBullet)("Starting a new rollout... this may take a few minutes.");
|
|
190
|
+
await delay(45 * 1000);
|
|
190
191
|
const buildId = await apphosting.getNextRolloutId(projectId, location, backendId, 1);
|
|
191
192
|
const buildOp = await apphosting.createBuild(projectId, location, backendId, buildId, buildInput);
|
|
192
193
|
const rolloutBody = {
|
|
@@ -233,3 +234,14 @@ async function deleteBackendAndPoll(projectId, location, backendId) {
|
|
|
233
234
|
await poller.pollOperation(Object.assign(Object.assign({}, apphostingPollerOptions), { pollerName: `delete-${projectId}-${location}-${backendId}`, operationResourceName: op.name }));
|
|
234
235
|
}
|
|
235
236
|
exports.deleteBackendAndPoll = deleteBackendAndPoll;
|
|
237
|
+
async function promptLocation(projectId, prompt = "Please select a location:") {
|
|
238
|
+
const allowedLocations = (await apphosting.listLocations(projectId)).map((loc) => loc.locationId);
|
|
239
|
+
return (await (0, prompt_1.promptOnce)({
|
|
240
|
+
name: "location",
|
|
241
|
+
type: "list",
|
|
242
|
+
default: constants_1.DEFAULT_LOCATION,
|
|
243
|
+
message: prompt,
|
|
244
|
+
choices: allowedLocations,
|
|
245
|
+
}));
|
|
246
|
+
}
|
|
247
|
+
exports.promptLocation = promptLocation;
|
package/lib/apphosting/repo.js
CHANGED
|
@@ -86,7 +86,7 @@ async function createFullyInstalledConnection(projectId, location, connectionId,
|
|
|
86
86
|
});
|
|
87
87
|
while (conn.installationState.stage !== "COMPLETE") {
|
|
88
88
|
utils.logBullet("Install the Cloud Build GitHub app to enable access to GitHub repositories");
|
|
89
|
-
const targetUri = conn.installationState.actionUri
|
|
89
|
+
const targetUri = conn.installationState.actionUri;
|
|
90
90
|
utils.logBullet(targetUri);
|
|
91
91
|
await utils.openInBrowser(targetUri);
|
|
92
92
|
await (0, prompt_1.promptOnce)({
|
|
@@ -5,6 +5,7 @@ const error_1 = require("../../error");
|
|
|
5
5
|
const gcsm = require("../../gcp/secretManager");
|
|
6
6
|
const gcb = require("../../gcp/cloudbuild");
|
|
7
7
|
const gce = require("../../gcp/computeEngine");
|
|
8
|
+
const apphosting = require("../../gcp/apphosting");
|
|
8
9
|
const secretManager_1 = require("../../gcp/secretManager");
|
|
9
10
|
const secretManager_2 = require("../../gcp/secretManager");
|
|
10
11
|
const utils = require("../../utils");
|
|
@@ -33,7 +34,8 @@ function serviceAccountsForBackend(projectNumber, backend) {
|
|
|
33
34
|
};
|
|
34
35
|
}
|
|
35
36
|
exports.serviceAccountsForBackend = serviceAccountsForBackend;
|
|
36
|
-
async function grantSecretAccess(projectId, secretName, accounts) {
|
|
37
|
+
async function grantSecretAccess(projectId, projectNumber, secretName, accounts) {
|
|
38
|
+
const p4saEmail = apphosting.serviceAgentEmail(projectNumber);
|
|
37
39
|
const newBindings = [
|
|
38
40
|
{
|
|
39
41
|
role: "roles/secretmanager.secretAccessor",
|
|
@@ -43,6 +45,10 @@ async function grantSecretAccess(projectId, secretName, accounts) {
|
|
|
43
45
|
role: "roles/secretmanager.viewer",
|
|
44
46
|
members: accounts.buildServiceAccounts.map((sa) => `serviceAccount:${sa}`),
|
|
45
47
|
},
|
|
48
|
+
{
|
|
49
|
+
role: "roles/secretmanager.secretVersionManager",
|
|
50
|
+
members: [`serviceAccount:${p4saEmail}`],
|
|
51
|
+
},
|
|
46
52
|
];
|
|
47
53
|
let existingBindings;
|
|
48
54
|
try {
|
|
@@ -9,9 +9,9 @@ const apphosting_2 = require("../gcp/apphosting");
|
|
|
9
9
|
exports.command = new command_1.Command("apphosting:backends:create")
|
|
10
10
|
.description("create a Firebase App Hosting backend")
|
|
11
11
|
.option("-a, --app <webApp>", "specify an existing Firebase web app to associate your App Hosting backend with")
|
|
12
|
-
.option("-l, --location <location>", "specify the
|
|
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
|
|
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) => {
|
|
@@ -5,32 +5,21 @@ const command_1 = require("../command");
|
|
|
5
5
|
const projectUtils_1 = require("../projectUtils");
|
|
6
6
|
const error_1 = require("../error");
|
|
7
7
|
const prompt_1 = require("../prompt");
|
|
8
|
-
const constants_1 = require("../apphosting/constants");
|
|
9
8
|
const utils = require("../utils");
|
|
10
9
|
const apphosting = require("../gcp/apphosting");
|
|
11
10
|
const apphosting_backends_list_1 = require("./apphosting-backends-list");
|
|
12
11
|
const apphosting_1 = require("../apphosting");
|
|
13
12
|
exports.command = new command_1.Command("apphosting:backends:delete <backend>")
|
|
14
13
|
.description("delete a Firebase App Hosting backend")
|
|
15
|
-
.option("-l, --location <location>", "specify the
|
|
14
|
+
.option("-l, --location <location>", "specify the location of the backend", "")
|
|
16
15
|
.withForce()
|
|
17
16
|
.before(apphosting.ensureApiEnabled)
|
|
18
17
|
.action(async (backendId, options) => {
|
|
19
18
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
20
19
|
let location = options.location;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
if (!location) {
|
|
25
|
-
const allowedLocations = (await apphosting.listLocations(projectId)).map((loc) => loc.locationId);
|
|
26
|
-
location = await (0, prompt_1.promptOnce)({
|
|
27
|
-
name: "region",
|
|
28
|
-
type: "list",
|
|
29
|
-
default: constants_1.DEFAULT_REGION,
|
|
30
|
-
message: "Please select the region of the backend you'd like to delete:",
|
|
31
|
-
choices: allowedLocations,
|
|
32
|
-
});
|
|
33
|
-
}
|
|
20
|
+
location =
|
|
21
|
+
location ||
|
|
22
|
+
(await (0, apphosting_1.promptLocation)(projectId, "Please select the location of the backend you'd like to delete:"));
|
|
34
23
|
let backend;
|
|
35
24
|
try {
|
|
36
25
|
backend = await apphosting.getBackend(projectId, location, backendId);
|
|
@@ -8,7 +8,7 @@ const logger_1 = require("../logger");
|
|
|
8
8
|
const projectUtils_1 = require("../projectUtils");
|
|
9
9
|
const apphosting = require("../gcp/apphosting");
|
|
10
10
|
const Table = require("cli-table");
|
|
11
|
-
const TABLE_HEAD = ["Backend
|
|
11
|
+
const TABLE_HEAD = ["Backend", "Repository", "URL", "Location", "Updated Date"];
|
|
12
12
|
exports.command = new command_1.Command("apphosting:backends:list")
|
|
13
13
|
.description("list Firebase App Hosting backends")
|
|
14
14
|
.option("-l, --location <location>", "list backends in the specified location", "-")
|
|
@@ -39,9 +39,8 @@ function printBackendsTable(backends) {
|
|
|
39
39
|
table.push([
|
|
40
40
|
backendId,
|
|
41
41
|
(_c = (_b = (_a = backend.codebase) === null || _a === void 0 ? void 0 : _a.repository) === null || _b === void 0 ? void 0 : _b.split("/").pop()) !== null && _c !== void 0 ? _c : "",
|
|
42
|
-
backendLocation,
|
|
43
42
|
backend.uri.startsWith("https:") ? backend.uri : "https://" + backend.uri,
|
|
44
|
-
|
|
43
|
+
backendLocation,
|
|
45
44
|
(0, utils_1.datetimeString)(new Date(backend.updateTime)),
|
|
46
45
|
]);
|
|
47
46
|
}
|
|
@@ -8,7 +8,7 @@ const secretManager_1 = require("../gcp/secretManager");
|
|
|
8
8
|
const requireAuth_1 = require("../requireAuth");
|
|
9
9
|
const secretManager = require("../gcp/secretManager");
|
|
10
10
|
const requirePermissions_1 = require("../requirePermissions");
|
|
11
|
-
exports.command = new command_1.Command("apphosting:secrets:access <secretName
|
|
11
|
+
exports.command = new command_1.Command("apphosting:secrets:access <secretName[@version]>")
|
|
12
12
|
.description("Access secret value given secret and its version. Defaults to accessing the latest version.")
|
|
13
13
|
.before(requireAuth_1.requireAuth)
|
|
14
14
|
.before(secretManager.ensureApi)
|
|
@@ -9,6 +9,7 @@ const secretManager = require("../gcp/secretManager");
|
|
|
9
9
|
const requirePermissions_1 = require("../requirePermissions");
|
|
10
10
|
const apphosting = require("../gcp/apphosting");
|
|
11
11
|
const secrets = require("../apphosting/secrets");
|
|
12
|
+
const apphosting_1 = require("../apphosting");
|
|
12
13
|
exports.command = new command_1.Command("apphosting:secrets:grantaccess <secretName>")
|
|
13
14
|
.description("grant service accounts permissions to the provided secret")
|
|
14
15
|
.option("-l, --location <location>", "backend location")
|
|
@@ -27,13 +28,12 @@ exports.command = new command_1.Command("apphosting:secrets:grantaccess <secretN
|
|
|
27
28
|
.action(async (secretName, options) => {
|
|
28
29
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
29
30
|
const projectNumber = await (0, projectUtils_1.needProjectNumber)(options);
|
|
30
|
-
if (!options.location) {
|
|
31
|
-
throw new error_1.FirebaseError("Missing required flag --location. See firebase apphosting:secrets:grantaccess --help for more info");
|
|
32
|
-
}
|
|
33
|
-
const location = options.location;
|
|
34
31
|
if (!options.backend) {
|
|
35
32
|
throw new error_1.FirebaseError("Missing required flag --backend. See firebase apphosting:secrets:grantaccess --help for more info");
|
|
36
33
|
}
|
|
34
|
+
let location = options.location;
|
|
35
|
+
location =
|
|
36
|
+
location || (await (0, apphosting_1.promptLocation)(projectId, "Please select the location of your backend"));
|
|
37
37
|
const exists = await secretManager.secretExists(projectId, secretName);
|
|
38
38
|
if (!exists) {
|
|
39
39
|
throw new error_1.FirebaseError(`Cannot find secret ${secretName}`);
|
|
@@ -41,5 +41,5 @@ exports.command = new command_1.Command("apphosting:secrets:grantaccess <secretN
|
|
|
41
41
|
const backendId = options.backend;
|
|
42
42
|
const backend = await apphosting.getBackend(projectId, location, backendId);
|
|
43
43
|
const accounts = secrets.toMulti(secrets.serviceAccountsForBackend(projectNumber, backend));
|
|
44
|
-
await secrets.grantSecretAccess(projectId, secretName, accounts);
|
|
44
|
+
await secrets.grantSecretAccess(projectId, projectNumber, secretName, accounts);
|
|
45
45
|
});
|
|
@@ -50,7 +50,7 @@ exports.command = new command_1.Command("apphosting:secrets:set <secretName>")
|
|
|
50
50
|
utils.logWarning(`To use this secret in your backend, you must grant access. You can do so in the future with ${clc.bold("firebase apphosting:secrets:grantaccess")}`);
|
|
51
51
|
}
|
|
52
52
|
else {
|
|
53
|
-
await secrets.grantSecretAccess(projectId, secretName, accounts);
|
|
53
|
+
await secrets.grantSecretAccess(projectId, projectNumber, secretName, accounts);
|
|
54
54
|
}
|
|
55
55
|
await config.maybeAddSecretToYaml(secretName);
|
|
56
56
|
});
|
|
@@ -23,9 +23,9 @@ const EMULATOR_UPDATE_DETAILS = {
|
|
|
23
23
|
expectedChecksum: "2fd771101c0e1f7898c04c9204f2ce63",
|
|
24
24
|
},
|
|
25
25
|
firestore: {
|
|
26
|
-
version: "1.19.
|
|
27
|
-
expectedSize:
|
|
28
|
-
expectedChecksum: "
|
|
26
|
+
version: "1.19.5",
|
|
27
|
+
expectedSize: 66204670,
|
|
28
|
+
expectedChecksum: "6d9fb826605701668af722f25048ad95",
|
|
29
29
|
},
|
|
30
30
|
storage: {
|
|
31
31
|
version: "1.1.3",
|
|
@@ -147,6 +147,7 @@ const Commands = {
|
|
|
147
147
|
"single_project_mode",
|
|
148
148
|
],
|
|
149
149
|
joinArgs: false,
|
|
150
|
+
shell: false,
|
|
150
151
|
},
|
|
151
152
|
firestore: {
|
|
152
153
|
binary: "java",
|
|
@@ -168,6 +169,7 @@ const Commands = {
|
|
|
168
169
|
"single_project_mode",
|
|
169
170
|
],
|
|
170
171
|
joinArgs: false,
|
|
172
|
+
shell: false,
|
|
171
173
|
},
|
|
172
174
|
storage: {
|
|
173
175
|
binary: "java",
|
|
@@ -179,18 +181,21 @@ const Commands = {
|
|
|
179
181
|
],
|
|
180
182
|
optionalArgs: [],
|
|
181
183
|
joinArgs: false,
|
|
184
|
+
shell: false,
|
|
182
185
|
},
|
|
183
186
|
pubsub: {
|
|
184
187
|
binary: getExecPath(types_1.Emulators.PUBSUB),
|
|
185
188
|
args: [],
|
|
186
189
|
optionalArgs: ["port", "host"],
|
|
187
190
|
joinArgs: true,
|
|
191
|
+
shell: true,
|
|
188
192
|
},
|
|
189
193
|
ui: {
|
|
190
194
|
binary: "node",
|
|
191
195
|
args: [getExecPath(types_1.Emulators.UI)],
|
|
192
196
|
optionalArgs: [],
|
|
193
197
|
joinArgs: false,
|
|
198
|
+
shell: false,
|
|
194
199
|
},
|
|
195
200
|
};
|
|
196
201
|
function getExecPath(name) {
|
|
@@ -237,6 +242,7 @@ function _getCommand(emulator, args) {
|
|
|
237
242
|
args: cmdLineArgs,
|
|
238
243
|
optionalArgs: baseCmd.optionalArgs,
|
|
239
244
|
joinArgs: baseCmd.joinArgs,
|
|
245
|
+
shell: baseCmd.shell,
|
|
240
246
|
};
|
|
241
247
|
}
|
|
242
248
|
exports._getCommand = _getCommand;
|
|
@@ -273,11 +279,15 @@ async function _runBinary(emulator, command, extraEnv) {
|
|
|
273
279
|
const logger = emulatorLogger_1.EmulatorLogger.forEmulator(emulator.name);
|
|
274
280
|
emulator.stdout = fs.createWriteStream(getLogFileName(emulator.name));
|
|
275
281
|
try {
|
|
276
|
-
|
|
282
|
+
const opts = {
|
|
277
283
|
env: Object.assign(Object.assign({}, process.env), extraEnv),
|
|
278
284
|
detached: true,
|
|
279
285
|
stdio: ["inherit", "pipe", "pipe"],
|
|
280
|
-
}
|
|
286
|
+
};
|
|
287
|
+
if (command.shell && utils.IS_WINDOWS) {
|
|
288
|
+
opts.shell = true;
|
|
289
|
+
}
|
|
290
|
+
emulator.instance = childProcess.spawn(command.binary, command.args, opts);
|
|
281
291
|
}
|
|
282
292
|
catch (e) {
|
|
283
293
|
if (e.code === "EACCES") {
|
|
@@ -123,9 +123,9 @@ async function build(dir, target, context) {
|
|
|
123
123
|
headers.push(...headersFromMetaFiles);
|
|
124
124
|
if (appPathsManifest) {
|
|
125
125
|
const unrenderedServerComponents = (0, utils_2.getNonStaticServerComponents)(appPathsManifest, appPathRoutesManifest, prerenderedRoutes, dynamicRoutes);
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
unrenderedServerComponents.delete(
|
|
126
|
+
const notFoundPageKey = ["/_not-found", "/_not-found/page"].find((key) => unrenderedServerComponents.has(key));
|
|
127
|
+
if (notFoundPageKey && (await (0, utils_2.hasStaticAppNotFoundComponent)(dir, distDir))) {
|
|
128
|
+
unrenderedServerComponents.delete(notFoundPageKey);
|
|
129
129
|
}
|
|
130
130
|
for (const key of unrenderedServerComponents) {
|
|
131
131
|
reasonsForBackend.add(`non-static component ${key}`);
|
package/lib/functions/python.js
CHANGED
|
@@ -4,13 +4,14 @@ exports.runWithVirtualEnv = exports.virtualEnvCmd = exports.DEFAULT_VENV_DIR = v
|
|
|
4
4
|
const path = require("path");
|
|
5
5
|
const spawn = require("cross-spawn");
|
|
6
6
|
const logger_1 = require("../logger");
|
|
7
|
+
const utils_1 = require("../utils");
|
|
7
8
|
exports.DEFAULT_VENV_DIR = "venv";
|
|
8
9
|
function virtualEnvCmd(cwd, venvDir) {
|
|
9
|
-
const activateScriptPath =
|
|
10
|
+
const activateScriptPath = utils_1.IS_WINDOWS ? ["Scripts", "activate.bat"] : ["bin", "activate"];
|
|
10
11
|
const venvActivate = `"${path.join(cwd, venvDir, ...activateScriptPath)}"`;
|
|
11
12
|
return {
|
|
12
|
-
command:
|
|
13
|
-
args: [
|
|
13
|
+
command: utils_1.IS_WINDOWS ? venvActivate : ".",
|
|
14
|
+
args: [utils_1.IS_WINDOWS ? "" : venvActivate],
|
|
14
15
|
};
|
|
15
16
|
}
|
|
16
17
|
exports.virtualEnvCmd = virtualEnvCmd;
|
package/lib/gcp/apphosting.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getNextRolloutId = exports.ensureApiEnabled = exports.listLocations = exports.updateTraffic = exports.listRollouts = exports.createRollout = exports.createBuild = exports.listBuilds = exports.getBuild = exports.deleteBackend = exports.listBackends = exports.getBackend = exports.createBackend = exports.client = exports.API_VERSION = void 0;
|
|
3
|
+
exports.getNextRolloutId = exports.ensureApiEnabled = exports.listLocations = exports.updateTraffic = exports.listRollouts = exports.createRollout = exports.createBuild = exports.listBuilds = exports.getBuild = exports.deleteBackend = exports.listBackends = exports.getBackend = exports.createBackend = exports.serviceAgentEmail = exports.client = exports.API_VERSION = void 0;
|
|
4
4
|
const proto = require("../gcp/proto");
|
|
5
5
|
const apiv2_1 = require("../apiv2");
|
|
6
6
|
const projectUtils_1 = require("../projectUtils");
|
|
@@ -19,6 +19,11 @@ exports.client = new apiv2_1.Client({
|
|
|
19
19
|
(0, metaprogramming_1.assertImplements)();
|
|
20
20
|
(0, metaprogramming_1.assertImplements)();
|
|
21
21
|
(0, metaprogramming_1.assertImplements)();
|
|
22
|
+
const P4SA_DOMAIN = (0, api_1.apphostingP4SADomain)();
|
|
23
|
+
function serviceAgentEmail(projectNumber) {
|
|
24
|
+
return `service-${projectNumber}@${P4SA_DOMAIN}`;
|
|
25
|
+
}
|
|
26
|
+
exports.serviceAgentEmail = serviceAgentEmail;
|
|
22
27
|
async function createBackend(projectId, location, backendReqBoby, backendId) {
|
|
23
28
|
const res = await exports.client.post(`projects/${projectId}/locations/${location}/backends`, Object.assign(Object.assign({}, backendReqBoby), { labels: Object.assign(Object.assign({}, backendReqBoby.labels), deploymentTool.labels()) }), { queryParams: { backendId } });
|
|
24
29
|
return res.body;
|
package/lib/gcp/devConnect.js
CHANGED
|
@@ -84,7 +84,7 @@ async function getGitRepositoryLink(projectId, location, connectionId, gitReposi
|
|
|
84
84
|
}
|
|
85
85
|
exports.getGitRepositoryLink = getGitRepositoryLink;
|
|
86
86
|
function serviceAgentEmail(projectNumber) {
|
|
87
|
-
return `service-${projectNumber}@${(0, api_1.
|
|
87
|
+
return `service-${projectNumber}@${(0, api_1.developerConnectP4SADomain)()}`;
|
|
88
88
|
}
|
|
89
89
|
exports.serviceAgentEmail = serviceAgentEmail;
|
|
90
90
|
async function generateP4SA(projectNumber) {
|