Skip to content
Snippets Groups Projects
Commit 65917164 authored by Tomas Vik's avatar Tomas Vik :m:
Browse files

feat: show all accounts in VS Code accounts view

parent 66b6410b
No related branches found
No related tags found
1 merge request!2357feat: show all accounts in VS Code accounts view
import { createOAuthAccount } from '../../test_utils/entities';
import { createOAuthAccount, createTokenAccount } from '../../test_utils/entities';
import { AccountService } from '../account_service';
import { createExtensionContext } from '../../../common/test_utils/entities';
import { GitLabAuthenticationProvider } from './gitlab_authentication_provider';
jest.mock('../../commands/openers');
jest.mock('../../gitlab/gitlab_service');
jest.useFakeTimers();
describe('GitLabAuthenticationProvider', () => {
let accountService: AccountService;
const oauthAccount = createOAuthAccount('https://test.com', 1, 'oauth-1');
const patAccount = createTokenAccount('https://test.com', 2, 'pat-1');
beforeEach(async () => {
accountService = new AccountService();
......@@ -17,13 +15,62 @@ describe('GitLabAuthenticationProvider', () => {
describe('getting existing session', () => {
it('gets a session if there is existing oauth account', async () => {
await accountService.addAccount(createOAuthAccount());
await accountService.addAccount(oauthAccount);
await accountService.addAccount(patAccount);
const provider = new GitLabAuthenticationProvider(accountService);
const [oauthSession, patSession] = await provider.getSessions(['api']);
expect(oauthSession.accessToken).toBe(oauthAccount.token);
expect(oauthSession.account.id).toBe(oauthAccount.id);
expect(oauthSession.account.label).toBe('user1 - https://test.com');
expect(patSession.accessToken).toBe(patAccount.token);
});
});
describe('notifying of changes', () => {
it('notifies about added accounts', async () => {
const listener = jest.fn();
const provider = new GitLabAuthenticationProvider(accountService);
provider.onDidChangeSessions(listener);
const sessions = await provider.getSessions(['api']);
await accountService.addAccount(oauthAccount);
expect(sessions).toHaveLength(1);
expect(sessions[0].accessToken).toBe(createOAuthAccount().token);
expect(listener).toHaveBeenCalledWith({
added: [expect.objectContaining({ accessToken: oauthAccount.token })],
removed: [],
});
});
it('notifies about removed accounts', async () => {
const listener = jest.fn();
const provider = new GitLabAuthenticationProvider(accountService);
await accountService.addAccount(oauthAccount);
provider.onDidChangeSessions(listener);
await accountService.removeAccount(oauthAccount.id);
expect(listener).toHaveBeenCalledWith({
removed: [expect.objectContaining({ accessToken: oauthAccount.token })],
added: [],
});
});
});
it('createSession throws an error', async () => {
const provider = new GitLabAuthenticationProvider(accountService);
await expect(provider.createSession()).rejects.toThrow(
/Creating `gitlab.com` sessions .* is not supported/,
);
});
it('removeSession deletes account', async () => {
await accountService.addAccount(oauthAccount);
const provider = new GitLabAuthenticationProvider(accountService);
await provider.removeSession(oauthAccount.id);
expect(accountService.getAllAccounts()).toHaveLength(0);
});
});
import vscode from 'vscode';
import { differenceBy } from 'lodash';
import { accountService, AccountService } from '../account_service';
import { OAuthAccount } from '../../../common/platform/gitlab_account';
import { sort } from '../../utils/sort';
import { Account } from '../../../common/platform/gitlab_account';
const scopesString = (scopes: readonly string[]) => sort(scopes).join();
const convertAccountToAuthenticationSession = (
account: OAuthAccount,
): vscode.AuthenticationSession => ({
const convertAccountToSession = (account: Account): vscode.AuthenticationSession => ({
accessToken: account.token,
id: account.id,
scopes: account.scopes,
scopes: ['api'],
account: {
id: account.id,
label: `${account.instanceUrl} (${account.username})`,
label: `${account.username} - ${account.instanceUrl}`,
},
});
const makeDiff = (prev: Account[], next: Account[]) => {
const added = differenceBy(next, prev, a => a.id).map(convertAccountToSession);
const removed = differenceBy(prev, next, a => a.id).map(convertAccountToSession);
return { added, removed, changed: undefined };
};
export class GitLabAuthenticationProvider implements vscode.AuthenticationProvider {
#eventEmitter =
new vscode.EventEmitter<vscode.AuthenticationProviderAuthenticationSessionsChangeEvent>();
#accountService: AccountService;
#prevAccounts: Account[];
constructor(as = accountService) {
this.#accountService = as;
this.#accountService.onDidChange(() => {
this.#eventEmitter.fire(makeDiff(this.#prevAccounts, this.#accountService.getAllAccounts()));
this.#prevAccounts = this.#accountService.getAllAccounts();
});
this.#prevAccounts = this.#accountService.getAllAccounts();
}
onDidChangeSessions = this.#eventEmitter.event;
async getSessions(scopes?: readonly string[]): Promise<readonly vscode.AuthenticationSession[]> {
return this.#accountService
.getAllAccounts()
.filter((a): a is OAuthAccount => a.type === 'oauth')
.filter(a => !scopes || scopesString(a.scopes) === scopesString(scopes))
.map(convertAccountToAuthenticationSession);
if (scopes && !scopes.includes('api')) return [];
return this.#accountService.getAllAccounts().map(convertAccountToSession);
}
async createSession(/* scopes: readonly string[] */): Promise<vscode.AuthenticationSession> {
// This would show to 3rd party extensions depending on our Auth provider.
throw new Error(
'Creating `gitlab.com` sessions is no longer supported. It will be implemented again and better in https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/issues/1381',
'Creating `gitlab.com` sessions from other extensions is not supported. Please create an issue if you are a 3rd party extension author and you would like to reuse GitLab account from the GitLab extension.',
);
}
......@@ -48,5 +54,3 @@ export class GitLabAuthenticationProvider implements vscode.AuthenticationProvid
await this.#accountService.removeAccount(sessionId);
}
}
export const gitlabAuthenticationProvider = new GitLabAuthenticationProvider();
......@@ -338,7 +338,7 @@ export const activate = async (context: vscode.ExtensionContext) => {
vscode.window.registerFileDecorationProvider(changeTypeDecorationProvider);
vscode.authentication.registerAuthenticationProvider(
'gitlab',
'GitLab.com Authentication',
'GitLab',
new GitLabAuthenticationProvider(),
);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment