firebase-tools 13.16.0 → 13.18.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.
Files changed (57) hide show
  1. package/lib/api.js +3 -1
  2. package/lib/apphosting/index.js +2 -1
  3. package/lib/commands/dataconnect-services-list.js +4 -3
  4. package/lib/commands/dataconnect-sql-diff.js +2 -1
  5. package/lib/commands/dataconnect-sql-grant.js +37 -0
  6. package/lib/commands/dataconnect-sql-migrate.js +2 -2
  7. package/lib/commands/deploy.js +2 -0
  8. package/lib/commands/firestore-databases-restore.js +39 -1
  9. package/lib/commands/index.js +1 -0
  10. package/lib/dataconnect/client.js +1 -1
  11. package/lib/dataconnect/dataplaneClient.js +1 -1
  12. package/lib/dataconnect/ensureApis.js +7 -1
  13. package/lib/dataconnect/load.js +3 -1
  14. package/lib/dataconnect/provisionCloudSql.js +34 -21
  15. package/lib/dataconnect/schemaMigration.js +214 -75
  16. package/lib/dataconnect/types.js +1 -0
  17. package/lib/deploy/dataconnect/deploy.js +16 -13
  18. package/lib/deploy/dataconnect/prepare.js +36 -0
  19. package/lib/deploy/dataconnect/release.js +9 -2
  20. package/lib/deploy/extensions/prepare.js +22 -9
  21. package/lib/deploy/firestore/prepare.js +10 -0
  22. package/lib/deploy/firestore/release.js +3 -6
  23. package/lib/deploy/functions/checkIam.js +7 -2
  24. package/lib/deploy/functions/ensure.js +10 -2
  25. package/lib/deploy/functions/prepare.js +2 -2
  26. package/lib/deploy/functions/release/planner.js +2 -1
  27. package/lib/deploy/index.js +9 -5
  28. package/lib/emulator/apphosting/index.js +38 -0
  29. package/lib/emulator/apphosting/serve.js +26 -0
  30. package/lib/emulator/auth/handlers.js +27 -0
  31. package/lib/emulator/auth/operations.js +41 -3
  32. package/lib/emulator/auth/state.js +2 -1
  33. package/lib/emulator/constants.js +3 -0
  34. package/lib/emulator/controller.js +12 -0
  35. package/lib/emulator/downloadableEmulators.js +9 -9
  36. package/lib/emulator/portUtils.js +1 -0
  37. package/lib/emulator/registry.js +1 -0
  38. package/lib/emulator/types.js +3 -0
  39. package/lib/experiments.js +4 -0
  40. package/lib/firestore/api.js +2 -1
  41. package/lib/firestore/checkDatabaseType.js +10 -3
  42. package/lib/firestore/options.js +7 -0
  43. package/lib/frameworks/angular/index.js +15 -3
  44. package/lib/frameworks/next/utils.js +1 -1
  45. package/lib/gcp/cloudsql/connect.js +49 -37
  46. package/lib/gcp/cloudsql/permissions.js +165 -0
  47. package/lib/gcp/secretManager.js +12 -5
  48. package/lib/init/features/dataconnect/index.js +25 -12
  49. package/lib/init/features/firestore/index.js +20 -1
  50. package/lib/init/features/firestore/indexes.js +4 -4
  51. package/lib/utils.js +9 -1
  52. package/package.json +1 -1
  53. package/schema/connector-yaml.json +43 -17
  54. package/schema/firebase-config.json +12 -0
  55. package/templates/init/dataconnect/connector.yaml +0 -1
  56. package/templates/init/dataconnect/dataconnect-fdccompatiblemode.yaml +12 -0
  57. package/templates/init/dataconnect/dataconnect.yaml +1 -1
