Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor createBackend and other utility functions.
Browse files Browse the repository at this point in the history
taeold committed Dec 6, 2023

Verified

This commit was signed with the committer’s verified signature.
heemankv Heemank Verma
1 parent e362f11 commit e361804
Showing 2 changed files with 60 additions and 113 deletions.
137 changes: 47 additions & 90 deletions src/init/features/frameworks/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 gcp from "../../../gcp/frameworks";
import { logBullet, logSuccess } from "../../../utils";
import { logBullet, logSuccess, logWarning } from "../../../utils";
import { frameworksOrigin } from "../../../api";
import { Backend, BackendOutputOnlyFields } from "../../../gcp/frameworks";
import { Repository } from "../../../gcp/cloudbuild";
@@ -26,32 +26,40 @@ export async function doSetup(setup: any, projectId: string): Promise<void> {

logBullet("First we need a few details to create your backend.");

await promptOnce(
{
name: "serviceName",
const location = await promptOnce({
name: "region",
type: "list",
default: DEFAULT_REGION,
message:
"Please select a region " +
`(${clc.yellow("info")}: Your region determines where your backend is located):\n`,
choices: ALLOWED_REGIONS,
});

logSuccess(`Region set to ${location}.\n`);

let backendId: string;
while (true) {
backendId = await promptOnce({
name: "backendId",
type: "input",
default: "acme-inc-web",
message: "Create a name for your backend [1-30 characters]",
},
setup.frameworks
);

await promptOnce(
{
name: "region",
type: "list",
default: DEFAULT_REGION,
message:
"Please select a region " +
`(${clc.yellow("info")}: Your region determines where your backend is located):\n`,
choices: ALLOWED_REGIONS,
},
setup.frameworks
);

logSuccess(`Region set to ${setup.frameworks.region}.\n`);

const backend: Backend | undefined = await getOrCreateBackend(projectId, setup);
});
try {
await gcp.getBackend(projectId, location, backendId);
} catch (err: any) {
if (err.status === 404) {
break;
}
throw new FirebaseError(
`Failed to check if backend with id ${backendId} already exists in ${location}`,
{ original: err }
);
}
logWarning(`Backend with id ${backendId} already exists in ${location}`);
}
const backend: Backend = await onboardBackend(projectId, location, backendId);

if (backend) {
logSuccess(`Successfully created backend:\n\t${backend.name}`);
@@ -74,75 +82,24 @@ function toBackend(cloudBuildConnRepo: Repository): Omit<Backend, BackendOutputO
}

/**
* Creates backend if it doesn't exist.
* Walkthrough the flow for creating a new backend.
*/
export async function getOrCreateBackend(
projectId: string,
setup: any
): Promise<Backend | undefined> {
const location: string = setup.frameworks.region;
try {
return await getExistingBackend(projectId, setup, location);
} catch (err: unknown) {
if ((err as FirebaseError).status === 404) {
const cloudBuildConnRepo = await repo.linkGitHubRepository(projectId, location);
await promptOnce(
{
name: "branchName",
type: "input",
default: "main",
message: "Which branch do you want to deploy?",
},
setup.frameworks
);
const backendDetails = toBackend(cloudBuildConnRepo);
return await createBackend(projectId, location, backendDetails, setup.frameworks.serviceName);
} else {
throw new FirebaseError(
`Failed to get or create a backend using the given initialization details: ${err}`
);
}
}

return undefined;
}

async function getExistingBackend(
export async function onboardBackend(
projectId: string,
setup: any,
location: string
location: string,
backendId: string
): Promise<Backend> {
let backend = await gcp.getBackend(projectId, location, setup.frameworks.serviceName);
while (backend) {
setup.frameworks.serviceName = undefined;
await promptOnce(
{
name: "existingBackend",
type: "confirm",
default: true,
message:
"A backend already exists for the given serviceName, do you want to use existing backend? (yes/no)",
},
setup.frameworks
);
if (setup.frameworks.existingBackend) {
logBullet("Using the existing backend.");
return backend;
}
await promptOnce(
{
name: "serviceName",
type: "input",
default: "acme-inc-web",
message: "Please enter a new service name [1-30 characters]",
},
setup.frameworks
);
backend = await gcp.getBackend(projectId, location, setup.frameworks.serviceName);
setup.frameworks.existingBackend = undefined;
}

return backend;
const cloudBuildConnRepo = await repo.linkGitHubRepository(projectId, location);
const barnchName = await promptOnce({
name: "branchName",
type: "input",
default: "main",
message: "Which branch do you want to deploy?",
});
// branchName unused for now.
void barnchName;
const backendDetails = toBackend(cloudBuildConnRepo);
return await createBackend(projectId, location, backendDetails, backendId);
}

/**
36 changes: 13 additions & 23 deletions src/test/init/frameworks/index.spec.ts
Original file line number Diff line number Diff line change
@@ -4,7 +4,8 @@ import { expect } from "chai";
import * as gcp from "../../../gcp/frameworks";
import * as repo from "../../../init/features/frameworks/repo";
import * as poller from "../../../operation-poller";
import { createBackend, getOrCreateBackend } from "../../../init/features/frameworks/index";
import * as prompt from "../../../prompt";
import { createBackend, onboardBackend } from "../../../init/features/frameworks/index";
import { FirebaseError } from "../../../error";

describe("operationsConverter", () => {
@@ -14,6 +15,7 @@ describe("operationsConverter", () => {
let createBackendStub: sinon.SinonStub;
let getBackendStub: sinon.SinonStub;
let linkGitHubRepositoryStub: sinon.SinonStub;
let promptOnce: sinon.SinonStub;

beforeEach(() => {
pollOperationStub = sandbox
@@ -24,42 +26,38 @@ describe("operationsConverter", () => {
linkGitHubRepositoryStub = sandbox
.stub(repo, "linkGitHubRepository")
.throws("Unexpected getBackend call");
promptOnce = sandbox.stub(prompt, "promptOnce").throws("Unexpected promptOnce call");
});

afterEach(() => {
sandbox.verifyAndRestore();
});

describe("createBackend", () => {
describe("onboardBackend", () => {
const projectId = "projectId";
const location = "us-central1";
const backendId = "backendId";

const op = {
name: `projects/${projectId}/locations/${location}/backends/${backendId}`,
done: true,
};

const completeBackend = {
name: `projects/${projectId}/locations/${location}/backends/${backendId}`,
labels: {},
createTime: "0",
updateTime: "1",
uri: "https://placeholder.com",
};
const setup = {
frameworks: {
region: location,
serviceName: backendId,
existingBackend: true,
deployMethod: "github",
branchName: "main",
},
};

const cloudBuildConnRepo = {
name: `projects/${projectId}/locations/${location}/connections/framework-${location}/repositories/repoId`,
remoteUri: "remoteUri",
createTime: "0",
updateTime: "1",
};

const backendInput: Omit<gcp.Backend, gcp.BackendOutputOnlyFields> = {
servingLocality: "GLOBAL_ACCESS",
codebase: {
@@ -68,6 +66,7 @@ describe("operationsConverter", () => {
},
labels: {},
};

it("should createBackend", async () => {
createBackendStub.resolves(op);
pollOperationStub.resolves(completeBackend);
@@ -77,27 +76,18 @@ describe("operationsConverter", () => {
expect(createBackendStub).to.be.calledWith(projectId, location, backendInput);
});

it("should return a backend, if user wants use the exiting backend", async () => {
getBackendStub.resolves(completeBackend);

const result = await getOrCreateBackend("projectId", setup);

expect(result).to.deep.equal(completeBackend);
expect(getBackendStub.calledOnceWithExactly(projectId, location, backendId)).to.be.true;
});

it("should create a new backend, if backend doesn't exist", async () => {
it("should onboard a new backend", async () => {
const newBackendId = "newBackendId";
const newPath = `projects/${projectId}/locations/${location}/backends/${newBackendId}`;
setup.frameworks.serviceName = newBackendId;
op.name = newPath;
completeBackend.name = newPath;
getBackendStub.throws(new FirebaseError("error", { status: 404 }));
linkGitHubRepositoryStub.resolves(cloudBuildConnRepo);
createBackendStub.resolves(op);
pollOperationStub.resolves(completeBackend);
promptOnce.resolves("main");

const result = await getOrCreateBackend(projectId, setup);
const result = await onboardBackend(projectId, location, backendId);

expect(result).to.deep.equal(completeBackend);
expect(createBackendStub).to.be.calledWith(projectId, location, backendInput);

0 comments on commit e361804

Please sign in to comment.