@gitkraken/core-gitlens 0.5.108 → 0.5.110
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 +49 -1
- package/dist/git/models/issue.d.ts +70 -0
- package/dist/git/models/issue.d.ts.map +1 -1
- package/dist/git/models/issue.js +17 -0
- package/dist/git/models/issue.js.map +1 -1
- package/dist/git/models/pullRequest.d.ts +81 -0
- package/dist/git/models/pullRequest.d.ts.map +1 -1
- package/dist/git/models/pullRequest.js +15 -0
- package/dist/git/models/pullRequest.js.map +1 -1
- package/dist/git/utils/issue.utils.d.ts +41 -1
- package/dist/git/utils/issue.utils.d.ts.map +1 -1
- package/dist/git/utils/issue.utils.js +80 -0
- package/dist/git/utils/issue.utils.js.map +1 -1
- package/dist/git/utils/pullRequest.utils.d.ts +11 -1
- package/dist/git/utils/pullRequest.utils.d.ts.map +1 -1
- package/dist/git/utils/pullRequest.utils.js +40 -0
- package/dist/git/utils/pullRequest.utils.js.map +1 -1
- package/dist/plus/git-github/api/github.d.ts +70 -10
- package/dist/plus/git-github/api/github.d.ts.map +1 -1
- package/dist/plus/git-github/api/github.js +284 -31
- package/dist/plus/git-github/api/github.js.map +1 -1
- package/dist/plus/git-github/api/issueSearchQuery.d.ts +49 -5
- package/dist/plus/git-github/api/issueSearchQuery.d.ts.map +1 -1
- package/dist/plus/git-github/api/issueSearchQuery.js +64 -6
- package/dist/plus/git-github/api/issueSearchQuery.js.map +1 -1
- package/dist/plus/git-github/api/pullRequestSearchQuery.d.ts +27 -1
- package/dist/plus/git-github/api/pullRequestSearchQuery.d.ts.map +1 -1
- package/dist/plus/git-github/api/pullRequestSearchQuery.js +73 -6
- package/dist/plus/git-github/api/pullRequestSearchQuery.js.map +1 -1
- package/dist/plus/git-github/models.d.ts +17 -5
- package/dist/plus/git-github/models.d.ts.map +1 -1
- package/dist/plus/git-github/models.js +14 -1
- package/dist/plus/git-github/models.js.map +1 -1
- package/dist/plus/integrations/collectionMetadata.d.ts +18 -0
- package/dist/plus/integrations/collectionMetadata.d.ts.map +1 -1
- package/dist/plus/integrations/collectionMetadata.js +24 -0
- package/dist/plus/integrations/collectionMetadata.js.map +1 -1
- package/dist/plus/integrations/integrationService.d.ts +31 -10
- package/dist/plus/integrations/integrationService.d.ts.map +1 -1
- package/dist/plus/integrations/integrationService.js +9 -1
- package/dist/plus/integrations/integrationService.js.map +1 -1
- package/dist/plus/integrations/manager.d.ts +85 -31
- package/dist/plus/integrations/manager.d.ts.map +1 -1
- package/dist/plus/integrations/models/gitHostIntegration.d.ts +18 -31
- package/dist/plus/integrations/models/gitHostIntegration.d.ts.map +1 -1
- package/dist/plus/integrations/models/gitHostIntegration.js +29 -1
- package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
- package/dist/plus/integrations/models/integration.d.ts +1 -1
- package/dist/plus/integrations/models/integration.d.ts.map +1 -1
- package/dist/plus/integrations/models/integration.js.map +1 -1
- package/dist/plus/integrations/models/issueReads.d.ts +63 -1
- package/dist/plus/integrations/models/issueReads.d.ts.map +1 -1
- package/dist/plus/integrations/models/issuesIntegration.d.ts +7 -21
- package/dist/plus/integrations/models/issuesIntegration.d.ts.map +1 -1
- package/dist/plus/integrations/models/issuesIntegration.js.map +1 -1
- package/dist/plus/integrations/providerFilters.d.ts +2 -2
- package/dist/plus/integrations/providerFilters.d.ts.map +1 -1
- package/dist/plus/integrations/providers/accounts.d.ts +6 -0
- package/dist/plus/integrations/providers/accounts.d.ts.map +1 -0
- package/dist/plus/integrations/providers/accounts.js +30 -0
- package/dist/plus/integrations/providers/accounts.js.map +1 -0
- package/dist/plus/integrations/providers/azureDevOps.d.ts.map +1 -1
- package/dist/plus/integrations/providers/azureDevOps.js +1 -0
- package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
- package/dist/plus/integrations/providers/github.d.ts +9 -0
- package/dist/plus/integrations/providers/github.d.ts.map +1 -1
- package/dist/plus/integrations/providers/github.js +115 -135
- package/dist/plus/integrations/providers/github.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab.d.ts +9 -0
- package/dist/plus/integrations/providers/gitlab.d.ts.map +1 -1
- package/dist/plus/integrations/providers/gitlab.js +24 -4
- package/dist/plus/integrations/providers/gitlab.js.map +1 -1
- package/dist/plus/integrations/providers/issueSorts.d.ts +36 -0
- package/dist/plus/integrations/providers/issueSorts.d.ts.map +1 -0
- package/dist/plus/integrations/providers/issueSorts.js +76 -0
- package/dist/plus/integrations/providers/issueSorts.js.map +1 -0
- package/dist/plus/integrations/providers/jira.d.ts +3 -9
- package/dist/plus/integrations/providers/jira.d.ts.map +1 -1
- package/dist/plus/integrations/providers/jira.js +5 -1
- package/dist/plus/integrations/providers/jira.js.map +1 -1
- package/dist/plus/integrations/providers/linear.d.ts +24 -9
- package/dist/plus/integrations/providers/linear.d.ts.map +1 -1
- package/dist/plus/integrations/providers/linear.js +63 -5
- package/dist/plus/integrations/providers/linear.js.map +1 -1
- package/dist/plus/integrations/providers/models.d.ts +76 -38
- package/dist/plus/integrations/providers/models.d.ts.map +1 -1
- package/dist/plus/integrations/providers/models.js +91 -105
- package/dist/plus/integrations/providers/models.js.map +1 -1
- package/dist/plus/integrations/providers/providersApi.d.ts +18 -3
- package/dist/plus/integrations/providers/providersApi.d.ts.map +1 -1
- package/dist/plus/integrations/providers/providersApi.js +24 -7
- package/dist/plus/integrations/providers/providersApi.js.map +1 -1
- package/dist/plus/integrations/providers/pullRequestReviews.d.ts +50 -0
- package/dist/plus/integrations/providers/pullRequestReviews.d.ts.map +1 -0
- package/dist/plus/integrations/providers/pullRequestReviews.js +99 -0
- package/dist/plus/integrations/providers/pullRequestReviews.js.map +1 -0
- package/dist/plus/integrations/providers/trello.d.ts +3 -9
- package/dist/plus/integrations/providers/trello.d.ts.map +1 -1
- package/dist/plus/integrations/providers/trello.js +1 -0
- package/dist/plus/integrations/providers/trello.js.map +1 -1
- package/dist/plus/integrations/providers/utils/providerPaging.d.ts.map +1 -1
- package/dist/plus/integrations/providers/utils/providerPaging.js +5 -1
- package/dist/plus/integrations/providers/utils/providerPaging.js.map +1 -1
- package/dist/plus/integrations/reads/broaden.d.ts +6 -0
- package/dist/plus/integrations/reads/broaden.d.ts.map +1 -1
- package/dist/plus/integrations/reads/broaden.js.map +1 -1
- package/dist/plus/integrations/reads/counts.d.ts +63 -1
- package/dist/plus/integrations/reads/counts.d.ts.map +1 -1
- package/dist/plus/integrations/reads/counts.js +146 -2
- package/dist/plus/integrations/reads/counts.js.map +1 -1
- package/dist/plus/integrations/reads/drains.d.ts +7 -1
- package/dist/plus/integrations/reads/drains.d.ts.map +1 -1
- package/dist/plus/integrations/reads/drains.js +13 -2
- package/dist/plus/integrations/reads/drains.js.map +1 -1
- package/dist/plus/integrations/reads/filters.d.ts +59 -9
- package/dist/plus/integrations/reads/filters.d.ts.map +1 -1
- package/dist/plus/integrations/reads/filters.js +39 -0
- package/dist/plus/integrations/reads/filters.js.map +1 -1
- package/dist/plus/integrations/reads/issueTracker.d.ts +18 -1
- package/dist/plus/integrations/reads/issueTracker.d.ts.map +1 -1
- package/dist/plus/integrations/reads/issueTracker.js +40 -3
- package/dist/plus/integrations/reads/issueTracker.js.map +1 -1
- package/dist/plus/integrations/reads/issues.d.ts +27 -3
- package/dist/plus/integrations/reads/issues.d.ts.map +1 -1
- package/dist/plus/integrations/reads/issues.js +223 -123
- package/dist/plus/integrations/reads/issues.js.map +1 -1
- package/dist/plus/integrations/reads/ordering.d.ts +101 -0
- package/dist/plus/integrations/reads/ordering.d.ts.map +1 -0
- package/dist/plus/integrations/reads/ordering.js +48 -0
- package/dist/plus/integrations/reads/ordering.js.map +1 -0
- package/dist/plus/integrations/reads/searchIssues.d.ts +7 -2
- package/dist/plus/integrations/reads/searchIssues.d.ts.map +1 -1
- package/dist/plus/integrations/reads/searchIssues.js +9 -3
- package/dist/plus/integrations/reads/searchIssues.js.map +1 -1
- package/dist/plus/integrations/reads/searchPullRequests.d.ts +4 -3
- package/dist/plus/integrations/reads/searchPullRequests.d.ts.map +1 -1
- package/dist/plus/integrations/reads/searchPullRequests.js +6 -4
- package/dist/plus/integrations/reads/searchPullRequests.js.map +1 -1
- package/dist/plus/integrations/reads/sweeps.js +1 -1
- package/dist/plus/integrations/reads/sweeps.js.map +1 -1
- package/dist/plus/integrations/reads/warnings.d.ts +35 -3
- package/dist/plus/integrations/reads/warnings.d.ts.map +1 -1
- package/dist/plus/integrations/reads/warnings.js +58 -4
- package/dist/plus/integrations/reads/warnings.js.map +1 -1
- package/dist/plus/integrations/results.d.ts +15 -0
- package/dist/plus/integrations/results.d.ts.map +1 -1
- package/dist/plus/integrations/results.js.map +1 -1
- package/docs/integrations.md +76 -10
- package/docs/kepler-read-api-parity.md +9 -0
- package/package.json +2 -2
- package/src/git/models/issue.ts +73 -0
- package/src/git/models/pullRequest.ts +84 -0
- package/src/git/utils/issue.utils.ts +91 -1
- package/src/git/utils/pullRequest.utils.ts +50 -0
- package/src/plus/git-github/api/github.ts +356 -36
- package/src/plus/git-github/api/issueSearchQuery.ts +67 -7
- package/src/plus/git-github/api/pullRequestSearchQuery.ts +81 -7
- package/src/plus/git-github/models.ts +29 -5
- package/src/plus/integrations/collectionMetadata.ts +24 -0
- package/src/plus/integrations/integrationService.ts +40 -12
- package/src/plus/integrations/manager.ts +89 -35
- package/src/plus/integrations/models/gitHostIntegration.ts +47 -31
- package/src/plus/integrations/models/integration.ts +1 -0
- package/src/plus/integrations/models/issueReads.ts +65 -1
- package/src/plus/integrations/models/issuesIntegration.ts +7 -6
- package/src/plus/integrations/providerFilters.ts +8 -1
- package/src/plus/integrations/providers/accounts.ts +34 -0
- package/src/plus/integrations/providers/azureDevOps.ts +1 -0
- package/src/plus/integrations/providers/github.ts +134 -144
- package/src/plus/integrations/providers/gitlab.ts +29 -10
- package/src/plus/integrations/providers/issueSorts.ts +89 -0
- package/src/plus/integrations/providers/jira.ts +9 -3
- package/src/plus/integrations/providers/linear.ts +77 -8
- package/src/plus/integrations/providers/models.ts +185 -128
- package/src/plus/integrations/providers/providersApi.ts +51 -13
- package/src/plus/integrations/providers/pullRequestReviews.ts +122 -0
- package/src/plus/integrations/providers/trello.ts +4 -3
- package/src/plus/integrations/providers/utils/providerPaging.ts +6 -1
- package/src/plus/integrations/reads/broaden.ts +6 -0
- package/src/plus/integrations/reads/counts.ts +281 -3
- package/src/plus/integrations/reads/drains.ts +12 -2
- package/src/plus/integrations/reads/filters.ts +92 -8
- package/src/plus/integrations/reads/issueTracker.ts +78 -4
- package/src/plus/integrations/reads/issues.ts +386 -194
- package/src/plus/integrations/reads/ordering.ts +124 -0
- package/src/plus/integrations/reads/searchIssues.ts +15 -3
- package/src/plus/integrations/reads/searchPullRequests.ts +12 -4
- package/src/plus/integrations/reads/sweeps.ts +1 -1
- package/src/plus/integrations/reads/warnings.ts +84 -2
- package/src/plus/integrations/results.ts +15 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { IssueSearchCriteria, IssueSearchRelationship } from '../../../git/models/issue.js';
|
|
1
|
+
import type { IssueSearchCriteria, IssueSearchRelationship, IssueSorting } from '../../../git/models/issue.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Translation of the provider-neutral issue-search criteria into GitHub search qualifiers, and the sanitizing
|
|
@@ -70,6 +70,56 @@ export const gitHubIssueSearchRelationships: Record<IssueSearchRelationship, { q
|
|
|
70
70
|
unassigned: { qualifier: 'no:assignee', alias: 'unassigned' },
|
|
71
71
|
};
|
|
72
72
|
|
|
73
|
+
/**
|
|
74
|
+
* How each orderable key becomes a GitHub `sort:` qualifier.
|
|
75
|
+
*
|
|
76
|
+
* A literal table rather than a derived transform, for the same reason {@link gitHubIssueSearchRelationships} is
|
|
77
|
+
* one: being a `Record` over the union means adding a sort field without deciding its qualifier FAILS THE BUILD,
|
|
78
|
+
* instead of quietly emitting a search with no ordering constraint at all — which is the one failure mode the
|
|
79
|
+
* ordering contract exists to prevent, and the one a caller cannot detect from the result.
|
|
80
|
+
*
|
|
81
|
+
* `updated:desc` maps to the bare `sort:updated`, not `sort:updated-desc`. The two are the same query to GitHub,
|
|
82
|
+
* but the bare form is what this read has always emitted, so keeping it makes the default byte-identical to
|
|
83
|
+
* today's query — and the exact-query tests and recorded fixtures stay valid. Do not "normalize" it.
|
|
84
|
+
*
|
|
85
|
+
* `reactions` maps to the per-emoji `sort:reactions-+1`, NOT the bare `sort:reactions`. GitHub's bare form orders
|
|
86
|
+
* by the total across every reaction type, but the only reaction count on an `IssueShape` is `thumbsUpCount`,
|
|
87
|
+
* which this client fills from `reactions(content: THUMBS_UP)`. Ordering by the total would rank the page by a
|
|
88
|
+
* number the caller cannot see — and would disagree with `getIssueComparator`, which re-sorts a merged page from
|
|
89
|
+
* `thumbsUpCount`, so the same request would order one way with a single relationship and another way with two.
|
|
90
|
+
* `@gitkraken/provider-apis` maps it the same way for the same reason.
|
|
91
|
+
*
|
|
92
|
+
* Absent keys are absent on purpose: `closed` is NOT here even though `IssueShape.closedDate` exists, because
|
|
93
|
+
* GitHub's search cannot order by close date and a client-side sort over a page cut off at the result ceiling is
|
|
94
|
+
* exactly the lie the contract avoids. `sorts` in `githubIssueSearchCapabilities` is the same set, and a parity
|
|
95
|
+
* test pins the two together.
|
|
96
|
+
*/
|
|
97
|
+
export const gitHubIssueSortQualifiers: Partial<Record<IssueSorting, string>> = {
|
|
98
|
+
'created:asc': 'sort:created-asc',
|
|
99
|
+
'created:desc': 'sort:created-desc',
|
|
100
|
+
'updated:asc': 'sort:updated-asc',
|
|
101
|
+
'updated:desc': 'sort:updated',
|
|
102
|
+
'comments:asc': 'sort:comments-asc',
|
|
103
|
+
'comments:desc': 'sort:comments-desc',
|
|
104
|
+
'reactions:asc': 'sort:reactions-+1-asc',
|
|
105
|
+
'reactions:desc': 'sort:reactions-+1-desc',
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The `sort:` qualifier for a key, or `undefined` when there is no key or GitHub can't express it.
|
|
110
|
+
*
|
|
111
|
+
* Applies no default of its own: the two callers differ on whether they HAVE one — the filtered search always
|
|
112
|
+
* orders, and `searchMyIssues` has never requested an order at all — so the default belongs at the call site that
|
|
113
|
+
* has one rather than behind a guard at the one that doesn't.
|
|
114
|
+
*
|
|
115
|
+
* `undefined` for an inexpressible key rather than a fallback to something orderable: every caller validated
|
|
116
|
+
* against the declared capability first, so reaching that case means the capability table has outrun this one, and
|
|
117
|
+
* a silently unordered search would change which rows land inside the result ceiling.
|
|
118
|
+
*/
|
|
119
|
+
export function toGitHubIssueSortQualifier(sort: IssueSorting | undefined): string | undefined {
|
|
120
|
+
return sort != null ? gitHubIssueSortQualifiers[sort] : undefined;
|
|
121
|
+
}
|
|
122
|
+
|
|
73
123
|
/**
|
|
74
124
|
* The scope half of an issue search query: `org:` plus one `repo:` per repository.
|
|
75
125
|
*
|
|
@@ -106,11 +156,18 @@ export function toGitHubIssueSearchScopeQualifiers(
|
|
|
106
156
|
* becomes its own aliased search, since GitHub AND-s qualifiers and relationships are OR-ed) and excluding the
|
|
107
157
|
* repository/org scope (which {@link toGitHubIssueSearchScopeQualifiers} owns).
|
|
108
158
|
*
|
|
109
|
-
* `sort
|
|
110
|
-
*
|
|
111
|
-
*
|
|
159
|
+
* A `sort:` qualifier is ALWAYS emitted. Never none: the provider serves at most a bounded window of matches, and
|
|
160
|
+
* without an explicit order GitHub answers in relevance order, so which rows land inside that window would shift
|
|
161
|
+
* with GitHub's ranking even when nothing changed upstream. A key GitHub can't express is refused before this by
|
|
162
|
+
* the facade, so it cannot arrive here.
|
|
163
|
+
*
|
|
164
|
+
* `sort` is passed in rather than read off `criteria` so that the qualifier this emits and the key the caller
|
|
165
|
+
* records elsewhere cannot disagree — see `effectiveIssueSort`.
|
|
166
|
+
*
|
|
167
|
+
* Free-form values go through the sanitizers above, and one emptied by sanitizing is dropped rather than emitted
|
|
168
|
+
* as an empty qualifier.
|
|
112
169
|
*/
|
|
113
|
-
export function toGitHubIssueSearchQualifiers(criteria: IssueSearchCriteria | undefined): string[] {
|
|
170
|
+
export function toGitHubIssueSearchQualifiers(criteria: IssueSearchCriteria | undefined, sort: IssueSorting): string[] {
|
|
114
171
|
const qualifiers = ['type:issue'];
|
|
115
172
|
|
|
116
173
|
switch (criteria?.state) {
|
|
@@ -158,8 +215,11 @@ export function toGitHubIssueSearchQualifiers(criteria: IssueSearchCriteria | un
|
|
|
158
215
|
}
|
|
159
216
|
}
|
|
160
217
|
|
|
161
|
-
//
|
|
162
|
-
|
|
218
|
+
// Last, where it has always been: the exact-query tests pin the whole qualifier string, not a set.
|
|
219
|
+
const sortQualifier = toGitHubIssueSortQualifier(sort);
|
|
220
|
+
if (sortQualifier != null) {
|
|
221
|
+
qualifiers.push(sortQualifier);
|
|
222
|
+
}
|
|
163
223
|
|
|
164
224
|
return qualifiers;
|
|
165
225
|
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import type {
|
|
2
|
+
PullRequestSearchCriteria,
|
|
3
|
+
PullRequestSorting,
|
|
4
|
+
PullRequestStateFilter,
|
|
5
|
+
} from '../../../git/models/pullRequest.js';
|
|
6
|
+
import { defaultPullRequestSort, PullRequestFilter } from '../../../git/models/pullRequest.js';
|
|
7
|
+
import { sanitizeGitHubQualifierValue, sanitizeGitHubSearchText } from './issueSearchQuery.js';
|
|
4
8
|
|
|
5
9
|
export type GitHubPullRequestSearchFacet = {
|
|
6
10
|
/** Stable GraphQL alias and composite-cursor key. */
|
|
@@ -8,10 +12,20 @@ export type GitHubPullRequestSearchFacet = {
|
|
|
8
12
|
qualifiers: string[];
|
|
9
13
|
};
|
|
10
14
|
|
|
11
|
-
|
|
15
|
+
/**
|
|
16
|
+
* The GitHub search qualifier each relationship translates to. Exhaustive over `PullRequestFilter` so a new
|
|
17
|
+
* member can't be silently unmapped.
|
|
18
|
+
*
|
|
19
|
+
* Exported because the account-wide read builds its own facets from the same vocabulary (see
|
|
20
|
+
* `GitHubIntegrationBase.getProviderMyPullRequestsForUser`). Kept as ONE declaration rather than a copy per
|
|
21
|
+
* caller: the exhaustive `Record` makes a missing key a compile error, but nothing would catch two copies
|
|
22
|
+
* disagreeing on a qualifier STRING, and a wrong qualifier is a read that quietly answers a different question.
|
|
23
|
+
*/
|
|
24
|
+
export const gitHubPullRequestRelationshipQualifiers: Record<PullRequestFilter, string> = {
|
|
12
25
|
[PullRequestFilter.Author]: 'author:@me',
|
|
13
26
|
[PullRequestFilter.Assignee]: 'assignee:@me',
|
|
14
27
|
[PullRequestFilter.ReviewRequested]: 'review-requested:@me',
|
|
28
|
+
[PullRequestFilter.Reviewed]: 'reviewed-by:@me',
|
|
15
29
|
[PullRequestFilter.Mention]: 'mentions:@me',
|
|
16
30
|
};
|
|
17
31
|
|
|
@@ -19,6 +33,7 @@ const relationshipAlias: Record<PullRequestFilter, string> = {
|
|
|
19
33
|
[PullRequestFilter.Author]: 'author',
|
|
20
34
|
[PullRequestFilter.Assignee]: 'assignee',
|
|
21
35
|
[PullRequestFilter.ReviewRequested]: 'reviewRequested',
|
|
36
|
+
[PullRequestFilter.Reviewed]: 'reviewed',
|
|
22
37
|
[PullRequestFilter.Mention]: 'mention',
|
|
23
38
|
};
|
|
24
39
|
|
|
@@ -29,6 +44,30 @@ const stateAlias: Record<PullRequestStateFilter, string> = {
|
|
|
29
44
|
all: 'All',
|
|
30
45
|
};
|
|
31
46
|
|
|
47
|
+
/**
|
|
48
|
+
* How each orderable key becomes a GitHub `sort:` qualifier.
|
|
49
|
+
*
|
|
50
|
+
* A literal `Record` over the union rather than a derived transform, for the same reason the relationship tables
|
|
51
|
+
* are: adding a sort field without deciding its qualifier fails the build instead of quietly emitting a search
|
|
52
|
+
* with no ordering constraint — the one failure mode the ordering contract exists to prevent, and the one a
|
|
53
|
+
* caller cannot detect from the result.
|
|
54
|
+
*
|
|
55
|
+
* `updated:desc` maps to the bare `sort:updated`, not `sort:updated-desc`. The two are the same query to GitHub,
|
|
56
|
+
* but the bare form is what this read has always emitted, so keeping it makes the default byte-identical to
|
|
57
|
+
* today's query — matching `toGitHubIssueSortQualifier`. Do not "normalize" it.
|
|
58
|
+
*/
|
|
59
|
+
export const gitHubPullRequestSortQualifiers: Partial<Record<PullRequestSorting, string>> = {
|
|
60
|
+
'created:asc': 'sort:created-asc',
|
|
61
|
+
'created:desc': 'sort:created-desc',
|
|
62
|
+
'updated:asc': 'sort:updated-asc',
|
|
63
|
+
'updated:desc': 'sort:updated',
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/** The `sort:` qualifier for a key, or `undefined` when there is no key or GitHub can't express it. */
|
|
67
|
+
export function toGitHubPullRequestSortQualifier(sort: PullRequestSorting | undefined): string | undefined {
|
|
68
|
+
return sort != null ? gitHubPullRequestSortQualifiers[sort] : undefined;
|
|
69
|
+
}
|
|
70
|
+
|
|
32
71
|
function stateQualifiers(state: PullRequestStateFilter): string[] {
|
|
33
72
|
switch (state) {
|
|
34
73
|
case 'closed':
|
|
@@ -62,18 +101,53 @@ export function toGitHubPullRequestSearchFacets(
|
|
|
62
101
|
: ['open'];
|
|
63
102
|
const states: PullRequestStateFilter[] = requestedStates.includes('all') ? ['all'] : requestedStates;
|
|
64
103
|
const text = criteria?.text != null ? sanitizeGitHubSearchText(criteria.text) : '';
|
|
104
|
+
// Ordering is part of the contract, not an option: without an explicit `sort:` GitHub answers in relevance
|
|
105
|
+
// order, so which rows land inside the result ceiling would shift with its ranking even when nothing changed
|
|
106
|
+
// upstream. A key GitHub can't express is REFUSED here, not approximated with a fallback order — a silent
|
|
107
|
+
// `sort:updated` substitute would emit one order in the query while the merged-page comparator applied another
|
|
108
|
+
// (or none for an unknown field), which is exactly the "the N most recent are what you get" promise the ceiling
|
|
109
|
+
// contract cannot keep under a guessed order. Unreachable through the facade — every key is validated against
|
|
110
|
+
// `githubPullRequestSearchCapabilities.sorts` first — so this guards the direct callers of this exported builder
|
|
111
|
+
// and of `GitHubApi.searchPullRequestsPage`.
|
|
112
|
+
//
|
|
113
|
+
// Deliberately STRICTER than the issue path, which drops an inexpressible qualifier and searches on
|
|
114
|
+
// (`toGitHubIssueSearchQualifiers` pushes `toGitHubIssueSortQualifier`'s result only when it is non-null). The
|
|
115
|
+
// two reads differ in what that costs: an issue search is served by whichever facets the provider ordered, while
|
|
116
|
+
// this one hands its merged page to `getPullRequestComparator`, so a dropped qualifier here means the query and
|
|
117
|
+
// the comparator disagree about the order the ceiling was applied under. Refusing is the only answer that
|
|
118
|
+
// cannot lie about which rows were reachable.
|
|
119
|
+
const sort = criteria?.sort ?? defaultPullRequestSort;
|
|
120
|
+
const sortQualifier = toGitHubPullRequestSortQualifier(sort);
|
|
121
|
+
if (sortQualifier == null) {
|
|
122
|
+
throw new Error(`GitHub cannot order a pull request search by '${sort}'`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Facet-independent, unlike the relationship/state qualifiers below — build once and share.
|
|
126
|
+
const dateQualifiers: string[] = [];
|
|
127
|
+
const pushDate = (value: string | undefined, toQualifier: (sanitized: string) => string): void => {
|
|
128
|
+
if (value == null) return;
|
|
129
|
+
|
|
130
|
+
const sanitized = sanitizeGitHubQualifierValue(value);
|
|
131
|
+
if (sanitized.length > 0) {
|
|
132
|
+
dateQualifiers.push(toQualifier(sanitized));
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
pushDate(criteria?.updatedAfter, v => `updated:>=${v}`);
|
|
136
|
+
pushDate(criteria?.createdAfter, v => `created:>=${v}`);
|
|
65
137
|
|
|
66
138
|
return relationships.flatMap(relationship =>
|
|
67
139
|
states.map(state => ({
|
|
68
140
|
alias: `${relationship != null ? relationshipAlias[relationship] : 'scope'}${stateAlias[state]}`,
|
|
69
141
|
qualifiers: [
|
|
70
142
|
'is:pr',
|
|
71
|
-
...(relationship != null ? [
|
|
143
|
+
...(relationship != null ? [gitHubPullRequestRelationshipQualifiers[relationship]] : []),
|
|
72
144
|
...stateQualifiers(state),
|
|
145
|
+
// `!= null`, not truthy: `draft:false` narrows to ready-for-review PRs just as `draft:true` narrows to drafts.
|
|
146
|
+
...(criteria?.draft != null ? [`draft:${criteria.draft}`] : []),
|
|
73
147
|
...(criteria?.includeArchived === true ? [] : ['archived:false']),
|
|
74
148
|
...(text.length > 0 ? [text] : []),
|
|
75
|
-
|
|
76
|
-
|
|
149
|
+
...dateQualifiers,
|
|
150
|
+
sortQualifier,
|
|
77
151
|
],
|
|
78
152
|
})),
|
|
79
153
|
);
|
|
@@ -194,6 +194,13 @@ export type GitHubPullRequestMergeableState = 'MERGEABLE' | 'CONFLICTING' | 'UNK
|
|
|
194
194
|
export type GitHubPullRequestStatusCheckRollupState = 'SUCCESS' | 'FAILURE' | 'PENDING' | 'EXPECTED' | 'ERROR';
|
|
195
195
|
export type GitHubPullRequestReviewState = 'APPROVED' | 'CHANGES_REQUESTED' | 'COMMENTED' | 'DISMISSED' | 'PENDING';
|
|
196
196
|
|
|
197
|
+
type GitHubPullRequestReview = {
|
|
198
|
+
id: string;
|
|
199
|
+
author: GitHubMember | null;
|
|
200
|
+
state: GitHubPullRequestReviewState;
|
|
201
|
+
commit?: { oid: string } | null;
|
|
202
|
+
};
|
|
203
|
+
|
|
197
204
|
export interface GitHubPullRequest extends GitHubPullRequestLite {
|
|
198
205
|
additions: number;
|
|
199
206
|
assignees: {
|
|
@@ -204,11 +211,14 @@ export interface GitHubPullRequest extends GitHubPullRequestLite {
|
|
|
204
211
|
mergeable: GitHubPullRequestMergeableState;
|
|
205
212
|
reviewDecision: GitHubPullRequestReviewDecision;
|
|
206
213
|
latestReviews: {
|
|
207
|
-
nodes:
|
|
208
|
-
author: GitHubMember | null;
|
|
209
|
-
state: GitHubPullRequestReviewState;
|
|
210
|
-
}[];
|
|
214
|
+
nodes: GitHubPullRequestReview[];
|
|
211
215
|
};
|
|
216
|
+
/**
|
|
217
|
+
* The current user's own latest review. `latestReviews` is capped, so on a heavily-reviewed pull request
|
|
218
|
+
* the viewer's own review can fall outside that window — which is exactly the row a "needs my review"
|
|
219
|
+
* surface is asking about.
|
|
220
|
+
*/
|
|
221
|
+
viewerLatestReview: GitHubPullRequestReview | null;
|
|
212
222
|
reviewRequests: {
|
|
213
223
|
nodes: {
|
|
214
224
|
asCodeOwner: boolean;
|
|
@@ -401,6 +411,19 @@ export function fromGitHubPullRequestStatusCheckRollupState(
|
|
|
401
411
|
}
|
|
402
412
|
|
|
403
413
|
export function fromGitHubPullRequest(pr: GitHubPullRequest, provider: Provider): PullRequest {
|
|
414
|
+
// `latestReviews` is capped, so keep the viewer's own review even when it falls outside that window, deduped
|
|
415
|
+
// by review id since the two selections overlap. Unsubmitted drafts are dropped from the union rather than
|
|
416
|
+
// from the viewer's side alone: `PENDING` is in GitHub's review-state enum on both selections, and the field
|
|
417
|
+
// this feeds is documented as reviews already SUBMITTED — a draft there tells a "needs my review" consumer
|
|
418
|
+
// the review is done, and a reviewer with a submitted review plus a draft would get two conflicting rows.
|
|
419
|
+
const viewerLatestReview = pr.viewerLatestReview;
|
|
420
|
+
const latestReviews = [
|
|
421
|
+
...pr.latestReviews.nodes,
|
|
422
|
+
...(viewerLatestReview != null && !pr.latestReviews.nodes.some(r => r.id === viewerLatestReview.id)
|
|
423
|
+
? [viewerLatestReview]
|
|
424
|
+
: []),
|
|
425
|
+
].filter(review => review.state !== 'PENDING');
|
|
426
|
+
|
|
404
427
|
return new PullRequest(
|
|
405
428
|
provider,
|
|
406
429
|
fromGitHubMemberOrGhost(pr.author),
|
|
@@ -467,9 +490,10 @@ export function fromGitHubPullRequest(pr: GitHubPullRequest, provider: Provider)
|
|
|
467
490
|
: undefined,
|
|
468
491
|
)
|
|
469
492
|
.filter(<T>(r?: T): r is T => Boolean(r)),
|
|
470
|
-
|
|
493
|
+
latestReviews.map(r => ({
|
|
471
494
|
reviewer: fromGitHubMemberOrGhost(r.author),
|
|
472
495
|
state: fromGitHubPullRequestReviewState(r.state),
|
|
496
|
+
commitOid: r.commit?.oid,
|
|
473
497
|
})),
|
|
474
498
|
pr.assignees.nodes.map(r => ({
|
|
475
499
|
id: r.login,
|
|
@@ -4,12 +4,36 @@ import type {
|
|
|
4
4
|
CollectionScope,
|
|
5
5
|
CollectionScopeFailure,
|
|
6
6
|
} from '@gitkraken/provider-apis';
|
|
7
|
+
// Matched by its `code` discriminator rather than by `instanceof`: the SDK ships one bundle per entry point, so
|
|
8
|
+
// the class reached through the root is not the same object as the one reached through `/providers`.
|
|
9
|
+
import { isInvalidRequestError, isUnsupportedSortError } from '@gitkraken/provider-apis';
|
|
7
10
|
import { AuthenticationError, RequestNotFoundError, RequestRateLimitError } from '../../git/errors.js';
|
|
8
11
|
import type { IntegrationIds } from './constants.js';
|
|
9
12
|
import { isRateLimitResponse } from './errors.js';
|
|
10
13
|
import type { ProviderWarning, ProviderWarningOmission } from './results.js';
|
|
11
14
|
import { appendDedupedWarning } from './results.js';
|
|
12
15
|
|
|
16
|
+
/**
|
|
17
|
+
* Re-throws an error that is a fact about the CALL rather than about one scope of a fan-out.
|
|
18
|
+
*
|
|
19
|
+
* Every provider fan-out catches per-scope rejections and records them as {@link CollectionScopeFailure}s, which is
|
|
20
|
+
* right for auth, rate limits and a missing project: those really did happen to one scope, and the siblings that
|
|
21
|
+
* succeeded must survive. A caller-contract error is the opposite — it is identical for every scope and was decided
|
|
22
|
+
* before any request went out — so degrading it would hand back N indistinguishable failures and an empty `partial`
|
|
23
|
+
* page, describing an invalid call as an incomplete read.
|
|
24
|
+
*
|
|
25
|
+
* Today that means the SDK's `UnsupportedSortError` and `InvalidRequestError` — the two codes it lists in its own
|
|
26
|
+
* `CALLER_CONTRACT_ERROR_CODES`, both documented as "never degraded into a `CollectionScopeFailure` or an
|
|
27
|
+
* omission". The second covers arguments rejected before the first request goes out: a project key list longer
|
|
28
|
+
* than one Jira search can carry (or an empty one), a non-integer `pageSize`, an unknown current-user filter, or a
|
|
29
|
+
* Jira Server read with no `baseUrl` to address. Called from every fan-out rather than spelled out in each, so a
|
|
30
|
+
* fan-out added later inherits the rule instead of silently omitting it — which is exactly how Azure's
|
|
31
|
+
* account-wide drain came to degrade it while its three siblings did not.
|
|
32
|
+
*/
|
|
33
|
+
export function throwIfCallerContractError(ex: unknown): void {
|
|
34
|
+
if (isUnsupportedSortError(ex) || isInvalidRequestError(ex)) throw ex;
|
|
35
|
+
}
|
|
36
|
+
|
|
13
37
|
/**
|
|
14
38
|
* Maps a caught GitLens request error to the SDK collection failure vocabulary used inside provider fan-outs.
|
|
15
39
|
*/
|
|
@@ -67,19 +67,24 @@ import { createApiClients } from './providers/apiClients.js';
|
|
|
67
67
|
import type { GitHubApi } from './providers/github/github.js';
|
|
68
68
|
import type {
|
|
69
69
|
IssueFilter,
|
|
70
|
-
|
|
70
|
+
IssueSorting,
|
|
71
71
|
ProviderOrganization,
|
|
72
72
|
ProviderReposInput,
|
|
73
73
|
ProviderRepositoryShape,
|
|
74
74
|
PullRequestFilter,
|
|
75
|
-
PullRequestSearchCapabilities,
|
|
76
75
|
} from './providers/models.js';
|
|
77
76
|
import { providersMetadata } from './providers/models.js';
|
|
78
77
|
import type { ProvidersApi } from './providers/providersApi.js';
|
|
79
78
|
import { broadenIssues } from './reads/broaden.js';
|
|
80
79
|
import type { RepositoryResolutionContext } from './reads/context.js';
|
|
81
|
-
import type {
|
|
82
|
-
|
|
80
|
+
import type {
|
|
81
|
+
IssueCountResult,
|
|
82
|
+
IssueCountScope,
|
|
83
|
+
PullRequestCountResult,
|
|
84
|
+
PullRequestCountScope,
|
|
85
|
+
} from './reads/counts.js';
|
|
86
|
+
import { countIssues, countPullRequests } from './reads/counts.js';
|
|
87
|
+
import type { SupportedFilters } from './reads/filters.js';
|
|
83
88
|
import { getSupportedFilters } from './reads/filters.js';
|
|
84
89
|
import { listOrgs, listProjects, listRepos } from './reads/hierarchy.js';
|
|
85
90
|
import { listIssuesPage } from './reads/issues.js';
|
|
@@ -537,14 +542,7 @@ export class IntegrationService implements Disposable, RepositoryResolutionConte
|
|
|
537
542
|
* stays a method here even though it needs no instance state; see {@link getSupportedFilters} for the
|
|
538
543
|
* capability table itself and why a consumer should intersect against it before reading.
|
|
539
544
|
*/
|
|
540
|
-
getSupportedFilters(providerId: IntegrationIds): {
|
|
541
|
-
pullRequests: PullRequestFilter[];
|
|
542
|
-
pullRequestsAccountWide: PullRequestFilter[];
|
|
543
|
-
pullRequestSearch: PullRequestSearchCapabilities;
|
|
544
|
-
issues: IssueFilter[];
|
|
545
|
-
issuesAccountWide: IssueFilter[];
|
|
546
|
-
issueSearch: IssueSearchCapabilities;
|
|
547
|
-
} {
|
|
545
|
+
getSupportedFilters(providerId: IntegrationIds): SupportedFilters {
|
|
548
546
|
return getSupportedFilters(providerId);
|
|
549
547
|
}
|
|
550
548
|
|
|
@@ -1092,6 +1090,13 @@ export class IntegrationService implements Disposable, RepositoryResolutionConte
|
|
|
1092
1090
|
filters?: IssueFilter[];
|
|
1093
1091
|
/** Broadens the read to every assignee. Contradicts `filters`; passing both is refused. */
|
|
1094
1092
|
includeAllAssignees?: boolean;
|
|
1093
|
+
/**
|
|
1094
|
+
* How to order the page, as `field:direction`. Omitted orders most-recently-updated-first wherever the
|
|
1095
|
+
* provider can express it. Validated against `getSupportedFilters().issueSorts` on the repo-scoped path and
|
|
1096
|
+
* `.issueSortsAccountWide` on the account-wide one, and refused rather than downgraded; a key no normalized
|
|
1097
|
+
* issue carries is additionally refused for a page spanning several repositories/projects, which is a merge.
|
|
1098
|
+
*/
|
|
1099
|
+
sort?: IssueSorting;
|
|
1095
1100
|
page?: number;
|
|
1096
1101
|
cursor?: string;
|
|
1097
1102
|
itemsPerPage?: number;
|
|
@@ -1147,6 +1152,24 @@ export class IntegrationService implements Disposable, RepositoryResolutionConte
|
|
|
1147
1152
|
return countIssues(this, options);
|
|
1148
1153
|
}
|
|
1149
1154
|
|
|
1155
|
+
/**
|
|
1156
|
+
* How many pull requests match each scope, without fetching any — the PR twin of {@link countIssues}. See
|
|
1157
|
+
* {@link IntegrationManager.countPullRequests} for the cost model, the per-scope isolation rules, and why
|
|
1158
|
+
* `count: undefined` must not be rendered as zero.
|
|
1159
|
+
*/
|
|
1160
|
+
async countPullRequests(options: {
|
|
1161
|
+
providerId: IntegrationIds;
|
|
1162
|
+
scopes: readonly PullRequestCountScope[];
|
|
1163
|
+
connectionId?: string;
|
|
1164
|
+
/**
|
|
1165
|
+
* Explicit self-managed host domain. Used only when the requested connection has no configured domain;
|
|
1166
|
+
* it must come from the trusted authentication configuration, not repository or remote data.
|
|
1167
|
+
*/
|
|
1168
|
+
domain?: string;
|
|
1169
|
+
}): Promise<ProviderResult<PullRequestCountResult>> {
|
|
1170
|
+
return countPullRequests(this, options);
|
|
1171
|
+
}
|
|
1172
|
+
|
|
1150
1173
|
/**
|
|
1151
1174
|
* Reads the user's issues from an issue-tracker provider (Jira/Linear/Trello), whose issues live under
|
|
1152
1175
|
* resource → project (not repos), so they can't go through {@link listIssuesPage} (git-host, repo-scoped).
|
|
@@ -1174,6 +1197,11 @@ export class IntegrationService implements Disposable, RepositoryResolutionConte
|
|
|
1174
1197
|
project?: string;
|
|
1175
1198
|
filters?: IssueFilter[];
|
|
1176
1199
|
includeAllAssignees?: boolean;
|
|
1200
|
+
/**
|
|
1201
|
+
* How to order the issues, as `field:direction`. Validated against `getSupportedFilters().issueSorts`, which
|
|
1202
|
+
* is where a tracker reports; a key no normalized issue carries is refused for a multi-project page.
|
|
1203
|
+
*/
|
|
1204
|
+
sort?: IssueSorting;
|
|
1177
1205
|
forceSync?: boolean;
|
|
1178
1206
|
page?: number;
|
|
1179
1207
|
cursor?: string;
|
|
@@ -8,13 +8,14 @@ import type { Event } from '../../utils/event.js';
|
|
|
8
8
|
import type { ConfiguredIntegrationsChangeEvent } from './authentication/configuredIntegrationService.js';
|
|
9
9
|
import type { ConfiguredIntegrationDescriptor } from './authentication/models.js';
|
|
10
10
|
import type { IntegrationIds } from './constants.js';
|
|
11
|
+
import type { IssueFilter, IssueSorting, PullRequestFilter } from './providerFilters.js';
|
|
11
12
|
import type {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
} from './
|
|
17
|
-
import type {
|
|
13
|
+
IssueCountResult,
|
|
14
|
+
IssueCountScope,
|
|
15
|
+
PullRequestCountResult,
|
|
16
|
+
PullRequestCountScope,
|
|
17
|
+
} from './reads/counts.js';
|
|
18
|
+
import type { SupportedFilters } from './reads/filters.js';
|
|
18
19
|
import type {
|
|
19
20
|
ConnectionStateChangeEvent,
|
|
20
21
|
ProviderBroadenResult,
|
|
@@ -160,6 +161,22 @@ type PullRequestSweepCommonOptions = {
|
|
|
160
161
|
* This extends the provider-native result; it is not a narrowing filter.
|
|
161
162
|
*/
|
|
162
163
|
includeReviewRequested?: boolean;
|
|
164
|
+
/**
|
|
165
|
+
* Account-wide only: fetch the full PR projection (review decision, review requests, latest reviews)
|
|
166
|
+
* instead of the default summary/lite one. Opt-in because it enlarges every account-wide page; callers
|
|
167
|
+
* that classify by review state (e.g. a "needs my review" surface) set it, others keep the lean read.
|
|
168
|
+
*
|
|
169
|
+
* GitHub/GHE only today — no other provider's account-wide read has a projection switch, so they return
|
|
170
|
+
* their native shape regardless. A cross-provider sweep therefore gets reviews from GitHub targets and
|
|
171
|
+
* whatever the others natively carry; it is a breadth request, not a guarantee, so it does not refuse
|
|
172
|
+
* (unlike `filters`, where dropping a member would change the requested set).
|
|
173
|
+
*
|
|
174
|
+
* Projection only: it cannot change which pull requests come back. Every GitHub account-wide read goes through
|
|
175
|
+
* the same search whether or not it is set, so the Launchpad ignored-repository and organization qualifiers
|
|
176
|
+
* (and the per-facet result ceiling) apply the same either way. What it costs is the reduced page size, and a
|
|
177
|
+
* document whose weight scales with the number of relationship × state facets in flight.
|
|
178
|
+
*/
|
|
179
|
+
includeReviews?: boolean;
|
|
163
180
|
forceSync?: boolean;
|
|
164
181
|
maxPages?: number;
|
|
165
182
|
/**
|
|
@@ -281,24 +298,7 @@ export interface IntegrationManager {
|
|
|
281
298
|
* This is a capability table, not a recommendation: a consumer matching another tool's behavior may pass fewer
|
|
282
299
|
* filters than are listed, or none where the underlying read is already scoped.
|
|
283
300
|
*/
|
|
284
|
-
getSupportedFilters(providerId: IntegrationIds):
|
|
285
|
-
pullRequests: PullRequestFilter[];
|
|
286
|
-
/** Optional for structural compatibility; missing means no account-wide narrowing filters are supported. */
|
|
287
|
-
pullRequestsAccountWide?: PullRequestFilter[];
|
|
288
|
-
/**
|
|
289
|
-
* Criteria and scopes {@link searchPullRequestsPage} can express. Always present; an empty relationship list
|
|
290
|
-
* means the provider exposes no filtered pull-request search.
|
|
291
|
-
*/
|
|
292
|
-
pullRequestSearch: PullRequestSearchCapabilities;
|
|
293
|
-
issues: IssueFilter[];
|
|
294
|
-
issuesAccountWide: IssueFilter[];
|
|
295
|
-
/**
|
|
296
|
-
* What {@link searchIssuesPage} (and {@link countIssues}, over the same criteria) can express for this
|
|
297
|
-
* provider. Always present: a provider with no filtered issue search reports an empty `relationships` and
|
|
298
|
-
* all-false flags, which is the signal to hide that surface rather than to hide individual chips.
|
|
299
|
-
*/
|
|
300
|
-
issueSearch: IssueSearchCapabilities;
|
|
301
|
-
};
|
|
301
|
+
getSupportedFilters(providerId: IntegrationIds): SupportedFilters;
|
|
302
302
|
/** Forces an authoritative cloud connection refresh. Rejects if the backend connection list cannot be read. */
|
|
303
303
|
refreshConnections(): Promise<void>;
|
|
304
304
|
/** Rejects unless `connectionId` is a configured cloud connection for `id`. */
|
|
@@ -376,10 +376,17 @@ export interface IntegrationManager {
|
|
|
376
376
|
* GitHub's mismatched `involves:@me`. Omit relationships only with a repository/organization scope to search
|
|
377
377
|
* every PR there.
|
|
378
378
|
*
|
|
379
|
-
*
|
|
380
|
-
*
|
|
381
|
-
*
|
|
382
|
-
*
|
|
379
|
+
* **Ordering is `criteria.sort`**, most-recently-updated-first when omitted. It is validated like every other
|
|
380
|
+
* criterion — a key not in `getSupportedFilters().pullRequestSearch.sorts` refuses the whole read rather than
|
|
381
|
+
* falling back, because at a bounded result window another order reaches another subset. The page is a union of
|
|
382
|
+
* the provider's relationship × state facets, so it is re-ordered as a whole rather than served as concatenated
|
|
383
|
+
* per-facet runs. Changing the sort invalidates a threaded cursor (it is part of the cursor's fingerprint,
|
|
384
|
+
* alongside the text and the scope); drop the cursor when you change the order.
|
|
385
|
+
*
|
|
386
|
+
* If the provider's result ceiling is reached, the request still succeeds and carries a warning omission with
|
|
387
|
+
* `totalCount`, `limit`, `sort`, and `recovery: 'none'`. `totalCount` is the largest provider-reported
|
|
388
|
+
* pre-ceiling facet count, not the reachable or returned row count; this mirrors the per-search ceiling's own
|
|
389
|
+
* unit.
|
|
383
390
|
*
|
|
384
391
|
* Check `getSupportedFilters().pullRequestSearch` before calling. A provider that reports no relationships
|
|
385
392
|
* refuses the read rather than returning a page that never honored the criteria or scope.
|
|
@@ -427,6 +434,21 @@ export interface IntegrationManager {
|
|
|
427
434
|
filters?: IssueFilter[];
|
|
428
435
|
/** Broadens to every assignee. On account-wide reads it contradicts `filters`, so passing both is refused. */
|
|
429
436
|
includeAllAssignees?: boolean;
|
|
437
|
+
/**
|
|
438
|
+
* How to order the page, as `field:direction` (e.g. `updated:desc`, `created:asc`). Omitted orders
|
|
439
|
+
* most-recently-updated-first wherever the provider can express it — this facade's default, not the
|
|
440
|
+
* provider's, which differ from each other.
|
|
441
|
+
*
|
|
442
|
+
* Validated against `getSupportedFilters().issueSorts` when `repos` is supplied and
|
|
443
|
+
* `.issueSortsAccountWide` when it isn't, and refused (warning + `fetchFailed`) rather than downgraded: at
|
|
444
|
+
* the provider's reachable window another order is another subset, so a silently different one is
|
|
445
|
+
* indistinguishable from the one asked for. Keep it fixed across a pagination.
|
|
446
|
+
*
|
|
447
|
+
* With SEVERAL repositories/projects the page is a merge of one query each, so only a key a normalized
|
|
448
|
+
* issue carries can be honored — `priority`, `dueDate` and `resolved` are refused there even where the
|
|
449
|
+
* provider supports them on a single scope. The order applies within a page; across pages it is per scope.
|
|
450
|
+
*/
|
|
451
|
+
sort?: IssueSorting;
|
|
430
452
|
/**
|
|
431
453
|
* Requested 1-based page. Without a `cursor` this may cost O(page) upstream requests on cursor-backed
|
|
432
454
|
* reads such as repo-scoped GitHub/GHE; aggregate single-page account-wide reads remain O(1).
|
|
@@ -454,16 +476,21 @@ export interface IntegrationManager {
|
|
|
454
476
|
* - **Scope is mandatory.** Pass `repos`, `org`, or a user relationship (`authored`/`assigned`/`mentioned`).
|
|
455
477
|
* `any-assignee`/`unassigned` do NOT scope anything — either alone matches every such issue on the host —
|
|
456
478
|
* so a call carrying only those is refused (warning + `fetchFailed`).
|
|
457
|
-
* - **Ordering is
|
|
458
|
-
*
|
|
479
|
+
* - **Ordering is `criteria.sort`**, most-recently-updated-first when omitted. It is validated like every other
|
|
480
|
+
* criterion (against `getSupportedFilters().issueSearch.sorts`) and refused rather than downgraded, and SOME
|
|
481
|
+
* order is always requested — a "show the N most recent" policy at the provider's result ceiling is only
|
|
482
|
+
* correct under a guaranteed one. Keep it fixed for the life of a pagination: a cursor is bound to the order
|
|
483
|
+
* that produced it, and threading it under a different key is REFUSED (warning + `fetchFailed`) rather than
|
|
484
|
+
* resumed into a differently-ordered set. To change the order, drop the cursor and read from the first page.
|
|
459
485
|
* - **At the result ceiling the read SUCCEEDS.** It reports an omission carrying `totalCount` (how many
|
|
460
|
-
* matched)
|
|
461
|
-
* matched, showing the 1.000 most recent"
|
|
462
|
-
*
|
|
486
|
+
* matched), `limit` (how many are reachable) and `sort` (the order that window was selected under) with
|
|
487
|
+
* `recovery: 'none'`, so a consumer can say "19.240 matched, showing the 1.000 most recent" — naming the
|
|
488
|
+
* order, since which 1.000 are reachable depends on it — and know not to offer a "load more". It never falls
|
|
489
|
+
* back to a per-repository recovery walk.
|
|
463
490
|
*
|
|
464
491
|
* Check `getSupportedFilters().issueSearch` first: a provider with no filtered issue search reports empty
|
|
465
|
-
* relationships (and this read refuses), and a criterion it can't express refuses the whole read
|
|
466
|
-
* serving a wider result than asked for.
|
|
492
|
+
* relationships (and this read refuses), and a criterion or sort key it can't express refuses the whole read
|
|
493
|
+
* rather than serving a wider or differently-ordered result than asked for.
|
|
467
494
|
*/
|
|
468
495
|
searchIssuesPage(options: {
|
|
469
496
|
providerId: IntegrationIds;
|
|
@@ -519,6 +546,23 @@ export interface IntegrationManager {
|
|
|
519
546
|
/** Self-managed host domain fallback; see {@link ProviderSweepTarget.domain}. */
|
|
520
547
|
domain?: string;
|
|
521
548
|
}): Promise<ProviderResult<IssueCountResult>>;
|
|
549
|
+
/**
|
|
550
|
+
* How many pull requests match each scope, fetching none of them — the PR twin of {@link countIssues}, behind a
|
|
551
|
+
* "this will fetch ~N pull requests" preview and a live count next to an unapplied filter. Same cost model,
|
|
552
|
+
* per-scope isolation, `key`-echo, and `count: undefined` ≠ zero rule as the issue count; GitHub/GHE only.
|
|
553
|
+
*
|
|
554
|
+
* The one PR-specific difference: a scope's `states` are counted as independent searches, so the reported count
|
|
555
|
+
* is the LARGEST of them (the same total {@link searchPullRequestsPage} surfaces), not their sum. Several states
|
|
556
|
+
* in one scope are therefore fine; only several relationships are refused — one relationship per scope, see
|
|
557
|
+
* {@link PullRequestCountScope}.
|
|
558
|
+
*/
|
|
559
|
+
countPullRequests(options: {
|
|
560
|
+
providerId: IntegrationIds;
|
|
561
|
+
scopes: readonly PullRequestCountScope[];
|
|
562
|
+
connectionId?: string;
|
|
563
|
+
/** Self-managed host domain fallback; see {@link ProviderSweepTarget.domain}. */
|
|
564
|
+
domain?: string;
|
|
565
|
+
}): Promise<ProviderResult<PullRequestCountResult>>;
|
|
522
566
|
/** Issue trackers are cloud-only, so this read takes no `domain`. */
|
|
523
567
|
listIssueTrackerIssuesPage(options: {
|
|
524
568
|
providerId: IntegrationIds;
|
|
@@ -526,6 +570,16 @@ export interface IntegrationManager {
|
|
|
526
570
|
project?: string;
|
|
527
571
|
filters?: IssueFilter[];
|
|
528
572
|
includeAllAssignees?: boolean;
|
|
573
|
+
/**
|
|
574
|
+
* How to order the issues, as `field:direction`. Omitted orders most-recently-updated-first where the
|
|
575
|
+
* tracker can express it; validated against `getSupportedFilters().issueSorts` and refused rather than
|
|
576
|
+
* downgraded. A page spanning several projects is a merge, so a key no normalized issue carries
|
|
577
|
+
* (`priority`, `dueDate`, `resolved`) is refused there.
|
|
578
|
+
*
|
|
579
|
+
* Safe to change between pages, unlike the git-host reads: this cursor windows PROJECTS and drains each in
|
|
580
|
+
* full, so which projects a round covers doesn't depend on how their issues are ordered.
|
|
581
|
+
*/
|
|
582
|
+
sort?: IssueSorting;
|
|
529
583
|
forceSync?: boolean;
|
|
530
584
|
page?: number;
|
|
531
585
|
/**
|