feat: support switching to a known user#8046
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds a new Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes 🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
📝 Coding Plan
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
tests/unit/commands/switch/switch.test.ts (1)
60-68: Strengthen fallback-path assertion.This test checks log/prompt behavior, but it should also assert that the selected account was persisted (
userIdset touser-2) to fully validate the fallback flow.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/unit/commands/switch/switch.test.ts` around lines 60 - 68, The test should also assert the fallback flow persisted the chosen account: after calling switchCommand (using createCommand, mockPrompt and logMessages), add an expectation that the persisted userId equals 'user-2' (use the same test-accessible persistence accessor used elsewhere in tests — e.g., the returned command/config/store from createCommand or the mock persistence helper) to confirm the selected account was saved.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/commands/switch/switch.ts`:
- Around line 18-27: The current options.email handling auto-switches on the
first substring match and can choose the wrong account when multiple entries
match; modify the logic around matchedAccount (found from
Object.entries(availableUsersChoices)) to detect if more than one entry matches
options.email and, in that case, do not auto-switch: instead present an
ambiguity error or prompt the user to pick (or list the matching labels),
otherwise continue to set the userId via command.netlify.globalConfig.set using
the single unambiguous match; ensure you reference options.email,
availableUsersChoices, matchedAccount, and command.netlify.globalConfig.set when
updating this behavior.
In `@tests/unit/commands/switch/switch.test.ts`:
- Line 53: The tests call switchCommand with a mocked command object typed as
any, violating the no-unsafe-argument rule; update the mock to satisfy the
switchCommand signature by replacing `command as any` with a properly typed mock
of BaseCommand (either construct a mock object that implements BaseCommand or
cast a typed mock variable to BaseCommand), ensuring methods/properties used by
switchCommand (e.g., any invoked methods or properties on the mock) are present;
apply this change to all switchCommand calls in the test so linting passes
without using `any`.
---
Nitpick comments:
In `@tests/unit/commands/switch/switch.test.ts`:
- Around line 60-68: The test should also assert the fallback flow persisted the
chosen account: after calling switchCommand (using createCommand, mockPrompt and
logMessages), add an expectation that the persisted userId equals 'user-2' (use
the same test-accessible persistence accessor used elsewhere in tests — e.g.,
the returned command/config/store from createCommand or the mock persistence
helper) to confirm the selected account was saved.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a9c4e2a1-9540-4d10-9740-263946083b66
📒 Files selected for processing (3)
src/commands/switch/index.tssrc/commands/switch/switch.tstests/unit/commands/switch/switch.test.ts
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
tests/unit/commands/switch/switch.test.ts (1)
60-68: Assert the fallback path actually updatesuserId.This test confirms prompt invocation, but it doesn’t validate the final state change after selection. Add an assertion for
globalConfig.set('userId', ...)so the fallback flow is fully covered.Suggested test tightening
- test('--email falls through to prompt when no match is found', async () => { - const { command } = createCommand() + test('--email falls through to prompt when no match is found', async () => { + const { command, mockSet } = createCommand() mockPrompt.mockResolvedValueOnce({ accountSwitchChoice: 'Bob (bob@corp.com)' }) await switchCommand({ email: 'nobody@example.com' }, command) expect(logMessages.some((m) => m.includes('No account found matching'))).toBe(true) expect(mockPrompt).toHaveBeenCalled() + expect(mockSet).toHaveBeenCalledWith('userId', 'user-2') })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/unit/commands/switch/switch.test.ts` around lines 60 - 68, The test for the fallback prompt path should also assert that the selected account actually updates globalConfig; after calling switchCommand({ email: 'nobody@example.com' }, command) and mocking the prompt (mockPrompt.mockResolvedValueOnce({ accountSwitchChoice: 'Bob (bob@corp.com)' })), add an expectation that globalConfig.set was called to update 'userId' to the selected account's id (e.g., expect(globalConfig.set).toHaveBeenCalledWith('userId', expectedUserId)); locate this in the same test that references switchCommand, mockPrompt and logMessages and derive expectedUserId from the test fixtures or the mapping used by the code under test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/commands/switch.md`:
- Line 21: The docs claim `email` but don't state matching semantics while
src/commands/switch/switch.ts currently does substring matching with .includes
and picks the first hit; update behavior to perform exact matching instead: in
switch.ts replace the .includes check on the account email with a strict
equality comparison (===) and prefer the exact match when selecting the target
account (e.g., find(account => account.email === email)), optionally falling
back to the previous substring-first behavior only if no exact match is found;
alternatively, if you prefer to keep substring semantics, update
docs/commands/switch.md to explicitly state that `email` is matched as a
substring and the first match is selected, referencing the `email` parameter and
the matching logic in switch.ts.
In `@tests/unit/commands/switch/switch.test.ts`:
- Around line 70-77: The test " --email matches partial email strings" currently
passes a partial email ('bob@corp') to switchCommand which encourages substring
auto-selection; change the test to use a full exact email string (e.g., the
exact email used in fixtures) or change expectations to require a prompt on
ambiguity: invoke switchCommand with the exact email to assert
mockSet('userId','user-2') and mockPrompt not called, or keep the partial email
but assert that mockPrompt is called (and mockSet not called) to enforce
prompt-on-ambiguous-match behavior; update the test name accordingly and
reference switchCommand, mockSet and mockPrompt in your change.
---
Nitpick comments:
In `@tests/unit/commands/switch/switch.test.ts`:
- Around line 60-68: The test for the fallback prompt path should also assert
that the selected account actually updates globalConfig; after calling
switchCommand({ email: 'nobody@example.com' }, command) and mocking the prompt
(mockPrompt.mockResolvedValueOnce({ accountSwitchChoice: 'Bob (bob@corp.com)'
})), add an expectation that globalConfig.set was called to update 'userId' to
the selected account's id (e.g.,
expect(globalConfig.set).toHaveBeenCalledWith('userId', expectedUserId)); locate
this in the same test that references switchCommand, mockPrompt and logMessages
and derive expectedUserId from the test fixtures or the mapping used by the code
under test.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6b3f72a3-3bae-46a6-a2c9-677f782e1dcc
📒 Files selected for processing (2)
docs/commands/switch.mdtests/unit/commands/switch/switch.test.ts
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/commands/switch/switch.ts (1)
38-39:⚠️ Potential issue | 🔴 CriticalRemove the unused
@ts-expect-errordirective to fix the pipeline failure.The TypeScript compiler reports this directive is unnecessary. The
choicesarray type is now correctly inferred.Proposed fix
{ type: 'list', name: 'accountSwitchChoice', message: 'Please select the account you want to use:', - // `@ts-expect-error` TS(2769) FIXME: No overload matches this call. choices: [...Object.entries(availableUsersChoices).map(([, val]) => val), LOGIN_NEW], },🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/commands/switch/switch.ts` around lines 38 - 39, Remove the unnecessary TypeScript suppression placed above the choices assignment: delete the line containing "// `@ts-expect-error` TS(2769) FIXME: No overload matches this call." and keep the existing choices expression as-is (choices: [...Object.entries(availableUsersChoices).map(([, val]) => val), LOGIN_NEW]). This removes the unused directive and lets the compiler use the now-correctly inferred type for choices while preserving use of availableUsersChoices and LOGIN_NEW.
🧹 Nitpick comments (1)
src/commands/switch/switch.ts (1)
46-54: Consider using a type guard to avoid the@ts-expect-errordirectives.The
selectedAccountlookup could theoretically returnundefined. While unlikely in practice (since the choice comes from the same list), using a guard would satisfy TypeScript and remove the suppression comments.Proposed refactor
} else { - // `@ts-expect-error` TS(2769) FIXME: No overload matches this call. const selectedAccount = Object.entries(availableUsersChoices).find( ([, availableUsersChoice]) => availableUsersChoice === accountSwitchChoice, ) - // `@ts-expect-error` TS(2532) FIXME: Object is possibly 'undefined'. - command.netlify.globalConfig.set('userId', selectedAccount[0]) - log('') - // `@ts-expect-error` TS(2532) FIXME: Object is possibly 'undefined'. - log(`You're now using ${chalk.bold(selectedAccount[1])}.`) + if (selectedAccount) { + command.netlify.globalConfig.set('userId', selectedAccount[0]) + log('') + log(`You're now using ${chalk.bold(selectedAccount[1])}.`) + } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/commands/switch/switch.ts` around lines 46 - 54, selectedAccount (result of Object.entries(availableUsersChoices).find(...)) can be undefined, so remove the `@ts-expect-error` markers and add a type guard: check if selectedAccount is undefined before using it; if undefined, log an error and return (or throw) to avoid calling command.netlify.globalConfig.set or accessing selectedAccount[0]/[1]; otherwise proceed to set('userId', selectedAccount[0]) and log the success message with chalk.bold(selectedAccount[1]). Ensure the guard is placed immediately after computing selectedAccount so TypeScript can narrow its type for subsequent uses.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@src/commands/switch/switch.ts`:
- Around line 38-39: Remove the unnecessary TypeScript suppression placed above
the choices assignment: delete the line containing "// `@ts-expect-error` TS(2769)
FIXME: No overload matches this call." and keep the existing choices expression
as-is (choices: [...Object.entries(availableUsersChoices).map(([, val]) => val),
LOGIN_NEW]). This removes the unused directive and lets the compiler use the
now-correctly inferred type for choices while preserving use of
availableUsersChoices and LOGIN_NEW.
---
Nitpick comments:
In `@src/commands/switch/switch.ts`:
- Around line 46-54: selectedAccount (result of
Object.entries(availableUsersChoices).find(...)) can be undefined, so remove the
`@ts-expect-error` markers and add a type guard: check if selectedAccount is
undefined before using it; if undefined, log an error and return (or throw) to
avoid calling command.netlify.globalConfig.set or accessing
selectedAccount[0]/[1]; otherwise proceed to set('userId', selectedAccount[0])
and log the success message with chalk.bold(selectedAccount[1]). Ensure the
guard is placed immediately after computing selectedAccount so TypeScript can
narrow its type for subsequent uses.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 7c7cfaec-a4db-431b-9fbb-aafae9070c08
📒 Files selected for processing (2)
src/commands/switch/switch.tstests/unit/commands/switch/switch.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- tests/unit/commands/switch/switch.test.ts
🤖 I have created a release *beep* *boop* --- ## [24.4.0](v24.3.0...v24.4.0) (2026-03-20) ### Features * propagate @netlify/build version, primary framework and its version ([#8049](#8049)) ([1db6f6e](1db6f6e)) * support switching to a known user ([#8046](#8046)) ([e460e68](e460e68)) ### Bug Fixes * **deps:** bump h3 from 1.15.5 to 1.15.8 ([#8055](#8055)) ([7a1c8fa](7a1c8fa)) * **deps:** update dependency @netlify/dev to v4.16.3 ([#8053](#8053)) ([4460d87](4460d87)) * **deps:** update dependency @netlify/dev to v4.16.4 ([#8060](#8060)) ([d0491da](d0491da)) * **deps:** update dependency @netlify/dev-utils to v4.4.2 ([#8054](#8054)) ([bdb944f](bdb944f)) * **deps:** update dependency @netlify/dev-utils to v4.4.3 ([#8061](#8061)) ([78b5af9](78b5af9)) * **deps:** update dependency @netlify/edge-functions to v3.0.5 ([#8056](#8056)) ([6254a75](6254a75)) * **deps:** update dependency @netlify/edge-functions to v3.0.6 ([#8063](#8063)) ([7646545](7646545)) * **deps:** update dependency @netlify/functions to v5.1.4 ([#8057](#8057)) ([18d5ccb](18d5ccb)) * **deps:** update dependency @netlify/functions to v5.1.5 ([#8064](#8064)) ([77a9249](77a9249)) * **deps:** update dependency @netlify/images to v1.3.6 ([#8058](#8058)) ([06f564b](06f564b)) * **deps:** update dependency @netlify/images to v1.3.7 ([#8065](#8065)) ([12a3a3f](12a3a3f)) * **deps:** update dependency cookie to v1.1.1 ([#8037](#8037)) ([6e6bcf5](6e6bcf5)) * **deps:** update dependency envinfo to v7.21.0 ([#8039](#8039)) ([08b5fc5](08b5fc5)) * **deps:** update netlify packages ([#8047](#8047)) ([d57ce32](d57ce32)) * **deps:** update netlify packages ([#8062](#8062)) ([3006f8c](3006f8c)) * **deps:** update netlify packages ([#8067](#8067)) ([02632aa](02632aa)) * **deps:** upgrade deps to fix new vulnerabilities ([#8070](#8070)) ([e3655f9](e3655f9)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: token-generator-app[bot] <82042599+token-generator-app[bot]@users.noreply.github.com>
🎉 Thanks for submitting a pull request! 🎉
Summary
When using
netlify switchwe should be able to pass an email to auto select if it's in the list. This allows users to quickly go into the known accounts that they have instead of the default which is an interactive selection experience.