Skip to content
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
- Add a confirmation in `firebase init dataconnect` before asking for app idea description. (#9282)
1 change: 0 additions & 1 deletion firebase-vscode/src/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ const defaultOptions: Readonly<VsCodeOptions> = {
projectNumber: "",
projectRoot: "",
account: "",
json: true,
nonInteractive: true,
interactive: false,
debug: false,
Expand Down
15 changes: 8 additions & 7 deletions npm-shrinkwrap.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@
"source-map-support": "^0.5.9",
"supertest": "^6.2.3",
"swagger2openapi": "^7.0.8",
"ts-node": "^10.4.0",
"ts-node": "^10.9.2",
"typescript": "^4.5.4",
"typescript-json-schema": "^0.65.1",
"vite": "^4.2.1"
Expand Down
1 change: 0 additions & 1 deletion src/checkValidTargetFilters.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ const SAMPLE_OPTIONS: Options = {
only: "",
except: "",
nonInteractive: false,
json: false,
interactive: false,
debug: false,
force: false,
Expand Down
1 change: 1 addition & 0 deletions src/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ export class Command {
}

if (getInheritedOption(options, "json")) {
options.interactive = false;
options.nonInteractive = true;
} else if (!options.isMCP) {
useConsoleLoggers();
Expand Down
14 changes: 11 additions & 3 deletions src/commands/dataconnect-sdk-generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,32 @@ import { Command } from "../command";
import { Options } from "../options";
import { DataConnectEmulator } from "../emulator/dataconnectEmulator";
import { needProjectId } from "../projectUtils";
import { loadAll } from "../dataconnect/load";
import { loadAll, pickService } from "../dataconnect/load";
import { logger } from "../logger";
import { getProjectDefaultAccount } from "../auth";
import { logLabeledSuccess } from "../utils";
import { ServiceInfo } from "../dataconnect/types";

type GenerateOptions = Options & { watch?: boolean };
type GenerateOptions = Options & { watch?: boolean; service?: string };

export const command = new Command("dataconnect:sdk:generate")
.description("generate typed SDKs for your Data Connect connectors")
.option(
"--service <serviceId>",
"the serviceId of the Data Connect service. If not provided, generates SDKs for all services.",
)
.option("--location <location>", "the location of the Data Connect service", "us-central1")
.option(
"--watch",
"watch for changes to your connector GQL files and regenerate your SDKs when updates occur",
)
.action(async (options: GenerateOptions) => {
const projectId = needProjectId(options);
const location = options.location as string;

const serviceInfos = await loadAll(projectId, options.config);
const serviceInfos = options.service
? [await pickService(projectId, options.config, options.service, location)]
: await loadAll(projectId, options.config, location);
const serviceInfosWithSDKs = serviceInfos.filter((serviceInfo) =>
serviceInfo.connectorInfo.some((c) => {
return (
Expand Down
13 changes: 10 additions & 3 deletions src/commands/dataconnect-sql-diff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,27 @@
import { diffSchema } from "../dataconnect/schemaMigration";
import { requireAuth } from "../requireAuth";

export const command = new Command("dataconnect:sql:diff [serviceId]")
export const command = new Command("dataconnect:sql:diff")
.description(
"display the differences between a local Data Connect schema and your CloudSQL database's current schema",
)
.option("--service <serviceId>", "the serviceId of the Data Connect service")
.option("--location <location>", "the location of the Data Connect service", "us-central1")
.before(requirePermissions, [
"firebasedataconnect.services.list",
"firebasedataconnect.schemas.list",
"firebasedataconnect.schemas.update",
])
.before(requireAuth)
.action(async (serviceId: string, options: Options) => {
.action(async (options: Options) => {
const projectId = needProjectId(options);
if (!options.service) {
throw new FirebaseError("Missing required flag --service");

Check failure on line 25 in src/commands/dataconnect-sql-diff.ts

View workflow job for this annotation

GitHub Actions / unit (20)

Cannot find name 'FirebaseError'.

Check failure on line 25 in src/commands/dataconnect-sql-diff.ts

View workflow job for this annotation

GitHub Actions / unit (22)

Cannot find name 'FirebaseError'.

Check failure on line 25 in src/commands/dataconnect-sql-diff.ts

View workflow job for this annotation

GitHub Actions / vscode_unit (20)

Cannot find name 'FirebaseError'.

Check failure on line 25 in src/commands/dataconnect-sql-diff.ts

View workflow job for this annotation

GitHub Actions / check-json-schema (20)

Cannot find name 'FirebaseError'.

Check failure on line 25 in src/commands/dataconnect-sql-diff.ts

View workflow job for this annotation

GitHub Actions / check-json-schema (22)

Cannot find name 'FirebaseError'.

Check failure on line 25 in src/commands/dataconnect-sql-diff.ts

View workflow job for this annotation

GitHub Actions / check-json-schema (22)

Cannot find name 'FirebaseError'.

Check failure on line 25 in src/commands/dataconnect-sql-diff.ts

View workflow job for this annotation

GitHub Actions / vscode_unit (22)

Cannot find name 'FirebaseError'.

Check failure on line 25 in src/commands/dataconnect-sql-diff.ts

View workflow job for this annotation

GitHub Actions / unit (20)

Cannot find name 'FirebaseError'.

Check failure on line 25 in src/commands/dataconnect-sql-diff.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Cannot find name 'FirebaseError'.

Check failure on line 25 in src/commands/dataconnect-sql-diff.ts

View workflow job for this annotation

GitHub Actions / unit (22)

Cannot find name 'FirebaseError'.

Check failure on line 25 in src/commands/dataconnect-sql-diff.ts

View workflow job for this annotation

GitHub Actions / check-json-schema (20)

Cannot find name 'FirebaseError'.
}
const serviceId = options.service as string;
const location = options.location as string;
await ensureApis(projectId);
const serviceInfo = await pickService(projectId, options.config, serviceId);
const serviceInfo = await pickService(projectId, options.config, serviceId, location);

const diffs = await diffSchema(
options,
Expand Down
13 changes: 10 additions & 3 deletions src/commands/dataconnect-sql-grant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,23 @@ import { iamUserIsCSQLAdmin } from "../gcp/cloudsql/cloudsqladmin";

const allowedRoles = Object.keys(fdcSqlRoleMap);

export const command = new Command("dataconnect:sql:grant [serviceId]")
export const command = new Command("dataconnect:sql:grant")
.description("grants the SQL role <role> to the provided user or service account <email>")
.option("--service <serviceId>", "the serviceId of the Data Connect service")
.option("--location <location>", "the location of the Data Connect service", "us-central1")
.option("-R, --role <role>", "The SQL role to grant. One of: owner, writer, or reader.")
.option(
"-E, --email <email>",
"The email of the user or service account we would like to grant the role to.",
)
.before(requirePermissions, ["firebasedataconnect.services.list"])
.before(requireAuth)
.action(async (serviceId: string, options: Options) => {
.action(async (options: Options) => {
if (!options.service) {
throw new FirebaseError("Missing required flag --service");
}
const serviceId = options.service as string;
const location = options.location as string;
const role = options.role as string;
const email = options.email as string;
if (!role) {
Expand Down Expand Up @@ -49,7 +56,7 @@ export const command = new Command("dataconnect:sql:grant [serviceId]")

const projectId = needProjectId(options);
await ensureApis(projectId);
const serviceInfo = await pickService(projectId, options.config, serviceId);
const serviceInfo = await pickService(projectId, options.config, serviceId, location);

await grantRoleToUserInSchema(options, serviceInfo.schema);
return { projectId, serviceId };
Expand Down
13 changes: 10 additions & 3 deletions src/commands/dataconnect-sql-migrate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import { requirePermissions } from "../requirePermissions";
import { ensureApis } from "../dataconnect/ensureApis";
import { logLabeledSuccess } from "../utils";

export const command = new Command("dataconnect:sql:migrate [serviceId]")
export const command = new Command("dataconnect:sql:migrate")
.description("migrate your CloudSQL database's schema to match your local Data Connect schema")
.option("--service <serviceId>", "the serviceId of the Data Connect service")
.option("--location <location>", "the location of the Data Connect service", "us-central1")
.before(requirePermissions, [
"firebasedataconnect.services.list",
"firebasedataconnect.schemas.list",
Expand All @@ -19,10 +21,15 @@ export const command = new Command("dataconnect:sql:migrate [serviceId]")
])
.before(requireAuth)
.withForce("execute any required database changes without prompting")
.action(async (serviceId: string, options: Options) => {
.action(async (options: Options) => {
const projectId = needProjectId(options);
if (!options.service) {
throw new FirebaseError("Missing required flag --service");
}
const serviceId = options.service as string;
const location = options.location as string;
await ensureApis(projectId);
const serviceInfo = await pickService(projectId, options.config, serviceId);
const serviceInfo = await pickService(projectId, options.config, serviceId, location);
const instanceId =
serviceInfo.dataConnectYaml.schema.datasource.postgresql?.cloudSql.instanceId;
if (!instanceId) {
Expand Down
13 changes: 10 additions & 3 deletions src/commands/dataconnect-sql-setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,26 @@ import { DEFAULT_SCHEMA } from "../gcp/cloudsql/permissions";
import { getIdentifiers, ensureServiceIsConnectedToCloudSql } from "../dataconnect/schemaMigration";
import { setupIAMUsers } from "../gcp/cloudsql/connect";

export const command = new Command("dataconnect:sql:setup [serviceId]")
export const command = new Command("dataconnect:sql:setup")
.description("set up your CloudSQL database")
.option("--service <serviceId>", "the serviceId of the Data Connect service")
.option("--location <location>", "the location of the Data Connect service", "us-central1")
.before(requirePermissions, [
"firebasedataconnect.services.list",
"firebasedataconnect.schemas.list",
"firebasedataconnect.schemas.update",
"cloudsql.instances.connect",
])
.before(requireAuth)
.action(async (serviceId: string, options: Options) => {
.action(async (options: Options) => {
const projectId = needProjectId(options);
if (!options.service) {
throw new FirebaseError("Missing required flag --service");
}
const serviceId = options.service as string;
const location = options.location as string;
await ensureApis(projectId);
const serviceInfo = await pickService(projectId, options.config, serviceId);
const serviceInfo = await pickService(projectId, options.config, serviceId, location);
const instanceId =
serviceInfo.dataConnectYaml.schema.datasource.postgresql?.cloudSql.instanceId;
if (!instanceId) {
Expand Down
13 changes: 10 additions & 3 deletions src/commands/dataconnect-sql-shell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,16 +81,23 @@ async function mainShellLoop(conn: pg.PoolClient) {
}
}

export const command = new Command("dataconnect:sql:shell [serviceId]")
export const command = new Command("dataconnect:sql:shell")
.description(
"start a shell connected directly to your Data Connect service's linked CloudSQL instance",
)
.option("--service <serviceId>", "the serviceId of the Data Connect service")
.option("--location <location>", "the location of the Data Connect service", "us-central1")
.before(requirePermissions, ["firebasedataconnect.services.list", "cloudsql.instances.connect"])
.before(requireAuth)
.action(async (serviceId: string, options: Options) => {
.action(async (options: Options) => {
const projectId = needProjectId(options);
if (!options.service) {
throw new FirebaseError("Missing required flag --service");
}
const serviceId = options.service as string;
const location = options.location as string;
await ensureApis(projectId);
const serviceInfo = await pickService(projectId, options.config, serviceId);
const serviceInfo = await pickService(projectId, options.config, serviceId, location);
const { instanceId, databaseId } = getIdentifiers(serviceInfo.schema);
const { user: username } = await getIAMUser(options);
const instance = await cloudSqlAdminClient.getInstance(projectId, instanceId);
Expand Down
6 changes: 1 addition & 5 deletions src/commands/firestore-backups-delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,7 @@ export const command = new Command("firestore:backups:delete <backup>")
throw new FirebaseError(`Failed to delete the backup ${backupName}`, { original: err });
}

if (options.json) {
logger.info(JSON.stringify(backup, undefined, 2));
} else {
logger.info(clc.bold(`Successfully deleted ${clc.yellow(backupName)}`));
}
logger.info(clc.bold(`Successfully deleted ${clc.yellow(backupName)}`));

return backup;
});
10 changes: 2 additions & 8 deletions src/commands/firestore-backups-get.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
import { Command } from "../command";
import { logger } from "../logger";
import { requirePermissions } from "../requirePermissions";
import { Emulators } from "../emulator/types";
import { warnEmulatorNotSupported } from "../emulator/commandUtils";
import { FirestoreOptions } from "../firestore/options";
import { Backup, getBackup } from "../gcp/firestore";
import { PrettyPrint } from "../firestore/pretty-print";

export const command = new Command("firestore:backups:get <backup>")
.description("get a Cloud Firestore database backup")
.before(requirePermissions, ["datastore.backups.get"])
.before(warnEmulatorNotSupported, Emulators.FIRESTORE)
.action(async (backupName: string, options: FirestoreOptions) => {
.action(async (backupName: string) => {
const backup: Backup = await getBackup(backupName);
const printer = new PrettyPrint();

if (options.json) {
logger.info(JSON.stringify(backup, undefined, 2));
} else {
printer.prettyPrintBackup(backup);
}
printer.prettyPrintBackup(backup);

return backup;
});
19 changes: 8 additions & 11 deletions src/commands/firestore-backups-list.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Command } from "../command";
import { logger } from "../logger";
import { requirePermissions } from "../requirePermissions";
import { Emulators } from "../emulator/types";
import { warnEmulatorNotSupported } from "../emulator/commandUtils";
Expand All @@ -23,17 +22,15 @@ export const command = new Command("firestore:backups:list")
const listBackupsResponse: ListBackupsResponse = await listBackups(options.project, location);
const backups: Backup[] = listBackupsResponse.backups || [];

if (options.json) {
logger.info(JSON.stringify(listBackupsResponse, undefined, 2));
} else {
printer.prettyPrintBackups(backups);
if (listBackupsResponse.unreachable && listBackupsResponse.unreachable.length > 0) {
logWarning(
"We were not able to reach the following locations: " +
listBackupsResponse.unreachable.join(", "),
);
}
printer.prettyPrintBackups(backups);
if (listBackupsResponse.unreachable && listBackupsResponse.unreachable.length > 0) {
logWarning(
"We were not able to reach the following locations: " +
listBackupsResponse.unreachable.join(", "),
);
}

// TODO: Consider returning listBackupResponse instead for --json. This will
// be a breaking change but exposes .unreachable, not just .backups.
return backups;
});
10 changes: 3 additions & 7 deletions src/commands/firestore-backups-schedules-create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,13 +81,9 @@ export const command = new Command("firestore:backups:schedules:create")
weeklyRecurrence,
);

if (options.json) {
logger.info(JSON.stringify(backupSchedule, undefined, 2));
} else {
logger.info(
clc.bold(`Successfully created ${printer.prettyBackupScheduleString(backupSchedule)}`),
);
}
logger.info(
clc.bold(`Successfully created ${printer.prettyBackupScheduleString(backupSchedule)}`),
);

return backupSchedule;
});
6 changes: 1 addition & 5 deletions src/commands/firestore-backups-schedules-delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,7 @@ export const command = new Command("firestore:backups:schedules:delete <backupSc
});
}

if (options.json) {
logger.info(JSON.stringify(backupSchedule, undefined, 2));
} else {
logger.info(clc.bold(`Successfully deleted ${clc.yellow(backupScheduleName)}`));
}
logger.info(clc.bold(`Successfully deleted ${clc.yellow(backupScheduleName)}`));

return backupSchedule;
});
7 changes: 1 addition & 6 deletions src/commands/firestore-backups-schedules-list.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Command } from "../command";
import { logger } from "../logger";
import { requirePermissions } from "../requirePermissions";
import { Emulators } from "../emulator/types";
import { warnEmulatorNotSupported } from "../emulator/commandUtils";
Expand All @@ -24,11 +23,7 @@ export const command = new Command("firestore:backups:schedules:list")
databaseId,
);

if (options.json) {
logger.info(JSON.stringify(backupSchedules, undefined, 2));
} else {
printer.prettyPrintBackupSchedules(backupSchedules, databaseId);
}
printer.prettyPrintBackupSchedules(backupSchedules, databaseId);

return backupSchedules;
});
10 changes: 3 additions & 7 deletions src/commands/firestore-backups-schedules-update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,9 @@ export const command = new Command("firestore:backups:schedules:update <backupSc
retention,
);

if (options.json) {
logger.info(JSON.stringify(backupSchedule, undefined, 2));
} else {
logger.info(
clc.bold(`Successfully updated ${printer.prettyBackupScheduleString(backupSchedule)}`),
);
}
logger.info(
clc.bold(`Successfully updated ${printer.prettyBackupScheduleString(backupSchedule)}`),
);

return backupSchedule;
});
Loading
Loading