Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
Expand Up @@ -4,6 +4,7 @@
- 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 'init hosting' failed to prompt for the public directory and set up Hosting files (#9403)
- Added `appdistribution:testcases:export` and `appdistribution:testcases:import` (#9397)
- Updated to v2.16.0 of the Data Connect emulator, which includes internal improvements.
- Data Connect now allows executing a valid query / operation even if the other operations are invalid. (This toleration provides convenience on a best-effort basis. Some errors like invalid syntax can still cause the whole request to be rejected.)
Expand Down
4 changes: 2 additions & 2 deletions src/init/features/hosting/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@
* - Writes GitHub workflow yaml configuration files that reference the newly created secret
* to configure the Deploy to Firebase Hosting GitHub Action
* - https://github.com/marketplace/actions/deploy-to-firebase-hosting
* - https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions

Check warning on line 49 in src/init/features/hosting/github.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Expected only 0 line after block description
*
* @param setup A helper object provided by the `firebase init` command.
* @param config Configuration for the project.

Check warning on line 52 in src/init/features/hosting/github.ts

View workflow job for this annotation

GitHub Actions / lint (20)

@param "config" does not match an existing function parameter
* @param options Command line options.
*/
export async function initGitHub(setup: Setup): Promise<void> {
Expand All @@ -57,7 +57,7 @@
return reject("Could not determine Project ID, can't set up GitHub workflow.", { exit: 1 });
}

if (!setup.config.hosting) {
if (!setup.config.hosting && !setup.featureInfo?.hosting) {
return reject(
`Didn't find a Hosting config in firebase.json. Run ${bold("firebase init hosting")} instead.`,
);
Expand All @@ -82,10 +82,10 @@

// Get GitHub user Details
const userDetails = await getGitHubUserDetails(ghAccessToken);
const ghUserName = userDetails.login;

Check warning on line 85 in src/init/features/hosting/github.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe assignment of an `any` value

logger.info();
logSuccess(`Success! Logged into GitHub as ${bold(ghUserName)}`);

Check warning on line 88 in src/init/features/hosting/github.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe argument of type `any` assigned to a parameter of type `string | number`
logger.info();

// Prompt for repo and validate by getting the public key
Expand Down Expand Up @@ -132,11 +132,11 @@

// If the developer is using predeploy scripts in firebase.json,
// remind them before they set up a script in their workflow file.
if (!Array.isArray(setup.config.hosting) && setup.config.hosting.predeploy) {
if (!Array.isArray(setup.config.hosting) && setup.config.hosting?.predeploy) {
logBullet(`You have a predeploy script configured in firebase.json.`);
}

const { script } = await promptForBuildScript(setup?.hosting?.useWebFrameworks);

Check warning on line 139 in src/init/features/hosting/github.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe argument of type `any` assigned to a parameter of type `boolean | undefined`

const ymlDeployDoc = loadYMLDeploy();

Expand All @@ -158,8 +158,8 @@
githubSecretName,
setup.projectId,
script,
setup?.hosting?.useWebFrameworks,

Check warning on line 161 in src/init/features/hosting/github.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe argument of type `any` assigned to a parameter of type `boolean | undefined`
setup?.hosting?.source,

Check warning on line 162 in src/init/features/hosting/github.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe argument of type `any` assigned to a parameter of type `string | undefined`
);

logger.info();
Expand Down Expand Up @@ -193,8 +193,8 @@
githubSecretName,
setup.projectId,
script,
setup?.hosting?.useWebFrameworks,

Check warning on line 196 in src/init/features/hosting/github.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe argument of type `any` assigned to a parameter of type `boolean | undefined`
setup?.hosting?.source,

Check warning on line 197 in src/init/features/hosting/github.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe argument of type `any` assigned to a parameter of type `string | undefined`
);

logger.info();
Expand All @@ -219,7 +219,7 @@
* For example, if the .git folder is /Users/sparky/projects/my-web-app/.git
* This function will return /Users/sparky/projects/my-web-app
*
* Modeled after https://github.com/firebase/firebase-tools/blob/master/src/detectProjectRoot.ts

Check warning on line 222 in src/init/features/hosting/github.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Expected only 0 line after block description
*
* @return {string} The folder that contains the .git folder
*/
Expand Down
89 changes: 45 additions & 44 deletions src/init/features/hosting/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,11 @@ export async function askQuestions(setup: Setup, config: Config, options: Option
}
}

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 @@ export async function askQuestions(setup: Setup, config: Config, options: Option
`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,6 +157,7 @@ export async function askQuestions(setup: Setup, config: Config, options: Option
"Configure as a single-page app (rewrite all urls to /index.html)?",
);
}

// GitHub Action set up is still structured as doSetup
Copy link
Contributor

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);
Expand Down
Loading