Skip to content

Commit

Permalink
Moves integration auth service and removes from GitHub git provider
Browse files Browse the repository at this point in the history
  • Loading branch information
axosoft-ramint committed Jan 23, 2025
1 parent f332ba7 commit 58991fd
Show file tree
Hide file tree
Showing 13 changed files with 221 additions and 241 deletions.
15 changes: 4 additions & 11 deletions src/container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { ServerConnection } from './plus/gk/serverConnection';
import { SubscriptionService } from './plus/gk/subscriptionService';
import { GraphStatusBarController } from './plus/graph/statusbar';
import type { CloudIntegrationService } from './plus/integrations/authentication/cloudIntegrationService';
import { IntegrationAuthenticationService } from './plus/integrations/authentication/integrationAuthentication';
import { IntegrationAuthenticationService } from './plus/integrations/authentication/integrationAuthenticationService';
import { IntegrationService } from './plus/integrations/integrationService';
import type { GitHubApi } from './plus/integrations/providers/github/github';
import type { GitLabApi } from './plus/integrations/providers/gitlab/gitlab';
Expand Down Expand Up @@ -297,7 +297,7 @@ export class Container {

@log()
private async registerGitProviders() {
const providers = await getSupportedGitProviders(this, this.authenticationService);
const providers = await getSupportedGitProviders(this);
for (const provider of providers) {
this._disposables.push(this._git.register(provider.descriptor.id, provider));
}
Expand Down Expand Up @@ -530,18 +530,11 @@ export class Container {
return this._context.extension.id;
}

private _authenticationService: IntegrationAuthenticationService | undefined;
private get authenticationService() {
if (this._authenticationService == null) {
this._disposables.push((this._authenticationService = new IntegrationAuthenticationService(this)));
}
return this._authenticationService;
}

private _integrations: IntegrationService | undefined;
get integrations(): IntegrationService {
if (this._integrations == null) {
this._disposables.push((this._integrations = new IntegrationService(this, this.authenticationService)));
const authService = new IntegrationAuthenticationService(this);
this._disposables.push(authService, (this._integrations = new IntegrationService(this, authService)));
}
return this._integrations;
}
Expand Down
8 changes: 2 additions & 6 deletions src/env/browser/providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type { GitCommandOptions } from '../../git/commandOptions';
// Force import of GitHub since dynamic imports are not supported in the WebWorker ExtensionHost
// eslint-disable-next-line @typescript-eslint/consistent-type-imports
import { GitProvider } from '../../git/gitProvider';
import type { IntegrationAuthenticationService } from '../../plus/integrations/authentication/integrationAuthentication';
import { GitHubGitProvider } from '../../plus/integrations/providers/github/githubGitProvider';
import { RepositoryWebPathMappingProvider } from './pathMapping/repositoryWebPathMappingProvider';
import { WorkspacesWebPathMappingProvider } from './pathMapping/workspacesWebPathMappingProvider';
Expand All @@ -22,11 +21,8 @@ export function gitLogStreamTo(
return Promise.resolve([[''], 0]);
}

export function getSupportedGitProviders(
container: Container,
authenticationService: IntegrationAuthenticationService,
): Promise<GitProvider[]> {
return Promise.resolve([new GitHubGitProvider(container, authenticationService)]);
export function getSupportedGitProviders(container: Container): Promise<GitProvider[]> {
return Promise.resolve([new GitHubGitProvider(container)]);
}

export function getSupportedRepositoryPathMappingProvider(container: Container) {
Expand Down
8 changes: 2 additions & 6 deletions src/env/node/providers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { Container } from '../../container';
import type { GitCommandOptions } from '../../git/commandOptions';
import type { GitProvider } from '../../git/gitProvider';
import type { IntegrationAuthenticationService } from '../../plus/integrations/authentication/integrationAuthentication';
import { configuration } from '../../system/-webview/configuration';
// import { GitHubGitProvider } from '../../plus/github/githubGitProvider';
import { Git } from './git/git';
Expand Down Expand Up @@ -32,10 +31,7 @@ export function gitLogStreamTo(
return ensureGit().logStreamTo(repoPath, sha, limit, options, ...args);
}

export async function getSupportedGitProviders(
container: Container,
authenticationService: IntegrationAuthenticationService,
): Promise<GitProvider[]> {
export async function getSupportedGitProviders(container: Container): Promise<GitProvider[]> {
const git = ensureGit();

const providers: GitProvider[] = [
Expand All @@ -49,7 +45,7 @@ export async function getSupportedGitProviders(
await import(
/* webpackChunkName: "integrations" */ '../../plus/integrations/providers/github/githubGitProvider'
)
).GitHubGitProvider(container, authenticationService),
).GitHubGitProvider(container),
);
}

Expand Down
6 changes: 2 additions & 4 deletions src/plus/integrations/authentication/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,12 @@ import { wrapForForcedInsecureSSL } from '@env/fetch';
import { HostingIntegrationId, SelfHostedIntegrationId } from '../../../constants.integrations';
import type { Sources } from '../../../constants.telemetry';
import type { Container } from '../../../container';
import type {
IntegrationAuthenticationService,
IntegrationAuthenticationSessionDescriptor,
} from './integrationAuthentication';
import type { IntegrationAuthenticationSessionDescriptor } from './integrationAuthentication';
import {
CloudIntegrationAuthenticationProvider,
LocalIntegrationAuthenticationProvider,
} from './integrationAuthentication';
import type { IntegrationAuthenticationService } from './integrationAuthenticationService';
import type { ProviderAuthenticationSession } from './models';

export class GitHubAuthenticationProvider extends CloudIntegrationAuthenticationProvider<HostingIntegrationId.GitHub> {
Expand Down
6 changes: 2 additions & 4 deletions src/plus/integrations/authentication/gitlab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@ import type { Disposable, QuickInputButton } from 'vscode';
import { env, ThemeIcon, Uri, window } from 'vscode';
import { HostingIntegrationId, SelfHostedIntegrationId } from '../../../constants.integrations';
import type { Container } from '../../../container';
import type {
IntegrationAuthenticationService,
IntegrationAuthenticationSessionDescriptor,
} from './integrationAuthentication';
import type { IntegrationAuthenticationSessionDescriptor } from './integrationAuthentication';
import {
CloudIntegrationAuthenticationProvider,
LocalIntegrationAuthenticationProvider,
} from './integrationAuthentication';
import type { IntegrationAuthenticationService } from './integrationAuthenticationService';
import type { ProviderAuthenticationSession } from './models';

type GitLabId = HostingIntegrationId.GitLab | SelfHostedIntegrationId.GitLabSelfHosted;
Expand Down
183 changes: 7 additions & 176 deletions src/plus/integrations/authentication/integrationAuthentication.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,16 @@
import type { CancellationToken, Disposable, Event, Uri } from 'vscode';
import { authentication, EventEmitter, window } from 'vscode';
import type { IntegrationId } from '../../../constants.integrations';
import { HostingIntegrationId, IssueIntegrationId, SelfHostedIntegrationId } from '../../../constants.integrations';
import type { IntegrationAuthenticationKeys, StoredConfiguredIntegrationDescriptor } from '../../../constants.storage';
import { HostingIntegrationId } from '../../../constants.integrations';
import type { IntegrationAuthenticationKeys } from '../../../constants.storage';
import type { Sources } from '../../../constants.telemetry';
import type { Container } from '../../../container';
import { gate } from '../../../system/decorators/-webview/gate';
import { debug, log } from '../../../system/decorators/log';
import { debug } from '../../../system/decorators/log';
import type { DeferredEventExecutor } from '../../../system/event';
import { getBuiltInIntegrationSession } from '../../gk/utils/-webview/integrationAuthentication.utils';
import {
isCloudSelfHostedIntegrationId,
isSelfHostedIntegrationId,
supportedIntegrationIds,
} from '../providers/models';
import type { ConfiguredIntegrationDescriptor, ProviderAuthenticationSession } from './models';
import { isCloudSelfHostedIntegrationId, isSelfHostedIntegrationId } from '../providers/models';
import type { IntegrationAuthenticationService } from './integrationAuthenticationService';
import type { ProviderAuthenticationSession } from './models';
import { isSupportedCloudIntegrationId } from './models';

const maxSmallIntegerV8 = 2 ** 30 - 1; // Max number that can be stored in V8's smis (small integers)
Expand Down Expand Up @@ -458,7 +454,7 @@ export abstract class CloudIntegrationAuthenticationProvider<
}
}

class BuiltInAuthenticationProvider extends LocalIntegrationAuthenticationProvider {
export class BuiltInAuthenticationProvider extends LocalIntegrationAuthenticationProvider {
constructor(
container: Container,
authenticationService: IntegrationAuthenticationService,
Expand Down Expand Up @@ -495,171 +491,6 @@ class BuiltInAuthenticationProvider extends LocalIntegrationAuthenticationProvid
}
}

export class IntegrationAuthenticationService implements Disposable {
private readonly providers = new Map<IntegrationId, IntegrationAuthenticationProvider>();
private _configured?: Map<IntegrationId, ConfiguredIntegrationDescriptor[]>;

constructor(private readonly container: Container) {}

dispose() {
this.providers.forEach(p => void p.dispose());
this.providers.clear();
}

get configured(): Map<IntegrationId, ConfiguredIntegrationDescriptor[]> {
if (this._configured == null) {
this._configured = new Map();
const storedConfigured = this.container.storage.get('integrations:configured');
for (const [id, configured] of Object.entries(storedConfigured ?? {})) {
if (configured == null) continue;
const descriptors = configured.map(d => ({
...d,
expiresAt: d.expiresAt ? new Date(d.expiresAt) : undefined,
}));
this._configured.set(id as IntegrationId, descriptors);
}
}

return this._configured;
}

private async storeConfigured() {
// We need to convert the map to a record to store
const configured: Record<string, StoredConfiguredIntegrationDescriptor[]> = {};
for (const [id, descriptors] of this.configured) {
configured[id] = descriptors.map(d => ({
...d,
expiresAt: d.expiresAt
? d.expiresAt instanceof Date
? d.expiresAt.toISOString()
: d.expiresAt
: undefined,
}));
}

await this.container.storage.store('integrations:configured', configured);
}

async addConfigured(descriptor: ConfiguredIntegrationDescriptor) {
const descriptors = this.configured.get(descriptor.integrationId) ?? [];
// Only add if one does not exist
if (descriptors.some(d => d.domain === descriptor.domain && d.integrationId === descriptor.integrationId)) {
return;
}
descriptors.push(descriptor);
this.configured.set(descriptor.integrationId, descriptors);
await this.storeConfigured();
}

async removeConfigured(descriptor: Pick<ConfiguredIntegrationDescriptor, 'integrationId' | 'domain'>) {
const descriptors = this.configured.get(descriptor.integrationId);
if (descriptors == null) return;
const index = descriptors.findIndex(
d => d.domain === descriptor.domain && d.integrationId === descriptor.integrationId,
);
if (index === -1) return;

descriptors.splice(index, 1);
this.configured.set(descriptor.integrationId, descriptors);

await this.storeConfigured();
}

async get(providerId: IntegrationId): Promise<IntegrationAuthenticationProvider> {
return this.ensureProvider(providerId);
}

@log()
async reset() {
// TODO: This really isn't ideal, since it will only work for "cloud" providers as we won't have any more specific descriptors
await Promise.allSettled(
supportedIntegrationIds.map(async providerId => (await this.ensureProvider(providerId)).deleteSession()),
);
}

supports(providerId: string): boolean {
switch (providerId) {
case HostingIntegrationId.AzureDevOps:
case HostingIntegrationId.Bitbucket:
case SelfHostedIntegrationId.GitHubEnterprise:
case HostingIntegrationId.GitLab:
case SelfHostedIntegrationId.GitLabSelfHosted:
case IssueIntegrationId.Jira:
return true;
case HostingIntegrationId.GitHub:
return isSupportedCloudIntegrationId(HostingIntegrationId.GitHub);
default:
return false;
}
}

@gate()
private async ensureProvider(providerId: IntegrationId): Promise<IntegrationAuthenticationProvider> {
let provider = this.providers.get(providerId);
if (provider == null) {
switch (providerId) {
case HostingIntegrationId.AzureDevOps:
provider = new (
await import(/* webpackChunkName: "integrations" */ './azureDevOps')
).AzureDevOpsAuthenticationProvider(this.container, this);
break;
case HostingIntegrationId.Bitbucket:
provider = new (
await import(/* webpackChunkName: "integrations" */ './bitbucket')
).BitbucketAuthenticationProvider(this.container, this);
break;
case HostingIntegrationId.GitHub:
provider = isSupportedCloudIntegrationId(HostingIntegrationId.GitHub)
? new (
await import(/* webpackChunkName: "integrations" */ './github')
).GitHubAuthenticationProvider(this.container, this)
: new BuiltInAuthenticationProvider(this.container, this, providerId);

break;
case SelfHostedIntegrationId.CloudGitHubEnterprise:
provider = new (
await import(/* webpackChunkName: "integrations" */ './github')
).GitHubEnterpriseCloudAuthenticationProvider(this.container, this);
break;
case SelfHostedIntegrationId.GitHubEnterprise:
provider = new (
await import(/* webpackChunkName: "integrations" */ './github')
).GitHubEnterpriseAuthenticationProvider(this.container, this);
break;
case HostingIntegrationId.GitLab:
provider = isSupportedCloudIntegrationId(HostingIntegrationId.GitLab)
? new (
await import(/* webpackChunkName: "integrations" */ './gitlab')
).GitLabCloudAuthenticationProvider(this.container, this)
: new (
await import(/* webpackChunkName: "integrations" */ './gitlab')
).GitLabLocalAuthenticationProvider(this.container, this, HostingIntegrationId.GitLab);
break;
case SelfHostedIntegrationId.CloudGitLabSelfHosted:
provider = new (
await import(/* webpackChunkName: "integrations" */ './gitlab')
).GitLabSelfHostedCloudAuthenticationProvider(this.container, this);
break;
case SelfHostedIntegrationId.GitLabSelfHosted:
provider = new (
await import(/* webpackChunkName: "integrations" */ './gitlab')
).GitLabLocalAuthenticationProvider(this.container, this, SelfHostedIntegrationId.GitLabSelfHosted);
break;
case IssueIntegrationId.Jira:
provider = new (
await import(/* webpackChunkName: "integrations" */ './jira')
).JiraAuthenticationProvider(this.container, this);
break;
default:
provider = new BuiltInAuthenticationProvider(this.container, this, providerId);
}
this.providers.set(providerId, provider);
}

return provider;
}
}

function convertStoredSessionToSession(
storedSession: StoredSession,
cloudIfMissing: boolean,
Expand Down
Loading

0 comments on commit 58991fd

Please sign in to comment.