firebase-tools 14.13.0 → 14.14.0
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/dataconnect/errors.js +7 -1
- package/lib/dataconnect/schemaMigration.js +152 -128
- package/lib/deploy/dataconnect/release.js +33 -27
- package/lib/deploy/functions/prepare.js +2 -0
- package/lib/emulator/controller.js +5 -2
- package/lib/emulator/functionsEmulator.js +2 -0
- package/lib/functions/env.js +19 -15
- package/lib/gcp/cloudsql/connect.js +2 -1
- package/lib/gcp/cloudsql/permissionsSetup.js +10 -1
- package/lib/init/features/dataconnect/index.js +1 -1
- package/lib/init/features/dataconnect/sdk.js +4 -4
- package/package.json +1 -1
- package/schema/firebase-config.json +3 -0
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getInvalidConnectors = exports.getIncompatibleSchemaError = void 0;
|
|
3
|
+
exports.getGQLErrors = exports.getInvalidConnectors = exports.getIncompatibleSchemaError = void 0;
|
|
4
|
+
const graphqlError_1 = require("./graphqlError");
|
|
4
5
|
const INCOMPATIBLE_SCHEMA_ERROR_TYPESTRING = "IncompatibleSqlSchemaError";
|
|
5
6
|
const PRECONDITION_ERROR_TYPESTRING = "type.googleapis.com/google.rpc.PreconditionFailure";
|
|
6
7
|
const INCOMPATIBLE_CONNECTOR_TYPE = "INCOMPATIBLE_CONNECTOR";
|
|
@@ -31,6 +32,11 @@ function getInvalidConnectors(err) {
|
|
|
31
32
|
return invalidConns;
|
|
32
33
|
}
|
|
33
34
|
exports.getInvalidConnectors = getInvalidConnectors;
|
|
35
|
+
function getGQLErrors(err) {
|
|
36
|
+
const gqlErrs = errorDetails(err, "GraphqlError");
|
|
37
|
+
return gqlErrs.map(graphqlError_1.prettify).join("\n");
|
|
38
|
+
}
|
|
39
|
+
exports.getGQLErrors = getGQLErrors;
|
|
34
40
|
function errorDetails(err, ofType) {
|
|
35
41
|
var _a, _b;
|
|
36
42
|
const original = ((_b = (_a = err.context) === null || _a === void 0 ? void 0 : _a.body) === null || _b === void 0 ? void 0 : _b.error) || (err === null || err === void 0 ? void 0 : err.original);
|
|
@@ -17,6 +17,7 @@ const cloudsqladmin_1 = require("../gcp/cloudsql/cloudsqladmin");
|
|
|
17
17
|
const cloudSqlAdminClient = require("../gcp/cloudsql/cloudsqladmin");
|
|
18
18
|
const errors = require("./errors");
|
|
19
19
|
const provisionCloudSql_1 = require("./provisionCloudSql");
|
|
20
|
+
const requireAuth_1 = require("../requireAuth");
|
|
20
21
|
async function setupSchemaIfNecessary(instanceId, databaseId, options) {
|
|
21
22
|
try {
|
|
22
23
|
await (0, connect_1.setupIAMUsers)(instanceId, options);
|
|
@@ -24,87 +25,89 @@ async function setupSchemaIfNecessary(instanceId, databaseId, options) {
|
|
|
24
25
|
switch (schemaInfo.setupStatus) {
|
|
25
26
|
case permissionsSetup_1.SchemaSetupStatus.BrownField:
|
|
26
27
|
case permissionsSetup_1.SchemaSetupStatus.GreenField:
|
|
28
|
+
logger_1.logger.debug(`Cloud SQL Database ${instanceId}:${databaseId} is already set up in ${schemaInfo.setupStatus}`);
|
|
27
29
|
return schemaInfo.setupStatus;
|
|
28
30
|
case permissionsSetup_1.SchemaSetupStatus.NotSetup:
|
|
29
31
|
case permissionsSetup_1.SchemaSetupStatus.NotFound:
|
|
32
|
+
(0, utils_1.logLabeledBullet)("dataconnect", "Setting up Cloud SQL Database SQL permissions...");
|
|
30
33
|
return await (0, permissionsSetup_1.setupSQLPermissions)(instanceId, databaseId, schemaInfo, options, true);
|
|
31
34
|
default:
|
|
32
35
|
throw new error_1.FirebaseError(`Unexpected schema setup status: ${schemaInfo.setupStatus}`);
|
|
33
36
|
}
|
|
34
37
|
}
|
|
35
38
|
catch (err) {
|
|
36
|
-
throw new error_1.FirebaseError(`Cannot setup SQL
|
|
39
|
+
throw new error_1.FirebaseError(`Cannot setup Postgres SQL permissions of Cloud SQL database ${instanceId}:${databaseId}\n${err}`);
|
|
37
40
|
}
|
|
38
41
|
}
|
|
39
42
|
async function diffSchema(options, schema, schemaValidation) {
|
|
40
|
-
|
|
43
|
+
let validationMode = schemaValidation !== null && schemaValidation !== void 0 ? schemaValidation : "STRICT";
|
|
44
|
+
setSchemaValidationMode(schema, validationMode);
|
|
45
|
+
displayStartSchemaDiff(validationMode);
|
|
41
46
|
const { serviceName, instanceName, databaseId, instanceId } = getIdentifiers(schema);
|
|
42
47
|
await ensureServiceIsConnectedToCloudSql(serviceName, instanceName, databaseId, false);
|
|
43
|
-
let
|
|
44
|
-
setSchemaValidationMode(schema, validationMode);
|
|
45
|
-
let diffs = [];
|
|
48
|
+
let incompatible = undefined;
|
|
46
49
|
try {
|
|
47
50
|
await (0, client_1.upsertSchema)(schema, true);
|
|
48
|
-
|
|
49
|
-
(0, utils_1.logLabeledSuccess)("dataconnect", `database schema of ${instanceId}:${databaseId} is up to date.`);
|
|
50
|
-
}
|
|
51
|
-
else {
|
|
52
|
-
(0, utils_1.logLabeledSuccess)("dataconnect", `database schema of ${instanceId}:${databaseId} is compatible.`);
|
|
53
|
-
}
|
|
51
|
+
displayNoSchemaDiff(instanceId, databaseId, validationMode);
|
|
54
52
|
}
|
|
55
53
|
catch (err) {
|
|
56
54
|
if ((err === null || err === void 0 ? void 0 : err.status) !== 400) {
|
|
57
55
|
throw err;
|
|
58
56
|
}
|
|
57
|
+
incompatible = errors.getIncompatibleSchemaError(err);
|
|
59
58
|
const invalidConnectors = errors.getInvalidConnectors(err);
|
|
60
|
-
const incompatible = errors.getIncompatibleSchemaError(err);
|
|
61
59
|
if (!incompatible && !invalidConnectors.length) {
|
|
60
|
+
const gqlErrs = errors.getGQLErrors(err);
|
|
61
|
+
if (gqlErrs) {
|
|
62
|
+
throw new error_1.FirebaseError(`There are errors in your schema files:\n${gqlErrs}`);
|
|
63
|
+
}
|
|
62
64
|
throw err;
|
|
63
65
|
}
|
|
64
66
|
if (invalidConnectors.length) {
|
|
65
67
|
displayInvalidConnectors(invalidConnectors);
|
|
66
68
|
}
|
|
67
|
-
if (incompatible) {
|
|
68
|
-
displaySchemaChanges(incompatible, validationMode, instanceName, databaseId);
|
|
69
|
-
diffs = incompatible.diffs;
|
|
70
|
-
}
|
|
71
69
|
}
|
|
72
|
-
if (!
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
displaySchemaChanges(incompatible, validationMode, instanceName, databaseId);
|
|
92
|
-
}
|
|
93
|
-
diffs = incompatible.diffs;
|
|
94
|
-
}
|
|
95
|
-
else {
|
|
96
|
-
(0, utils_1.logLabeledSuccess)("dataconnect", `no additional optional changes`);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
70
|
+
if (!incompatible) {
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
if (schemaValidation) {
|
|
74
|
+
displaySchemaChanges(incompatible, validationMode);
|
|
75
|
+
return incompatible.diffs;
|
|
76
|
+
}
|
|
77
|
+
const strictIncompatible = incompatible;
|
|
78
|
+
let compatibleIncompatible = undefined;
|
|
79
|
+
validationMode = "COMPATIBLE";
|
|
80
|
+
setSchemaValidationMode(schema, validationMode);
|
|
81
|
+
try {
|
|
82
|
+
displayStartSchemaDiff(validationMode);
|
|
83
|
+
await (0, client_1.upsertSchema)(schema, true);
|
|
84
|
+
displayNoSchemaDiff(instanceId, databaseId, validationMode);
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
if ((err === null || err === void 0 ? void 0 : err.status) !== 400) {
|
|
88
|
+
throw err;
|
|
99
89
|
}
|
|
90
|
+
compatibleIncompatible = errors.getIncompatibleSchemaError(err);
|
|
100
91
|
}
|
|
101
|
-
|
|
92
|
+
if (!compatibleIncompatible) {
|
|
93
|
+
displaySchemaChanges(strictIncompatible, "STRICT");
|
|
94
|
+
}
|
|
95
|
+
else if (diffsEqual(strictIncompatible.diffs, compatibleIncompatible.diffs)) {
|
|
96
|
+
displaySchemaChanges(strictIncompatible, "STRICT");
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
displaySchemaChanges(compatibleIncompatible, "COMPATIBLE");
|
|
100
|
+
displaySchemaChanges(strictIncompatible, "STRICT_AFTER_COMPATIBLE");
|
|
101
|
+
}
|
|
102
|
+
return incompatible.diffs;
|
|
102
103
|
}
|
|
103
104
|
exports.diffSchema = diffSchema;
|
|
104
105
|
async function migrateSchema(args) {
|
|
105
106
|
var _a;
|
|
106
|
-
(0, utils_1.logLabeledBullet)("dataconnect", `Generating SQL schema migrations...`);
|
|
107
107
|
const { options, schema, validateOnly, schemaValidation } = args;
|
|
108
|
+
let validationMode = schemaValidation !== null && schemaValidation !== void 0 ? schemaValidation : "COMPATIBLE";
|
|
109
|
+
setSchemaValidationMode(schema, validationMode);
|
|
110
|
+
displayStartSchemaDiff(validationMode);
|
|
108
111
|
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
109
112
|
const { serviceName, instanceId, instanceName, databaseId } = getIdentifiers(schema);
|
|
110
113
|
await ensureServiceIsConnectedToCloudSql(serviceName, instanceName, databaseId, true);
|
|
@@ -124,12 +127,10 @@ async function migrateSchema(args) {
|
|
|
124
127
|
return [];
|
|
125
128
|
}
|
|
126
129
|
await setupSchemaIfNecessary(instanceId, databaseId, options);
|
|
127
|
-
let validationMode = schemaValidation !== null && schemaValidation !== void 0 ? schemaValidation : "COMPATIBLE";
|
|
128
|
-
setSchemaValidationMode(schema, validationMode);
|
|
129
130
|
let diffs = [];
|
|
130
131
|
try {
|
|
131
132
|
await (0, client_1.upsertSchema)(schema, validateOnly);
|
|
132
|
-
(
|
|
133
|
+
displayNoSchemaDiff(instanceId, databaseId, validationMode);
|
|
133
134
|
}
|
|
134
135
|
catch (err) {
|
|
135
136
|
if ((err === null || err === void 0 ? void 0 : err.status) !== 400) {
|
|
@@ -138,9 +139,13 @@ async function migrateSchema(args) {
|
|
|
138
139
|
const incompatible = errors.getIncompatibleSchemaError(err);
|
|
139
140
|
const invalidConnectors = errors.getInvalidConnectors(err);
|
|
140
141
|
if (!incompatible && !invalidConnectors.length) {
|
|
142
|
+
const gqlErrs = errors.getGQLErrors(err);
|
|
143
|
+
if (gqlErrs) {
|
|
144
|
+
throw new error_1.FirebaseError(`There are errors in your schema files:\n${gqlErrs}`);
|
|
145
|
+
}
|
|
141
146
|
throw err;
|
|
142
147
|
}
|
|
143
|
-
const migrationMode = await promptForSchemaMigration(options,
|
|
148
|
+
const migrationMode = await promptForSchemaMigration(options, instanceId, databaseId, incompatible, validateOnly, validationMode);
|
|
144
149
|
const shouldDeleteInvalidConnectors = await promptForInvalidConnectorError(options, serviceName, invalidConnectors, validateOnly);
|
|
145
150
|
if (incompatible) {
|
|
146
151
|
diffs = await handleIncompatibleSchemaError({
|
|
@@ -173,7 +178,7 @@ async function migrateSchema(args) {
|
|
|
173
178
|
if (!incompatible && !invalidConnectors.length) {
|
|
174
179
|
throw err;
|
|
175
180
|
}
|
|
176
|
-
const migrationMode = await promptForSchemaMigration(options,
|
|
181
|
+
const migrationMode = await promptForSchemaMigration(options, instanceId, databaseId, incompatible, validateOnly, "STRICT_AFTER_COMPATIBLE");
|
|
177
182
|
if (incompatible) {
|
|
178
183
|
const maybeDiffs = await handleIncompatibleSchemaError({
|
|
179
184
|
options,
|
|
@@ -193,16 +198,12 @@ async function grantRoleToUserInSchema(options, schema) {
|
|
|
193
198
|
const role = options.role;
|
|
194
199
|
const email = options.email;
|
|
195
200
|
const { serviceName, instanceId, instanceName, databaseId } = getIdentifiers(schema);
|
|
196
|
-
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
197
|
-
const { user, mode } = (0, connect_1.toDatabaseUser)(email);
|
|
198
|
-
const fdcSqlRole = permissionsSetup_1.fdcSqlRoleMap[role](databaseId);
|
|
199
201
|
await ensureServiceIsConnectedToCloudSql(serviceName, instanceName, databaseId, false);
|
|
200
202
|
const schemaSetupStatus = await setupSchemaIfNecessary(instanceId, databaseId, options);
|
|
201
203
|
if (schemaSetupStatus !== permissionsSetup_1.SchemaSetupStatus.GreenField && role === "owner") {
|
|
202
204
|
throw new error_1.FirebaseError(`Owner rule isn't available in ${schemaSetupStatus} databases. If you would like Data Connect to manage and own your database schema, run 'firebase dataconnect:sql:setup'`);
|
|
203
205
|
}
|
|
204
|
-
await
|
|
205
|
-
await (0, connect_1.executeSqlCmdsAsSuperUser)(options, instanceId, databaseId, [`GRANT "${fdcSqlRole}" TO "${user}"`], false);
|
|
206
|
+
await (0, permissionsSetup_1.grantRoleTo)(options, instanceId, databaseId, role, email);
|
|
206
207
|
}
|
|
207
208
|
exports.grantRoleToUserInSchema = grantRoleToUserInSchema;
|
|
208
209
|
function diffsEqual(x, y) {
|
|
@@ -253,11 +254,7 @@ function suggestedCommand(serviceName, invalidConnectorNames) {
|
|
|
253
254
|
}
|
|
254
255
|
async function handleIncompatibleSchemaError(args) {
|
|
255
256
|
const { incompatibleSchemaError, options, instanceId, databaseId, choice } = args;
|
|
256
|
-
|
|
257
|
-
throw new error_1.FirebaseError("This schema migration includes potentially destructive changes. If you'd like to execute it anyway, rerun this command with --force");
|
|
258
|
-
}
|
|
259
|
-
const commandsToExecute = incompatibleSchemaError.diffs
|
|
260
|
-
.filter((d) => {
|
|
257
|
+
const commandsToExecute = incompatibleSchemaError.diffs.filter((d) => {
|
|
261
258
|
switch (choice) {
|
|
262
259
|
case "all":
|
|
263
260
|
return true;
|
|
@@ -266,16 +263,15 @@ async function handleIncompatibleSchemaError(args) {
|
|
|
266
263
|
case "none":
|
|
267
264
|
return false;
|
|
268
265
|
}
|
|
269
|
-
})
|
|
270
|
-
.map((d) => d.sql);
|
|
266
|
+
});
|
|
271
267
|
if (commandsToExecute.length) {
|
|
272
|
-
const commandsToExecuteBySuperUser = commandsToExecute.filter(
|
|
273
|
-
const commandsToExecuteByOwner = commandsToExecute.filter((sql) => !
|
|
268
|
+
const commandsToExecuteBySuperUser = commandsToExecute.filter(requireSuperUser);
|
|
269
|
+
const commandsToExecuteByOwner = commandsToExecute.filter((sql) => !requireSuperUser(sql));
|
|
274
270
|
const userIsCSQLAdmin = await (0, cloudsqladmin_1.iamUserIsCSQLAdmin)(options);
|
|
275
271
|
if (!userIsCSQLAdmin && commandsToExecuteBySuperUser.length) {
|
|
276
272
|
throw new error_1.FirebaseError(`Some SQL commands required for this migration require Admin permissions.\n
|
|
277
273
|
Please ask a user with 'roles/cloudsql.admin' to apply the following commands.\n
|
|
278
|
-
${commandsToExecuteBySuperUser
|
|
274
|
+
${diffsToString(commandsToExecuteBySuperUser)}`);
|
|
279
275
|
}
|
|
280
276
|
const schemaInfo = await (0, permissionsSetup_1.getSchemaMetadata)(instanceId, databaseId, permissions_1.DEFAULT_SCHEMA, options);
|
|
281
277
|
if (schemaInfo.setupStatus !== permissionsSetup_1.SchemaSetupStatus.GreenField) {
|
|
@@ -284,56 +280,67 @@ async function handleIncompatibleSchemaError(args) {
|
|
|
284
280
|
`If you would like Data Connect to manage your database schema, run 'firebase dataconnect:sql:setup'`);
|
|
285
281
|
}
|
|
286
282
|
if (!(await (0, permissionsSetup_1.checkSQLRoleIsGranted)(options, instanceId, databaseId, (0, permissions_1.firebaseowner)(databaseId), (await (0, connect_1.getIAMUser)(options)).user))) {
|
|
287
|
-
|
|
283
|
+
if (!userIsCSQLAdmin) {
|
|
284
|
+
throw new error_1.FirebaseError(`Command aborted. Only users granted firebaseowner SQL role can run migrations.`);
|
|
285
|
+
}
|
|
286
|
+
const account = (await (0, requireAuth_1.requireAuth)(options));
|
|
287
|
+
(0, utils_1.logLabeledBullet)("dataconnect", `Granting firebaseowner role to myself ${account}...`);
|
|
288
|
+
await (0, permissionsSetup_1.grantRoleTo)(options, instanceId, databaseId, "owner", account);
|
|
288
289
|
}
|
|
289
290
|
if (commandsToExecuteBySuperUser.length) {
|
|
290
|
-
|
|
291
|
-
await (0, connect_1.executeSqlCmdsAsSuperUser)(options, instanceId, databaseId, commandsToExecuteBySuperUser, false);
|
|
291
|
+
(0, utils_1.logLabeledBullet)("dataconnect", `Executing admin SQL commands as superuser...`);
|
|
292
|
+
await (0, connect_1.executeSqlCmdsAsSuperUser)(options, instanceId, databaseId, commandsToExecuteBySuperUser.map((d) => d.sql), false);
|
|
292
293
|
}
|
|
293
294
|
if (commandsToExecuteByOwner.length) {
|
|
294
|
-
await (0, connect_1.executeSqlCmdsAsIamUser)(options, instanceId, databaseId, [`SET ROLE "${(0, permissions_1.firebaseowner)(databaseId)}"`, ...commandsToExecuteByOwner], false);
|
|
295
|
+
await (0, connect_1.executeSqlCmdsAsIamUser)(options, instanceId, databaseId, [`SET ROLE "${(0, permissions_1.firebaseowner)(databaseId)}"`, ...commandsToExecuteByOwner.map((d) => d.sql)], false);
|
|
295
296
|
return incompatibleSchemaError.diffs;
|
|
296
297
|
}
|
|
297
298
|
}
|
|
298
299
|
return [];
|
|
299
300
|
}
|
|
300
|
-
async function promptForSchemaMigration(options,
|
|
301
|
+
async function promptForSchemaMigration(options, instanceId, databaseId, err, validateOnly, validationMode) {
|
|
301
302
|
if (!err) {
|
|
302
303
|
return "none";
|
|
303
304
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
}
|
|
307
|
-
displaySchemaChanges(err, validationMode, instanceName, databaseId);
|
|
305
|
+
const defaultChoice = validationMode === "STRICT_AFTER_COMPATIBLE" ? "none" : "all";
|
|
306
|
+
displaySchemaChanges(err, validationMode);
|
|
308
307
|
if (!options.nonInteractive) {
|
|
309
308
|
if (validateOnly && options.force) {
|
|
310
|
-
return
|
|
309
|
+
return defaultChoice;
|
|
310
|
+
}
|
|
311
|
+
let choices = [
|
|
312
|
+
{ name: "Execute all", value: "all" },
|
|
313
|
+
];
|
|
314
|
+
if (err.destructive) {
|
|
315
|
+
choices = [{ name: `Execute all ${clc.red("(including destructive)")}`, value: "all" }];
|
|
316
|
+
if (err.diffs.some((d) => !d.destructive)) {
|
|
317
|
+
choices.push({ name: "Execute safe only", value: "safe" });
|
|
318
|
+
}
|
|
311
319
|
}
|
|
312
|
-
const message = validationMode === "STRICT_AFTER_COMPATIBLE"
|
|
313
|
-
? `Would you like to execute these optional changes against ${databaseId} in your CloudSQL instance ${instanceName}?`
|
|
314
|
-
: `Would you like to execute these changes against ${databaseId} in your CloudSQL instance ${instanceName}?`;
|
|
315
|
-
let executeChangePrompt = "Execute changes";
|
|
316
320
|
if (validationMode === "STRICT_AFTER_COMPATIBLE") {
|
|
317
|
-
|
|
321
|
+
choices.push({ name: "Skip them", value: "none" });
|
|
318
322
|
}
|
|
319
|
-
|
|
320
|
-
|
|
323
|
+
else {
|
|
324
|
+
choices.push({ name: "Abort", value: "abort" });
|
|
321
325
|
}
|
|
322
|
-
const
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
326
|
+
const ans = await (0, prompt_1.select)({
|
|
327
|
+
message: `Do you want to execute these SQL against ${instanceId}:${databaseId}?`,
|
|
328
|
+
choices: choices,
|
|
329
|
+
default: defaultChoice,
|
|
330
|
+
});
|
|
331
|
+
if (ans === "abort") {
|
|
332
|
+
throw new error_1.FirebaseError("Command aborted.");
|
|
333
|
+
}
|
|
334
|
+
return ans;
|
|
328
335
|
}
|
|
329
336
|
if (!validateOnly) {
|
|
330
337
|
throw new error_1.FirebaseError("Command aborted. Your database schema is incompatible with your Data Connect schema. Run `firebase dataconnect:sql:migrate` to migrate your database schema");
|
|
331
338
|
}
|
|
332
339
|
else if (options.force) {
|
|
333
|
-
return
|
|
340
|
+
return defaultChoice;
|
|
334
341
|
}
|
|
335
342
|
else if (!err.destructive) {
|
|
336
|
-
return
|
|
343
|
+
return defaultChoice;
|
|
337
344
|
}
|
|
338
345
|
else {
|
|
339
346
|
throw new error_1.FirebaseError("Command aborted. This schema migration includes potentially destructive changes. If you'd like to execute it anyway, rerun this command with --force");
|
|
@@ -362,7 +369,7 @@ async function deleteInvalidConnectors(invalidConnectors) {
|
|
|
362
369
|
}
|
|
363
370
|
function displayInvalidConnectors(invalidConnectors) {
|
|
364
371
|
const connectorIds = invalidConnectors.map((i) => i.split("/").pop()).join(", ");
|
|
365
|
-
(0, utils_1.logLabeledWarning)("dataconnect", `The schema you are deploying is incompatible with the following existing connectors: ${connectorIds}.`);
|
|
372
|
+
(0, utils_1.logLabeledWarning)("dataconnect", `The schema you are deploying is incompatible with the following existing connectors: ${clc.bold(connectorIds)}.`);
|
|
366
373
|
(0, utils_1.logLabeledWarning)("dataconnect", `This is a ${clc.red("breaking")} change and may break existing apps.`);
|
|
367
374
|
}
|
|
368
375
|
async function ensureServiceIsConnectedToCloudSql(serviceName, instanceName, databaseId, linkIfNotConnected) {
|
|
@@ -424,50 +431,61 @@ async function ensureServiceIsConnectedToCloudSql(serviceName, instanceName, dat
|
|
|
424
431
|
}
|
|
425
432
|
}
|
|
426
433
|
exports.ensureServiceIsConnectedToCloudSql = ensureServiceIsConnectedToCloudSql;
|
|
427
|
-
function
|
|
434
|
+
function displayStartSchemaDiff(validationMode) {
|
|
435
|
+
switch (validationMode) {
|
|
436
|
+
case "COMPATIBLE":
|
|
437
|
+
(0, utils_1.logLabeledBullet)("dataconnect", `Generating SQL schema migrations to be compatible...`);
|
|
438
|
+
break;
|
|
439
|
+
case "STRICT":
|
|
440
|
+
(0, utils_1.logLabeledBullet)("dataconnect", `Generating SQL schema migrations to match exactly...`);
|
|
441
|
+
break;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
function displayNoSchemaDiff(instanceId, databaseId, validationMode) {
|
|
445
|
+
switch (validationMode) {
|
|
446
|
+
case "COMPATIBLE":
|
|
447
|
+
(0, utils_1.logLabeledSuccess)("dataconnect", `Database schema of ${instanceId}:${databaseId} is compatible with Data Connect Schema.`);
|
|
448
|
+
break;
|
|
449
|
+
case "STRICT":
|
|
450
|
+
(0, utils_1.logLabeledSuccess)("dataconnect", `Database schema of ${instanceId}:${databaseId} matches Data Connect Schema exactly.`);
|
|
451
|
+
break;
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
function displaySchemaChanges(error, validationMode) {
|
|
428
455
|
switch (error.violationType) {
|
|
429
456
|
case "INCOMPATIBLE_SCHEMA":
|
|
430
457
|
{
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
458
|
+
switch (validationMode) {
|
|
459
|
+
case "COMPATIBLE":
|
|
460
|
+
(0, utils_1.logLabeledWarning)("dataconnect", `PostgreSQL schema is incompatible with the Data Connect Schema.
|
|
461
|
+
Those SQL statements will migrate it to be compatible:
|
|
462
|
+
|
|
463
|
+
${diffsToString(error.diffs)}
|
|
464
|
+
`);
|
|
465
|
+
break;
|
|
466
|
+
case "STRICT_AFTER_COMPATIBLE":
|
|
467
|
+
(0, utils_1.logLabeledBullet)("dataconnect", `PostgreSQL schema contains unused SQL objects not part of the Data Connect Schema.
|
|
468
|
+
Those SQL statements will migrate it to match exactly:
|
|
469
|
+
|
|
470
|
+
${diffsToString(error.diffs)}
|
|
471
|
+
`);
|
|
472
|
+
break;
|
|
473
|
+
case "STRICT":
|
|
474
|
+
(0, utils_1.logLabeledWarning)("dataconnect", `PostgreSQL schema does not match the Data Connect Schema.
|
|
475
|
+
Those SQL statements will migrate it to match exactly:
|
|
476
|
+
|
|
477
|
+
${diffsToString(error.diffs)}
|
|
478
|
+
`);
|
|
479
|
+
break;
|
|
441
480
|
}
|
|
442
|
-
else if (validationMode === "STRICT_AFTER_COMPATIBLE") {
|
|
443
|
-
message =
|
|
444
|
-
"Your new application schema is compatible with the schema of your PostgreSQL database " +
|
|
445
|
-
databaseId +
|
|
446
|
-
" in your CloudSQL instance " +
|
|
447
|
-
instanceName +
|
|
448
|
-
", but contains unused tables or columns. " +
|
|
449
|
-
"The following optional SQL statements will migrate your database schema to match your new Data Connect schema.\n" +
|
|
450
|
-
error.diffs.map(toString).join("\n");
|
|
451
|
-
}
|
|
452
|
-
else {
|
|
453
|
-
message =
|
|
454
|
-
"Your PostgreSQL database " +
|
|
455
|
-
databaseId +
|
|
456
|
-
" in your CloudSQL instance " +
|
|
457
|
-
instanceName +
|
|
458
|
-
" must be migrated in order to match your application schema. " +
|
|
459
|
-
"The following SQL statements will migrate your database schema to match your new Data Connect schema.\n" +
|
|
460
|
-
error.diffs.map(toString).join("\n");
|
|
461
|
-
}
|
|
462
|
-
(0, utils_1.logLabeledWarning)("dataconnect", message);
|
|
463
481
|
}
|
|
464
482
|
break;
|
|
465
483
|
case "INACCESSIBLE_SCHEMA":
|
|
466
484
|
{
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
485
|
+
(0, utils_1.logLabeledWarning)("dataconnect", `Cannot access CloudSQL database to validate schema.
|
|
486
|
+
Here is the complete expected SQL schema:
|
|
487
|
+
${diffsToString(error.diffs)}
|
|
488
|
+
`);
|
|
471
489
|
(0, utils_1.logLabeledWarning)("dataconnect", "Some SQL resources may already exist.");
|
|
472
490
|
}
|
|
473
491
|
break;
|
|
@@ -475,6 +493,12 @@ function displaySchemaChanges(error, validationMode, instanceName, databaseId) {
|
|
|
475
493
|
throw new error_1.FirebaseError(`Unknown schema violation type: ${error.violationType}, IncompatibleSqlSchemaError: ${error}`);
|
|
476
494
|
}
|
|
477
495
|
}
|
|
478
|
-
function
|
|
496
|
+
function requireSuperUser(diff) {
|
|
497
|
+
return diff.sql.startsWith("CREATE EXTENSION") || diff.sql.startsWith("CREATE SCHEMA");
|
|
498
|
+
}
|
|
499
|
+
function diffsToString(diffs) {
|
|
500
|
+
return diffs.map(diffToString).join("\n\n");
|
|
501
|
+
}
|
|
502
|
+
function diffToString(diff) {
|
|
479
503
|
return `\/** ${diff.destructive ? clc.red("Destructive: ") : ""}${diff.description}*\/\n${(0, sql_formatter_1.format)(diff.sql, { language: "postgresql" })}`;
|
|
480
504
|
}
|
|
@@ -6,6 +6,7 @@ const prompts_1 = require("../../dataconnect/prompts");
|
|
|
6
6
|
const schemaMigration_1 = require("../../dataconnect/schemaMigration");
|
|
7
7
|
const projectUtils_1 = require("../../projectUtils");
|
|
8
8
|
const names_1 = require("../../dataconnect/names");
|
|
9
|
+
const logger_1 = require("../../logger");
|
|
9
10
|
async function default_1(context, options) {
|
|
10
11
|
const project = (0, projectUtils_1.needProjectId)(options);
|
|
11
12
|
const serviceInfos = context.dataconnect.serviceInfos;
|
|
@@ -24,19 +25,7 @@ async function default_1(context, options) {
|
|
|
24
25
|
validationMode: (_d = (_c = (_b = (_a = s.dataConnectYaml) === null || _a === void 0 ? void 0 : _a.schema) === null || _b === void 0 ? void 0 : _b.datasource) === null || _c === void 0 ? void 0 : _c.postgresql) === null || _d === void 0 ? void 0 : _d.schemaValidation,
|
|
25
26
|
});
|
|
26
27
|
});
|
|
27
|
-
|
|
28
|
-
for (const s of wantSchemas) {
|
|
29
|
-
await (0, schemaMigration_1.migrateSchema)({
|
|
30
|
-
options,
|
|
31
|
-
schema: s.schema,
|
|
32
|
-
validateOnly: false,
|
|
33
|
-
schemaValidation: s.validationMode,
|
|
34
|
-
});
|
|
35
|
-
utils.logLabeledSuccess("dataconnect", `Migrated schema ${s.schema.name}`);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
let wantConnectors = [];
|
|
39
|
-
wantConnectors = wantConnectors.concat(...serviceInfos.map((si) => si.connectorInfo
|
|
28
|
+
const wantConnectors = serviceInfos.flatMap((si) => si.connectorInfo
|
|
40
29
|
.filter((c) => {
|
|
41
30
|
return (!filters ||
|
|
42
31
|
filters.some((f) => {
|
|
@@ -44,22 +33,39 @@ async function default_1(context, options) {
|
|
|
44
33
|
(f.connectorId === c.connectorYaml.connectorId || f.fullService));
|
|
45
34
|
}));
|
|
46
35
|
})
|
|
47
|
-
.map((c) => c.connector))
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
? []
|
|
51
|
-
: haveConnectors.filter((h) => !wantConnectors.some((w) => w.name === h.name));
|
|
52
|
-
if (wantConnectors.length) {
|
|
53
|
-
await Promise.all(wantConnectors.map(async (c) => {
|
|
36
|
+
.map((c) => c.connector));
|
|
37
|
+
const remainingConnectors = await Promise.all(wantConnectors.map(async (c) => {
|
|
38
|
+
try {
|
|
54
39
|
await (0, client_1.upsertConnector)(c);
|
|
55
|
-
utils.logLabeledSuccess("dataconnect", `Deployed connector ${c.name}`);
|
|
56
|
-
}));
|
|
57
|
-
for (const c of connectorsToDelete) {
|
|
58
|
-
await (0, prompts_1.promptDeleteConnector)(options, c.name);
|
|
59
40
|
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
logger_1.logger.debug("Error pre-deploying connector", c.name, err);
|
|
43
|
+
return c;
|
|
44
|
+
}
|
|
45
|
+
utils.logLabeledSuccess("dataconnect", `Deployed connector ${c.name}`);
|
|
46
|
+
return undefined;
|
|
47
|
+
}));
|
|
48
|
+
for (const s of wantSchemas) {
|
|
49
|
+
await (0, schemaMigration_1.migrateSchema)({
|
|
50
|
+
options,
|
|
51
|
+
schema: s.schema,
|
|
52
|
+
validateOnly: false,
|
|
53
|
+
schemaValidation: s.validationMode,
|
|
54
|
+
});
|
|
55
|
+
utils.logLabeledSuccess("dataconnect", `Migrated schema ${s.schema.name}`);
|
|
60
56
|
}
|
|
61
|
-
|
|
62
|
-
|
|
57
|
+
await Promise.all(remainingConnectors.map(async (c) => {
|
|
58
|
+
if (c) {
|
|
59
|
+
await (0, client_1.upsertConnector)(c);
|
|
60
|
+
utils.logLabeledSuccess("dataconnect", `Deployed connector ${c.name}`);
|
|
61
|
+
}
|
|
62
|
+
}));
|
|
63
|
+
const allConnectors = await deployedConnectors(serviceInfos);
|
|
64
|
+
const connectorsToDelete = filters
|
|
65
|
+
? []
|
|
66
|
+
: allConnectors.filter((h) => !wantConnectors.some((w) => w.name === h.name));
|
|
67
|
+
for (const c of connectorsToDelete) {
|
|
68
|
+
await (0, prompts_1.promptDeleteConnector)(options, c.name);
|
|
63
69
|
}
|
|
64
70
|
let consolePath = "/dataconnect";
|
|
65
71
|
if (serviceInfos.length === 1) {
|
|
@@ -73,7 +79,7 @@ async function default_1(context, options) {
|
|
|
73
79
|
return;
|
|
74
80
|
}
|
|
75
81
|
exports.default = default_1;
|
|
76
|
-
async function
|
|
82
|
+
async function deployedConnectors(serviceInfos) {
|
|
77
83
|
let connectors = [];
|
|
78
84
|
for (const si of serviceInfos) {
|
|
79
85
|
connectors = connectors.concat(await (0, client_1.listConnectors)(si.serviceName));
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ensureAllRequiredAPIsEnabled = exports.warnIfNewGenkitFunctionIsMissingSecrets = exports.loadCodebases = exports.resolveCpuAndConcurrency = exports.inferBlockingDetails = exports.updateEndpointTargetedStatus = exports.inferDetailsFromExisting = exports.prepare = exports.EVENTARC_SOURCE_ENV = void 0;
|
|
4
4
|
const clc = require("colorette");
|
|
5
|
+
const proto = require("../../gcp/proto");
|
|
5
6
|
const backend = require("./backend");
|
|
6
7
|
const build = require("./build");
|
|
7
8
|
const ensureApiEnabled = require("../../ensureApiEnabled");
|
|
@@ -76,6 +77,7 @@ async function prepare(context, options, payload) {
|
|
|
76
77
|
projectId: projectId,
|
|
77
78
|
projectAlias: options.projectAlias,
|
|
78
79
|
};
|
|
80
|
+
proto.convertIfPresent(userEnvOpt, config, "configDir", (cd) => options.config.path(cd));
|
|
79
81
|
const userEnvs = functionsEnv.loadUserEnvs(userEnvOpt);
|
|
80
82
|
const envs = Object.assign(Object.assign({}, userEnvs), firebaseEnvs);
|
|
81
83
|
const { backend: wantBackend, envs: resolvedEnvs } = await build.resolveBackend({
|
|
@@ -5,6 +5,7 @@ const clc = require("colorette");
|
|
|
5
5
|
const fs = require("fs");
|
|
6
6
|
const path = require("path");
|
|
7
7
|
const fsConfig = require("../firestore/fsConfig");
|
|
8
|
+
const proto = require("../gcp/proto");
|
|
8
9
|
const logger_1 = require("../logger");
|
|
9
10
|
const track_1 = require("../track");
|
|
10
11
|
const utils = require("../utils");
|
|
@@ -344,7 +345,7 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
344
345
|
if (runtime && !(0, supported_1.isRuntime)(runtime)) {
|
|
345
346
|
throw new error_1.FirebaseError(`Cannot load functions from ${functionsDir} because it has invalid runtime ${runtime}`);
|
|
346
347
|
}
|
|
347
|
-
|
|
348
|
+
const backend = {
|
|
348
349
|
functionsDir,
|
|
349
350
|
runtime,
|
|
350
351
|
codebase: cfg.codebase,
|
|
@@ -353,7 +354,9 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
353
354
|
secretEnv: [],
|
|
354
355
|
predefinedTriggers: options.extDevTriggers,
|
|
355
356
|
ignore: cfg.ignore,
|
|
356
|
-
}
|
|
357
|
+
};
|
|
358
|
+
proto.convertIfPresent(backend, cfg, "configDir", (cd) => path.join(projectDir, cd));
|
|
359
|
+
emulatableBackends.push(backend);
|
|
357
360
|
}
|
|
358
361
|
}
|
|
359
362
|
if (extensionEmulator) {
|
|
@@ -329,6 +329,7 @@ class FunctionsEmulator {
|
|
|
329
329
|
projectId: this.args.projectId,
|
|
330
330
|
projectAlias: this.args.projectAlias,
|
|
331
331
|
isEmulator: true,
|
|
332
|
+
configDir: emulatableBackend.configDir,
|
|
332
333
|
};
|
|
333
334
|
const userEnvs = functionsEnv.loadUserEnvs(userEnvOpt);
|
|
334
335
|
const discoveredBuild = await runtimeDelegate.discoverBuild(runtimeConfig, environment);
|
|
@@ -879,6 +880,7 @@ class FunctionsEmulator {
|
|
|
879
880
|
getUserEnvs(backend) {
|
|
880
881
|
const projectInfo = {
|
|
881
882
|
functionsSource: backend.functionsDir,
|
|
883
|
+
configDir: backend.configDir,
|
|
882
884
|
projectId: this.args.projectId,
|
|
883
885
|
projectAlias: this.args.projectAlias,
|
|
884
886
|
isEmulator: true,
|
package/lib/functions/env.js
CHANGED
|
@@ -140,7 +140,7 @@ function parseStrict(data) {
|
|
|
140
140
|
return envs;
|
|
141
141
|
}
|
|
142
142
|
exports.parseStrict = parseStrict;
|
|
143
|
-
function findEnvfiles(
|
|
143
|
+
function findEnvfiles(configDir, projectId, projectAlias, isEmulator) {
|
|
144
144
|
const files = [".env"];
|
|
145
145
|
files.push(`.env.${projectId}`);
|
|
146
146
|
if (projectAlias) {
|
|
@@ -150,26 +150,28 @@ function findEnvfiles(functionsSource, projectId, projectAlias, isEmulator) {
|
|
|
150
150
|
files.push(FUNCTIONS_EMULATOR_DOTENV);
|
|
151
151
|
}
|
|
152
152
|
return files
|
|
153
|
-
.map((f) => path.join(
|
|
153
|
+
.map((f) => path.join(configDir, f))
|
|
154
154
|
.filter(fs.existsSync)
|
|
155
155
|
.map((p) => path.basename(p));
|
|
156
156
|
}
|
|
157
|
-
function hasUserEnvs(
|
|
158
|
-
|
|
157
|
+
function hasUserEnvs(opts) {
|
|
158
|
+
const configDir = opts.configDir || opts.functionsSource;
|
|
159
|
+
return findEnvfiles(configDir, opts.projectId, opts.projectAlias, opts.isEmulator).length > 0;
|
|
159
160
|
}
|
|
160
161
|
exports.hasUserEnvs = hasUserEnvs;
|
|
161
162
|
function writeUserEnvs(toWrite, envOpts) {
|
|
162
163
|
if (Object.keys(toWrite).length === 0) {
|
|
163
164
|
return;
|
|
164
165
|
}
|
|
165
|
-
const {
|
|
166
|
-
const
|
|
166
|
+
const { projectId, projectAlias, isEmulator } = envOpts;
|
|
167
|
+
const configDir = envOpts.configDir || envOpts.functionsSource;
|
|
168
|
+
const allEnvFiles = findEnvfiles(configDir, projectId, projectAlias, isEmulator);
|
|
167
169
|
const targetEnvFile = envOpts.isEmulator
|
|
168
170
|
? FUNCTIONS_EMULATOR_DOTENV
|
|
169
171
|
: `.env.${envOpts.projectId}`;
|
|
170
172
|
const targetEnvFileExists = allEnvFiles.includes(targetEnvFile);
|
|
171
173
|
if (!targetEnvFileExists) {
|
|
172
|
-
fs.writeFileSync(path.join(
|
|
174
|
+
fs.writeFileSync(path.join(configDir, targetEnvFile), "", { flag: "wx" });
|
|
173
175
|
(0, utils_1.logBullet)(clc.yellow(clc.bold("functions: ")) +
|
|
174
176
|
`Created new local file ${targetEnvFile} to store param values. We suggest explicitly adding or excluding this file from version control.`);
|
|
175
177
|
}
|
|
@@ -186,7 +188,7 @@ function writeUserEnvs(toWrite, envOpts) {
|
|
|
186
188
|
for (const k of Object.keys(toWrite)) {
|
|
187
189
|
lines += formatUserEnvForWrite(k, toWrite[k]);
|
|
188
190
|
}
|
|
189
|
-
fs.appendFileSync(path.join(
|
|
191
|
+
fs.appendFileSync(path.join(configDir, targetEnvFile), lines);
|
|
190
192
|
}
|
|
191
193
|
exports.writeUserEnvs = writeUserEnvs;
|
|
192
194
|
function checkForDuplicateKeys(isEmulator, keys, fullEnv, envsWithoutLocal) {
|
|
@@ -210,22 +212,24 @@ function formatUserEnvForWrite(key, value) {
|
|
|
210
212
|
}
|
|
211
213
|
return `${key}=${escapedValue}\n`;
|
|
212
214
|
}
|
|
213
|
-
function loadUserEnvs(
|
|
215
|
+
function loadUserEnvs(opts) {
|
|
214
216
|
var _a;
|
|
215
|
-
const
|
|
217
|
+
const configDir = opts.configDir || opts.functionsSource;
|
|
218
|
+
const envFiles = findEnvfiles(configDir, opts.projectId, opts.projectAlias, opts.isEmulator);
|
|
216
219
|
if (envFiles.length === 0) {
|
|
217
220
|
return {};
|
|
218
221
|
}
|
|
219
|
-
if (projectAlias) {
|
|
220
|
-
if (envFiles.includes(`.env.${projectId}`) &&
|
|
221
|
-
|
|
222
|
-
|
|
222
|
+
if (opts.projectAlias) {
|
|
223
|
+
if (envFiles.includes(`.env.${opts.projectId}`) &&
|
|
224
|
+
envFiles.includes(`.env.${opts.projectAlias}`)) {
|
|
225
|
+
throw new error_1.FirebaseError(`Can't have both dotenv files with projectId (env.${opts.projectId}) ` +
|
|
226
|
+
`and projectAlias (.env.${opts.projectAlias}) as extensions.`);
|
|
223
227
|
}
|
|
224
228
|
}
|
|
225
229
|
let envs = {};
|
|
226
230
|
for (const f of envFiles) {
|
|
227
231
|
try {
|
|
228
|
-
const data = fs.readFileSync(path.join(
|
|
232
|
+
const data = fs.readFileSync(path.join(configDir, f), "utf8");
|
|
229
233
|
envs = Object.assign(Object.assign({}, envs), parseStrict(data));
|
|
230
234
|
}
|
|
231
235
|
catch (err) {
|
|
@@ -72,7 +72,7 @@ async function execute(sqlStatements, opts) {
|
|
|
72
72
|
sqlStatements.push("COMMIT;");
|
|
73
73
|
}
|
|
74
74
|
for (const s of sqlStatements) {
|
|
75
|
-
logFn(
|
|
75
|
+
logFn(`> ${s}`);
|
|
76
76
|
try {
|
|
77
77
|
results.push(await conn.query(s));
|
|
78
78
|
}
|
|
@@ -84,6 +84,7 @@ async function execute(sqlStatements, opts) {
|
|
|
84
84
|
}
|
|
85
85
|
}
|
|
86
86
|
await cleanUpFn();
|
|
87
|
+
logFn(``);
|
|
87
88
|
return results;
|
|
88
89
|
}
|
|
89
90
|
exports.execute = execute;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.brownfieldSqlSetup = exports.setupBrownfieldAsGreenfield = exports.getSchemaMetadata = exports.greenFieldSchemaSetup = exports.setupSQLPermissions = exports.checkSQLRoleIsGranted = exports.fdcSqlRoleMap = exports.SchemaSetupStatus = void 0;
|
|
3
|
+
exports.grantRoleTo = exports.brownfieldSqlSetup = exports.setupBrownfieldAsGreenfield = exports.getSchemaMetadata = exports.greenFieldSchemaSetup = exports.setupSQLPermissions = exports.checkSQLRoleIsGranted = exports.fdcSqlRoleMap = exports.SchemaSetupStatus = void 0;
|
|
4
4
|
const clc = require("colorette");
|
|
5
5
|
const permissions_1 = require("./permissions");
|
|
6
6
|
const cloudsqladmin_1 = require("./cloudsqladmin");
|
|
@@ -12,6 +12,7 @@ const connect_1 = require("./connect");
|
|
|
12
12
|
const lodash_1 = require("lodash");
|
|
13
13
|
const connect_2 = require("./connect");
|
|
14
14
|
const utils = require("../../utils");
|
|
15
|
+
const cloudSqlAdminClient = require("./cloudsqladmin");
|
|
15
16
|
var SchemaSetupStatus;
|
|
16
17
|
(function (SchemaSetupStatus) {
|
|
17
18
|
SchemaSetupStatus["NotSetup"] = "not-setup";
|
|
@@ -220,3 +221,11 @@ async function brownfieldSqlSetup(instanceId, databaseId, schemaInfo, options, s
|
|
|
220
221
|
await (0, connect_1.executeSqlCmdsAsSuperUser)(options, instanceId, databaseId, brownfieldSetupCmds, silent, true);
|
|
221
222
|
}
|
|
222
223
|
exports.brownfieldSqlSetup = brownfieldSqlSetup;
|
|
224
|
+
async function grantRoleTo(options, instanceId, databaseId, role, email) {
|
|
225
|
+
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
226
|
+
const { user, mode } = (0, connect_2.toDatabaseUser)(email);
|
|
227
|
+
await cloudSqlAdminClient.createUser(projectId, instanceId, mode, user);
|
|
228
|
+
const fdcSqlRole = exports.fdcSqlRoleMap[role](databaseId);
|
|
229
|
+
await (0, connect_1.executeSqlCmdsAsSuperUser)(options, instanceId, databaseId, [`GRANT "${fdcSqlRole}" TO "${user}"`], false);
|
|
230
|
+
}
|
|
231
|
+
exports.grantRoleTo = grantRoleTo;
|
|
@@ -135,7 +135,7 @@ async function generateSdkYaml(targetPlatform, connectorYaml, connectorDir, appD
|
|
|
135
135
|
if (targetPlatform === types_1.Platform.IOS) {
|
|
136
136
|
const swiftSdk = {
|
|
137
137
|
outputDir: path.relative(connectorDir, path.join(appDir, `dataconnect-generated/swift`)),
|
|
138
|
-
package:
|
|
138
|
+
package: "DataConnectGenerated",
|
|
139
139
|
};
|
|
140
140
|
connectorYaml.generate.swiftSdk = swiftSdk;
|
|
141
141
|
}
|
|
@@ -144,7 +144,7 @@ async function generateSdkYaml(targetPlatform, connectorYaml, connectorDir, appD
|
|
|
144
144
|
const packageJsonDir = path.relative(connectorDir, appDir);
|
|
145
145
|
const javascriptSdk = {
|
|
146
146
|
outputDir: path.relative(connectorDir, path.join(appDir, `dataconnect-generated/js/${pkg}`)),
|
|
147
|
-
package: `@
|
|
147
|
+
package: `@dataconnect/generated`,
|
|
148
148
|
packageJsonDir,
|
|
149
149
|
};
|
|
150
150
|
const packageJson = await (0, fileUtils_1.resolvePackageJson)(appDir);
|
|
@@ -161,14 +161,14 @@ async function generateSdkYaml(targetPlatform, connectorYaml, connectorDir, appD
|
|
|
161
161
|
const pkg = `${(0, lodash_1.snakeCase)(connectorYaml.connectorId)}_connector`;
|
|
162
162
|
const dartSdk = {
|
|
163
163
|
outputDir: path.relative(connectorDir, path.join(appDir, `dataconnect-generated/dart/${pkg}`)),
|
|
164
|
-
package:
|
|
164
|
+
package: "dataconnect_generated",
|
|
165
165
|
};
|
|
166
166
|
connectorYaml.generate.dartSdk = dartSdk;
|
|
167
167
|
}
|
|
168
168
|
if (targetPlatform === types_1.Platform.ANDROID) {
|
|
169
169
|
const kotlinSdk = {
|
|
170
170
|
outputDir: path.relative(connectorDir, path.join(appDir, `dataconnect-generated/kotlin`)),
|
|
171
|
-
package: `
|
|
171
|
+
package: `com.google.firebase.dataconnect.generated`,
|
|
172
172
|
};
|
|
173
173
|
for (const candidateSubdir of ["app/src/main/java", "app/src/main/kotlin"]) {
|
|
174
174
|
const candidateDir = path.join(appDir, candidateSubdir);
|
package/package.json
CHANGED