package/lib/api.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  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.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.consoleOrigin = exports.authOrigin = exports.apphostingGitHubAppInstallationURL = exports.apphostingP4SADomain = exports.apphostingOrigin = exports.appDistributionOrigin = exports.artifactRegistryDomain = exports.developerConnectP4SADomain = exports.developerConnectOrigin = exports.containerRegistryDomain = exports.cloudMonitoringOrigin = exports.cloudloggingOrigin = exports.cloudbillingOrigin = exports.clientSecret = exports.clientId = exports.authProxyOrigin = void 0;
4
- exports.setScopes = exports.getScopes = exports.vertexAIOrigin = exports.cloudSQLAdminOrigin = exports.dataConnectLocalConnString = exports.dataconnectOrigin = exports.githubClientSecret = exports.githubClientId = exports.computeOrigin = exports.secretManagerOrigin = exports.githubApiOrigin = exports.githubOrigin = exports.serviceUsageOrigin = void 0;
4
+ exports.setScopes = exports.getScopes = exports.vertexAIOrigin = exports.cloudSQLAdminOrigin = exports.dataConnectLocalConnString = exports.dataconnectP4SADomain = exports.dataconnectOrigin = exports.githubClientSecret = exports.githubClientId = exports.computeOrigin = exports.secretManagerOrigin = exports.githubApiOrigin = exports.githubOrigin = exports.serviceUsageOrigin = void 0;
5
5
  const constants_1 = require("./emulator/constants");
6
6
  const logger_1 = require("./logger");
7
7
  const scopes = require("./scopes");
