Skip to content

Commit

Permalink
Add utility commands for app hosting.
Browse files Browse the repository at this point in the history
taeold committed Dec 14, 2023

Verified

This commit was signed with the committer’s verified signature. The key has expired.
marekmosna Marek Mosna
1 parent f35a365 commit c5cad6b
Showing 8 changed files with 149 additions and 17 deletions.
32 changes: 32 additions & 0 deletions src/commands/apphosting-builds-create.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import * as apphosting from "../gcp/apphosting";
import { logger } from "../logger";
import { Command } from "../command";
import { Options } from "../options";
import { generateId } from "../utils";
import { needProjectId } from "../projectUtils";

export const command = new Command("apphosting:builds:create <backendId>")
.description("Create a build for an App Hosting backend")
.option("-l, --location <location>", "Specify the region of the backend", "us-central1")
.option("-i, --id <buildId>", "Id of the build. If not present, autogenerate a random id", "")
.option("-b, --branch <branch>", "Repository branch to deploy. Defaults to 'main'", "main")
.before(apphosting.ensureApiEnabled)
.action(async (backendId: string, options: Options) => {
const projectId = needProjectId(options);
const location = options.location as string;
const buildId = (options.buildId as string) || generateId();
const branch = options.branch as string;

const op = await apphosting.createBuild(projectId, location, backendId, buildId, {
source: {
codebase: {
branch: "main",
},
},
});

logger.info(`Started a build for backend ${backendId} on branch ${branch}.`);
logger.info("Check status by running:");
logger.info(`\tfirebase apphosting:builds:get ${backendId} ${buildId} --location ${location}`);
return op;
});
17 changes: 17 additions & 0 deletions src/commands/apphosting-builds-get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import * as apphosting from "../gcp/apphosting";
import { logger } from "../logger";
import { Command } from "../command";
import { Options } from "../options";
import { needProjectId } from "../projectUtils";

export const command = new Command("apphosting:builds:get <backendId> <buildId>")
.description("Create a build for an App Hosting backend")
.option("-l, --location <location>", "Specify the region of the backend", "us-central1")
.before(apphosting.ensureApiEnabled)
.action(async (backendId: string, buildId: string, options: Options) => {
const projectId = needProjectId(options);
const location = options.location as string;
const build = await apphosting.getBuild(projectId, location, backendId, buildId);
logger.info(JSON.stringify(build, null, 2));
return build;
});
25 changes: 25 additions & 0 deletions src/commands/apphosting-rollouts-create.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import * as apphosting from "../gcp/apphosting";
import { logger } from "../logger";
import { Command } from "../command";
import { Options } from "../options";
import { needProjectId } from "../projectUtils";
import { generateId } from "../utils";

export const command = new Command("apphosting:rollouts:create <backendId> <buildId>")
.description("Create a build for an App Hosting backend")
.option("-l, --location <location>", "Specify the region of the backend", "us-central1")
.option("-i, --id <rolloutId>", "Id of the rollout. If not present, autogenerate a random id", "")
.before(apphosting.ensureApiEnabled)
.action(async (backendId: string, buildId: string, options: Options) => {
const projectId = needProjectId(options);
const location = options.location as string;
const rolloutId = (options.buildId as string) || generateId();
const build = `projects/${projectId}/backends/${backendId}/builds/${buildId}`;
const op = await apphosting.createRollout(projectId, location, backendId, rolloutId, {
build,
});
logger.info(`Started a rollout for backend ${backendId} with build ${buildId}.`);
logger.info("Check status by running:");
logger.info(`\tfirebase apphosting:rollouts:list --location ${location}`);
return op;
});
21 changes: 21 additions & 0 deletions src/commands/apphosting-rollouts-list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import * as apphosting from "../gcp/apphosting";
import { logger } from "../logger";
import { Command } from "../command";
import { Options } from "../options";
import { needProjectId } from "../projectUtils";

