Skip to content

Commit dba92c4

Browse files
committed
Add support for GKDev Cloud GitHub Enterprise integration
(#3901)
1 parent d61feb8 commit dba92c4

File tree

8 files changed

+78
-9
lines changed

8 files changed

+78
-9
lines changed

src/constants.integrations.ts

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export enum HostingIntegrationId {
77

88
export enum SelfHostedIntegrationId {
99
GitHubEnterprise = 'github-enterprise',
10+
CloudGitHubEnterprise = 'cloud-github-enterprise',
1011
GitLabSelfHosted = 'gitlab-self-hosted',
1112
}
1213

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

2021
export const supportedOrderedCloudIssueIntegrationIds = [IssueIntegrationId.Jira];
2122
export const supportedOrderedCloudIntegrationIds = [
23+
SelfHostedIntegrationId.CloudGitHubEnterprise,
2224
HostingIntegrationId.GitHub,
2325
HostingIntegrationId.GitLab,
2426
IssueIntegrationId.Jira,

src/plus/integrations/authentication/github.ts

+10
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,16 @@ export class GitHubAuthenticationProvider extends CloudIntegrationAuthentication
6969
}
7070
}
7171

72+
export class GitHubEnterpriseCloudAuthenticationProvider extends CloudIntegrationAuthenticationProvider<SelfHostedIntegrationId.CloudGitHubEnterprise> {
73+
protected override getCompletionInputTitle(): string {
74+
throw new Error('Connect to GitHub Enterprise');
75+
}
76+
77+
protected override get authProviderId(): SelfHostedIntegrationId.CloudGitHubEnterprise {
78+
return SelfHostedIntegrationId.CloudGitHubEnterprise;
79+
}
80+
}
81+
7282
export class GitHubEnterpriseAuthenticationProvider extends LocalIntegrationAuthenticationProvider<SelfHostedIntegrationId.GitHubEnterprise> {
7383
protected override get authProviderId(): SelfHostedIntegrationId.GitHubEnterprise {
7484
return SelfHostedIntegrationId.GitHubEnterprise;

src/plus/integrations/authentication/integrationAuthentication.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,11 @@ export abstract class CloudIntegrationAuthenticationProvider<
338338
let session = await cloudIntegrations.getConnectionSession(this.authProviderId);
339339

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

529+
break;
530+
case SelfHostedIntegrationId.CloudGitHubEnterprise:
531+
provider = new (
532+
await import(/* webpackChunkName: "integrations" */ './github')
533+
).GitHubEnterpriseCloudAuthenticationProvider(this.container);
525534
break;
526535
case SelfHostedIntegrationId.GitHubEnterprise:
527536
provider = new (

src/plus/integrations/authentication/models.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export interface CloudIntegrationConnection {
3232
domain: string;
3333
}
3434

35-
export type CloudIntegrationType = 'jira' | 'trello' | 'gitlab' | 'github' | 'bitbucket' | 'azure';
35+
export type CloudIntegrationType = 'jira' | 'trello' | 'gitlab' | 'github' | 'bitbucket' | 'azure' | 'githubEnterprise';
3636

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

@@ -53,6 +53,7 @@ export const toIntegrationId: { [key in CloudIntegrationType]: IntegrationId } =
5353
trello: IssueIntegrationId.Trello,
5454
gitlab: HostingIntegrationId.GitLab,
5555
github: HostingIntegrationId.GitHub,
56+
githubEnterprise: SelfHostedIntegrationId.CloudGitHubEnterprise,
5657
bitbucket: HostingIntegrationId.Bitbucket,
5758
azure: HostingIntegrationId.AzureDevOps,
5859
};
@@ -64,6 +65,7 @@ export const toCloudIntegrationType: { [key in IntegrationId]: CloudIntegrationT
6465
[HostingIntegrationId.GitHub]: 'github',
6566
[HostingIntegrationId.Bitbucket]: 'bitbucket',
6667
[HostingIntegrationId.AzureDevOps]: 'azure',
68+
[SelfHostedIntegrationId.CloudGitHubEnterprise]: 'githubEnterprise',
6769
[SelfHostedIntegrationId.GitHubEnterprise]: undefined,
6870
[SelfHostedIntegrationId.GitLabSelfHosted]: undefined,
6971
};

src/plus/integrations/integrationService.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ export class IntegrationService implements Disposable {
9090
private async syncCloudIntegrations(forceConnect: boolean) {
9191
const connectedIntegrations = new Set<IntegrationId>();
9292
const loggedIn = await this.container.subscription.getAuthenticationSession();
93+
const domains = new Map<string, string>();
9394
if (loggedIn) {
9495
const cloudIntegrations = await this.container.cloudIntegrations;
9596
const connections = await cloudIntegrations?.getConnections();
@@ -100,10 +101,13 @@ export class IntegrationService implements Disposable {
100101
// GKDev includes some integrations like "google" that we don't support
101102
if (integrationId == null) return;
102103
connectedIntegrations.add(toIntegrationId[p.provider]);
104+
if (p.domain != null) {
105+
domains.set(integrationId, p.domain);
106+
}
103107
});
104108
}
105109

106-
for await (const integration of this.getSupportedCloudIntegrations()) {
110+
for await (const integration of this.getSupportedCloudIntegrations(domains)) {
107111
await integration.syncCloudConnection(
108112
connectedIntegrations.has(integration.id) ? 'connected' : 'disconnected',
109113
forceConnect,
@@ -121,9 +125,9 @@ export class IntegrationService implements Disposable {
121125
return connectedIntegrations;
122126
}
123127

124-
private async *getSupportedCloudIntegrations() {
128+
private async *getSupportedCloudIntegrations(domains: Map<string, string>): AsyncIterable<Integration> {
125129
for (const id of getSupportedCloudIntegrationIds()) {
126-
yield this.get(id);
130+
yield this.get(id, domains?.get(id));
127131
}
128132
}
129133

@@ -437,6 +441,7 @@ export class IntegrationService implements Disposable {
437441
await import(/* webpackChunkName: "integrations" */ './providers/github')
438442
).GitHubIntegration(this.container, this.authenticationService, this.getProvidersApi.bind(this));
439443
break;
444+
case SelfHostedIntegrationId.CloudGitHubEnterprise:
440445
case SelfHostedIntegrationId.GitHubEnterprise:
441446
if (domain == null) throw new Error(`Domain is required for '${id}' integration`);
442447
integration = new (
@@ -446,6 +451,7 @@ export class IntegrationService implements Disposable {
446451
this.authenticationService,
447452
this.getProvidersApi.bind(this),
448453
domain,
454+
id,
449455
);
450456
break;
451457
case HostingIntegrationId.GitLab:

src/plus/integrations/providers/github.ts

+14-4
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ const enterpriseAuthProvider: IntegrationAuthenticationProviderDescriptor = Obje
3434
id: enterpriseMetadata.id,
3535
scopes: enterpriseMetadata.scopes,
3636
});
37+
const cloudEnterpriseMetadata = providersMetadata[SelfHostedIntegrationId.CloudGitHubEnterprise];
38+
const cloudEnterpriseAuthProvider: IntegrationAuthenticationProviderDescriptor = Object.freeze({
39+
id: cloudEnterpriseMetadata.id,
40+
scopes: cloudEnterpriseMetadata.scopes,
41+
});
3742

3843
export type GitHubRepositoryDescriptor = RepositoryDescriptor;
3944

@@ -294,10 +299,11 @@ export class GitHubIntegration extends GitHubIntegrationBase<HostingIntegrationI
294299
}
295300
}
296301

297-
export class GitHubEnterpriseIntegration extends GitHubIntegrationBase<SelfHostedIntegrationId.GitHubEnterprise> {
298-
readonly authProvider = enterpriseAuthProvider;
299-
readonly id = SelfHostedIntegrationId.GitHubEnterprise;
300-
protected readonly key = `${this.id}:${this.domain}` as const;
302+
export class GitHubEnterpriseIntegration extends GitHubIntegrationBase<
303+
SelfHostedIntegrationId.GitHubEnterprise | SelfHostedIntegrationId.CloudGitHubEnterprise
304+
> {
305+
readonly authProvider;
306+
protected readonly key;
301307
readonly name = 'GitHub Enterprise';
302308
get domain(): string {
303309
return this._domain;
@@ -312,8 +318,12 @@ export class GitHubEnterpriseIntegration extends GitHubIntegrationBase<SelfHoste
312318
authenticationService: IntegrationAuthenticationService,
313319
getProvidersApi: () => Promise<ProvidersApi>,
314320
private readonly _domain: string,
321+
readonly id: SelfHostedIntegrationId.GitHubEnterprise | SelfHostedIntegrationId.CloudGitHubEnterprise,
315322
) {
316323
super(container, authenticationService, getProvidersApi);
324+
this.key = `${this.id}:${this.domain}` as const;
325+
this.authProvider =
326+
this.id === SelfHostedIntegrationId.GitHubEnterprise ? enterpriseAuthProvider : cloudEnterpriseAuthProvider;
317327
}
318328

319329
@log()

src/plus/integrations/providers/models.ts

+16
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,22 @@ export const providersMetadata: ProvidersMetadata = {
349349
supportedIssueFilters: [IssueFilter.Author, IssueFilter.Assignee, IssueFilter.Mention],
350350
scopes: ['repo', 'read:user', 'user:email'],
351351
},
352+
[SelfHostedIntegrationId.CloudGitHubEnterprise]: {
353+
domain: '',
354+
id: SelfHostedIntegrationId.CloudGitHubEnterprise,
355+
issuesPagingMode: PagingMode.Repos,
356+
pullRequestsPagingMode: PagingMode.Repos,
357+
// Use 'username' property on account for PR filters
358+
supportedPullRequestFilters: [
359+
PullRequestFilter.Author,
360+
PullRequestFilter.Assignee,
361+
PullRequestFilter.ReviewRequested,
362+
PullRequestFilter.Mention,
363+
],
364+
// Use 'username' property on account for issue filters
365+
supportedIssueFilters: [IssueFilter.Author, IssueFilter.Assignee, IssueFilter.Mention],
366+
scopes: ['repo', 'read:user', 'user:email'],
367+
},
352368
[SelfHostedIntegrationId.GitHubEnterprise]: {
353369
domain: '',
354370
id: SelfHostedIntegrationId.GitHubEnterprise,

src/plus/integrations/providers/providersApi.ts

+14
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,20 @@ export class ProvidersApi {
9898
providerApis.github,
9999
) as GetIssuesForReposFn,
100100
},
101+
[SelfHostedIntegrationId.CloudGitHubEnterprise]: {
102+
...providersMetadata[SelfHostedIntegrationId.GitHubEnterprise],
103+
provider: providerApis.github,
104+
getCurrentUserFn: providerApis.github.getCurrentUser.bind(providerApis.github) as GetCurrentUserFn,
105+
getPullRequestsForReposFn: providerApis.github.getPullRequestsForRepos.bind(
106+
providerApis.github,
107+
) as GetPullRequestsForReposFn,
108+
getPullRequestsForUserFn: providerApis.github.getPullRequestsAssociatedWithUser.bind(
109+
providerApis.github,
110+
) as GetPullRequestsForUserFn,
111+
getIssuesForReposFn: providerApis.github.getIssuesForRepos.bind(
112+
providerApis.github,
113+
) as GetIssuesForReposFn,
114+
},
101115
[SelfHostedIntegrationId.GitHubEnterprise]: {
102116
...providersMetadata[SelfHostedIntegrationId.GitHubEnterprise],
103117
provider: providerApis.github,

0 commit comments

Comments
 (0)