Skip to content

Commit 0576d13

Browse files
joehangoogle-labs-jules[bot]gemini-code-assist[bot]
authored
feat(init): split hosting setup into askQuestions and actuate (#9338)
* feat(init): split hosting setup into askQuestions and actuate Refactors the hosting feature's `doSetup` function into `askQuestions` and `actuate` functions, following the pattern of other features like `firestore` and `database`. This change separates user interaction from the actuation of changes, improving modularity and maintainability. * revert shrinkwrap * revert shrinkwrap * Substanial cleanup and simplification * Apply suggestion from @gemini-code-assist[bot] Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Apply suggestion from @gemini-code-assist[bot] Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * fix test --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent 9297d8e commit 0576d13

File tree

12 files changed

+190
-150
lines changed

12 files changed

+190
-150
lines changed

src/commands/deploy.ts

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ import { requireHostingSite } from "../requireHostingSite";
1010
import { errNoDefaultSite } from "../getDefaultHostingSite";
1111
import { FirebaseError } from "../error";
1212
import { bold } from "colorette";
13-
import { interactiveCreateHostingSite } from "../hosting/interactive";
13+
import { pickHostingSiteName } from "../hosting/interactive";
1414
import { logBullet } from "../utils";
15+
import { createSite } from "../hosting/api";
16+
import { Options } from "../options";
1517

1618
// in order of least time-consuming to most time-consuming
1719
export const VALID_DEPLOY_TARGETS = [
@@ -98,26 +100,26 @@ export const command = new Command("deploy")
98100
"In order to provide better validation, this may still enable APIs on the target project",
99101
)
100102
.before(requireConfig)
101-
.before((options) => {
103+
.before((options: Options) => {
102104
options.filteredTargets = filterTargets(options, VALID_DEPLOY_TARGETS);
103105
const permissions = options.filteredTargets.reduce((perms: string[], target: string) => {
104106
return perms.concat(TARGET_PERMISSIONS[target]);
105107
}, []);
106108
return requirePermissions(options, permissions);
107109
})
108-
.before((options) => {
110+
.before((options: Options) => {
109111
if (options.filteredTargets.includes("functions")) {
110-
return checkServiceAccountIam(options.project);
112+
return checkServiceAccountIam(options.project!);
111113
}
112114
})
113-
.before(async (options) => {
115+
.before(async (options: Options) => {
114116
// only fetch the default instance for hosting or database deploys
115117
if (options.filteredTargets.includes("database")) {
116118
await requireDatabaseInstance(options);
117119
}
118120

119121
if (options.filteredTargets.includes("hosting")) {
120-
let createSite = false;
122+
let shouldCreateSite = false;
121123
try {
122124
await requireHostingSite(options);
123125
} catch (err: unknown) {
@@ -128,10 +130,10 @@ export const command = new Command("deploy")
128130
if (isPermissionError) {
129131
throw err;
130132
} else if (err === errNoDefaultSite) {
131-
createSite = true;
133+
shouldCreateSite = true;
132134
}
133135
}
134-
if (!createSite) {
136+
if (!shouldCreateSite) {
135137
return;
136138
}
137139
if (options.nonInteractive) {
@@ -142,7 +144,8 @@ export const command = new Command("deploy")
142144
);
143145
}
144146
logBullet("No Hosting site detected.");
145-
await interactiveCreateHostingSite("", "", options);
147+
const siteId = await pickHostingSiteName("", options);
148+
await createSite(options.project!, siteId);
146149
}
147150
})
148151
.before(checkValidTargetFilters)

src/commands/hosting-sites-create.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import { bold } from "colorette";
22

33
import { Command } from "../command";
4-
import { interactiveCreateHostingSite } from "../hosting/interactive";
5-
import { last, logLabeledSuccess } from "../utils";
4+
import { pickHostingSiteName } from "../hosting/interactive";
5+
import { logLabeledSuccess } from "../utils";
66
import { logger } from "../logger";
77
import { needProjectId } from "../projectUtils";
88
import { Options } from "../options";
99
import { requirePermissions } from "../requirePermissions";
10-
import { Site } from "../hosting/api";
10+
import { createSite, Site } from "../hosting/api";
1111
import { FirebaseError } from "../error";
1212

1313
const LOG_TAG = "hosting:sites";
@@ -16,16 +16,16 @@ export const command = new Command("hosting:sites:create [siteId]")
1616
.description("create a Firebase Hosting site")
1717
.option("--app <appId>", "specify an existing Firebase Web App ID")
1818
.before(requirePermissions, ["firebasehosting.sites.update"])
19-
.action(async (siteId: string, options: Options & { app: string }): Promise<Site> => {
19+
.action(async (siteId: string | undefined, options: Options & { app: string }): Promise<Site> => {
2020
const projectId = needProjectId(options);
2121
const appId = options.app;
2222

2323
if (options.nonInteractive && !siteId) {
24-
throw new FirebaseError(`${bold(siteId)} is required in a non-interactive environment`);
24+
throw new FirebaseError(`${bold("siteId")} is required in a non-interactive environment`);
2525
}
2626

27-
const site = await interactiveCreateHostingSite(siteId, appId, options);
28-
siteId = last(site.name.split("/"));
27+
siteId = await pickHostingSiteName(siteId ?? "", options);
28+
const site = await createSite(projectId, siteId, appId);
2929

3030
logger.info();
3131
logLabeledSuccess(

src/frameworks/angular/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export async function discover(dir: string): Promise<Discovery | undefined> {
4747

4848
export function init(setup: any, config: any) {
4949
execSync(
50-
`npx --yes -p @angular/cli@"${supportedRange}" ng new ${setup.projectId} --directory ${setup.hosting.source} --skip-git`,
50+
`npx --yes -p @angular/cli@"${supportedRange}" ng new ${setup.projectId} --directory ${setup.featureInfo.hosting.source} --skip-git`,
5151
{
5252
stdio: "inherit",
5353
cwd: config.projectDir,

src/frameworks/flutter/index.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ describe("Flutter", () => {
139139

140140
const stub = sandbox.stub(crossSpawn, "sync").returns(process as any);
141141

142-
const result = init({ projectId, hosting: { source } }, { projectDir });
142+
const result = init({ projectId, featureInfo: { hosting: { source } } }, { projectDir });
143143

144144
expect(await result).to.eql(undefined);
145145
sinon.assert.calledWith(

src/frameworks/flutter/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export function init(setup: any, config: any) {
3636
`--project-name=${projectName}`,
3737
"--overwrite",
3838
"--platforms=web",
39-
setup.hosting.source,
39+
setup.featureInfo.hosting.source,
4040
],
4141
{ stdio: "inherit", cwd: config.projectDir },
4242
);

src/frameworks/next/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -387,7 +387,7 @@ export async function init(setup: any, config: any) {
387387
});
388388
execSync(
389389
`npx --yes create-next-app@"${supportedRange}" -e hello-world ` +
390-
`${setup.hosting.source} --use-npm --${language}`,
390+
`${setup.featureInfo.hosting.source} --use-npm --${language}`,
391391
{ stdio: "inherit", cwd: config.projectDir },
392392
);
393393
}

src/frameworks/nuxt/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ export async function getConfig(cwd: string): Promise<NuxtOptions> {
116116
* Utility method used during project initialization.
117117
*/
118118
export function init(setup: any, config: any) {
119-
execSync(`npx --yes nuxi@"${supportedRange}" init ${setup.hosting.source}`, {
119+
execSync(`npx --yes nuxi@"${supportedRange}" init ${setup.featureInfo.hosting.source}`, {
120120
stdio: "inherit",
121121
cwd: config.projectDir,
122122
});

src/frameworks/vite/index.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,16 @@ export async function init(setup: any, config: any, baseTemplate: string = "vani
3434
],
3535
});
3636
execSync(
37-
`npm create vite@"${supportedRange}" ${setup.hosting.source} --yes -- --template ${template}`,
37+
`npm create vite@"${supportedRange}" ${setup.featureInfo.hosting.source} --yes -- --template ${template}`,
3838
{
3939
stdio: "inherit",
4040
cwd: config.projectDir,
4141
},
4242
);
43-
execSync(`npm install`, { stdio: "inherit", cwd: join(config.projectDir, setup.hosting.source) });
43+
execSync(`npm install`, {
44+
stdio: "inherit",
45+
cwd: join(config.projectDir, setup.featureInfo.hosting.source),
46+
});
4447
}
4548

4649
export const viteDiscoverWithNpmDependency = (dep: string) => async (dir: string) =>

src/hosting/interactive.ts

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { FirebaseError } from "../error";
22
import { logWarning } from "../utils";
33
import { needProjectId, needProjectNumber } from "../projectUtils";
4-
import { Site, createSite } from "./api";
4+
import { createSite } from "./api";
55
import { input } from "../prompt";
66

77
const nameSuggestion = new RegExp("try something like `(.+)`");
@@ -11,17 +11,16 @@ const prompt =
1111
'We recommend using letters, numbers, and hyphens (e.g. "{project-id}-{random-hash}"):';
1212

1313
/**
14-
* Interactively prompt to create a Hosting site.
14+
* Interactively prompt to name a Hosting site.
1515
*/
16-
export async function interactiveCreateHostingSite(
16+
export async function pickHostingSiteName(
1717
siteId: string,
18-
appId: string,
1918
options: { projectId?: string; nonInteractive?: boolean },
20-
): Promise<Site> {
19+
): Promise<string> {
2120
const projectId = needProjectId(options);
2221
const projectNumber = await needProjectNumber(options);
2322
let id = siteId;
24-
let newSite: Site | undefined;
23+
let nameConfirmed: boolean = false;
2524
let suggestion: string | undefined;
2625

2726
// If we were given an ID, we're going to start with that, so don't check the project ID.
@@ -35,34 +34,26 @@ export async function interactiveCreateHostingSite(
3534
}
3635
}
3736

38-
while (!newSite) {
37+
while (!nameConfirmed) {
3938
if (!id || suggestion) {
4039
id = await input({
4140
message: prompt,
4241
validate: (s: string) => s.length > 0, // Prevents an empty string from being submitted!
4342
default: suggestion,
4443
});
4544
}
46-
try {
47-
newSite = await createSite(projectNumber, id, appId);
48-
} catch (err: unknown) {
49-
if (!(err instanceof FirebaseError)) {
50-
throw err;
51-
}
52-
if (options.nonInteractive) {
53-
throw err;
54-
}
55-
56-
id = ""; // Clear so the prompt comes back.
57-
suggestion = getSuggestionFromError(err);
58-
}
45+
const attempt = await trySiteID(projectNumber, id, options.nonInteractive);
46+
nameConfirmed = attempt.available;
47+
suggestion = attempt.suggestion;
48+
if (!nameConfirmed) id = ""; // Clear so the prompt comes back.
5949
}
60-
return newSite;
50+
return id;
6151
}
6252

6353
async function trySiteID(
6454
projectNumber: string,
6555
id: string,
56+
nonInteractive = false,
6657
): Promise<{ available: boolean; suggestion?: string }> {
6758
try {
6859
await createSite(projectNumber, id, "", true);
@@ -71,6 +62,9 @@ async function trySiteID(
7162
if (!(err instanceof FirebaseError)) {
7263
throw err;
7364
}
65+
if (nonInteractive) {
66+
throw err;
67+
}
7468
const suggestion = getSuggestionFromError(err);
7569
return { available: false, suggestion };
7670
}

0 commit comments

Comments
 (0)