export const command = new Command("apphosting:rollouts:list <backendId>")
.description("List rollouts of an App Hosting backend")
.option(
"-l, --location <location>",
"Rgion of the rollouts. Defaults to listing rollouts from all regions",
"-"
)
.before(apphosting.ensureApiEnabled)
.action(async (backendId: string, options: Options) => {
const projectId = needProjectId(options);
const location = options.location as string;
const rollouts = await apphosting.listRollouts(projectId, location, backendId);
logger.info(JSON.stringify(rollouts, null, 2));
return rollouts;
});
6 changes: 6 additions & 0 deletions src/commands/index.ts
Original file line number Diff line number Diff line change
@@ -157,6 +157,12 @@ export function load(client: any): any {
client.apphosting.backends.create = loadCommand("apphosting-backends-create");
client.apphosting.backends.get = loadCommand("apphosting-backends-get");
client.apphosting.backends.delete = loadCommand("apphosting-backends-delete");
client.apphosting.builds = {};
client.apphosting.builds.get = loadCommand("apphosting-builds-get");
client.apphosting.builds.create = loadCommand("apphosting-builds-create");
client.apphosting.rollouts = {};
client.apphosting.rollouts.create = loadCommand("apphosting-rollouts-create");
client.apphosting.rollouts.list = loadCommand("apphosting-rollouts-list");
}
client.login = loadCommand("login");
client.login.add = loadCommand("login-add");
32 changes: 30 additions & 2 deletions src/gcp/apphosting.ts
Original file line number Diff line number Diff line change
@@ -303,6 +303,20 @@ export async function deleteBackend(
return res.body;
}

/**
* Get a Build by Id
*/
export async function getBuild(
projectId: string,
location: string,
backendId: string,
buildId: string
): Promise<Build> {
const name = `projects/${projectId}/locations/${location}/backends/${backendId}/builds/${buildId}`;
const res = await client.get<Build>(name);
return res.body;
}

/**
* Creates a new Build in a given project and location.
*/
@@ -322,7 +336,7 @@ export async function createBuild(
}

/**
* Create a new rollout for a backend
* Create a new rollout for a backend.
*/
export async function createRollout(
projectId: string,
@@ -340,7 +354,21 @@ export async function createRollout(
}

/**
* Update traffic of a backend
* List all rollouts for a backend.
*/
export async function listRollouts(
projectId: string,
location: string,
backendId: string
): Promise<Rollout[]> {
const res = await client.get<{ rollouts: Rollout[] }>(
`projects/${projectId}/locations/${location}/backends/${backendId}/rollouts`
);
return res.body.rollouts;
}

/**
* Update traffic of a backend.
*/
export async function updateTraffic(
projectId: string,
16 changes: 1 addition & 15 deletions src/init/features/apphosting/index.ts
Original file line number Diff line number Diff line change
@@ -2,7 +2,7 @@ import * as clc from "colorette";
import * as repo from "./repo";
import * as poller from "../../../operation-poller";
import * as apphosting from "../../../gcp/apphosting";
import { logBullet, logSuccess, logWarning } from "../../../utils";
import { generateId, logBullet, logSuccess, logWarning } from "../../../utils";
import { apphostingOrigin } from "../../../api";
import {
Backend,
@@ -205,17 +205,3 @@ export async function onboardRollout(
logSuccess("Rollout completed.");
return { rollout, build };
}

/**
* Only lowercase, digits, and hyphens; must begin with letter, and cannot end with hyphen
*/
function generateId(n = 6): string {
const letters = "abcdefghijklmnopqrstuvwxyz";
const allChars = "01234567890-abcdefghijklmnopqrstuvwxyz";
let id = letters[Math.floor(Math.random() * letters.length)];
for (let i = 1; i < n; i++) {
const idx = Math.floor(Math.random() * allChars.length);
id += allChars[idx];
}
return id;
}
17 changes: 17 additions & 0 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -810,3 +810,20 @@ export function getHostnameFromUrl(url: string): string | null {
return null;
}
}

/**
* Generate id meeting the following criterias:
* - Lowercase, digits, and hyphens only
* - Must begin with letter
* - Cannot end with hyphen
*/
export function generateId(n = 6): string {
const letters = "abcdefghijklmnopqrstuvwxyz";
const allChars = "01234567890-abcdefghijklmnopqrstuvwxyz";
let id = letters[Math.floor(Math.random() * letters.length)];
for (let i = 1; i < n; i++) {
const idx = Math.floor(Math.random() * allChars.length);
id += allChars[idx];
}
return id;
}

0 comments on commit c5cad6b

Please sign in to comment.