Skip to content

Commit 36e40da

Browse files
authored
Non interactive setup for dataconnect init and sdk (#8993)
* Make it possibe to set dataconnect without project and create sdk with env vars * change == to === * use FDC_APP_FOLDER directly instead of adding another env var * code review * Add changelog
1 parent 05518e4 commit 36e40da

File tree

4 files changed

+49
-15
lines changed

4 files changed

+49
-15
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
- Added prefix support for multi-instance Cloud Functions extension parameters. (#8911)
22
- Fixed a bug when `firebase deploy --only dataconnect` doesn't include GQL in nested folders (#8981)
3+
- Make it possible to init a dataconnect project in non interactive mode (#8993)

src/init/features/dataconnect/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import * as sdk from "./sdk";
2525
import { getPlatformFromFolder } from "../../../dataconnect/fileUtils";
2626
import { extractCodeBlock, generateSchema } from "../../../gemini/fdcExperience";
2727
import { configstore } from "../../../configstore";
28+
import { Options } from "../../../options";
2829

2930
const DATACONNECT_YAML_TEMPLATE = readTemplateSync("init/dataconnect/dataconnect.yaml");
3031
const CONNECTOR_YAML_TEMPLATE = readTemplateSync("init/dataconnect/connector.yaml");
@@ -171,12 +172,12 @@ export async function actuate(setup: Setup, config: Config, options: any): Promi
171172
}
172173
}
173174

174-
export async function postSetup(setup: Setup, config: Config): Promise<void> {
175+
export async function postSetup(setup: Setup, config: Config, options: Options): Promise<void> {
175176
const cwdPlatformGuess = await getPlatformFromFolder(process.cwd());
176177
// If a platform can be detected or a connector is chosen via env var, always
177178
// setup SDK. FDC_CONNECTOR is used for scripts under https://firebase.tools/.
178179
if (cwdPlatformGuess !== Platform.NONE || envOverride("FDC_CONNECTOR", "")) {
179-
await sdk.doSetup(setup, config);
180+
await sdk.doSetup(setup, config, options);
180181
} else {
181182
logBullet(
182183
`If you'd like to add the generated SDK to your app later, run ${clc.bold("firebase init dataconnect:sdk")}`,

src/init/features/dataconnect/sdk.ts

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,22 +28,26 @@ import { FirebaseError } from "../../../error";
2828
import { camelCase, snakeCase, upperFirst } from "lodash";
2929
import { logSuccess, logBullet, promptForDirectory, envOverride, logWarning } from "../../../utils";
3030
import { getGlobalDefaultAccount } from "../../../auth";
31+
import { Options } from "../../../options";
32+
33+
export const FDC_APP_FOLDER = "FDC_APP_FOLDER";
34+
export const FDC_SDK_FRAMEWORKS_ENV = "FDC_SDK_FRAMEWORKS";
35+
export const FDC_SDK_PLATFORM_ENV = "FDC_SDK_PLATFORM";
3136

32-
export const FDC_APP_FOLDER = "_FDC_APP_FOLDER";
3337
export type SDKInfo = {
3438
connectorYamlContents: string;
3539
connectorInfo: ConnectorInfo;
3640
displayIOSWarning: boolean;
3741
};
38-
export async function doSetup(setup: Setup, config: Config): Promise<void> {
39-
const sdkInfo = await askQuestions(setup, config);
42+
export async function doSetup(setup: Setup, config: Config, options: Options): Promise<void> {
43+
const sdkInfo = await askQuestions(setup, config, options);
4044
await actuate(sdkInfo, config);
4145
logSuccess(
4246
`If you'd like to add more generated SDKs to your app your later, run ${clc.bold("firebase init dataconnect:sdk")} again`,
4347
);
4448
}
4549

46-
async function askQuestions(setup: Setup, config: Config): Promise<SDKInfo> {
50+
async function askQuestions(setup: Setup, config: Config, options: Options): Promise<SDKInfo> {
4751
const serviceCfgs = readFirebaseJson(config);
4852
// TODO: This current approach removes comments from YAML files. Consider a different approach that won't.
4953
const serviceInfos = await Promise.all(
@@ -69,7 +73,21 @@ async function askQuestions(setup: Setup, config: Config): Promise<SDKInfo> {
6973

7074
// First, lets check if we are in an app directory
7175
let appDir = process.env[FDC_APP_FOLDER] || process.cwd();
72-
let targetPlatform = await getPlatformFromFolder(appDir);
76+
let targetPlatform = envOverride(
77+
FDC_SDK_PLATFORM_ENV,
78+
(await getPlatformFromFolder(appDir)) || Platform.NONE,
79+
) as Platform;
80+
81+
if (options.nonInteractive && targetPlatform === Platform.NONE) {
82+
throw new FirebaseError(
83+
`In non-interactive mode, the target platform and app directory must be specified using environment variables if they cannot be automatically detected.
84+
Please set the ${FDC_SDK_PLATFORM_ENV} and ${FDC_APP_FOLDER} environment variables.
85+
For example:
86+
${clc.bold(
87+
`${FDC_SDK_PLATFORM_ENV}=WEB ${FDC_APP_FOLDER}=app-dir ${FDC_SDK_FRAMEWORKS_ENV}=react firebase init dataconnect:sdk --non-interactive`,
88+
)}`,
89+
);
90+
}
7391
if (targetPlatform === Platform.NONE && !process.env[FDC_APP_FOLDER]?.length) {
7492
// If we aren't in an app directory, ask the user where their app is, and try to autodetect from there.
7593
appDir = await promptForDirectory({
@@ -114,14 +132,22 @@ async function askQuestions(setup: Setup, config: Config): Promise<SDKInfo> {
114132
(framework) => !newConnectorYaml!.generate?.javascriptSdk![framework],
115133
);
116134
if (unusedFrameworks.length > 0) {
117-
const additionalFrameworks = await checkbox<(typeof SUPPORTED_FRAMEWORKS)[number]>({
118-
message:
119-
"Which frameworks would you like to generate SDKs for in addition to the TypeScript SDK? Press Enter to skip.\n",
120-
choices: SUPPORTED_FRAMEWORKS.map((frameworkStr) => ({
121-
value: frameworkStr,
122-
checked: newConnectorYaml?.generate?.javascriptSdk?.[frameworkStr],
123-
})),
124-
});
135+
let additionalFrameworks: (typeof SUPPORTED_FRAMEWORKS)[number][] = [];
136+
if (options.nonInteractive) {
137+
additionalFrameworks = envOverride(FDC_SDK_FRAMEWORKS_ENV, "")
138+
.split(",")
139+
.filter((f) => f) as (typeof SUPPORTED_FRAMEWORKS)[number][];
140+
} else {
141+
additionalFrameworks = await checkbox<(typeof SUPPORTED_FRAMEWORKS)[number]>({
142+
message:
143+
"Which frameworks would you like to generate SDKs for in addition to the TypeScript SDK? Press Enter to skip.\n",
144+
choices: SUPPORTED_FRAMEWORKS.map((frameworkStr) => ({
145+
value: frameworkStr,
146+
checked: newConnectorYaml?.generate?.javascriptSdk?.[frameworkStr],
147+
})),
148+
});
149+
}
150+
125151
for (const framework of additionalFrameworks) {
126152
newConnectorYaml!.generate!.javascriptSdk![framework] = true;
127153
}

src/init/features/project.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,12 @@ export async function doSetup(setup: any, config: any, options: any): Promise<vo
133133
logger.debug(`Using project from $FIREBASE_PROJECT: ${projectEnvVar}`);
134134
projectMetaData = await getFirebaseProject(projectEnvVar);
135135
} else {
136+
if (options.nonInteractive) {
137+
logger.info(
138+
"No default project found. Continuing without a project in non interactive mode.",
139+
);
140+
return;
141+
}
136142
projectMetaData = await projectChoicePrompt(options);
137143
if (!projectMetaData) {
138144
return;

0 commit comments

Comments
 (0)