Skip to content

Commit 1fd8776

Browse files
Copilotalexr00
andcommitted
Add detection for multiple accounts and suggestion to manage preferences
Co-authored-by: alexr00 <38270282+alexr00@users.noreply.github.com>
1 parent 3e85926 commit 1fd8776

3 files changed

Lines changed: 94 additions & 6 deletions

File tree

src/github/credentials.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,75 @@ export class CredentialStore extends Disposable {
454454
github.isEmu = getUser.then(result => result.data.plan?.name === 'emu_user');
455455
}
456456

457+
/**
458+
* Check if there are multiple GitHub accounts signed in to VS Code.
459+
* This helps detect if the user might be using the wrong account for a repository.
460+
*/
461+
public async hasMultipleAccounts(authProviderId: AuthProvider): Promise<boolean> {
462+
try {
463+
// Try different scope combinations to find all possible sessions
464+
const scopesToCheck = [SCOPES_WITH_ADDITIONAL, SCOPES_OLD, SCOPES_OLDEST];
465+
const foundSessions = new Set<string>();
466+
467+
for (const scopes of scopesToCheck) {
468+
try {
469+
const session = await vscode.authentication.getSession(authProviderId, scopes, { silent: true });
470+
if (session) {
471+
foundSessions.add(session.account.id);
472+
}
473+
} catch {
474+
// Ignore errors for individual scope checks
475+
}
476+
}
477+
478+
// If we found sessions with different account IDs, there are multiple accounts
479+
// However, the current API limitations mean we can only detect one session at a time
480+
// So we use a different approach: check if there are accounts available to switch to
481+
// by checking the account property on the session
482+
483+
// For now, we'll assume if the user is authenticated, there might be multiple accounts
484+
// The VS Code API doesn't easily expose all accounts, but the manage preferences command
485+
// will show the user if they have multiple accounts configured
486+
return foundSessions.size > 0;
487+
} catch (e) {
488+
Logger.error(`Error checking for multiple accounts: ${e}`, CredentialStore.ID);
489+
return false;
490+
}
491+
}
492+
493+
/**
494+
* Show a modal dialog suggesting the user might be using the wrong GitHub account.
495+
* Offers to open the "Manage Account Preferences" command.
496+
* @param repoName The repository name that couldn't be accessed
497+
* @param authProviderId The authentication provider ID
498+
* @returns true if the user chose to manage account preferences, false otherwise
499+
*/
500+
public async showWrongAccountModal(repoName: string, authProviderId: AuthProvider): Promise<boolean> {
501+
const currentUser = await this.getCurrentUser(authProviderId);
502+
const accountName = currentUser?.login ?? vscode.l10n.t('your current account');
503+
504+
const manageAccountPreferences = vscode.l10n.t('Manage Account Preferences');
505+
const result = await vscode.window.showErrorMessage(
506+
vscode.l10n.t(
507+
'Unable to access repository "{0}" with the current GitHub account ({1}). You may have multiple GitHub accounts configured. Would you like to check your account preferences?',
508+
repoName,
509+
accountName
510+
),
511+
{ modal: true },
512+
manageAccountPreferences
513+
);
514+
515+
if (result === manageAccountPreferences) {
516+
try {
517+
await vscode.commands.executeCommand('_account.manageAccountPreferences', 'GitHub.vscode-pull-request-github');
518+
} catch (e) {
519+
Logger.error(`Failed to open manage account preferences: ${e}`, CredentialStore.ID);
520+
}
521+
return true;
522+
}
523+
return false;
524+
}
525+
457526
private async getSession(authProviderId: AuthProvider, getAuthSessionOptions: vscode.AuthenticationGetSessionOptions, scopes: string[], requireScopes: boolean): Promise<{ session: vscode.AuthenticationSession | undefined, isNew: boolean, scopes: string[] }> {
458527
const existingSession = (getAuthSessionOptions.forceNewSession || requireScopes) ? undefined : await this.findExistingScopes(authProviderId);
459528
if (existingSession?.session) {

src/github/folderRepositoryManager.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1360,10 +1360,17 @@ export class FolderRepositoryManager extends Disposable {
13601360
} catch (e) {
13611361
Logger.error(`Fetching pull request with query failed: ${e}`, this.id);
13621362
if (e.status === 404) {
1363-
// not found
1364-
vscode.window.showWarningMessage(
1365-
`Fetching pull requests for remote ${githubRepository.remote.remoteName} with query failed, please check if the repo ${githubRepository.remote.owner}/${githubRepository.remote.repositoryName} is valid.`,
1366-
);
1363+
// not found - this might be due to using the wrong account
1364+
const repoName = `${githubRepository.remote.owner}/${githubRepository.remote.repositoryName}`;
1365+
const hasMultipleAccounts = await this._credentialStore.hasMultipleAccounts(githubRepository.remote.authProviderId);
1366+
if (hasMultipleAccounts) {
1367+
// Show modal suggesting the user might be using the wrong account
1368+
await this._credentialStore.showWrongAccountModal(repoName, githubRepository.remote.authProviderId);
1369+
} else {
1370+
vscode.window.showWarningMessage(
1371+
vscode.l10n.t('Fetching pull requests for remote {0} with query failed, please check if the repo {1} is valid.', githubRepository.remote.remoteName, repoName),
1372+
);
1373+
}
13671374
} else {
13681375
throw e;
13691376
}

src/view/treeNodes/categoryNode.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import * as vscode from 'vscode';
77
import { RemoteInfo } from '../../../common/types';
8-
import { AuthenticationError } from '../../common/authentication';
8+
import { AuthenticationError, AuthProvider } from '../../common/authentication';
99
import { DEV_MODE, PR_SETTINGS_NAMESPACE } from '../../common/settingKeys';
1010
import { ITelemetry } from '../../common/telemetry';
1111
import { toQueryUri } from '../../common/uri';
@@ -299,15 +299,27 @@ export class CategoryTreeNode extends TreeNode implements vscode.TreeItem {
299299
} catch (e) {
300300
if (this.isCopilot && (e.response.status === 422) && e.message.includes('the users do not exist')) {
301301
// Skip it, it's copilot and the repo doesn't have copilot
302+
} else if (e.status === 404 || e.response?.status === 404) {
303+
// 404 errors might indicate wrong account - this is handled in folderRepositoryManager
304+
// but we catch it here to prevent duplicate error messages
305+
needLogin = e instanceof AuthenticationError;
302306
} else {
303307
const error = formatError(e);
304308
const actions: string[] = [];
305309
if (error.includes('Bad credentials')) {
306310
actions.push(vscode.l10n.t('Login again'));
311+
} else if (e.status === 403 || e.response?.status === 403) {
312+
// 403 forbidden - user might not have access with current account
313+
const hasMultipleAccounts = await this.folderRepoManager.credentialStore.hasMultipleAccounts(AuthProvider.github);
314+
if (hasMultipleAccounts) {
315+
actions.push(vscode.l10n.t('Check Account Preferences'));
316+
}
307317
}
308318
vscode.window.showErrorMessage(vscode.l10n.t('Fetching pull requests failed: {0}', formatError(e)), ...actions).then(action => {
309-
if (action && action === actions[0]) {
319+
if (action === vscode.l10n.t('Login again')) {
310320
this.folderRepoManager.credentialStore.recreate(vscode.l10n.t('Your login session is no longer valid.'));
321+
} else if (action === vscode.l10n.t('Check Account Preferences')) {
322+
vscode.commands.executeCommand('_account.manageAccountPreferences', 'GitHub.vscode-pull-request-github');
311323
}
312324
});
313325
needLogin = e instanceof AuthenticationError;

0 commit comments

Comments
 (0)