@gitkraken/core-gitlens 0.5.104 → 0.5.106
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 +15 -1
- package/dist/git/models/pullRequest.d.ts +47 -0
- package/dist/git/models/pullRequest.d.ts.map +1 -1
- package/dist/git/models/pullRequest.js +8 -0
- package/dist/git/models/pullRequest.js.map +1 -1
- package/dist/plus/git-github/api/github.d.ts +33 -1
- package/dist/plus/git-github/api/github.d.ts.map +1 -1
- package/dist/plus/git-github/api/github.js +176 -0
- package/dist/plus/git-github/api/github.js.map +1 -1
- package/dist/plus/git-github/api/pullRequestSearchQuery.d.ts +16 -0
- package/dist/plus/git-github/api/pullRequestSearchQuery.d.ts.map +1 -0
- package/dist/plus/git-github/api/pullRequestSearchQuery.js +64 -0
- package/dist/plus/git-github/api/pullRequestSearchQuery.js.map +1 -0
- package/dist/plus/integrations/authentication/configuredIntegrationService.d.ts +1 -0
- package/dist/plus/integrations/authentication/configuredIntegrationService.d.ts.map +1 -1
- package/dist/plus/integrations/authentication/configuredIntegrationService.js +4 -1
- package/dist/plus/integrations/authentication/configuredIntegrationService.js.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 +16 -2
- package/dist/plus/integrations/integrationService.d.ts.map +1 -1
- package/dist/plus/integrations/integrationService.js +34 -23
- package/dist/plus/integrations/integrationService.js.map +1 -1
- package/dist/plus/integrations/manager.d.ts +46 -4
- package/dist/plus/integrations/manager.d.ts.map +1 -1
- package/dist/plus/integrations/models/gitHostIntegration.d.ts +22 -2
- package/dist/plus/integrations/models/gitHostIntegration.d.ts.map +1 -1
- package/dist/plus/integrations/models/gitHostIntegration.js +21 -0
- package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
- package/dist/plus/integrations/models/integration.d.ts +2 -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/pullRequestReads.d.ts +18 -0
- package/dist/plus/integrations/models/pullRequestReads.d.ts.map +1 -0
- package/dist/plus/integrations/models/pullRequestReads.js +2 -0
- package/dist/plus/integrations/models/pullRequestReads.js.map +1 -0
- package/dist/plus/integrations/providerFilters.d.ts +7 -6
- package/dist/plus/integrations/providerFilters.d.ts.map +1 -1
- package/dist/plus/integrations/providerFilters.js +1 -7
- package/dist/plus/integrations/providerFilters.js.map +1 -1
- package/dist/plus/integrations/providers/github.d.ts +14 -2
- package/dist/plus/integrations/providers/github.d.ts.map +1 -1
- package/dist/plus/integrations/providers/github.js +15 -0
- package/dist/plus/integrations/providers/github.js.map +1 -1
- package/dist/plus/integrations/providers/models.d.ts +12 -2
- package/dist/plus/integrations/providers/models.d.ts.map +1 -1
- package/dist/plus/integrations/providers/models.js +18 -0
- package/dist/plus/integrations/providers/models.js.map +1 -1
- package/dist/plus/integrations/reads/context.d.ts +1 -1
- package/dist/plus/integrations/reads/filters.d.ts +34 -1
- package/dist/plus/integrations/reads/filters.d.ts.map +1 -1
- package/dist/plus/integrations/reads/filters.js +73 -0
- package/dist/plus/integrations/reads/filters.js.map +1 -1
- package/dist/plus/integrations/reads/searchPullRequests.d.ts +26 -0
- package/dist/plus/integrations/reads/searchPullRequests.d.ts.map +1 -0
- package/dist/plus/integrations/reads/searchPullRequests.js +108 -0
- package/dist/plus/integrations/reads/searchPullRequests.js.map +1 -0
- package/dist/plus/integrations/reads/warnings.d.ts +6 -2
- package/dist/plus/integrations/reads/warnings.d.ts.map +1 -1
- package/dist/plus/integrations/reads/warnings.js +40 -0
- package/dist/plus/integrations/reads/warnings.js.map +1 -1
- package/docs/integrations.md +53 -4
- package/package.json +1 -1
- package/src/git/models/pullRequest.ts +50 -0
- package/src/plus/git-github/api/github.ts +254 -1
- package/src/plus/git-github/api/pullRequestSearchQuery.ts +80 -0
- package/src/plus/integrations/authentication/configuredIntegrationService.ts +6 -1
- package/src/plus/integrations/index.ts +2 -0
- package/src/plus/integrations/integrationService.ts +108 -70
- package/src/plus/integrations/manager.ts +55 -4
- package/src/plus/integrations/models/gitHostIntegration.ts +56 -2
- package/src/plus/integrations/models/integration.ts +2 -0
- package/src/plus/integrations/models/pullRequestReads.ts +18 -0
- package/src/plus/integrations/providerFilters.ts +8 -6
- package/src/plus/integrations/providers/github.ts +37 -1
- package/src/plus/integrations/providers/models.ts +37 -2
- package/src/plus/integrations/reads/context.ts +1 -1
- package/src/plus/integrations/reads/filters.ts +105 -0
- package/src/plus/integrations/reads/searchPullRequests.ts +210 -0
- package/src/plus/integrations/reads/warnings.ts +73 -3
|
@@ -5,6 +5,8 @@ import type {
|
|
|
5
5
|
IssueSearchCriteria,
|
|
6
6
|
IssueSearchRelationship,
|
|
7
7
|
PullRequestFilter,
|
|
8
|
+
PullRequestSearchCapabilities,
|
|
9
|
+
PullRequestSearchCriteria,
|
|
8
10
|
} from '../providerFilters.js';
|
|
9
11
|
import type { ProviderRepoInput, ProviderReposInput } from '../providers/models.js';
|
|
10
12
|
import { providersMetadata } from '../providers/models.js';
|
|
@@ -65,6 +67,88 @@ export function resolveAccountWidePullRequestFilters(
|
|
|
65
67
|
return { filters: [...new Set(filters)], unsupported: false };
|
|
66
68
|
}
|
|
67
69
|
|
|
70
|
+
/** Why {@link resolvePullRequestSearchCriteria} refused a criteria set. */
|
|
71
|
+
export type PullRequestSearchCriteriaRejection =
|
|
72
|
+
/** The provider has no filtered pull-request search. */
|
|
73
|
+
| { reason: 'unsupported-search' }
|
|
74
|
+
/** The provider has one, but cannot express every requested criterion server-side. */
|
|
75
|
+
| { reason: 'unsupported-criteria'; criteria: string[] };
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Validates filtered pull-request search criteria all-or-nothing. Dropping an unsupported criterion would
|
|
79
|
+
* widen the provider query while leaving its page and cursor describing the wider set, so the facade refuses the
|
|
80
|
+
* request before any upstream call instead.
|
|
81
|
+
*/
|
|
82
|
+
export function resolvePullRequestSearchCriteria(
|
|
83
|
+
id: IntegrationIds,
|
|
84
|
+
criteria: PullRequestSearchCriteria | undefined,
|
|
85
|
+
): { rejection?: PullRequestSearchCriteriaRejection } {
|
|
86
|
+
const supported = providersMetadata[id]?.supportedPullRequestSearch;
|
|
87
|
+
if (supported == null || supported.relationships.length === 0) {
|
|
88
|
+
return { rejection: { reason: 'unsupported-search' } };
|
|
89
|
+
}
|
|
90
|
+
if (criteria == null) return {};
|
|
91
|
+
|
|
92
|
+
const unsupported: string[] = [];
|
|
93
|
+
for (const relationship of criteria.relationships ?? []) {
|
|
94
|
+
if (!supported.relationships.includes(relationship)) {
|
|
95
|
+
unsupported.push(`relationships:${relationship}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
for (const state of criteria.states ?? []) {
|
|
99
|
+
if (!supported.states.includes(state)) {
|
|
100
|
+
unsupported.push(`states:${state}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (criteria.text != null && criteria.text.trim().length > 0 && !supported.text) {
|
|
104
|
+
unsupported.push('text');
|
|
105
|
+
}
|
|
106
|
+
if (criteria.includeArchived === true && !supported.includeArchived) {
|
|
107
|
+
unsupported.push('includeArchived');
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return unsupported.length > 0 ? { rejection: { reason: 'unsupported-criteria', criteria: unsupported } } : {};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** Why a filtered pull-request search's repository/organization boundary was refused. */
|
|
114
|
+
export type PullRequestSearchScopeRejection =
|
|
115
|
+
| 'unscoped'
|
|
116
|
+
| 'repo-ids'
|
|
117
|
+
| 'unsupported-repository-scope'
|
|
118
|
+
| 'unsupported-organization-scope';
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Validates the search boundary independently from its criteria. A current-user relationship is itself a safe
|
|
122
|
+
* account-wide boundary; without one, a repository or organization scope is mandatory.
|
|
123
|
+
*/
|
|
124
|
+
export function resolvePullRequestSearchScope(
|
|
125
|
+
id: IntegrationIds,
|
|
126
|
+
repos: ProviderReposInput | undefined,
|
|
127
|
+
org: string | undefined,
|
|
128
|
+
criteria: PullRequestSearchCriteria | undefined,
|
|
129
|
+
): { rejection?: PullRequestSearchScopeRejection; repos?: ProviderRepoInput[] } {
|
|
130
|
+
const supported = providersMetadata[id]?.supportedPullRequestSearch;
|
|
131
|
+
let resolvedRepos: ProviderRepoInput[] | undefined;
|
|
132
|
+
|
|
133
|
+
if (repos?.length) {
|
|
134
|
+
if (repos.some(r => typeof r === 'string' || typeof r === 'number')) return { rejection: 'repo-ids' };
|
|
135
|
+
if (supported?.repositoryScope !== true) return { rejection: 'unsupported-repository-scope' };
|
|
136
|
+
|
|
137
|
+
resolvedRepos = repos as ProviderRepoInput[];
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const hasOrganizationScope = org != null && org.length > 0;
|
|
141
|
+
if (hasOrganizationScope && supported?.organizationScope !== true) {
|
|
142
|
+
return { rejection: 'unsupported-organization-scope' };
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (resolvedRepos != null || hasOrganizationScope || (criteria?.relationships?.length ?? 0) > 0) {
|
|
146
|
+
return { repos: resolvedRepos };
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return { rejection: 'unscoped' };
|
|
150
|
+
}
|
|
151
|
+
|
|
68
152
|
/**
|
|
69
153
|
* Validates a caller-provided issue filter set against what the provider's ACCOUNT-WIDE issue read can express
|
|
70
154
|
* server-side (`ProviderMetadata.supportedAccountWideIssueFilters`), which is a different — usually narrower —
|
|
@@ -182,6 +266,16 @@ const unsupportedIssueSearchCapabilities: IssueSearchCapabilities = {
|
|
|
182
266
|
states: false,
|
|
183
267
|
};
|
|
184
268
|
|
|
269
|
+
/** What a provider with no filtered pull-request search reports. */
|
|
270
|
+
const unsupportedPullRequestSearchCapabilities: PullRequestSearchCapabilities = {
|
|
271
|
+
relationships: [],
|
|
272
|
+
states: [],
|
|
273
|
+
text: false,
|
|
274
|
+
includeArchived: false,
|
|
275
|
+
repositoryScope: false,
|
|
276
|
+
organizationScope: false,
|
|
277
|
+
};
|
|
278
|
+
|
|
185
279
|
/** Why a filtered issue search's scope was refused, or `undefined` when it is usable. */
|
|
186
280
|
export type IssueSearchScopeRejection =
|
|
187
281
|
/** No repositories, no org, and no user-relative relationship: a search of the whole host. */
|
|
@@ -248,6 +342,9 @@ export function resolveIssueSearchScope(
|
|
|
248
342
|
* rather than a list, because its criteria aren't a single kind. An empty `relationships` means the provider has
|
|
249
343
|
* no filtered issue search — hide the surface, not just its chips.
|
|
250
344
|
*
|
|
345
|
+
* `pullRequestSearch` describes the separate filtered PR search. Its table declares each criteria vocabulary
|
|
346
|
+
* plus repository/organization scope support; an empty relationship list means the search itself is absent.
|
|
347
|
+
*
|
|
251
348
|
* Note this is a CAPABILITY table — "what the provider can express" — not a recommendation. A consumer
|
|
252
349
|
* matching another tool's behavior may deliberately pass fewer filters than are listed here (or none, where an
|
|
253
350
|
* already-scoped read would only be narrowed by them). Intersecting against this table is what keeps a
|
|
@@ -256,15 +353,23 @@ export function resolveIssueSearchScope(
|
|
|
256
353
|
export function getSupportedFilters(providerId: IntegrationIds): {
|
|
257
354
|
pullRequests: PullRequestFilter[];
|
|
258
355
|
pullRequestsAccountWide: PullRequestFilter[];
|
|
356
|
+
pullRequestSearch: PullRequestSearchCapabilities;
|
|
259
357
|
issues: IssueFilter[];
|
|
260
358
|
issuesAccountWide: IssueFilter[];
|
|
261
359
|
issueSearch: IssueSearchCapabilities;
|
|
262
360
|
} {
|
|
263
361
|
const metadata = providersMetadata[providerId];
|
|
264
362
|
const issueSearch = metadata?.supportedIssueSearch;
|
|
363
|
+
const pullRequestSearch = metadata?.supportedPullRequestSearch;
|
|
265
364
|
return {
|
|
266
365
|
pullRequests: [...(metadata?.supportedPullRequestFilters ?? [])],
|
|
267
366
|
pullRequestsAccountWide: [...(metadata?.supportedAccountWidePullRequestFilters ?? [])],
|
|
367
|
+
pullRequestSearch: {
|
|
368
|
+
...unsupportedPullRequestSearchCapabilities,
|
|
369
|
+
...pullRequestSearch,
|
|
370
|
+
relationships: [...(pullRequestSearch?.relationships ?? [])],
|
|
371
|
+
states: [...(pullRequestSearch?.states ?? [])],
|
|
372
|
+
},
|
|
268
373
|
issues: [...(metadata?.supportedIssueFilters ?? [])],
|
|
269
374
|
issuesAccountWide: [...(metadata?.supportedAccountWideIssueFilters ?? [])],
|
|
270
375
|
// Always an object, never `undefined`: a provider WITHOUT a filtered issue search reports one whose
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
import type { PullRequestSearchCriteria, PullRequestShape } from '../../../git/models/pullRequest.js';
|
|
2
|
+
import type { IntegrationIds } from '../constants.js';
|
|
3
|
+
import type { ProviderReposInput } from '../providers/models.js';
|
|
4
|
+
import type { ProviderPagedResult, ProviderWarning } from '../results.js';
|
|
5
|
+
import {
|
|
6
|
+
isGitHostIntegration,
|
|
7
|
+
isIssuesHostIntegrationId,
|
|
8
|
+
warnOnMissingSessionForDomain,
|
|
9
|
+
} from '../utils/integration.utils.js';
|
|
10
|
+
import type { ProviderReadContext } from './context.js';
|
|
11
|
+
import { runCaptured } from './drains.js';
|
|
12
|
+
import { resolvePullRequestSearchCriteria, resolvePullRequestSearchScope } from './filters.js';
|
|
13
|
+
import {
|
|
14
|
+
drainFlatPagesToRequestedPage,
|
|
15
|
+
refusedPage,
|
|
16
|
+
resolveContinuation,
|
|
17
|
+
resolveCurrentPage,
|
|
18
|
+
usableCursor,
|
|
19
|
+
} from './paging.js';
|
|
20
|
+
import {
|
|
21
|
+
gitHostOnlySurfaceWarning,
|
|
22
|
+
otherWarning,
|
|
23
|
+
pullRequestSearchCapResultWarning,
|
|
24
|
+
truncationWarning,
|
|
25
|
+
unsupportedPullRequestSearchCriteriaWarning,
|
|
26
|
+
} from './warnings.js';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Pull requests matching structured criteria over a repository/organization or current-user relationship scope.
|
|
30
|
+
*
|
|
31
|
+
* The read is deliberately separate from `listPullRequestsPage`: the list has provider-specific "my PRs"
|
|
32
|
+
* semantics and no text channel, while this method promises a sanitized query, most-recently-updated-first
|
|
33
|
+
* ordering, one upstream request per cursor-threaded page, and a quantified omission at the provider's result
|
|
34
|
+
* ceiling.
|
|
35
|
+
*/
|
|
36
|
+
export async function searchPullRequestsPage(
|
|
37
|
+
ctx: ProviderReadContext,
|
|
38
|
+
options: {
|
|
39
|
+
providerId: IntegrationIds;
|
|
40
|
+
repos?: ProviderReposInput;
|
|
41
|
+
org?: string;
|
|
42
|
+
criteria?: PullRequestSearchCriteria;
|
|
43
|
+
page?: number;
|
|
44
|
+
cursor?: string;
|
|
45
|
+
itemsPerPage?: number;
|
|
46
|
+
forceSync?: boolean;
|
|
47
|
+
connectionId?: string;
|
|
48
|
+
domain?: string;
|
|
49
|
+
},
|
|
50
|
+
): Promise<ProviderPagedResult<PullRequestShape>> {
|
|
51
|
+
const page = Math.max(1, Math.trunc(options.page ?? 1));
|
|
52
|
+
const refused = (warning: ProviderWarning) => refusedPage<PullRequestShape>(1, [warning], true);
|
|
53
|
+
|
|
54
|
+
if (isIssuesHostIntegrationId(options.providerId)) {
|
|
55
|
+
return refused(
|
|
56
|
+
gitHostOnlySurfaceWarning(
|
|
57
|
+
options.providerId,
|
|
58
|
+
undefined,
|
|
59
|
+
options.connectionId,
|
|
60
|
+
'Filtered pull request search',
|
|
61
|
+
),
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const integration = await ctx.getIntegrationForRead(options.providerId, options.connectionId, options.domain);
|
|
66
|
+
if (integration == null) {
|
|
67
|
+
const early = ctx.earlyReturnConnectionWarnings(options.providerId, options.connectionId, options.domain);
|
|
68
|
+
return refusedPage(1, early.warnings, early.fetchFailed);
|
|
69
|
+
}
|
|
70
|
+
if (!isGitHostIntegration(integration)) {
|
|
71
|
+
return refused(
|
|
72
|
+
gitHostOnlySurfaceWarning(
|
|
73
|
+
options.providerId,
|
|
74
|
+
undefined,
|
|
75
|
+
options.connectionId,
|
|
76
|
+
'Filtered pull request search',
|
|
77
|
+
),
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
await ctx.forceRefreshIfRequested(integration, options.forceSync, options.connectionId);
|
|
82
|
+
|
|
83
|
+
const domain = ctx.domainForRead(integration, options.providerId, options.connectionId, options.domain);
|
|
84
|
+
const warnOnMissingSession = warnOnMissingSessionForDomain(options.providerId, options.domain);
|
|
85
|
+
|
|
86
|
+
const resolved = resolvePullRequestSearchCriteria(options.providerId, options.criteria);
|
|
87
|
+
if (resolved.rejection != null) {
|
|
88
|
+
return refused(
|
|
89
|
+
unsupportedPullRequestSearchCriteriaWarning(
|
|
90
|
+
options.providerId,
|
|
91
|
+
domain,
|
|
92
|
+
options.connectionId,
|
|
93
|
+
resolved.rejection,
|
|
94
|
+
),
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const scope = resolvePullRequestSearchScope(options.providerId, options.repos, options.org, options.criteria);
|
|
99
|
+
switch (scope.rejection) {
|
|
100
|
+
case 'unscoped':
|
|
101
|
+
return refused(
|
|
102
|
+
otherWarning(
|
|
103
|
+
options.providerId,
|
|
104
|
+
domain,
|
|
105
|
+
options.connectionId,
|
|
106
|
+
'A filtered pull request search must be scoped: pass `repos`, `org`, or at least one current-user relationship.',
|
|
107
|
+
),
|
|
108
|
+
);
|
|
109
|
+
case 'repo-ids':
|
|
110
|
+
return refused(
|
|
111
|
+
otherWarning(
|
|
112
|
+
options.providerId,
|
|
113
|
+
domain,
|
|
114
|
+
options.connectionId,
|
|
115
|
+
'A filtered pull request search cannot be scoped by repository id; pass repository descriptors (namespace + name) instead.',
|
|
116
|
+
),
|
|
117
|
+
);
|
|
118
|
+
case 'unsupported-repository-scope':
|
|
119
|
+
case 'unsupported-organization-scope':
|
|
120
|
+
return refused(
|
|
121
|
+
unsupportedPullRequestSearchCriteriaWarning(options.providerId, domain, options.connectionId, {
|
|
122
|
+
reason: 'unsupported-criteria',
|
|
123
|
+
criteria: [
|
|
124
|
+
scope.rejection === 'unsupported-repository-scope' ? 'repositoryScope' : 'organizationScope',
|
|
125
|
+
],
|
|
126
|
+
}),
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const readPage = (cursor: string | undefined) =>
|
|
131
|
+
runCaptured(
|
|
132
|
+
options.providerId,
|
|
133
|
+
domain,
|
|
134
|
+
options.connectionId,
|
|
135
|
+
() =>
|
|
136
|
+
integration.searchPullRequestsPageResult(
|
|
137
|
+
{
|
|
138
|
+
repos: scope.repos,
|
|
139
|
+
org: options.org,
|
|
140
|
+
criteria: options.criteria,
|
|
141
|
+
cursor: cursor,
|
|
142
|
+
pageSize: options.itemsPerPage,
|
|
143
|
+
},
|
|
144
|
+
undefined,
|
|
145
|
+
options.connectionId,
|
|
146
|
+
),
|
|
147
|
+
{ warnOnMissingSession: warnOnMissingSession },
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
const first = await readPage(options.cursor);
|
|
151
|
+
const warnings = first.warning != null ? [first.warning] : [];
|
|
152
|
+
let totalCount = first.value?.totalCount;
|
|
153
|
+
const drained = await drainFlatPagesToRequestedPage(first, {
|
|
154
|
+
requestedPage: page,
|
|
155
|
+
suppliedCursor: options.cursor,
|
|
156
|
+
warnings: warnings,
|
|
157
|
+
readPage: readPage,
|
|
158
|
+
fold: p => {
|
|
159
|
+
if (p.totalCount != null) {
|
|
160
|
+
totalCount = Math.max(totalCount ?? 0, p.totalCount);
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
const { value, currentPage, requestedPageMissing } = drained;
|
|
165
|
+
|
|
166
|
+
if (value == null && warnings.length === 0) {
|
|
167
|
+
return refused(
|
|
168
|
+
unsupportedPullRequestSearchCriteriaWarning(options.providerId, domain, options.connectionId, {
|
|
169
|
+
reason: 'unsupported-search',
|
|
170
|
+
}),
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const items = requestedPageMissing ? [] : (value?.values ?? []);
|
|
175
|
+
const continuation = resolveContinuation(
|
|
176
|
+
{
|
|
177
|
+
hasMore: requestedPageMissing ? false : (value?.hasMore ?? false),
|
|
178
|
+
cursor: requestedPageMissing ? undefined : usableCursor(value?.cursor),
|
|
179
|
+
truncated: drained.truncated,
|
|
180
|
+
},
|
|
181
|
+
undefined,
|
|
182
|
+
);
|
|
183
|
+
const truncated = continuation.truncated;
|
|
184
|
+
if (truncated && warnings.length === 0) {
|
|
185
|
+
warnings.push(
|
|
186
|
+
pullRequestSearchCapResultWarning(options.providerId, domain, options.connectionId, totalCount) ??
|
|
187
|
+
truncationWarning(options.providerId, domain, options.connectionId, 'Pull request search', 'exhausted'),
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
items: items,
|
|
193
|
+
warnings: warnings,
|
|
194
|
+
page: {
|
|
195
|
+
currentPage: requestedPageMissing
|
|
196
|
+
? page
|
|
197
|
+
: resolveCurrentPage({
|
|
198
|
+
providerPage: currentPage,
|
|
199
|
+
requestedPage: page,
|
|
200
|
+
suppliedCursor: options.cursor,
|
|
201
|
+
pageAdvanceable: false,
|
|
202
|
+
}),
|
|
203
|
+
itemsPerPage: items.length,
|
|
204
|
+
truncated: truncated || undefined,
|
|
205
|
+
},
|
|
206
|
+
hasMore: continuation.hasMore,
|
|
207
|
+
cursor: continuation.cursor,
|
|
208
|
+
fetchFailed: drained.fetchFailed || undefined,
|
|
209
|
+
};
|
|
210
|
+
}
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
import type { IntegrationIds } from '../constants.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
IssueFilter,
|
|
4
|
+
IssueSearchCapabilities,
|
|
5
|
+
PullRequestFilter,
|
|
6
|
+
PullRequestSearchCapabilities,
|
|
7
|
+
} from '../providerFilters.js';
|
|
3
8
|
import { providersMetadata } from '../providers/models.js';
|
|
4
9
|
import type { ProviderWarning } from '../results.js';
|
|
5
|
-
import type { IssueSearchCriteriaRejection } from './filters.js';
|
|
10
|
+
import type { IssueSearchCriteriaRejection, PullRequestSearchCriteriaRejection } from './filters.js';
|
|
6
11
|
|
|
7
12
|
/**
|
|
8
13
|
* The warnings the provider facade raises on its OWN terms, as opposed to the ones derived from a caught
|
|
@@ -154,7 +159,8 @@ type TruncatedReadKind =
|
|
|
154
159
|
| 'Organization'
|
|
155
160
|
| 'Project'
|
|
156
161
|
| 'Account-wide issue search'
|
|
157
|
-
| 'Issue search'
|
|
162
|
+
| 'Issue search'
|
|
163
|
+
| 'Pull request search';
|
|
158
164
|
|
|
159
165
|
/** {@link incompleteReadWarning} for a paged or drained read, phrased per surface. */
|
|
160
166
|
export function truncationWarning(
|
|
@@ -246,6 +252,44 @@ export function unsupportedFiltersWarning(
|
|
|
246
252
|
);
|
|
247
253
|
}
|
|
248
254
|
|
|
255
|
+
/** Warning for a filtered pull-request search the provider cannot run as requested. */
|
|
256
|
+
export function unsupportedPullRequestSearchCriteriaWarning(
|
|
257
|
+
id: IntegrationIds,
|
|
258
|
+
domain: string | undefined,
|
|
259
|
+
connectionId: string | undefined,
|
|
260
|
+
rejection: PullRequestSearchCriteriaRejection,
|
|
261
|
+
): ProviderWarning {
|
|
262
|
+
let message: string;
|
|
263
|
+
switch (rejection.reason) {
|
|
264
|
+
case 'unsupported-search':
|
|
265
|
+
message = `Filtered pull request search is not supported by '${id}'; use \`listPullRequestsPage\` for its own pull request reads.`;
|
|
266
|
+
break;
|
|
267
|
+
case 'unsupported-criteria': {
|
|
268
|
+
const supported = providersMetadata[id]?.supportedPullRequestSearch;
|
|
269
|
+
message = unsupportedNarrowingMessage(
|
|
270
|
+
id,
|
|
271
|
+
'pull request search criteria',
|
|
272
|
+
rejection.criteria.join(', '),
|
|
273
|
+
supported != null ? describePullRequestSearchCapabilities(supported) : '',
|
|
274
|
+
);
|
|
275
|
+
break;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
return otherWarning(id, domain, connectionId, message);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function describePullRequestSearchCapabilities(capabilities: PullRequestSearchCapabilities): string {
|
|
283
|
+
return [
|
|
284
|
+
...(capabilities.relationships.length ? [`relationships:${capabilities.relationships.join('|')}`] : []),
|
|
285
|
+
...(capabilities.states.length ? [`states:${capabilities.states.join('|')}`] : []),
|
|
286
|
+
...(capabilities.text ? ['text'] : []),
|
|
287
|
+
...(capabilities.includeArchived ? ['includeArchived'] : []),
|
|
288
|
+
...(capabilities.repositoryScope ? ['repository scope'] : []),
|
|
289
|
+
...(capabilities.organizationScope ? ['organization scope'] : []),
|
|
290
|
+
].join(', ');
|
|
291
|
+
}
|
|
292
|
+
|
|
249
293
|
/**
|
|
250
294
|
* Warning for a filtered issue search whose criteria the provider can't serve — either it has no such search at
|
|
251
295
|
* all, or it can't express what was asked for, or the set contradicts itself.
|
|
@@ -343,6 +387,32 @@ export function issueSearchCapResultWarning(
|
|
|
343
387
|
};
|
|
344
388
|
}
|
|
345
389
|
|
|
390
|
+
/** Quantified omission for a pull-request search that exceeded the provider's reachable result window. */
|
|
391
|
+
export function pullRequestSearchCapResultWarning(
|
|
392
|
+
id: IntegrationIds,
|
|
393
|
+
domain: string | undefined,
|
|
394
|
+
connectionId: string | undefined,
|
|
395
|
+
totalCount: number | undefined,
|
|
396
|
+
): ProviderWarning | undefined {
|
|
397
|
+
const limit = providersMetadata[id]?.pullRequestSearchResultLimit;
|
|
398
|
+
if (limit == null || totalCount == null || totalCount <= limit) return undefined;
|
|
399
|
+
|
|
400
|
+
return {
|
|
401
|
+
...otherWarning(
|
|
402
|
+
id,
|
|
403
|
+
domain,
|
|
404
|
+
connectionId,
|
|
405
|
+
`Pull request search matched ${totalCount} results, but '${id}' serves at most ${limit}; narrow the search to read the rest.`,
|
|
406
|
+
),
|
|
407
|
+
omission: {
|
|
408
|
+
kind: 'provider-limit',
|
|
409
|
+
recovery: 'none',
|
|
410
|
+
limit: limit,
|
|
411
|
+
totalCount: totalCount,
|
|
412
|
+
},
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
|
|
346
416
|
/** Warning for a git host that doesn't expose issues on this surface (e.g. Bitbucket, deprecated in favor of Jira). */
|
|
347
417
|
export function issuesUnsupportedWarning(
|
|
348
418
|
id: IntegrationIds,
|