firebase-tools 13.5.0 → 13.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/api.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
exports.setScopes = exports.getScopes = exports.githubClientSecret = exports.githubClientId = exports.computeOrigin = exports.secretManagerOrigin = void 0;
|
|
3
|
+
exports.apphostingOrigin = exports.serviceUsageOrigin = exports.cloudRunApiOrigin = exports.hostingApiOrigin = exports.firebaseStorageOrigin = exports.storageOrigin = exports.runtimeconfigOrigin = exports.rulesOrigin = exports.resourceManagerOrigin = exports.remoteConfigApiOrigin = exports.rtdbMetadataOrigin = exports.rtdbManagementOrigin = exports.realtimeOrigin = exports.extensionsTOSOrigin = exports.extensionsPublisherOrigin = exports.extensionsOrigin = exports.iamOrigin = exports.identityOrigin = exports.hostingOrigin = exports.googleOrigin = exports.pubsubOrigin = exports.cloudTasksOrigin = exports.cloudschedulerOrigin = exports.developerConnectP4SAOrigin = exports.developerConnectOrigin = exports.cloudbuildOrigin = exports.functionsDefaultRegion = exports.runOrigin = exports.functionsV2Origin = exports.functionsOrigin = exports.firestoreOrigin = exports.firestoreOriginOrEmulator = exports.firedataOrigin = exports.firebaseExtensionsRegistryOrigin = exports.firebaseApiOrigin = exports.eventarcOrigin = exports.dynamicLinksKey = exports.dynamicLinksOrigin = exports.deployOrigin = exports.consoleOrigin = exports.authOrigin = exports.appDistributionOrigin = exports.artifactRegistryDomain = exports.containerRegistryDomain = exports.cloudMonitoringOrigin = exports.cloudloggingOrigin = exports.cloudbillingOrigin = exports.clientSecret = exports.clientId = exports.authProxyOrigin = void 0;
|
|
4
|
+
exports.setScopes = exports.getScopes = exports.githubClientSecret = exports.githubClientId = exports.computeOrigin = exports.secretManagerOrigin = exports.githubApiOrigin = exports.githubOrigin = void 0;
|
|
5
5
|
const constants_1 = require("./emulator/constants");
|
|
6
6
|
const logger_1 = require("./logger");
|
|
7
7
|
const scopes = require("./scopes");
|
|
@@ -37,6 +37,8 @@ exports.functionsV2Origin = utils.envOverride("FIREBASE_FUNCTIONS_V2_URL", "http
|
|
|
37
37
|
exports.runOrigin = utils.envOverride("CLOUD_RUN_URL", "https://run.googleapis.com");
|
|
38
38
|
exports.functionsDefaultRegion = utils.envOverride("FIREBASE_FUNCTIONS_DEFAULT_REGION", "us-central1");
|
|
39
39
|
exports.cloudbuildOrigin = utils.envOverride("FIREBASE_CLOUDBUILD_URL", "https://cloudbuild.googleapis.com");
|
|
40
|
+
exports.developerConnectOrigin = utils.envOverride("FIREBASE_DEVELOPERCONNECT_URL", "https://developerconnect.googleapis.com");
|
|
41
|
+
exports.developerConnectP4SAOrigin = utils.envOverride("FIREBASE_DEVELOPERCONNECT_P4SA_URL", "gcp-sa-developerconnect.iam.gserviceaccount.com");
|
|
40
42
|
exports.cloudschedulerOrigin = utils.envOverride("FIREBASE_CLOUDSCHEDULER_URL", "https://cloudscheduler.googleapis.com");
|
|
41
43
|
exports.cloudTasksOrigin = utils.envOverride("FIREBASE_CLOUD_TAKS_URL", "https://cloudtasks.googleapis.com");
|
|
42
44
|
exports.pubsubOrigin = utils.envOverride("FIREBASE_PUBSUB_URL", "https://pubsub.googleapis.com");
|
|
@@ -189,6 +189,7 @@ function inferDetailsFromExisting(want, have, usedDotenv) {
|
|
|
189
189
|
if (!haveE) {
|
|
190
190
|
continue;
|
|
191
191
|
}
|
|
192
|
+
wantE.runServiceId = haveE.runServiceId;
|
|
192
193
|
if (!usedDotenv) {
|
|
193
194
|
wantE.environmentVariables = Object.assign(Object.assign({}, haveE.environmentVariables), wantE.environmentVariables);
|
|
194
195
|
}
|
|
@@ -35,9 +35,9 @@ const EMULATOR_UPDATE_DETAILS = {
|
|
|
35
35
|
ui: experiments.isEnabled("emulatoruisnapshot")
|
|
36
36
|
? { version: "SNAPSHOT", expectedSize: -1, expectedChecksum: "" }
|
|
37
37
|
: {
|
|
38
|
-
version: "1.11.
|
|
39
|
-
expectedSize:
|
|
40
|
-
expectedChecksum: "
|
|
38
|
+
version: "1.11.8",
|
|
39
|
+
expectedSize: 3523907,
|
|
40
|
+
expectedChecksum: "49f6dc1911dda9d10df62a6c09aaf9a0",
|
|
41
41
|
},
|
|
42
42
|
pubsub: {
|
|
43
43
|
version: "0.7.1",
|
|
@@ -83,7 +83,7 @@ exports.DownloadDetails = {
|
|
|
83
83
|
version: EMULATOR_UPDATE_DETAILS.ui.version,
|
|
84
84
|
downloadPath: path.join(CACHE_DIR, `ui-v${EMULATOR_UPDATE_DETAILS.ui.version}.zip`),
|
|
85
85
|
unzipDir: path.join(CACHE_DIR, `ui-v${EMULATOR_UPDATE_DETAILS.ui.version}`),
|
|
86
|
-
binaryPath: path.join(CACHE_DIR, `ui-v${EMULATOR_UPDATE_DETAILS.ui.version}`, "server", "server.
|
|
86
|
+
binaryPath: path.join(CACHE_DIR, `ui-v${EMULATOR_UPDATE_DETAILS.ui.version}`, "server", "server.mjs"),
|
|
87
87
|
opts: {
|
|
88
88
|
cacheDir: CACHE_DIR,
|
|
89
89
|
remoteUrl: `https://storage.googleapis.com/firebase-preview-drop/emulator/ui-v${EMULATOR_UPDATE_DETAILS.ui.version}.zip`,
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.serviceAgentEmail = exports.getGitRepositoryLink = exports.createGitRepositoryLink = exports.fetchLinkableGitRepositories = exports.listConnections = exports.getConnection = exports.createConnection = exports.client = void 0;
|
|
4
|
+
const apiv2_1 = require("../apiv2");
|
|
5
|
+
const api_1 = require("../api");
|
|
6
|
+
const PAGE_SIZE_MAX = 100;
|
|
7
|
+
exports.client = new apiv2_1.Client({
|
|
8
|
+
urlPrefix: api_1.developerConnectOrigin,
|
|
9
|
+
auth: true,
|
|
10
|
+
apiVersion: "v1",
|
|
11
|
+
});
|
|
12
|
+
async function createConnection(projectId, location, connectionId, githubConfig) {
|
|
13
|
+
const config = Object.assign(Object.assign({}, githubConfig), { githubApp: "FIREBASE" });
|
|
14
|
+
const res = await exports.client.post(`projects/${projectId}/locations/${location}/connections`, {
|
|
15
|
+
githubConfig: config,
|
|
16
|
+
}, { queryParams: { connectionId } });
|
|
17
|
+
return res.body;
|
|
18
|
+
}
|
|
19
|
+
exports.createConnection = createConnection;
|
|
20
|
+
async function getConnection(projectId, location, connectionId) {
|
|
21
|
+
const name = `projects/${projectId}/locations/${location}/connections/${connectionId}`;
|
|
22
|
+
const res = await exports.client.get(name);
|
|
23
|
+
return res.body;
|
|
24
|
+
}
|
|
25
|
+
exports.getConnection = getConnection;
|
|
26
|
+
async function listConnections(projectId, location) {
|
|
27
|
+
const conns = [];
|
|
28
|
+
const getNextPage = async (pageToken = "") => {
|
|
29
|
+
const res = await exports.client.get(`/projects/${projectId}/locations/${location}/connections`, {
|
|
30
|
+
queryParams: {
|
|
31
|
+
pageSize: PAGE_SIZE_MAX,
|
|
32
|
+
pageToken,
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
if (Array.isArray(res.body.connections)) {
|
|
36
|
+
conns.push(...res.body.connections);
|
|
37
|
+
}
|
|
38
|
+
if (res.body.nextPageToken) {
|
|
39
|
+
await getNextPage(res.body.nextPageToken);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
await getNextPage();
|
|
43
|
+
return conns;
|
|
44
|
+
}
|
|
45
|
+
exports.listConnections = listConnections;
|
|
46
|
+
async function fetchLinkableGitRepositories(projectId, location, connectionId, pageToken = "", pageSize = 1000) {
|
|
47
|
+
const name = `projects/${projectId}/locations/${location}/connections/${connectionId}:fetchLinkableRepositories`;
|
|
48
|
+
const res = await exports.client.get(name, {
|
|
49
|
+
queryParams: {
|
|
50
|
+
pageSize,
|
|
51
|
+
pageToken,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
return res.body;
|
|
55
|
+
}
|
|
56
|
+
exports.fetchLinkableGitRepositories = fetchLinkableGitRepositories;
|
|
57
|
+
async function createGitRepositoryLink(projectId, location, connectionId, gitRepositoryLinkId, cloneUri) {
|
|
58
|
+
const res = await exports.client.post(`projects/${projectId}/locations/${location}/connections/${connectionId}/gitRepositoryLinks`, { cloneUri }, { queryParams: { gitRepositoryLinkId } });
|
|
59
|
+
return res.body;
|
|
60
|
+
}
|
|
61
|
+
exports.createGitRepositoryLink = createGitRepositoryLink;
|
|
62
|
+
async function getGitRepositoryLink(projectId, location, connectionId, gitRepositoryLinkId) {
|
|
63
|
+
const name = `projects/${projectId}/locations/${location}/connections/${connectionId}/gitRepositoryLinks/${gitRepositoryLinkId}`;
|
|
64
|
+
const res = await exports.client.get(name);
|
|
65
|
+
return res.body;
|
|
66
|
+
}
|
|
67
|
+
exports.getGitRepositoryLink = getGitRepositoryLink;
|
|
68
|
+
function serviceAgentEmail(projectNumber) {
|
|
69
|
+
return `service-${projectNumber}@${api_1.developerConnectP4SAOrigin}`;
|
|
70
|
+
}
|
|
71
|
+
exports.serviceAgentEmail = serviceAgentEmail;
|
|
@@ -172,9 +172,31 @@ async function orchestrateRollout(projectId, location, backendId, buildInput) {
|
|
|
172
172
|
(0, utils_1.logBullet)("Starting a new rollout... this may take a few minutes.");
|
|
173
173
|
const buildId = await apphosting.getNextRolloutId(projectId, location, backendId, 1);
|
|
174
174
|
const buildOp = await apphosting.createBuild(projectId, location, backendId, buildId, buildInput);
|
|
175
|
-
const
|
|
175
|
+
const rolloutBody = {
|
|
176
176
|
build: `projects/${projectId}/locations/${location}/backends/${backendId}/builds/${buildId}`,
|
|
177
|
-
}
|
|
177
|
+
};
|
|
178
|
+
let tries = 0;
|
|
179
|
+
let done = false;
|
|
180
|
+
while (!done) {
|
|
181
|
+
tries++;
|
|
182
|
+
try {
|
|
183
|
+
const validateOnly = true;
|
|
184
|
+
await apphosting.createRollout(projectId, location, backendId, buildId, rolloutBody, validateOnly);
|
|
185
|
+
done = true;
|
|
186
|
+
}
|
|
187
|
+
catch (err) {
|
|
188
|
+
if (err instanceof error_1.FirebaseError && err.status === 400) {
|
|
189
|
+
if (tries >= 5) {
|
|
190
|
+
throw err;
|
|
191
|
+
}
|
|
192
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
throw err;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
const rolloutOp = await apphosting.createRollout(projectId, location, backendId, buildId, rolloutBody);
|
|
178
200
|
const rolloutPoll = poller.pollOperation(Object.assign(Object.assign({}, apphostingPollerOptions), { pollerName: `create-${projectId}-${location}-backend-${backendId}-rollout-${buildId}`, operationResourceName: rolloutOp.name }));
|
|
179
201
|
const buildPoll = poller.pollOperation(Object.assign(Object.assign({}, apphostingPollerOptions), { pollerName: `create-${projectId}-${location}-backend-${backendId}-build-${buildId}`, operationResourceName: buildOp.name }));
|
|
180
202
|
const [rollout, build] = await Promise.all([rolloutPoll, buildPoll]);
|
|
@@ -49,107 +49,107 @@ function generateConnectionId() {
|
|
|
49
49
|
const randomHash = Math.random().toString(36).slice(6);
|
|
50
50
|
return `apphosting-github-conn-${randomHash}`;
|
|
51
51
|
}
|
|
52
|
-
const ADD_REPO_CHOICE = "@ADD_REPO";
|
|
53
52
|
const ADD_CONN_CHOICE = "@ADD_CONN";
|
|
54
|
-
const CONFIGURE_REMOTE_URI_CHOICES = [ADD_REPO_CHOICE, ADD_CONN_CHOICE];
|
|
55
53
|
async function linkGitHubRepository(projectId, location) {
|
|
56
|
-
var _a, _b
|
|
54
|
+
var _a, _b;
|
|
57
55
|
utils.logBullet(clc.bold(`${clc.yellow("===")} Set up a GitHub connection`));
|
|
58
|
-
|
|
59
|
-
while (oauthConn.installationState.stage === "PENDING_USER_OAUTH") {
|
|
60
|
-
oauthConn = await promptConnectionAuth(oauthConn);
|
|
61
|
-
}
|
|
56
|
+
const oauthConn = await getOrCreateOauthConnection(projectId, location);
|
|
62
57
|
const existingConns = await listAppHostingConnections(projectId);
|
|
63
|
-
if (existingConns.length
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
throw new error_1.FirebaseError("Insufficient IAM permissions to create a new connection to GitHub");
|
|
67
|
-
}
|
|
68
|
-
const connectionId = generateConnectionId();
|
|
69
|
-
const conn = await createConnection(projectId, location, connectionId, {
|
|
70
|
-
authorizerCredential: (_a = oauthConn.githubConfig) === null || _a === void 0 ? void 0 : _a.authorizerCredential,
|
|
71
|
-
});
|
|
72
|
-
let refreshedConn = conn;
|
|
73
|
-
while (refreshedConn.installationState.stage !== "COMPLETE") {
|
|
74
|
-
refreshedConn = await promptAppInstall(conn);
|
|
75
|
-
}
|
|
76
|
-
existingConns.push(refreshedConn);
|
|
58
|
+
if (existingConns.length === 0) {
|
|
59
|
+
await ensureSecretManagerAdminGrant(projectId);
|
|
60
|
+
existingConns.push(await createFullyInstalledConnection(projectId, location, generateConnectionId(), oauthConn));
|
|
77
61
|
}
|
|
78
|
-
let
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
await (
|
|
83
|
-
type: "input",
|
|
84
|
-
message: "Press ENTER once you have provided the GitHub app installation with access to your desired repository.",
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
else if (remoteUri === ADD_CONN_CHOICE) {
|
|
88
|
-
const connectionId = generateConnectionId();
|
|
89
|
-
const conn = await createConnection(projectId, location, connectionId, {
|
|
90
|
-
authorizerCredential: (_b = oauthConn.githubConfig) === null || _b === void 0 ? void 0 : _b.authorizerCredential,
|
|
91
|
-
});
|
|
92
|
-
let refreshedConn = conn;
|
|
93
|
-
while (refreshedConn.installationState.stage !== "COMPLETE") {
|
|
94
|
-
refreshedConn = await promptAppInstall(conn);
|
|
95
|
-
}
|
|
96
|
-
existingConns.push(refreshedConn);
|
|
62
|
+
let repoRemoteUri;
|
|
63
|
+
let connection;
|
|
64
|
+
do {
|
|
65
|
+
if (repoRemoteUri === ADD_CONN_CHOICE) {
|
|
66
|
+
existingConns.push(await createFullyInstalledConnection(projectId, location, generateConnectionId(), oauthConn));
|
|
97
67
|
}
|
|
98
68
|
const selection = await promptRepositoryUri(projectId, existingConns);
|
|
99
|
-
|
|
69
|
+
repoRemoteUri = selection.remoteUri;
|
|
100
70
|
connection = selection.connection;
|
|
101
|
-
}
|
|
71
|
+
} while (repoRemoteUri === ADD_CONN_CHOICE);
|
|
102
72
|
const { id: connectionId } = parseConnectionName(connection.name);
|
|
103
73
|
await getOrCreateConnection(projectId, location, connectionId, {
|
|
104
|
-
authorizerCredential: (
|
|
105
|
-
appInstallationId: (
|
|
74
|
+
authorizerCredential: (_a = connection.githubConfig) === null || _a === void 0 ? void 0 : _a.authorizerCredential,
|
|
75
|
+
appInstallationId: (_b = connection.githubConfig) === null || _b === void 0 ? void 0 : _b.appInstallationId,
|
|
106
76
|
});
|
|
107
|
-
const repo = await getOrCreateRepository(projectId, location, connectionId,
|
|
77
|
+
const repo = await getOrCreateRepository(projectId, location, connectionId, repoRemoteUri);
|
|
108
78
|
utils.logSuccess(`Successfully linked GitHub repository at remote URI`);
|
|
109
|
-
utils.logSuccess(`\t${
|
|
79
|
+
utils.logSuccess(`\t${repoRemoteUri}`);
|
|
110
80
|
return repo;
|
|
111
81
|
}
|
|
112
82
|
exports.linkGitHubRepository = linkGitHubRepository;
|
|
83
|
+
async function createFullyInstalledConnection(projectId, location, connectionId, oauthConn) {
|
|
84
|
+
var _a;
|
|
85
|
+
let conn = await createConnection(projectId, location, connectionId, {
|
|
86
|
+
authorizerCredential: (_a = oauthConn.githubConfig) === null || _a === void 0 ? void 0 : _a.authorizerCredential,
|
|
87
|
+
});
|
|
88
|
+
while (conn.installationState.stage !== "COMPLETE") {
|
|
89
|
+
utils.logBullet("Install the Cloud Build GitHub app to enable access to GitHub repositories");
|
|
90
|
+
const targetUri = conn.installationState.actionUri.replace("install_v2", "direct_install_v2");
|
|
91
|
+
utils.logBullet(targetUri);
|
|
92
|
+
await utils.openInBrowser(targetUri);
|
|
93
|
+
await (0, prompt_1.promptOnce)({
|
|
94
|
+
type: "input",
|
|
95
|
+
message: "Press Enter once you have installed or configured the Cloud Build GitHub app to access your GitHub repo.",
|
|
96
|
+
});
|
|
97
|
+
conn = await gcb.getConnection(projectId, location, connectionId);
|
|
98
|
+
}
|
|
99
|
+
return conn;
|
|
100
|
+
}
|
|
101
|
+
async function getOrCreateOauthConnection(projectId, location) {
|
|
102
|
+
let conn = await getOrCreateConnection(projectId, location, APPHOSTING_OAUTH_CONN_NAME);
|
|
103
|
+
while (conn.installationState.stage === "PENDING_USER_OAUTH") {
|
|
104
|
+
utils.logBullet("You must authorize the Cloud Build GitHub app.");
|
|
105
|
+
utils.logBullet("Sign in to GitHub and authorize Cloud Build GitHub app:");
|
|
106
|
+
const { url, cleanup } = await utils.openInBrowserPopup(conn.installationState.actionUri, "Authorize the GitHub app");
|
|
107
|
+
utils.logBullet(`\t${url}`);
|
|
108
|
+
await (0, prompt_1.promptOnce)({
|
|
109
|
+
type: "input",
|
|
110
|
+
message: "Press Enter once you have authorized the app",
|
|
111
|
+
});
|
|
112
|
+
cleanup();
|
|
113
|
+
const { projectId, location, id } = parseConnectionName(conn.name);
|
|
114
|
+
conn = await gcb.getConnection(projectId, location, id);
|
|
115
|
+
}
|
|
116
|
+
return conn;
|
|
117
|
+
}
|
|
113
118
|
async function promptRepositoryUri(projectId, connections) {
|
|
114
119
|
const { repos, remoteUriToConnection } = await fetchAllRepositories(projectId, connections);
|
|
115
|
-
const searchRepos = (repos) => async (_, input = "") => {
|
|
116
|
-
return [
|
|
117
|
-
new inquirer.Separator(),
|
|
118
|
-
{
|
|
119
|
-
name: "Missing a repo? Select this option to configure your installation's access settings",
|
|
120
|
-
value: ADD_REPO_CHOICE,
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
name: "Missing an account or org? Select this option to create a new connection",
|
|
124
|
-
value: ADD_CONN_CHOICE,
|
|
125
|
-
},
|
|
126
|
-
new inquirer.Separator(),
|
|
127
|
-
...fuzzy
|
|
128
|
-
.filter(input, repos, {
|
|
129
|
-
extract: (repo) => extractRepoSlugFromUri(repo.remoteUri) || "",
|
|
130
|
-
})
|
|
131
|
-
.map((result) => {
|
|
132
|
-
return {
|
|
133
|
-
name: extractRepoSlugFromUri(result.original.remoteUri) || "",
|
|
134
|
-
value: result.original.remoteUri,
|
|
135
|
-
};
|
|
136
|
-
}),
|
|
137
|
-
];
|
|
138
|
-
};
|
|
139
120
|
const remoteUri = await (0, prompt_1.promptOnce)({
|
|
140
121
|
type: "autocomplete",
|
|
141
122
|
name: "remoteUri",
|
|
142
123
|
message: "Which of the following repositories would you like to deploy?",
|
|
143
|
-
source:
|
|
124
|
+
source: (_, input = "") => {
|
|
125
|
+
return new Promise((resolve) => resolve([
|
|
126
|
+
new inquirer.Separator(),
|
|
127
|
+
{
|
|
128
|
+
name: "Missing a repo? Select this option to configure your GitHub connection settings",
|
|
129
|
+
value: ADD_CONN_CHOICE,
|
|
130
|
+
},
|
|
131
|
+
new inquirer.Separator(),
|
|
132
|
+
...fuzzy
|
|
133
|
+
.filter(input, repos, {
|
|
134
|
+
extract: (repo) => extractRepoSlugFromUri(repo.remoteUri) || "",
|
|
135
|
+
})
|
|
136
|
+
.map((result) => {
|
|
137
|
+
return {
|
|
138
|
+
name: extractRepoSlugFromUri(result.original.remoteUri) || "",
|
|
139
|
+
value: result.original.remoteUri,
|
|
140
|
+
};
|
|
141
|
+
}),
|
|
142
|
+
]));
|
|
143
|
+
},
|
|
144
144
|
});
|
|
145
145
|
return { remoteUri, connection: remoteUriToConnection[remoteUri] };
|
|
146
146
|
}
|
|
147
|
-
async function
|
|
147
|
+
async function ensureSecretManagerAdminGrant(projectId) {
|
|
148
148
|
const projectNumber = await (0, getProjectNumber_1.getProjectNumber)({ projectId });
|
|
149
149
|
const cbsaEmail = gcb.serviceAgentEmail(projectNumber);
|
|
150
150
|
const alreadyGranted = await rm.serviceAccountHasRoles(projectId, cbsaEmail, ["roles/secretmanager.admin"], true);
|
|
151
151
|
if (alreadyGranted) {
|
|
152
|
-
return
|
|
152
|
+
return;
|
|
153
153
|
}
|
|
154
154
|
utils.logBullet("To create a new GitHub connection, Secret Manager Admin role (roles/secretmanager.admin) is required on the Cloud Build Service Agent.");
|
|
155
155
|
const grant = await (0, prompt_1.promptOnce)({
|
|
@@ -162,36 +162,10 @@ async function promptSecretManagerAdminGrant(projectId) {
|
|
|
162
162
|
`\tgcloud projects add-iam-policy-binding ${projectId} \\\n` +
|
|
163
163
|
`\t --member="serviceAccount:${cbsaEmail} \\\n` +
|
|
164
164
|
`\t --role="roles/secretmanager.admin\n`);
|
|
165
|
-
|
|
165
|
+
throw new error_1.FirebaseError("Insufficient IAM permissions to create a new connection to GitHub");
|
|
166
166
|
}
|
|
167
167
|
await rm.addServiceAccountToRoles(projectId, cbsaEmail, ["roles/secretmanager.admin"], true);
|
|
168
168
|
utils.logSuccess("Successfully granted the required role to the Cloud Build Service Agent!");
|
|
169
|
-
return true;
|
|
170
|
-
}
|
|
171
|
-
async function promptConnectionAuth(conn) {
|
|
172
|
-
utils.logBullet("You must authorize the Cloud Build GitHub app.");
|
|
173
|
-
utils.logBullet("Sign in to GitHub and authorize Cloud Build GitHub app:");
|
|
174
|
-
const { url, cleanup } = await utils.openInBrowserPopup(conn.installationState.actionUri, "Authorize the GitHub app");
|
|
175
|
-
utils.logBullet(`\t${url}`);
|
|
176
|
-
await (0, prompt_1.promptOnce)({
|
|
177
|
-
type: "input",
|
|
178
|
-
message: "Press Enter once you have authorized the app",
|
|
179
|
-
});
|
|
180
|
-
cleanup();
|
|
181
|
-
const { projectId, location, id } = parseConnectionName(conn.name);
|
|
182
|
-
return await gcb.getConnection(projectId, location, id);
|
|
183
|
-
}
|
|
184
|
-
async function promptAppInstall(conn) {
|
|
185
|
-
utils.logBullet("Install the Cloud Build GitHub app to enable access to GitHub repositories");
|
|
186
|
-
const targetUri = conn.installationState.actionUri.replace("install_v2", "direct_install_v2");
|
|
187
|
-
utils.logBullet(targetUri);
|
|
188
|
-
await utils.openInBrowser(targetUri);
|
|
189
|
-
await (0, prompt_1.promptOnce)({
|
|
190
|
-
type: "input",
|
|
191
|
-
message: "Press Enter once you have installed or configured the Cloud Build GitHub app to access your GitHub repo.",
|
|
192
|
-
});
|
|
193
|
-
const { projectId, location, id } = parseConnectionName(conn.name);
|
|
194
|
-
return await gcb.getConnection(projectId, location, id);
|
|
195
169
|
}
|
|
196
170
|
async function createConnection(projectId, location, connectionId, githubConfig) {
|
|
197
171
|
const op = await gcb.createConnection(projectId, location, connectionId, githubConfig);
|