Skip to content

feat(functions): support subsequent installs and multi-project configuration for function kits - #10931

Merged
wandamora merged 14 commits into
mainfrom
morawand-kits-add-instances
Aug 18, 2026
Merged

feat(functions): support subsequent installs and multi-project configuration for function kits#10931
wandamora merged 14 commits into
mainfrom
morawand-kits-add-instances

Conversation

@wandamora

@wandamora wandamora commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Description

Enhances the functions:kits:install command to support subsequent installations of an already installed Function Kit package in both single-project and multi-project settings:

  1. Subsequent Install Detection:

    • Detects whether the specified package is already configured under a kit in firebase.json.
  2. Project Dotenv Detection & Conditional Prompting:

    • Inspects all instance configuration directories (configDir) in the kit for existing .env.<project-id> files matching the active project ID or alias.
    • If no .env file exists for the active project (and in interactive mode): Prompts the user to choose between:
      • "Add an instance to the existing kit": Prompts for a new instance ID (or generates a unique ID), creates function-kits/<kit>/config-<instanceId>, and updates firebase.json.
      • "Configure an existing instance for this project": Selects the instance (prompting if multiple exist) and outputs the recommended firebase deploy command so the deploy workflow can prompt for parameters and automatically generate .env.<project-id>.
    • If a .env file already exists for the active project (or in --non-interactive mode): Automatically skips the choice prompt and directly proceeds with adding a new instance.
  3. Collision & Validation Checks:

    • Ensures instance IDs are unique across all kits and do not collide with existing codebase names.

Scenarios Tested

  • Subsequent install in non-interactive mode: Auto-generates unique instance ID, updates firebase.json, and skips npm install.
  • Subsequent install in interactive mode (addInstance): Prompts for custom instance name, creates config directory, and updates firebase.json.
  • Subsequent install when .env.<current-project> already exists: Skips the action prompt and directly enters addInstance.
  • Subsequent install with addEnv:
    • Single instance + active project: Outputs firebase deploy --only functions:<inst> --project <project> without writing empty .env files or modifying firebase.json.
    • Single instance without active project: Outputs deploy suggestion with <project-name> placeholder.
    • Multiple instances: Prompts to select which instance to configure.
  • Duplicate instance ID validation: Rejects duplicate instance IDs and codebase name collisions.
  • Unit test suite in src/commands/functions-kits-install.spec.ts (57 passing tests).

Sample Commands

  • firebase functions:kits:install --npm_package <package> for subsequent installs to add an instance
  • firebase functions:kits:install --npm_package <package> --project <unconfigured-project>

@wiz-9635d3485b

wiz-9635d3485b Bot commented Aug 12, 2026

Copy link
Copy Markdown

Wiz Scan Summary

Scanner Findings
Vulnerability Finding Vulnerabilities -
Data Finding Sensitive Data -
Secret Finding Secrets -
IaC Misconfiguration IaC Misconfigurations -
SAST Finding SAST Findings 20 Medium 3 Low
Software Management Finding Software Management Findings -
Total 20 Medium 3 Low

View scan details in Wiz

To detect these findings earlier in the dev lifecycle, try the Wiz Code extension for VS Code, JetBrains, or Visual Studio.

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

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.

Code Review

This pull request introduces support for subsequent installations of already installed function kits, allowing users to add new instances or configure existing ones for their active project. The review feedback highlights a potential TypeError when options.rc.projects is undefined, recommends throwing a FirebaseError in non-interactive mode if multiple matching kits are found, and suggests simplifying the configuration update logic to avoid duplication and silent failures.

Comment thread src/commands/functions-kits-install.ts Outdated
Comment thread src/commands/functions-kits-install.ts Outdated
Comment thread src/commands/functions-kits-install.ts Outdated
We should assume there is at most one kit containing the package to install.
@wandamora
wandamora marked this pull request as ready for review August 12, 2026 23:31
@wandamora
wandamora requested a review from ajperel August 12, 2026 23:39
Comment thread src/commands/functions-kits-install.spec.ts
Comment thread src/commands/functions-kits-install.spec.ts Outdated

