Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
- Added `functions.list_functions` as a MCP tool (#9369)
- Added AI Logic to `firebase init` CLI command and `firebase_init` MCP tool. (#9185)
- Improved error messages for Firebase AI Logic provisioning during 'firebase init' (#9377)
- Fixed issue where CLI fails to prompt for the public directory and set up Hosting files (#9403)
97 changes: 49 additions & 48 deletions src/init/features/hosting/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@

// TODO: come up with a better way to type this
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export async function askQuestions(setup: Setup, config: Config, options: Options): Promise<void> {

Check warning on line 39 in src/init/features/hosting/index.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Missing JSDoc comment
setup.featureInfo = setup.featureInfo || {};
setup.featureInfo.hosting = {};

Expand Down Expand Up @@ -68,10 +68,11 @@
}
}

let discoveredFramework = experiments.isEnabled("webframeworks")
? await discover(config.projectDir, false)
: undefined;

if (experiments.isEnabled("webframeworks")) {
let discoveredFramework = experiments.isEnabled("webframeworks")
? await discover(config.projectDir, false)
: undefined;
// First, if we're in a framework directory, ask to use that.
if (
discoveredFramework &&
Expand All @@ -90,54 +91,53 @@
`Do you want to use a web framework? (${clc.bold("experimental")})`,
);
}
// If they say yes, ask for source directory if its not already known
if (setup.featureInfo.hosting.useWebFrameworks) {
setup.featureInfo.hosting.source ??= await input({
message: "What folder would you like to use for your web application's root directory?",
default: "hosting",
});
}

discoveredFramework = await discover(
join(config.projectDir, setup.featureInfo.hosting.source),
);
// If they say yes, ask for source directory if its not already known
if (setup.featureInfo.hosting.useWebFrameworks) {
setup.featureInfo.hosting.source ??= await input({
message: "What folder would you like to use for your web application's root directory?",
default: "hosting",
});

if (discoveredFramework) {
const name = WebFrameworks[discoveredFramework.framework].name;
setup.featureInfo.hosting.useDiscoveredFramework ??= await confirm({
message: `Detected an existing ${name} codebase in ${setup.featureInfo.hosting.source}, should we use this?`,
default: true,
});
if (setup.featureInfo.hosting.useDiscoveredFramework)
setup.featureInfo.hosting.webFramework = discoveredFramework.framework;
}
discoveredFramework = await discover(join(config.projectDir, setup.featureInfo.hosting.source));

// If it is not known already, ask what framework to use.
const choices: { name: string; value: string }[] = [];
for (const value in WebFrameworks) {
if (WebFrameworks[value]) {
const { name, init } = WebFrameworks[value];
if (init) choices.push({ name, value });
}
if (discoveredFramework) {
const name = WebFrameworks[discoveredFramework.framework].name;
setup.featureInfo.hosting.useDiscoveredFramework ??= await confirm({
message: `Detected an existing ${name} codebase in ${setup.featureInfo.hosting.source}, should we use this?`,
default: true,
});
if (setup.featureInfo.hosting.useDiscoveredFramework)
setup.featureInfo.hosting.webFramework = discoveredFramework.framework;
}

// If it is not known already, ask what framework to use.
const choices: { name: string; value: string }[] = [];
for (const value in WebFrameworks) {
if (WebFrameworks[value]) {
const { name, init } = WebFrameworks[value];
if (init) choices.push({ name, value });
}
}

const defaultChoice = choices.find(
({ value }) => value === discoveredFramework?.framework,
)?.value;
const defaultChoice = choices.find(
({ value }) => value === discoveredFramework?.framework,
)?.value;

setup.featureInfo.hosting.webFramework ??= await select({
message: "Please choose the framework:",
default: defaultChoice,
choices,
});
setup.featureInfo.hosting.webFramework ??= await select({
message: "Please choose the framework:",
default: defaultChoice,
choices,
});

setup.featureInfo.hosting.region =
setup.featureInfo.hosting.region ||
(await select({
message: "In which region would you like to host server-side content, if applicable?",
default: DEFAULT_REGION,
choices: ALLOWED_SSR_REGIONS.filter((region) => region.recommended),
}));
}
setup.featureInfo.hosting.region =
setup.featureInfo.hosting.region ||
(await select({
message: "In which region would you like to host server-side content, if applicable?",
default: DEFAULT_REGION,
choices: ALLOWED_SSR_REGIONS.filter((region) => region.recommended),
}));
} else {
logger.info();
logger.info(
Expand All @@ -157,15 +157,11 @@
"Configure as a single-page app (rewrite all urls to /index.html)?",
);
}
// GitHub Action set up is still structured as doSetup
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we still need to keep this in here instead of allowing it into actuate - initGithub includes interactive prompts, and we need actuate to be safe to run noninteractively

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if can move initGitHub into askQuestions. initGitHub uses setup.config.hosting a couple of times, which is only set during actuate.

if (!setup.config.hosting) {
return reject(
`Didn't find a Hosting config in firebase.json. Run ${bold("firebase init hosting")} instead.`,
);
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated, moved initGitHub into askQuestions.

It looks like the only scenario Didn't find a Hosting config in firebase.json will error out is during the setup of a fresh project, otherwise it will correctly pick up the existing config.

During the initial set up with a blank project, I think we can instead use setup.featureInfo?.hosting if setup.config.hosting does not have values

if (await confirm("Set up automatic builds and deploys with GitHub?")) {
return initGitHub(setup);
}
}

// TODO: come up with a better way to type this
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export async function actuate(setup: Setup, config: Config, options: Options): Promise<void> {

Check warning on line 164 in src/init/features/hosting/index.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Missing JSDoc comment
const hostingInfo = setup.featureInfo?.hosting;
if (!hostingInfo) {
throw new FirebaseError(
Expand All @@ -186,7 +182,7 @@
if (hostingInfo.source && existsSync(hostingInfo.source)) {
rmSync(hostingInfo.source, { recursive: true });
}
await WebFrameworks[hostingInfo.webFramework].init!(setup, config);

Check warning on line 185 in src/init/features/hosting/index.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Forbidden non-null assertion
}
setup.config.hosting = {
source: hostingInfo.source,
Expand All @@ -207,7 +203,7 @@
} else {
// SPA doesn't need a 404 page since everything is index.html
await config.askWriteProjectFile(
`${hostingInfo.public}/404.html`,

Check warning on line 206 in src/init/features/hosting/index.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Invalid type "string | undefined" of template literal expression
MISSING_TEMPLATE,
!!options.force,
);
Expand All @@ -216,9 +212,14 @@
const c = new Client({ urlPrefix: "https://www.gstatic.com", auth: false });
const response = await c.get<{ current: { version: string } }>("/firebasejs/releases.json");
await config.askWriteProjectFile(
`${hostingInfo.public}/index.html`,

Check warning on line 215 in src/init/features/hosting/index.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Invalid type "string | undefined" of template literal expression
INDEX_TEMPLATE.replace(/{{VERSION}}/g, response.body.current.version),
!!options.force,
);
}

// GitHub Action set up is still structured as doSetup
if (await confirm("Set up automatic builds and deploys with GitHub?")) {
return initGitHub(setup);
}
}
Loading