Skip to content

Commit 33f4c48

Browse files
committed
WIP: Manage GCB connection resources more carefully.
1 parent edbbc62 commit 33f4c48

File tree

4 files changed

+215
-146
lines changed

4 files changed

+215
-146
lines changed

src/gcp/cloudbuild.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -85,14 +85,15 @@ interface LinkableRepositories {
8585
export async function createConnection(
8686
projectId: string,
8787
location: string,
88-
connectionId: string
88+
connectionId: string,
89+
githubConfig: GitHubConfig = {}
8990
): Promise<Operation> {
9091
const res = await client.post<
9192
Omit<Omit<Connection, "name">, ConnectionOutputOnlyFields>,
9293
Operation
9394
>(
9495
`projects/${projectId}/locations/${location}/connections`,
95-
{ githubConfig: {} },
96+
{ githubConfig },
9697
{ queryParams: { connectionId } }
9798
);
9899
return res.body;

src/init/features/frameworks/index.ts

Lines changed: 126 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -1,170 +1,171 @@
11
import * as clc from "colorette";
22
import * as utils from "../../../utils";
3-
import { logger } from "../../../logger";
4-
import { promptOnce } from "../../../prompt";
5-
import { DEFAULT_REGION, ALLOWED_REGIONS } from "./constants";
63
import * as repo from "./repo";
7-
import { Backend, BackendOutputOnlyFields } from "../../../gcp/frameworks";
8-
import { Repository } from "../../../gcp/cloudbuild";
94
import * as poller from "../../../operation-poller";
10-
import { frameworksOrigin } from "../../../api";
115
import * as gcp from "../../../gcp/frameworks";
12-
import { API_VERSION } from "../../../gcp/frameworks";
13-
import { FirebaseError } from "../../../error";
6+
import {frameworksOrigin} from "../../../api";
7+
import {Backend, BackendOutputOnlyFields} from "../../../gcp/frameworks";
8+
import {Repository} from "../../../gcp/cloudbuild";
9+
import {API_VERSION} from "../../../gcp/frameworks";
10+
import {FirebaseError} from "../../../error";
11+
import {logger} from "../../../logger";
12+
import {promptOnce} from "../../../prompt";
13+
import {DEFAULT_REGION, ALLOWED_REGIONS} from "./constants";
1414

1515
const frameworksPollerOptions: Omit<poller.OperationPollerOptions, "operationResourceName"> = {
16-
apiOrigin: frameworksOrigin,
17-
apiVersion: API_VERSION,
18-
masterTimeout: 25 * 60 * 1_000,
19-
maxBackoff: 10_000,
16+
apiOrigin: frameworksOrigin,
17+
apiVersion: API_VERSION,
18+
masterTimeout: 25 * 60 * 1_000,
19+
maxBackoff: 10_000,
2020
};
2121

2222
/**
2323
* Setup new frameworks project.
2424
*/
2525
export async function doSetup(setup: any, projectId: string): Promise<void> {
26-
setup.frameworks = {};
26+
setup.frameworks = {};
2727

28-
utils.logBullet("First we need a few details to create your backend.");
28+
utils.logBullet("First we need a few details to create your backend.");
2929

30-
await promptOnce(
31-
{
32-
name: "serviceName",
33-
type: "input",
34-
default: "acme-inc-web",
35-
message: "Create a name for your backend [1-30 characters]",
36-
},
37-
setup.frameworks
38-
);
30+
await promptOnce(
31+
{
32+
name: "serviceName",
33+
type: "input",
34+
default: "acme-inc-web",
35+
message: "Create a name for your backend [1-30 characters]",
36+
},
37+
setup.frameworks
38+
);
3939

40-
await promptOnce(
41-
{
42-
name: "region",
43-
type: "list",
44-
default: DEFAULT_REGION,
45-
message:
46-
"Please select a region " +
47-
`(${clc.yellow("info")}: Your region determines where your backend is located):\n`,
48-
choices: ALLOWED_REGIONS,
49-
},
50-
setup.frameworks
51-
);
40+
await promptOnce(
41+
{
42+
name: "region",
43+
type: "list",
44+
default: DEFAULT_REGION,
45+
message:
46+
"Please select a region " +
47+
`(${clc.yellow("info")}: Your region determines where your backend is located):\n`,
48+
choices: ALLOWED_REGIONS,
49+
},
50+
setup.frameworks
51+
);
5252

53-
utils.logSuccess(`Region set to ${setup.frameworks.region}.`);
53+
utils.logSuccess(`Region set to ${setup.frameworks.region}.`);
5454

55-
const backend: Backend | undefined = await getOrCreateBackend(projectId, setup);
56-
if (backend) {
57-
logger.info();
58-
utils.logSuccess(`Successfully created backend:\n ${backend.name}`);
59-
logger.info();
60-
utils.logSuccess(`Your site is being deployed at:\n https://${backend.uri}`);
61-
logger.info();
62-
utils.logSuccess(
63-
`View the rollout status by running:\n firebase backends:get --backend=${backend.name}`
64-
);
65-
logger.info();
66-
}
55+
const backend: Backend | undefined = await getOrCreateBackend(projectId, setup);
56+
57+
if (backend) {
58+
logger.info();
59+
utils.logSuccess(`Successfully created backend:\n ${backend.name}`);
60+
logger.info();
61+
utils.logSuccess(`Your site is being deployed at:\n https://${backend.uri}`);
62+
logger.info();
63+
utils.logSuccess(
64+
`View the rollout status by running:\n firebase backends:get --backend=${backend.name}`
65+
);
66+
logger.info();
67+
}
6768
}
6869

6970
function toBackend(cloudBuildConnRepo: Repository): Omit<Backend, BackendOutputOnlyFields> {
70-
return {
71-
codebase: {
72-
repository: `${cloudBuildConnRepo.name}`,
73-
rootDirectory: "/",
74-
},
75-
labels: {},
76-
};
71+
return {
72+
codebase: {
73+
repository: `${cloudBuildConnRepo.name}`,
74+
rootDirectory: "/",
75+
},
76+
labels: {},
77+
};
7778
}
7879

7980
/**
8081
* Creates backend if it doesn't exist.
8182
*/
8283
export async function getOrCreateBackend(
83-
projectId: string,
84-
setup: any
84+
projectId: string,
85+
setup: any
8586
): Promise<Backend | undefined> {
86-
const location: string = setup.frameworks.region;
87-
try {
88-
return await getExistingBackend(projectId, setup, location);
89-
} catch (err: unknown) {
90-
if ((err as FirebaseError).status === 404) {
91-
const cloudBuildConnRepo = await repo.linkGitHubRepository(projectId, location);
92-
logger.info();
93-
await promptOnce(
94-
{
95-
name: "branchName",
96-
type: "input",
97-
default: "main",
98-
message: "Which branch do you want to deploy?",
99-
},
100-
setup.frameworks
101-
);
102-
const backendDetails = toBackend(cloudBuildConnRepo);
103-
logger.info(clc.bold(`\n${clc.white("===")} Creating your backend`));
104-
return await createBackend(projectId, location, backendDetails, setup.frameworks.serviceName);
105-
} else {
106-
throw new FirebaseError(
107-
`Failed to get or create a backend using the given initialization details: ${err}`
108-
);
87+
const location: string = setup.frameworks.region;
88+
try {
89+
return await getExistingBackend(projectId, setup, location);
90+
} catch (err: unknown) {
91+
if ((err as FirebaseError).status === 404) {
92+
const cloudBuildConnRepo = await repo.linkGitHubRepository(projectId, location);
93+
logger.info();
94+
await promptOnce(
95+
{
96+
name: "branchName",
97+
type: "input",
98+
default: "main",
99+
message: "Which branch do you want to deploy?",
100+
},
101+
setup.frameworks
102+
);
103+
const backendDetails = toBackend(cloudBuildConnRepo);
104+
logger.info(clc.bold(`\n${clc.white("===")} Creating your backend`));
105+
return await createBackend(projectId, location, backendDetails, setup.frameworks.serviceName);
106+
} else {
107+
throw new FirebaseError(
108+
`Failed to get or create a backend using the given initialization details: ${err}`
109+
);
110+
}
109111
}
110-
}
111112

112-
return undefined;
113+
return undefined;
113114
}
114115

115116
async function getExistingBackend(
116-
projectId: string,
117-
setup: any,
118-
location: string
117+
projectId: string,
118+
setup: any,
119+
location: string
119120
): Promise<Backend> {
120-
let backend = await gcp.getBackend(projectId, location, setup.frameworks.serviceName);
121-
while (backend) {
122-
setup.frameworks.serviceName = undefined;
123-
await promptOnce(
124-
{
125-
name: "existingBackend",
126-
type: "confirm",
127-
default: true,
128-
message:
129-
"A backend already exists for the given serviceName, do you want to use existing backend? (yes/no)",
130-
},
131-
setup.frameworks
132-
);
133-
if (setup.frameworks.existingBackend) {
134-
logger.info("Using the existing backend.");
135-
return backend;
121+
let backend = await gcp.getBackend(projectId, location, setup.frameworks.serviceName);
122+
while (backend) {
123+
setup.frameworks.serviceName = undefined;
124+
await promptOnce(
125+
{
126+
name: "existingBackend",
127+
type: "confirm",
128+
default: true,
129+
message:
130+
"A backend already exists for the given serviceName, do you want to use existing backend? (yes/no)",
131+
},
132+
setup.frameworks
133+
);
134+
if (setup.frameworks.existingBackend) {
135+
logger.info("Using the existing backend.");
136+
return backend;
137+
}
138+
await promptOnce(
139+
{
140+
name: "serviceName",
141+
type: "input",
142+
default: "acme-inc-web",
143+
message: "Please enter a new service name [1-30 characters]",
144+
},
145+
setup.frameworks
146+
);
147+
backend = await gcp.getBackend(projectId, location, setup.frameworks.serviceName);
148+
setup.frameworks.existingBackend = undefined;
136149
}
137-
await promptOnce(
138-
{
139-
name: "serviceName",
140-
type: "input",
141-
default: "acme-inc-web",
142-
message: "Please enter a new service name [1-30 characters]",
143-
},
144-
setup.frameworks
145-
);
146-
backend = await gcp.getBackend(projectId, location, setup.frameworks.serviceName);
147-
setup.frameworks.existingBackend = undefined;
148-
}
149150

150-
return backend;
151+
return backend;
151152
}
152153

153154
/**
154155
* Creates backend object from long running operations.
155156
*/
156157
export async function createBackend(
157-
projectId: string,
158-
location: string,
159-
backendReqBoby: Omit<Backend, BackendOutputOnlyFields>,
160-
backendId: string
158+
projectId: string,
159+
location: string,
160+
backendReqBoby: Omit<Backend, BackendOutputOnlyFields>,
161+
backendId: string
161162
): Promise<Backend> {
162-
const op = await gcp.createBackend(projectId, location, backendReqBoby, backendId);
163-
const backend = await poller.pollOperation<Backend>({
164-
...frameworksPollerOptions,
165-
pollerName: `create-${projectId}-${location}-${backendId}`,
166-
operationResourceName: op.name,
167-
});
163+
const op = await gcp.createBackend(projectId, location, backendReqBoby, backendId);
164+
const backend = await poller.pollOperation<Backend>({
165+
...frameworksPollerOptions,
166+
pollerName: `create-${projectId}-${location}-${backendId}`,
167+
operationResourceName: op.name,
168+
});
168169

169-
return backend;
170+
return backend;
170171
}

0 commit comments

Comments
 (0)