Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 13 additions & 4 deletions src/apphosting/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
// SSL.
const maybeNodeError = err as { cause: { code: string }; code: string };
if (
/HANDSHAKE_FAILURE/.test(maybeNodeError?.cause?.code) ||

Check warning on line 55 in src/apphosting/backend.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Use `String#includes()` method with a string instead
"EPROTO" === maybeNodeError?.code
) {
return false;
Expand Down Expand Up @@ -134,12 +134,21 @@
if (nonInteractive) {
runtime = DEFAULT_RUNTIME;
} else {
const choices: Choice<string>[] = [{ name: "Node.js (default)", value: DEFAULT_RUNTIME }];
try {
const supportedRuntimes = await apphosting.listSupportedRuntimes(projectId, location);
for (const r of supportedRuntimes) {
if (r.runtimeId !== DEFAULT_RUNTIME) {
choices.push({ name: r.runtimeId, value: r.runtimeId });
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

For dynamically listed runtimes, it would be more user-friendly to display the name property from the SupportedRuntime interface rather than just the runtimeId. The SupportedRuntime interface already includes a name field that can be used for this purpose.

Suggested change
choices.push({ name: r.runtimeId, value: r.runtimeId });
choices.push({ name: r.name, value: r.runtimeId });

}
}
} catch (err) {
logWarning("Failed to list supported runtimes. Falling back to default.");
}

runtime = await select({
message: "Which runtime do you want to use?",
choices: [
{ name: "Node.js (default)", value: DEFAULT_RUNTIME },
{ name: "Node.js 22", value: "nodejs22" },
],
choices: choices,
default: DEFAULT_RUNTIME,
});
}
Expand Down Expand Up @@ -337,7 +346,7 @@
* Prompts the user for a backend id and verifies that it doesn't match a pre-existing backend.
*/
export async function promptNewBackendId(projectId: string, location: string): Promise<string> {
while (true) {

Check warning on line 349 in src/apphosting/backend.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unexpected constant condition
const backendId = await input({
default: "my-web-app",
message: "Provide a name for your backend [1-30 characters]",
Expand Down Expand Up @@ -650,7 +659,7 @@
message: locationDisambugationPrompt,
choices: [...backendsByLocation.keys()],
});
return backendsByLocation.get(location)!;

Check warning on line 662 in src/apphosting/backend.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Forbidden non-null assertion
}

/**
Expand Down
12 changes: 12 additions & 0 deletions src/gcp/apphosting.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -278,5 +278,17 @@ describe("apphosting", () => {
queryParams: { pageToken: "2" },
});
});

it("lists supported runtimes", async () => {
get.resolves({
body: {
supportedRuntimes: [{ runtimeId: "nodejs22" }],
},
});
await expect(apphosting.listSupportedRuntimes("p", "l")).to.eventually.deep.equal([
{ runtimeId: "nodejs22" },
]);
expect(get).to.have.been.calledWithMatch("projects/p/locations/l/supportedRuntimes");
});
});
});
24 changes: 24 additions & 0 deletions src/gcp/apphosting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,18 @@
automaticBaseImageUpdatesDisabled?: boolean;
}

export interface SupportedRuntime {
name: string;
runtimeId: string;
automaticBaseImageUpdatesSupported: boolean;
deprecateTime?: string;
decommissionTime?: string;
}

export interface ListSupportedRuntimesResponse {
supportedRuntimes: SupportedRuntime[];
}

export interface ManagedResource {
runService: { service: string };
}
Expand Down Expand Up @@ -298,7 +310,7 @@
done: boolean;
// oneof result
error?: Status;
response?: any;

Check warning on line 313 in src/gcp/apphosting.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unexpected any. Specify a different type
// end oneof result
}

Expand Down Expand Up @@ -711,17 +723,29 @@
return locations;
}

/**
* Lists supported runtimes for a given project and location.
*/
export async function listSupportedRuntimes(
projectId: string,
location: string,
): Promise<SupportedRuntime[]> {
const name = `projects/${projectId}/locations/${location}/supportedRuntimes`;
const res = await client.get<ListSupportedRuntimesResponse>(name);
return res.body.supportedRuntimes || [];
}

/**
* Ensure that the App Hosting API is enabled on the project.
*/
export async function ensureApiEnabled(options: any): Promise<void> {

Check warning on line 741 in src/gcp/apphosting.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unexpected any. Specify a different type
const projectId = needProjectId(options);

Check warning on line 742 in src/gcp/apphosting.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe argument of type `any` assigned to a parameter of type `{ projectId?: string | undefined; project?: string | undefined; rc?: RC | undefined; }`
return await ensure(projectId, apphostingOrigin(), "app hosting", true);
}

/**
* Generates the next build ID to fit with the naming scheme of the backend API.
* @param counter Overrides the counter to use, avoiding an API call.

Check warning on line 748 in src/gcp/apphosting.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Expected @param names to be "projectId, location, backendId, counter". Got "counter"
*/
export async function getNextRolloutId(
projectId: string,
Expand Down
Loading