@gitkraken/core-gitlens 0.5.114 → 0.5.116
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 +38 -1
- package/dist/plus/git-github/api/github.d.ts +3 -2
- package/dist/plus/git-github/api/github.d.ts.map +1 -1
- package/dist/plus/git-github/api/github.js +37 -37
- package/dist/plus/git-github/api/github.js.map +1 -1
- package/dist/plus/integrations/collectionMetadata.d.ts +2 -0
- package/dist/plus/integrations/collectionMetadata.d.ts.map +1 -1
- package/dist/plus/integrations/collectionMetadata.js +17 -1
- package/dist/plus/integrations/collectionMetadata.js.map +1 -1
- package/dist/plus/integrations/context.d.ts +4 -1
- package/dist/plus/integrations/context.d.ts.map +1 -1
- package/dist/plus/integrations/index.d.ts +1 -0
- package/dist/plus/integrations/index.d.ts.map +1 -1
- package/dist/plus/integrations/integrationService.d.ts +9 -1
- package/dist/plus/integrations/integrationService.d.ts.map +1 -1
- package/dist/plus/integrations/integrationService.js +8 -4
- package/dist/plus/integrations/integrationService.js.map +1 -1
- package/dist/plus/integrations/manager.d.ts +65 -6
- package/dist/plus/integrations/manager.d.ts.map +1 -1
- package/dist/plus/integrations/models/gitHostIntegration.d.ts +22 -26
- package/dist/plus/integrations/models/gitHostIntegration.d.ts.map +1 -1
- package/dist/plus/integrations/models/gitHostIntegration.js +92 -47
- package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
- package/dist/plus/integrations/models/integration.d.ts +9 -0
- package/dist/plus/integrations/models/integration.d.ts.map +1 -1
- package/dist/plus/integrations/models/integration.js +52 -19
- package/dist/plus/integrations/models/integration.js.map +1 -1
- package/dist/plus/integrations/models/issueCache.d.ts +16 -0
- package/dist/plus/integrations/models/issueCache.d.ts.map +1 -0
- package/dist/plus/integrations/models/issueCache.js +9 -0
- package/dist/plus/integrations/models/issueCache.js.map +1 -0
- package/dist/plus/integrations/models/issueReads.d.ts +13 -0
- package/dist/plus/integrations/models/issueReads.d.ts.map +1 -1
- package/dist/plus/integrations/models/issuesIntegration.d.ts +11 -13
- package/dist/plus/integrations/models/issuesIntegration.d.ts.map +1 -1
- package/dist/plus/integrations/models/issuesIntegration.js +15 -1
- package/dist/plus/integrations/models/issuesIntegration.js.map +1 -1
- package/dist/plus/integrations/providers/azureDevOps.d.ts +3 -5
- package/dist/plus/integrations/providers/azureDevOps.d.ts.map +1 -1
- package/dist/plus/integrations/providers/azureDevOps.js +9 -8
- package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket-server.d.ts +3 -5
- package/dist/plus/integrations/providers/bitbucket-server.d.ts.map +1 -1
- package/dist/plus/integrations/providers/bitbucket-server.js +2 -2
- package/dist/plus/integrations/providers/bitbucket-server.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket.d.ts +3 -5
- package/dist/plus/integrations/providers/bitbucket.d.ts.map +1 -1
- package/dist/plus/integrations/providers/bitbucket.js +2 -1
- package/dist/plus/integrations/providers/bitbucket.js.map +1 -1
- package/dist/plus/integrations/providers/github.d.ts +3 -5
- package/dist/plus/integrations/providers/github.d.ts.map +1 -1
- package/dist/plus/integrations/providers/github.js +3 -3
- package/dist/plus/integrations/providers/github.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab.d.ts +3 -5
- package/dist/plus/integrations/providers/gitlab.d.ts.map +1 -1
- package/dist/plus/integrations/providers/gitlab.js +2 -2
- package/dist/plus/integrations/providers/gitlab.js.map +1 -1
- package/dist/plus/integrations/providers/jira.d.ts +3 -7
- package/dist/plus/integrations/providers/jira.d.ts.map +1 -1
- package/dist/plus/integrations/providers/jira.js +35 -22
- package/dist/plus/integrations/providers/jira.js.map +1 -1
- package/dist/plus/integrations/providers/jiraIssueByKey.d.ts +7 -0
- package/dist/plus/integrations/providers/jiraIssueByKey.d.ts.map +1 -0
- package/dist/plus/integrations/providers/jiraIssueByKey.js +102 -0
- package/dist/plus/integrations/providers/jiraIssueByKey.js.map +1 -0
- package/dist/plus/integrations/providers/linear.d.ts +3 -7
- package/dist/plus/integrations/providers/linear.d.ts.map +1 -1
- package/dist/plus/integrations/providers/linear.js +23 -22
- package/dist/plus/integrations/providers/linear.js.map +1 -1
- package/dist/plus/integrations/providers/models.d.ts +3 -1
- package/dist/plus/integrations/providers/models.d.ts.map +1 -1
- package/dist/plus/integrations/providers/models.js +10 -4
- package/dist/plus/integrations/providers/models.js.map +1 -1
- package/dist/plus/integrations/providers/providerErrors.d.ts +7 -0
- package/dist/plus/integrations/providers/providerErrors.d.ts.map +1 -0
- package/dist/plus/integrations/providers/providerErrors.js +91 -0
- package/dist/plus/integrations/providers/providerErrors.js.map +1 -0
- package/dist/plus/integrations/providers/providersApi.d.ts +3 -2
- package/dist/plus/integrations/providers/providersApi.d.ts.map +1 -1
- package/dist/plus/integrations/providers/providersApi.js +18 -52
- package/dist/plus/integrations/providers/providersApi.js.map +1 -1
- package/dist/plus/integrations/providers/trello.d.ts +2 -7
- package/dist/plus/integrations/providers/trello.d.ts.map +1 -1
- package/dist/plus/integrations/providers/trello.js +3 -1
- package/dist/plus/integrations/providers/trello.js.map +1 -1
- package/dist/plus/integrations/providers/utils/providerPaging.d.ts +2 -0
- package/dist/plus/integrations/providers/utils/providerPaging.d.ts.map +1 -1
- package/dist/plus/integrations/providers/utils/providerPaging.js +12 -7
- package/dist/plus/integrations/providers/utils/providerPaging.js.map +1 -1
- package/dist/plus/integrations/reads/broaden.d.ts.map +1 -1
- package/dist/plus/integrations/reads/broaden.js +26 -14
- package/dist/plus/integrations/reads/broaden.js.map +1 -1
- package/dist/plus/integrations/reads/counts.d.ts.map +1 -1
- package/dist/plus/integrations/reads/counts.js +39 -15
- package/dist/plus/integrations/reads/counts.js.map +1 -1
- package/dist/plus/integrations/reads/filters.d.ts +33 -11
- package/dist/plus/integrations/reads/filters.d.ts.map +1 -1
- package/dist/plus/integrations/reads/filters.js +114 -25
- package/dist/plus/integrations/reads/filters.js.map +1 -1
- package/dist/plus/integrations/reads/issueTracker.d.ts.map +1 -1
- package/dist/plus/integrations/reads/issueTracker.js +23 -17
- package/dist/plus/integrations/reads/issueTracker.js.map +1 -1
- package/dist/plus/integrations/reads/searchIssues.d.ts +1 -5
- package/dist/plus/integrations/reads/searchIssues.d.ts.map +1 -1
- package/dist/plus/integrations/reads/searchIssues.js +12 -6
- package/dist/plus/integrations/reads/searchIssues.js.map +1 -1
- package/dist/plus/integrations/reads/searchPullRequests.d.ts +1 -0
- package/dist/plus/integrations/reads/searchPullRequests.d.ts.map +1 -1
- package/dist/plus/integrations/reads/searchPullRequests.js +8 -3
- package/dist/plus/integrations/reads/searchPullRequests.js.map +1 -1
- package/dist/plus/integrations/reads/trackerIssue.d.ts +21 -0
- package/dist/plus/integrations/reads/trackerIssue.d.ts.map +1 -0
- package/dist/plus/integrations/reads/trackerIssue.js +51 -0
- package/dist/plus/integrations/reads/trackerIssue.js.map +1 -0
- package/dist/plus/integrations/reads/warnings.d.ts +18 -15
- package/dist/plus/integrations/reads/warnings.d.ts.map +1 -1
- package/dist/plus/integrations/reads/warnings.js +37 -1
- package/dist/plus/integrations/reads/warnings.js.map +1 -1
- package/dist/plus/integrations/results.d.ts +4 -20
- package/dist/plus/integrations/results.d.ts.map +1 -1
- package/dist/plus/integrations/results.js.map +1 -1
- package/dist/utils/promise.d.ts +2 -0
- package/dist/utils/promise.d.ts.map +1 -1
- package/dist/utils/promise.js +11 -0
- package/dist/utils/promise.js.map +1 -1
- package/docs/integrations.md +63 -28
- package/docs/kepler-read-api-parity.md +13 -0
- package/package.json +2 -2
- package/src/plus/git-github/api/github.ts +54 -60
- package/src/plus/integrations/collectionMetadata.ts +23 -1
- package/src/plus/integrations/context.ts +1 -1
- package/src/plus/integrations/index.ts +1 -0
- package/src/plus/integrations/integrationService.ts +14 -4
- package/src/plus/integrations/manager.ts +65 -6
- package/src/plus/integrations/models/gitHostIntegration.ts +117 -129
- package/src/plus/integrations/models/integration.ts +56 -22
- package/src/plus/integrations/models/issueCache.ts +29 -0
- package/src/plus/integrations/models/issueReads.ts +15 -0
- package/src/plus/integrations/models/issuesIntegration.ts +38 -8
- package/src/plus/integrations/providers/azureDevOps.ts +16 -13
- package/src/plus/integrations/providers/bitbucket-server.ts +4 -6
- package/src/plus/integrations/providers/bitbucket.ts +3 -4
- package/src/plus/integrations/providers/github.ts +5 -7
- package/src/plus/integrations/providers/gitlab.ts +4 -6
- package/src/plus/integrations/providers/jira.ts +52 -26
- package/src/plus/integrations/providers/jiraIssueByKey.ts +155 -0
- package/src/plus/integrations/providers/linear.ts +38 -25
- package/src/plus/integrations/providers/models.ts +17 -5
- package/src/plus/integrations/providers/providerErrors.ts +115 -0
- package/src/plus/integrations/providers/providersApi.ts +26 -68
- package/src/plus/integrations/providers/trello.ts +5 -4
- package/src/plus/integrations/providers/utils/providerPaging.ts +14 -7
- package/src/plus/integrations/reads/broaden.ts +35 -16
- package/src/plus/integrations/reads/counts.ts +62 -15
- package/src/plus/integrations/reads/filters.ts +131 -29
- package/src/plus/integrations/reads/issueTracker.ts +26 -24
- package/src/plus/integrations/reads/searchIssues.ts +23 -13
- package/src/plus/integrations/reads/searchPullRequests.ts +16 -2
- package/src/plus/integrations/reads/trackerIssue.ts +105 -0
- package/src/plus/integrations/reads/warnings.ts +42 -17
- package/src/plus/integrations/results.ts +4 -20
- package/src/utils/promise.ts +15 -0
|
@@ -17,6 +17,7 @@ import type {
|
|
|
17
17
|
} from './reads/counts.js';
|
|
18
18
|
import type { SupportedFilters } from './reads/filters.js';
|
|
19
19
|
import type { IssueBatchResult, IssueBatchTarget } from './reads/issueBatch.js';
|
|
20
|
+
import type { TrackerIssueResult } from './reads/trackerIssue.js';
|
|
20
21
|
import type {
|
|
21
22
|
ConnectionStateChangeEvent,
|
|
22
23
|
ProviderBroadenResult,
|
|
@@ -403,15 +404,36 @@ export interface IntegrationManager {
|
|
|
403
404
|
*/
|
|
404
405
|
searchPullRequestsPage(options: {
|
|
405
406
|
providerId: IntegrationIds;
|
|
406
|
-
/**
|
|
407
|
+
/**
|
|
408
|
+
* Repository descriptors that bound the search; ids cannot name provider search qualifiers.
|
|
409
|
+
*
|
|
410
|
+
* Both halves of a descriptor must reach the provider unchanged — see `org` — since a search names a
|
|
411
|
+
* repository by its `namespace/name` path.
|
|
412
|
+
*/
|
|
407
413
|
repos?: ProviderRepositoriesInput;
|
|
408
|
-
/**
|
|
414
|
+
/**
|
|
415
|
+
* Organization/account that bounds the search.
|
|
416
|
+
*
|
|
417
|
+
* Held to a STRICTER rule than the free-form `criteria.text`, which is sanitized: a scope name carrying a
|
|
418
|
+
* quote, or an inner space or control character, is REFUSED (warning + `fetchFailed`), and the refusal
|
|
419
|
+
* names the value. Leading and trailing whitespace and control characters are stripped and accepted,
|
|
420
|
+
* since removing them cannot change which scope the query names. Sanitizing a scope would answer the wrong question — the sanitized value may name a real but
|
|
421
|
+
* DIFFERENT organization, whose result looks entirely normal. Pass the name exactly as the provider spells
|
|
422
|
+
* it; `''` means "no org supplied" and falls through to the other scopes.
|
|
423
|
+
*/
|
|
409
424
|
org?: string;
|
|
410
425
|
criteria?: PullRequestSearchCriteria;
|
|
411
426
|
/** Cursor-only: without a cursor, reaching page N costs O(N) upstream requests. */
|
|
412
427
|
page?: number;
|
|
413
428
|
cursor?: string;
|
|
414
|
-
/**
|
|
429
|
+
/**
|
|
430
|
+
* Page size PER RELATIONSHIP × STATE facet, not per page. Each facet is its own aliased provider query —
|
|
431
|
+
* one axis more than {@link searchIssuesPage}'s per-relationship fan-out — so a page of a 3-relationship,
|
|
432
|
+
* 2-state search returns up to `6 × itemsPerPage` items before deduplication, and fewer than that where
|
|
433
|
+
* the facets overlap. Deduplication does NOT bring the page back to this size: it removes only the rows the
|
|
434
|
+
* facets share. `page.itemsPerPage` reports what actually came back, so size the UI off that rather than
|
|
435
|
+
* off this. A provider may also cap it below what is asked for.
|
|
436
|
+
*/
|
|
415
437
|
itemsPerPage?: number;
|
|
416
438
|
forceSync?: boolean;
|
|
417
439
|
connectionId?: string;
|
|
@@ -419,7 +441,9 @@ export interface IntegrationManager {
|
|
|
419
441
|
domain?: string;
|
|
420
442
|
/**
|
|
421
443
|
* Requests the lightweight row shape: identity, body, author, repository, branch refs and stack info,
|
|
422
|
-
* without review, check or diff statistics. It also
|
|
444
|
+
* without review, check or diff statistics. It also replaces the flat per-facet default page size with a
|
|
445
|
+
* fixed budget shared across the search's ACTIVE facets, so with up to three of them it raises the page
|
|
446
|
+
* and from four on it LOWERS it — measured against GitHub, a 100-row budget versus a flat 30 each.
|
|
423
447
|
*
|
|
424
448
|
* A provider without a lightweight projection ignores it and returns its usual shape, so this is a hint
|
|
425
449
|
* rather than a contract about which fields are present.
|
|
@@ -512,9 +536,23 @@ export interface IntegrationManager {
|
|
|
512
536
|
*/
|
|
513
537
|
searchIssuesPage(options: {
|
|
514
538
|
providerId: IntegrationIds;
|
|
515
|
-
/**
|
|
539
|
+
/**
|
|
540
|
+
* Repositories to search. Combines with `org`; both constrain the same query.
|
|
541
|
+
*
|
|
542
|
+
* Both halves of a descriptor must reach the provider unchanged — see `org` — since a search names a
|
|
543
|
+
* repository by its `namespace/name` path.
|
|
544
|
+
*/
|
|
516
545
|
repos?: ProviderRepositoriesInput;
|
|
517
|
-
/**
|
|
546
|
+
/**
|
|
547
|
+
* Organization/account to search. Combines with `repos`.
|
|
548
|
+
*
|
|
549
|
+
* Held to a STRICTER rule than the free-form criteria, which are sanitized: a scope name carrying a quote,
|
|
550
|
+
* or an inner space or control character, is REFUSED (warning + `fetchFailed`), and the refusal names the
|
|
551
|
+
* value. Leading and trailing whitespace and control characters are stripped and accepted, since removing
|
|
552
|
+
* them cannot change which scope the query names.
|
|
553
|
+
* The sanitized value may name a real but DIFFERENT org, whose result looks entirely normal. `''` means
|
|
554
|
+
* "no org supplied" and falls through to the other scopes.
|
|
555
|
+
*/
|
|
518
556
|
org?: string;
|
|
519
557
|
criteria?: IssueSearchCriteria;
|
|
520
558
|
/**
|
|
@@ -589,6 +627,27 @@ export interface IntegrationManager {
|
|
|
589
627
|
/** Self-managed host domain fallback; see {@link ProviderSweepTarget.domain}. */
|
|
590
628
|
domain?: string;
|
|
591
629
|
}): Promise<ProviderResult<IssueBatchResult>>;
|
|
630
|
+
/**
|
|
631
|
+
* Resolves one issue-tracker issue by key within a resource — the tracker counterpart of
|
|
632
|
+
* {@link getIssuesBatch}, which cannot serve one.
|
|
633
|
+
*
|
|
634
|
+
* `issue: undefined` is a proven absence and may be cached. A failed read returns no item and sets
|
|
635
|
+
* `fetchFailed`. `resourceId` is required and trusted; Jira also requires the resource's site URL so the result
|
|
636
|
+
* retains its browser link. The read performs no resource discovery.
|
|
637
|
+
*
|
|
638
|
+
* Jira and Linear only. Trello refuses: its single-issue read falls back to a capped board scan for a numeric
|
|
639
|
+
* identifier, so it cannot prove absence.
|
|
640
|
+
*/
|
|
641
|
+
getTrackerIssue(options: {
|
|
642
|
+
providerId: IntegrationIds;
|
|
643
|
+
/** Provider resource ID for the Atlassian site or Linear workspace. */
|
|
644
|
+
resourceId: string;
|
|
645
|
+
/** Jira site URL from resource discovery. Required for Jira so the result retains a browser link. */
|
|
646
|
+
resourceUrl?: string;
|
|
647
|
+
/** The provider's own key, e.g. `ABC-123`. Not a number. */
|
|
648
|
+
key: string;
|
|
649
|
+
connectionId?: string;
|
|
650
|
+
}): Promise<ProviderResult<TrackerIssueResult>>;
|
|
592
651
|
/**
|
|
593
652
|
* How many pull requests match each scope, fetching none of them — the PR twin of {@link countIssues}, behind a
|
|
594
653
|
* "this will fetch ~N pull requests" preview and a live count next to an unapplied filter. Same cost model,
|
|
@@ -13,6 +13,7 @@ import type {
|
|
|
13
13
|
import type { RepositoryMetadata } from '../../../git/models/repositoryMetadata.js';
|
|
14
14
|
import type { ResourceDescriptor } from '../../../git/models/resourceDescriptor.js';
|
|
15
15
|
import type { PullRequestUrlIdentity } from '../../../git/utils/pullRequest.utils.js';
|
|
16
|
+
import { ensureArray } from '../../../utils/array.js';
|
|
16
17
|
import { isCancellationError } from '../../../utils/cancellation.js';
|
|
17
18
|
import { gate } from '../../../utils/decorators/gate.js';
|
|
18
19
|
import { trace } from '../../../utils/decorators/log.js';
|
|
@@ -22,7 +23,11 @@ import { getScopedLogger } from '../../../utils/logger.scoped.js';
|
|
|
22
23
|
import type { PagedResult } from '../../../utils/paging.js';
|
|
23
24
|
import type { ProviderAuthenticationSession } from '../authentication/models.js';
|
|
24
25
|
import { toTokenWithInfo } from '../authentication/models.js';
|
|
25
|
-
import {
|
|
26
|
+
import {
|
|
27
|
+
throwIfCallerContractError,
|
|
28
|
+
toCollectionFailureError,
|
|
29
|
+
toCollectionScopeFailure,
|
|
30
|
+
} from '../collectionMetadata.js';
|
|
26
31
|
import type { IntegrationIds } from '../constants.js';
|
|
27
32
|
import { GitCloudHostIntegrationId, GitSelfManagedHostIntegrationId } from '../constants.js';
|
|
28
33
|
import { toError } from '../errors.js';
|
|
@@ -50,7 +55,7 @@ import {
|
|
|
50
55
|
toProviderPullRequestStates,
|
|
51
56
|
} from '../providers/models.js';
|
|
52
57
|
import type { ProvidersApi } from '../providers/providersApi.js';
|
|
53
|
-
import { mergeCollectionMetadata } from '../providers/utils/providerPaging.js';
|
|
58
|
+
import { mergeCollectionMetadata, throwIfAllSettledFailed } from '../providers/utils/providerPaging.js';
|
|
54
59
|
import type {
|
|
55
60
|
IntegrationResult,
|
|
56
61
|
IntegrationType,
|
|
@@ -113,10 +118,24 @@ function getSelfManagedApiBaseUrl(
|
|
|
113
118
|
}
|
|
114
119
|
}
|
|
115
120
|
|
|
121
|
+
/** Read options for {@link GitHostIntegration.searchMyPullRequests} and the provider hook behind it. */
|
|
116
122
|
export type SearchMyPullRequestsOptions = {
|
|
123
|
+
/** Suppresses the user-facing notification when the read fails. */
|
|
124
|
+
silent?: boolean;
|
|
125
|
+
/**
|
|
126
|
+
* PR states to include (open/closed/merged/all). Providers that cannot express it in a single query
|
|
127
|
+
* filter the normalized results; omitted preserves the historical open-only behavior.
|
|
128
|
+
*/
|
|
129
|
+
state?: PullRequestStateFilter;
|
|
117
130
|
includeReviewRequested?: boolean;
|
|
118
131
|
};
|
|
119
132
|
|
|
133
|
+
/** Read options for {@link GitHostIntegration.searchPullRequests} and the provider hook behind it. */
|
|
134
|
+
export type SearchPullRequestsOptions = {
|
|
135
|
+
/** PR states to include; omitted preserves the provider's default. */
|
|
136
|
+
include?: PullRequestState[];
|
|
137
|
+
};
|
|
138
|
+
|
|
120
139
|
type MyPullRequestsForReposOptions = {
|
|
121
140
|
filters?: PullRequestFilter[];
|
|
122
141
|
cursor?: string;
|
|
@@ -747,10 +766,17 @@ export abstract class GitHostIntegration<
|
|
|
747
766
|
const customUrl =
|
|
748
767
|
options?.customUrl ?? getSelfManagedApiBaseUrl(providerId, session.domain || this.domain, session.protocol);
|
|
749
768
|
|
|
750
|
-
|
|
769
|
+
let api: ProvidersApi;
|
|
770
|
+
try {
|
|
771
|
+
api = await this.getProvidersApi();
|
|
772
|
+
} catch (ex) {
|
|
773
|
+
this.handleProviderException('getIssuesForRepos', ex, { scope: scope, connectionId: connectionId });
|
|
774
|
+
return { error: toError(ex), duration: performance.now() - start };
|
|
775
|
+
}
|
|
776
|
+
const repoIdsInput = api.isRepoIdsInput(reposOrRepoIds);
|
|
751
777
|
if (
|
|
752
778
|
providerId !== GitCloudHostIntegrationId.GitLab &&
|
|
753
|
-
(
|
|
779
|
+
(repoIdsInput ||
|
|
754
780
|
(isAzureDevOpsProvider(providerId) &&
|
|
755
781
|
!reposOrRepoIds.every(repo => repo.project != null && repo.namespace != null)))
|
|
756
782
|
) {
|
|
@@ -791,7 +817,10 @@ export abstract class GitHostIntegration<
|
|
|
791
817
|
try {
|
|
792
818
|
userAccount = await this.getFilterAccount(api, session, customUrl, organization);
|
|
793
819
|
} catch (ex) {
|
|
794
|
-
|
|
820
|
+
this.handleProviderException('getIssuesForRepos', ex, {
|
|
821
|
+
scope: scope,
|
|
822
|
+
connectionId: connectionId,
|
|
823
|
+
});
|
|
795
824
|
return { error: toError(ex), duration: performance.now() - start };
|
|
796
825
|
}
|
|
797
826
|
|
|
@@ -861,6 +890,7 @@ export abstract class GitHostIntegration<
|
|
|
861
890
|
return { projectInput: projectInput, results: results };
|
|
862
891
|
}),
|
|
863
892
|
);
|
|
893
|
+
throwIfAllSettledFailed(settled);
|
|
864
894
|
|
|
865
895
|
for (let i = 0; i < settled.length; i++) {
|
|
866
896
|
const outcome = settled[i];
|
|
@@ -904,6 +934,7 @@ export abstract class GitHostIntegration<
|
|
|
904
934
|
cursor.page = options.page;
|
|
905
935
|
}
|
|
906
936
|
|
|
937
|
+
this.resetRequestExceptionCount('getIssuesForRepos');
|
|
907
938
|
return {
|
|
908
939
|
value: {
|
|
909
940
|
values: data,
|
|
@@ -921,7 +952,10 @@ export abstract class GitHostIntegration<
|
|
|
921
952
|
duration: performance.now() - start,
|
|
922
953
|
};
|
|
923
954
|
} catch (ex) {
|
|
924
|
-
|
|
955
|
+
this.handleProviderException('getIssuesForRepos', ex, {
|
|
956
|
+
scope: scope,
|
|
957
|
+
connectionId: connectionId,
|
|
958
|
+
});
|
|
925
959
|
return { error: toError(ex), duration: performance.now() - start };
|
|
926
960
|
}
|
|
927
961
|
}
|
|
@@ -937,7 +971,10 @@ export abstract class GitHostIntegration<
|
|
|
937
971
|
try {
|
|
938
972
|
userAccount = await this.getFilterAccount(api, session, customUrl);
|
|
939
973
|
} catch (ex) {
|
|
940
|
-
|
|
974
|
+
this.handleProviderException('getIssuesForRepos', ex, {
|
|
975
|
+
scope: scope,
|
|
976
|
+
connectionId: connectionId,
|
|
977
|
+
});
|
|
941
978
|
return { error: toError(ex), duration: performance.now() - start };
|
|
942
979
|
}
|
|
943
980
|
|
|
@@ -964,7 +1001,7 @@ export abstract class GitHostIntegration<
|
|
|
964
1001
|
};
|
|
965
1002
|
}
|
|
966
1003
|
|
|
967
|
-
if (api.getProviderIssuesPagingMode(providerId) === PagingMode.Repo && !
|
|
1004
|
+
if (api.getProviderIssuesPagingMode(providerId) === PagingMode.Repo && !repoIdsInput) {
|
|
968
1005
|
const cursorInfo = this.parseCursorInfo<PagedRepoInput>(options?.cursor);
|
|
969
1006
|
const cursors: PagedRepoInput[] = cursorInfo.cursors ?? [];
|
|
970
1007
|
let repoInputs: PagedRepoInput[] = reposOrRepoIds.map(repo => ({ repo: repo, cursor: undefined }));
|
|
@@ -1001,6 +1038,7 @@ export abstract class GitHostIntegration<
|
|
|
1001
1038
|
return { repoInput: repoInput, results: results };
|
|
1002
1039
|
}),
|
|
1003
1040
|
);
|
|
1041
|
+
throwIfAllSettledFailed(settled);
|
|
1004
1042
|
|
|
1005
1043
|
for (let i = 0; i < settled.length; i++) {
|
|
1006
1044
|
const outcome = settled[i];
|
|
@@ -1038,6 +1076,7 @@ export abstract class GitHostIntegration<
|
|
|
1038
1076
|
cursor.page = options.page;
|
|
1039
1077
|
}
|
|
1040
1078
|
|
|
1079
|
+
this.resetRequestExceptionCount('getIssuesForRepos');
|
|
1041
1080
|
return {
|
|
1042
1081
|
value: {
|
|
1043
1082
|
values: data,
|
|
@@ -1055,13 +1094,17 @@ export abstract class GitHostIntegration<
|
|
|
1055
1094
|
duration: performance.now() - start,
|
|
1056
1095
|
};
|
|
1057
1096
|
} catch (ex) {
|
|
1058
|
-
|
|
1097
|
+
this.handleProviderException('getIssuesForRepos', ex, {
|
|
1098
|
+
scope: scope,
|
|
1099
|
+
connectionId: connectionId,
|
|
1100
|
+
});
|
|
1059
1101
|
return { error: toError(ex), duration: performance.now() - start };
|
|
1060
1102
|
}
|
|
1061
1103
|
}
|
|
1062
1104
|
|
|
1063
1105
|
try {
|
|
1064
|
-
const
|
|
1106
|
+
const tokenWithInfo = toTokenWithInfo(providerId, session);
|
|
1107
|
+
const result = await api.getIssuesForRepos(tokenWithInfo, reposOrRepoIds, {
|
|
1065
1108
|
...getIssuesOptions,
|
|
1066
1109
|
cursor: options?.cursor,
|
|
1067
1110
|
baseUrl: customUrl,
|
|
@@ -1070,9 +1113,28 @@ export abstract class GitHostIntegration<
|
|
|
1070
1113
|
states: states,
|
|
1071
1114
|
sort: options?.sort,
|
|
1072
1115
|
});
|
|
1116
|
+
const failures = result.metadata?.failures;
|
|
1117
|
+
if (
|
|
1118
|
+
repoIdsInput &&
|
|
1119
|
+
reposOrRepoIds.length > 0 &&
|
|
1120
|
+
result.values.length === 0 &&
|
|
1121
|
+
failures?.length === reposOrRepoIds.length
|
|
1122
|
+
) {
|
|
1123
|
+
const ex = toCollectionFailureError(failures[0], tokenWithInfo);
|
|
1124
|
+
this.handleProviderException('getIssuesForRepos', ex, {
|
|
1125
|
+
scope: scope,
|
|
1126
|
+
connectionId: connectionId,
|
|
1127
|
+
});
|
|
1128
|
+
return { error: ex, duration: performance.now() - start };
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
this.resetRequestExceptionCount('getIssuesForRepos');
|
|
1073
1132
|
return { value: result, duration: performance.now() - start };
|
|
1074
1133
|
} catch (ex) {
|
|
1075
|
-
|
|
1134
|
+
this.handleProviderException('getIssuesForRepos', ex, {
|
|
1135
|
+
scope: scope,
|
|
1136
|
+
connectionId: connectionId,
|
|
1137
|
+
});
|
|
1076
1138
|
return { error: toError(ex), duration: performance.now() - start };
|
|
1077
1139
|
}
|
|
1078
1140
|
}
|
|
@@ -1134,7 +1196,16 @@ export abstract class GitHostIntegration<
|
|
|
1134
1196
|
const customUrl =
|
|
1135
1197
|
options?.customUrl ?? getSelfManagedApiBaseUrl(providerId, session.domain || this.domain, session.protocol);
|
|
1136
1198
|
|
|
1137
|
-
|
|
1199
|
+
let api: ProvidersApi;
|
|
1200
|
+
try {
|
|
1201
|
+
api = await this.getProvidersApi();
|
|
1202
|
+
} catch (ex) {
|
|
1203
|
+
this.handleProviderException('getPullRequestsForRepos', ex, {
|
|
1204
|
+
scope: scope,
|
|
1205
|
+
connectionId: connectionId,
|
|
1206
|
+
});
|
|
1207
|
+
return { error: toError(ex), duration: performance.now() - start };
|
|
1208
|
+
}
|
|
1138
1209
|
if (
|
|
1139
1210
|
providerId !== GitCloudHostIntegrationId.GitLab &&
|
|
1140
1211
|
(api.isRepoIdsInput(reposOrRepoIds) ||
|
|
@@ -1182,14 +1253,20 @@ export abstract class GitHostIntegration<
|
|
|
1182
1253
|
try {
|
|
1183
1254
|
userAccount = await this.getFilterAccount(api, session, customUrl, organization);
|
|
1184
1255
|
} catch (ex) {
|
|
1185
|
-
|
|
1256
|
+
this.handleProviderException('getPullRequestsForRepos', ex, {
|
|
1257
|
+
scope: scope,
|
|
1258
|
+
connectionId: connectionId,
|
|
1259
|
+
});
|
|
1186
1260
|
return { error: toError(ex), duration: performance.now() - start };
|
|
1187
1261
|
}
|
|
1188
1262
|
} else {
|
|
1189
1263
|
try {
|
|
1190
1264
|
userAccount = await this.getFilterAccount(api, session, customUrl);
|
|
1191
1265
|
} catch (ex) {
|
|
1192
|
-
|
|
1266
|
+
this.handleProviderException('getPullRequestsForRepos', ex, {
|
|
1267
|
+
scope: scope,
|
|
1268
|
+
connectionId: connectionId,
|
|
1269
|
+
});
|
|
1193
1270
|
return { error: toError(ex), duration: performance.now() - start };
|
|
1194
1271
|
}
|
|
1195
1272
|
}
|
|
@@ -1298,6 +1375,7 @@ export abstract class GitHostIntegration<
|
|
|
1298
1375
|
return { repoInput: repoInput, results: results };
|
|
1299
1376
|
}),
|
|
1300
1377
|
);
|
|
1378
|
+
throwIfAllSettledFailed(settled);
|
|
1301
1379
|
|
|
1302
1380
|
// `allSettled` preserves order, so `settled[i]` is `repoInputs[i]`.
|
|
1303
1381
|
settled.forEach((outcome, i) => {
|
|
@@ -1338,6 +1416,7 @@ export abstract class GitHostIntegration<
|
|
|
1338
1416
|
cursor.page = options.page;
|
|
1339
1417
|
}
|
|
1340
1418
|
|
|
1419
|
+
this.resetRequestExceptionCount('getPullRequestsForRepos');
|
|
1341
1420
|
return {
|
|
1342
1421
|
value: {
|
|
1343
1422
|
values: data,
|
|
@@ -1355,7 +1434,10 @@ export abstract class GitHostIntegration<
|
|
|
1355
1434
|
duration: performance.now() - start,
|
|
1356
1435
|
};
|
|
1357
1436
|
} catch (ex) {
|
|
1358
|
-
|
|
1437
|
+
this.handleProviderException('getPullRequestsForRepos', ex, {
|
|
1438
|
+
scope: scope,
|
|
1439
|
+
connectionId: connectionId,
|
|
1440
|
+
});
|
|
1359
1441
|
return { error: toError(ex), duration: performance.now() - start };
|
|
1360
1442
|
}
|
|
1361
1443
|
}
|
|
@@ -1372,80 +1454,40 @@ export abstract class GitHostIntegration<
|
|
|
1372
1454
|
includeRemoteInfo: isAzureDevOpsProvider(providerId) ? true : undefined,
|
|
1373
1455
|
fields: options?.summary ? summaryPullRequestFields : undefined,
|
|
1374
1456
|
});
|
|
1457
|
+
this.resetRequestExceptionCount('getPullRequestsForRepos');
|
|
1375
1458
|
return { value: result, duration: performance.now() - start };
|
|
1376
1459
|
} catch (ex) {
|
|
1377
|
-
|
|
1460
|
+
this.handleProviderException('getPullRequestsForRepos', ex, {
|
|
1461
|
+
scope: scope,
|
|
1462
|
+
connectionId: connectionId,
|
|
1463
|
+
});
|
|
1378
1464
|
return { error: toError(ex), duration: performance.now() - start };
|
|
1379
1465
|
}
|
|
1380
1466
|
}
|
|
1381
1467
|
|
|
1382
|
-
|
|
1383
|
-
repo?: T,
|
|
1384
|
-
cancellation?: AbortSignal,
|
|
1385
|
-
silent?: boolean,
|
|
1386
|
-
connectionId?: string,
|
|
1387
|
-
state?: PullRequestStateFilter,
|
|
1388
|
-
options?: SearchMyPullRequestsOptions,
|
|
1389
|
-
): Promise<IntegrationResult<PullRequest[] | undefined>>;
|
|
1390
|
-
async searchMyPullRequests(
|
|
1391
|
-
repos?: T[],
|
|
1392
|
-
cancellation?: AbortSignal,
|
|
1393
|
-
silent?: boolean,
|
|
1394
|
-
connectionId?: string,
|
|
1395
|
-
state?: PullRequestStateFilter,
|
|
1396
|
-
options?: SearchMyPullRequestsOptions,
|
|
1397
|
-
): Promise<IntegrationResult<PullRequest[] | undefined>>;
|
|
1468
|
+
/** Account-wide (or repo-scoped) search for the current user's pull requests. */
|
|
1398
1469
|
@trace()
|
|
1399
1470
|
async searchMyPullRequests(
|
|
1400
1471
|
repos?: T | T[],
|
|
1401
1472
|
cancellation?: AbortSignal,
|
|
1402
|
-
|
|
1403
|
-
connectionId?: string,
|
|
1404
|
-
state?: PullRequestStateFilter,
|
|
1405
|
-
options?: SearchMyPullRequestsOptions,
|
|
1473
|
+
options?: SearchMyPullRequestsOptions & { connectionId?: string },
|
|
1406
1474
|
): Promise<IntegrationResult<PullRequest[] | undefined>> {
|
|
1407
1475
|
const scope = getScopedLogger();
|
|
1476
|
+
const { connectionId, ...searchOptions } = options ?? {};
|
|
1408
1477
|
// `connectionId` targets a specific account (multi-account); omitted reads the primary.
|
|
1409
1478
|
const session = await this.resolveReadSession(connectionId, scope);
|
|
1410
1479
|
if (session == null) return undefined;
|
|
1411
1480
|
|
|
1412
1481
|
const start = performance.now();
|
|
1413
1482
|
try {
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
session,
|
|
1421
|
-
repos != null ? (Array.isArray(repos) ? repos : [repos]) : undefined,
|
|
1422
|
-
cancellation,
|
|
1423
|
-
silent,
|
|
1424
|
-
state,
|
|
1425
|
-
options,
|
|
1426
|
-
);
|
|
1427
|
-
} else {
|
|
1428
|
-
result = {
|
|
1429
|
-
value: await this.searchProviderMyPullRequests(
|
|
1430
|
-
session,
|
|
1431
|
-
repos != null ? (Array.isArray(repos) ? repos : [repos]) : undefined,
|
|
1432
|
-
cancellation,
|
|
1433
|
-
silent,
|
|
1434
|
-
state,
|
|
1435
|
-
options,
|
|
1436
|
-
),
|
|
1437
|
-
};
|
|
1438
|
-
}
|
|
1483
|
+
const prs = await this.searchProviderMyPullRequests(
|
|
1484
|
+
session,
|
|
1485
|
+
ensureArray(repos),
|
|
1486
|
+
cancellation,
|
|
1487
|
+
searchOptions,
|
|
1488
|
+
);
|
|
1439
1489
|
this.resetRequestExceptionCount('searchMyPullRequests');
|
|
1440
|
-
|
|
1441
|
-
// matching branch explicitly; a missing result is treated as a successful empty read.
|
|
1442
|
-
if (result == null) {
|
|
1443
|
-
return { value: undefined, duration: performance.now() - start };
|
|
1444
|
-
}
|
|
1445
|
-
if (result.error != null) {
|
|
1446
|
-
return { error: result.error, duration: performance.now() - start };
|
|
1447
|
-
}
|
|
1448
|
-
return { value: result.value, duration: performance.now() - start };
|
|
1490
|
+
return { value: prs, duration: performance.now() - start };
|
|
1449
1491
|
} catch (ex) {
|
|
1450
1492
|
this.handleProviderException('searchMyPullRequests', ex, {
|
|
1451
1493
|
scope: scope,
|
|
@@ -1542,34 +1584,13 @@ export abstract class GitHostIntegration<
|
|
|
1542
1584
|
}
|
|
1543
1585
|
}
|
|
1544
1586
|
|
|
1545
|
-
// `state` selects which PR states to include (open/closed/merged/all). Providers that cannot express it
|
|
1546
|
-
// in a single query filter the normalized results; omitted preserves the historical open-only behavior.
|
|
1547
1587
|
protected abstract searchProviderMyPullRequests(
|
|
1548
1588
|
session: ProviderAuthenticationSession,
|
|
1549
1589
|
repos?: T[],
|
|
1550
1590
|
cancellation?: AbortSignal,
|
|
1551
|
-
silent?: boolean,
|
|
1552
|
-
state?: PullRequestStateFilter,
|
|
1553
1591
|
options?: SearchMyPullRequestsOptions,
|
|
1554
1592
|
): Promise<PullRequest[] | undefined>;
|
|
1555
1593
|
|
|
1556
|
-
/**
|
|
1557
|
-
* Optional metadata-aware counterpart of {@link searchProviderMyPullRequests}. Providers whose account-wide
|
|
1558
|
-
* "my PRs" read already produces {@link ProviderApiPagedResult} with completeness/failures can override
|
|
1559
|
-
* this to return a soft `{ value, error }` result so `searchMyPullRequests` surfaces partial data and a
|
|
1560
|
-
* warning instead of silently discarding the failure signal. The wrapper prefers this when present; the
|
|
1561
|
-
* abstract {@link searchProviderMyPullRequests} remains the required fallback for repo-scoped and
|
|
1562
|
-
* metadata-oblivious paths.
|
|
1563
|
-
*/
|
|
1564
|
-
protected searchProviderMyPullRequestsResult?(
|
|
1565
|
-
session: ProviderAuthenticationSession,
|
|
1566
|
-
repos?: T[],
|
|
1567
|
-
cancellation?: AbortSignal,
|
|
1568
|
-
silent?: boolean,
|
|
1569
|
-
state?: PullRequestStateFilter,
|
|
1570
|
-
options?: SearchMyPullRequestsOptions,
|
|
1571
|
-
): Promise<IntegrationResult<PullRequest[] | undefined>>;
|
|
1572
|
-
|
|
1573
1594
|
/**
|
|
1574
1595
|
* Result-returning wrapper for the filtered pull-request search. Errors become the soft
|
|
1575
1596
|
* `{ error }` branch so the public facade can preserve an empty account and a failed request as distinct
|
|
@@ -1618,49 +1639,16 @@ export abstract class GitHostIntegration<
|
|
|
1618
1639
|
cancellation?: AbortSignal,
|
|
1619
1640
|
): Promise<ProviderPullRequestSearchPage | undefined>;
|
|
1620
1641
|
|
|
1621
|
-
|
|
1622
|
-
searchQuery: string,
|
|
1623
|
-
repo?: T,
|
|
1624
|
-
cancellation?: AbortSignal,
|
|
1625
|
-
options?: { include?: PullRequestState[] },
|
|
1626
|
-
): Promise<PullRequest[] | undefined>;
|
|
1627
|
-
async searchPullRequests(
|
|
1628
|
-
searchQuery: string,
|
|
1629
|
-
repos?: T[],
|
|
1630
|
-
cancellation?: AbortSignal,
|
|
1631
|
-
options?: { include?: PullRequestState[] },
|
|
1632
|
-
): Promise<PullRequest[] | undefined>;
|
|
1633
|
-
async searchPullRequests(
|
|
1634
|
-
searchQuery: string,
|
|
1635
|
-
repo?: T,
|
|
1636
|
-
cancellation?: AbortSignal,
|
|
1637
|
-
connectionId?: string,
|
|
1638
|
-
options?: { include?: PullRequestState[] },
|
|
1639
|
-
): Promise<PullRequest[] | undefined>;
|
|
1640
|
-
async searchPullRequests(
|
|
1641
|
-
searchQuery: string,
|
|
1642
|
-
repos?: T[],
|
|
1643
|
-
cancellation?: AbortSignal,
|
|
1644
|
-
connectionId?: string,
|
|
1645
|
-
options?: { include?: PullRequestState[] },
|
|
1646
|
-
): Promise<PullRequest[] | undefined>;
|
|
1642
|
+
/** Free-text search across pull requests, optionally narrowed to `repos`. */
|
|
1647
1643
|
@trace()
|
|
1648
1644
|
async searchPullRequests(
|
|
1649
1645
|
searchQuery: string,
|
|
1650
1646
|
repos?: T | T[],
|
|
1651
1647
|
cancellation?: AbortSignal,
|
|
1652
|
-
|
|
1653
|
-
options?: { include?: PullRequestState[] },
|
|
1648
|
+
options?: SearchPullRequestsOptions & { connectionId?: string },
|
|
1654
1649
|
): Promise<PullRequest[] | undefined> {
|
|
1655
|
-
// `connectionId` (string) can be omitted when passing `options`; split the overlapping 4th arg.
|
|
1656
|
-
// When the 4th arg isn't the options object (a string `connectionId` or `undefined`), fall back to
|
|
1657
|
-
// the 5th-arg `options` so an explicit `undefined` connectionId still honors state filtering.
|
|
1658
|
-
const connectionId = typeof connectionIdOrOptions === 'string' ? connectionIdOrOptions : undefined;
|
|
1659
|
-
const searchOptions =
|
|
1660
|
-
connectionIdOrOptions != null && typeof connectionIdOrOptions !== 'string'
|
|
1661
|
-
? connectionIdOrOptions
|
|
1662
|
-
: options;
|
|
1663
1650
|
const scope = getScopedLogger();
|
|
1651
|
+
const { connectionId, ...searchOptions } = options ?? {};
|
|
1664
1652
|
// `connectionId` targets a specific account (multi-account); omitted reads the primary.
|
|
1665
1653
|
const session = await this.resolveReadSession(connectionId, scope);
|
|
1666
1654
|
if (session == null) return undefined;
|
|
@@ -1669,7 +1657,7 @@ export abstract class GitHostIntegration<
|
|
|
1669
1657
|
const prs = await this.searchProviderPullRequests?.(
|
|
1670
1658
|
session,
|
|
1671
1659
|
searchQuery,
|
|
1672
|
-
|
|
1660
|
+
ensureArray(repos),
|
|
1673
1661
|
cancellation,
|
|
1674
1662
|
searchOptions,
|
|
1675
1663
|
);
|
|
@@ -1686,7 +1674,7 @@ export abstract class GitHostIntegration<
|
|
|
1686
1674
|
searchQuery: string,
|
|
1687
1675
|
repos?: T[],
|
|
1688
1676
|
cancellation?: AbortSignal,
|
|
1689
|
-
options?:
|
|
1677
|
+
options?: SearchPullRequestsOptions,
|
|
1690
1678
|
): Promise<PullRequest[] | undefined>;
|
|
1691
1679
|
|
|
1692
1680
|
/**
|