firebase-tools 13.0.0 → 13.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/commands/frameworks-backends-create.js +2 -0
- package/lib/commands/frameworks-backends-delete.js +2 -0
- package/lib/commands/frameworks-backends-get.js +4 -7
- package/lib/commands/frameworks-backends-list.js +7 -12
- 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 +3 -3
- package/lib/frameworks/next/index.js +6 -4
- 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/cloudbuild.js +5 -1
- package/lib/gcp/frameworks.js +9 -1
- package/lib/init/features/frameworks/index.js +49 -71
- package/lib/init/features/frameworks/repo.js +40 -15
- package/lib/init/features/hosting/index.js +1 -1
- package/lib/utils.js +5 -3
- package/package.json +1 -1
|
@@ -5,8 +5,10 @@ const command_1 = require("../command");
|
|
|
5
5
|
const projectUtils_1 = require("../projectUtils");
|
|
6
6
|
const requireInteractive_1 = require("../requireInteractive");
|
|
7
7
|
const frameworks_1 = require("../init/features/frameworks");
|
|
8
|
+
const frameworks_2 = require("../gcp/frameworks");
|
|
8
9
|
exports.command = new command_1.Command("backends:create")
|
|
9
10
|
.description("Create a backend in a Firebase project")
|
|
11
|
+
.before(frameworks_2.ensureApiEnabled)
|
|
10
12
|
.before(requireInteractive_1.default)
|
|
11
13
|
.action(async (options) => {
|
|
12
14
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
@@ -9,6 +9,7 @@ const prompt_1 = require("../prompt");
|
|
|
9
9
|
const utils = require("../utils");
|
|
10
10
|
const logger_1 = require("../logger");
|
|
11
11
|
const constants_1 = require("../init/features/frameworks/constants");
|
|
12
|
+
const frameworks_1 = require("../gcp/frameworks");
|
|
12
13
|
const Table = require("cli-table");
|
|
13
14
|
const COLUMN_LENGTH = 20;
|
|
14
15
|
const TABLE_HEAD = [
|
|
@@ -24,6 +25,7 @@ exports.command = new command_1.Command("backends:delete")
|
|
|
24
25
|
.option("-l, --location <location>", "App Backend location", "")
|
|
25
26
|
.option("-s, --backend <backend>", "Backend Id", "")
|
|
26
27
|
.withForce()
|
|
28
|
+
.before(frameworks_1.ensureApiEnabled)
|
|
27
29
|
.action(async (options) => {
|
|
28
30
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
29
31
|
let location = options.location;
|
|
@@ -6,6 +6,7 @@ const projectUtils_1 = require("../projectUtils");
|
|
|
6
6
|
const gcp = require("../gcp/frameworks");
|
|
7
7
|
const error_1 = require("../error");
|
|
8
8
|
const logger_1 = require("../logger");
|
|
9
|
+
const frameworks_1 = require("../gcp/frameworks");
|
|
9
10
|
const Table = require("cli-table");
|
|
10
11
|
const COLUMN_LENGTH = 20;
|
|
11
12
|
const TABLE_HEAD = [
|
|
@@ -16,17 +17,13 @@ const TABLE_HEAD = [
|
|
|
16
17
|
"Created Date",
|
|
17
18
|
"Updated Date",
|
|
18
19
|
];
|
|
19
|
-
exports.command = new command_1.Command("backends:get")
|
|
20
|
+
exports.command = new command_1.Command("backends:get <backendId>")
|
|
20
21
|
.description("Get backend details of a Firebase project")
|
|
21
22
|
.option("-l, --location <location>", "App Backend location", "-")
|
|
22
|
-
.
|
|
23
|
-
.action(async (options) => {
|
|
23
|
+
.before(frameworks_1.ensureApiEnabled)
|
|
24
|
+
.action(async (backendId, options) => {
|
|
24
25
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
25
26
|
const location = options.location;
|
|
26
|
-
const backendId = options.backend;
|
|
27
|
-
if (!backendId) {
|
|
28
|
-
throw new error_1.FirebaseError("Backend id can't be empty.");
|
|
29
|
-
}
|
|
30
27
|
let backendsList = [];
|
|
31
28
|
const table = new Table({
|
|
32
29
|
head: TABLE_HEAD,
|
|
@@ -7,19 +7,14 @@ const gcp = require("../gcp/frameworks");
|
|
|
7
7
|
const error_1 = require("../error");
|
|
8
8
|
const logger_1 = require("../logger");
|
|
9
9
|
const colorette_1 = require("colorette");
|
|
10
|
+
const frameworks_1 = require("../gcp/frameworks");
|
|
10
11
|
const Table = require("cli-table");
|
|
11
12
|
const COLUMN_LENGTH = 20;
|
|
12
|
-
const TABLE_HEAD = [
|
|
13
|
-
"Backend Id",
|
|
14
|
-
"Repository Name",
|
|
15
|
-
"Location",
|
|
16
|
-
"URL",
|
|
17
|
-
"Created Date",
|
|
18
|
-
"Updated Date",
|
|
19
|
-
];
|
|
13
|
+
const TABLE_HEAD = ["Backend Id", "Repository", "Location", "URL", "Created Date", "Updated Date"];
|
|
20
14
|
exports.command = new command_1.Command("backends:list")
|
|
21
15
|
.description("List backends of a Firebase project.")
|
|
22
16
|
.option("-l, --location <location>", "App Backend location", "-")
|
|
17
|
+
.before(frameworks_1.ensureApiEnabled)
|
|
23
18
|
.action(async (options) => {
|
|
24
19
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
25
20
|
const location = options.location;
|
|
@@ -31,8 +26,8 @@ exports.command = new command_1.Command("backends:list")
|
|
|
31
26
|
const backendsList = [];
|
|
32
27
|
try {
|
|
33
28
|
const backendsPerRegion = await gcp.listBackends(projectId, location);
|
|
34
|
-
backendsList.push(backendsPerRegion);
|
|
35
|
-
populateTable(
|
|
29
|
+
backendsList.push(...backendsPerRegion.backends);
|
|
30
|
+
populateTable(backendsList, table);
|
|
36
31
|
logger_1.logger.info();
|
|
37
32
|
logger_1.logger.info(`Backends for project ${(0, colorette_1.bold)(projectId)}`);
|
|
38
33
|
logger_1.logger.info();
|
|
@@ -43,9 +38,9 @@ exports.command = new command_1.Command("backends:list")
|
|
|
43
38
|
}
|
|
44
39
|
return backendsList;
|
|
45
40
|
});
|
|
46
|
-
function populateTable(
|
|
41
|
+
function populateTable(backends, table) {
|
|
47
42
|
var _a;
|
|
48
|
-
for (const backend of
|
|
43
|
+
for (const backend of backends) {
|
|
49
44
|
const [location, , backendId] = backend.name.split("/").slice(3, 6);
|
|
50
45
|
const entry = [
|
|
51
46
|
backendId,
|
|
@@ -3,9 +3,19 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ensureFirestoreTriggerRegion = void 0;
|
|
4
4
|
const firestore = require("../../../gcp/firestore");
|
|
5
5
|
const error_1 = require("../../../error");
|
|
6
|
+
const dbCache = new Map();
|
|
7
|
+
async function getDatabase(project, databaseId) {
|
|
8
|
+
const key = `${project}/${databaseId}`;
|
|
9
|
+
if (dbCache.has(key)) {
|
|
10
|
+
return dbCache.get(key);
|
|
11
|
+
}
|
|
12
|
+
const db = await firestore.getDatabase(project, databaseId);
|
|
13
|
+
dbCache.set(key, db);
|
|
14
|
+
return db;
|
|
15
|
+
}
|
|
6
16
|
async function ensureFirestoreTriggerRegion(endpoint) {
|
|
7
17
|
var _a;
|
|
8
|
-
const db = await
|
|
18
|
+
const db = await getDatabase(endpoint.project, ((_a = endpoint.eventTrigger.eventFilters) === null || _a === void 0 ? void 0 : _a.database) || "(default)");
|
|
9
19
|
const dbRegion = db.locationId;
|
|
10
20
|
if (!endpoint.eventTrigger.region) {
|
|
11
21
|
endpoint.eventTrigger.region = dbRegion;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ɵcodegenFunctionsDirectory = exports.shouldUseDevModeHandle = exports.getValidBuildTargets = exports.ɵcodegenPublicDirectory = exports.getDevModeHandle = exports.build = exports.init = exports.discover = exports.docsUrl = exports.type = exports.support = exports.name = void 0;
|
|
3
|
+
exports.ɵcodegenFunctionsDirectory = exports.shouldUseDevModeHandle = exports.getValidBuildTargets = exports.ɵcodegenPublicDirectory = exports.getDevModeHandle = exports.build = exports.init = exports.discover = exports.supportedRange = exports.docsUrl = exports.type = exports.support = exports.name = void 0;
|
|
4
4
|
const path_1 = require("path");
|
|
5
5
|
const child_process_1 = require("child_process");
|
|
6
6
|
const cross_spawn_1 = require("cross-spawn");
|
|
@@ -15,16 +15,18 @@ exports.support = "preview";
|
|
|
15
15
|
exports.type = 3;
|
|
16
16
|
exports.docsUrl = "https://firebase.google.com/docs/hosting/frameworks/angular";
|
|
17
17
|
const DEFAULT_BUILD_SCRIPT = ["ng build"];
|
|
18
|
+
exports.supportedRange = "14 - 17";
|
|
18
19
|
async function discover(dir) {
|
|
19
20
|
if (!(await (0, fs_extra_1.pathExists)((0, path_1.join)(dir, "package.json"))))
|
|
20
21
|
return;
|
|
21
22
|
if (!(await (0, fs_extra_1.pathExists)((0, path_1.join)(dir, "angular.json"))))
|
|
22
23
|
return;
|
|
23
|
-
|
|
24
|
+
const version = (0, utils_2.getAngularVersion)(dir);
|
|
25
|
+
return { mayWantBackend: true, publicDirectory: (0, path_1.join)(dir, "src", "assets"), version };
|
|
24
26
|
}
|
|
25
27
|
exports.discover = discover;
|
|
26
28
|
function init(setup, config) {
|
|
27
|
-
(0, child_process_1.execSync)(`npx --yes -p @angular/cli@
|
|
29
|
+
(0, child_process_1.execSync)(`npx --yes -p @angular/cli@"${exports.supportedRange}" ng new ${setup.projectId} --directory ${setup.hosting.source} --skip-git`, {
|
|
28
30
|
stdio: "inherit",
|
|
29
31
|
cwd: config.projectDir,
|
|
30
32
|
});
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getBuildConfig = exports.getServerConfig = exports.getBrowserConfig = exports.getContext = exports.getAllTargets = void 0;
|
|
3
|
+
exports.getAngularVersion = exports.getBuildConfig = exports.getServerConfig = exports.getBrowserConfig = exports.getContext = exports.getAllTargets = void 0;
|
|
4
4
|
const utils_1 = require("../utils");
|
|
5
5
|
const error_1 = require("../../error");
|
|
6
6
|
const path_1 = require("path");
|
|
7
7
|
const assert_1 = require("assert");
|
|
8
8
|
const utils_2 = require("../../utils");
|
|
9
|
+
const semver_1 = require("semver");
|
|
9
10
|
async function localesForTarget(dir, architectHost, target, workspaceProject) {
|
|
10
11
|
var _a;
|
|
11
12
|
const { targetStringFromTarget } = (0, utils_1.relativeRequire)(dir, "@angular-devkit/architect");
|
|
@@ -182,7 +183,9 @@ async function getContext(dir, targetOrConfiguration) {
|
|
|
182
183
|
}
|
|
183
184
|
}
|
|
184
185
|
if (deployTarget) {
|
|
185
|
-
const options = await architectHost
|
|
186
|
+
const options = await architectHost
|
|
187
|
+
.getOptionsForTarget(deployTarget)
|
|
188
|
+
.catch(() => { var _a; return (_a = workspaceProject.targets.get(deployTarget.target)) === null || _a === void 0 ? void 0 : _a.options; });
|
|
186
189
|
if (!options)
|
|
187
190
|
throw new error_1.FirebaseError("Unable to get options for ng-deploy.");
|
|
188
191
|
if (options.buildTarget) {
|
|
@@ -201,6 +204,10 @@ async function getContext(dir, targetOrConfiguration) {
|
|
|
201
204
|
(0, utils_2.assertIsString)(options.serverTarget);
|
|
202
205
|
serverTarget = targetFromTargetString(options.serverTarget);
|
|
203
206
|
}
|
|
207
|
+
if (options.serveTarget) {
|
|
208
|
+
(0, utils_2.assertIsString)(options.serveTarget);
|
|
209
|
+
serveTarget = targetFromTargetString(options.serveTarget);
|
|
210
|
+
}
|
|
204
211
|
if (options.serveOptimizedImages) {
|
|
205
212
|
serveOptimizedImages = true;
|
|
206
213
|
}
|
|
@@ -441,3 +448,13 @@ async function getBuildConfig(sourceDir, configuration) {
|
|
|
441
448
|
};
|
|
442
449
|
}
|
|
443
450
|
exports.getBuildConfig = getBuildConfig;
|
|
451
|
+
function getAngularVersion(cwd) {
|
|
452
|
+
const dependency = (0, utils_1.findDependency)("@angular/core", { cwd, depth: 0, omitDev: false });
|
|
453
|
+
if (!dependency)
|
|
454
|
+
return undefined;
|
|
455
|
+
const angularVersionSemver = (0, semver_1.coerce)(dependency.version);
|
|
456
|
+
if (!angularVersionSemver)
|
|
457
|
+
return dependency.version;
|
|
458
|
+
return angularVersionSemver.toString();
|
|
459
|
+
}
|
|
460
|
+
exports.getAngularVersion = getAngularVersion;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getDevModeHandle = exports.ɵcodegenFunctionsDirectory = exports.ɵcodegenPublicDirectory = exports.build = exports.discover = exports.type = exports.support = exports.name = void 0;
|
|
3
|
+
exports.getDevModeHandle = exports.ɵcodegenFunctionsDirectory = exports.ɵcodegenPublicDirectory = exports.build = exports.discover = exports.supportedRange = exports.type = exports.support = exports.name = void 0;
|
|
4
4
|
const cross_spawn_1 = require("cross-spawn");
|
|
5
5
|
const fs_extra_1 = require("fs-extra");
|
|
6
6
|
const path_1 = require("path");
|
|
@@ -10,15 +10,18 @@ const utils_2 = require("./utils");
|
|
|
10
10
|
exports.name = "Astro";
|
|
11
11
|
exports.support = "experimental";
|
|
12
12
|
exports.type = 2;
|
|
13
|
+
exports.supportedRange = "2 - 3";
|
|
13
14
|
async function discover(dir) {
|
|
14
15
|
if (!(0, fs_extra_1.existsSync)((0, path_1.join)(dir, "package.json")))
|
|
15
16
|
return;
|
|
16
|
-
|
|
17
|
+
const version = (0, utils_2.getAstroVersion)(dir);
|
|
18
|
+
if (!version)
|
|
17
19
|
return;
|
|
18
20
|
const { output, publicDir: publicDirectory } = await (0, utils_2.getConfig)(dir);
|
|
19
21
|
return {
|
|
20
22
|
mayWantBackend: output !== "static",
|
|
21
23
|
publicDirectory,
|
|
24
|
+
version,
|
|
22
25
|
};
|
|
23
26
|
}
|
|
24
27
|
exports.discover = discover;
|
|
@@ -4,6 +4,7 @@ exports.getAstroVersion = exports.getConfig = exports.getBootstrapScript = void
|
|
|
4
4
|
const path_1 = require("path");
|
|
5
5
|
const utils_1 = require("../utils");
|
|
6
6
|
const semver_1 = require("semver");
|
|
7
|
+
const url_1 = require("url");
|
|
7
8
|
const { dynamicImport } = require(true && "../../dynamicImport");
|
|
8
9
|
function getBootstrapScript() {
|
|
9
10
|
return `const entry = import('./entry.mjs');\nexport const handle = async (req, res) => (await entry).handler(req, res)`;
|
|
@@ -26,8 +27,8 @@ async function getConfig(cwd) {
|
|
|
26
27
|
config = astroConfig;
|
|
27
28
|
}
|
|
28
29
|
return {
|
|
29
|
-
outDir: (0, path_1.relative)(cwd, config.outDir
|
|
30
|
-
publicDir: (0, path_1.relative)(cwd, config.publicDir
|
|
30
|
+
outDir: (0, path_1.relative)(cwd, (0, url_1.fileURLToPath)(config.outDir)),
|
|
31
|
+
publicDir: (0, path_1.relative)(cwd, (0, url_1.fileURLToPath)(config.publicDir)),
|
|
31
32
|
output: config.output,
|
|
32
33
|
adapter: config.adapter,
|
|
33
34
|
};
|
|
@@ -6,10 +6,10 @@ const experiments = require("../experiments");
|
|
|
6
6
|
exports.NPM_COMMAND_TIMEOUT_MILLIES = 10000;
|
|
7
7
|
exports.SupportLevelWarnings = {
|
|
8
8
|
["experimental"]: (framework) => `Thank you for trying our ${clc.italic("experimental")} support for ${framework} on Firebase Hosting.
|
|
9
|
-
${clc.
|
|
9
|
+
${clc.red(`While this integration is maintained by Googlers it is not a supported Firebase product.
|
|
10
10
|
Issues filed on GitHub will be addressed on a best-effort basis by maintainers and other community members.`)}`,
|
|
11
11
|
["preview"]: (framework) => `Thank you for trying our ${clc.italic("early preview")} of ${framework} support on Firebase Hosting.
|
|
12
|
-
${clc.
|
|
12
|
+
${clc.red("During the preview, support is best-effort and breaking changes can be expected. Proceed with caution.")}`,
|
|
13
13
|
};
|
|
14
14
|
exports.DEFAULT_DOCS_URL = "https://firebase.google.com/docs/hosting/frameworks/frameworks-overview";
|
|
15
15
|
exports.FILE_BUG_URL = "https://github.com/firebase/firebase-tools/issues/new?template=bug_report.md";
|
|
@@ -26,11 +26,35 @@ exports.VALID_ENGINES = { node: [16, 18, 20] };
|
|
|
26
26
|
exports.VALID_LOCALE_FORMATS = [/^ALL_[a-z]+$/, /^[a-z]+_ALL$/, /^[a-z]+(_[a-z]+)?$/];
|
|
27
27
|
exports.DEFAULT_REGION = "us-central1";
|
|
28
28
|
exports.ALLOWED_SSR_REGIONS = [
|
|
29
|
-
{ name: "us-central1 (Iowa)", value: "us-central1" },
|
|
30
|
-
{ name: "us-
|
|
31
|
-
{ name: "us-
|
|
32
|
-
{ name: "
|
|
33
|
-
{ name: "
|
|
29
|
+
{ name: "us-central1 (Iowa)", value: "us-central1", recommended: true },
|
|
30
|
+
{ name: "us-east1 (South Carolina)", value: "us-east1", recommended: true },
|
|
31
|
+
{ name: "us-east4 (Northern Virginia)", value: "us-east4" },
|
|
32
|
+
{ name: "us-west1 (Oregon)", value: "us-west1", recommended: true },
|
|
33
|
+
{ name: "us-west2 (Los Angeles)", value: "us-west2" },
|
|
34
|
+
{ name: "us-west3 (Salt Lake City)", value: "us-west3" },
|
|
35
|
+
{ name: "us-west4 (Las Vegas)", value: "us-west4" },
|
|
36
|
+
{ name: "asia-east1 (Taiwan)", value: "asia-east1", recommended: true },
|
|
37
|
+
{ name: "asia-east2 (Hong Kong)", value: "asia-east2" },
|
|
38
|
+
{ name: "asia-northeast1 (Tokyo)", value: "asia-northeast1" },
|
|
39
|
+
{ name: "asia-northeast2 (Osaka)", value: "asia-northeast2" },
|
|
40
|
+
{ name: "asia-northeast3 (Seoul)", value: "asia-northeast3" },
|
|
41
|
+
{ name: "asia-south1 (Mumbai)", value: "asia-south1" },
|
|
42
|
+
{ name: "asia-south2 (Delhi)", value: "asia-south2" },
|
|
43
|
+
{ name: "asia-southeast1 (Singapore)", value: "asia-southeast1" },
|
|
44
|
+
{ name: "asia-southeast2 (Jakarta)", value: "asia-southeast2" },
|
|
45
|
+
{ name: "australia-southeast1 (Sydney)", value: "australia-southeast1" },
|
|
46
|
+
{ name: "australia-southeast2 (Melbourne)", value: "australia-southeast2" },
|
|
47
|
+
{ name: "europe-central2 (Warsaw)", value: "europe-central2" },
|
|
48
|
+
{ name: "europe-north1 (Finland)", value: "europe-north1" },
|
|
49
|
+
{ name: "europe-west1 (Belgium)", value: "europe-west1", recommended: true },
|
|
50
|
+
{ name: "europe-west2 (London)", value: "europe-west2" },
|
|
51
|
+
{ name: "europe-west3 (Frankfurt)", value: "europe-west3" },
|
|
52
|
+
{ name: "europe-west4 (Netherlands)", value: "europe-west4" },
|
|
53
|
+
{ name: "europe-west6 (Zurich)", value: "europe-west6" },
|
|
54
|
+
{ name: "northamerica-northeast1 (Montreal)", value: "northamerica-northeast1" },
|
|
55
|
+
{ name: "northamerica-northeast2 (Toronto)", value: "northamerica-northeast2" },
|
|
56
|
+
{ name: "southamerica-east1 (São Paulo)", value: "southamerica-east1" },
|
|
57
|
+
{ name: "southamerica-west1 (Santiago)", value: "southamerica-west1" },
|
|
34
58
|
];
|
|
35
59
|
exports.I18N_ROOT = "/";
|
|
36
60
|
function GET_DEFAULT_BUILD_TARGETS() {
|
package/lib/frameworks/index.js
CHANGED
|
@@ -119,7 +119,7 @@ async function prepareFrameworks(purpose, targetNames, context, options, emulato
|
|
|
119
119
|
throw new error_1.FirebaseError(`Hosting config for site ${site} places server-side content in region ${ssrRegion} which is not known. Valid regions are ${validRegions}`);
|
|
120
120
|
}
|
|
121
121
|
const getProjectPath = (...args) => (0, path_1.join)(projectRoot, source, ...args);
|
|
122
|
-
const functionId = `ssr${site.toLowerCase().replace(/-/g, "")}`;
|
|
122
|
+
const functionId = `ssr${site.toLowerCase().replace(/-/g, "").substring(0, 20)}`;
|
|
123
123
|
const usesFirebaseAdminSdk = !!(0, utils_1.findDependency)("firebase-admin", { cwd: getProjectPath() });
|
|
124
124
|
const usesFirebaseJsSdk = !!(0, utils_1.findDependency)("@firebase/app", { cwd: getProjectPath() });
|
|
125
125
|
if (usesFirebaseAdminSdk) {
|
|
@@ -190,8 +190,8 @@ async function prepareFrameworks(purpose, targetNames, context, options, emulato
|
|
|
190
190
|
throw new error_1.FirebaseError((0, utils_1.frameworksCallToAction)("Unable to detect the web framework in use, check firebase-debug.log for more info."));
|
|
191
191
|
}
|
|
192
192
|
const { framework, mayWantBackend, publicDirectory } = results;
|
|
193
|
-
const { build, ɵcodegenPublicDirectory, ɵcodegenFunctionsDirectory: codegenProdModeFunctionsDirectory, getDevModeHandle, name, support, docsUrl, getValidBuildTargets = constants_2.GET_DEFAULT_BUILD_TARGETS, shouldUseDevModeHandle = constants_2.DEFAULT_SHOULD_USE_DEV_MODE_HANDLE, } = frameworks_1.WebFrameworks[framework];
|
|
194
|
-
logger_1.logger.info(`\n${(0, utils_1.frameworksCallToAction)(constants_2.SupportLevelWarnings[support](name), docsUrl, " ")}\n`);
|
|
193
|
+
const { build, ɵcodegenPublicDirectory, ɵcodegenFunctionsDirectory: codegenProdModeFunctionsDirectory, getDevModeHandle, name, support, docsUrl, supportedRange, getValidBuildTargets = constants_2.GET_DEFAULT_BUILD_TARGETS, shouldUseDevModeHandle = constants_2.DEFAULT_SHOULD_USE_DEV_MODE_HANDLE, } = frameworks_1.WebFrameworks[framework];
|
|
194
|
+
logger_1.logger.info(`\n${(0, utils_1.frameworksCallToAction)(constants_2.SupportLevelWarnings[support](name), docsUrl, " ", name, results.version, supportedRange, results.vite)}\n`);
|
|
195
195
|
const hostingEmulatorInfo = emulators.find((e) => e.name === types_1.Emulators.HOSTING);
|
|
196
196
|
const validBuildTargets = await getValidBuildTargets(purpose, getProjectPath());
|
|
197
197
|
const frameworksBuildTarget = (0, utils_1.getFrameworksBuildTarget)(purpose, validBuildTargets);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getDevModeHandle = exports.ɵcodegenFunctionsDirectory = exports.ɵcodegenPublicDirectory = exports.init = exports.build = exports.discover = exports.docsUrl = exports.type = exports.support = exports.name = void 0;
|
|
3
|
+
exports.getDevModeHandle = exports.ɵcodegenFunctionsDirectory = exports.ɵcodegenPublicDirectory = exports.init = exports.build = exports.discover = exports.docsUrl = exports.type = exports.support = exports.name = exports.supportedRange = void 0;
|
|
4
4
|
const child_process_1 = require("child_process");
|
|
5
5
|
const cross_spawn_1 = require("cross-spawn");
|
|
6
6
|
const promises_1 = require("fs/promises");
|
|
@@ -25,6 +25,7 @@ const api_1 = require("../../hosting/api");
|
|
|
25
25
|
const logger_1 = require("../../logger");
|
|
26
26
|
const DEFAULT_BUILD_SCRIPT = ["next build"];
|
|
27
27
|
const PUBLIC_DIR = "public";
|
|
28
|
+
exports.supportedRange = "12 - 14.0";
|
|
28
29
|
exports.name = "Next.js";
|
|
29
30
|
exports.support = "preview";
|
|
30
31
|
exports.type = 2;
|
|
@@ -38,9 +39,10 @@ function getReactVersion(cwd) {
|
|
|
38
39
|
async function discover(dir) {
|
|
39
40
|
if (!(await (0, fs_extra_1.pathExists)((0, path_1.join)(dir, "package.json"))))
|
|
40
41
|
return;
|
|
41
|
-
|
|
42
|
+
const version = (0, utils_2.getNextVersion)(dir);
|
|
43
|
+
if (!(await (0, fs_extra_1.pathExists)("next.config.js")) && !version)
|
|
42
44
|
return;
|
|
43
|
-
return { mayWantBackend: true, publicDirectory: (0, path_1.join)(dir, PUBLIC_DIR) };
|
|
45
|
+
return { mayWantBackend: true, publicDirectory: (0, path_1.join)(dir, PUBLIC_DIR), version };
|
|
44
46
|
}
|
|
45
47
|
exports.discover = discover;
|
|
46
48
|
async function build(dir) {
|
|
@@ -186,7 +188,7 @@ async function init(setup, config) {
|
|
|
186
188
|
message: "What language would you like to use?",
|
|
187
189
|
choices: ["JavaScript", "TypeScript"],
|
|
188
190
|
});
|
|
189
|
-
(0, child_process_1.execSync)(`npx --yes create-next-app@
|
|
191
|
+
(0, child_process_1.execSync)(`npx --yes create-next-app@"${exports.supportedRange}" -e hello-world ${setup.hosting.source} --use-npm ${language === "TypeScript" ? "--ts" : "--js"}`, { stdio: "inherit", cwd: config.projectDir });
|
|
190
192
|
}
|
|
191
193
|
exports.init = init;
|
|
192
194
|
async function ɵcodegenPublicDirectory(sourceDir, destDir, _, context) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getConfig = exports.getDevModeHandle = exports.ɵcodegenFunctionsDirectory = exports.ɵcodegenPublicDirectory = exports.build = exports.discover = exports.type = exports.support = exports.name = void 0;
|
|
3
|
+
exports.init = exports.getConfig = exports.getDevModeHandle = exports.ɵcodegenFunctionsDirectory = exports.ɵcodegenPublicDirectory = exports.build = exports.discover = exports.supportedRange = exports.type = exports.support = exports.name = void 0;
|
|
4
4
|
const fs_extra_1 = require("fs-extra");
|
|
5
5
|
const promises_1 = require("fs/promises");
|
|
6
6
|
const path_1 = require("path");
|
|
@@ -11,20 +11,22 @@ const utils_2 = require("./utils");
|
|
|
11
11
|
exports.name = "Nuxt";
|
|
12
12
|
exports.support = "experimental";
|
|
13
13
|
exports.type = 4;
|
|
14
|
+
exports.supportedRange = "3";
|
|
14
15
|
const utils_3 = require("./utils");
|
|
15
16
|
const error_1 = require("../../error");
|
|
17
|
+
const child_process_1 = require("child_process");
|
|
16
18
|
const DEFAULT_BUILD_SCRIPT = ["nuxt build", "nuxi build"];
|
|
17
19
|
async function discover(dir) {
|
|
18
20
|
if (!(await (0, fs_extra_1.pathExists)((0, path_1.join)(dir, "package.json"))))
|
|
19
21
|
return;
|
|
20
22
|
const anyConfigFileExists = await (0, utils_3.nuxtConfigFilesExist)(dir);
|
|
21
|
-
const
|
|
22
|
-
if (!anyConfigFileExists && !
|
|
23
|
+
const version = (0, utils_2.getNuxtVersion)(dir);
|
|
24
|
+
if (!anyConfigFileExists && !version)
|
|
23
25
|
return;
|
|
24
|
-
if (
|
|
26
|
+
if (version && (0, semver_1.lt)(version, "3.0.0-0"))
|
|
25
27
|
return;
|
|
26
28
|
const { dir: { public: publicDirectory }, ssr: mayWantBackend, } = await getConfig(dir);
|
|
27
|
-
return { publicDirectory, mayWantBackend };
|
|
29
|
+
return { publicDirectory, mayWantBackend, version };
|
|
28
30
|
}
|
|
29
31
|
exports.discover = discover;
|
|
30
32
|
async function build(cwd) {
|
|
@@ -90,3 +92,11 @@ async function getConfig(dir) {
|
|
|
90
92
|
return await loadNuxtConfig(dir);
|
|
91
93
|
}
|
|
92
94
|
exports.getConfig = getConfig;
|
|
95
|
+
function init(setup, config) {
|
|
96
|
+
(0, child_process_1.execSync)(`npx --yes nuxi@"${exports.supportedRange}" init ${setup.hosting.source}`, {
|
|
97
|
+
stdio: "inherit",
|
|
98
|
+
cwd: config.projectDir,
|
|
99
|
+
});
|
|
100
|
+
return Promise.resolve();
|
|
101
|
+
}
|
|
102
|
+
exports.init = init;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getDevModeHandle = exports.ɵcodegenFunctionsDirectory = exports.ɵcodegenPublicDirectory = exports.build = exports.discover = exports.type = exports.support = exports.name = void 0;
|
|
3
|
+
exports.getDevModeHandle = exports.ɵcodegenFunctionsDirectory = exports.ɵcodegenPublicDirectory = exports.build = exports.discover = exports.supportedRange = exports.type = exports.support = exports.name = void 0;
|
|
4
4
|
const fs_extra_1 = require("fs-extra");
|
|
5
5
|
const promises_1 = require("fs/promises");
|
|
6
6
|
const path_1 = require("path");
|
|
@@ -12,6 +12,7 @@ const cross_spawn_1 = require("cross-spawn");
|
|
|
12
12
|
exports.name = "Nuxt";
|
|
13
13
|
exports.support = "experimental";
|
|
14
14
|
exports.type = 2;
|
|
15
|
+
exports.supportedRange = "2";
|
|
15
16
|
async function getAndLoadNuxt(options) {
|
|
16
17
|
const nuxt = await (0, utils_1.relativeRequire)(options.rootDir, "nuxt/dist/nuxt.js");
|
|
17
18
|
const app = await nuxt.loadNuxt(options);
|
|
@@ -21,11 +22,11 @@ async function getAndLoadNuxt(options) {
|
|
|
21
22
|
async function discover(rootDir) {
|
|
22
23
|
if (!(await (0, fs_extra_1.pathExists)((0, path_1.join)(rootDir, "package.json"))))
|
|
23
24
|
return;
|
|
24
|
-
const
|
|
25
|
-
if (!
|
|
25
|
+
const version = (0, utils_2.getNuxtVersion)(rootDir);
|
|
26
|
+
if (!version || (version && (0, semver_1.gte)(version, "3.0.0-0")))
|
|
26
27
|
return;
|
|
27
28
|
const { app } = await getAndLoadNuxt({ rootDir, for: "build" });
|
|
28
|
-
return { mayWantBackend: true, publicDirectory: app.options.dir.static };
|
|
29
|
+
return { mayWantBackend: true, publicDirectory: app.options.dir.static, version };
|
|
29
30
|
}
|
|
30
31
|
exports.discover = discover;
|
|
31
32
|
async function build(rootDir) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ɵcodegenFunctionsDirectory = exports.ɵcodegenPublicDirectory = exports.build = exports.getDevModeHandle = exports.discover = exports.type = exports.support = exports.name = void 0;
|
|
3
|
+
exports.ɵcodegenFunctionsDirectory = exports.ɵcodegenPublicDirectory = exports.build = exports.supportedRange = exports.getDevModeHandle = exports.discover = exports.type = exports.support = exports.name = void 0;
|
|
4
4
|
const fs_extra_1 = require("fs-extra");
|
|
5
5
|
const path_1 = require("path");
|
|
6
6
|
const vite_1 = require("../vite");
|
|
@@ -12,6 +12,7 @@ exports.type = 2;
|
|
|
12
12
|
exports.discover = (0, vite_1.viteDiscoverWithNpmDependency)("@sveltejs/kit");
|
|
13
13
|
var vite_2 = require("../vite");
|
|
14
14
|
Object.defineProperty(exports, "getDevModeHandle", { enumerable: true, get: function () { return vite_2.getDevModeHandle; } });
|
|
15
|
+
Object.defineProperty(exports, "supportedRange", { enumerable: true, get: function () { return vite_2.supportedRange; } });
|
|
15
16
|
async function build(root) {
|
|
16
17
|
var _a;
|
|
17
18
|
const config = await getConfig(root);
|
package/lib/frameworks/utils.js
CHANGED
|
@@ -7,6 +7,7 @@ const promises_1 = require("fs/promises");
|
|
|
7
7
|
const http_1 = require("http");
|
|
8
8
|
const cross_spawn_1 = require("cross-spawn");
|
|
9
9
|
const clc = require("colorette");
|
|
10
|
+
const semver_1 = require("semver");
|
|
10
11
|
const logger_1 = require("../logger");
|
|
11
12
|
const error_1 = require("../error");
|
|
12
13
|
const fsutils_1 = require("../fsutils");
|
|
@@ -206,20 +207,23 @@ function relativeRequire(dir, mod) {
|
|
|
206
207
|
}
|
|
207
208
|
}
|
|
208
209
|
exports.relativeRequire = relativeRequire;
|
|
209
|
-
function conjoinOptions(
|
|
210
|
-
if (!
|
|
211
|
-
return;
|
|
210
|
+
function conjoinOptions(_opts, conjunction = "and", separator = ",") {
|
|
211
|
+
if (!_opts.length)
|
|
212
|
+
return "";
|
|
213
|
+
const opts = _opts.map((it) => it.toString().trim());
|
|
212
214
|
if (opts.length === 1)
|
|
213
|
-
return opts[0]
|
|
215
|
+
return opts[0];
|
|
214
216
|
if (opts.length === 2)
|
|
215
|
-
return `${opts[0]
|
|
216
|
-
const lastElement = opts.slice(-1)[0]
|
|
217
|
-
const allButLast = opts.slice(0, -1)
|
|
217
|
+
return `${opts[0]} ${conjunction} ${opts[1]}`;
|
|
218
|
+
const lastElement = opts.slice(-1)[0];
|
|
219
|
+
const allButLast = opts.slice(0, -1);
|
|
218
220
|
return `${allButLast.join(`${separator} `)}${separator} ${conjunction} ${lastElement}`;
|
|
219
221
|
}
|
|
220
222
|
exports.conjoinOptions = conjoinOptions;
|
|
221
|
-
function frameworksCallToAction(message, docsUrl = constants_1.DEFAULT_DOCS_URL, prefix = "") {
|
|
222
|
-
return `${prefix}${message}
|
|
223
|
+
function frameworksCallToAction(message, docsUrl = constants_1.DEFAULT_DOCS_URL, prefix = "", framework, version, supportedRange, vite = false) {
|
|
224
|
+
return `${prefix}${message}${framework && supportedRange && (!version || !(0, semver_1.satisfies)(version, supportedRange))
|
|
225
|
+
? clc.yellow(`\n${prefix}The integration is known to work with ${vite ? "Vite" : framework} version ${clc.italic(conjoinOptions(supportedRange.split("||")))}. You may encounter errors.`)
|
|
226
|
+
: ``}
|
|
223
227
|
|
|
224
228
|
${prefix}${clc.bold("Documentation:")} ${docsUrl}
|
|
225
229
|
${prefix}${clc.bold("File a bug:")} ${constants_1.FILE_BUG_URL}
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getDevModeHandle = exports.ɵcodegenPublicDirectory = exports.build = exports.discover = exports.vitePluginDiscover = exports.viteDiscoverWithNpmDependency = exports.init = exports.initViteTemplate = exports.DEFAULT_BUILD_SCRIPT = exports.type = exports.support = exports.name = void 0;
|
|
3
|
+
exports.getDevModeHandle = exports.ɵcodegenPublicDirectory = exports.build = exports.discover = exports.vitePluginDiscover = exports.viteDiscoverWithNpmDependency = exports.init = exports.initViteTemplate = exports.DEFAULT_BUILD_SCRIPT = exports.supportedRange = exports.type = exports.support = exports.name = void 0;
|
|
4
4
|
const child_process_1 = require("child_process");
|
|
5
5
|
const cross_spawn_1 = require("cross-spawn");
|
|
6
6
|
const fs_1 = require("fs");
|
|
7
7
|
const fs_extra_1 = require("fs-extra");
|
|
8
8
|
const path_1 = require("path");
|
|
9
|
+
const strip_ansi_1 = require("strip-ansi");
|
|
9
10
|
const prompt_1 = require("../../prompt");
|
|
10
11
|
const utils_1 = require("../utils");
|
|
11
12
|
exports.name = "Vite";
|
|
12
13
|
exports.support = "experimental";
|
|
13
14
|
exports.type = 4;
|
|
15
|
+
exports.supportedRange = "3 - 5";
|
|
14
16
|
exports.DEFAULT_BUILD_SCRIPT = ["vite build", "tsc && vite build"];
|
|
15
17
|
const initViteTemplate = (template) => async (setup, config) => await init(setup, config, template);
|
|
16
18
|
exports.initViteTemplate = initViteTemplate;
|
|
@@ -24,7 +26,7 @@ async function init(setup, config, baseTemplate = "vanilla") {
|
|
|
24
26
|
{ name: "TypeScript", value: `${baseTemplate}-ts` },
|
|
25
27
|
],
|
|
26
28
|
});
|
|
27
|
-
(0, child_process_1.execSync)(`npm create vite@
|
|
29
|
+
(0, child_process_1.execSync)(`npm create vite@"${exports.supportedRange}" ${setup.hosting.source} --yes -- --template ${template}`, {
|
|
28
30
|
stdio: "inherit",
|
|
29
31
|
cwd: config.projectDir,
|
|
30
32
|
});
|
|
@@ -36,6 +38,7 @@ exports.viteDiscoverWithNpmDependency = viteDiscoverWithNpmDependency;
|
|
|
36
38
|
const vitePluginDiscover = (plugin) => async (dir) => await discover(dir, plugin);
|
|
37
39
|
exports.vitePluginDiscover = vitePluginDiscover;
|
|
38
40
|
async function discover(dir, plugin, npmDependency) {
|
|
41
|
+
var _a;
|
|
39
42
|
if (!(0, fs_1.existsSync)((0, path_1.join)(dir, "package.json")))
|
|
40
43
|
return;
|
|
41
44
|
const additionalDep = npmDependency && (0, utils_1.findDependency)(npmDependency, { cwd: dir, depth: 0, omitDev: false });
|
|
@@ -45,14 +48,24 @@ async function discover(dir, plugin, npmDependency) {
|
|
|
45
48
|
(0, fs_extra_1.pathExists)((0, path_1.join)(dir, "vite.config.ts")),
|
|
46
49
|
]);
|
|
47
50
|
const anyConfigFileExists = configFilesExist.some((it) => it);
|
|
48
|
-
|
|
51
|
+
const version = (_a = (0, utils_1.findDependency)("vite", {
|
|
52
|
+
cwd: dir,
|
|
53
|
+
depth,
|
|
54
|
+
omitDev: false,
|
|
55
|
+
})) === null || _a === void 0 ? void 0 : _a.version;
|
|
56
|
+
if (!anyConfigFileExists && !version)
|
|
49
57
|
return;
|
|
50
58
|
if (npmDependency && !additionalDep)
|
|
51
59
|
return;
|
|
52
60
|
const { appType, publicDir: publicDirectory, plugins } = await getConfig(dir);
|
|
53
61
|
if (plugin && !plugins.find(({ name }) => name === plugin))
|
|
54
62
|
return;
|
|
55
|
-
return {
|
|
63
|
+
return {
|
|
64
|
+
mayWantBackend: appType !== "spa",
|
|
65
|
+
publicDirectory,
|
|
66
|
+
version,
|
|
67
|
+
vite: true,
|
|
68
|
+
};
|
|
56
69
|
}
|
|
57
70
|
exports.discover = discover;
|
|
58
71
|
async function build(root) {
|
|
@@ -77,7 +90,8 @@ async function getDevModeHandle(dir) {
|
|
|
77
90
|
const serve = (0, cross_spawn_1.spawn)(cli, [], { cwd: dir });
|
|
78
91
|
serve.stdout.on("data", (data) => {
|
|
79
92
|
process.stdout.write(data);
|
|
80
|
-
const
|
|
93
|
+
const dataWithoutAnsiCodes = (0, strip_ansi_1.default)(data.toString());
|
|
94
|
+
const match = dataWithoutAnsiCodes.match(/(http:\/\/.+:\d+)/);
|
|
81
95
|
if (match)
|
|
82
96
|
resolve(match[1]);
|
|
83
97
|
});
|
package/lib/gcp/cloudbuild.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.deleteRepository = exports.getRepository = exports.createRepository = exports.fetchLinkableRepositories = exports.deleteConnection = exports.listConnections = exports.getConnection = exports.createConnection = void 0;
|
|
3
|
+
exports.serviceAgentEmail = exports.deleteRepository = exports.getRepository = exports.createRepository = exports.fetchLinkableRepositories = exports.deleteConnection = exports.listConnections = exports.getConnection = exports.createConnection = void 0;
|
|
4
4
|
const apiv2_1 = require("../apiv2");
|
|
5
5
|
const api_1 = require("../api");
|
|
6
6
|
const PAGE_SIZE_MAX = 100;
|
|
@@ -69,3 +69,7 @@ async function deleteRepository(projectId, location, connectionId, repositoryId)
|
|
|
69
69
|
return res.body;
|
|
70
70
|
}
|
|
71
71
|
exports.deleteRepository = deleteRepository;
|
|
72
|
+
function serviceAgentEmail(projectNumber) {
|
|
73
|
+
return `service-${projectNumber}@gcp-sa-cloudbuild.iam.gserviceaccount.com`;
|
|
74
|
+
}
|
|
75
|
+
exports.serviceAgentEmail = serviceAgentEmail;
|
package/lib/gcp/frameworks.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createBuild = exports.deleteBackend = exports.listBackends = exports.getBackend = exports.createBackend = exports.API_VERSION = void 0;
|
|
3
|
+
exports.ensureApiEnabled = exports.createBuild = exports.deleteBackend = exports.listBackends = exports.getBackend = exports.createBackend = exports.API_VERSION = exports.API_HOST = void 0;
|
|
4
4
|
const apiv2_1 = require("../apiv2");
|
|
5
|
+
const projectUtils_1 = require("../projectUtils");
|
|
5
6
|
const api_1 = require("../api");
|
|
7
|
+
const ensureApiEnabled_1 = require("../ensureApiEnabled");
|
|
8
|
+
exports.API_HOST = new URL(api_1.frameworksOrigin).host;
|
|
6
9
|
exports.API_VERSION = "v1alpha";
|
|
7
10
|
const client = new apiv2_1.Client({
|
|
8
11
|
urlPrefix: api_1.frameworksOrigin,
|
|
@@ -38,3 +41,8 @@ async function createBuild(projectId, location, backendId, buildInput) {
|
|
|
38
41
|
return res.body;
|
|
39
42
|
}
|
|
40
43
|
exports.createBuild = createBuild;
|
|
44
|
+
async function ensureApiEnabled(options) {
|
|
45
|
+
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
46
|
+
return await (0, ensureApiEnabled_1.ensure)(projectId, exports.API_HOST, "frameworks", true);
|
|
47
|
+
}
|
|
48
|
+
exports.ensureApiEnabled = ensureApiEnabled;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createBackend = exports.
|
|
3
|
+
exports.createBackend = exports.onboardBackend = exports.doSetup = void 0;
|
|
4
4
|
const clc = require("colorette");
|
|
5
|
-
const utils = require("../../../utils");
|
|
6
5
|
const repo = require("./repo");
|
|
7
6
|
const poller = require("../../../operation-poller");
|
|
8
7
|
const gcp = require("../../../gcp/frameworks");
|
|
8
|
+
const utils_1 = require("../../../utils");
|
|
9
9
|
const api_1 = require("../../../api");
|
|
10
10
|
const frameworks_1 = require("../../../gcp/frameworks");
|
|
11
11
|
const error_1 = require("../../../error");
|
|
12
|
-
const logger_1 = require("../../../logger");
|
|
13
12
|
const prompt_1 = require("../../../prompt");
|
|
14
13
|
const constants_1 = require("./constants");
|
|
14
|
+
const ensureApiEnabled_1 = require("../../../ensureApiEnabled");
|
|
15
15
|
const frameworksPollerOptions = {
|
|
16
16
|
apiOrigin: api_1.frameworksOrigin,
|
|
17
17
|
apiVersion: frameworks_1.API_VERSION,
|
|
@@ -20,36 +20,52 @@ const frameworksPollerOptions = {
|
|
|
20
20
|
};
|
|
21
21
|
async function doSetup(setup, projectId) {
|
|
22
22
|
setup.frameworks = {};
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
await (0, prompt_1.promptOnce)({
|
|
23
|
+
await Promise.all([
|
|
24
|
+
(0, ensureApiEnabled_1.ensure)(projectId, "cloudbuild.googleapis.com", "frameworks", true),
|
|
25
|
+
(0, ensureApiEnabled_1.ensure)(projectId, "secretmanager.googleapis.com", "frameworks", true),
|
|
26
|
+
(0, ensureApiEnabled_1.ensure)(projectId, "run.googleapis.com", "frameworks", true),
|
|
27
|
+
(0, ensureApiEnabled_1.ensure)(projectId, "artifactregistry.googleapis.com", "frameworks", true),
|
|
28
|
+
]);
|
|
29
|
+
(0, utils_1.logBullet)("First we need a few details to create your backend.");
|
|
30
|
+
const location = await (0, prompt_1.promptOnce)({
|
|
31
31
|
name: "region",
|
|
32
32
|
type: "list",
|
|
33
33
|
default: constants_1.DEFAULT_REGION,
|
|
34
34
|
message: "Please select a region " +
|
|
35
35
|
`(${clc.yellow("info")}: Your region determines where your backend is located):\n`,
|
|
36
36
|
choices: constants_1.ALLOWED_REGIONS,
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
});
|
|
38
|
+
(0, utils_1.logSuccess)(`Region set to ${location}.\n`);
|
|
39
|
+
let backendId;
|
|
40
|
+
while (true) {
|
|
41
|
+
backendId = await (0, prompt_1.promptOnce)({
|
|
42
|
+
name: "backendId",
|
|
43
|
+
type: "input",
|
|
44
|
+
default: "acme-inc-web",
|
|
45
|
+
message: "Create a name for your backend [1-30 characters]",
|
|
46
|
+
});
|
|
47
|
+
try {
|
|
48
|
+
await gcp.getBackend(projectId, location, backendId);
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
if (err.status === 404) {
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
throw new error_1.FirebaseError(`Failed to check if backend with id ${backendId} already exists in ${location}`, { original: err });
|
|
55
|
+
}
|
|
56
|
+
(0, utils_1.logWarning)(`Backend with id ${backendId} already exists in ${location}`);
|
|
57
|
+
}
|
|
58
|
+
const backend = await onboardBackend(projectId, location, backendId);
|
|
40
59
|
if (backend) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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();
|
|
60
|
+
(0, utils_1.logSuccess)(`Successfully created backend:\n\t${backend.name}`);
|
|
61
|
+
(0, utils_1.logSuccess)(`Your site is being deployed at:\n\thttps://${backend.uri}`);
|
|
62
|
+
(0, utils_1.logSuccess)(`View the rollout status by running:\n\tfirebase backends:get ${backendId} --project ${projectId}`);
|
|
48
63
|
}
|
|
49
64
|
}
|
|
50
65
|
exports.doSetup = doSetup;
|
|
51
66
|
function toBackend(cloudBuildConnRepo) {
|
|
52
67
|
return {
|
|
68
|
+
servingLocality: "GLOBAL_ACCESS",
|
|
53
69
|
codebase: {
|
|
54
70
|
repository: `${cloudBuildConnRepo.name}`,
|
|
55
71
|
rootDirectory: "/",
|
|
@@ -57,57 +73,19 @@ function toBackend(cloudBuildConnRepo) {
|
|
|
57
73
|
labels: {},
|
|
58
74
|
};
|
|
59
75
|
}
|
|
60
|
-
async function
|
|
61
|
-
const
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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;
|
|
76
|
+
async function onboardBackend(projectId, location, backendId) {
|
|
77
|
+
const cloudBuildConnRepo = await repo.linkGitHubRepository(projectId, location);
|
|
78
|
+
const barnchName = await (0, prompt_1.promptOnce)({
|
|
79
|
+
name: "branchName",
|
|
80
|
+
type: "input",
|
|
81
|
+
default: "main",
|
|
82
|
+
message: "Which branch do you want to deploy?",
|
|
83
|
+
});
|
|
84
|
+
void barnchName;
|
|
85
|
+
const backendDetails = toBackend(cloudBuildConnRepo);
|
|
86
|
+
return await createBackend(projectId, location, backendDetails, backendId);
|
|
110
87
|
}
|
|
88
|
+
exports.onboardBackend = onboardBackend;
|
|
111
89
|
async function createBackend(projectId, location, backendReqBoby, backendId) {
|
|
112
90
|
const op = await gcp.createBackend(projectId, location, backendReqBoby, backendId);
|
|
113
91
|
const backend = await poller.pollOperation(Object.assign(Object.assign({}, frameworksPollerOptions), { pollerName: `create-${projectId}-${location}-${backendId}`, operationResourceName: op.name }));
|
|
@@ -3,12 +3,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.listFrameworksConnections = 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 getProjectNumber_1 = require("../../../getProjectNumber");
|
|
12
13
|
const FRAMEWORKS_CONN_PATTERN = /.+\/frameworks-github-conn-.+$/;
|
|
13
14
|
const FRAMEWORKS_OAUTH_CONN_NAME = "frameworks-github-oauth";
|
|
14
15
|
const CONNECTION_NAME_REGEX = /^projects\/(?<projectId>[^\/]+)\/locations\/(?<location>[^\/]+)\/connections\/(?<id>[^\/]+)$/;
|
|
@@ -48,9 +49,13 @@ function generateConnectionId() {
|
|
|
48
49
|
}
|
|
49
50
|
async function linkGitHubRepository(projectId, location) {
|
|
50
51
|
var _a, _b, _c;
|
|
51
|
-
|
|
52
|
+
utils.logBullet(clc.bold(`${clc.yellow("===")} Set up a GitHub connection`));
|
|
52
53
|
const existingConns = await listFrameworksConnections(projectId);
|
|
53
54
|
if (existingConns.length < 1) {
|
|
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
|
+
}
|
|
54
59
|
let oauthConn = await getOrCreateConnection(projectId, location, FRAMEWORKS_OAUTH_CONN_NAME);
|
|
55
60
|
while (oauthConn.installationState.stage === "PENDING_USER_OAUTH") {
|
|
56
61
|
oauthConn = await promptConnectionAuth(oauthConn);
|
|
@@ -82,8 +87,8 @@ 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;
|
|
@@ -92,7 +97,7 @@ async function promptRepositoryUri(projectId, location, connections) {
|
|
|
92
97
|
for (const conn of connections) {
|
|
93
98
|
const { 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) {
|
|
@@ -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,
|
package/lib/utils.js
CHANGED
|
@@ -506,10 +506,12 @@ 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;
|