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.
- package/lib/api.js +2 -2
- package/lib/commands/{frameworks-backends-create.js → apphosting-backends-create.js} +6 -3
- package/lib/commands/{frameworks-backends-delete.js → apphosting-backends-delete.js} +9 -7
- package/lib/commands/{frameworks-backends-get.js → apphosting-backends-get.js} +16 -27
- package/lib/commands/{frameworks-backends-list.js → apphosting-backends-list.js} +9 -19
- package/lib/commands/apphosting-builds-create.js +31 -0
- package/lib/commands/apphosting-builds-get.js +18 -0
- package/lib/commands/apphosting-rollouts-create.js +26 -0
- package/lib/commands/apphosting-rollouts-list.js +18 -0
- package/lib/commands/index.js +12 -6
- package/lib/deploy/functions/services/firestore.js +11 -1
- package/lib/frameworks/angular/index.js +5 -3
- package/lib/frameworks/angular/utils.js +19 -2
- package/lib/frameworks/astro/index.js +5 -2
- package/lib/frameworks/astro/utils.js +3 -2
- package/lib/frameworks/constants.js +31 -7
- package/lib/frameworks/index.js +12 -7
- package/lib/frameworks/next/index.js +24 -8
- package/lib/frameworks/next/utils.js +1 -1
- package/lib/frameworks/nuxt/index.js +15 -5
- package/lib/frameworks/nuxt2/index.js +5 -4
- package/lib/frameworks/sveltekit/index.js +2 -1
- package/lib/frameworks/utils.js +13 -9
- package/lib/frameworks/vite/index.js +19 -5
- package/lib/gcp/apphosting.js +89 -0
- package/lib/gcp/cloudbuild.js +5 -1
- package/lib/hosting/api.js +19 -1
- package/lib/init/features/{frameworks → apphosting}/constants.js +1 -2
- package/lib/init/features/apphosting/index.js +135 -0
- package/lib/init/features/{frameworks → apphosting}/repo.js +53 -28
- package/lib/init/features/hosting/index.js +1 -1
- package/lib/init/features/index.js +3 -3
- package/lib/init/index.js +0 -4
- package/lib/utils.js +26 -4
- package/package.json +1 -1
- package/lib/gcp/frameworks.js +0 -40
- 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.
|
|
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
|
|
13
|
-
const
|
|
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 `
|
|
48
|
+
return `apphosting-github-conn-${randomHash}`;
|
|
48
49
|
}
|
|
49
50
|
async function linkGitHubRepository(projectId, location) {
|
|
50
51
|
var _a, _b, _c;
|
|
51
|
-
|
|
52
|
-
const existingConns = await
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
86
|
-
utils.logSuccess(
|
|
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,
|
|
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 >
|
|
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
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
213
|
+
async function listAppHostingConnections(projectId) {
|
|
189
214
|
const conns = await gcb.listConnections(projectId, "-");
|
|
190
|
-
return conns.filter((conn) =>
|
|
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.
|
|
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.
|
|
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
|
|
27
|
-
Object.defineProperty(exports, "
|
|
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
|
-
|
|
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
package/lib/gcp/frameworks.js
DELETED
|
@@ -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;
|