diff --git a/src/github/credentials.ts b/src/github/credentials.ts index ce2f62b102..18469f845c 100644 --- a/src/github/credentials.ts +++ b/src/github/credentials.ts @@ -454,6 +454,54 @@ export class CredentialStore extends Disposable { github.isEmu = getUser.then(result => result.data.plan?.name === 'emu_user'); } + /** + * Check if the user is authenticated and might benefit from checking account preferences. + * Note: Due to VS Code API limitations, we cannot directly check if multiple accounts are available. + * This method returns true if the user is authenticated, as they may have multiple accounts + * configured in VS Code that they can switch to via the "Manage Account Preferences" command. + */ + public async isAuthenticatedForAccountPreferences(authProviderId: AuthProvider): Promise { + return this.isAuthenticated(authProviderId); + } + + /** + * Show a modal dialog suggesting the user might be using the wrong GitHub account. + * Offers to open the "Manage Account Preferences" command. + * @param repoName The repository name that couldn't be accessed + * @param authProviderId The authentication provider ID + * @returns true if the user chose to manage account preferences, false otherwise + */ + public async showWrongAccountModal(repoName: string, authProviderId: AuthProvider): Promise { + let accountName: string; + try { + const currentUser = await this.getCurrentUser(authProviderId); + accountName = currentUser?.login ?? vscode.l10n.t('your current account'); + } catch { + accountName = vscode.l10n.t('your current account'); + } + + const manageAccountPreferences = vscode.l10n.t('Manage Account Preferences'); + const result = await vscode.window.showErrorMessage( + vscode.l10n.t( + '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?', + repoName, + accountName + ), + { modal: true }, + manageAccountPreferences + ); + + if (result === manageAccountPreferences) { + try { + await vscode.commands.executeCommand('_account.manageAccountPreferences', 'GitHub.vscode-pull-request-github'); + } catch (e) { + Logger.error(`Failed to open manage account preferences: ${e}`, CredentialStore.ID); + } + return true; + } + return false; + } + private async getSession(authProviderId: AuthProvider, getAuthSessionOptions: vscode.AuthenticationGetSessionOptions, scopes: string[], requireScopes: boolean): Promise<{ session: vscode.AuthenticationSession | undefined, isNew: boolean, scopes: string[] }> { const existingSession = (getAuthSessionOptions.forceNewSession || requireScopes) ? undefined : await this.findExistingScopes(authProviderId); if (existingSession?.session) { diff --git a/src/github/folderRepositoryManager.ts b/src/github/folderRepositoryManager.ts index dac84ca592..0850bb3782 100644 --- a/src/github/folderRepositoryManager.ts +++ b/src/github/folderRepositoryManager.ts @@ -1360,10 +1360,17 @@ export class FolderRepositoryManager extends Disposable { } catch (e) { Logger.error(`Fetching pull request with query failed: ${e}`, this.id); if (e.status === 404) { - // not found - vscode.window.showWarningMessage( - `Fetching pull requests for remote ${githubRepository.remote.remoteName} with query failed, please check if the repo ${githubRepository.remote.owner}/${githubRepository.remote.repositoryName} is valid.`, - ); + // not found - this might be due to using the wrong account + const repoName = `${githubRepository.remote.owner}/${githubRepository.remote.repositoryName}`; + const isAuthenticated = await this._credentialStore.isAuthenticatedForAccountPreferences(githubRepository.remote.authProviderId); + if (isAuthenticated) { + // Show modal suggesting the user might be using the wrong account + await this._credentialStore.showWrongAccountModal(repoName, githubRepository.remote.authProviderId); + } else { + vscode.window.showWarningMessage( + vscode.l10n.t('Fetching pull requests for remote {0} with query failed, please check if the repo {1} is valid.', githubRepository.remote.remoteName, repoName), + ); + } } else { throw e; } diff --git a/src/view/treeNodes/categoryNode.ts b/src/view/treeNodes/categoryNode.ts index b7f0d2baa2..00d289f519 100644 --- a/src/view/treeNodes/categoryNode.ts +++ b/src/view/treeNodes/categoryNode.ts @@ -5,7 +5,7 @@ import * as vscode from 'vscode'; import { RemoteInfo } from '../../../common/types'; -import { AuthenticationError } from '../../common/authentication'; +import { AuthenticationError, AuthProvider } from '../../common/authentication'; import { DEV_MODE, PR_SETTINGS_NAMESPACE } from '../../common/settingKeys'; import { ITelemetry } from '../../common/telemetry'; import { toQueryUri } from '../../common/uri'; @@ -299,15 +299,29 @@ export class CategoryTreeNode extends TreeNode implements vscode.TreeItem { } catch (e) { if (this.isCopilot && (e.response.status === 422) && e.message.includes('the users do not exist')) { // Skip it, it's copilot and the repo doesn't have copilot + } else if (e.status === 404 || e.response?.status === 404) { + // 404 errors might indicate wrong account - this is handled in folderRepositoryManager + // but we catch it here to prevent duplicate error messages + needLogin = e instanceof AuthenticationError; } else { const error = formatError(e); const actions: string[] = []; if (error.includes('Bad credentials')) { actions.push(vscode.l10n.t('Login again')); + } else if (e.status === 403 || e.response?.status === 403) { + // 403 forbidden - user might not have access with current account + // Check both GitHub.com and Enterprise providers since we might have repos from either + const isAuthenticatedGitHub = await this.folderRepoManager.credentialStore.isAuthenticatedForAccountPreferences(AuthProvider.github); + const isAuthenticatedEnterprise = await this.folderRepoManager.credentialStore.isAuthenticatedForAccountPreferences(AuthProvider.githubEnterprise); + if (isAuthenticatedGitHub || isAuthenticatedEnterprise) { + actions.push(vscode.l10n.t('Check Account Preferences')); + } } vscode.window.showErrorMessage(vscode.l10n.t('Fetching pull requests failed: {0}', formatError(e)), ...actions).then(action => { - if (action && action === actions[0]) { + if (action === vscode.l10n.t('Login again')) { this.folderRepoManager.credentialStore.recreate(vscode.l10n.t('Your login session is no longer valid.')); + } else if (action === vscode.l10n.t('Check Account Preferences')) { + vscode.commands.executeCommand('_account.manageAccountPreferences', 'GitHub.vscode-pull-request-github'); } }); needLogin = e instanceof AuthenticationError;