[REQUIRED] Use case
In src/deploy/functions/deploy.ts (introduced in #9707), uploadSourceV2 currently provisions and manages a custom Bring-Your-Own (BYO) GCS bucket (firebase-functions-src-${projectNumber}) whenever deploying directly to the Cloud Run v2 API (platform === "run", dartfunctions, or the functionsrunapionly experiment):
// Future behavior: BYO bucket if we're using the Cloud Run API directly because it does not provide a source upload API.
// We use this behavior whenever the "functionsrunapionly" experiment is enabled for now just to help vet the codepath incrementally.
// Using project number to ensure we don't exceed the bucket name length limit (in addition to PII controversy).
const baseName = `firebase-functions-src-${projectNumber}`;
const bucketName = await gcs.upsertBucket({
product: "functions",
createMessage: `Creating Cloud Storage bucket in ${region} to store Functions source codeUploads...`,
projectId,
req: {
baseName,
location: region,
lifecycle: {
rule: [{ action: { type: "Delete" }, condition: { age: 1 } }],
},
},
});
const objectPath = `${source.functionsSourceV2Hash}${path.extname(source.functionsSourceV2!)}`;
await gcs.upload(uploadOpts, `${bucketName}/${objectPath}`, undefined, true /* ignoreQuotaProject */);
return { bucket: bucketName, object: objectPath };
As noted in the inline comment, this BYO bucket workaround was needed because Cloud Run v2 did not previously expose a native source upload endpoint comparable to gcfv2.generateUploadUrl. Managing the bucket client-side requires the caller to hold storage.buckets.get, storage.buckets.create, storage.buckets.update, and storage.objects.create permissions, and requires firebase-tools to handle bucket naming, region provisioning, and lifecycle cleanup rules.
Cloud Run v2 now provides a native projects.locations.sourceUploads.upload (uploadSource) API (already used by default in gcloud for --no-build source deployments).
[REQUIRED] Proposal
Update uploadSourceV2 in src/deploy/functions/deploy.ts (and src/gcp/runv2.ts) to upload source archives via Cloud Run's native uploadSource endpoint instead of upserting firebase-functions-src-${projectNumber}:
- Endpoint:
POST https://run.googleapis.com/upload/v2/projects/{project}/locations/{location}:uploadSource
- Response: Returns
UploadSourceResponse containing cloudStorageSource ({ bucket, object, generation }), which maps directly to the storage.Source / cloudStorageSource field expected by runv2 service creation/updates.
- Benefits:
- Eliminates client-side bucket orchestration: Cloud Run provisions and manages the regional source bucket (
run-sources-{project}-{region}) server-side.
- Simpler IAM footprint: Callers only need
run.locations.uploadSource rather than broad Cloud Storage bucket creation/lifecycle permissions.
- Parity with
gcloud and gcfv2: Aligns the direct-to-Cloud-Run (dartfunctions / functionsrunapionly) upload flow with gcloud run deploy --no-build.
[OPTIONAL] Implementation
- Add an
uploadSource helper in src/gcp/runv2.ts targeting POST https://run.googleapis.com/upload/v2/projects/${projectId}/locations/${region}:uploadSource.
- In
src/deploy/functions/deploy.ts (uploadSourceV2), call runv2.uploadSource(...) when useApiOnly || v2Endpoints.some((e) => e.platform === "run") and return the resulting { bucket, object, generation } from cloudStorageSource.
[REQUIRED] Use case
In
src/deploy/functions/deploy.ts(introduced in #9707),uploadSourceV2currently provisions and manages a custom Bring-Your-Own (BYO) GCS bucket (firebase-functions-src-${projectNumber}) whenever deploying directly to the Cloud Run v2 API (platform === "run",dartfunctions, or thefunctionsrunapionlyexperiment):As noted in the inline comment, this BYO bucket workaround was needed because Cloud Run v2 did not previously expose a native source upload endpoint comparable to
gcfv2.generateUploadUrl. Managing the bucket client-side requires the caller to holdstorage.buckets.get,storage.buckets.create,storage.buckets.update, andstorage.objects.createpermissions, and requiresfirebase-toolsto handle bucket naming, region provisioning, and lifecycle cleanup rules.Cloud Run v2 now provides a native
projects.locations.sourceUploads.upload(uploadSource) API (already used by default ingcloudfor--no-buildsource deployments).[REQUIRED] Proposal
Update
uploadSourceV2insrc/deploy/functions/deploy.ts(andsrc/gcp/runv2.ts) to upload source archives via Cloud Run's nativeuploadSourceendpoint instead of upsertingfirebase-functions-src-${projectNumber}:POST https://run.googleapis.com/upload/v2/projects/{project}/locations/{location}:uploadSourceUploadSourceResponsecontainingcloudStorageSource({ bucket, object, generation }), which maps directly to thestorage.Source/cloudStorageSourcefield expected byrunv2service creation/updates.run-sources-{project}-{region}) server-side.run.locations.uploadSourcerather than broad Cloud Storage bucket creation/lifecycle permissions.gcloudandgcfv2: Aligns the direct-to-Cloud-Run (dartfunctions/functionsrunapionly) upload flow withgcloud run deploy --no-build.[OPTIONAL] Implementation
uploadSourcehelper insrc/gcp/runv2.tstargetingPOST https://run.googleapis.com/upload/v2/projects/${projectId}/locations/${region}:uploadSource.src/deploy/functions/deploy.ts(uploadSourceV2), callrunv2.uploadSource(...)whenuseApiOnly || v2Endpoints.some((e) => e.platform === "run")and return the resulting{ bucket, object, generation }fromcloudStorageSource.