@@ -128,6 +128,8 @@ const githubClientSecret = () => utils.envOverride("GITHUB_CLIENT_SECRET", "3330
128
128
  exports.githubClientSecret = githubClientSecret;
129
129
  const dataconnectOrigin = () => utils.envOverride("FIREBASE_DATACONNECT_URL", "https://firebasedataconnect.googleapis.com");
130
130
  exports.dataconnectOrigin = dataconnectOrigin;
131
+ const dataconnectP4SADomain = () => utils.envOverride("FIREBASE_DATACONNECT_P4SA_DOMAIN", "gcp-sa-firebasedataconnect.iam.gserviceaccount.com");
132
+ exports.dataconnectP4SADomain = dataconnectP4SADomain;
131
133
  const dataConnectLocalConnString = () => utils.envOverride("FIREBASE_DATACONNECT_POSTGRESQL_STRING", "");
132
134
  exports.dataConnectLocalConnString = dataConnectLocalConnString;
133
135
  const cloudSQLAdminOrigin = () => utils.envOverride("CLOUD_SQL_URL", "https://sqladmin.googleapis.com");
@@ -33,7 +33,8 @@ async function tlsReady(url) {
33
33
  }
34
34
  catch (err) {
35
35
  const maybeNodeError = err;
36
- if (/HANDSHAKE_FAILURE/.test((_a = maybeNodeError === null || maybeNodeError === void 0 ? void 0 : maybeNodeError.cause) === null || _a === void 0 ? void 0 : _a.code)) {
36
+ if (/HANDSHAKE_FAILURE/.test((_a = maybeNodeError === null || maybeNodeError === void 0 ? void 0 : maybeNodeError.cause) === null || _a === void 0 ? void 0 : _a.code) ||
37
+ "EPROTO" === (maybeNodeError === null || maybeNodeError === void 0 ? void 0 : maybeNodeError.code)) {
37
38
  return false;
38
39
  }
39
40
  return true;
@@ -36,14 +36,15 @@ exports.command = new command_1.Command("dataconnect:services:list")
36
36
  for (const service of services) {
37
37
  const schema = (_a = (await client.getSchema(service.name))) !== null && _a !== void 0 ? _a : {
38
38
  name: "",
39
- primaryDatasource: {},
39
+ datasources: [{}],
40
40
  source: { files: [] },
41
41
  };
42
42
  const connectors = await client.listConnectors(service.name);
43
43
  const serviceName = names.parseServiceName(service.name);
44
- const instanceName = (_c = (_b = schema === null || schema === void 0 ? void 0 : schema.primaryDatasource.postgresql) === null || _b === void 0 ? void 0 : _b.cloudSql.instance) !== null && _c !== void 0 ? _c : "";
44
+ const postgresDatasource = schema === null || schema === void 0 ? void 0 : schema.datasources.find((d) => d.postgresql);
45
+ const instanceName = (_c = (_b = postgresDatasource === null || postgresDatasource === void 0 ? void 0 : postgresDatasource.postgresql) === null || _b === void 0 ? void 0 : _b.cloudSql.instance) !== null && _c !== void 0 ? _c : "";
45
46
  const instanceId = instanceName.split("/").pop();
46
- const dbId = (_e = (_d = schema === null || schema === void 0 ? void 0 : schema.primaryDatasource.postgresql) === null || _d === void 0 ? void 0 : _d.database) !== null && _e !== void 0 ? _e : "";
47
+ const dbId = (_e = (_d = postgresDatasource === null || postgresDatasource === void 0 ? void 0 : postgresDatasource.postgresql) === null || _d === void 0 ? void 0 : _d.database) !== null && _e !== void 0 ? _e : "";
47
48
  const dbName = `CloudSQL Instance: ${instanceId}\nDatabase: ${dbId}`;
48
49
  table.push([
49
50
  serviceName.serviceId,
@@ -17,9 +17,10 @@ exports.command = new command_1.Command("dataconnect:sql:diff [serviceId]")
17
17
  ])
18
18
  .before(requireAuth_1.requireAuth)
19
19
  .action(async (serviceId, options) => {
20
+ var _a;
20
21
  const projectId = (0, projectUtils_1.needProjectId)(options);
21
22
  await (0, ensureApis_1.ensureApis)(projectId);
22
23
  const serviceInfo = await (0, fileUtils_1.pickService)(projectId, options.config, serviceId);
23
- const diffs = await (0, schemaMigration_1.diffSchema)(serviceInfo.schema);
24
+ const diffs = await (0, schemaMigration_1.diffSchema)(serviceInfo.schema, (_a = serviceInfo.dataConnectYaml.schema.datasource.postgresql) === null || _a === void 0 ? void 0 : _a.schemaValidation);
24
25
  return { projectId, serviceId, diffs };
25
26
  });
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.command = void 0;
4
+ const command_1 = require("../command");
5
+ const projectUtils_1 = require("../projectUtils");
6
+ const ensureApis_1 = require("../dataconnect/ensureApis");
7
+ const requirePermissions_1 = require("../requirePermissions");
8
+ const fileUtils_1 = require("../dataconnect/fileUtils");
9
+ const schemaMigration_1 = require("../dataconnect/schemaMigration");
10
+ const requireAuth_1 = require("../requireAuth");
11
+ const error_1 = require("../error");
12
+ const permissions_1 = require("../gcp/cloudsql/permissions");
13
+ const allowedRoles = Object.keys(permissions_1.fdcSqlRoleMap);
14
+ exports.command = new command_1.Command("dataconnect:sql:grant [serviceId]")
15
+ .description("Grants the SQL role <role> to the provided user or service account <email>.")
16
+ .option("-R, --role <role>", "The SQL role to grant. One of: owner, writer, or reader.")
17
+ .option("-E, --email <email>", "The email of the user or service account we would like to grant the role to.")
18
+ .before(requirePermissions_1.requirePermissions, ["firebasedataconnect.services.list"])
19
+ .before(requireAuth_1.requireAuth)
20
+ .action(async (serviceId, options) => {
21
+ const role = options.role;
22
+ const email = options.email;
23
+ if (!role) {
24
+ throw new error_1.FirebaseError("-R, --role <role> is required. Run the command with -h for more info.");
25
+ }
26
+ if (!email) {
27
+ throw new error_1.FirebaseError("-E, --email <email> is required. Run the command with -h for more info.");
28
+ }
29
+ if (!allowedRoles.includes(role.toLowerCase())) {
30
+ throw new error_1.FirebaseError(`Role should be one of ${allowedRoles.join(" | ")}.`);
31
+ }
32
+ const projectId = (0, projectUtils_1.needProjectId)(options);
33
+ await (0, ensureApis_1.ensureApis)(projectId);
34
+ const serviceInfo = await (0, fileUtils_1.pickService)(projectId, options.config, serviceId);
35
+ await (0, schemaMigration_1.grantRoleToUserInSchema)(options, serviceInfo.schema);
36
+ return { projectId, serviceId };
37
+ });
@@ -17,12 +17,11 @@ exports.command = new command_1.Command("dataconnect:sql:migrate [serviceId]")
17
17
  "firebasedataconnect.schemas.list",
18
18
  "firebasedataconnect.schemas.update",
19
19
  "cloudsql.instances.connect",
20
- "cloudsql.users.create",
21
20
  ])
22
21
  .before(requireAuth_1.requireAuth)
23
22
  .withForce("Execute any required database changes without prompting")
24
23
  .action(async (serviceId, options) => {
25
- var _a;
24
+ var _a, _b;
26
25
  const projectId = (0, projectUtils_1.needProjectId)(options);
27
26
  await (0, ensureApis_1.ensureApis)(projectId);
28
27
  const serviceInfo = await (0, fileUtils_1.pickService)(projectId, options.config, serviceId);
@@ -34,6 +33,7 @@ exports.command = new command_1.Command("dataconnect:sql:migrate [serviceId]")
34
33
  options,
35
34
  schema: serviceInfo.schema,
36
35
  validateOnly: true,
36
+ schemaValidation: (_b = serviceInfo.dataConnectYaml.schema.datasource.postgresql) === null || _b === void 0 ? void 0 : _b.schemaValidation,
37
37
  });
38
38
  if (diffs.length) {
39
39
  (0, utils_1.logLabeledSuccess)("dataconnect", `Database schema sucessfully migrated! Run 'firebase deploy' to deploy your new schema to your Data Connect service.`);
@@ -86,6 +86,8 @@ exports.command = new command_1.Command("deploy")
86
86
  "For data connect, can specify filters with colons to deploy only a service, connector, or schema" +
87
87
  '(e.g. "--only dataconnect:serviceId,dataconnect:serviceId:connectorId,dataconnect:serviceId:schema"). ')
88
88
  .option("--except <targets>", 'deploy to all targets except specified (e.g. "database")')
89
+ .option("--dry-run", "Perform a dry run of your deployment. Validates your changes and builds your code without deploying any changes to your project. " +
90
+ "In order to provide better validation, this may still enable APIs on the target project.")
89
91
  .before(requireConfig_1.requireConfig)
90
92
  .before((options) => {
91
93
  options.filteredTargets = (0, filterTargets_1.filterTargets)(options, exports.VALID_DEPLOY_TARGETS);
@@ -8,12 +8,17 @@ const logger_1 = require("../logger");
8
8
  const requirePermissions_1 = require("../requirePermissions");
9
9
  const types_1 = require("../emulator/types");
10
10
  const commandUtils_1 = require("../emulator/commandUtils");
11
+ const options_1 = require("../firestore/options");
11
12
  const pretty_print_1 = require("../firestore/pretty-print");
12
13
  const error_1 = require("../error");
13
14
  exports.command = new command_1.Command("firestore:databases:restore")
14
15
  .description("Restore a Firestore database in your Firebase project.")
15
16
  .option("-d, --database <databaseID>", "ID of the database to restore into")
16
17
  .option("-b, --backup <backup>", "Backup from which to restore")
18
+ .option("-e, --encryption-type <encryptionType>", `Encryption method of the restored database; one of ${options_1.EncryptionType.USE_SOURCE_ENCRYPTION} (default), ` +
19
+ `${options_1.EncryptionType.CUSTOMER_MANAGED_ENCRYPTION}, ${options_1.EncryptionType.GOOGLE_DEFAULT_ENCRYPTION}`)
20
+ .option("-k, --kms-key-name <kmsKeyName>", "Resource ID of the Cloud KMS key to encrypt the restored database. This " +
21
+ "feature is allowlist only in initial launch.")
17
22
  .before(requirePermissions_1.requirePermissions, ["datastore.backups.restoreDatabase"])
18
23
  .before(commandUtils_1.warnEmulatorNotSupported, types_1.Emulators.FIRESTORE)
19
24
  .action(async (options) => {
@@ -28,7 +33,28 @@ exports.command = new command_1.Command("firestore:databases:restore")
28
33
  throw new error_1.FirebaseError(`Missing required flag --backup. ${helpCommandText}`);
29
34
  }
30
35
  const backupName = options.backup;
31
- const databaseResp = await api.restoreDatabase(options.project, databaseId, backupName);
36
+ let encryptionConfig = undefined;
37
+ switch (options.encryptionType) {
38
+ case options_1.EncryptionType.GOOGLE_DEFAULT_ENCRYPTION:
39
+ throwIfKmsKeyNameIsSet(options.kmsKeyName);
40
+ encryptionConfig = { googleDefaultEncryption: {} };
41
+ break;
42
+ case options_1.EncryptionType.USE_SOURCE_ENCRYPTION:
43
+ throwIfKmsKeyNameIsSet(options.kmsKeyName);
44
+ encryptionConfig = { useSourceEncryption: {} };
45
+ break;
46
+ case options_1.EncryptionType.CUSTOMER_MANAGED_ENCRYPTION:
47
+ encryptionConfig = {
48
+ customerManagedEncryption: { kmsKeyName: getKmsKeyOrThrow(options.kmsKeyName) },
49
+ };
50
+ break;
51
+ case undefined:
52
+ throwIfKmsKeyNameIsSet(options.kmsKeyName);
53
+ break;
54
+ default:
55
+ throw new error_1.FirebaseError(`Invalid value for flag --encryption-type. ${helpCommandText}`);
56
+ }
57
+ const databaseResp = await api.restoreDatabase(options.project, databaseId, backupName, encryptionConfig);
32
58
  if (options.json) {
33
59
  logger_1.logger.info(JSON.stringify(databaseResp, undefined, 2));
34
60
  }
@@ -40,4 +66,16 @@ exports.command = new command_1.Command("firestore:databases:restore")
40
66
  logger_1.logger.info(`Once the restore is complete, your database may be viewed at ${printer.firebaseConsoleDatabaseUrl(options.project, databaseId)}`);
41
67
  }
42
68
  return databaseResp;
69
+ function throwIfKmsKeyNameIsSet(kmsKeyName) {
70
+ if (kmsKeyName) {
71
+ throw new error_1.FirebaseError("--kms-key-name can only be set when specifying an --encryption-type " +
72
+ `of ${options_1.EncryptionType.CUSTOMER_MANAGED_ENCRYPTION}.`);
73
+ }
74
+ }
75
+ function getKmsKeyOrThrow(kmsKeyName) {
76
+ if (kmsKeyName)
77
+ return kmsKeyName;
78
+ throw new error_1.FirebaseError("--kms-key-name must be provided when specifying an --encryption-type " +
79
+ `of ${options_1.EncryptionType.CUSTOMER_MANAGED_ENCRYPTION}.`);
80
+ }
43
81
  });
@@ -207,6 +207,7 @@ function load(client) {
207
207
  client.dataconnect.sql = {};
208
208
  client.dataconnect.sql.diff = loadCommand("dataconnect-sql-diff");
209
209
  client.dataconnect.sql.migrate = loadCommand("dataconnect-sql-migrate");
210
+ client.dataconnect.sql.grant = loadCommand("dataconnect-sql-grant");
210
211
  client.dataconnect.sdk = {};
211
212
  client.dataconnect.sdk.generate = loadCommand("dataconnect-sdk-generate");
212
213
  client.target = loadCommand("target");
@@ -5,7 +5,7 @@ const api_1 = require("../api");
5
5
  const apiv2_1 = require("../apiv2");
6
6
  const operationPoller = require("../operation-poller");
7
7
  const types = require("./types");
8
- const DATACONNECT_API_VERSION = "v1alpha";
8
+ const DATACONNECT_API_VERSION = "v1beta";
9
9
  const PAGE_SIZE_MAX = 100;
10
10
  const dataconnectClient = () => new apiv2_1.Client({
11
11
  urlPrefix: (0, api_1.dataconnectOrigin)(),
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.executeGraphQL = void 0;
4
4
  const api_1 = require("../api");
5
5
  const apiv2_1 = require("../apiv2");
6
- const DATACONNECT_API_VERSION = "v1alpha";
6
+ const DATACONNECT_API_VERSION = "v1beta";
7
7
  const dataconnectDataplaneClient = () => new apiv2_1.Client({
8
8
  urlPrefix: (0, api_1.dataconnectOrigin)(),
9
9
  apiVersion: DATACONNECT_API_VERSION,
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ensureApis = void 0;
3
+ exports.ensureSparkApis = exports.ensureApis = void 0;
4
4
  const api = require("../api");
5
5
  const ensureApiEnabled_1 = require("../ensureApiEnabled");
6
6
  async function ensureApis(projectId) {
@@ -10,3 +10,9 @@ async function ensureApis(projectId) {
10
10
  await (0, ensureApiEnabled_1.ensure)(projectId, api.computeOrigin(), prefix);
11
11
  }
12
12
  exports.ensureApis = ensureApis;
13
+ async function ensureSparkApis(projectId) {
14
+ const prefix = "dataconnect";
15
+ await (0, ensureApiEnabled_1.ensure)(projectId, api.dataconnectOrigin(), prefix);
16
+ await (0, ensureApiEnabled_1.ensure)(projectId, api.cloudSQLAdminOrigin(), prefix);
17
+ }
18
+ exports.ensureSparkApis = ensureSparkApis;
@@ -30,7 +30,9 @@ async function load(projectId, config, sourceDirectory) {
30
30
  sourceDirectory: resolvedDir,
31
31
  schema: {
32
32
  name: `${serviceName}/schemas/${types_1.SCHEMA_ID}`,
33
- primaryDatasource: (0, types_1.toDatasource)(projectId, dataConnectYaml.location, dataConnectYaml.schema.datasource),
33
+ datasources: [
34
+ (0, types_1.toDatasource)(projectId, dataConnectYaml.location, dataConnectYaml.schema.datasource),
35
+ ],
34
36
  source: {
35
37
  files: schemaGQLs,
36
38
  },
@@ -11,19 +11,22 @@ const freeTrial_1 = require("./freeTrial");
11
11
  const error_1 = require("../error");
12
12
  async function provisionCloudSql(args) {
13
13
  let connectionName = "";
14
- const { projectId, locationId, instanceId, databaseId, enableGoogleMlIntegration, waitForCreation, silent, } = args;
14
+ const { projectId, locationId, instanceId, databaseId, enableGoogleMlIntegration, waitForCreation, silent, dryRun, } = args;
15
15
  try {
16
16
  const existingInstance = await cloudSqlAdminClient.getInstance(projectId, instanceId);
17
17
  silent || utils.logLabeledBullet("dataconnect", `Found existing instance ${instanceId}.`);
18
18
  connectionName = (existingInstance === null || existingInstance === void 0 ? void 0 : existingInstance.connectionName) || "";
19
19
  const why = getUpdateReason(existingInstance, enableGoogleMlIntegration);
20
20
  if (why) {
21
+ const cta = dryRun
22
+ ? `It will be updated on your next deploy.`
23
+ : `Updating instance. This may take a few minutes...`;
21
24
  silent ||
22
- utils.logLabeledBullet("dataconnect", `Instance ${instanceId} settings not compatible with Firebase Data Connect. ` +
23
- `Updating instance. This may take a few minutes...` +
24
- why);
25
- await (0, utils_1.promiseWithSpinner)(() => cloudSqlAdminClient.updateInstanceForDataConnect(existingInstance, enableGoogleMlIntegration), "Updating your instance...");
26
- silent || utils.logLabeledBullet("dataconnect", "Instance updated");
25
+ utils.logLabeledBullet("dataconnect", `Instance ${instanceId} settings not compatible with Firebase Data Connect. ` + cta + why);
26
+ if (!dryRun) {
27
+ await (0, utils_1.promiseWithSpinner)(() => cloudSqlAdminClient.updateInstanceForDataConnect(existingInstance, enableGoogleMlIntegration), "Updating your instance...");
28
+ silent || utils.logLabeledBullet("dataconnect", "Instance updated");
29
+ }
27
30
  }
28
31
  }
29
32
  catch (err) {
@@ -35,19 +38,23 @@ async function provisionCloudSql(args) {
35
38
  (0, freeTrial_1.printFreeTrialUnavailable)(projectId, freeTrialInstanceId);
36
39
  throw new error_1.FirebaseError("Free trial unavailable.");
37
40
  }
41
+ const cta = dryRun ? "It will be created on your next deploy" : "Creating it now.";
38
42
  silent ||
39
- utils.logLabeledBullet("dataconnect", `CloudSQL instance '${instanceId}' not found, creating it.` +
43
+ utils.logLabeledBullet("dataconnect", `CloudSQL instance '${instanceId}' not found.` +
44
+ cta +
40
45
  `\nThis instance is provided under the terms of the Data Connect free trial ${(0, freeTrial_1.freeTrialTermsLink)()}` +
41
46
  `\nMonitor the progress at ${cloudSqlAdminClient.instanceConsoleLink(projectId, instanceId)}`);
42
- const newInstance = await (0, utils_1.promiseWithSpinner)(() => cloudSqlAdminClient.createInstance(projectId, locationId, instanceId, enableGoogleMlIntegration, waitForCreation), "Creating your instance...");
43
- if (newInstance) {
44
- silent || utils.logLabeledBullet("dataconnect", "Instance created");
45
- connectionName = (newInstance === null || newInstance === void 0 ? void 0 : newInstance.connectionName) || "";
46
- }
47
- else {
48
- silent ||
49
- utils.logLabeledBullet("dataconnect", "Cloud SQL instance creation started - it should be ready shortly. Database and users will be created on your next deploy.");
50
- return connectionName;
47
+ if (!dryRun) {
48
+ const newInstance = await (0, utils_1.promiseWithSpinner)(() => cloudSqlAdminClient.createInstance(projectId, locationId, instanceId, enableGoogleMlIntegration, waitForCreation), "Creating your instance...");
49
+ if (newInstance) {
50
+ silent || utils.logLabeledBullet("dataconnect", "Instance created");
51
+ connectionName = (newInstance === null || newInstance === void 0 ? void 0 : newInstance.connectionName) || "";
52
+ }
53
+ else {
54
+ silent ||
55
+ utils.logLabeledBullet("dataconnect", "Cloud SQL instance creation started - it should be ready shortly. Database and users will be created on your next deploy.");
56
+ return connectionName;
57
+ }
51
58
  }
52
59
  }
53
60
  try {
@@ -56,17 +63,23 @@ async function provisionCloudSql(args) {
56
63
  }
57
64
  catch (err) {
58
65
  if (err.status === 404) {
59
- silent ||
60
- utils.logLabeledBullet("dataconnect", `Database ${databaseId} not found, creating it now...`);
61
- await cloudSqlAdminClient.createDatabase(projectId, instanceId, databaseId);
62
- silent || utils.logLabeledBullet("dataconnect", `Database ${databaseId} created.`);
66
+ if (dryRun) {
67
+ silent ||
68
+ utils.logLabeledBullet("dataconnect", `Database ${databaseId} not found. It will be created on your next deploy.`);
69
+ }
70
+ else {
71
+ silent ||
72
+ utils.logLabeledBullet("dataconnect", `Database ${databaseId} not found, creating it now...`);
73
+ await cloudSqlAdminClient.createDatabase(projectId, instanceId, databaseId);
74
+ silent || utils.logLabeledBullet("dataconnect", `Database ${databaseId} created.`);
75
+ }
63
76
  }
64
77
  else {
65
78
  logger_1.logger.debug(`Unexpected error from CloudSQL: ${err}`);
66
79
  silent || utils.logLabeledWarning("dataconnect", `Database ${databaseId} is not accessible.`);
67
80
  }
68
81
  }
69
- if (enableGoogleMlIntegration) {
82
+ if (enableGoogleMlIntegration && !dryRun) {
70
83
  await (0, checkIam_1.grantRolesToCloudSqlServiceAccount)(projectId, instanceId, [GOOGLE_ML_INTEGRATION_ROLE]);
71
84
  }
72
85
  return connectionName;