Skip to content

Commit

Permalink
Add support for GKDev Cloud GitHub Enterprise integration
Browse files Browse the repository at this point in the history
  • Loading branch information
sergeibbb committed Jan 8, 2025
1 parent 31e5067 commit 173e454
Show file tree
Hide file tree
Showing 8 changed files with 78 additions and 9 deletions.
2 changes: 2 additions & 0 deletions src/constants.integrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export enum HostingIntegrationId {

export enum SelfHostedIntegrationId {
GitHubEnterprise = 'github-enterprise',
CloudGitHubEnterprise = 'cloud-github-enterprise',
GitLabSelfHosted = 'gitlab-self-hosted',
}

Expand All @@ -19,6 +20,7 @@ export type IntegrationId = HostingIntegrationId | IssueIntegrationId | SelfHost

export const supportedOrderedCloudIssueIntegrationIds = [IssueIntegrationId.Jira];
export const supportedOrderedCloudIntegrationIds = [
SelfHostedIntegrationId.CloudGitHubEnterprise,
HostingIntegrationId.GitHub,
HostingIntegrationId.GitLab,
IssueIntegrationId.Jira,
Expand Down
10 changes: 10 additions & 0 deletions src/plus/integrations/authentication/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,16 @@ export class GitHubAuthenticationProvider extends CloudIntegrationAuthentication
}
}

export class GitHubEnterpriseCloudAuthenticationProvider extends CloudIntegrationAuthenticationProvider<SelfHostedIntegrationId.CloudGitHubEnterprise> {
protected override getCompletionInputTitle(): string {
throw new Error('Connect to GitHub Enterprise');
}

protected override get authProviderId(): SelfHostedIntegrationId.CloudGitHubEnterprise {
return SelfHostedIntegrationId.CloudGitHubEnterprise;
}
}