expect(writeProjectFileStub).to.not.have.been.called;
expect(loggerInfoStub).to.have.been.calledWith(
sinon.match(/firebase deploy --only functions:inst-1 --project my-staging-project/),

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.

Is it always including a --project flag?

If the active project is the default such that deploy --only functions:inst-1 would do the right thing and the user didn't include a --project flag on install I kind of lean towards not including it. The users may not be familiar with the flag if they're only ever working in one project.

But if there's a CLI convention to always include it or something I could easily be convicned otherwise.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Since it's a standard CLI flag, I don't think should be confusing or misleading to users. We're just being extra explicit about what to run if they want to configure an instance for a certain project.

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.

I might check with Joe. Standard flag doesn't mean commonly used or seen. In my own usage I setup a default project as I configured things and have almost never used the --project flag.

But this is a minor UX nit since you're right it will work. Easy to adjust later and shouldn't block this PR.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've used --project quite a bit in my own testing, so I'm not sure what speaks to the most common UX :) Getting Joe's insight isn't a bad idea.

Comment thread src/commands/functions-kits-install.spec.ts
Comment thread src/commands/functions-kits-install.ts Outdated
Comment thread src/commands/functions-kits-install.ts Outdated
Comment thread src/commands/functions-kits-install.ts
Simplifies the instance assignment logic in `functions:kits:install` by directly updating `existingKit.instances` in place instead of performing a redundant search and defensive error check over `configSrc.functions`. Removes the synthetic unit test that artificially zeroed out config mid-execution to hit the unreachable error branch.
- Adds `hasProjectEnv(dir, projectId, projectAlias)` to `src/functions/env.ts` as a generic helper to check for `.env.<projectId>` and `.env.<projectAlias>` in a directory.
- Renames `hasDotenvForProject` in `functions-kits-install.ts` to `isKitConfiguredForProject` and delegates directory checks to `hasProjectEnv`.
- Eliminates custom `getProjectIdentifiers` resolution and `readdirSync` directory itøeration, aligning with how the CLI resolves environment files.

@ajperel ajperel left a comment

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.

Some last thoughts I trust you to work through. Thanks for addressing my last feedback.

Comment thread src/commands/functions-kits-install.spec.ts

expect(writeProjectFileStub).to.not.have.been.called;
expect(loggerInfoStub).to.have.been.calledWith(
sinon.match(/firebase deploy --only functions:inst-1 --project my-staging-project/),

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.

I might check with Joe. Standard flag doesn't mean commonly used or seen. In my own usage I setup a default project as I configured things and have almost never used the --project flag.

But this is a minor UX nit since you're right it will work. Easy to adjust later and shouldn't block this PR.

Comment thread src/commands/functions-kits-install.spec.ts
): Promise<boolean> {
const isThirdParty = isThirdPartyPackage(packageName);
if (isThirdParty) {
logger.warn(

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.

Could be in a different PR if we want to address... but trying actual installs I wonder if this should use the log bullets like other messages.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah definitely. I was planning to do a small PR for this after this lands.

const absConfigDirPath = options.config.path(configDirPath);
await fs.ensureDir(absConfigDirPath);

existingKit.instances[instanceId] = configDirPath;

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.

Comment from Joe's tools review skill:

Finding: Mutating existingKit.instances in-place modifies the shared options.config.src object in memory. While safe in this CLI context because the command exits immediately, it can lead to side effects in long-running processes (like dev servers) or cause state pollution in unit tests.

Suggested Fix: Clone the configuration before mutating (e.g., using _.cloneDeep(options.config.src)).

I don't think we're relying on the mutated existingKit object after this so it'd be safe to do?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Exactly, we're not relying on this object after this as the CLI exits soon after. Also I'm not too worried about tests since unit tests supply a fresh Config object per test.

Comment thread src/commands/functions-kits-install.ts Outdated
@wandamora
wandamora enabled auto-merge (squash) August 17, 2026 22:51
@wandamora
wandamora merged commit 414cc02 into main Aug 18, 2026
75 of 80 checks passed
@wandamora
wandamora deleted the morawand-kits-add-instances branch August 18, 2026 00:54
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