diff --git a/src/apphosting/backend.ts b/src/apphosting/backend.ts index 8a5aa579901..aba3fa65efb 100644 --- a/src/apphosting/backend.ts +++ b/src/apphosting/backend.ts @@ -17,7 +17,7 @@ import { Backend, BackendOutputOnlyFields, API_VERSION } from "../gcp/apphosting import { addServiceAccountToRoles } from "../gcp/resourceManager"; import * as iam from "../gcp/iam"; import { FirebaseError, getErrStatus, getError } from "../error"; -import { promptOnce } from "../prompt"; +import { promptOnce, confirm } from "../prompt"; import { DEFAULT_LOCATION } from "./constants"; import { ensure } from "../ensureApiEnabled"; import * as deploymentTool from "../deploymentTool"; @@ -474,3 +474,51 @@ export async function getBackendForAmbiguousLocation( }); return backendsByLocation.get(location)!; } + +/** + * Fetches a backend from the server. If there are multiple backends with the name, it will fetch the first + * in the list and warn the user that there are other backends with the same name that need to be deleted. If + * the force option is specified nad multiple backends have the same name, it throws an error. + */ +export async function getBackend( + projectId: string, + backendId: string, + force?: boolean, +): Promise { + // TODO: call apphosting.getBackend() once all duplicate named backends have been deleted. + let { unreachable, backends } = await apphosting.listBackends(projectId, "-"); + backends = backends.filter( + (backend) => apphosting.parseBackendName(backend.name).id === backendId, + ); + if (backends.length > 0) { + if (backends.length > 1) { + logWarning( + `You have multiple backends with the same ${backendId} ID. This is no longer supported. ` + + "Please delete and recreate any backends that share an ID with another backend." + ); + if (force) { + throw new FirebaseError( + `Force cannot be used when multiple backends share the same ID`, + ); + } + const options = { force: force, nonInteractive: false }; + const confirmed = await confirm({ + ...options, + message: `Using backend ${backends[0].name} continue?`, + }); + if (!confirmed) { + throw new FirebaseError("Command aborted."); + } + } + return backends[0]; + } + if (unreachable && unreachable.length !== 0) { + logWarning( + `Backends with the following primary regions are unreachable: ${unreachable}.\n` + + "If your backend is in one of these regions, please try again later." + ); + }; + throw new FirebaseError( + `No backend named ${backendId} found.`, + ); +} diff --git a/src/apphosting/rollout.ts b/src/apphosting/rollout.ts index 32b2bcb8d4e..0a6dbc78b25 100644 --- a/src/apphosting/rollout.ts +++ b/src/apphosting/rollout.ts @@ -13,7 +13,7 @@ import * as poller from "../operation-poller"; import { logBullet, sleep } from "../utils"; import { apphostingOrigin, consoleOrigin } from "../api"; import { DeepOmit } from "../metaprogramming"; -import { getBackendForAmbiguousLocation, getBackendForLocation } from "./backend"; +import { getBackendForAmbiguousLocation, getBackendForLocation, getBackend } from "./backend"; const apphostingPollerOptions: Omit = { apiOrigin: apphostingOrigin(), @@ -38,10 +38,9 @@ export async function createRollout( ): Promise { let backend: apphosting.Backend; if (location === "-" || location === "") { - backend = await getBackendForAmbiguousLocation( + backend = await getBackend( projectId, backendId, - "Please select the location of the backend you'd like to roll out:", force, ); location = apphosting.parseBackendName(backend.name).location; diff --git a/src/commands/apphosting-backends-list.ts b/src/commands/apphosting-backends-list.ts index 3bfa44b9733..f7340cf4495 100644 --- a/src/commands/apphosting-backends-list.ts +++ b/src/commands/apphosting-backends-list.ts @@ -7,7 +7,7 @@ import { Options } from "../options"; import * as apphosting from "../gcp/apphosting"; import * as Table from "cli-table3"; -const TABLE_HEAD = ["Backend", "Repository", "URL", "Location", "Updated Date"]; +const TABLE_HEAD = ["Backend", "Repository", "URL", "Primary Region", "Updated Date"]; export const command = new Command("apphosting:backends:list") .description("list Firebase App Hosting backends")