Skip to content

Commit 26a79fe

Browse files
feat: Add GEMINI_DEFAULT_AUTH_TYPE support (google-gemini#4002)
1 parent 4442e89 commit 26a79fe

File tree

2 files changed

+199
-25
lines changed

2 files changed

+199
-25
lines changed

packages/cli/src/ui/components/AuthDialog.test.tsx

Lines changed: 156 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ describe('AuthDialog', () => {
1818
beforeEach(() => {
1919
originalEnv = { ...process.env };
2020
process.env.GEMINI_API_KEY = '';
21+
process.env.GEMINI_DEFAULT_AUTH_TYPE = '';
2122
vi.clearAllMocks();
2223
});
2324

@@ -59,28 +60,165 @@ describe('AuthDialog', () => {
5960
);
6061
});
6162

62-
it('should detect GEMINI_API_KEY environment variable', () => {
63-
process.env.GEMINI_API_KEY = 'foobar';
63+
describe('GEMINI_API_KEY environment variable', () => {
64+
it('should detect GEMINI_API_KEY environment variable', () => {
65+
process.env.GEMINI_API_KEY = 'foobar';
6466

65-
const settings: LoadedSettings = new LoadedSettings(
66-
{
67-
settings: {
68-
selectedAuthType: undefined,
67+
const settings: LoadedSettings = new LoadedSettings(
68+
{
69+
settings: {
70+
selectedAuthType: undefined,
71+
},
72+
path: '',
6973
},
70-
path: '',
71-
},
72-
{
73-
settings: {},
74-
path: '',
75-
},
76-
[],
77-
);
74+
{
75+
settings: {},
76+
path: '',
77+
},
78+
[],
79+
);
7880

79-
const { lastFrame } = render(
80-
<AuthDialog onSelect={() => {}} settings={settings} />,
81-
);
81+
const { lastFrame } = render(
82+
<AuthDialog onSelect={() => {}} settings={settings} />,
83+
);
84+
85+
expect(lastFrame()).toContain(
86+
'Existing API key detected (GEMINI_API_KEY)',
87+
);
88+
});
89+
90+
it('should not show the GEMINI_API_KEY message if GEMINI_DEFAULT_AUTH_TYPE is set to something else', () => {
91+
process.env.GEMINI_API_KEY = 'foobar';
92+
process.env.GEMINI_DEFAULT_AUTH_TYPE = AuthType.LOGIN_WITH_GOOGLE;
93+
94+
const settings: LoadedSettings = new LoadedSettings(
95+
{
96+
settings: {
97+
selectedAuthType: undefined,
98+
},
99+
path: '',
100+
},
101+
{
102+
settings: {},
103+
path: '',
104+
},
105+
[],
106+
);
107+
108+
const { lastFrame } = render(
109+
<AuthDialog onSelect={() => {}} settings={settings} />,
110+
);
111+
112+
expect(lastFrame()).not.toContain(
113+
'Existing API key detected (GEMINI_API_KEY)',
114+
);
115+
});
116+
117+
it('should show the GEMINI_API_KEY message if GEMINI_DEFAULT_AUTH_TYPE is set to use api key', () => {
118+
process.env.GEMINI_API_KEY = 'foobar';
119+
process.env.GEMINI_DEFAULT_AUTH_TYPE = AuthType.USE_GEMINI;
120+
121+
const settings: LoadedSettings = new LoadedSettings(
122+
{
123+
settings: {
124+
selectedAuthType: undefined,
125+
},
126+
path: '',
127+
},
128+
{
129+
settings: {},
130+
path: '',
131+
},
132+
[],
133+
);
134+
135+
const { lastFrame } = render(
136+
<AuthDialog onSelect={() => {}} settings={settings} />,
137+
);
138+
139+
expect(lastFrame()).toContain(
140+
'Existing API key detected (GEMINI_API_KEY)',
141+
);
142+
});
143+
});
144+
145+
describe('GEMINI_DEFAULT_AUTH_TYPE environment variable', () => {
146+
it('should select the auth type specified by GEMINI_DEFAULT_AUTH_TYPE', () => {
147+
process.env.GEMINI_DEFAULT_AUTH_TYPE = AuthType.LOGIN_WITH_GOOGLE;
148+
149+
const settings: LoadedSettings = new LoadedSettings(
150+
{
151+
settings: {
152+
selectedAuthType: undefined,
153+
},
154+
path: '',
155+
},
156+
{
157+
settings: {},
158+
path: '',
159+
},
160+
[],
161+
);
162+
163+
const { lastFrame } = render(
164+
<AuthDialog onSelect={() => {}} settings={settings} />,
165+
);
166+
167+
// This is a bit brittle, but it's the best way to check which item is selected.
168+
expect(lastFrame()).toContain('● Login with Google');
169+
});
170+
171+
it('should fall back to default if GEMINI_DEFAULT_AUTH_TYPE is not set', () => {
172+
const settings: LoadedSettings = new LoadedSettings(
173+
{
174+
settings: {
175+
selectedAuthType: undefined,
176+
},
177+
path: '',
178+
},
179+
{
180+
settings: {},
181+
path: '',
182+
},
183+
[],
184+
);
185+
186+
const { lastFrame } = render(
187+
<AuthDialog onSelect={() => {}} settings={settings} />,
188+
);
189+
190+
// Default is LOGIN_WITH_GOOGLE
191+
expect(lastFrame()).toContain('● Login with Google');
192+
});
193+
194+
it('should show an error and fall back to default if GEMINI_DEFAULT_AUTH_TYPE is invalid', () => {
195+
process.env.GEMINI_DEFAULT_AUTH_TYPE = 'invalid-auth-type';
196+
197+
const settings: LoadedSettings = new LoadedSettings(
198+
{
199+
settings: {
200+
selectedAuthType: undefined,
201+
},
202+
path: '',
203+
},
204+
{
205+
settings: {},
206+
path: '',
207+
},
208+
[],
209+
);
210+
211+
const { lastFrame } = render(
212+
<AuthDialog onSelect={() => {}} settings={settings} />,
213+
);
214+
215+
expect(lastFrame()).toContain(
216+
'Invalid value for GEMINI_DEFAULT_AUTH_TYPE: "invalid-auth-type"',
217+
);
82218

83-
expect(lastFrame()).toContain('Existing API key detected (GEMINI_API_KEY)');
219+
// Default is LOGIN_WITH_GOOGLE
220+
expect(lastFrame()).toContain('● Login with Google');
221+
});
84222
});
85223

86224
it('should prevent exiting when no auth method is selected and show error message', async () => {

packages/cli/src/ui/components/AuthDialog.tsx

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,47 @@ interface AuthDialogProps {
1818
initialErrorMessage?: string | null;
1919
}
2020

21+
function parseDefaultAuthType(
22+
defaultAuthType: string | undefined,
23+
): AuthType | null {
24+
if (
25+
defaultAuthType &&
26+
Object.values(AuthType).includes(defaultAuthType as AuthType)
27+
) {
28+
return defaultAuthType as AuthType;
29+
}
30+
return null;
31+
}
32+
2133
export function AuthDialog({
2234
onSelect,
2335
settings,
2436
initialErrorMessage,
2537
}: AuthDialogProps): React.JSX.Element {
26-
const [errorMessage, setErrorMessage] = useState<string | null>(
27-
initialErrorMessage
28-
? initialErrorMessage
29-
: process.env.GEMINI_API_KEY
30-
? 'Existing API key detected (GEMINI_API_KEY). Select "Gemini API Key" option to use it.'
31-
: null,
32-
);
38+
const [errorMessage, setErrorMessage] = useState<string | null>(() => {
39+
if (initialErrorMessage) {
40+
return initialErrorMessage;
41+
}
42+
43+
const defaultAuthType = parseDefaultAuthType(
44+
process.env.GEMINI_DEFAULT_AUTH_TYPE,
45+
);
46+
47+
if (process.env.GEMINI_DEFAULT_AUTH_TYPE && defaultAuthType === null) {
48+
return (
49+
`Invalid value for GEMINI_DEFAULT_AUTH_TYPE: "${process.env.GEMINI_DEFAULT_AUTH_TYPE}". ` +
50+
`Valid values are: ${Object.values(AuthType).join(', ')}.`
51+
);
52+
}
53+
54+
if (
55+
process.env.GEMINI_API_KEY &&
56+
(!defaultAuthType || defaultAuthType === AuthType.USE_GEMINI)
57+
) {
58+
return 'Existing API key detected (GEMINI_API_KEY). Select "Gemini API Key" option to use it.';
59+
}
60+
return null;
61+
});
3362
const items = [
3463
{
3564
label: 'Login with Google',
@@ -55,6 +84,13 @@ export function AuthDialog({
5584
return item.value === settings.merged.selectedAuthType;
5685
}
5786

87+
const defaultAuthType = parseDefaultAuthType(
88+
process.env.GEMINI_DEFAULT_AUTH_TYPE,
89+
);
90+
if (defaultAuthType) {
91+
return item.value === defaultAuthType;
92+
}
93+
5894
if (process.env.GEMINI_API_KEY) {
5995
return item.value === AuthType.USE_GEMINI;
6096
}

0 commit comments

Comments
 (0)