@gitkraken/core-gitlens 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +41 -1
- package/dist/git/cache.js +2 -0
- package/dist/git/cache.js.map +1 -1
- package/dist/git/models/issue.d.ts +3 -1
- package/dist/git/models/issue.js.map +1 -1
- package/dist/git/providers/branches.d.ts +4 -2
- package/dist/git/utils/issue.utils.d.ts +3 -1
- package/dist/git/utils/issue.utils.js +5 -1
- package/dist/git/utils/issue.utils.js.map +1 -1
- package/dist/git/watching/worktreeSummary.d.ts +20 -9
- package/dist/git/watching/worktreeSummary.js +24 -22
- package/dist/git/watching/worktreeSummary.js.map +1 -1
- package/dist/git-cli/providers/branches.js +26 -4
- package/dist/git-cli/providers/branches.js.map +1 -1
- package/dist/plus/integrations/models/gitHostIntegration.js +3 -1
- package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
- package/dist/plus/integrations/models/integration.js +1 -1
- package/dist/plus/integrations/providers/azure/azure.js +3 -2
- package/dist/plus/integrations/providers/azure/azure.js.map +1 -1
- package/dist/plus/integrations/providers/azure/models.d.ts +27 -10
- package/dist/plus/integrations/providers/azure/models.js +39 -19
- package/dist/plus/integrations/providers/azure/models.js.map +1 -1
- package/dist/plus/integrations/providers/azure/workItemStateCategories.d.ts +19 -0
- package/dist/plus/integrations/providers/azure/workItemStateCategories.js +32 -0
- package/dist/plus/integrations/providers/azure/workItemStateCategories.js.map +1 -0
- package/dist/plus/integrations/providers/azureDevOps.js +5 -5
- package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
- package/dist/plus/integrations/providers/issueSorts.d.ts +0 -1
- package/dist/plus/integrations/providers/jira-server.js +11 -5
- package/dist/plus/integrations/providers/jira-server.js.map +1 -1
- package/dist/plus/integrations/providers/jira.d.ts +5 -2
- package/dist/plus/integrations/providers/jira.js +45 -30
- package/dist/plus/integrations/providers/jira.js.map +1 -1
- package/dist/plus/integrations/providers/jiraIssueByKey.d.ts +3 -4
- package/dist/plus/integrations/providers/jiraIssueByKey.js +3 -4
- package/dist/plus/integrations/providers/jiraIssueByKey.js.map +1 -1
- package/dist/plus/integrations/providers/linearIssuesEtag.d.ts +5 -5
- package/dist/plus/integrations/providers/linearIssuesEtag.js +6 -6
- package/dist/plus/integrations/providers/linearIssuesEtag.js.map +1 -1
- package/dist/plus/integrations/providers/models.d.ts +11 -1
- package/dist/plus/integrations/providers/models.js +9 -9
- package/dist/plus/integrations/providers/models.js.map +1 -1
- package/dist/plus/integrations/providers/providersApi.d.ts +30 -32
- package/dist/plus/integrations/providers/providersApi.js +149 -46
- package/dist/plus/integrations/providers/providersApi.js.map +1 -1
- package/dist/plus/integrations/providers/utils/jiraIssueDrains.d.ts +27 -15
- package/dist/plus/integrations/providers/utils/jiraIssueDrains.js +72 -10
- package/dist/plus/integrations/providers/utils/jiraIssueDrains.js.map +1 -1
- package/dist/plus/integrations/reads/batchEtags.d.ts +5 -2
- package/dist/plus/integrations/reads/batchEtags.js +31 -10
- package/dist/plus/integrations/reads/batchEtags.js.map +1 -1
- package/dist/plus/integrations/reads/cursors.js +1 -1
- package/dist/plus/integrations/reads/drains.d.ts +0 -1
- package/dist/plus/integrations/reads/hierarchy.js +2 -2
- package/dist/plus/integrations/reads/hierarchy.js.map +1 -1
- package/dist/plus/integrations/reads/hierarchy.utils.d.ts +13 -0
- package/dist/plus/integrations/reads/hierarchy.utils.js +26 -1
- package/dist/plus/integrations/reads/hierarchy.utils.js.map +1 -1
- package/dist/plus/integrations/reads/issueTracker.js +4 -4
- package/dist/plus/integrations/reads/issueTracker.js.map +1 -1
- package/dist/plus/integrations/reads/issues.js +1 -1
- package/dist/plus/integrations/reads/pullRequestBranches.js +10 -3
- package/dist/plus/integrations/reads/pullRequestBranches.js.map +1 -1
- package/dist/plus/integrations/results.d.ts +28 -3
- package/dist/plus/integrations/results.js +22 -3
- package/dist/plus/integrations/results.js.map +1 -1
- package/dist/plus/integrations/utils/integration.utils.d.ts +6 -1
- package/dist/plus/integrations/utils/integration.utils.js +8 -1
- package/dist/plus/integrations/utils/integration.utils.js.map +1 -1
- package/docs/integrations.md +54 -19
- package/package.json +2 -2
|
@@ -6,8 +6,8 @@ import { GitCloudHostIntegrationId, GitSelfManagedHostIntegrationId, Integration
|
|
|
6
6
|
import { ProviderOrganization } from "../results.js";
|
|
7
7
|
import { ProviderPullRequestCount, ProviderPullRequestSearchPage } from "../models/pullRequestReads.js";
|
|
8
8
|
import { IssueFilter } from "../providerFilters.js";
|
|
9
|
-
import { GetIssuesOptions, GetPullRequestsForUserOptions, GetPullRequestsOptions, GetReposOptions, PageInfo, PagingInput, PagingMode, ProviderAccount, ProviderApiCollectionResult, ProviderApiPagedResult, ProviderAzureProject, ProviderAzureResource, ProviderBitbucketResource, ProviderGitHubOrganization, ProviderGitLabGroup, ProviderHierarchyResult, ProviderIssue, ProviderJiraProject, ProviderJiraResource, ProviderJiraServerProject, ProviderLinearOrganization, ProviderLinearTeam, ProviderPullRequest, ProviderRepoInput, ProviderReposInput, ProviderRepository, ProviderRequestResponse } from "./models.js";
|
|
10
|
-
import { AzurePullRequest,
|
|
9
|
+
import { GetIssuesOptions, GetPullRequestsForUserOptions, GetPullRequestsOptions, GetReposOptions, JiraIssuePage, PageInfo, PagingInput, PagingMode, ProviderAccount, ProviderApiCollectionResult, ProviderApiPagedResult, ProviderAzureProject, ProviderAzureResource, ProviderBitbucketResource, ProviderGitHubOrganization, ProviderGitLabGroup, ProviderHierarchyResult, ProviderIssue, ProviderJiraProject, ProviderJiraResource, ProviderJiraServerProject, ProviderLinearOrganization, ProviderLinearTeam, ProviderPullRequest, ProviderRepoInput, ProviderReposInput, ProviderRepository, ProviderRequestResponse } from "./models.js";
|
|
10
|
+
import { AzurePullRequest, AzureWorkItemEtagRead } from "./azure/models.js";
|
|
11
11
|
import { countBitbucketServerPullRequests, searchBitbucketServerPullRequestsPage } from "./bitbucket-server/pullRequestSearch.js";
|
|
12
12
|
import { JiraIssueEtagResponse } from "./jiraIssueByKey.js";
|
|
13
13
|
import { LinearIssueEtagNode } from "./linearIssuesEtag.js";
|
|
@@ -18,6 +18,12 @@ export declare class ProvidersApi {
|
|
|
18
18
|
private readonly authenticationService;
|
|
19
19
|
private readonly providers;
|
|
20
20
|
private readonly request;
|
|
21
|
+
/**
|
|
22
|
+
* Each work item type's states, by URL (host, organization, project and type) and credential: coalesces the reads
|
|
23
|
+
* of the same type, and never answers one credential with what another one read. A failed read is not kept, so the
|
|
24
|
+
* next read retries it.
|
|
25
|
+
*/
|
|
26
|
+
private readonly azureWorkItemTypeStates;
|
|
21
27
|
constructor(authenticationService: IntegrationAuthenticationService);
|
|
22
28
|
getScopesForProvider(providerId: IntegrationIds): string[] | undefined;
|
|
23
29
|
getProviderDomain(providerId: IntegrationIds): string | undefined;
|
|
@@ -122,8 +128,9 @@ export declare class ProvidersApi {
|
|
|
122
128
|
* request, where {@link getAzureWorkItem} reads one work item per request, selecting only
|
|
123
129
|
* `azureWorkItemEtagFieldNames`. Asked with `errorPolicy=omit`, without which one missing id fails the whole
|
|
124
130
|
* request; Azure then leaves out every id it can't return, for whatever reason, so a caller matches the work items
|
|
125
|
-
* to its ids by `id`, never by position, and reads an omission as unknown rather than absent.
|
|
126
|
-
*
|
|
131
|
+
* to its ids by `id`, never by position, and reads an omission as unknown rather than absent. Each work item comes
|
|
132
|
+
* with the workflow category its state classifies to, as {@link getAzureWorkItem} classifies it. Every failure
|
|
133
|
+
* throws, classified as {@link getAzureWorkItem} classifies it, the states reads' included.
|
|
127
134
|
*/
|
|
128
135
|
getAzureWorkItemsEtagFields(tokenOptInfo: TokenOptInfo, scope: {
|
|
129
136
|
namespace: string;
|
|
@@ -131,7 +138,7 @@ export declare class ProvidersApi {
|
|
|
131
138
|
}, ids: readonly number[], options: {
|
|
132
139
|
isPAT?: boolean;
|
|
133
140
|
baseUrl?: string;
|
|
134
|
-
}): Promise<
|
|
141
|
+
}): Promise<AzureWorkItemEtagRead[]>;
|
|
135
142
|
/**
|
|
136
143
|
* The cheap check behind the batch pull request read's etags: one pull request as Azure DevOps returns it, by the
|
|
137
144
|
* same request {@link getPullRequestForRepo} has provider-apis send, but without the repository read it adds for
|
|
@@ -341,18 +348,25 @@ export declare class ProvidersApi {
|
|
|
341
348
|
getIssuesForAzureProject(tokenOptInfo: TokenOptInfo<GitCloudHostIntegrationId.AzureDevOps | GitSelfManagedHostIntegrationId.AzureDevOpsServer>, namespace: string, project: string, options?: GetIssuesOptions & {
|
|
342
349
|
isPAT?: boolean;
|
|
343
350
|
baseUrl?: string;
|
|
344
|
-
}): Promise<
|
|
351
|
+
}): Promise<ProviderApiPagedResult<ProviderIssue>>;
|
|
352
|
+
/**
|
|
353
|
+
* Gives each of `issues` with both a type and a state the workflow category of that state, from its type's states
|
|
354
|
+
* (see {@link azureWorkItemTypeStates}): `undefined` for a state the type doesn't list. Keyed on the raw
|
|
355
|
+
* `System.State`, which is the state name on every Azure read here because core passes the SDK no state-name map;
|
|
356
|
+
* passing one would break the lookup.
|
|
357
|
+
*
|
|
358
|
+
* Reads each distinct type once, a bounded number at a time. A type whose read fails leaves its issues untouched,
|
|
359
|
+
* after the other types' issues are classified, and the first failure then rejects, classified by
|
|
360
|
+
* {@link handleProviderError}.
|
|
361
|
+
*/
|
|
362
|
+
private classifyAzureIssueStates;
|
|
345
363
|
getIssuesForProject(tokenOptInfo: TokenWithInfo, project: string, resourceId: string, options?: GetIssuesOptions): Promise<ProviderIssue[] | undefined>;
|
|
346
364
|
/**
|
|
347
365
|
* Single page of {@link getIssuesForProject} that preserves the SDK's `pageInfo` so a caller can drain
|
|
348
366
|
* every page (the plain {@link getIssuesForProject} discards it, silently capping at the first page).
|
|
349
367
|
* `nextCursor` is the raw provider cursor (Jira offset / nextPageToken) fed back verbatim as `options.cursor`.
|
|
350
368
|
*/
|
|
351
|
-
getIssuesForProjectPaged(tokenOptInfo: TokenWithInfo, project: string, resourceId: string, options?: GetIssuesOptions): Promise<
|
|
352
|
-
data: ProviderIssue[];
|
|
353
|
-
hasMore: boolean;
|
|
354
|
-
nextCursor: string | undefined;
|
|
355
|
-
} | undefined>;
|
|
369
|
+
getIssuesForProjectPaged(tokenOptInfo: TokenWithInfo, project: string, resourceId: string, options?: GetIssuesOptions): Promise<JiraIssuePage>;
|
|
356
370
|
getJiraServerCurrentUser(tokenOptInfo: TokenWithInfo<IssuesSelfManagedHostIntegrationId.JiraServer>, baseUrl: string): Promise<ProviderAccount | undefined>;
|
|
357
371
|
/**
|
|
358
372
|
* Jira Server's project list, which is a single unpaged `/rest/api/2/project` read rather than Cloud's
|
|
@@ -363,42 +377,26 @@ export declare class ProvidersApi {
|
|
|
363
377
|
* One page of a Jira Server project's issues, preserving the SDK's `pageInfo` so the integration can drain
|
|
364
378
|
* every page — the same contract as {@link getIssuesForProjectPaged} on Cloud.
|
|
365
379
|
*/
|
|
366
|
-
getJiraServerIssuesForProjectPaged(tokenOptInfo: TokenWithInfo<IssuesSelfManagedHostIntegrationId.JiraServer>, baseUrl: string, projectKey: string, options?: GetIssuesOptions): Promise<
|
|
367
|
-
data: ProviderIssue[];
|
|
368
|
-
hasMore: boolean;
|
|
369
|
-
nextCursor: string | undefined;
|
|
370
|
-
} | undefined>;
|
|
380
|
+
getJiraServerIssuesForProjectPaged(tokenOptInfo: TokenWithInfo<IssuesSelfManagedHostIntegrationId.JiraServer>, baseUrl: string, projectKey: string, options?: GetIssuesOptions): Promise<JiraIssuePage>;
|
|
371
381
|
/**
|
|
372
382
|
* Single page of one issue search across several projects of a Jira Server instance — the contract of
|
|
373
383
|
* {@link getIssuesForProjectsPaged} on Cloud: the page and its cursor are global to the project set, and at
|
|
374
384
|
* most `JIRA_MAX_PROJECT_KEYS_PER_REQUEST` keys are accepted per call.
|
|
375
385
|
*/
|
|
376
|
-
getJiraServerIssuesForProjectsPaged(tokenOptInfo: TokenWithInfo<IssuesSelfManagedHostIntegrationId.JiraServer>, baseUrl: string, projectKeys: string[], options?: GetIssuesOptions): Promise<
|
|
377
|
-
data: ProviderIssue[];
|
|
378
|
-
hasMore: boolean;
|
|
379
|
-
nextCursor: string | undefined;
|
|
380
|
-
} | undefined>;
|
|
386
|
+
getJiraServerIssuesForProjectsPaged(tokenOptInfo: TokenWithInfo<IssuesSelfManagedHostIntegrationId.JiraServer>, baseUrl: string, projectKeys: string[], options?: GetIssuesOptions): Promise<JiraIssuePage>;
|
|
381
387
|
getJiraServerIssue(tokenOptInfo: TokenWithInfo<IssuesSelfManagedHostIntegrationId.JiraServer>, baseUrl: string, number: string): Promise<ProviderIssue | undefined>;
|
|
382
388
|
/** The account-wide read: every issue related to the current user on this instance, no project needed. */
|
|
383
389
|
getJiraServerIssuesForCurrentUser(tokenOptInfo: TokenWithInfo<IssuesSelfManagedHostIntegrationId.JiraServer>, baseUrl: string, options?: {
|
|
384
390
|
cursor?: string;
|
|
385
391
|
states?: GitIssueState[];
|
|
386
392
|
sort?: IssueSorting;
|
|
387
|
-
}): Promise<
|
|
388
|
-
data: ProviderIssue[];
|
|
389
|
-
hasMore: boolean;
|
|
390
|
-
nextCursor: string | undefined;
|
|
391
|
-
} | undefined>;
|
|
393
|
+
}): Promise<JiraIssuePage>;
|
|
392
394
|
/**
|
|
393
395
|
* Single page of one issue search across several projects of the same Jira site. The page, its cursor and
|
|
394
396
|
* `hasMore` are global to the whole project set, not per project; at most `JIRA_MAX_PROJECT_KEYS_PER_REQUEST`
|
|
395
397
|
* keys are accepted per call (the SDK throws past it), so the caller chunks.
|
|
396
398
|
*/
|
|
397
|
-
getIssuesForProjectsPaged(tokenOptInfo: TokenWithInfo, projectKeys: string[], resourceId: string, options?: GetIssuesOptions): Promise<
|
|
398
|
-
data: ProviderIssue[];
|
|
399
|
-
hasMore: boolean;
|
|
400
|
-
nextCursor: string | undefined;
|
|
401
|
-
} | undefined>;
|
|
399
|
+
getIssuesForProjectsPaged(tokenOptInfo: TokenWithInfo, projectKeys: string[], resourceId: string, options?: GetIssuesOptions): Promise<JiraIssuePage>;
|
|
402
400
|
getTrelloCard(tokenOptInfo: TokenWithInfo<IssuesCloudHostIntegrationId.Trello>, appKey: string, cardId: string, options?: {
|
|
403
401
|
trelloBoardListsById?: Record<string, {
|
|
404
402
|
name: string;
|
|
@@ -435,7 +433,7 @@ export declare class ProvidersApi {
|
|
|
435
433
|
states?: GitIssueState[];
|
|
436
434
|
isPAT?: boolean;
|
|
437
435
|
baseUrl?: string;
|
|
438
|
-
}): Promise<
|
|
436
|
+
}): Promise<ProviderApiPagedResult<ProviderIssue>>;
|
|
439
437
|
getJiraIssueByKey(tokenOptInfo: TokenWithInfo<IssuesCloudHostIntegrationId.Jira>, resourceId: string, resourceUrl: string, key: string): Promise<ProviderIssue | undefined>;
|
|
440
438
|
/**
|
|
441
439
|
* The change state of up to `jiraBulkFetchMaxKeys` issues of one Jira Cloud site, in one bulk fetch. Unlike
|
|
@@ -1,13 +1,17 @@
|
|
|
1
|
+
import { mapSettledBounded } from "../../../utils/promise.js";
|
|
2
|
+
import { PromiseCache } from "../../../utils/promiseCache.js";
|
|
1
3
|
import { RequestNotFoundError } from "../../../git/errors.js";
|
|
2
4
|
import { base64 } from "../../../utils/base64.js";
|
|
5
|
+
import { isTerminalIssueStateCategory } from "../../../git/utils/issue.utils.js";
|
|
3
6
|
import { toError } from "../errors.js";
|
|
4
7
|
import "../constants.js";
|
|
5
8
|
import { UnexpectedHtmlResponseError, getProviderResponseBodyMessage, isAzureProviderId, isProviderIssueNotFoundError, throwProviderError } from "./providerErrors.js";
|
|
6
|
-
import { isIncompleteCollection } from "../collectionMetadata.js";
|
|
9
|
+
import { isIncompleteCollection, toCollectionScopeFailure } from "../collectionMetadata.js";
|
|
7
10
|
import { toTokenWithInfo } from "../authentication/models.js";
|
|
8
11
|
import { collectProviderPagedResult, mergeCollectionMetadata, parsePageCursor, toPageCursor } from "./utils/providerPaging.js";
|
|
9
|
-
import { isRepoIdsInput, providersMetadata } from "./models.js";
|
|
12
|
+
import { GitIssueState as GitIssueState$1, isRepoIdsInput, providersMetadata } from "./models.js";
|
|
10
13
|
import { azureWorkItemEtagFieldNames, encodeAzurePathSegment, fromAzureWorkItemToProviderIssue } from "./azure/models.js";
|
|
14
|
+
import { getAzureWorkItemTypeStatesUrl, parseAzureWorkItemTypeStates } from "./azure/workItemStateCategories.js";
|
|
11
15
|
import { requestJiraIssueByKey, requestJiraIssuesEtagFields } from "./jiraIssueByKey.js";
|
|
12
16
|
import { requestLinearIssuesEtagFields } from "./linearIssuesEtag.js";
|
|
13
17
|
import { requestBitbucketServerProjects, requestBitbucketServerRepositories } from "./bitbucket-server/discovery.js";
|
|
@@ -45,6 +49,21 @@ function azureAuthorization(token, isPAT) {
|
|
|
45
49
|
return isPAT ? `Basic ${base64(`:${token}`)}` : `Bearer ${token}`;
|
|
46
50
|
}
|
|
47
51
|
const azureDevOpsBaseUrl = "https://dev.azure.com";
|
|
52
|
+
/**
|
|
53
|
+
* The work items of an Azure list read that are in the states it asked for. provider-apis selects them by their closed
|
|
54
|
+
* and resolved dates (no state asks for open ones), while a row now also closes on its workflow category: a Removed work
|
|
55
|
+
* item has neither date, so an open read would otherwise list it, closed. A read of closed work items is left as the
|
|
56
|
+
* query selected it, since a resolved date alone selects one that carries no closed date or, when its type's states
|
|
57
|
+
* could not be read, no category; and it can't be completed either, as the query never selects a dateless one.
|
|
58
|
+
*/
|
|
59
|
+
function withRequestedAzureIssueStates(issues, states) {
|
|
60
|
+
if (!(!states?.length || states.includes(GitIssueState$1.Open) && !states.includes(GitIssueState$1.Closed))) return issues;
|
|
61
|
+
return issues.filter((i) => i.closedDate == null && !isTerminalIssueStateCategory(i.state?.category));
|
|
62
|
+
}
|
|
63
|
+
/** How long a work item type's states classify its work items before they are read again. */
|
|
64
|
+
const azureWorkItemTypeStatesTTL = 3e5;
|
|
65
|
+
/** The most work item type state reads kept, across hosts, projects, types and credentials. */
|
|
66
|
+
const azureWorkItemTypeStatesCapacity = 256;
|
|
48
67
|
/** The most group descriptors one identity batch read resolves. */
|
|
49
68
|
const azureIdentityBatchSize = 100;
|
|
50
69
|
/** Azure DevOps Services serves the identity APIs from its own host, below the organization like the main one. */
|
|
@@ -103,10 +122,32 @@ function fromTrelloCard(card, trelloBoardListsById) {
|
|
|
103
122
|
}))
|
|
104
123
|
};
|
|
105
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* One Jira search page as the drains read it: `nextCursor` is the raw provider cursor (Jira offset / nextPageToken)
|
|
127
|
+
* fed back verbatim as `options.cursor`, and `metadata` is the SDK's, kept only when it reported something.
|
|
128
|
+
*/
|
|
129
|
+
function toJiraIssuePage(result) {
|
|
130
|
+
if (result == null) return void 0;
|
|
131
|
+
return {
|
|
132
|
+
data: result.data,
|
|
133
|
+
hasMore: result.pageInfo?.hasNextPage ?? false,
|
|
134
|
+
nextCursor: result.pageInfo?.endCursor ?? void 0,
|
|
135
|
+
...result.metadata != null ? { metadata: result.metadata } : {}
|
|
136
|
+
};
|
|
137
|
+
}
|
|
106
138
|
var ProvidersApi = class {
|
|
107
139
|
authenticationService;
|
|
108
140
|
providers;
|
|
109
141
|
request;
|
|
142
|
+
/**
|
|
143
|
+
* Each work item type's states, by URL (host, organization, project and type) and credential: coalesces the reads
|
|
144
|
+
* of the same type, and never answers one credential with what another one read. A failed read is not kept, so the
|
|
145
|
+
* next read retries it.
|
|
146
|
+
*/
|
|
147
|
+
azureWorkItemTypeStates = new PromiseCache({
|
|
148
|
+
createTTL: azureWorkItemTypeStatesTTL,
|
|
149
|
+
capacity: azureWorkItemTypeStatesCapacity
|
|
150
|
+
});
|
|
110
151
|
constructor(authenticationService) {
|
|
111
152
|
this.authenticationService = authenticationService;
|
|
112
153
|
const http = authenticationService.ctx.http;
|
|
@@ -634,6 +675,7 @@ var ProvidersApi = class {
|
|
|
634
675
|
if (issue == null) throw new Error(`Azure DevOps returned no readable work item ${id}`);
|
|
635
676
|
const project = workItem?.fields?.["System.TeamProject"];
|
|
636
677
|
if (typeof project === "string" && project.toLowerCase() !== scope.project.toLowerCase()) throw new Error(`Azure DevOps work item ${id} is in project '${project}', not '${scope.project}'`);
|
|
678
|
+
await this.classifyAzureIssueStates([issue], tokenWithInfo, scope.namespace, scope.project, options);
|
|
637
679
|
return issue;
|
|
638
680
|
}
|
|
639
681
|
/**
|
|
@@ -641,8 +683,9 @@ var ProvidersApi = class {
|
|
|
641
683
|
* request, where {@link getAzureWorkItem} reads one work item per request, selecting only
|
|
642
684
|
* `azureWorkItemEtagFieldNames`. Asked with `errorPolicy=omit`, without which one missing id fails the whole
|
|
643
685
|
* request; Azure then leaves out every id it can't return, for whatever reason, so a caller matches the work items
|
|
644
|
-
* to its ids by `id`, never by position, and reads an omission as unknown rather than absent.
|
|
645
|
-
*
|
|
686
|
+
* to its ids by `id`, never by position, and reads an omission as unknown rather than absent. Each work item comes
|
|
687
|
+
* with the workflow category its state classifies to, as {@link getAzureWorkItem} classifies it. Every failure
|
|
688
|
+
* throws, classified as {@link getAzureWorkItem} classifies it, the states reads' included.
|
|
646
689
|
*/
|
|
647
690
|
async getAzureWorkItemsEtagFields(tokenOptInfo, scope, ids, options) {
|
|
648
691
|
const { tokenWithInfo } = await this.ensureProviderToken(tokenOptInfo);
|
|
@@ -656,7 +699,20 @@ var ProvidersApi = class {
|
|
|
656
699
|
headers: { Authorization: options.isPAT ? `Basic ${base64(`:${token}`)}` : `Bearer ${token}` }
|
|
657
700
|
})).body?.value;
|
|
658
701
|
if (!Array.isArray(workItems)) throw new Error("Azure DevOps returned no work items");
|
|
659
|
-
|
|
702
|
+
const readable = workItems.filter((w) => w != null);
|
|
703
|
+
const issues = readable.map((w) => {
|
|
704
|
+
const state = w.fields?.["System.State"];
|
|
705
|
+
const type = w.fields?.["System.WorkItemType"];
|
|
706
|
+
return {
|
|
707
|
+
type: typeof type === "string" ? type : void 0,
|
|
708
|
+
state: typeof state === "string" && state ? { name: state } : void 0
|
|
709
|
+
};
|
|
710
|
+
});
|
|
711
|
+
await this.classifyAzureIssueStates(issues, tokenWithInfo, scope.namespace, scope.project, options);
|
|
712
|
+
return readable.map((w, i) => ({
|
|
713
|
+
workItem: w,
|
|
714
|
+
category: issues[i].state?.category
|
|
715
|
+
}));
|
|
660
716
|
} catch (e) {
|
|
661
717
|
return this.handleProviderError(tokenWithInfo, e);
|
|
662
718
|
}
|
|
@@ -1088,11 +1144,88 @@ var ProvidersApi = class {
|
|
|
1088
1144
|
}
|
|
1089
1145
|
async getIssuesForAzureProject(tokenOptInfo, namespace, project, options) {
|
|
1090
1146
|
const { provider, tokenWithInfo } = await this.ensureProviderTokenAndFunction(tokenOptInfo, "getIssuesForAzureProjectFn");
|
|
1091
|
-
|
|
1147
|
+
const result = await this.getPagedResult({
|
|
1092
1148
|
namespace,
|
|
1093
1149
|
project,
|
|
1094
1150
|
...options
|
|
1095
1151
|
}, provider.getIssuesForAzureProjectFn, tokenWithInfo, options?.cursor, options?.isPAT, options?.baseUrl);
|
|
1152
|
+
try {
|
|
1153
|
+
await this.classifyAzureIssueStates(result.values, tokenWithInfo, namespace, project, options);
|
|
1154
|
+
} catch (ex) {
|
|
1155
|
+
return {
|
|
1156
|
+
...result,
|
|
1157
|
+
values: withRequestedAzureIssueStates(result.values, options?.states),
|
|
1158
|
+
paging: {
|
|
1159
|
+
...result.paging ?? {
|
|
1160
|
+
cursor: "{}",
|
|
1161
|
+
more: false
|
|
1162
|
+
},
|
|
1163
|
+
truncated: true
|
|
1164
|
+
},
|
|
1165
|
+
metadata: mergeCollectionMetadata(result.metadata, {
|
|
1166
|
+
completeness: "partial",
|
|
1167
|
+
failures: [toCollectionScopeFailure({
|
|
1168
|
+
providerId: tokenWithInfo.providerId,
|
|
1169
|
+
resourceId: namespace,
|
|
1170
|
+
projectId: project
|
|
1171
|
+
}, ex)]
|
|
1172
|
+
})
|
|
1173
|
+
};
|
|
1174
|
+
}
|
|
1175
|
+
return {
|
|
1176
|
+
...result,
|
|
1177
|
+
values: withRequestedAzureIssueStates(result.values, options?.states)
|
|
1178
|
+
};
|
|
1179
|
+
}
|
|
1180
|
+
/**
|
|
1181
|
+
* Gives each of `issues` with both a type and a state the workflow category of that state, from its type's states
|
|
1182
|
+
* (see {@link azureWorkItemTypeStates}): `undefined` for a state the type doesn't list. Keyed on the raw
|
|
1183
|
+
* `System.State`, which is the state name on every Azure read here because core passes the SDK no state-name map;
|
|
1184
|
+
* passing one would break the lookup.
|
|
1185
|
+
*
|
|
1186
|
+
* Reads each distinct type once, a bounded number at a time. A type whose read fails leaves its issues untouched,
|
|
1187
|
+
* after the other types' issues are classified, and the first failure then rejects, classified by
|
|
1188
|
+
* {@link handleProviderError}.
|
|
1189
|
+
*/
|
|
1190
|
+
async classifyAzureIssueStates(issues, tokenWithInfo, namespace, project, options) {
|
|
1191
|
+
const baseUrl = options?.baseUrl ?? azureDevOpsBaseUrl;
|
|
1192
|
+
const types = [...new Set(issues.flatMap((i) => i.state?.name && i.type ? [i.type] : []))];
|
|
1193
|
+
if (!types.length) return;
|
|
1194
|
+
const token = tokenWithInfo.accessToken;
|
|
1195
|
+
const results = await mapSettledBounded(types, 6, async (type) => {
|
|
1196
|
+
const url = getAzureWorkItemTypeStatesUrl(baseUrl, namespace, project, type);
|
|
1197
|
+
return [type, await this.azureWorkItemTypeStates.getOrCreate(JSON.stringify([
|
|
1198
|
+
baseUrl.replace(/\/$/, ""),
|
|
1199
|
+
namespace.toLowerCase(),
|
|
1200
|
+
project.toLowerCase(),
|
|
1201
|
+
type.toLowerCase(),
|
|
1202
|
+
token,
|
|
1203
|
+
options?.isPAT === true
|
|
1204
|
+
]), async () => {
|
|
1205
|
+
try {
|
|
1206
|
+
const response = await this.request({
|
|
1207
|
+
url,
|
|
1208
|
+
headers: { Authorization: azureAuthorization(token, options?.isPAT) }
|
|
1209
|
+
});
|
|
1210
|
+
return parseAzureWorkItemTypeStates(response.body);
|
|
1211
|
+
} catch (ex) {
|
|
1212
|
+
return this.handleProviderError(tokenWithInfo, ex);
|
|
1213
|
+
}
|
|
1214
|
+
})];
|
|
1215
|
+
});
|
|
1216
|
+
const statesByType = /* @__PURE__ */ new Map();
|
|
1217
|
+
let failure;
|
|
1218
|
+
for (const result of results) if (result.status === "fulfilled") statesByType.set(result.value[0], result.value[1]);
|
|
1219
|
+
else failure ??= result;
|
|
1220
|
+
for (const issue of issues) {
|
|
1221
|
+
const states = issue.type ? statesByType.get(issue.type) : void 0;
|
|
1222
|
+
if (states == null || issue.state == null) continue;
|
|
1223
|
+
issue.state = {
|
|
1224
|
+
...issue.state,
|
|
1225
|
+
category: states.get(issue.state.name)
|
|
1226
|
+
};
|
|
1227
|
+
}
|
|
1228
|
+
if (failure != null) throw failure.reason;
|
|
1096
1229
|
}
|
|
1097
1230
|
async getIssuesForProject(tokenOptInfo, project, resourceId, options) {
|
|
1098
1231
|
const { provider, tokenWithInfo } = await this.ensureProviderTokenAndFunction(tokenOptInfo, "getIssuesForProjectFn");
|
|
@@ -1117,18 +1250,12 @@ var ProvidersApi = class {
|
|
|
1117
1250
|
const { provider, tokenWithInfo } = await this.ensureProviderTokenAndFunction(tokenOptInfo, "getIssuesForProjectFn");
|
|
1118
1251
|
const token = tokenWithInfo.accessToken;
|
|
1119
1252
|
try {
|
|
1120
|
-
|
|
1253
|
+
return toJiraIssuePage(await provider.getIssuesForProjectFn?.({
|
|
1121
1254
|
projectKey: project,
|
|
1122
1255
|
resourceId,
|
|
1123
1256
|
...options,
|
|
1124
1257
|
includeTransitions: jiraListIncludeTransitions
|
|
1125
|
-
}, { token });
|
|
1126
|
-
if (result == null) return void 0;
|
|
1127
|
-
return {
|
|
1128
|
-
data: result.data,
|
|
1129
|
-
hasMore: result.pageInfo?.hasNextPage ?? false,
|
|
1130
|
-
nextCursor: result.pageInfo?.endCursor ?? void 0
|
|
1131
|
-
};
|
|
1258
|
+
}, { token }));
|
|
1132
1259
|
} catch (e) {
|
|
1133
1260
|
return this.handleProviderError(tokenWithInfo, e);
|
|
1134
1261
|
}
|
|
@@ -1166,20 +1293,14 @@ var ProvidersApi = class {
|
|
|
1166
1293
|
async getJiraServerIssuesForProjectPaged(tokenOptInfo, baseUrl, projectKey, options) {
|
|
1167
1294
|
const { provider, tokenWithInfo } = await this.ensureProviderTokenAndFunction(tokenOptInfo, "getJiraServerIssuesForProjectFn");
|
|
1168
1295
|
try {
|
|
1169
|
-
|
|
1296
|
+
return toJiraIssuePage(await provider.getJiraServerIssuesForProjectFn?.({
|
|
1170
1297
|
projectKey,
|
|
1171
1298
|
...options,
|
|
1172
1299
|
includeTransitions: jiraListIncludeTransitions
|
|
1173
1300
|
}, {
|
|
1174
1301
|
token: tokenWithInfo.accessToken,
|
|
1175
1302
|
baseUrl
|
|
1176
|
-
});
|
|
1177
|
-
if (result == null) return void 0;
|
|
1178
|
-
return {
|
|
1179
|
-
data: result.data,
|
|
1180
|
-
hasMore: result.pageInfo?.hasNextPage ?? false,
|
|
1181
|
-
nextCursor: result.pageInfo?.endCursor ?? void 0
|
|
1182
|
-
};
|
|
1303
|
+
}));
|
|
1183
1304
|
} catch (e) {
|
|
1184
1305
|
return this.handleProviderError(tokenWithInfo, e);
|
|
1185
1306
|
}
|
|
@@ -1192,20 +1313,14 @@ var ProvidersApi = class {
|
|
|
1192
1313
|
async getJiraServerIssuesForProjectsPaged(tokenOptInfo, baseUrl, projectKeys, options) {
|
|
1193
1314
|
const { provider, tokenWithInfo } = await this.ensureProviderTokenAndFunction(tokenOptInfo, "getJiraServerIssuesForProjectsFn");
|
|
1194
1315
|
try {
|
|
1195
|
-
|
|
1316
|
+
return toJiraIssuePage(await provider.getJiraServerIssuesForProjectsFn?.({
|
|
1196
1317
|
projectKeys,
|
|
1197
1318
|
...options,
|
|
1198
1319
|
includeTransitions: jiraListIncludeTransitions
|
|
1199
1320
|
}, {
|
|
1200
1321
|
token: tokenWithInfo.accessToken,
|
|
1201
1322
|
baseUrl
|
|
1202
|
-
});
|
|
1203
|
-
if (result == null) return void 0;
|
|
1204
|
-
return {
|
|
1205
|
-
data: result.data,
|
|
1206
|
-
hasMore: result.pageInfo?.hasNextPage ?? false,
|
|
1207
|
-
nextCursor: result.pageInfo?.endCursor ?? void 0
|
|
1208
|
-
};
|
|
1323
|
+
}));
|
|
1209
1324
|
} catch (e) {
|
|
1210
1325
|
return this.handleProviderError(tokenWithInfo, e);
|
|
1211
1326
|
}
|
|
@@ -1226,7 +1341,7 @@ var ProvidersApi = class {
|
|
|
1226
1341
|
async getJiraServerIssuesForCurrentUser(tokenOptInfo, baseUrl, options) {
|
|
1227
1342
|
const { provider, tokenWithInfo } = await this.ensureProviderTokenAndFunction(tokenOptInfo, "getJiraServerIssuesForCurrentUserFn");
|
|
1228
1343
|
try {
|
|
1229
|
-
|
|
1344
|
+
return toJiraIssuePage(await provider.getJiraServerIssuesForCurrentUserFn?.({
|
|
1230
1345
|
cursor: options?.cursor,
|
|
1231
1346
|
states: options?.states,
|
|
1232
1347
|
sort: options?.sort,
|
|
@@ -1234,13 +1349,7 @@ var ProvidersApi = class {
|
|
|
1234
1349
|
}, {
|
|
1235
1350
|
token: tokenWithInfo.accessToken,
|
|
1236
1351
|
baseUrl
|
|
1237
|
-
});
|
|
1238
|
-
if (result == null) return void 0;
|
|
1239
|
-
return {
|
|
1240
|
-
data: result.data,
|
|
1241
|
-
hasMore: result.pageInfo?.hasNextPage ?? false,
|
|
1242
|
-
nextCursor: result.pageInfo?.endCursor ?? void 0
|
|
1243
|
-
};
|
|
1352
|
+
}));
|
|
1244
1353
|
} catch (e) {
|
|
1245
1354
|
return this.handleProviderError(tokenWithInfo, e);
|
|
1246
1355
|
}
|
|
@@ -1254,18 +1363,12 @@ var ProvidersApi = class {
|
|
|
1254
1363
|
const { provider, tokenWithInfo } = await this.ensureProviderTokenAndFunction(tokenOptInfo, "getIssuesForProjectsFn");
|
|
1255
1364
|
const token = tokenWithInfo.accessToken;
|
|
1256
1365
|
try {
|
|
1257
|
-
|
|
1366
|
+
return toJiraIssuePage(await provider.getIssuesForProjectsFn?.({
|
|
1258
1367
|
projectKeys,
|
|
1259
1368
|
resourceId,
|
|
1260
1369
|
...options,
|
|
1261
1370
|
includeTransitions: jiraListIncludeTransitions
|
|
1262
|
-
}, { token });
|
|
1263
|
-
if (result == null) return void 0;
|
|
1264
|
-
return {
|
|
1265
|
-
data: result.data,
|
|
1266
|
-
hasMore: result.pageInfo?.hasNextPage ?? false,
|
|
1267
|
-
nextCursor: result.pageInfo?.endCursor ?? void 0
|
|
1268
|
-
};
|
|
1371
|
+
}, { token }));
|
|
1269
1372
|
} catch (e) {
|
|
1270
1373
|
return this.handleProviderError(tokenWithInfo, e);
|
|
1271
1374
|
}
|