Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@
- Fixes Storage Emulator to support JSON uploads larger than 100KB without hanging or throwing 413 error (#8355)
- Add `extdeprecationwarnings` experiment to display phased deprecation notices and guidance across `ext:*` CLI commands.
- Fixes Data Connect emulator crash when in-flight GraphQL requests are cancelled (#10821)
- Automatically enable non-interactive mode when an AI agent is detected in the environment to prevent the CLI from hanging on interactive prompts.
11 changes: 9 additions & 2 deletions src/command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { getProject } from "./management/projects";
import { reconcileStudioFirebaseProject } from "./management/studio";
import { requireAuth } from "./requireAuth";
import { Options } from "./options";
import { isFirebaseStudio } from "./env";
import { isFirebaseStudio, detectAIAgent } from "./env";
import * as experiments from "./experiments";
import { showDeprecationWarningBefore, showDeprecationWarningAfter } from "./extensions/warnings";

Expand Down Expand Up @@ -314,7 +314,8 @@ export class Command {
if (
!process.stdin.isTTY ||
getInheritedOption(options, "nonInteractive") ||
getInheritedOption(options, "json") // --json implies --non-interactive.
getInheritedOption(options, "json") || // --json implies --non-interactive.
detectAIAgent() !== "unknown"
) {
options.nonInteractive = true;
}
Expand All @@ -324,6 +325,12 @@ export class Command {
options.nonInteractive = false;
}

if (options.nonInteractive) {
process.env.NON_INTERACTIVE = "true";
} else {
delete process.env.NON_INTERACTIVE;
}

if (getInheritedOption(options, "debug")) {
options.debug = true;
}
Expand Down
19 changes: 10 additions & 9 deletions src/dataconnect/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,16 +249,17 @@ export function toDatasource(
ds: DatasourceYaml,
): Datasource {
if (ds?.postgresql) {
return {
postgresql: {
database: ds.postgresql.database,
schema: ds.postgresql.schema,
cloudSql: {
instance: `projects/${projectId}/locations/${locationId}/instances/${ds.postgresql.cloudSql.instanceId}`,
},
schemaValidation: ds.postgresql.schemaValidation,
},
const postgresql: PostgreSql = {
database: ds.postgresql.database,
schema: ds.postgresql.schema,
schemaValidation: ds.postgresql.schemaValidation,
};
if (ds.postgresql.cloudSql) {
postgresql.cloudSql = {
instance: `projects/${projectId}/locations/${locationId}/instances/${ds.postgresql.cloudSql.instanceId}`,
};
}
return { postgresql };
}
if (ds?.httpGraphql) {
return {
Expand Down
26 changes: 26 additions & 0 deletions src/prompt.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,21 @@ import { FirebaseError } from "./error";
import * as prompt from "./prompt";

describe("prompt", () => {
let originalNonInteractiveEnv: string | undefined;

beforeEach(() => {
originalNonInteractiveEnv = process.env.NON_INTERACTIVE;
delete process.env.NON_INTERACTIVE;
});

afterEach(() => {
if (typeof originalNonInteractiveEnv !== "undefined") {
process.env.NON_INTERACTIVE = originalNonInteractiveEnv;
} else {
delete process.env.NON_INTERACTIVE;
}
});

describe("guard", () => {
it("returns default in non-interactive if present", () => {
const { shouldReturn, value } = prompt.guard({
Expand All @@ -25,6 +40,17 @@ describe("prompt", () => {
expect(value).to.be.undefined;
});

it("returns default if process.env.NON_INTERACTIVE is true", () => {
process.env.NON_INTERACTIVE = "true";
const { shouldReturn, value } = prompt.guard({
message: "message",
nonInteractive: false,
default: 42,
});
expect(shouldReturn).to.be.true;
expect(value).to.equal(42);
});

it("throws if non-interactive without default", () => {
expect(() =>
prompt.guard({
Expand Down
2 changes: 1 addition & 1 deletion src/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export interface BasicOptions<T> {
export function guard<T>(
opts: BasicOptions<T>,
): { shouldReturn: true; value: T } | { shouldReturn: false; value: undefined } {
if (!opts.nonInteractive) {
if (!opts.nonInteractive && process.env.NON_INTERACTIVE !== "true") {
return { shouldReturn: false, value: undefined };
}
if (typeof opts.default !== "undefined") {
Expand Down
Loading