Skip to content

Integrate FAH Local Builds with Universal Maker#10382

Draft
falahat wants to merge 28 commits intonextfrom
universal_maker
Draft

Integrate FAH Local Builds with Universal Maker#10382
falahat wants to merge 28 commits intonextfrom
universal_maker

Conversation

@falahat
Copy link
Copy Markdown
Contributor

@falahat falahat commented Apr 17, 2026

Description

This takes the existing local builds solution and uses the Universal Maker binary (which runs all relevant buildpacks) instead of hackily running the apphosting adapter manually.

The Universal Maker is a more well-supported tool and behaves more similar to Cloud Builds so we can have more confidence about framework support and fidelity.

Major changes

  • Automatically downloads the universal maker when it's needed, verifying its hash
  • Calls the universal maker, correctly handling the .apphosting folder.
  • For now, this relies on the apphosting generated bundle.yaml file rather than UM's output.json, but that will be fixed later

Scenarios Tested

Created a local build with the

Sample Commands

firebase experiments:enable apphostinglocalbuilds
firebase experiments:enable universalMaker

firebase deploy

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request adds support for 'Universal Maker' local builds, integrates Secret Manager secret resolution for local environments, and refactors ABIU configuration. Key feedback includes fixing a blocking issue in the build watcher, adhering to style guides for YAML parsing and error handling, and optimizing the bundling process to avoid slow file copies of node_modules.

Comment thread src/apphosting/localbuilds.ts Outdated
Comment thread src/apphosting/localbuilds.ts
Comment thread src/apphosting/localbuilds.ts Outdated
Comment thread src/apphosting/secrets/index.ts
Comment thread src/deploy/apphosting/util.ts Outdated
@falahat
Copy link
Copy Markdown
Contributor Author

falahat commented Apr 17, 2026

/gemini review

@falahat falahat changed the base branch from main to next April 17, 2026 18:11
Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the "Universal Maker" for App Hosting local builds, enabling standalone binary builds through a new experiment. It also enhances secret management by implementing a utility to resolve secrets from Secret Manager during local builds, adding a security confirmation prompt, and introducing the --allow-local-build-secrets flag. Furthermore, the PR removes explicit "Automatic Base Image Updates" (ABIU) configuration flags, integrating ABIU status into the runtime selection instead. Review feedback suggests strengthening test assertions for binary execution, removing unknown type assertions to comply with the style guide, and generalizing build artifact packaging logic to remove framework-specific assumptions.

Comment thread src/apphosting/localbuilds.spec.ts Outdated
Comment thread src/apphosting/localbuilds.ts Outdated
Comment thread src/apphosting/localbuilds.ts Outdated
Comment thread src/deploy/apphosting/util.ts Outdated
@falahat
Copy link
Copy Markdown
Contributor Author

falahat commented Apr 17, 2026

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces support for a new 'Universal Maker' standalone binary for local builds in App Hosting, controlled via an experimental flag. It adds the runUniversalMaker function to handle the binary execution, artifact management, and metadata parsing, while also updating the tar archive creation logic to support flattened directory structures for .apphosting outputs. Feedback focuses on improving the robustness of the build process by checking the binary's exit status, ensuring proper cleanup of stale artifacts and temporary directories, and removing hardcoded environment variables that might conflict with user configurations.

Comment thread src/apphosting/localbuilds.ts Outdated
Comment thread src/apphosting/localbuilds.ts Outdated
Comment thread src/apphosting/localbuilds.ts
Comment thread src/deploy/apphosting/util.ts
Comment thread src/apphosting/universalMakerDownload.ts Outdated
Comment thread src/apphosting/universalMakerDownload.ts Outdated
@falahat
Copy link
Copy Markdown
Contributor Author

falahat commented Apr 21, 2026

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the 'Universal Maker' binary for local builds in App Hosting, including logic for downloading, validating, and executing the tool. It also improves temporary file management during deployments by ensuring cleanup via callbacks. Several improvements were identified regarding the safety of command construction, the use of blocking synchronous calls in an asynchronous environment, and the need for better error handling and type safety in accordance with the repository's style guide.

throw new FirebaseError(`Failed to parse build_output.json: ${(e as Error).message}`);
}

let finalRunCommand = `${umOutput.command} ${umOutput.args.join(" ")}`;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Constructing a command string by joining arguments with spaces can lead to broken commands if any argument contains spaces or special characters. It is safer to keep the command and arguments separate or use a utility that handles shell escaping.

Comment on lines +40 to +51
const res = childProcess.spawnSync(
universalMakerBinary,
["-application_dir", projectRoot, "-output_dir", projectRoot, "-output_format", "json"],
{
env: {
...process.env,
X_GOOGLE_TARGET_PLATFORM: "fah",
FIREBASE_OUTPUT_BUNDLE_DIR: bundleOutput,
},
stdio: "pipe",
},
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

Using spawnSync blocks the Node.js event loop until the process exits. For a build process that can take a significant amount of time, this can make the CLI feel unresponsive. Consider using an asynchronous spawn wrapped in a Promise to allow the event loop to remain active, which is also better for handling process signals like SIGINT.

Comment thread src/apphosting/localbuilds.ts
Comment thread src/apphosting/localbuilds.ts Outdated
metadata: {
language: umOutput.language,
runtime: umOutput.runtime,
framework: framework || "nextjs",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The hardcoded default value "nextjs" should be extracted into a constant to improve maintainability and avoid magic strings.

Comment thread src/downloadUtils.ts
Comment on lines +55 to +67
export function validateSize(filepath: string, expectedSize: number): Promise<void> {
return new Promise((resolve, reject) => {
const stat = fs.statSync(filepath);
return stat.size === expectedSize
? resolve()
: reject(
new FirebaseError(
`download failed, expected ${expectedSize} bytes but got ${stat.size}`,
{ exit: 1 },
),
);
});
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The validateSize function returns a Promise but performs synchronous file operations (fs.statSync). This is misleading and still blocks the event loop. It should either be fully synchronous or use fs.promises.stat to be truly asynchronous.

falahat and others added 8 commits April 21, 2026 18:28
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
… the "deploy" flow as well"

This reverts commit 59a79f5.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants