Skip to content

Commit 11d4c05

Browse files
committed
Conects and syncs to AzureDevOps
(#3976, #3984)
1 parent 9b8e414 commit 11d4c05

File tree

2 files changed

+11
-113
lines changed

2 files changed

+11
-113
lines changed

src/constants.integrations.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ export const supportedOrderedCloudIntegrationIds = [
2929
SelfHostedIntegrationId.CloudGitHubEnterprise,
3030
HostingIntegrationId.GitLab,
3131
SelfHostedIntegrationId.CloudGitLabSelfHosted,
32+
HostingIntegrationId.AzureDevOps,
3233
IssueIntegrationId.Jira,
3334
];
3435

@@ -71,6 +72,12 @@ export const supportedCloudIntegrationDescriptors: IntegrationDescriptor[] = [
7172
icon: 'gl-provider-gitlab',
7273
supports: ['prs', 'issues'],
7374
},
75+
{
76+
id: HostingIntegrationId.AzureDevOps,
77+
name: 'Azure DevOps',
78+
icon: 'gl-provider-azdo',
79+
supports: ['prs', 'issues'],
80+
},
7481
{
7582
id: IssueIntegrationId.Jira,
7683
name: 'Jira',
Lines changed: 4 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,121 +1,12 @@
1-
import type { Disposable, QuickInputButton } from 'vscode';
2-
import { env, ThemeIcon, Uri, window } from 'vscode';
31
import { HostingIntegrationId } from '../../../constants.integrations';
4-
import { base64 } from '../../../system/string';
5-
import type { IntegrationAuthenticationSessionDescriptor } from './integrationAuthenticationProvider';
6-
import { LocalIntegrationAuthenticationProvider } from './integrationAuthenticationProvider';
7-
import type { ProviderAuthenticationSession } from './models';
2+
import { CloudIntegrationAuthenticationProvider } from './integrationAuthenticationProvider';
83

9-
export class AzureDevOpsAuthenticationProvider extends LocalIntegrationAuthenticationProvider<HostingIntegrationId.AzureDevOps> {
4+
export class AzureDevOpsAuthenticationProvider extends CloudIntegrationAuthenticationProvider<HostingIntegrationId.AzureDevOps> {
105
protected override get authProviderId(): HostingIntegrationId.AzureDevOps {
116
return HostingIntegrationId.AzureDevOps;
127
}
138

14-
override async createSession(
15-
descriptor?: IntegrationAuthenticationSessionDescriptor,
16-
): Promise<ProviderAuthenticationSession | undefined> {
17-
let azureOrganization: string | undefined = descriptor?.organization as string | undefined;
18-
if (!azureOrganization) {
19-
const orgInput = window.createInputBox();
20-
orgInput.ignoreFocusOut = true;
21-
const orgInputDisposables: Disposable[] = [];
22-
try {
23-
azureOrganization = await new Promise<string | undefined>(resolve => {
24-
orgInputDisposables.push(
25-
orgInput.onDidHide(() => resolve(undefined)),
26-
orgInput.onDidChangeValue(() => (orgInput.validationMessage = undefined)),
27-
orgInput.onDidAccept(() => {
28-
const value = orgInput.value.trim();
29-
if (!value) {
30-
orgInput.validationMessage = 'An organization is required';
31-
return;
32-
}
33-
34-
resolve(value);
35-
}),
36-
);
37-
38-
orgInput.title = `Azure DevOps Authentication${
39-
descriptor?.domain ? ` \u2022 ${descriptor.domain}` : ''
40-
}`;
41-
orgInput.placeholder = 'Organization';
42-
orgInput.prompt = 'Enter your Azure DevOps organization';
43-
orgInput.show();
44-
});
45-
} finally {
46-
orgInput.dispose();
47-
orgInputDisposables.forEach(d => void d.dispose());
48-
}
49-
}
50-
51-
if (!azureOrganization) return undefined;
52-
53-
const tokenInput = window.createInputBox();
54-
tokenInput.ignoreFocusOut = true;
55-
56-
const disposables: Disposable[] = [];
57-
58-
let token;
59-
try {
60-
const infoButton: QuickInputButton = {
61-
iconPath: new ThemeIcon(`link-external`),
62-
tooltip: 'Open the Azure DevOps Access Tokens Page',
63-
};
64-
65-
token = await new Promise<string | undefined>(resolve => {
66-
disposables.push(
67-
tokenInput.onDidHide(() => resolve(undefined)),
68-
tokenInput.onDidChangeValue(() => (tokenInput.validationMessage = undefined)),
69-
tokenInput.onDidAccept(() => {
70-
const value = tokenInput.value.trim();
71-
if (!value) {
72-
tokenInput.validationMessage = 'A personal access token is required';
73-
return;
74-
}
75-
76-
resolve(value);
77-
}),
78-
tokenInput.onDidTriggerButton(e => {
79-
if (e === infoButton) {
80-
void env.openExternal(
81-
Uri.parse(
82-
`https://${
83-
descriptor?.domain ?? 'dev.azure.com'
84-
}/${azureOrganization}/_usersSettings/tokens`,
85-
),
86-
);
87-
}
88-
}),
89-
);
90-
91-
tokenInput.password = true;
92-
tokenInput.title = `Azure DevOps Authentication${
93-
descriptor?.domain ? ` \u2022 ${descriptor.domain}` : ''
94-
}`;
95-
tokenInput.placeholder = `Requires ${descriptor?.scopes.join(', ') ?? 'all'} scopes`;
96-
tokenInput.prompt = `Paste your [Azure DevOps Personal Access Token](https://${
97-
descriptor?.domain ?? 'dev.azure.com'
98-
}/${azureOrganization}/_usersSettings/tokens "Get your Azure DevOps Access Token")`;
99-
tokenInput.buttons = [infoButton];
100-
101-
tokenInput.show();
102-
});
103-
} finally {
104-
tokenInput.dispose();
105-
disposables.forEach(d => void d.dispose());
106-
}
107-
108-
if (!token) return undefined;
109-
110-
return {
111-
id: this.getSessionId(descriptor),
112-
accessToken: base64(`:${token}`),
113-
scopes: descriptor?.scopes ?? [],
114-
account: {
115-
id: '',
116-
label: '',
117-
},
118-
cloud: false,
119-
};
9+
protected override getCompletionInputTitle(): string {
10+
return 'Connect to Azure Dev Ops';
12011
}
12112
}

0 commit comments

Comments
 (0)