Browse Source

Fixes #2166 avoids multiple auth prompts

main
Eric Amodio 2 years ago
parent
commit
f66b636525
4 changed files with 78 additions and 16 deletions
  1. +1
    -0
      CHANGELOG.md
  2. +6
    -2
      src/git/remotes/github.ts
  3. +66
    -14
      src/plus/github/githubGitProvider.ts
  4. +5
    -0
      src/storage.ts

+ 1
- 0
CHANGELOG.md View File

@ -51,6 +51,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
### Fixed
- Fixes [#2166](https://github.com/gitkraken/vscode-gitlens/issues/2166) - Don't always prompt for GitHub authentication on virtual repositories
- Fixes [#2156](https://github.com/gitkraken/vscode-gitlens/issues/2156) - Reduce extension package size
- Fixes [#2136](https://github.com/gitkraken/vscode-gitlens/issues/2136) - Search & Compare quickpick shouldn't select the mode text when opening
- Fixes [#1896](https://github.com/gitkraken/vscode-gitlens/issues/1896) - Cannot read property 'fsPath' of undefined

+ 6
- 2
src/git/remotes/github.ts View File

@ -22,10 +22,14 @@ const rangeRegex = /^L(\d+)(?:-L(\d+))?$/;
const authProvider = Object.freeze({ id: 'github', scopes: ['repo', 'read:user', 'user:email'] });
const enterpriseAuthProvider = Object.freeze({ id: 'github-enterprise', scopes: ['repo', 'read:user', 'user:email'] });
function isGitHubDotCom(domain: string): boolean {
return equalsIgnoreCase(domain, 'github.com');
}
export class GitHubRemote extends RichRemoteProvider {
@memoize()
protected get authProvider() {
return equalsIgnoreCase(this.domain, 'github.com') ? authProvider : enterpriseAuthProvider;
return isGitHubDotCom(this.domain) ? authProvider : enterpriseAuthProvider;
}
constructor(
@ -115,7 +119,7 @@ export class GitHubRemote extends RichRemoteProvider {
@log()
override async connect(): Promise<boolean> {
if (!equalsIgnoreCase(this.domain, 'github.com')) {
if (!isGitHubDotCom(this.domain)) {
const title =
'Connecting to a GitHub Enterprise instance for rich integration features requires a paid GitLens+ account.';

+ 66
- 14
src/plus/github/githubGitProvider.ts View File

@ -1,5 +1,13 @@
/* eslint-disable @typescript-eslint/require-await */
import type { AuthenticationSession, Disposable, Event, Range, TextDocument, WorkspaceFolder } from 'vscode';
import type {
AuthenticationSession,
AuthenticationSessionsChangeEvent,
Disposable,
Event,
Range,
TextDocument,
WorkspaceFolder,
} from 'vscode';
import { authentication, EventEmitter, FileType, Uri, window, workspace } from 'vscode';
import { encodeUtf8Hex } from '@env/hex';
import { configuration } from '../../configuration';
@ -117,12 +125,21 @@ export class GitHubGitProvider implements GitProvider, Disposable {
private readonly _disposables: Disposable[] = [];
constructor(private readonly container: Container) {}
constructor(private readonly container: Container) {
this._disposables.push(authentication.onDidChangeSessions(this.onAuthenticationSessionsChanged, this));
}
dispose() {
this._disposables.forEach(d => void d.dispose());
}
private onAuthenticationSessionsChanged(e: AuthenticationSessionsChangeEvent) {
if (e.provider.id === 'github') {
this._sessionPromise = undefined;
void this.ensureSession(false, true);
}
}
private onRepositoryChanged(repo: Repository, e: RepositoryChangeEvent) {
// if (e.changed(RepositoryChange.Config, RepositoryChangeComparisonMode.Any)) {
// this._repoInfoCache.delete(repo.path);
@ -2699,12 +2716,7 @@ export class GitHubGitProvider implements GitProvider, Disposable {
if (this._github == null) {
const github = await this.container.github;
if (github != null) {
this._disposables.push(
github.onDidReauthenticate(() => {
this._sessionPromise = undefined;
void this.ensureSession(true);
}),
);
this._disposables.push(github.onDidReauthenticate(() => void this.ensureSession(true)));
}
this._github = github;
}
@ -2737,21 +2749,61 @@ export class GitHubGitProvider implements GitProvider, Disposable {
}
private _sessionPromise: Promise<AuthenticationSession> | undefined;
private async ensureSession(force: boolean = false): Promise<AuthenticationSession> {
if (this._sessionPromise == null) {
async function getSession(): Promise<AuthenticationSession> {
private async ensureSession(force: boolean = false, silent: boolean = false): Promise<AuthenticationSession> {
if (force || this._sessionPromise == null) {
async function getSession(this: GitHubGitProvider): Promise<AuthenticationSession> {
let skip = this.container.storage.get(`provider:authentication:skip:${this.descriptor.id}`, false);
try {
if (force) {
skip = false;
void this.container.storage.delete(`provider:authentication:skip:${this.descriptor.id}`);
return await authentication.getSession('github', githubAuthenticationScopes, {
forceNewSession: true,
});
}
return await authentication.getSession('github', githubAuthenticationScopes, {
createIfNone: true,
if (!skip && !silent) {
return await authentication.getSession('github', githubAuthenticationScopes, {
createIfNone: true,
});
}
const session = await authentication.getSession('github', githubAuthenticationScopes, {
createIfNone: false,
silent: silent,
});
if (session != null) return session;
throw new Error('User did not consent');
} catch (ex) {
if (ex instanceof Error && ex.message.includes('User did not consent')) {
if (!silent) {
await this.container.storage.store(
`provider:authentication:skip:${this.descriptor.id}`,
true,
);
if (!skip) {
if (!force) {
queueMicrotask(async () => {
const enable = 'Re-enable';
const result = await window.showInformationMessage(
'GitLens has been disabled. Authentication is required for GitLens to work with remote GitHub repositories.',
enable,
);
if (result === enable) {
void this.ensureSession(true);
}
});
}
force = false;
return getSession.call(this);
}
}
throw new AuthenticationError('github', AuthenticationErrorReason.UserDidNotConsent);
}
@ -2761,7 +2813,7 @@ export class GitHubGitProvider implements GitProvider, Disposable {
}
}
this._sessionPromise = getSession();
this._sessionPromise = getSession.call(this);
}
return this._sessionPromise;

+ 5
- 0
src/storage.ts View File

@ -115,6 +115,11 @@ export const enum SyncedStorageKeys {
export interface GlobalStorage {
avatars?: [string, StoredAvatar][];
provider: {
authentication: {
skip: Record<string, boolean>;
};
};
home: {
actions: {
completed?: CompletedActions[];

Loading…
Cancel
Save