Skip to content

Commit 63a529e

Browse files
authored
Consolidate the ABIU prompts in the CLI so it matches the UI behavior (#10352)
* Consolidate the ABIU prompts in the CLI so it matches the UI more closely * Address linter errors
1 parent b5cb204 commit 63a529e

6 files changed

Lines changed: 36 additions & 140 deletions

File tree

src/apphosting/backend.spec.ts

Lines changed: 0 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,6 @@ describe("apphosting setup functions", () => {
123123
serviceAccount: "custom-service-account",
124124
appId: webAppId,
125125
runtime: { value: "" },
126-
automaticBaseImageUpdatesDisabled: undefined,
127126
};
128127
expect(createBackendStub).to.be.calledWith(projectId, location, backendInput, backendId);
129128
});
@@ -155,74 +154,11 @@ describe("apphosting setup functions", () => {
155154
serviceAccount: "custom-service-account",
156155
appId: webAppId,
157156
runtime: { value: runtime ?? "" },
158-
automaticBaseImageUpdatesDisabled: undefined,
159157
};
160158
expect(createBackendStub).to.be.calledWith(projectId, location, backendInput, backendId);
161159
});
162160
}
163161

164-
it("should create a new backend with automatic base image updates disabled", async () => {
165-
createBackendStub.resolves(op);
166-
pollOperationStub.resolves(completeBackend);
167-
168-
await createBackend(
169-
projectId,
170-
location,
171-
backendId,
172-
"custom-service-account",
173-
cloudBuildConnRepo,
174-
webAppId,
175-
"/",
176-
undefined,
177-
true, // automaticBaseImageUpdatesDisabled
178-
);
179-
180-
const backendInput: Omit<apphosting.Backend, apphosting.BackendOutputOnlyFields> = {
181-
servingLocality: "GLOBAL_ACCESS",
182-
codebase: {
183-
repository: cloudBuildConnRepo.name,
184-
rootDirectory: "/",
185-
},
186-
labels: deploymentTool.labels(),
187-
serviceAccount: "custom-service-account",
188-
appId: webAppId,
189-
runtime: { value: "" },
190-
automaticBaseImageUpdatesDisabled: true,
191-
};
192-
expect(createBackendStub).to.be.calledWith(projectId, location, backendInput, backendId);
193-
});
194-
195-
it("should create a new backend with automatic base image updates enabled", async () => {
196-
createBackendStub.resolves(op);
197-
pollOperationStub.resolves(completeBackend);
198-
199-
await createBackend(
200-
projectId,
201-
location,
202-
backendId,
203-
"custom-service-account",
204-
cloudBuildConnRepo,
205-
webAppId,
206-
"/",
207-
undefined,
208-
false, // automaticBaseImageUpdatesDisabled
209-
);
210-
211-
const backendInput: Omit<apphosting.Backend, apphosting.BackendOutputOnlyFields> = {
212-
servingLocality: "GLOBAL_ACCESS",
213-
codebase: {
214-
repository: cloudBuildConnRepo.name,
215-
rootDirectory: "/",
216-
},
217-
labels: deploymentTool.labels(),
218-
serviceAccount: "custom-service-account",
219-
appId: webAppId,
220-
runtime: { value: "" },
221-
automaticBaseImageUpdatesDisabled: false,
222-
};
223-
expect(createBackendStub).to.be.calledWith(projectId, location, backendInput, backendId);
224-
});
225-
226162
it("should set default rollout policy to 100% all at once", async () => {
227163
const completeTraffic: apphosting.Traffic = {
228164
name: `projects/${projectId}/locations/${location}/backends/${backendId}/traffic`,

src/apphosting/backend.ts

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import fetch from "node-fetch";
2929
import { orchestrateRollout } from "./rollout";
3030
import * as fuzzy from "fuzzy";
3131
import { isEnabled } from "../experiments";
32-
import { DEFAULT_RUNTIME, promptRuntime, promptAutomaticBaseImageUpdates } from "./prompts";
32+
import { DEFAULT_RUNTIME, promptRuntime } from "./prompts";
3333

3434
const DEFAULT_COMPUTE_SERVICE_ACCOUNT_NAME = "firebase-app-hosting-compute";
3535

@@ -82,7 +82,6 @@ export async function doSetup(
8282
primaryRegion?: string,
8383
rootDir?: string,
8484
runtime?: string,
85-
automaticBaseImageUpdatesDisabled?: boolean,
8685
): Promise<void> {
8786
await ensureRequiredApisEnabled(projectId);
8887

@@ -137,12 +136,6 @@ export async function doSetup(
137136
}
138137
}
139138

140-
if (automaticBaseImageUpdatesDisabled === undefined && isEnabled("abiu")) {
141-
if (!nonInteractive) {
142-
automaticBaseImageUpdatesDisabled = !(await promptAutomaticBaseImageUpdates());
143-
}
144-
}
145-
146139
const webApp = await webApps.getOrCreateWebApp(
147140
projectId,
148141
webAppName ? webAppName : null,
@@ -162,7 +155,6 @@ export async function doSetup(
162155
webApp?.id,
163156
rootDir,
164157
runtime,
165-
automaticBaseImageUpdatesDisabled,
166158
);
167159
createBackendSpinner.succeed(`Successfully created backend!\n\t${backend.name}\n`);
168160

@@ -373,7 +365,6 @@ export async function createBackend(
373365
webAppId: string | undefined,
374366
rootDir = "/",
375367
runtime?: string,
376-
automaticBaseImageUpdatesDisabled?: boolean,
377368
): Promise<Backend> {
378369
const defaultServiceAccount = defaultComputeServiceAccountEmail(projectId);
379370
const backendReqBody: Omit<Backend, BackendOutputOnlyFields> = {
@@ -392,7 +383,6 @@ export async function createBackend(
392383
// this is to be extra careful that we do not set the ABIU fields if the experiment is disabled
393384
if (isEnabled("abiu")) {
394385
backendReqBody.runtime = { value: runtime ?? "" };
395-
backendReqBody.automaticBaseImageUpdatesDisabled = automaticBaseImageUpdatesDisabled;
396386
}
397387

398388
async function createBackendAndPoll(): Promise<apphosting.Backend> {

src/apphosting/prompts.ts

Lines changed: 26 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,46 @@
1-
import { select, confirm, Choice } from "../prompt";
2-
import { logWarning } from "../utils";
1+
import { select, Choice } from "../prompt";
2+
import { logWarning, logBullet } from "../utils";
33
import * as apphosting from "../gcp/apphosting";
4+
45
export const DEFAULT_RUNTIME = "nodejs";
56

67
/**
7-
* Asks the user for their runtime. This is required for ABIU.
8+
* Asks the user for their runtime.
89
*/
910
export async function promptRuntime(projectId: string, location: string): Promise<string> {
10-
const choices: Choice<string>[] = [{ name: "Node.js (default)", value: DEFAULT_RUNTIME }];
11+
const choices: Choice<string>[] = [];
12+
let nodejsChoice: Choice<string> = { name: "Node.js (default)", value: DEFAULT_RUNTIME };
13+
1114
try {
1215
const supportedRuntimes = await apphosting.listSupportedRuntimes(projectId, location);
1316
for (const r of supportedRuntimes) {
14-
if (r.runtimeId !== DEFAULT_RUNTIME) {
15-
choices.push({ name: r.runtimeId, value: r.runtimeId });
17+
const abiuText = r.automaticBaseImageUpdatesSupported
18+
? "Enables Automatic Base Image Updates"
19+
: "No Automatic Base Image Updates";
20+
const choiceName = `${r.runtimeId} - ${abiuText}`;
21+
22+
if (r.runtimeId === DEFAULT_RUNTIME) {
23+
nodejsChoice = { name: choiceName, value: r.runtimeId };
24+
} else {
25+
choices.push({ name: choiceName, value: r.runtimeId });
1626
}
1727
}
28+
choices.unshift(nodejsChoice);
1829
} catch (err) {
1930
logWarning("Failed to list supported runtimes. Falling back to hardcoded list.");
20-
// We add this hardcoded nodejs22 to unblock testing.
21-
// This line will be removed when the ListSupportedRuntime API is stable.
22-
choices.push({ name: "nodejs22", value: "nodejs22" });
31+
choices.push({ name: "nodejs - No Automatic Base Image Updates", value: "nodejs" });
32+
choices.push({ name: "nodejs22 - Enables Automatic Base Image Updates", value: "nodejs22" });
2333
}
24-
return await select({
34+
35+
const selectedRuntime = await select({
2536
message: "Which runtime do you want to use?",
2637
choices: choices,
2738
default: DEFAULT_RUNTIME,
2839
});
29-
}
3040

31-
/**
32-
* Asks the user if ABIU should be enabled. True by default.
33-
*/
34-
export async function promptAutomaticBaseImageUpdates(): Promise<boolean> {
35-
return await confirm({
36-
message: "Would you like to enable Automatic Base Image Updates (ABIU)?",
37-
default: true,
38-
});
41+
if (selectedRuntime === DEFAULT_RUNTIME) {
42+
logBullet("ABIU will not be enabled for the unversioned 'nodejs' runtime.");
43+
}
44+
45+
return selectedRuntime;
3946
}

src/commands/apphosting-backends-create.spec.ts

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ describe("apphosting:backends:create", () => {
2323
sinon.restore();
2424
});
2525

26-
it("should fail if ABIU flags are used without experiment enabled", async () => {
26+
it("should fail if runtime flag is used without experiment enabled", async () => {
2727
isEnabledStub.returns(false);
2828
const options = {
2929
project: PROJECT_ID,
@@ -34,11 +34,11 @@ describe("apphosting:backends:create", () => {
3434

3535
await expect(command.runner()(options)).to.be.rejectedWith(
3636
FirebaseError,
37-
/The --runtime and --automatic-base-image-updates flags are only available when the 'abiu' experiment is enabled/,
37+
/The --runtime flag is only available when the 'abiu' experiment is enabled/,
3838
);
3939
});
4040

41-
it("should default ABIU to enabled and runtime to empty string when experiment is on", async () => {
41+
it("should default runtime to undefined when experiment is on and no flag provided", async () => {
4242
isEnabledStub.returns(true);
4343
const options = {
4444
project: PROJECT_ID,
@@ -59,33 +59,6 @@ describe("apphosting:backends:create", () => {
5959
"us-central1", // primaryRegion
6060
undefined, // rootDir
6161
undefined, // expected runtime (doSetup handles the default to 'nodejs')
62-
false, // expected default automaticBaseImageUpdatesDisabled (enabled)
63-
);
64-
});
65-
66-
it("should pass explicit ABIU disabled flag", async () => {
67-
isEnabledStub.returns(true);
68-
const options = {
69-
project: PROJECT_ID,
70-
nonInteractive: true,
71-
backend: "test-backend",
72-
primaryRegion: "us-central1",
73-
serviceAccount: "",
74-
automaticBaseImageUpdates: false,
75-
};
76-
77-
await command.runner()(options);
78-
79-
expect(doSetupStub).to.be.calledWith(
80-
PROJECT_ID,
81-
true,
82-
undefined,
83-
"test-backend",
84-
"",
85-
"us-central1",
86-
undefined,
87-
undefined,
88-
true, // automaticBaseImageUpdatesDisabled should be true
8962
);
9063
});
9164

@@ -111,7 +84,6 @@ describe("apphosting:backends:create", () => {
11184
"us-central1",
11285
undefined,
11386
"", // explicit empty string should be preserved
114-
false,
11587
);
11688
});
11789

@@ -137,7 +109,6 @@ describe("apphosting:backends:create", () => {
137109
"us-central1",
138110
undefined,
139111
"nodejs22",
140-
false, // ABIU defaults to enabled even with explicit runtime
141112
);
142113
});
143114

@@ -163,7 +134,6 @@ describe("apphosting:backends:create", () => {
163134
"us-central1",
164135
undefined,
165136
undefined, // Should default to undefined, then nodejs in doSetup
166-
false,
167137
);
168138
});
169139
});

src/commands/apphosting-backends-create.ts

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ export const command = new Command("apphosting:backends:create")
3131
.option("--root-dir <rootDir>", "specify the root directory for the backend.");
3232
const abiuEnabled = experiments.isEnabled("abiu");
3333
if (abiuEnabled) {
34-
command
35-
.option("--runtime [runtime]", "specify the runtime for the backend (e.g., nodejs, nodejs22)")
36-
.option("--automatic-base-image-updates", "enable automatic base image updates")
37-
.option("--no-automatic-base-image-updates", "disable automatic base image updates");
34+
command.option(
35+
"--runtime [runtime]",
36+
"specify the runtime for the backend (e.g., nodejs, nodejs22)",
37+
);
3838
}
3939

4040
command
@@ -48,18 +48,15 @@ command
4848
}
4949

5050
const abiuAllowed = experiments.isEnabled("abiu");
51-
if (!abiuAllowed && (options.runtime || options.automaticBaseImageUpdates !== undefined)) {
51+
if (!abiuAllowed && options.runtime) {
5252
throw new FirebaseError(
53-
"The --runtime and --automatic-base-image-updates flags are only available when the 'abiu' experiment is enabled. To enable it, run 'firebase experiments:enable abiu'.",
53+
"The --runtime flag is only available when the 'abiu' experiment is enabled. To enable it, run 'firebase experiments:enable abiu'.",
5454
);
5555
}
5656
// When ABIU is allowed but the user doesn't provide a runtime string, we let doSetup handle it.
5757
// We strictly check for string type to avoid boolean true (flag present without value) causing issues.
5858
const runtime =
5959
abiuAllowed && typeof options.runtime === "string" ? options.runtime : undefined;
60-
const automaticBaseImageUpdatesDisabled = abiuAllowed
61-
? options.automaticBaseImageUpdates === false
62-
: undefined;
6360

6461
return doSetup(
6562
projectId,
@@ -70,6 +67,5 @@ command
7067
options.primaryRegion as string | undefined,
7168
options.rootDir as string | undefined,
7269
runtime,
73-
automaticBaseImageUpdatesDisabled,
7470
);
7571
});

src/init/features/apphosting.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,9 @@ export async function doSetup(setup: Setup, config: Config, options: Options): P
9595
const prompts = await dynamicImport("./apphosting/prompts");
9696

9797
let runtime = experiments.isEnabled("abiu") ? prompts.DEFAULT_RUNTIME : undefined;
98-
let automaticBaseImageUpdatesDisabled = experiments.isEnabled("abiu") ? false : undefined;
9998

10099
if (experiments.isEnabled("abiu") && !options.nonInteractive) {
101100
runtime = await prompts.promptRuntime(projectId, location);
102-
automaticBaseImageUpdatesDisabled = !(await prompts.promptAutomaticBaseImageUpdates());
103101
}
104102

105103
const createBackendSpinner = ora("Creating your new backend...").start();
@@ -112,7 +110,6 @@ export async function doSetup(setup: Setup, config: Config, options: Options): P
112110
webApp?.id,
113111
/* rootDir= */ "/",
114112
runtime,
115-
automaticBaseImageUpdatesDisabled,
116113
);
117114

118115
createBackendSpinner.succeed(`Successfully created backend!\n\t${backend.name}\n`);

0 commit comments

Comments
 (0)