Skip to content

Commit 9c70f39

Browse files
committed
Adds Azure DevOps Server as a supported integration
(#4478, #4516)
1 parent 7d3072c commit 9c70f39

20 files changed

+350
-157
lines changed

docs/telemetry-events.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,7 @@ void
590590
```typescript
591591
{
592592
'hostingProvider.key': string,
593-
'hostingProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'jira' | 'trello'
593+
'hostingProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'azure-devops-server' | 'jira' | 'trello'
594594
}
595595
```
596596

@@ -601,7 +601,7 @@ void
601601
```typescript
602602
{
603603
'hostingProvider.key': string,
604-
'hostingProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'jira' | 'trello'
604+
'hostingProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'azure-devops-server' | 'jira' | 'trello'
605605
}
606606
```
607607

@@ -612,7 +612,7 @@ void
612612
```typescript
613613
{
614614
'issueProvider.key': string,
615-
'issueProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'jira' | 'trello'
615+
'issueProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'azure-devops-server' | 'jira' | 'trello'
616616
}
617617
```
618618

@@ -623,7 +623,7 @@ void
623623
```typescript
624624
{
625625
'issueProvider.key': string,
626-
'issueProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'jira' | 'trello'
626+
'issueProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'azure-devops-server' | 'jira' | 'trello'
627627
}
628628
```
629629

@@ -657,7 +657,7 @@ or when connection refresh is skipped due to being a non-cloud session
657657
658658
```typescript
659659
{
660-
'integration.id': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'jira' | 'trello'
660+
'integration.id': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'azure-devops-server' | 'jira' | 'trello'
661661
}
662662
```
663663

@@ -1800,7 +1800,7 @@ void
18001800
```typescript
18011801
{
18021802
'hostingProvider.key': string,
1803-
'hostingProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'jira' | 'trello',
1803+
'hostingProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'azure-devops-server' | 'jira' | 'trello',
18041804
// @deprecated: true
18051805
'remoteProviders.key': string
18061806
}
@@ -1813,7 +1813,7 @@ void
18131813
```typescript
18141814
{
18151815
'hostingProvider.key': string,
1816-
'hostingProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'jira' | 'trello',
1816+
'hostingProvider.provider': 'github' | 'gitlab' | 'bitbucket' | 'azureDevOps' | 'bitbucket-server' | 'github-enterprise' | 'cloud-github-enterprise' | 'gitlab-self-hosted' | 'cloud-gitlab-self-hosted' | 'azure-devops-server' | 'jira' | 'trello',
18171817
// @deprecated: true
18181818
'remoteProviders.key': string
18191819
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24576,7 +24576,7 @@
2457624576
},
2457724577
"dependencies": {
2457824578
"@gitkraken/gitkraken-components": "13.0.0-vnext.8",
24579-
"@gitkraken/provider-apis": "0.28.5",
24579+
"@gitkraken/provider-apis": "0.29.6",
2458024580
"@gitkraken/shared-web-components": "0.1.1-rc.15",
2458124581
"@gk-nzaytsev/fast-string-truncated-width": "1.1.0",
2458224582
"@lit-labs/signals": "0.1.3",

pnpm-lock.yaml

Lines changed: 5 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/autolinks/autolinksProvider.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@ import type { IntegrationIds } from '../constants.integrations';
55
import { IssuesCloudHostIntegrationId } from '../constants.integrations';
66
import type { Container } from '../container';
77
import type { GitRemote } from '../git/models/remote';
8-
import type { RemoteProviderId } from '../git/remotes/remoteProvider';
8+
import type { RemoteProvider, RemoteProviderId } from '../git/remotes/remoteProvider';
99
import { getIssueOrPullRequestHtmlIcon, getIssueOrPullRequestMarkdownIcon } from '../git/utils/-webview/icons';
1010
import type { ConfiguredIntegrationsChangeEvent } from '../plus/integrations/authentication/configuredIntegrationService';
1111
import type { GitHostIntegration } from '../plus/integrations/models/gitHostIntegration';
1212
import type { Integration } from '../plus/integrations/models/integration';
1313
import { IntegrationBase } from '../plus/integrations/models/integration';
1414
import type { IssuesIntegration } from '../plus/integrations/models/issuesIntegration';
15-
import { convertRemoteProviderIdToIntegrationId } from '../plus/integrations/utils/-webview/integration.utils';
15+
import {
16+
convertRemoteProviderIdToIntegrationId,
17+
getIntegrationIdForRemote,
18+
} from '../plus/integrations/utils/-webview/integration.utils';
1619
import { configuration } from '../system/-webview/configuration';
1720
import { fromNow } from '../system/date';
1821
import { debug } from '../system/decorators/log';
@@ -227,7 +230,8 @@ export class AutolinksProvider implements Disposable {
227230
: // TODO: Tighten the typing on ProviderReference to be specific to a remote provider, and then have a separate "integration" property (on autolinks and elsewhere)
228231
// that is of a new type IntegrationReference specific to integrations. Otherwise, make remote provider ids line up directly with integration ids.
229232
// Either way, this converting/casting hackery needs to go away.
230-
convertRemoteProviderIdToIntegrationId(link.provider.id as RemoteProviderId);
233+
(getIntegrationIdForRemote(link.provider as RemoteProvider) ??
234+
convertRemoteProviderIdToIntegrationId(link.provider.id as RemoteProviderId));
231235
if (integrationId == null) {
232236
// Fall back to the old logic assuming that integration id might be saved as provider id.
233237
// TODO: it should be removed when we put providers and integrations in order. Conversation: https://github.com/gitkraken/vscode-gitlens/pull/3996#discussion_r1936422826

src/constants.integrations.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ export enum GitSelfManagedHostIntegrationId {
1111
CloudGitHubEnterprise = 'cloud-github-enterprise',
1212
GitLabSelfHosted = 'gitlab-self-hosted',
1313
CloudGitLabSelfHosted = 'cloud-gitlab-self-hosted',
14+
AzureDevOpsServer = 'azure-devops-server',
1415
}
1516

1617
export enum IssuesCloudHostIntegrationId {
@@ -21,6 +22,7 @@ export enum IssuesCloudHostIntegrationId {
2122
export type CloudGitSelfManagedHostIntegrationIds =
2223
| GitSelfManagedHostIntegrationId.CloudGitHubEnterprise
2324
| GitSelfManagedHostIntegrationId.BitbucketServer
25+
| GitSelfManagedHostIntegrationId.AzureDevOpsServer
2426
| GitSelfManagedHostIntegrationId.CloudGitLabSelfHosted;
2527

2628
export type GitHostIntegrationIds = GitCloudHostIntegrationId | GitSelfManagedHostIntegrationId;
@@ -35,6 +37,7 @@ export const supportedOrderedCloudIntegrationIds = [
3537
GitCloudHostIntegrationId.GitLab,
3638
GitSelfManagedHostIntegrationId.CloudGitLabSelfHosted,
3739
GitCloudHostIntegrationId.AzureDevOps,
40+
GitSelfManagedHostIntegrationId.AzureDevOpsServer,
3841
GitCloudHostIntegrationId.Bitbucket,
3942
GitSelfManagedHostIntegrationId.BitbucketServer,
4043
IssuesCloudHostIntegrationId.Jira,
@@ -92,6 +95,13 @@ export const supportedCloudIntegrationDescriptors: IntegrationDescriptor[] = [
9295
supports: ['prs', 'issues'],
9396
requiresPro: true,
9497
},
98+
{
99+
id: GitSelfManagedHostIntegrationId.AzureDevOpsServer,
100+
name: 'Azure DevOps Server',
101+
icon: 'gl-provider-azdo',
102+
supports: ['prs', 'issues'],
103+
requiresPro: true,
104+
},
95105
{
96106
id: GitCloudHostIntegrationId.Bitbucket,
97107
name: 'Bitbucket',

src/git/remotes/remoteProviders.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ const cloudProviderCreatorsMap: Record<
9292
path: string,
9393
scheme: string | undefined,
9494
) => new BitbucketServerRemote(container, domain, path, cleanProtocol(scheme)),
95+
[GitSelfManagedHostIntegrationId.AzureDevOpsServer]: (container: Container, domain: string, path: string) =>
96+
new AzureDevOpsRemote(container, domain, path),
9597
};
9698

9799
const dirtyProtocolPattern = /(\w+)\W*/;
Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
1-
import { GitCloudHostIntegrationId } from '../../../constants.integrations';
1+
import { GitCloudHostIntegrationId, GitSelfManagedHostIntegrationId } from '../../../constants.integrations';
22
import { CloudIntegrationAuthenticationProvider } from './integrationAuthenticationProvider';
33

44
export class AzureDevOpsAuthenticationProvider extends CloudIntegrationAuthenticationProvider<GitCloudHostIntegrationId.AzureDevOps> {
55
protected override get authProviderId(): GitCloudHostIntegrationId.AzureDevOps {
66
return GitCloudHostIntegrationId.AzureDevOps;
77
}
88
}
9+
10+
export class AzureDevOpsServerAuthenticationProvider extends CloudIntegrationAuthenticationProvider<GitSelfManagedHostIntegrationId.AzureDevOpsServer> {
11+
protected override get authProviderId(): GitSelfManagedHostIntegrationId.AzureDevOpsServer {
12+
return GitSelfManagedHostIntegrationId.AzureDevOpsServer;
13+
}
14+
}

src/plus/integrations/authentication/integrationAuthenticationService.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export class IntegrationAuthenticationService implements Disposable {
4444
supports(providerId: string): boolean {
4545
switch (providerId) {
4646
case GitCloudHostIntegrationId.AzureDevOps:
47+
case GitSelfManagedHostIntegrationId.AzureDevOpsServer:
4748
case GitCloudHostIntegrationId.Bitbucket:
4849
case GitSelfManagedHostIntegrationId.GitHubEnterprise:
4950
case GitCloudHostIntegrationId.GitLab:
@@ -67,6 +68,11 @@ export class IntegrationAuthenticationService implements Disposable {
6768
await import(/* webpackChunkName: "integrations" */ './azureDevOps')
6869
).AzureDevOpsAuthenticationProvider(this.container, this, this.configuredIntegrationService);
6970
break;
71+
case GitSelfManagedHostIntegrationId.AzureDevOpsServer:
72+
provider = new (
73+
await import(/* webpackChunkName: "integrations" */ './azureDevOps')
74+
).AzureDevOpsServerAuthenticationProvider(this.container, this, this.configuredIntegrationService);
75+
break;
7076
case GitCloudHostIntegrationId.Bitbucket:
7177
provider = new (
7278
await import(/* webpackChunkName: "integrations" */ './bitbucket')

src/plus/integrations/authentication/models.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ export type CloudIntegrationType =
5050
| 'bitbucket'
5151
| 'bitbucketServer'
5252
| 'azure'
53+
| 'azureDevopsServer'
5354
| 'githubEnterprise'
5455
| 'gitlabSelfHosted';
5556

@@ -77,6 +78,7 @@ export const toIntegrationId: { [key in CloudIntegrationType]: IntegrationIds }
7778
bitbucket: GitCloudHostIntegrationId.Bitbucket,
7879
bitbucketServer: GitSelfManagedHostIntegrationId.BitbucketServer,
7980
azure: GitCloudHostIntegrationId.AzureDevOps,
81+
azureDevopsServer: GitSelfManagedHostIntegrationId.AzureDevOpsServer,
8082
};
8183

8284
export const toCloudIntegrationType: { [key in IntegrationIds]: CloudIntegrationType | undefined } = {
@@ -86,6 +88,7 @@ export const toCloudIntegrationType: { [key in IntegrationIds]: CloudIntegration
8688
[GitCloudHostIntegrationId.GitHub]: 'github',
8789
[GitCloudHostIntegrationId.Bitbucket]: 'bitbucket',
8890
[GitCloudHostIntegrationId.AzureDevOps]: 'azure',
91+
[GitSelfManagedHostIntegrationId.AzureDevOpsServer]: 'azureDevopsServer',
8992
[GitSelfManagedHostIntegrationId.CloudGitHubEnterprise]: 'githubEnterprise',
9093
[GitSelfManagedHostIntegrationId.CloudGitLabSelfHosted]: 'gitlabSelfHosted',
9194
[GitSelfManagedHostIntegrationId.BitbucketServer]: 'bitbucketServer',

src/plus/integrations/integrationService.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,46 @@ export class IntegrationService implements Disposable {
486486
) as GitHostIntegration as IntegrationById<T>;
487487
break;
488488

489+
case GitSelfManagedHostIntegrationId.AzureDevOpsServer:
490+
if (domain == null) {
491+
integration = this.findCachedById(id);
492+
// return immediately in order to not to cache it after the "switch" block:
493+
if (integration != null) return integration;
494+
495+
const configured = this.getConfiguredLite(GitSelfManagedHostIntegrationId.AzureDevOpsServer);
496+
if (configured.length) {
497+
const { domain: configuredDomain } = configured[0];
498+
if (configuredDomain == null) throw new Error(`Domain is required for '${id}' integration`);
499+
500+
integration = new (
501+
await import(/* webpackChunkName: "integrations" */ './providers/azureDevOps')
502+
).AzureDevOpsServerIntegration(
503+
this.container,
504+
this.authenticationService,
505+
this.getProvidersApi.bind(this),
506+
this._onDidChangeIntegrationConnection,
507+
configuredDomain,
508+
) as GitHostIntegration as IntegrationById<T>;
509+
510+
// assign domain because it's part of caching key:
511+
domain = configuredDomain;
512+
break;
513+
}
514+
515+
return undefined;
516+
}
517+
518+
integration = new (
519+
await import(/* webpackChunkName: "integrations" */ './providers/azureDevOps')
520+
).AzureDevOpsServerIntegration(
521+
this.container,
522+
this.authenticationService,
523+
this.getProvidersApi.bind(this),
524+
this._onDidChangeIntegrationConnection,
525+
domain,
526+
) as GitHostIntegration as IntegrationById<T>;
527+
break;
528+
489529
case IssuesCloudHostIntegrationId.Jira:
490530
integration = new (
491531
await import(/* webpackChunkName: "integrations" */ './providers/jira')

0 commit comments

Comments
 (0)