Skip to content

fix: normalize GCF v2 IDs loaded from Cloud Run services - #10910

Open
ajperel wants to merge 1 commit into
mainfrom
ajp/fix-dot-vs-dash
Open

fix: normalize GCF v2 IDs loaded from Cloud Run services#10910
ajperel wants to merge 1 commit into
mainfrom
ajp/fix-dot-vs-dash

Conversation

@ajperel

@ajperel ajperel commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Description

Fixes an issue where GCF v2 functions with dots in their names (which GCF normalizes to dashes) were incorrectly flagged for deletion during deployments when the dartfunctions or functionsrunapionly experiments were enabled.

The Bug:
When loading the existing state of a project, the GCF V2 API returns function IDs with dashes (e.g. v2-helloWorldNode). However, if the experiments are enabled, the CLI also queries the Cloud Run API to check for missing services. It parses the ID from the service annotations, which preserves the original name with dots (e.g. v2.helloWorldNode). Because of this mismatch, the CLI loaded both as separate duplicate endpoints in existingBackend. The planner then flagged the dot-version for deletion while planning to update the dash-version.

How to Reproduce:

  1. Enable the dartfunctions experiment: firebase experiments:enable dartfunctions
  2. Define a nested GCF v2 function (e.g. exports.v2 = { helloWorldNode: ... }), which has the logical ID v2.helloWorldNode.
  3. Deploy the function: firebase deploy --only functions (it will be created in GCP as v2-helloWorldNode).
  4. Run another deployment: firebase deploy --only functions.
  5. Observe that the CLI prompts to delete v2.helloWorldNode while also updating v2-helloWorldNode.

The Fix:
Normalized GCF v2 IDs loaded from Cloud Run services to replace dots (.) with dashes (-), matching GCF V2 API behavior. Underscores (_) are preserved because GCF v2 natively supports them. We do not normalize for "run" platform services (like Dart functions) because their local specs do not undergo GCF-style normalization.

Scenarios Tested

  • Verified all tests pass
  • Verified bad behavior happens only when dartfunctions experiment is on (and presumably runfunctionsonly)
  • Manually tested deploys creating, updating, and deleting with and without this change using a function in code as "v2.helloWorld" (and some others)

Sample Commands

npm run test
firebase deploy --only functions (with and without additional filters)

TAG=agy
CONV=ca939fe8-e463-44c5-b6ae-7a50e7b4599a

@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 ID normalization for GCF v2 services in src/gcp/runv2.ts by replacing dots with dashes to match GCF v2 API behavior and prevent duplicate endpoints, alongside adding comprehensive unit tests in src/gcp/runv2.spec.ts. The review feedback recommends handling cases where rawId might be undefined to ensure strict null safety and prevent potential runtime TypeErrors.

Comment thread src/gcp/runv2.ts Outdated
@ajperel
ajperel force-pushed the ajp/fix-dot-vs-dash branch from 85dc512 to 0df8948 Compare August 10, 2026 16:18
…dots only)

### Description
Fixes an issue where GCF v2 functions with dots in their names (which GCF normalizes to dashes) were incorrectly flagged for deletion during deployments when the `dartfunctions` or `functionsrunapionly` experiments were enabled.

**The Bug:**
When loading the existing state of a project, the GCF V2 API returns function IDs with dashes (e.g. `v2-helloWorldNode`). However, if the experiments are enabled, the CLI also queries the Cloud Run API to check for missing services. It parses the ID from the service annotations, which preserves the original name with dots (e.g. `v2.helloWorldNode`). Because of this mismatch, the CLI loaded both as separate duplicate endpoints in `existingBackend`. The planner then flagged the dot-version for deletion while planning to update the dash-version.

**How to Reproduce:**
1. Enable the `dartfunctions` experiment: `firebase experiments:enable dartfunctions`
2. Define a nested GCF v2 function (e.g. `exports.v2 = { helloWorldNode: ... }`), which has the logical ID `v2.helloWorldNode`.
3. Deploy the function: `firebase deploy --only functions` (it will be created in GCP as `v2-helloWorldNode`).
4. Run another deployment: `firebase deploy --only functions`.
5. Observe that the CLI prompts to delete `v2.helloWorldNode` while also updating `v2-helloWorldNode`.

**The Fix:**
Normalized GCF v2 IDs loaded from Cloud Run services to replace dots (`.`) with dashes (`-`), matching GCF V2 API behavior. Underscores (`_`) are preserved because GCF v2 natively supports them. We do not normalize for `"run"` platform services (like Dart functions) because their local specs do not undergo GCF-style normalization.

### Scenarios Tested
- Verified all tests pass
- Verified bad behavior happens only when dartfunctions experiment is on (and presumably runfunctionsonly)
- Manually tested deploys creating, updating, and deleting with and without this change using a function in code as "v2.helloWorld" (and some others)

### Sample Commands
`npm run test`
`firebase deploy --only functions` (with and without additional filters)

TAG=agy
CONV=ca939fe8-e463-44c5-b6ae-7a50e7b4599a

@inlined inlined left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It might be worth improving comments a bit.

It sounds like we're NOT finding FUNCTION_ID_ANNOTATION but we ARE finding FUNCTIN_TARGET_ANNOTATION, and in the case of function groups specifically those are not the same thing.

It's also not entirely clear why you have to conditionally replace.

@joehan
joehan requested review from joehan and removed request for joehan August 13, 2026 21:08
@ajperel

ajperel commented Aug 13, 2026

Copy link
Copy Markdown
Contributor Author

I will probably abandon this PR because I think the Run API will be fixed instead. Leaving it open till that's verified. That said.

It's also not entirely clear why you have to conditionally replace.

I'm replacing for gcfv2 only because that's the only case where we're reconciling between the two. If we're only using cloud run (the dart case) the rawID is the only one we have and use. There is a different bug that right now you can only reference Dart functions by the renamed method so if we turn helloWorldDart into helloworlddart you can only do firebase deploy --only functions:helloworlddart. That's a separate issue and when we fix that we may need something like this for dart?

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