export class GitHubEnterpriseAuthenticationProvider extends LocalIntegrationAuthenticationProvider<SelfHostedIntegrationId.GitHubEnterprise> {
protected override get authProviderId(): SelfHostedIntegrationId.GitHubEnterprise {
return SelfHostedIntegrationId.GitHubEnterprise;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -338,7 +338,11 @@ export abstract class CloudIntegrationAuthenticationProvider<
let session = await cloudIntegrations.getConnectionSession(this.authProviderId);

// Make an exception for GitHub because they always return 0
if (session?.expiresIn === 0 && this.authProviderId === HostingIntegrationId.GitHub) {
if (
session?.expiresIn === 0 &&
(this.authProviderId === HostingIntegrationId.GitHub ||
this.authProviderId === SelfHostedIntegrationId.CloudGitHubEnterprise)
) {
// It never expires so don't refresh it frequently:
session.expiresIn = maxSmallIntegerV8; // maximum expiration length
}
Expand Down Expand Up @@ -522,6 +526,11 @@ export class IntegrationAuthenticationService implements Disposable {
).GitHubAuthenticationProvider(this.container)
: new BuiltInAuthenticationProvider(this.container, providerId);

break;
case SelfHostedIntegrationId.CloudGitHubEnterprise:
provider = new (
await import(/* webpackChunkName: "integrations" */ './github')
).GitHubEnterpriseCloudAuthenticationProvider(this.container);
break;
case SelfHostedIntegrationId.GitHubEnterprise:
provider = new (
Expand Down
4 changes: 3 additions & 1 deletion src/plus/integrations/authentication/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export interface CloudIntegrationConnection {
domain: string;
}

export type CloudIntegrationType = 'jira' | 'trello' | 'gitlab' | 'github' | 'bitbucket' | 'azure';
export type CloudIntegrationType = 'jira' | 'trello' | 'gitlab' | 'github' | 'bitbucket' | 'azure' | 'githubEnterprise';

export type CloudIntegrationAuthType = 'oauth' | 'pat';

Expand All @@ -53,6 +53,7 @@ export const toIntegrationId: { [key in CloudIntegrationType]: IntegrationId } =
trello: IssueIntegrationId.Trello,
gitlab: HostingIntegrationId.GitLab,
github: HostingIntegrationId.GitHub,
githubEnterprise: SelfHostedIntegrationId.CloudGitHubEnterprise,
bitbucket: HostingIntegrationId.Bitbucket,
azure: HostingIntegrationId.AzureDevOps,
};
Expand All @@ -64,6 +65,7 @@ export const toCloudIntegrationType: { [key in IntegrationId]: CloudIntegrationT
[HostingIntegrationId.GitHub]: 'github',
[HostingIntegrationId.Bitbucket]: 'bitbucket',
[HostingIntegrationId.AzureDevOps]: 'azure',
[SelfHostedIntegrationId.CloudGitHubEnterprise]: 'githubEnterprise',
[SelfHostedIntegrationId.GitHubEnterprise]: undefined,
[SelfHostedIntegrationId.GitLabSelfHosted]: undefined,
};
12 changes: 9 additions & 3 deletions src/plus/integrations/integrationService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ export class IntegrationService implements Disposable {
private async syncCloudIntegrations(forceConnect: boolean) {
const connectedIntegrations = new Set<IntegrationId>();
const loggedIn = await this.container.subscription.getAuthenticationSession();
const domains = new Map<string, string>();
if (loggedIn) {
const cloudIntegrations = await this.container.cloudIntegrations;
const connections = await cloudIntegrations?.getConnections();
Expand All @@ -100,10 +101,13 @@ export class IntegrationService implements Disposable {
// GKDev includes some integrations like "google" that we don't support
if (integrationId == null) return;
connectedIntegrations.add(toIntegrationId[p.provider]);
if (p.domain != null) {
domains.set(integrationId, p.domain);
}
});
}

for await (const integration of this.getSupportedCloudIntegrations()) {
for await (const integration of this.getSupportedCloudIntegrations(domains)) {
await integration.syncCloudConnection(
connectedIntegrations.has(integration.id) ? 'connected' : 'disconnected',
forceConnect,
Expand All @@ -121,9 +125,9 @@ export class IntegrationService implements Disposable {
return connectedIntegrations;
}

private async *getSupportedCloudIntegrations() {
private async *getSupportedCloudIntegrations(domains: Map<string, string>): AsyncIterable<Integration> {
for (const id of getSupportedCloudIntegrationIds()) {
yield this.get(id);
yield this.get(id, domains?.get(id));
}
}

Expand Down Expand Up @@ -437,6 +441,7 @@ export class IntegrationService implements Disposable {
await import(/* webpackChunkName: "integrations" */ './providers/github')
).GitHubIntegration(this.container, this.authenticationService, this.getProvidersApi.bind(this));
break;
case SelfHostedIntegrationId.CloudGitHubEnterprise:
case SelfHostedIntegrationId.GitHubEnterprise:
if (domain == null) throw new Error(`Domain is required for '${id}' integration`);
integration = new (
Expand All @@ -446,6 +451,7 @@ export class IntegrationService implements Disposable {
this.authenticationService,
this.getProvidersApi.bind(this),
domain,
id,
);
break;
case HostingIntegrationId.GitLab:
Expand Down
18 changes: 14 additions & 4 deletions src/plus/integrations/providers/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ const enterpriseAuthProvider: IntegrationAuthenticationProviderDescriptor = Obje
id: enterpriseMetadata.id,
scopes: enterpriseMetadata.scopes,
});
const cloudEnterpriseMetadata = providersMetadata[SelfHostedIntegrationId.CloudGitHubEnterprise];
const cloudEnterpriseAuthProvider: IntegrationAuthenticationProviderDescriptor = Object.freeze({
id: cloudEnterpriseMetadata.id,
scopes: cloudEnterpriseMetadata.scopes,
});

export type GitHubRepositoryDescriptor = RepositoryDescriptor;

Expand Down Expand Up @@ -294,10 +299,11 @@ export class GitHubIntegration extends GitHubIntegrationBase<HostingIntegrationI
}
}

export class GitHubEnterpriseIntegration extends GitHubIntegrationBase<SelfHostedIntegrationId.GitHubEnterprise> {
readonly authProvider = enterpriseAuthProvider;
readonly id = SelfHostedIntegrationId.GitHubEnterprise;
protected readonly key = `${this.id}:${this.domain}` as const;
export class GitHubEnterpriseIntegration extends GitHubIntegrationBase<
SelfHostedIntegrationId.GitHubEnterprise | SelfHostedIntegrationId.CloudGitHubEnterprise
> {
readonly authProvider;
protected readonly key;
readonly name = 'GitHub Enterprise';
get domain(): string {
return this._domain;
Expand All @@ -312,8 +318,12 @@ export class GitHubEnterpriseIntegration extends GitHubIntegrationBase<SelfHoste
authenticationService: IntegrationAuthenticationService,
getProvidersApi: () => Promise<ProvidersApi>,
private readonly _domain: string,
readonly id: SelfHostedIntegrationId.GitHubEnterprise | SelfHostedIntegrationId.CloudGitHubEnterprise,
) {
super(container, authenticationService, getProvidersApi);
this.key = `${this.id}:${this.domain}` as const;
this.authProvider =
this.id === SelfHostedIntegrationId.GitHubEnterprise ? enterpriseAuthProvider : cloudEnterpriseAuthProvider;
}

@log()
Expand Down
16 changes: 16 additions & 0 deletions src/plus/integrations/providers/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,22 @@ export const providersMetadata: ProvidersMetadata = {
supportedIssueFilters: [IssueFilter.Author, IssueFilter.Assignee, IssueFilter.Mention],
scopes: ['repo', 'read:user', 'user:email'],
},
[SelfHostedIntegrationId.CloudGitHubEnterprise]: {
domain: '',
id: SelfHostedIntegrationId.CloudGitHubEnterprise,
issuesPagingMode: PagingMode.Repos,
pullRequestsPagingMode: PagingMode.Repos,
// Use 'username' property on account for PR filters
supportedPullRequestFilters: [
PullRequestFilter.Author,
PullRequestFilter.Assignee,
PullRequestFilter.ReviewRequested,
PullRequestFilter.Mention,
],
// Use 'username' property on account for issue filters
supportedIssueFilters: [IssueFilter.Author, IssueFilter.Assignee, IssueFilter.Mention],
scopes: ['repo', 'read:user', 'user:email'],
},
[SelfHostedIntegrationId.GitHubEnterprise]: {
domain: '',
id: SelfHostedIntegrationId.GitHubEnterprise,
Expand Down
14 changes: 14 additions & 0 deletions src/plus/integrations/providers/providersApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,20 @@ export class ProvidersApi {
providerApis.github,
) as GetIssuesForReposFn,
},
[SelfHostedIntegrationId.CloudGitHubEnterprise]: {
...providersMetadata[SelfHostedIntegrationId.GitHubEnterprise],
provider: providerApis.github,
getCurrentUserFn: providerApis.github.getCurrentUser.bind(providerApis.github) as GetCurrentUserFn,
getPullRequestsForReposFn: providerApis.github.getPullRequestsForRepos.bind(
providerApis.github,
) as GetPullRequestsForReposFn,
getPullRequestsForUserFn: providerApis.github.getPullRequestsAssociatedWithUser.bind(
providerApis.github,
) as GetPullRequestsForUserFn,
getIssuesForReposFn: providerApis.github.getIssuesForRepos.bind(
providerApis.github,
) as GetIssuesForReposFn,
},
[SelfHostedIntegrationId.GitHubEnterprise]: {
...providersMetadata[SelfHostedIntegrationId.GitHubEnterprise],
provider: providerApis.github,
Expand Down

0 comments on commit 173e454

Please sign in to comment.