@gitkraken/core-gitlens 0.18.0 → 0.19.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -1
- package/dist/git/models/issue.d.ts +13 -3
- package/dist/git/models/issue.js +3 -1
- package/dist/git/models/issue.js.map +1 -1
- package/dist/git/models/pullRequest.d.ts +13 -2
- package/dist/git/models/pullRequest.js +3 -1
- package/dist/git/models/pullRequest.js.map +1 -1
- package/dist/git/utils/issue.utils.js +2 -1
- package/dist/git/utils/issue.utils.js.map +1 -1
- package/dist/git/utils/pullRequest.utils.js +1 -0
- package/dist/git/utils/pullRequest.utils.js.map +1 -1
- package/dist/plus/integrations/models/gitHostIntegration.d.ts +7 -6
- package/dist/plus/integrations/models/gitHostIntegration.js +4 -3
- package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
- package/dist/plus/integrations/models/integration.d.ts +5 -0
- package/dist/plus/integrations/models/integration.js.map +1 -1
- package/dist/plus/integrations/providers/azure/azure.d.ts +8 -6
- package/dist/plus/integrations/providers/azure/azure.js +3 -2
- package/dist/plus/integrations/providers/azure/azure.js.map +1 -1
- package/dist/plus/integrations/providers/azure/models.d.ts +4 -2
- package/dist/plus/integrations/providers/azure/models.js +6 -5
- package/dist/plus/integrations/providers/azure/models.js.map +1 -1
- package/dist/plus/integrations/providers/azureDevOps.d.ts +15 -13
- package/dist/plus/integrations/providers/azureDevOps.js +26 -22
- package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
- package/dist/plus/integrations/providers/azureDevOpsServer.js +6 -3
- package/dist/plus/integrations/providers/azureDevOpsServer.js.map +1 -1
- package/dist/plus/integrations/providers/issueSorts.d.ts +1 -0
- package/dist/plus/integrations/providers/models.d.ts +26 -4
- package/dist/plus/integrations/providers/models.js +27 -5
- package/dist/plus/integrations/providers/models.js.map +1 -1
- package/dist/plus/integrations/reads/drains.d.ts +2 -1
- package/dist/plus/integrations/reads/drains.js.map +1 -1
- package/dist/plus/integrations/reads/etag.js +3 -1
- package/dist/plus/integrations/reads/etag.js.map +1 -1
- package/docs/integrations.md +21 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,16 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.19.0] - 2026-10-26
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- Adds `viewerUnresolved?: true` to `IssueShape`/`Issue` and `PullRequestShape`/`PullRequest`: set on an Azure DevOps or Azure DevOps Server work item or pull request that names someone when the user's identity in its organization (collection) couldn't be read, because its `ConnectionData` failed, answered without an identity or took more than 10 seconds. Such a row has no `viewer` and, on a pull request, no `authoredByMe`, and a host should treat whether it's the user's as unknown rather than match it against `getCurrentAccount`, whose id is the one that may not match there. Every read that stamps `viewer` on those rows sets it: `listIssuesPage`, `getIssuesBatch`, the work item point read and Azure DevOps Server's `searchIssuesPage`; the repository-scoped `listPullRequestsPage` and sweeps, `getPullRequestsBatch`, `getPullRequestsForBranches` and Azure DevOps Server's `searchPullRequestsPage` without a current-user relationship. The account-wide pull request reads and a relationship search still report such an organization as a failed scope instead, since they filter by that identity. Absent on every other row, so a row with neither field still means what it did. A pull request row marked this way never compares unchanged on `getPullRequestsBatch`'s etag check, as a work item already didn't, so it's read in full again once the identity can be read ([#6083](https://github.com/gitkraken/vscode-gitlens/issues/6083)) (git, plus/integrations)
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
|
|
17
|
+
- Fixes Azure DevOps Server's `searchPullRequestsPage` without a current-user relationship leaving its rows without `viewer` and `authoredByMe`: it now resolves the user's identity in the collection of each row it serves, as the other pull request reads do ([#6083](https://github.com/gitkraken/vscode-gitlens/issues/6083)) (plus/integrations)
|
|
18
|
+
|
|
9
19
|
## [0.18.0] - 2026-10-25
|
|
10
20
|
|
|
11
21
|
## [0.17.0] - 2026-10-25
|
|
@@ -958,7 +968,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
|
|
|
958
968
|
|
|
959
969
|
- Initial release. Bundles `@gitlens/utils`, `@gitlens/git`, `@gitlens/git-cli`, `@gitlens/ai`, and `@gitlens/git-github` into a single core npm package with subpath exports.
|
|
960
970
|
|
|
961
|
-
[unreleased]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.
|
|
971
|
+
[unreleased]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.19.0...HEAD
|
|
972
|
+
[0.19.0]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.18.0...gitkraken:releases/core/v0.19.0
|
|
962
973
|
[0.18.0]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.17.0...gitkraken:releases/core/v0.18.0
|
|
963
974
|
[0.17.0]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.16.5...gitkraken:releases/core/v0.17.0
|
|
964
975
|
[0.16.5]: https://github.com/gitkraken/vscode-gitlens/compare/releases/core/v0.16.4...gitkraken:releases/core/v0.16.5
|
|
@@ -201,13 +201,22 @@ export interface IssueShape extends IssueOrPullRequest {
|
|
|
201
201
|
* `getCurrentAccount` returns: Azure DevOps can know one person by another id in each organization (Azure DevOps
|
|
202
202
|
* Server: collection) than the account's, and a work item's {@link author} and {@link assignees} carry the
|
|
203
203
|
* organization's. A consumer matching them to the current user compares against this when present, and against
|
|
204
|
-
* the account otherwise. Absent on every other provider, and on an Azure
|
|
205
|
-
* couldn't be read.
|
|
204
|
+
* the account otherwise, unless {@link viewerUnresolved} is set. Absent on every other provider, and on an Azure
|
|
205
|
+
* DevOps row whose organization's identity couldn't be read.
|
|
206
206
|
*/
|
|
207
207
|
readonly viewer?: {
|
|
208
208
|
readonly id: string;
|
|
209
209
|
readonly username?: string;
|
|
210
210
|
};
|
|
211
|
+
/**
|
|
212
|
+
* Set, and only ever `true`, on an Azure DevOps row that names someone ({@link author} or {@link assignees}) whose
|
|
213
|
+
* organization's (Azure DevOps Server: collection's) identity the read tried and failed to resolve: its
|
|
214
|
+
* `ConnectionData` failed, answered without an identity, or didn't answer within 10 seconds. Such a row has no
|
|
215
|
+
* {@link viewer}, and neither the account `getCurrentAccount` returns nor anyone else can be matched against its
|
|
216
|
+
* people: whether it is the current user's is unknown, not "no". Absent everywhere else, so a row with neither
|
|
217
|
+
* field is still one whose provider has no per-row identity, matched against the account.
|
|
218
|
+
*/
|
|
219
|
+
readonly viewerUnresolved?: true;
|
|
211
220
|
}
|
|
212
221
|
export declare class Issue implements IssueShape {
|
|
213
222
|
readonly provider: ProviderReference;
|
|
@@ -239,11 +248,12 @@ export declare class Issue implements IssueShape {
|
|
|
239
248
|
readonly id: string;
|
|
240
249
|
readonly username?: string;
|
|
241
250
|
} | undefined;
|
|
251
|
+
readonly viewerUnresolved?: true | undefined;
|
|
242
252
|
readonly type = "issue";
|
|
243
253
|
constructor(provider: ProviderReference, id: string, nodeId: string | undefined, title: string, url: string, createdDate: Date, updatedDate: Date, closed: boolean, state: IssueOrPullRequestState | undefined, author: IssueMember | undefined, assignees: IssueMember[], repository?: IssueRepository | undefined, closedDate?: Date | undefined, labels?: IssueLabel[] | undefined, commentsCount?: number | undefined, thumbsUpCount?: number | undefined, body?: string | undefined, project?: IssueProject | undefined, number?: string | undefined, issueType?: string | undefined, providerState?: IssueProviderState | undefined, bodyFormat?: IssueBodyFormat | undefined, iterations?: IssueIteration[] | undefined, projection?: IssueProjection | undefined, bodyField?: IssueBodyField | undefined, viewer?: {
|
|
244
254
|
readonly id: string;
|
|
245
255
|
readonly username?: string;
|
|
246
|
-
} | undefined);
|
|
256
|
+
} | undefined, viewerUnresolved?: true | undefined);
|
|
247
257
|
static is(issue: unknown): issue is Issue;
|
|
248
258
|
}
|
|
249
259
|
export type IssueBodyFormat = 'markdown' | 'jira-wiki';
|
package/dist/git/models/issue.js
CHANGED
|
@@ -46,8 +46,9 @@ let Issue = _Issue = class Issue {
|
|
|
46
46
|
projection;
|
|
47
47
|
bodyField;
|
|
48
48
|
viewer;
|
|
49
|
+
viewerUnresolved;
|
|
49
50
|
type = "issue";
|
|
50
|
-
constructor(provider, id, nodeId, title, url, createdDate, updatedDate, closed, state, author, assignees, repository, closedDate, labels, commentsCount, thumbsUpCount, body, project, number, issueType, providerState, bodyFormat, iterations, projection, bodyField, viewer) {
|
|
51
|
+
constructor(provider, id, nodeId, title, url, createdDate, updatedDate, closed, state, author, assignees, repository, closedDate, labels, commentsCount, thumbsUpCount, body, project, number, issueType, providerState, bodyFormat, iterations, projection, bodyField, viewer, viewerUnresolved) {
|
|
51
52
|
this.provider = provider;
|
|
52
53
|
this.id = id;
|
|
53
54
|
this.nodeId = nodeId;
|
|
@@ -74,6 +75,7 @@ let Issue = _Issue = class Issue {
|
|
|
74
75
|
this.projection = projection;
|
|
75
76
|
this.bodyField = bodyField;
|
|
76
77
|
this.viewer = viewer;
|
|
78
|
+
this.viewerUnresolved = viewerUnresolved;
|
|
77
79
|
}
|
|
78
80
|
static is(issue) {
|
|
79
81
|
return issue instanceof _Issue;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue.js","names":[],"sources":["../../../../git/src/models/issue.ts"],"sourcesContent":["import { loggable } from '@gitlens/utils/decorators/log.js';\nimport type { RequireSome, RequireSomeWithProps } from '@gitlens/utils/types.js';\nimport type { IssueOrPullRequest, IssueOrPullRequestState } from './issueOrPullRequest.js';\nimport type { ProviderReference } from './remoteProvider.js';\nimport type { RepositoryIdentityDescriptor } from './repositoryIdentities.js';\n\n/** Selects which issue states a read should include. `all` covers open + closed. */\nexport type IssueStateFilter = 'open' | 'closed' | 'all';\n\n/**\n * One relationship a filtered issue search can constrain on.\n *\n * The last two are USER-INDEPENDENT — they describe the issue, not the caller — and neither is a SCOPE: either\n * one alone matches every such issue on the host, so a search using one still needs a repository/org scope.\n */\nexport type IssueSearchRelationship =\n\t/** Authored by the current user. */\n\t| 'authored'\n\t/** Assigned to the current user. */\n\t| 'assigned'\n\t/** Mentions the current user. */\n\t| 'mentioned'\n\t/** Assigned to ANYONE. Excludes unassigned issues — see {@link IssueSearchCriteria.relationships}. */\n\t| 'any-assignee'\n\t/** Assigned to nobody. The complement of `any-assignee`, not a broadening of it. */\n\t| 'unassigned';\n\n/**\n * A field an issue read can be ordered by, provider-neutral. No provider expresses all of them: each read\n * validates the requested key against the capability its provider declares and refuses one it can't express\n * server-side, rather than serving a differently-ordered list under the name of the one that was asked for.\n *\n * `closed` and `resolved` are deliberately SEPARATE, not two names for the same date. Azure DevOps tracks both\n * and they differ (an issue can be closed without being resolved and resolved without being closed), and Jira\n * has no close date at all — it models the equivalent as `resolutiondate`. Collapsing them would force one of\n * those two providers to lie about which date it ordered by.\n */\nexport type IssueSortField =\n\t/** Creation date. */\n\t| 'created'\n\t/** Last activity. */\n\t| 'updated'\n\t/** Close date. Only where the provider orders by it server-side — notably NOT GitHub. */\n\t| 'closed'\n\t/** Resolution date (Jira `resolutiondate`, Azure `ResolvedDate`). Distinct from `closed`. */\n\t| 'resolved'\n\t/** Number of comments. */\n\t| 'comments'\n\t/** Reactions/upvotes. */\n\t| 'reactions'\n\t/** The provider's own priority field. */\n\t| 'priority'\n\t/** Due date. */\n\t| 'dueDate'\n\t/** Alphabetical by title. */\n\t| 'title';\n\n/**\n * How an issue read is ordered, as `field:direction` — the same shape `BranchSorting`/`TagSorting` already use,\n * so it is one serializable string a consumer can persist, compare, or bind straight to a setting or a dropdown.\n */\nexport type IssueSorting = `${IssueSortField}:asc` | `${IssueSortField}:desc`;\n\n/**\n * The order every issue read that HAS a default applies when the caller asks for none: most recently updated\n * first, which is what those reads served before ordering was an option.\n *\n * One definition rather than one per layer, because it is a promise made in several places at once — the criteria\n * model documents it, the GitHub query emits it, and the result-ceiling warning quotes it — and three copies would\n * be free to disagree about what \"the default\" is.\n *\n * Note it is not a default every read has, and the two layers differ. The API client's account-wide \"my issues\"\n * search (`GitHubApi.searchMyIssues`) never requested an order, so a direct caller omitting `sort` still gets\n * GitHub's relevance order — the default is opt-in there, to keep that read's already-shipped results unchanged.\n * The FACADE does apply it: GitHub declares `updated:desc` among its account-wide keys, so\n * `readAccountWideIssuesPage` resolves the omission to this default and forwards it, and that read's emitted query\n * gained a `sort:updated` qualifier it did not have before. A read whose surface cannot express even this key is\n * the only one the facade leaves in the provider's own order.\n */\nexport const defaultIssueSort: IssueSorting = 'updated:desc';\n\n/**\n * What a filtered issue search narrows on: a provider-neutral criteria set, translated to each provider's own\n * query language by its integration.\n *\n * Structured rather than a provider query string so a consumer can render filter chips and hide the ones a\n * provider can't express, and so the same criteria mean the same thing on a provider whose query language looks\n * nothing like GitHub's search syntax. Every field is validated against the provider's declared capability\n * BEFORE the read runs, all-or-nothing: a criterion the provider can't express server-side refuses the whole\n * read rather than serving a list that was never narrowed. Client-side narrowing is not an option — the dropped\n * items still counted toward the page and cursor the provider produced, so a post-filter would leave the items\n * describing a different result set than the paging that came with them.\n */\nexport interface IssueSearchCriteria {\n\t/**\n\t * Relationships to constrain on, OR-ed together (each becomes its own provider query, unioned and deduped).\n\t * Omitted means NO relationship constraint at all — every issue in scope, assigned or not — which requires a\n\t * repository/org scope.\n\t *\n\t * `any-assignee` and `unassigned` partition the scope between them and are mutually exclusive; passing both is\n\t * refused rather than silently dropping one. Note that \"all visible issues\" is the OMITTED case, NOT\n\t * `any-assignee`, which excludes unassigned issues.\n\t */\n\trelationships?: IssueSearchRelationship[];\n\t/**\n\t * Free text, matched by the provider's own relevance rules — NOT a substring match, and not a way to smuggle\n\t * qualifiers: a token that would read as one is dropped, as are quotes and control characters, so text can\n\t * never re-scope the search. The structured criteria are the qualifier channel.\n\t */\n\ttext?: string;\n\t/** Issue states to include. Omitted reads open issues only. */\n\tstate?: IssueStateFilter;\n\t/** Labels the issue must carry — AND-ed, matching GitHub's own `label:` semantics. */\n\tlabels?: string[];\n\tmilestone?: string;\n\t/** ISO date (`YYYY-MM-DD`). The most effective narrowing criterion by far on a large scope. */\n\tupdatedAfter?: string;\n\t/** ISO date (`YYYY-MM-DD`). */\n\tcreatedAfter?: string;\n\t/** Issues with no linked pull request. */\n\twithoutLinkedPullRequest?: boolean;\n\t/** Includes issues in archived repositories, which are excluded by default. */\n\tincludeArchived?: boolean;\n\t/**\n\t * How to order the results. Omitted means `updated:desc`, which is what this search has always served.\n\t *\n\t * Validated like every other criterion — all-or-nothing against {@link IssueSearchCapabilities.sorts}: a key\n\t * the provider can't express server-side refuses the WHOLE read rather than falling back to the default.\n\t * Serving another order is not a smaller error than serving a wider result: combined with the provider's\n\t * result ceiling it returns a different subset than was asked for, and the paging that comes with it describes\n\t * that other subset.\n\t *\n\t * Do not change it mid-pagination. A cursor carries the sort it was produced under, and threading it under a\n\t * different key is refused rather than serving a sequence with gaps and repeats: drop the cursor instead.\n\t */\n\tsort?: IssueSorting;\n}\n\n/**\n * Which {@link IssueSearchCriteria} fields a provider's filtered issue search can express server-side.\n *\n * An empty `relationships` with every flag false means the provider has NO filtered issue search — the read is\n * refused outright, so a consumer should offer neither the surface nor its chips.\n */\nexport interface IssueSearchCapabilities {\n\t/** Relationships the search can constrain on. Empty means the search itself is unsupported. */\n\trelationships: IssueSearchRelationship[];\n\ttext: boolean;\n\tlabels: boolean;\n\tmilestone: boolean;\n\tupdatedAfter: boolean;\n\tcreatedAfter: boolean;\n\twithoutLinkedPullRequest: boolean;\n\t/** Whether {@link IssueSearchCriteria.state} can select anything other than the provider's default (open). */\n\tstates: boolean;\n\t/**\n\t * Sort keys the search can express IN SERVER. Always contains at least `updated:desc` — the historical default\n\t * — when the search exists at all, so it is never empty for a usable surface; a provider without a filtered\n\t * search reports an empty `relationships`, which is already the signal that there is no surface to order.\n\t */\n\tsorts: IssueSorting[];\n}\n\n/**\n * The read that produced an issue row, as a key for `getIssueFieldPresence` (`@gitlens/integrations`). It names a\n * READ, not a field set: the same tag can carry different fields on different providers.\n */\nexport type IssueProjection =\n\t/** A single-item read. */\n\t| 'point'\n\t/** The filtered search. */\n\t| 'search'\n\t/** The account-wide list, and the trackers' \"my issues\". */\n\t| 'account'\n\t/** A repository-scoped list. */\n\t| 'repos'\n\t/** A tracker project's issues (`listIssueTrackerIssuesPage`, `getIssuesForProject`). */\n\t| 'project'\n\t/** The batch read. */\n\t| 'batch';\n\nexport interface IssueShape extends IssueOrPullRequest {\n\t/** `undefined` when the provider can't resolve the author, e.g. a deleted GitHub account */\n\tauthor: IssueMember | undefined;\n\tassignees: IssueMember[];\n\t/** The provider's own workflow state, when it exposes one beyond the normalized open/closed state. */\n\tproviderState?: IssueProviderState;\n\trepository?: IssueRepository;\n\tlabels?: IssueLabel[];\n\tbody?: string;\n\t/**\n\t * The syntax used by `body`. When omitted, consumers should treat `body` as Markdown — except that Azure DevOps\n\t * work items and Bitbucket Cloud issues carry HTML with no `bodyFormat` set.\n\t */\n\tbodyFormat?: IssueBodyFormat;\n\t/**\n\t * The provider field `body` was read from, for providers whose issues keep it in different fields: an Azure\n\t * DevOps work item's type decides it (Description, Repro Steps on a Bug, a custom field on an inherited process).\n\t * Absent when the provider has a single body field, or there is no body.\n\t */\n\tbodyField?: IssueBodyField;\n\tproject?: IssueProject;\n\tissueType?: string;\n\t/** An issue can belong to several Jira sprints; Azure reports one iteration. */\n\titerations?: IssueIteration[];\n\t/** The read that produced this row. Absent means unknown: a legacy row, or a provider or read not yet tagged. */\n\treadonly projection?: IssueProjection;\n\t/**\n\t * The current account as this issue's members identify it, present only where that can differ from the account\n\t * `getCurrentAccount` returns: Azure DevOps can know one person by another id in each organization (Azure DevOps\n\t * Server: collection) than the account's, and a work item's {@link author} and {@link assignees} carry the\n\t * organization's. A consumer matching them to the current user compares against this when present, and against\n\t * the account otherwise. Absent on every other provider, and on an Azure DevOps row whose organization's identity\n\t * couldn't be read.\n\t */\n\treadonly viewer?: { readonly id: string; readonly username?: string };\n}\n\n@loggable(i => i.id)\nexport class Issue implements IssueShape {\n\treadonly type = 'issue';\n\n\tconstructor(\n\t\tpublic readonly provider: ProviderReference,\n\t\tpublic readonly id: string,\n\t\tpublic readonly nodeId: string | undefined,\n\t\tpublic readonly title: string,\n\t\tpublic readonly url: string,\n\t\tpublic readonly createdDate: Date,\n\t\tpublic readonly updatedDate: Date,\n\t\tpublic readonly closed: boolean,\n\t\tpublic readonly state: IssueOrPullRequestState | undefined,\n\t\tpublic readonly author: IssueMember | undefined,\n\t\tpublic readonly assignees: IssueMember[],\n\t\tpublic readonly repository?: IssueRepository,\n\t\tpublic readonly closedDate?: Date,\n\t\tpublic readonly labels?: IssueLabel[],\n\t\tpublic readonly commentsCount?: number,\n\t\tpublic readonly thumbsUpCount?: number,\n\t\tpublic readonly body?: string,\n\t\tpublic readonly project?: IssueProject,\n\t\tpublic readonly number?: string,\n\t\tpublic readonly issueType?: string,\n\t\tpublic readonly providerState?: IssueProviderState,\n\t\tpublic readonly bodyFormat?: IssueBodyFormat,\n\t\tpublic readonly iterations?: IssueIteration[],\n\t\tpublic readonly projection?: IssueProjection,\n\t\tpublic readonly bodyField?: IssueBodyField,\n\t\tpublic readonly viewer?: { readonly id: string; readonly username?: string },\n\t) {}\n\n\tstatic is(issue: unknown): issue is Issue {\n\t\treturn issue instanceof Issue;\n\t}\n}\n\nexport type IssueBodyFormat = 'markdown' | 'jira-wiki';\n\nexport interface IssueBodyField {\n\t/** The provider's id for the field, e.g. `Microsoft.VSTS.TCM.ReproSteps`. */\n\treadonly id: string;\n\t/** The field's display name, e.g. `Repro Steps`. */\n\treadonly name: string;\n}\n\nexport const enum RepositoryAccessLevel {\n\tAdmin = 100,\n\tMaintain = 40,\n\tWrite = 30,\n\tTriage = 20,\n\tRead = 10,\n\tNone = 0,\n}\n\nexport interface IssueLabel {\n\tcolor?: string;\n\tname: string;\n}\n\n/**\n * Sprint metadata is optional because some providers only report an iteration path. An absent `isActive`\n * means unknown, not inactive, so consumers must not use it to exclude those iterations by default.\n */\nexport interface IssueIteration {\n\t/**\n\t * A sprint id on Jira, the verbatim iteration path on Azure — so it is only meaningful within the provider's\n\t * project, never across providers. Unique at read time but NOT durable: Azure rewrites the path when an\n\t * iteration node is renamed or re-parented, so don't persist it as a long-lived id.\n\t */\n\tid: string;\n\tname: string;\n\tisActive?: boolean;\n\tstartDate?: Date;\n\tendDate?: Date;\n}\n\nexport interface IssueMember {\n\tid: string;\n\t/**\n\t * Absent when the provider exposes no display name for the member. Optional on purpose: a fallback string\n\t * invented here (`'unknown'`, `''`) can't be told apart from a real name downstream, so it can't be undone by a\n\t * consumer that needs to render something else — or nothing at all, as when the member feeds an AI prompt.\n\t * Each consumer picks its own presentation.\n\t */\n\tname?: string;\n\t/** The provider's handle for this person, when it has one — GitHub's login, Azure's `uniqueName` (a UPN,\n\t * so an email), Bitbucket's mutable `nickname`. Display/labelling only: it is neither guaranteed present\n\t * (GitLab's native mapper has none) nor a stable identity, so never key a match off it. */\n\tusername?: string;\n\tavatarUrl?: string;\n\turl?: string;\n}\n\nexport type IssueProviderState = {\n\tid?: string;\n\tname: string;\n\tcolor?: string;\n\t/** The provider's workflow category. `CANCELED` is abandoned work (Linear's canceled and duplicate states, Azure's\n\t * `Removed` category): closed like `DONE`, kept apart so a consumer can tell the two outcomes apart. */\n\tcategory?: 'TO_DO' | 'IN_PROGRESS' | 'DONE' | 'CANCELED';\n};\n\nexport interface IssueProject {\n\tid: string;\n\tname: string;\n\tresourceId: string;\n\tresourceName: string;\n}\n\nexport interface IssueRepository {\n\towner: string;\n\trepo: string;\n\taccessLevel?: RepositoryAccessLevel;\n\turl?: string;\n\tid?: string;\n}\n\nexport type IssueRepositoryIdentityDescriptor = RequireSomeWithProps<\n\tRequireSome<RepositoryIdentityDescriptor<string>, 'provider'>,\n\t'provider',\n\t'id' | 'domain' | 'repoDomain' | 'repoName'\n> &\n\tRequireSomeWithProps<RequireSome<RepositoryIdentityDescriptor<string>, 'remote'>, 'remote', 'domain'>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA+EA,MAAa,mBAAiC;AA4IvC,IAAM,QAAA,SAAN,MAAM,MAA4B;CAIvB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CA5BjB,OAAgB;CAEhB,YACC,UACA,IACA,QACA,OACA,KACA,aACA,aACA,QACA,OACA,QACA,WACA,YACA,YACA,QACA,eACA,eACA,MACA,SACA,QACA,WACA,eACA,YACA,YACA,YACA,WACA,QACC;EA1Be,KAAA,WAAA;EACA,KAAA,KAAA;EACA,KAAA,SAAA;EACA,KAAA,QAAA;EACA,KAAA,MAAA;EACA,KAAA,cAAA;EACA,KAAA,cAAA;EACA,KAAA,SAAA;EACA,KAAA,QAAA;EACA,KAAA,SAAA;EACA,KAAA,YAAA;EACA,KAAA,aAAA;EACA,KAAA,aAAA;EACA,KAAA,SAAA;EACA,KAAA,gBAAA;EACA,KAAA,gBAAA;EACA,KAAA,OAAA;EACA,KAAA,UAAA;EACA,KAAA,SAAA;EACA,KAAA,YAAA;EACA,KAAA,gBAAA;EACA,KAAA,aAAA;EACA,KAAA,aAAA;EACA,KAAA,aAAA;EACA,KAAA,YAAA;EACA,KAAA,SAAA;CACd;CAEH,OAAO,GAAG,OAAgC;EACzC,OAAO,iBAAA;CACR;AACD;AApCC,QAAA,SAAA,WAAA,CAAA,UAAS,MAAK,EAAE,EAAE,CAAA,GAAA,KAAA;AA+CnB,IAAkB,wBAAX,yBAAA,uBAAA;CACN,sBAAA,sBAAA,WAAA,OAAA;CACA,sBAAA,sBAAA,cAAA,MAAA;CACA,sBAAA,sBAAA,WAAA,MAAA;CACA,sBAAA,sBAAA,YAAA,MAAA;CACA,sBAAA,sBAAA,UAAA,MAAA;CACA,sBAAA,sBAAA,UAAA,KAAA;;AACD,EAAA,CAAA,CAAA"}
|
|
1
|
+
{"version":3,"file":"issue.js","names":[],"sources":["../../../../git/src/models/issue.ts"],"sourcesContent":["import { loggable } from '@gitlens/utils/decorators/log.js';\nimport type { RequireSome, RequireSomeWithProps } from '@gitlens/utils/types.js';\nimport type { IssueOrPullRequest, IssueOrPullRequestState } from './issueOrPullRequest.js';\nimport type { ProviderReference } from './remoteProvider.js';\nimport type { RepositoryIdentityDescriptor } from './repositoryIdentities.js';\n\n/** Selects which issue states a read should include. `all` covers open + closed. */\nexport type IssueStateFilter = 'open' | 'closed' | 'all';\n\n/**\n * One relationship a filtered issue search can constrain on.\n *\n * The last two are USER-INDEPENDENT — they describe the issue, not the caller — and neither is a SCOPE: either\n * one alone matches every such issue on the host, so a search using one still needs a repository/org scope.\n */\nexport type IssueSearchRelationship =\n\t/** Authored by the current user. */\n\t| 'authored'\n\t/** Assigned to the current user. */\n\t| 'assigned'\n\t/** Mentions the current user. */\n\t| 'mentioned'\n\t/** Assigned to ANYONE. Excludes unassigned issues — see {@link IssueSearchCriteria.relationships}. */\n\t| 'any-assignee'\n\t/** Assigned to nobody. The complement of `any-assignee`, not a broadening of it. */\n\t| 'unassigned';\n\n/**\n * A field an issue read can be ordered by, provider-neutral. No provider expresses all of them: each read\n * validates the requested key against the capability its provider declares and refuses one it can't express\n * server-side, rather than serving a differently-ordered list under the name of the one that was asked for.\n *\n * `closed` and `resolved` are deliberately SEPARATE, not two names for the same date. Azure DevOps tracks both\n * and they differ (an issue can be closed without being resolved and resolved without being closed), and Jira\n * has no close date at all — it models the equivalent as `resolutiondate`. Collapsing them would force one of\n * those two providers to lie about which date it ordered by.\n */\nexport type IssueSortField =\n\t/** Creation date. */\n\t| 'created'\n\t/** Last activity. */\n\t| 'updated'\n\t/** Close date. Only where the provider orders by it server-side — notably NOT GitHub. */\n\t| 'closed'\n\t/** Resolution date (Jira `resolutiondate`, Azure `ResolvedDate`). Distinct from `closed`. */\n\t| 'resolved'\n\t/** Number of comments. */\n\t| 'comments'\n\t/** Reactions/upvotes. */\n\t| 'reactions'\n\t/** The provider's own priority field. */\n\t| 'priority'\n\t/** Due date. */\n\t| 'dueDate'\n\t/** Alphabetical by title. */\n\t| 'title';\n\n/**\n * How an issue read is ordered, as `field:direction` — the same shape `BranchSorting`/`TagSorting` already use,\n * so it is one serializable string a consumer can persist, compare, or bind straight to a setting or a dropdown.\n */\nexport type IssueSorting = `${IssueSortField}:asc` | `${IssueSortField}:desc`;\n\n/**\n * The order every issue read that HAS a default applies when the caller asks for none: most recently updated\n * first, which is what those reads served before ordering was an option.\n *\n * One definition rather than one per layer, because it is a promise made in several places at once — the criteria\n * model documents it, the GitHub query emits it, and the result-ceiling warning quotes it — and three copies would\n * be free to disagree about what \"the default\" is.\n *\n * Note it is not a default every read has, and the two layers differ. The API client's account-wide \"my issues\"\n * search (`GitHubApi.searchMyIssues`) never requested an order, so a direct caller omitting `sort` still gets\n * GitHub's relevance order — the default is opt-in there, to keep that read's already-shipped results unchanged.\n * The FACADE does apply it: GitHub declares `updated:desc` among its account-wide keys, so\n * `readAccountWideIssuesPage` resolves the omission to this default and forwards it, and that read's emitted query\n * gained a `sort:updated` qualifier it did not have before. A read whose surface cannot express even this key is\n * the only one the facade leaves in the provider's own order.\n */\nexport const defaultIssueSort: IssueSorting = 'updated:desc';\n\n/**\n * What a filtered issue search narrows on: a provider-neutral criteria set, translated to each provider's own\n * query language by its integration.\n *\n * Structured rather than a provider query string so a consumer can render filter chips and hide the ones a\n * provider can't express, and so the same criteria mean the same thing on a provider whose query language looks\n * nothing like GitHub's search syntax. Every field is validated against the provider's declared capability\n * BEFORE the read runs, all-or-nothing: a criterion the provider can't express server-side refuses the whole\n * read rather than serving a list that was never narrowed. Client-side narrowing is not an option — the dropped\n * items still counted toward the page and cursor the provider produced, so a post-filter would leave the items\n * describing a different result set than the paging that came with them.\n */\nexport interface IssueSearchCriteria {\n\t/**\n\t * Relationships to constrain on, OR-ed together (each becomes its own provider query, unioned and deduped).\n\t * Omitted means NO relationship constraint at all — every issue in scope, assigned or not — which requires a\n\t * repository/org scope.\n\t *\n\t * `any-assignee` and `unassigned` partition the scope between them and are mutually exclusive; passing both is\n\t * refused rather than silently dropping one. Note that \"all visible issues\" is the OMITTED case, NOT\n\t * `any-assignee`, which excludes unassigned issues.\n\t */\n\trelationships?: IssueSearchRelationship[];\n\t/**\n\t * Free text, matched by the provider's own relevance rules — NOT a substring match, and not a way to smuggle\n\t * qualifiers: a token that would read as one is dropped, as are quotes and control characters, so text can\n\t * never re-scope the search. The structured criteria are the qualifier channel.\n\t */\n\ttext?: string;\n\t/** Issue states to include. Omitted reads open issues only. */\n\tstate?: IssueStateFilter;\n\t/** Labels the issue must carry — AND-ed, matching GitHub's own `label:` semantics. */\n\tlabels?: string[];\n\tmilestone?: string;\n\t/** ISO date (`YYYY-MM-DD`). The most effective narrowing criterion by far on a large scope. */\n\tupdatedAfter?: string;\n\t/** ISO date (`YYYY-MM-DD`). */\n\tcreatedAfter?: string;\n\t/** Issues with no linked pull request. */\n\twithoutLinkedPullRequest?: boolean;\n\t/** Includes issues in archived repositories, which are excluded by default. */\n\tincludeArchived?: boolean;\n\t/**\n\t * How to order the results. Omitted means `updated:desc`, which is what this search has always served.\n\t *\n\t * Validated like every other criterion — all-or-nothing against {@link IssueSearchCapabilities.sorts}: a key\n\t * the provider can't express server-side refuses the WHOLE read rather than falling back to the default.\n\t * Serving another order is not a smaller error than serving a wider result: combined with the provider's\n\t * result ceiling it returns a different subset than was asked for, and the paging that comes with it describes\n\t * that other subset.\n\t *\n\t * Do not change it mid-pagination. A cursor carries the sort it was produced under, and threading it under a\n\t * different key is refused rather than serving a sequence with gaps and repeats: drop the cursor instead.\n\t */\n\tsort?: IssueSorting;\n}\n\n/**\n * Which {@link IssueSearchCriteria} fields a provider's filtered issue search can express server-side.\n *\n * An empty `relationships` with every flag false means the provider has NO filtered issue search — the read is\n * refused outright, so a consumer should offer neither the surface nor its chips.\n */\nexport interface IssueSearchCapabilities {\n\t/** Relationships the search can constrain on. Empty means the search itself is unsupported. */\n\trelationships: IssueSearchRelationship[];\n\ttext: boolean;\n\tlabels: boolean;\n\tmilestone: boolean;\n\tupdatedAfter: boolean;\n\tcreatedAfter: boolean;\n\twithoutLinkedPullRequest: boolean;\n\t/** Whether {@link IssueSearchCriteria.state} can select anything other than the provider's default (open). */\n\tstates: boolean;\n\t/**\n\t * Sort keys the search can express IN SERVER. Always contains at least `updated:desc` — the historical default\n\t * — when the search exists at all, so it is never empty for a usable surface; a provider without a filtered\n\t * search reports an empty `relationships`, which is already the signal that there is no surface to order.\n\t */\n\tsorts: IssueSorting[];\n}\n\n/**\n * The read that produced an issue row, as a key for `getIssueFieldPresence` (`@gitlens/integrations`). It names a\n * READ, not a field set: the same tag can carry different fields on different providers.\n */\nexport type IssueProjection =\n\t/** A single-item read. */\n\t| 'point'\n\t/** The filtered search. */\n\t| 'search'\n\t/** The account-wide list, and the trackers' \"my issues\". */\n\t| 'account'\n\t/** A repository-scoped list. */\n\t| 'repos'\n\t/** A tracker project's issues (`listIssueTrackerIssuesPage`, `getIssuesForProject`). */\n\t| 'project'\n\t/** The batch read. */\n\t| 'batch';\n\nexport interface IssueShape extends IssueOrPullRequest {\n\t/** `undefined` when the provider can't resolve the author, e.g. a deleted GitHub account */\n\tauthor: IssueMember | undefined;\n\tassignees: IssueMember[];\n\t/** The provider's own workflow state, when it exposes one beyond the normalized open/closed state. */\n\tproviderState?: IssueProviderState;\n\trepository?: IssueRepository;\n\tlabels?: IssueLabel[];\n\tbody?: string;\n\t/**\n\t * The syntax used by `body`. When omitted, consumers should treat `body` as Markdown — except that Azure DevOps\n\t * work items and Bitbucket Cloud issues carry HTML with no `bodyFormat` set.\n\t */\n\tbodyFormat?: IssueBodyFormat;\n\t/**\n\t * The provider field `body` was read from, for providers whose issues keep it in different fields: an Azure\n\t * DevOps work item's type decides it (Description, Repro Steps on a Bug, a custom field on an inherited process).\n\t * Absent when the provider has a single body field, or there is no body.\n\t */\n\tbodyField?: IssueBodyField;\n\tproject?: IssueProject;\n\tissueType?: string;\n\t/** An issue can belong to several Jira sprints; Azure reports one iteration. */\n\titerations?: IssueIteration[];\n\t/** The read that produced this row. Absent means unknown: a legacy row, or a provider or read not yet tagged. */\n\treadonly projection?: IssueProjection;\n\t/**\n\t * The current account as this issue's members identify it, present only where that can differ from the account\n\t * `getCurrentAccount` returns: Azure DevOps can know one person by another id in each organization (Azure DevOps\n\t * Server: collection) than the account's, and a work item's {@link author} and {@link assignees} carry the\n\t * organization's. A consumer matching them to the current user compares against this when present, and against\n\t * the account otherwise, unless {@link viewerUnresolved} is set. Absent on every other provider, and on an Azure\n\t * DevOps row whose organization's identity couldn't be read.\n\t */\n\treadonly viewer?: { readonly id: string; readonly username?: string };\n\t/**\n\t * Set, and only ever `true`, on an Azure DevOps row that names someone ({@link author} or {@link assignees}) whose\n\t * organization's (Azure DevOps Server: collection's) identity the read tried and failed to resolve: its\n\t * `ConnectionData` failed, answered without an identity, or didn't answer within 10 seconds. Such a row has no\n\t * {@link viewer}, and neither the account `getCurrentAccount` returns nor anyone else can be matched against its\n\t * people: whether it is the current user's is unknown, not \"no\". Absent everywhere else, so a row with neither\n\t * field is still one whose provider has no per-row identity, matched against the account.\n\t */\n\treadonly viewerUnresolved?: true;\n}\n\n@loggable(i => i.id)\nexport class Issue implements IssueShape {\n\treadonly type = 'issue';\n\n\tconstructor(\n\t\tpublic readonly provider: ProviderReference,\n\t\tpublic readonly id: string,\n\t\tpublic readonly nodeId: string | undefined,\n\t\tpublic readonly title: string,\n\t\tpublic readonly url: string,\n\t\tpublic readonly createdDate: Date,\n\t\tpublic readonly updatedDate: Date,\n\t\tpublic readonly closed: boolean,\n\t\tpublic readonly state: IssueOrPullRequestState | undefined,\n\t\tpublic readonly author: IssueMember | undefined,\n\t\tpublic readonly assignees: IssueMember[],\n\t\tpublic readonly repository?: IssueRepository,\n\t\tpublic readonly closedDate?: Date,\n\t\tpublic readonly labels?: IssueLabel[],\n\t\tpublic readonly commentsCount?: number,\n\t\tpublic readonly thumbsUpCount?: number,\n\t\tpublic readonly body?: string,\n\t\tpublic readonly project?: IssueProject,\n\t\tpublic readonly number?: string,\n\t\tpublic readonly issueType?: string,\n\t\tpublic readonly providerState?: IssueProviderState,\n\t\tpublic readonly bodyFormat?: IssueBodyFormat,\n\t\tpublic readonly iterations?: IssueIteration[],\n\t\tpublic readonly projection?: IssueProjection,\n\t\tpublic readonly bodyField?: IssueBodyField,\n\t\tpublic readonly viewer?: { readonly id: string; readonly username?: string },\n\t\tpublic readonly viewerUnresolved?: true,\n\t) {}\n\n\tstatic is(issue: unknown): issue is Issue {\n\t\treturn issue instanceof Issue;\n\t}\n}\n\nexport type IssueBodyFormat = 'markdown' | 'jira-wiki';\n\nexport interface IssueBodyField {\n\t/** The provider's id for the field, e.g. `Microsoft.VSTS.TCM.ReproSteps`. */\n\treadonly id: string;\n\t/** The field's display name, e.g. `Repro Steps`. */\n\treadonly name: string;\n}\n\nexport const enum RepositoryAccessLevel {\n\tAdmin = 100,\n\tMaintain = 40,\n\tWrite = 30,\n\tTriage = 20,\n\tRead = 10,\n\tNone = 0,\n}\n\nexport interface IssueLabel {\n\tcolor?: string;\n\tname: string;\n}\n\n/**\n * Sprint metadata is optional because some providers only report an iteration path. An absent `isActive`\n * means unknown, not inactive, so consumers must not use it to exclude those iterations by default.\n */\nexport interface IssueIteration {\n\t/**\n\t * A sprint id on Jira, the verbatim iteration path on Azure — so it is only meaningful within the provider's\n\t * project, never across providers. Unique at read time but NOT durable: Azure rewrites the path when an\n\t * iteration node is renamed or re-parented, so don't persist it as a long-lived id.\n\t */\n\tid: string;\n\tname: string;\n\tisActive?: boolean;\n\tstartDate?: Date;\n\tendDate?: Date;\n}\n\nexport interface IssueMember {\n\tid: string;\n\t/**\n\t * Absent when the provider exposes no display name for the member. Optional on purpose: a fallback string\n\t * invented here (`'unknown'`, `''`) can't be told apart from a real name downstream, so it can't be undone by a\n\t * consumer that needs to render something else — or nothing at all, as when the member feeds an AI prompt.\n\t * Each consumer picks its own presentation.\n\t */\n\tname?: string;\n\t/** The provider's handle for this person, when it has one — GitHub's login, Azure's `uniqueName` (a UPN,\n\t * so an email), Bitbucket's mutable `nickname`. Display/labelling only: it is neither guaranteed present\n\t * (GitLab's native mapper has none) nor a stable identity, so never key a match off it. */\n\tusername?: string;\n\tavatarUrl?: string;\n\turl?: string;\n}\n\nexport type IssueProviderState = {\n\tid?: string;\n\tname: string;\n\tcolor?: string;\n\t/** The provider's workflow category. `CANCELED` is abandoned work (Linear's canceled and duplicate states, Azure's\n\t * `Removed` category): closed like `DONE`, kept apart so a consumer can tell the two outcomes apart. */\n\tcategory?: 'TO_DO' | 'IN_PROGRESS' | 'DONE' | 'CANCELED';\n};\n\nexport interface IssueProject {\n\tid: string;\n\tname: string;\n\tresourceId: string;\n\tresourceName: string;\n}\n\nexport interface IssueRepository {\n\towner: string;\n\trepo: string;\n\taccessLevel?: RepositoryAccessLevel;\n\turl?: string;\n\tid?: string;\n}\n\nexport type IssueRepositoryIdentityDescriptor = RequireSomeWithProps<\n\tRequireSome<RepositoryIdentityDescriptor<string>, 'provider'>,\n\t'provider',\n\t'id' | 'domain' | 'repoDomain' | 'repoName'\n> &\n\tRequireSomeWithProps<RequireSome<RepositoryIdentityDescriptor<string>, 'remote'>, 'remote', 'domain'>;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA+EA,MAAa,mBAAiC;AAqJvC,IAAM,QAAA,SAAN,MAAM,MAA4B;CAIvB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CA7BjB,OAAgB;CAEhB,YACC,UACA,IACA,QACA,OACA,KACA,aACA,aACA,QACA,OACA,QACA,WACA,YACA,YACA,QACA,eACA,eACA,MACA,SACA,QACA,WACA,eACA,YACA,YACA,YACA,WACA,QACA,kBACC;EA3Be,KAAA,WAAA;EACA,KAAA,KAAA;EACA,KAAA,SAAA;EACA,KAAA,QAAA;EACA,KAAA,MAAA;EACA,KAAA,cAAA;EACA,KAAA,cAAA;EACA,KAAA,SAAA;EACA,KAAA,QAAA;EACA,KAAA,SAAA;EACA,KAAA,YAAA;EACA,KAAA,aAAA;EACA,KAAA,aAAA;EACA,KAAA,SAAA;EACA,KAAA,gBAAA;EACA,KAAA,gBAAA;EACA,KAAA,OAAA;EACA,KAAA,UAAA;EACA,KAAA,SAAA;EACA,KAAA,YAAA;EACA,KAAA,gBAAA;EACA,KAAA,aAAA;EACA,KAAA,aAAA;EACA,KAAA,aAAA;EACA,KAAA,YAAA;EACA,KAAA,SAAA;EACA,KAAA,mBAAA;CACd;CAEH,OAAO,GAAG,OAAgC;EACzC,OAAO,iBAAA;CACR;AACD;AArCC,QAAA,SAAA,WAAA,CAAA,UAAS,MAAK,EAAE,EAAE,CAAA,GAAA,KAAA;AAgDnB,IAAkB,wBAAX,yBAAA,uBAAA;CACN,sBAAA,sBAAA,WAAA,OAAA;CACA,sBAAA,sBAAA,cAAA,MAAA;CACA,sBAAA,sBAAA,WAAA,MAAA;CACA,sBAAA,sBAAA,YAAA,MAAA;CACA,sBAAA,sBAAA,UAAA,MAAA;CACA,sBAAA,sBAAA,UAAA,KAAA;;AACD,EAAA,CAAA,CAAA"}
|
|
@@ -61,7 +61,7 @@ export interface PullRequestShape extends IssueOrPullRequest {
|
|
|
61
61
|
readonly authoredByMe?: boolean;
|
|
62
62
|
/**
|
|
63
63
|
* The current account as this pull request's members identify it: the identity its people were matched against,
|
|
64
|
-
* present whenever it was resolved. {@link authoredByMe} is matched against it too, and stays `undefined` when the
|
|
64
|
+
* present whenever it was resolved (see {@link viewerUnresolved} for an Azure DevOps row it couldn't be for). {@link authoredByMe} is matched against it too, and stays `undefined` when the
|
|
65
65
|
* row has no author, though its reviewers or assignees still get this. A consumer matching {@link reviewRequests}
|
|
66
66
|
* or {@link latestReviews} entries to the current user compares against this, not the account `getCurrentAccount`
|
|
67
67
|
* returns: Azure DevOps can know one person by another id in each organization (Azure DevOps Server: collection)
|
|
@@ -72,6 +72,16 @@ export interface PullRequestShape extends IssueOrPullRequest {
|
|
|
72
72
|
readonly id: string;
|
|
73
73
|
readonly username?: string;
|
|
74
74
|
};
|
|
75
|
+
/**
|
|
76
|
+
* Set, and only ever `true`, on an Azure DevOps row that names someone (its author, a reviewer or an assignee)
|
|
77
|
+
* whose organization's (Azure DevOps Server: collection's) identity the read tried and failed to resolve: its
|
|
78
|
+
* `ConnectionData` failed, answered without an identity, or didn't answer within 10 seconds. Such a row has neither
|
|
79
|
+
* {@link viewer} nor {@link authoredByMe}, and neither the account `getCurrentAccount` returns nor anyone else can
|
|
80
|
+
* be matched against its people: whether it is the current user's, or asks for their review, is unknown, not "no".
|
|
81
|
+
* Absent everywhere else, so a row with neither field is still one whose identity wasn't resolved for another
|
|
82
|
+
* reason (a read that doesn't resolve it, or a failed account read), as before.
|
|
83
|
+
*/
|
|
84
|
+
readonly viewerUnresolved?: true;
|
|
75
85
|
/** The read that produced this row. Absent means unknown: a legacy row, or a provider or read not yet tagged. */
|
|
76
86
|
readonly projection?: PullRequestProjection;
|
|
77
87
|
}
|
|
@@ -117,6 +127,7 @@ export declare class PullRequest implements PullRequestShape {
|
|
|
117
127
|
readonly id: string;
|
|
118
128
|
readonly username?: string;
|
|
119
129
|
} | undefined;
|
|
130
|
+
readonly viewerUnresolved?: true | undefined;
|
|
120
131
|
readonly type = "pullrequest";
|
|
121
132
|
constructor(provider: ProviderReference, author: PullRequestMember, id: string, nodeId: string | undefined, title: string, url: string, repository: IssueRepository, state: IssueOrPullRequestState, createdDate: Date, updatedDate: Date, closedDate?: Date | undefined, mergedDate?: Date | undefined, mergeableState?: PullRequestMergeableState | undefined, viewerCanUpdate?: boolean | undefined, refs?: PullRequestRefs | undefined, isDraft?: boolean | undefined, additions?: number | undefined, deletions?: number | undefined, commentsCount?: number | undefined, thumbsUpCount?: number | undefined, reviewDecision?: PullRequestReviewDecision | undefined, reviewRequests?: PullRequestReviewer[] | undefined, latestReviews?: PullRequestReviewer[] | undefined, assignees?: PullRequestMember[] | undefined, statusCheckRollupState?: PullRequestStatusCheckRollupState | undefined, project?: IssueProject | undefined, version?: number | undefined,
|
|
122
133
|
/** Commits on the head that aren't on the base. Appended rather than slotted with the other counts:
|
|
@@ -126,7 +137,7 @@ export declare class PullRequest implements PullRequestShape {
|
|
|
126
137
|
body?: string | undefined, number?: number | undefined, authoredByMe?: boolean | undefined, projection?: PullRequestProjection | undefined, viewer?: {
|
|
127
138
|
readonly id: string;
|
|
128
139
|
readonly username?: string;
|
|
129
|
-
} | undefined);
|
|
140
|
+
} | undefined, viewerUnresolved?: true | undefined);
|
|
130
141
|
get closed(): boolean;
|
|
131
142
|
static is(pr: unknown): pr is PullRequest;
|
|
132
143
|
static formatDate(pr: PullRequestShape, format?: string | null): string;
|
|
@@ -40,8 +40,9 @@ let PullRequest = _PullRequest = class PullRequest {
|
|
|
40
40
|
authoredByMe;
|
|
41
41
|
projection;
|
|
42
42
|
viewer;
|
|
43
|
+
viewerUnresolved;
|
|
43
44
|
type = "pullrequest";
|
|
44
|
-
constructor(provider, author, id, nodeId, title, url, repository, state, createdDate, updatedDate, closedDate, mergedDate, mergeableState, viewerCanUpdate, refs, isDraft, additions, deletions, commentsCount, thumbsUpCount, reviewDecision, reviewRequests, latestReviews, assignees, statusCheckRollupState, project, version, commitCount, stack, filesChanged, body, number, authoredByMe, projection, viewer) {
|
|
45
|
+
constructor(provider, author, id, nodeId, title, url, repository, state, createdDate, updatedDate, closedDate, mergedDate, mergeableState, viewerCanUpdate, refs, isDraft, additions, deletions, commentsCount, thumbsUpCount, reviewDecision, reviewRequests, latestReviews, assignees, statusCheckRollupState, project, version, commitCount, stack, filesChanged, body, number, authoredByMe, projection, viewer, viewerUnresolved) {
|
|
45
46
|
this.provider = provider;
|
|
46
47
|
this.author = author;
|
|
47
48
|
this.id = id;
|
|
@@ -77,6 +78,7 @@ let PullRequest = _PullRequest = class PullRequest {
|
|
|
77
78
|
this.authoredByMe = authoredByMe;
|
|
78
79
|
this.projection = projection;
|
|
79
80
|
this.viewer = viewer;
|
|
81
|
+
this.viewerUnresolved = viewerUnresolved;
|
|
80
82
|
}
|
|
81
83
|
get closed() {
|
|
82
84
|
return this.state === "closed";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pullRequest.js","names":[],"sources":["../../../../git/src/models/pullRequest.ts"],"sourcesContent":["import { formatDate, fromNow } from '@gitlens/utils/date.js';\nimport { loggable } from '@gitlens/utils/decorators/log.js';\nimport { serializable } from '@gitlens/utils/decorators/serializable.js';\nimport type { RequireSome, RequireSomeWithProps } from '@gitlens/utils/types.js';\nimport type { IssueProject, IssueRepository } from './issue.js';\nimport type { IssueOrPullRequest, IssueOrPullRequestState as PullRequestState } from './issueOrPullRequest.js';\nimport type { ProviderReference } from './remoteProvider.js';\nimport type { RepositoryIdentityDescriptor } from './repositoryIdentities.js';\n\nexport type { PullRequestState };\n\n/**\n * The read that produced a pull request row, as a key for `getPullRequestFieldPresence` (`@gitlens/integrations`). It\n * names a READ, not a field set: the same tag can carry different fields on different providers.\n */\nexport type PullRequestProjection =\n\t/** A single-item read: by number, for a branch, or for a commit. */\n\t| 'point'\n\t/** The filtered search with the full projection, and the host's \"my pull requests\" search. */\n\t| 'search'\n\t/** The filtered search with `summary`. */\n\t| 'search-summary'\n\t/** The free-text search (`searchPullRequests`). */\n\t| 'text-search'\n\t/** An account-wide sweep with the full projection (`includeReviews`). */\n\t| 'account'\n\t/** An account-wide list or sweep with the lightweight projection. */\n\t| 'account-summary'\n\t/** A repository-scoped list or sweep. */\n\t| 'repos'\n\t/** A repository-scoped list with `summary`. */\n\t| 'repos-summary'\n\t/** The coordinate and branch batch reads. */\n\t| 'batch';\n\nexport interface PullRequestShape extends IssueOrPullRequest {\n\treadonly state: PullRequestState;\n\treadonly author: PullRequestMember;\n\t/**\n\t * Canonical base-repository identity returned by the provider. Some providers\n\t * scope pull-request ids to a repository, so consumers must not have to infer\n\t * identity from optional refs or URLs.\n\t */\n\treadonly repository?: IssueRepository;\n\treadonly mergedDate?: Date;\n\treadonly refs?: PullRequestRefs;\n\treadonly isDraft?: boolean;\n\treadonly additions?: number;\n\treadonly deletions?: number;\n\treadonly filesChanged?: number;\n\treadonly body?: string;\n\treadonly mergeableState?: PullRequestMergeableState;\n\treadonly reviewDecision?: PullRequestReviewDecision;\n\treadonly reviewRequests?: PullRequestReviewer[];\n\t/**\n\t * Reviews already submitted, as opposed to the still-pending {@link reviewRequests}. Absent means the read\n\t * didn't fetch reviews; empty means nobody has reviewed — but only where the read actually fetched them, which\n\t * is provider- and read-dependent: ask `getPullRequestFieldPresence` (`@gitlens/integrations`) for the row's\n\t * `reviews` group rather than trusting an empty array.\n\t * {@link PullRequestReviewer.commitOid} is the narrower promise: only the full GitHub/GHE projection has it.\n\t */\n\treadonly latestReviews?: PullRequestReviewer[];\n\treadonly assignees?: PullRequestMember[];\n\treadonly project?: IssueProject;\n\treadonly stack?: PullRequestStackInfo;\n\treadonly number?: number;\n\treadonly authoredByMe?: boolean;\n\t/**\n\t * The current account as this pull request's members identify it: the identity its people were matched against,\n\t * present whenever it was resolved. {@link authoredByMe} is matched against it too, and stays `undefined` when the\n\t * row has no author, though its reviewers or assignees still get this. A consumer matching {@link reviewRequests}\n\t * or {@link latestReviews} entries to the current user compares against this, not the account `getCurrentAccount`\n\t * returns: Azure DevOps can know one person by another id in each organization (Azure DevOps Server: collection)\n\t * than the account's, and the members carry the organization's. Core matches `username` too only on GitHub and\n\t * GitHub Enterprise, whose rows key people by login.\n\t */\n\treadonly viewer?: { readonly id: string; readonly username?: string };\n\t/** The read that produced this row. Absent means unknown: a legacy row, or a provider or read not yet tagged. */\n\treadonly projection?: PullRequestProjection;\n}\n\n@loggable(i => i.id)\n@serializable\nexport class PullRequest implements PullRequestShape {\n\treadonly type = 'pullrequest';\n\n\tconstructor(\n\t\tpublic readonly provider: ProviderReference,\n\t\tpublic readonly author: PullRequestMember,\n\t\tpublic readonly id: string,\n\t\tpublic readonly nodeId: string | undefined,\n\t\tpublic readonly title: string,\n\t\tpublic readonly url: string,\n\t\tpublic readonly repository: IssueRepository,\n\t\tpublic readonly state: PullRequestState,\n\t\tpublic readonly createdDate: Date,\n\t\tpublic readonly updatedDate: Date,\n\t\tpublic readonly closedDate?: Date,\n\t\tpublic readonly mergedDate?: Date,\n\t\tpublic readonly mergeableState?: PullRequestMergeableState,\n\t\tpublic readonly viewerCanUpdate?: boolean,\n\t\tpublic readonly refs?: PullRequestRefs,\n\t\tpublic readonly isDraft?: boolean,\n\t\tpublic readonly additions?: number,\n\t\tpublic readonly deletions?: number,\n\t\tpublic readonly commentsCount?: number,\n\t\tpublic readonly thumbsUpCount?: number,\n\t\tpublic readonly reviewDecision?: PullRequestReviewDecision,\n\t\tpublic readonly reviewRequests?: PullRequestReviewer[],\n\t\tpublic readonly latestReviews?: PullRequestReviewer[],\n\t\tpublic readonly assignees?: PullRequestMember[],\n\t\tpublic readonly statusCheckRollupState?: PullRequestStatusCheckRollupState,\n\t\tpublic readonly project?: IssueProject,\n\t\tpublic readonly version?: number,\n\t\t/** Commits on the head that aren't on the base. Appended rather than slotted with the other counts:\n\t\t * this constructor is positional and every mapper passes through it. */\n\t\tpublic readonly commitCount?: number,\n\t\tpublic readonly stack?: PullRequestStackInfo,\n\t\tpublic readonly filesChanged?: number,\n\t\t/** The pull request's description, as markdown. */\n\t\tpublic readonly body?: string,\n\t\tpublic readonly number?: number,\n\t\tpublic readonly authoredByMe?: boolean,\n\t\tpublic readonly projection?: PullRequestProjection,\n\t\tpublic readonly viewer?: { readonly id: string; readonly username?: string },\n\t) {}\n\n\tget closed(): boolean {\n\t\treturn this.state === 'closed';\n\t}\n\n\tstatic is(pr: unknown): pr is PullRequest {\n\t\treturn pr instanceof PullRequest;\n\t}\n\n\tstatic formatDate(pr: PullRequestShape, format?: string | null): string {\n\t\treturn formatDate(pr.mergedDate ?? pr.closedDate ?? pr.updatedDate, format ?? 'MMMM Do, YYYY h:mma');\n\t}\n\n\tstatic formatDateFromNow(pr: PullRequestShape): string {\n\t\treturn fromNow(pr.mergedDate ?? pr.closedDate ?? pr.updatedDate);\n\t}\n\n\tstatic formatDateWithStyle(\n\t\tpr: PullRequestShape,\n\t\tformatting: { dateStyle: string; dateFormat: string | null },\n\t): string {\n\t\treturn formatting.dateStyle === 'absolute'\n\t\t\t? PullRequest.formatDate(pr, formatting.dateFormat)\n\t\t\t: PullRequest.formatDateFromNow(pr);\n\t}\n}\n\nexport const enum PullRequestReviewDecision {\n\tApproved = 'Approved',\n\tChangesRequested = 'ChangesRequested',\n\tReviewRequired = 'ReviewRequired',\n}\n\nexport const enum PullRequestMergeableState {\n\tUnknown = 'Unknown',\n\tMergeable = 'Mergeable',\n\tConflicting = 'Conflicting',\n\tFailingChecks = 'FailingChecks',\n\tBlockedByPolicy = 'BlockedByPolicy',\n}\n\nexport const enum PullRequestStatusCheckRollupState {\n\tSuccess = 'success',\n\tPending = 'pending',\n\tFailed = 'failed',\n}\n\nexport const enum PullRequestMergeMethod {\n\tMerge = 'merge',\n\tSquash = 'squash',\n\tRebase = 'rebase',\n}\n\nexport const enum PullRequestReviewState {\n\tApproved = 'APPROVED',\n\tChangesRequested = 'CHANGES_REQUESTED',\n\tCommented = 'COMMENTED',\n\tDismissed = 'DISMISSED',\n\tPending = 'PENDING',\n\tReviewRequested = 'REVIEW_REQUESTED',\n}\n\nexport interface PullRequestComparisonRefs {\n\trepoPath: string;\n\tbase: { ref: string; label: string };\n\thead: { ref: string; label: string };\n}\n\nexport interface PullRequestMember {\n\tid: string;\n\t/**\n\t * Absent when the provider exposes no display name for the member — same contract as `IssueMember.name`: a\n\t * fallback invented here can't be told apart from a real name downstream, so each consumer picks its own\n\t * presentation.\n\t */\n\tname?: string;\n\t/** The provider's handle for this person, when it has one — GitHub's login, Azure's `uniqueName` (a UPN,\n\t * so an email), Bitbucket's mutable `nickname`. Display/labelling only: it is neither guaranteed present\n\t * (GitLab's native mapper has none) nor a stable identity, so never key a match off it. */\n\tusername?: string;\n\tavatarUrl?: string;\n\turl?: string;\n}\n\n/** Provider-neutral relationship facets shared by PR listings and filtered PR search. */\nexport enum PullRequestFilter {\n\tAuthor = 'author',\n\tAssignee = 'assignee',\n\tReviewRequested = 'review-requested',\n\t/**\n\t * PRs the user has already reviewed (GitHub `reviewed-by:@me`), as opposed to `ReviewRequested` (a\n\t * still-pending request). Distinguishes \"waiting on the author after my review\" from \"waiting for my\n\t * review\". Not expressible on the repo-scoped listing — no provider SDK exposes a reviewed-by axis there —\n\t * so it is advertised for the account-wide read and for the filtered search (which can still bound itself\n\t * to repositories or an org), never under `supportedPullRequestFilters`.\n\t */\n\tReviewed = 'reviewed-by',\n\tMention = 'mention',\n}\n\n/** Selects which pull request states a read should include. `all` covers open + closed + merged. */\nexport type PullRequestStateFilter = 'open' | 'closed' | 'merged' | 'all';\n\n/**\n * A field a pull-request read can be ordered by, provider-neutral.\n *\n * Only two, and deliberately so — unlike {@link IssueSortField} this is the INTERSECTION of what GitHub's PR\n * search can order by server-side and what a {@link PullRequestShape} carries, because the filtered PR search\n * always merges its relationship × state facets in the facade and so must re-order the union itself (see\n * `getPullRequestComparator`). `created` and `updated` are both. A field GitHub cannot order PRs by, or one a\n * merged page can't reproduce, is left out rather than advertised and then approximated: relevance is unstable\n * and has no comparable value on a merge, and priority is not a pull-request concept on any provider that has PRs.\n */\nexport type PullRequestSortField =\n\t/** Creation date. */\n\t| 'created'\n\t/** Last activity. */\n\t| 'updated';\n\n/**\n * How a pull-request read is ordered, as `field:direction` — the same serializable shape {@link IssueSorting}\n * and `BranchSorting` use, so a consumer can persist it, compare it, or bind it straight to a setting or dropdown.\n */\nexport type PullRequestSorting = `${PullRequestSortField}:asc` | `${PullRequestSortField}:desc`;\n\n/**\n * The order the filtered pull-request search applies when the caller asks for none: most recently updated first,\n * which is what it served before ordering was an option. Named once rather than per layer — the criteria model\n * documents it, the GitHub query emits it, and the result-ceiling warning quotes it — so the three cannot\n * disagree about what \"the default\" is.\n */\nexport const defaultPullRequestSort: PullRequestSorting = 'updated:desc';\n\n/**\n * What the filtered pull-request search narrows on.\n *\n * Structured rather than a provider query string so callers can send free text without giving it a qualifier\n * channel, and can check {@link PullRequestSearchCapabilities} before issuing a read. Every requested criterion\n * is validated all-or-nothing before the provider runs; unsupported criteria never fall through to a wider\n * result set whose paging would no longer describe the returned items.\n *\n * Relationships are OR-ed, as are states. Omitting `relationships` removes the current-user constraint, which is\n * only safe when the manager call supplies a repository or organization scope. Omitting `states` reads open PRs.\n */\nexport interface PullRequestSearchCriteria {\n\t/**\n\t * Free text matched by the provider's own relevance rules. Tokens that look like provider qualifiers are\n\t * removed before the query is built, so text cannot change the search's scope or state.\n\t */\n\ttext?: string;\n\t/** Current-user relationship facets to union. Empty/omitted means no relationship constraint. */\n\trelationships?: PullRequestFilter[];\n\t/** Pull request states to union. Empty/omitted reads open PRs; `all` subsumes every other member. */\n\tstates?: PullRequestStateFilter[];\n\t/** ISO date (`YYYY-MM-DD`). The most effective narrowing criterion by far on a large scope. */\n\tupdatedAfter?: string;\n\t/** ISO date (`YYYY-MM-DD`). */\n\tcreatedAfter?: string;\n\t/** Includes PRs from archived repositories. They are excluded by default. */\n\tincludeArchived?: boolean;\n\t/**\n\t * Narrows on draft state: `true` returns only drafts, `false` only ready-for-review PRs. Omitted places no\n\t * constraint. A boolean rather than a truthy flag because `false` is a distinct request, not the absence of one.\n\t */\n\tdraft?: boolean;\n\t/**\n\t * How to order the results. Omitted means `updated:desc`, which is what this search has always served.\n\t *\n\t * Validated all-or-nothing against {@link PullRequestSearchCapabilities.sorts} like every other criterion: a\n\t * key the provider can't express server-side refuses the WHOLE read rather than falling back to the default,\n\t * because combined with the provider's result ceiling another order returns a different subset than was asked\n\t * for and the paging that comes with it describes that other subset. Do not change it mid-pagination — a\n\t * cursor carries the sort it was produced under; drop the cursor instead of threading it under a new key.\n\t */\n\tsort?: PullRequestSorting;\n}\n\n/**\n * Which {@link PullRequestSearchCriteria} fields and manager-level scopes a provider can express server-side.\n * An empty `relationships` means the provider has no filtered PR search at all.\n */\nexport interface PullRequestSearchCapabilities {\n\t/** Current-user relationship facets the provider can union. Empty means the search itself is unsupported. */\n\trelationships: PullRequestFilter[];\n\t/** Individual state values the provider can union in one logical search. */\n\tstates: PullRequestStateFilter[];\n\ttext: boolean;\n\tupdatedAfter: boolean;\n\tcreatedAfter: boolean;\n\tincludeArchived: boolean;\n\t/** Whether the provider can constrain the search by draft state server-side. */\n\tdraft: boolean;\n\t/** Whether the manager's repository-descriptor scope is supported. */\n\trepositoryScope: boolean;\n\t/** Whether the manager's organization scope is supported. */\n\torganizationScope: boolean;\n\t/**\n\t * Sort keys the search can express server-side. Always contains at least `updated:desc` — the historical\n\t * default — when the search exists at all, so it is never empty for a usable surface; a provider without a\n\t * filtered PR search reports an empty `relationships`, which is already the signal there is no surface to order.\n\t */\n\tsorts: PullRequestSorting[];\n}\n\nexport interface PullRequestRef {\n\t/**\n\t * `undefined` when the ref's repository was deleted (a removed fork): GitHub's rows say so, with `exists` false.\n\t * provider-apis' converters fill `''` instead, so test for a value rather than for `undefined`.\n\t */\n\towner: string | undefined;\n\t/** `undefined` (or `''`) when the ref's repository was deleted, as {@link owner}. */\n\trepo: string | undefined;\n\tbranch: string;\n\tsha: string;\n\texists: boolean;\n\t/**\n\t * Web URL of the ref's repository. `undefined` when the provider cannot resolve it — Azure DevOps embeds an\n\t * abbreviated repository reference in a pull request, so a fork's URL may need a lookup that can fail.\n\t */\n\turl: string | undefined;\n\t/** HTTPS clone URL of the ref's repository, when the provider exposes it. */\n\tcloneHttps?: string;\n\t/** SSH clone URL of the ref's repository, when the provider exposes it. */\n\tcloneSsh?: string;\n\t/** Best-effort flag: whether the ref's repository is a fork. `undefined` when the provider can't tell. */\n\tisFork?: boolean;\n}\n\nexport interface PullRequestRefs {\n\tbase: PullRequestRef & { url: string };\n\thead: PullRequestRef;\n\tisCrossRepository: boolean;\n}\n\n/**\n * A pull request's membership in a stack — an ordered chain of dependent pull requests where each\n * targets the branch of the one below it.\n *\n * `baseRef` is the stack's ultimate target (its trunk) and is NOT the same as `refs.base`, which for\n * anything above the bottom layer names the layer below. Use `refs.base` to diff a single layer; use\n * `baseRef` to answer where the work ultimately lands.\n */\nexport interface PullRequestStackInfo {\n\t/**\n\t * Opaque, and NOT comparable across read paths: GitHub's GraphQL selection returns a node id\n\t * (`PRS_kwDO…`) while its REST stacks endpoint returns a numeric id (`1347135`) that we stringify —\n\t * both verified against the same live stack. Use {@link number} to identify a stack; two views of one\n\t * stack agree there and will not agree here.\n\t */\n\tid: string;\n\t/** Identifies the stack within its repository. */\n\tnumber: number;\n\t/** Total pull requests in the stack. */\n\tsize: number;\n\t/** This pull request's layer, 1-based, where 1 is closest to `baseRef`. */\n\tposition: number;\n\t/** The branch the bottom of the stack targets. */\n\tbaseRef: string;\n}\n\n/**\n * One layer of a stack — the pull request occupying it, and the head ref a rebase or push needs to act\n * on. Unlike {@link PullRequestStackInfo}, which locates a single pull request within a stack, this is\n * the per-layer detail a caller walking the whole stack needs, e.g. to cascade a rebase bottom to top.\n */\nexport interface PullRequestStackLayer {\n\t/** The pull request's number. */\n\tnumber: number;\n\t/** The pull request's head branch name, without a remote prefix. */\n\theadRef: string;\n\t/** The head branch's tip when the stack was read. */\n\theadSha: string;\n\t/** `true` once this layer has landed. */\n\tmerged: boolean;\n\t/** `true` while this layer is still a draft. */\n\tdraft: boolean;\n}\n\n/**\n * A stack's layers, ordered bottom to top. `baseRef` is the stack's ultimate target (its trunk), the\n * same distinction drawn on {@link PullRequestStackInfo} — it is NOT the base of any individual layer\n * above the bottom, which targets the layer below it instead.\n */\nexport interface PullRequestStackLayers {\n\t/** Opaque and not comparable across read paths — see {@link PullRequestStackInfo.id}. */\n\tid: string;\n\tnumber: number;\n\t/** The branch the bottom of the stack targets. */\n\tbaseRef: string;\n\t/** The stack's layers, ordered bottom (closest to {@link baseRef}) to top. */\n\tlayers: PullRequestStackLayer[];\n}\n\nexport interface PullRequestReviewer {\n\tisCodeOwner?: boolean;\n\treviewer: PullRequestMember;\n\tstate: PullRequestReviewState;\n\t/**\n\t * The head commit oid this review was submitted against (GitHub). Lets a consumer tell \"the PR moved past\n\t * my review\" (oid !== the PR's current head) from a review still at the tip — without a per-review\n\t * timestamp. Only populated where the full GitHub/GHE projection is selected: the filtered search read, and\n\t * an account-wide sweep that opts in with `includeReviews`. Undefined elsewhere, including reviews the\n\t * repo-scoped read carries natively.\n\t */\n\tcommitOid?: string;\n\t/**\n\t * The reviewer is a group the current user is a member of (a team or another group, directly or through a group\n\t * nested in it) rather than a person: a request to it is one the user can answer as a member, not one addressed to\n\t * them by name. Only the Azure DevOps reads that resolve the user's groups set it; absent elsewhere, including for\n\t * groups a read could not tell the user belongs to.\n\t */\n\tisMyGroup?: boolean;\n}\n\nexport type PullRequestRepositoryIdentityDescriptor = RequireSomeWithProps<\n\tRequireSome<RepositoryIdentityDescriptor<string>, 'provider'>,\n\t'provider',\n\t'id' | 'domain' | 'repoDomain' | 'repoName'\n> &\n\tRequireSomeWithProps<RequireSome<RepositoryIdentityDescriptor<string>, 'remote'>, 'remote', 'domain'>;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pullRequest.js","names":[],"sources":["../../../../git/src/models/pullRequest.ts"],"sourcesContent":["import { formatDate, fromNow } from '@gitlens/utils/date.js';\nimport { loggable } from '@gitlens/utils/decorators/log.js';\nimport { serializable } from '@gitlens/utils/decorators/serializable.js';\nimport type { RequireSome, RequireSomeWithProps } from '@gitlens/utils/types.js';\nimport type { IssueProject, IssueRepository } from './issue.js';\nimport type { IssueOrPullRequest, IssueOrPullRequestState as PullRequestState } from './issueOrPullRequest.js';\nimport type { ProviderReference } from './remoteProvider.js';\nimport type { RepositoryIdentityDescriptor } from './repositoryIdentities.js';\n\nexport type { PullRequestState };\n\n/**\n * The read that produced a pull request row, as a key for `getPullRequestFieldPresence` (`@gitlens/integrations`). It\n * names a READ, not a field set: the same tag can carry different fields on different providers.\n */\nexport type PullRequestProjection =\n\t/** A single-item read: by number, for a branch, or for a commit. */\n\t| 'point'\n\t/** The filtered search with the full projection, and the host's \"my pull requests\" search. */\n\t| 'search'\n\t/** The filtered search with `summary`. */\n\t| 'search-summary'\n\t/** The free-text search (`searchPullRequests`). */\n\t| 'text-search'\n\t/** An account-wide sweep with the full projection (`includeReviews`). */\n\t| 'account'\n\t/** An account-wide list or sweep with the lightweight projection. */\n\t| 'account-summary'\n\t/** A repository-scoped list or sweep. */\n\t| 'repos'\n\t/** A repository-scoped list with `summary`. */\n\t| 'repos-summary'\n\t/** The coordinate and branch batch reads. */\n\t| 'batch';\n\nexport interface PullRequestShape extends IssueOrPullRequest {\n\treadonly state: PullRequestState;\n\treadonly author: PullRequestMember;\n\t/**\n\t * Canonical base-repository identity returned by the provider. Some providers\n\t * scope pull-request ids to a repository, so consumers must not have to infer\n\t * identity from optional refs or URLs.\n\t */\n\treadonly repository?: IssueRepository;\n\treadonly mergedDate?: Date;\n\treadonly refs?: PullRequestRefs;\n\treadonly isDraft?: boolean;\n\treadonly additions?: number;\n\treadonly deletions?: number;\n\treadonly filesChanged?: number;\n\treadonly body?: string;\n\treadonly mergeableState?: PullRequestMergeableState;\n\treadonly reviewDecision?: PullRequestReviewDecision;\n\treadonly reviewRequests?: PullRequestReviewer[];\n\t/**\n\t * Reviews already submitted, as opposed to the still-pending {@link reviewRequests}. Absent means the read\n\t * didn't fetch reviews; empty means nobody has reviewed — but only where the read actually fetched them, which\n\t * is provider- and read-dependent: ask `getPullRequestFieldPresence` (`@gitlens/integrations`) for the row's\n\t * `reviews` group rather than trusting an empty array.\n\t * {@link PullRequestReviewer.commitOid} is the narrower promise: only the full GitHub/GHE projection has it.\n\t */\n\treadonly latestReviews?: PullRequestReviewer[];\n\treadonly assignees?: PullRequestMember[];\n\treadonly project?: IssueProject;\n\treadonly stack?: PullRequestStackInfo;\n\treadonly number?: number;\n\treadonly authoredByMe?: boolean;\n\t/**\n\t * The current account as this pull request's members identify it: the identity its people were matched against,\n\t * present whenever it was resolved (see {@link viewerUnresolved} for an Azure DevOps row it couldn't be for). {@link authoredByMe} is matched against it too, and stays `undefined` when the\n\t * row has no author, though its reviewers or assignees still get this. A consumer matching {@link reviewRequests}\n\t * or {@link latestReviews} entries to the current user compares against this, not the account `getCurrentAccount`\n\t * returns: Azure DevOps can know one person by another id in each organization (Azure DevOps Server: collection)\n\t * than the account's, and the members carry the organization's. Core matches `username` too only on GitHub and\n\t * GitHub Enterprise, whose rows key people by login.\n\t */\n\treadonly viewer?: { readonly id: string; readonly username?: string };\n\t/**\n\t * Set, and only ever `true`, on an Azure DevOps row that names someone (its author, a reviewer or an assignee)\n\t * whose organization's (Azure DevOps Server: collection's) identity the read tried and failed to resolve: its\n\t * `ConnectionData` failed, answered without an identity, or didn't answer within 10 seconds. Such a row has neither\n\t * {@link viewer} nor {@link authoredByMe}, and neither the account `getCurrentAccount` returns nor anyone else can\n\t * be matched against its people: whether it is the current user's, or asks for their review, is unknown, not \"no\".\n\t * Absent everywhere else, so a row with neither field is still one whose identity wasn't resolved for another\n\t * reason (a read that doesn't resolve it, or a failed account read), as before.\n\t */\n\treadonly viewerUnresolved?: true;\n\t/** The read that produced this row. Absent means unknown: a legacy row, or a provider or read not yet tagged. */\n\treadonly projection?: PullRequestProjection;\n}\n\n@loggable(i => i.id)\n@serializable\nexport class PullRequest implements PullRequestShape {\n\treadonly type = 'pullrequest';\n\n\tconstructor(\n\t\tpublic readonly provider: ProviderReference,\n\t\tpublic readonly author: PullRequestMember,\n\t\tpublic readonly id: string,\n\t\tpublic readonly nodeId: string | undefined,\n\t\tpublic readonly title: string,\n\t\tpublic readonly url: string,\n\t\tpublic readonly repository: IssueRepository,\n\t\tpublic readonly state: PullRequestState,\n\t\tpublic readonly createdDate: Date,\n\t\tpublic readonly updatedDate: Date,\n\t\tpublic readonly closedDate?: Date,\n\t\tpublic readonly mergedDate?: Date,\n\t\tpublic readonly mergeableState?: PullRequestMergeableState,\n\t\tpublic readonly viewerCanUpdate?: boolean,\n\t\tpublic readonly refs?: PullRequestRefs,\n\t\tpublic readonly isDraft?: boolean,\n\t\tpublic readonly additions?: number,\n\t\tpublic readonly deletions?: number,\n\t\tpublic readonly commentsCount?: number,\n\t\tpublic readonly thumbsUpCount?: number,\n\t\tpublic readonly reviewDecision?: PullRequestReviewDecision,\n\t\tpublic readonly reviewRequests?: PullRequestReviewer[],\n\t\tpublic readonly latestReviews?: PullRequestReviewer[],\n\t\tpublic readonly assignees?: PullRequestMember[],\n\t\tpublic readonly statusCheckRollupState?: PullRequestStatusCheckRollupState,\n\t\tpublic readonly project?: IssueProject,\n\t\tpublic readonly version?: number,\n\t\t/** Commits on the head that aren't on the base. Appended rather than slotted with the other counts:\n\t\t * this constructor is positional and every mapper passes through it. */\n\t\tpublic readonly commitCount?: number,\n\t\tpublic readonly stack?: PullRequestStackInfo,\n\t\tpublic readonly filesChanged?: number,\n\t\t/** The pull request's description, as markdown. */\n\t\tpublic readonly body?: string,\n\t\tpublic readonly number?: number,\n\t\tpublic readonly authoredByMe?: boolean,\n\t\tpublic readonly projection?: PullRequestProjection,\n\t\tpublic readonly viewer?: { readonly id: string; readonly username?: string },\n\t\tpublic readonly viewerUnresolved?: true,\n\t) {}\n\n\tget closed(): boolean {\n\t\treturn this.state === 'closed';\n\t}\n\n\tstatic is(pr: unknown): pr is PullRequest {\n\t\treturn pr instanceof PullRequest;\n\t}\n\n\tstatic formatDate(pr: PullRequestShape, format?: string | null): string {\n\t\treturn formatDate(pr.mergedDate ?? pr.closedDate ?? pr.updatedDate, format ?? 'MMMM Do, YYYY h:mma');\n\t}\n\n\tstatic formatDateFromNow(pr: PullRequestShape): string {\n\t\treturn fromNow(pr.mergedDate ?? pr.closedDate ?? pr.updatedDate);\n\t}\n\n\tstatic formatDateWithStyle(\n\t\tpr: PullRequestShape,\n\t\tformatting: { dateStyle: string; dateFormat: string | null },\n\t): string {\n\t\treturn formatting.dateStyle === 'absolute'\n\t\t\t? PullRequest.formatDate(pr, formatting.dateFormat)\n\t\t\t: PullRequest.formatDateFromNow(pr);\n\t}\n}\n\nexport const enum PullRequestReviewDecision {\n\tApproved = 'Approved',\n\tChangesRequested = 'ChangesRequested',\n\tReviewRequired = 'ReviewRequired',\n}\n\nexport const enum PullRequestMergeableState {\n\tUnknown = 'Unknown',\n\tMergeable = 'Mergeable',\n\tConflicting = 'Conflicting',\n\tFailingChecks = 'FailingChecks',\n\tBlockedByPolicy = 'BlockedByPolicy',\n}\n\nexport const enum PullRequestStatusCheckRollupState {\n\tSuccess = 'success',\n\tPending = 'pending',\n\tFailed = 'failed',\n}\n\nexport const enum PullRequestMergeMethod {\n\tMerge = 'merge',\n\tSquash = 'squash',\n\tRebase = 'rebase',\n}\n\nexport const enum PullRequestReviewState {\n\tApproved = 'APPROVED',\n\tChangesRequested = 'CHANGES_REQUESTED',\n\tCommented = 'COMMENTED',\n\tDismissed = 'DISMISSED',\n\tPending = 'PENDING',\n\tReviewRequested = 'REVIEW_REQUESTED',\n}\n\nexport interface PullRequestComparisonRefs {\n\trepoPath: string;\n\tbase: { ref: string; label: string };\n\thead: { ref: string; label: string };\n}\n\nexport interface PullRequestMember {\n\tid: string;\n\t/**\n\t * Absent when the provider exposes no display name for the member — same contract as `IssueMember.name`: a\n\t * fallback invented here can't be told apart from a real name downstream, so each consumer picks its own\n\t * presentation.\n\t */\n\tname?: string;\n\t/** The provider's handle for this person, when it has one — GitHub's login, Azure's `uniqueName` (a UPN,\n\t * so an email), Bitbucket's mutable `nickname`. Display/labelling only: it is neither guaranteed present\n\t * (GitLab's native mapper has none) nor a stable identity, so never key a match off it. */\n\tusername?: string;\n\tavatarUrl?: string;\n\turl?: string;\n}\n\n/** Provider-neutral relationship facets shared by PR listings and filtered PR search. */\nexport enum PullRequestFilter {\n\tAuthor = 'author',\n\tAssignee = 'assignee',\n\tReviewRequested = 'review-requested',\n\t/**\n\t * PRs the user has already reviewed (GitHub `reviewed-by:@me`), as opposed to `ReviewRequested` (a\n\t * still-pending request). Distinguishes \"waiting on the author after my review\" from \"waiting for my\n\t * review\". Not expressible on the repo-scoped listing — no provider SDK exposes a reviewed-by axis there —\n\t * so it is advertised for the account-wide read and for the filtered search (which can still bound itself\n\t * to repositories or an org), never under `supportedPullRequestFilters`.\n\t */\n\tReviewed = 'reviewed-by',\n\tMention = 'mention',\n}\n\n/** Selects which pull request states a read should include. `all` covers open + closed + merged. */\nexport type PullRequestStateFilter = 'open' | 'closed' | 'merged' | 'all';\n\n/**\n * A field a pull-request read can be ordered by, provider-neutral.\n *\n * Only two, and deliberately so — unlike {@link IssueSortField} this is the INTERSECTION of what GitHub's PR\n * search can order by server-side and what a {@link PullRequestShape} carries, because the filtered PR search\n * always merges its relationship × state facets in the facade and so must re-order the union itself (see\n * `getPullRequestComparator`). `created` and `updated` are both. A field GitHub cannot order PRs by, or one a\n * merged page can't reproduce, is left out rather than advertised and then approximated: relevance is unstable\n * and has no comparable value on a merge, and priority is not a pull-request concept on any provider that has PRs.\n */\nexport type PullRequestSortField =\n\t/** Creation date. */\n\t| 'created'\n\t/** Last activity. */\n\t| 'updated';\n\n/**\n * How a pull-request read is ordered, as `field:direction` — the same serializable shape {@link IssueSorting}\n * and `BranchSorting` use, so a consumer can persist it, compare it, or bind it straight to a setting or dropdown.\n */\nexport type PullRequestSorting = `${PullRequestSortField}:asc` | `${PullRequestSortField}:desc`;\n\n/**\n * The order the filtered pull-request search applies when the caller asks for none: most recently updated first,\n * which is what it served before ordering was an option. Named once rather than per layer — the criteria model\n * documents it, the GitHub query emits it, and the result-ceiling warning quotes it — so the three cannot\n * disagree about what \"the default\" is.\n */\nexport const defaultPullRequestSort: PullRequestSorting = 'updated:desc';\n\n/**\n * What the filtered pull-request search narrows on.\n *\n * Structured rather than a provider query string so callers can send free text without giving it a qualifier\n * channel, and can check {@link PullRequestSearchCapabilities} before issuing a read. Every requested criterion\n * is validated all-or-nothing before the provider runs; unsupported criteria never fall through to a wider\n * result set whose paging would no longer describe the returned items.\n *\n * Relationships are OR-ed, as are states. Omitting `relationships` removes the current-user constraint, which is\n * only safe when the manager call supplies a repository or organization scope. Omitting `states` reads open PRs.\n */\nexport interface PullRequestSearchCriteria {\n\t/**\n\t * Free text matched by the provider's own relevance rules. Tokens that look like provider qualifiers are\n\t * removed before the query is built, so text cannot change the search's scope or state.\n\t */\n\ttext?: string;\n\t/** Current-user relationship facets to union. Empty/omitted means no relationship constraint. */\n\trelationships?: PullRequestFilter[];\n\t/** Pull request states to union. Empty/omitted reads open PRs; `all` subsumes every other member. */\n\tstates?: PullRequestStateFilter[];\n\t/** ISO date (`YYYY-MM-DD`). The most effective narrowing criterion by far on a large scope. */\n\tupdatedAfter?: string;\n\t/** ISO date (`YYYY-MM-DD`). */\n\tcreatedAfter?: string;\n\t/** Includes PRs from archived repositories. They are excluded by default. */\n\tincludeArchived?: boolean;\n\t/**\n\t * Narrows on draft state: `true` returns only drafts, `false` only ready-for-review PRs. Omitted places no\n\t * constraint. A boolean rather than a truthy flag because `false` is a distinct request, not the absence of one.\n\t */\n\tdraft?: boolean;\n\t/**\n\t * How to order the results. Omitted means `updated:desc`, which is what this search has always served.\n\t *\n\t * Validated all-or-nothing against {@link PullRequestSearchCapabilities.sorts} like every other criterion: a\n\t * key the provider can't express server-side refuses the WHOLE read rather than falling back to the default,\n\t * because combined with the provider's result ceiling another order returns a different subset than was asked\n\t * for and the paging that comes with it describes that other subset. Do not change it mid-pagination — a\n\t * cursor carries the sort it was produced under; drop the cursor instead of threading it under a new key.\n\t */\n\tsort?: PullRequestSorting;\n}\n\n/**\n * Which {@link PullRequestSearchCriteria} fields and manager-level scopes a provider can express server-side.\n * An empty `relationships` means the provider has no filtered PR search at all.\n */\nexport interface PullRequestSearchCapabilities {\n\t/** Current-user relationship facets the provider can union. Empty means the search itself is unsupported. */\n\trelationships: PullRequestFilter[];\n\t/** Individual state values the provider can union in one logical search. */\n\tstates: PullRequestStateFilter[];\n\ttext: boolean;\n\tupdatedAfter: boolean;\n\tcreatedAfter: boolean;\n\tincludeArchived: boolean;\n\t/** Whether the provider can constrain the search by draft state server-side. */\n\tdraft: boolean;\n\t/** Whether the manager's repository-descriptor scope is supported. */\n\trepositoryScope: boolean;\n\t/** Whether the manager's organization scope is supported. */\n\torganizationScope: boolean;\n\t/**\n\t * Sort keys the search can express server-side. Always contains at least `updated:desc` — the historical\n\t * default — when the search exists at all, so it is never empty for a usable surface; a provider without a\n\t * filtered PR search reports an empty `relationships`, which is already the signal there is no surface to order.\n\t */\n\tsorts: PullRequestSorting[];\n}\n\nexport interface PullRequestRef {\n\t/**\n\t * `undefined` when the ref's repository was deleted (a removed fork): GitHub's rows say so, with `exists` false.\n\t * provider-apis' converters fill `''` instead, so test for a value rather than for `undefined`.\n\t */\n\towner: string | undefined;\n\t/** `undefined` (or `''`) when the ref's repository was deleted, as {@link owner}. */\n\trepo: string | undefined;\n\tbranch: string;\n\tsha: string;\n\texists: boolean;\n\t/**\n\t * Web URL of the ref's repository. `undefined` when the provider cannot resolve it — Azure DevOps embeds an\n\t * abbreviated repository reference in a pull request, so a fork's URL may need a lookup that can fail.\n\t */\n\turl: string | undefined;\n\t/** HTTPS clone URL of the ref's repository, when the provider exposes it. */\n\tcloneHttps?: string;\n\t/** SSH clone URL of the ref's repository, when the provider exposes it. */\n\tcloneSsh?: string;\n\t/** Best-effort flag: whether the ref's repository is a fork. `undefined` when the provider can't tell. */\n\tisFork?: boolean;\n}\n\nexport interface PullRequestRefs {\n\tbase: PullRequestRef & { url: string };\n\thead: PullRequestRef;\n\tisCrossRepository: boolean;\n}\n\n/**\n * A pull request's membership in a stack — an ordered chain of dependent pull requests where each\n * targets the branch of the one below it.\n *\n * `baseRef` is the stack's ultimate target (its trunk) and is NOT the same as `refs.base`, which for\n * anything above the bottom layer names the layer below. Use `refs.base` to diff a single layer; use\n * `baseRef` to answer where the work ultimately lands.\n */\nexport interface PullRequestStackInfo {\n\t/**\n\t * Opaque, and NOT comparable across read paths: GitHub's GraphQL selection returns a node id\n\t * (`PRS_kwDO…`) while its REST stacks endpoint returns a numeric id (`1347135`) that we stringify —\n\t * both verified against the same live stack. Use {@link number} to identify a stack; two views of one\n\t * stack agree there and will not agree here.\n\t */\n\tid: string;\n\t/** Identifies the stack within its repository. */\n\tnumber: number;\n\t/** Total pull requests in the stack. */\n\tsize: number;\n\t/** This pull request's layer, 1-based, where 1 is closest to `baseRef`. */\n\tposition: number;\n\t/** The branch the bottom of the stack targets. */\n\tbaseRef: string;\n}\n\n/**\n * One layer of a stack — the pull request occupying it, and the head ref a rebase or push needs to act\n * on. Unlike {@link PullRequestStackInfo}, which locates a single pull request within a stack, this is\n * the per-layer detail a caller walking the whole stack needs, e.g. to cascade a rebase bottom to top.\n */\nexport interface PullRequestStackLayer {\n\t/** The pull request's number. */\n\tnumber: number;\n\t/** The pull request's head branch name, without a remote prefix. */\n\theadRef: string;\n\t/** The head branch's tip when the stack was read. */\n\theadSha: string;\n\t/** `true` once this layer has landed. */\n\tmerged: boolean;\n\t/** `true` while this layer is still a draft. */\n\tdraft: boolean;\n}\n\n/**\n * A stack's layers, ordered bottom to top. `baseRef` is the stack's ultimate target (its trunk), the\n * same distinction drawn on {@link PullRequestStackInfo} — it is NOT the base of any individual layer\n * above the bottom, which targets the layer below it instead.\n */\nexport interface PullRequestStackLayers {\n\t/** Opaque and not comparable across read paths — see {@link PullRequestStackInfo.id}. */\n\tid: string;\n\tnumber: number;\n\t/** The branch the bottom of the stack targets. */\n\tbaseRef: string;\n\t/** The stack's layers, ordered bottom (closest to {@link baseRef}) to top. */\n\tlayers: PullRequestStackLayer[];\n}\n\nexport interface PullRequestReviewer {\n\tisCodeOwner?: boolean;\n\treviewer: PullRequestMember;\n\tstate: PullRequestReviewState;\n\t/**\n\t * The head commit oid this review was submitted against (GitHub). Lets a consumer tell \"the PR moved past\n\t * my review\" (oid !== the PR's current head) from a review still at the tip — without a per-review\n\t * timestamp. Only populated where the full GitHub/GHE projection is selected: the filtered search read, and\n\t * an account-wide sweep that opts in with `includeReviews`. Undefined elsewhere, including reviews the\n\t * repo-scoped read carries natively.\n\t */\n\tcommitOid?: string;\n\t/**\n\t * The reviewer is a group the current user is a member of (a team or another group, directly or through a group\n\t * nested in it) rather than a person: a request to it is one the user can answer as a member, not one addressed to\n\t * them by name. Only the Azure DevOps reads that resolve the user's groups set it; absent elsewhere, including for\n\t * groups a read could not tell the user belongs to.\n\t */\n\tisMyGroup?: boolean;\n}\n\nexport type PullRequestRepositoryIdentityDescriptor = RequireSomeWithProps<\n\tRequireSome<RepositoryIdentityDescriptor<string>, 'provider'>,\n\t'provider',\n\t'id' | 'domain' | 'repoDomain' | 'repoName'\n> &\n\tRequireSomeWithProps<RequireSome<RepositoryIdentityDescriptor<string>, 'remote'>, 'remote', 'domain'>;\n"],"mappings":"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"}
|
|
@@ -169,7 +169,8 @@ function serializeIssue(value) {
|
|
|
169
169
|
viewer: value.viewer != null ? {
|
|
170
170
|
id: value.viewer.id,
|
|
171
171
|
username: value.viewer.username
|
|
172
|
-
} : void 0
|
|
172
|
+
} : void 0,
|
|
173
|
+
viewerUnresolved: value.viewerUnresolved
|
|
173
174
|
};
|
|
174
175
|
}
|
|
175
176
|
/** Whether a provider's workflow category ends the issue: done or abandoned (see {@link IssueProviderState.category}). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"issue.utils.js","names":[],"sources":["../../../../git/src/utils/issue.utils.ts"],"sourcesContent":["import type {\n\tIssue,\n\tIssueProviderState,\n\tIssueRepositoryIdentityDescriptor,\n\tIssueShape,\n\tIssueSortField,\n\tIssueSorting,\n} from '../models/issue.js';\nimport { defaultIssueSort } from '../models/issue.js';\n\n/**\n * How each sort field is read off an {@link IssueShape}, for the reads that MERGE several provider queries and so\n * have to order the union themselves instead of letting the provider do it.\n *\n * Only the fields the shape actually carries appear. `priority`, `dueDate` and `resolved` are absent because\n * `IssueOrPullRequest`/`IssueShape` doesn't model them: a provider may well order by them server-side on a\n * single-query read, but a merged one cannot — which is exactly what {@link getIssueComparator} returning\n * `undefined` lets its caller refuse, instead of concatenating unordered runs and calling them sorted.\n */\nconst issueSortValues: Partial<Record<IssueSortField, (issue: IssueShape) => number | Date | string | undefined>> = {\n\tcreated: i => i.createdDate,\n\tupdated: i => i.updatedDate,\n\tclosed: i => i.closedDate,\n\tcomments: i => i.commentsCount,\n\treactions: i => i.thumbsUpCount,\n\ttitle: i => i.title,\n};\n\n/**\n * The order a read that ALWAYS orders is being made under: the caller's key, or the facade's default.\n *\n * The one place `?? defaultIssueSort` may be written. Several things downstream must agree on the answer — the\n * emitted provider qualifier, the fingerprint sealed into a cursor, the comparator that re-sorts a merged page and\n * the ceiling warning that names the order — and re-deriving the fallback at each is how they come to disagree,\n * which is not cosmetic: a cursor sealed with a key its query wasn't built with makes the fingerprint check refuse\n * valid resumptions.\n *\n * Note this is for a surface that CAN always order. A read whose provider may not express even the default resolves\n * through `resolveIssueSort` instead, which can answer \"leave the provider's own order\".\n */\nexport function effectiveIssueSort(sort: IssueSorting | undefined): IssueSorting {\n\treturn sort ?? defaultIssueSort;\n}\n\n/**\n * A comparator for one sort key over normalized issues, or `undefined` when the field isn't derivable from an\n * {@link IssueShape} — the signal that the key is only honorable on a SINGLE-origin read, where the provider\n * already ordered the page.\n *\n * `@gitkraken/provider-apis` carries a twin of this over its own `Issue` shape (`src/issueSort.ts`), which it uses\n * for the merges it performs itself. It is not importable — the SDK does not export it, and it takes a different\n * shape — so the two are separate implementations of one rule, and the rule below is the part that must not drift.\n *\n * Missing values sort LAST in both directions. That is deliberately not the same as negating the descending\n * comparator (which would float them to the front when ascending), and it is why they're partitioned before any\n * arithmetic rather than mapped to an infinite sentinel: two missing values have to compare equal, and\n * `-Infinity - -Infinity` is `NaN`, which makes the comparator inconsistent and the resulting order\n * implementation-defined.\n *\n * Note it orders whatever it is handed. Sorting a page that was already capped does not make it the top N.\n *\n * KNOWN DIVERGENCE, `title` only: strings are compared by code unit, so `'B' < 'a'`. A single-scope read is\n * ordered by the provider's own database instead — case-insensitive and accent-aware — so the same `title:asc`\n * yields \"Banana, apple, ábaco\" from a merged page and \"ábaco, apple, Banana\" from one repository. Deliberately\n * NOT fixed with `localeCompare`: the SDK's twin comparator (which performs the merges core doesn't, notably\n * GitLab's repo-ids aggregate) compares by code unit, so switching here would make two paths of the SAME\n * multi-repo read disagree — a worse divergence than the one it closes, and it would break the parity test in\n * `issueSortCapabilities.test.ts`. Closing this properly means changing the rule on BOTH sides at once; until\n * then it is a cosmetic ordering difference on one key, not wrong data.\n */\nexport function getIssueComparator(sort: IssueSorting): ((a: IssueShape, b: IssueShape) => number) | undefined {\n\t// The union's shape guarantees both halves, so this needs no validation — only the cast tsc can't infer.\n\tconst [field, direction] = sort.split(':') as [IssueSortField, 'asc' | 'desc'];\n\tconst getValue = issueSortValues[field];\n\tif (getValue == null) return undefined;\n\n\treturn (a, b) => {\n\t\tconst left = toComparable(getValue(a));\n\t\tconst right = toComparable(getValue(b));\n\t\tif (left == null || right == null) {\n\t\t\tif (left == null && right == null) return 0;\n\t\t\treturn left == null ? 1 : -1;\n\t\t}\n\n\t\tconst ordered = left < right ? -1 : left > right ? 1 : 0;\n\t\treturn direction === 'asc' ? ordered : -ordered;\n\t};\n}\n\nfunction toComparable(value: number | Date | string | undefined): number | string | undefined {\n\treturn value instanceof Date ? value.getTime() : value;\n}\n\nexport function getRepositoryIdentityForIssue(issue: IssueShape | Issue): IssueRepositoryIdentityDescriptor {\n\tif (issue.repository == null) throw new Error('Missing repository');\n\n\treturn {\n\t\tremote: {\n\t\t\turl: issue.repository.url,\n\t\t\tdomain: issue.provider.domain,\n\t\t},\n\t\tname: `${issue.repository.owner}/${issue.repository.repo}`,\n\t\tprovider: {\n\t\t\tid: issue.provider.id,\n\t\t\tdomain: issue.provider.domain,\n\t\t\trepoDomain: issue.repository.owner,\n\t\t\trepoName: issue.repository.repo,\n\t\t\trepoOwnerDomain: issue.repository.owner,\n\t\t},\n\t};\n}\n\n/**\n * Deliberately leaves `projection` out: this copy drops `repository.accessLevel`, so a tag would have field presence\n * report the viewer's access as fetched when the copy no longer has it.\n */\nexport function serializeIssue(value: IssueShape): IssueShape {\n\tconst serialized: IssueShape = {\n\t\ttype: value.type,\n\t\tprovider: {\n\t\t\tid: value.provider.id,\n\t\t\tname: value.provider.name,\n\t\t\tdomain: value.provider.domain,\n\t\t\ticon: value.provider.icon,\n\t\t},\n\t\tid: value.id,\n\t\tnodeId: value.nodeId,\n\t\tissueType: value.issueType,\n\t\ttitle: value.title,\n\t\turl: value.url,\n\t\tcreatedDate: value.createdDate,\n\t\tupdatedDate: value.updatedDate,\n\t\tclosedDate: value.closedDate,\n\t\tclosed: value.closed,\n\t\tstate: value.state,\n\t\tproviderState:\n\t\t\tvalue.providerState == null\n\t\t\t\t? undefined\n\t\t\t\t: {\n\t\t\t\t\t\tid: value.providerState.id,\n\t\t\t\t\t\tname: value.providerState.name,\n\t\t\t\t\t\tcolor: value.providerState.color,\n\t\t\t\t\t\tcategory: value.providerState.category,\n\t\t\t\t\t},\n\t\tauthor:\n\t\t\tvalue.author == null\n\t\t\t\t? undefined\n\t\t\t\t: {\n\t\t\t\t\t\tid: value.author.id,\n\t\t\t\t\t\tname: value.author.name,\n\t\t\t\t\t\tusername: value.author.username,\n\t\t\t\t\t\tavatarUrl: value.author.avatarUrl,\n\t\t\t\t\t\turl: value.author.url,\n\t\t\t\t\t},\n\t\trepository:\n\t\t\tvalue.repository == null\n\t\t\t\t? undefined\n\t\t\t\t: {\n\t\t\t\t\t\towner: value.repository.owner,\n\t\t\t\t\t\trepo: value.repository.repo,\n\t\t\t\t\t\turl: value.repository.url,\n\t\t\t\t\t},\n\t\tproject:\n\t\t\tvalue.project == null\n\t\t\t\t? undefined\n\t\t\t\t: {\n\t\t\t\t\t\tid: value.project.id,\n\t\t\t\t\t\tname: value.project.name,\n\t\t\t\t\t\tresourceId: value.project.resourceId,\n\t\t\t\t\t\tresourceName: value.project.resourceName,\n\t\t\t\t\t},\n\t\tassignees: value.assignees.map(assignee => ({\n\t\t\tid: assignee.id,\n\t\t\tname: assignee.name,\n\t\t\tusername: assignee.username,\n\t\t\tavatarUrl: assignee.avatarUrl,\n\t\t\turl: assignee.url,\n\t\t})),\n\t\tlabels:\n\t\t\tvalue.labels == null\n\t\t\t\t? undefined\n\t\t\t\t: value.labels.map(label => ({\n\t\t\t\t\t\tcolor: label.color,\n\t\t\t\t\t\tname: label.name,\n\t\t\t\t\t})),\n\t\tcommentsCount: value.commentsCount,\n\t\tthumbsUpCount: value.thumbsUpCount,\n\t\tbody: value.body,\n\t\tbodyFormat: value.bodyFormat,\n\t\tbodyField: value.bodyField == null ? undefined : { id: value.bodyField.id, name: value.bodyField.name },\n\t\titerations:\n\t\t\tvalue.iterations == null\n\t\t\t\t? undefined\n\t\t\t\t: value.iterations.map(iteration => ({\n\t\t\t\t\t\tid: iteration.id,\n\t\t\t\t\t\tname: iteration.name,\n\t\t\t\t\t\tisActive: iteration.isActive,\n\t\t\t\t\t\tstartDate: iteration.startDate,\n\t\t\t\t\t\tendDate: iteration.endDate,\n\t\t\t\t\t})),\n\t\tviewer: value.viewer != null ? { id: value.viewer.id, username: value.viewer.username } : undefined,\n\t};\n\treturn serialized;\n}\n\n/** Whether a provider's workflow category ends the issue: done or abandoned (see {@link IssueProviderState.category}). */\nexport function isTerminalIssueStateCategory(category: IssueProviderState['category']): boolean {\n\treturn category === 'DONE' || category === 'CANCELED';\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"issue.utils.js","names":[],"sources":["../../../../git/src/utils/issue.utils.ts"],"sourcesContent":["import type {\n\tIssue,\n\tIssueProviderState,\n\tIssueRepositoryIdentityDescriptor,\n\tIssueShape,\n\tIssueSortField,\n\tIssueSorting,\n} from '../models/issue.js';\nimport { defaultIssueSort } from '../models/issue.js';\n\n/**\n * How each sort field is read off an {@link IssueShape}, for the reads that MERGE several provider queries and so\n * have to order the union themselves instead of letting the provider do it.\n *\n * Only the fields the shape actually carries appear. `priority`, `dueDate` and `resolved` are absent because\n * `IssueOrPullRequest`/`IssueShape` doesn't model them: a provider may well order by them server-side on a\n * single-query read, but a merged one cannot — which is exactly what {@link getIssueComparator} returning\n * `undefined` lets its caller refuse, instead of concatenating unordered runs and calling them sorted.\n */\nconst issueSortValues: Partial<Record<IssueSortField, (issue: IssueShape) => number | Date | string | undefined>> = {\n\tcreated: i => i.createdDate,\n\tupdated: i => i.updatedDate,\n\tclosed: i => i.closedDate,\n\tcomments: i => i.commentsCount,\n\treactions: i => i.thumbsUpCount,\n\ttitle: i => i.title,\n};\n\n/**\n * The order a read that ALWAYS orders is being made under: the caller's key, or the facade's default.\n *\n * The one place `?? defaultIssueSort` may be written. Several things downstream must agree on the answer — the\n * emitted provider qualifier, the fingerprint sealed into a cursor, the comparator that re-sorts a merged page and\n * the ceiling warning that names the order — and re-deriving the fallback at each is how they come to disagree,\n * which is not cosmetic: a cursor sealed with a key its query wasn't built with makes the fingerprint check refuse\n * valid resumptions.\n *\n * Note this is for a surface that CAN always order. A read whose provider may not express even the default resolves\n * through `resolveIssueSort` instead, which can answer \"leave the provider's own order\".\n */\nexport function effectiveIssueSort(sort: IssueSorting | undefined): IssueSorting {\n\treturn sort ?? defaultIssueSort;\n}\n\n/**\n * A comparator for one sort key over normalized issues, or `undefined` when the field isn't derivable from an\n * {@link IssueShape} — the signal that the key is only honorable on a SINGLE-origin read, where the provider\n * already ordered the page.\n *\n * `@gitkraken/provider-apis` carries a twin of this over its own `Issue` shape (`src/issueSort.ts`), which it uses\n * for the merges it performs itself. It is not importable — the SDK does not export it, and it takes a different\n * shape — so the two are separate implementations of one rule, and the rule below is the part that must not drift.\n *\n * Missing values sort LAST in both directions. That is deliberately not the same as negating the descending\n * comparator (which would float them to the front when ascending), and it is why they're partitioned before any\n * arithmetic rather than mapped to an infinite sentinel: two missing values have to compare equal, and\n * `-Infinity - -Infinity` is `NaN`, which makes the comparator inconsistent and the resulting order\n * implementation-defined.\n *\n * Note it orders whatever it is handed. Sorting a page that was already capped does not make it the top N.\n *\n * KNOWN DIVERGENCE, `title` only: strings are compared by code unit, so `'B' < 'a'`. A single-scope read is\n * ordered by the provider's own database instead — case-insensitive and accent-aware — so the same `title:asc`\n * yields \"Banana, apple, ábaco\" from a merged page and \"ábaco, apple, Banana\" from one repository. Deliberately\n * NOT fixed with `localeCompare`: the SDK's twin comparator (which performs the merges core doesn't, notably\n * GitLab's repo-ids aggregate) compares by code unit, so switching here would make two paths of the SAME\n * multi-repo read disagree — a worse divergence than the one it closes, and it would break the parity test in\n * `issueSortCapabilities.test.ts`. Closing this properly means changing the rule on BOTH sides at once; until\n * then it is a cosmetic ordering difference on one key, not wrong data.\n */\nexport function getIssueComparator(sort: IssueSorting): ((a: IssueShape, b: IssueShape) => number) | undefined {\n\t// The union's shape guarantees both halves, so this needs no validation — only the cast tsc can't infer.\n\tconst [field, direction] = sort.split(':') as [IssueSortField, 'asc' | 'desc'];\n\tconst getValue = issueSortValues[field];\n\tif (getValue == null) return undefined;\n\n\treturn (a, b) => {\n\t\tconst left = toComparable(getValue(a));\n\t\tconst right = toComparable(getValue(b));\n\t\tif (left == null || right == null) {\n\t\t\tif (left == null && right == null) return 0;\n\t\t\treturn left == null ? 1 : -1;\n\t\t}\n\n\t\tconst ordered = left < right ? -1 : left > right ? 1 : 0;\n\t\treturn direction === 'asc' ? ordered : -ordered;\n\t};\n}\n\nfunction toComparable(value: number | Date | string | undefined): number | string | undefined {\n\treturn value instanceof Date ? value.getTime() : value;\n}\n\nexport function getRepositoryIdentityForIssue(issue: IssueShape | Issue): IssueRepositoryIdentityDescriptor {\n\tif (issue.repository == null) throw new Error('Missing repository');\n\n\treturn {\n\t\tremote: {\n\t\t\turl: issue.repository.url,\n\t\t\tdomain: issue.provider.domain,\n\t\t},\n\t\tname: `${issue.repository.owner}/${issue.repository.repo}`,\n\t\tprovider: {\n\t\t\tid: issue.provider.id,\n\t\t\tdomain: issue.provider.domain,\n\t\t\trepoDomain: issue.repository.owner,\n\t\t\trepoName: issue.repository.repo,\n\t\t\trepoOwnerDomain: issue.repository.owner,\n\t\t},\n\t};\n}\n\n/**\n * Deliberately leaves `projection` out: this copy drops `repository.accessLevel`, so a tag would have field presence\n * report the viewer's access as fetched when the copy no longer has it.\n */\nexport function serializeIssue(value: IssueShape): IssueShape {\n\tconst serialized: IssueShape = {\n\t\ttype: value.type,\n\t\tprovider: {\n\t\t\tid: value.provider.id,\n\t\t\tname: value.provider.name,\n\t\t\tdomain: value.provider.domain,\n\t\t\ticon: value.provider.icon,\n\t\t},\n\t\tid: value.id,\n\t\tnodeId: value.nodeId,\n\t\tissueType: value.issueType,\n\t\ttitle: value.title,\n\t\turl: value.url,\n\t\tcreatedDate: value.createdDate,\n\t\tupdatedDate: value.updatedDate,\n\t\tclosedDate: value.closedDate,\n\t\tclosed: value.closed,\n\t\tstate: value.state,\n\t\tproviderState:\n\t\t\tvalue.providerState == null\n\t\t\t\t? undefined\n\t\t\t\t: {\n\t\t\t\t\t\tid: value.providerState.id,\n\t\t\t\t\t\tname: value.providerState.name,\n\t\t\t\t\t\tcolor: value.providerState.color,\n\t\t\t\t\t\tcategory: value.providerState.category,\n\t\t\t\t\t},\n\t\tauthor:\n\t\t\tvalue.author == null\n\t\t\t\t? undefined\n\t\t\t\t: {\n\t\t\t\t\t\tid: value.author.id,\n\t\t\t\t\t\tname: value.author.name,\n\t\t\t\t\t\tusername: value.author.username,\n\t\t\t\t\t\tavatarUrl: value.author.avatarUrl,\n\t\t\t\t\t\turl: value.author.url,\n\t\t\t\t\t},\n\t\trepository:\n\t\t\tvalue.repository == null\n\t\t\t\t? undefined\n\t\t\t\t: {\n\t\t\t\t\t\towner: value.repository.owner,\n\t\t\t\t\t\trepo: value.repository.repo,\n\t\t\t\t\t\turl: value.repository.url,\n\t\t\t\t\t},\n\t\tproject:\n\t\t\tvalue.project == null\n\t\t\t\t? undefined\n\t\t\t\t: {\n\t\t\t\t\t\tid: value.project.id,\n\t\t\t\t\t\tname: value.project.name,\n\t\t\t\t\t\tresourceId: value.project.resourceId,\n\t\t\t\t\t\tresourceName: value.project.resourceName,\n\t\t\t\t\t},\n\t\tassignees: value.assignees.map(assignee => ({\n\t\t\tid: assignee.id,\n\t\t\tname: assignee.name,\n\t\t\tusername: assignee.username,\n\t\t\tavatarUrl: assignee.avatarUrl,\n\t\t\turl: assignee.url,\n\t\t})),\n\t\tlabels:\n\t\t\tvalue.labels == null\n\t\t\t\t? undefined\n\t\t\t\t: value.labels.map(label => ({\n\t\t\t\t\t\tcolor: label.color,\n\t\t\t\t\t\tname: label.name,\n\t\t\t\t\t})),\n\t\tcommentsCount: value.commentsCount,\n\t\tthumbsUpCount: value.thumbsUpCount,\n\t\tbody: value.body,\n\t\tbodyFormat: value.bodyFormat,\n\t\tbodyField: value.bodyField == null ? undefined : { id: value.bodyField.id, name: value.bodyField.name },\n\t\titerations:\n\t\t\tvalue.iterations == null\n\t\t\t\t? undefined\n\t\t\t\t: value.iterations.map(iteration => ({\n\t\t\t\t\t\tid: iteration.id,\n\t\t\t\t\t\tname: iteration.name,\n\t\t\t\t\t\tisActive: iteration.isActive,\n\t\t\t\t\t\tstartDate: iteration.startDate,\n\t\t\t\t\t\tendDate: iteration.endDate,\n\t\t\t\t\t})),\n\t\tviewer: value.viewer != null ? { id: value.viewer.id, username: value.viewer.username } : undefined,\n\t\tviewerUnresolved: value.viewerUnresolved,\n\t};\n\treturn serialized;\n}\n\n/** Whether a provider's workflow category ends the issue: done or abandoned (see {@link IssueProviderState.category}). */\nexport function isTerminalIssueStateCategory(category: IssueProviderState['category']): boolean {\n\treturn category === 'DONE' || category === 'CANCELED';\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pullRequest.utils.js","names":[],"sources":["../../../../git/src/utils/pullRequest.utils.ts"],"sourcesContent":["import type {\n\tPullRequest,\n\tPullRequestComparisonRefs,\n\tPullRequestRefs,\n\tPullRequestRepositoryIdentityDescriptor,\n\tPullRequestShape,\n\tPullRequestSortField,\n\tPullRequestSorting,\n\tPullRequestStackInfo,\n} from '../models/pullRequest.js';\nimport { shortenRevision } from './revision.utils.js';\n\n/** How many pull requests a merge action affects — unstacked is always 1; a stacked merge lands either\n * just this layer and everything below it (`position`), or the whole stack (`wholeStack`). The one\n * source every merge-confirmation and merge-action label counts from, so they can't drift apart.\n * Takes only the two fields it needs (not the full {@link PullRequestStackInfo}) since callers on the\n * webview side carry narrower serialized stack shapes. */\nexport function getStackedMergeCount(\n\tstack: Pick<PullRequestStackInfo, 'position' | 'size'> | undefined,\n\toptions?: { wholeStack?: boolean },\n): number {\n\tif (stack == null) return 1;\n\treturn options?.wholeStack ? stack.size : stack.position;\n}\n\n/**\n * How each sort field is read off a {@link PullRequestShape}, for the filtered PR search, which MERGES its\n * relationship × state facets in the facade and so has to order the union itself instead of trusting the\n * per-facet server order. Only the fields the shape carries appear — the same rule as `getIssueComparator`, and\n * the reason {@link PullRequestSortField} is just these two.\n */\nconst pullRequestSortValues: Partial<\n\tRecord<PullRequestSortField, (pr: PullRequestShape) => number | Date | string | undefined>\n> = {\n\tcreated: pr => pr.createdDate,\n\tupdated: pr => pr.updatedDate,\n};\n\n/**\n * A comparator for one sort key over normalized pull requests, or `undefined` when the field isn't derivable\n * from a {@link PullRequestShape} — the signal that the key is only honorable on a SINGLE-origin read where the\n * provider already ordered the page. Missing values sort LAST in both directions (partitioned before any\n * arithmetic so two missing values compare equal, exactly as `getIssueComparator` does).\n *\n * Note it orders whatever it is handed. Sorting a page already capped at the result ceiling does not make it the\n * top N.\n */\nexport function getPullRequestComparator(\n\tsort: PullRequestSorting,\n): ((a: PullRequestShape, b: PullRequestShape) => number) | undefined {\n\tconst [field, direction] = sort.split(':') as [PullRequestSortField, 'asc' | 'desc'];\n\tconst getValue = pullRequestSortValues[field];\n\tif (getValue == null) return undefined;\n\n\treturn (a, b) => {\n\t\tconst left = toComparable(getValue(a));\n\t\tconst right = toComparable(getValue(b));\n\t\tif (left == null || right == null) {\n\t\t\tif (left == null && right == null) return 0;\n\n\t\t\treturn left == null ? 1 : -1;\n\t\t}\n\n\t\tconst ordered = left < right ? -1 : left > right ? 1 : 0;\n\t\treturn direction === 'asc' ? ordered : -ordered;\n\t};\n}\n\nfunction toComparable(value: number | Date | string | undefined): number | string | undefined {\n\treturn value instanceof Date ? value.getTime() : value;\n}\n\nexport interface PullRequestUrlIdentity<TProvider extends string = string> {\n\tprovider?: TProvider;\n\n\townerAndRepo?: string;\n\tprNumber: string;\n}\n\nexport function getComparisonRefsForPullRequest(repoPath: string, prRefs: PullRequestRefs): PullRequestComparisonRefs {\n\tconst refs: PullRequestComparisonRefs = {\n\t\trepoPath: repoPath,\n\t\tbase: { ref: prRefs.base.sha, label: `${prRefs.base.branch} (${shortenRevision(prRefs.base.sha)})` },\n\t\thead: { ref: prRefs.head.sha, label: prRefs.head.branch },\n\t};\n\treturn refs;\n}\n\nexport function getPullRequestIdentityFromMaybeUrl(search: string): PullRequestUrlIdentity | undefined {\n\tlet prNumber: string | undefined = undefined;\n\n\tlet match = search.match(/(?:\\/)(\\d+)/); // any number starting with \"/\"\n\tif (match != null) {\n\t\tprNumber = match[1];\n\t}\n\n\tif (prNumber == null) {\n\t\tmatch = search.match(/^#?(\\d+)$/); // just a number or with a leading \"#\"\n\t\tif (match != null) {\n\t\t\tprNumber = match[1];\n\t\t}\n\t}\n\n\treturn prNumber == null ? undefined : { ownerAndRepo: undefined, prNumber: prNumber, provider: undefined };\n}\n\n/** A pull request's display number from its url, or `undefined` for a url naming no pull request. Anchors\n * on the provider's pull request path segment (GitHub `pull`, Bitbucket `pull-requests`, GitLab\n * `merge_requests`, Azure `pullrequest`) so a digit-leading owner (`github.com/1Password/x/pull/123`)\n * can't win. */\nexport function getPullRequestNumberFromUrl(url: string): string | undefined {\n\t// No loose fallback: `getPullRequestIdentityFromMaybeUrl` scans for any `/<digits>`, which reads a bare\n\t// repository url like `github.com/1Password/sdk` as pull request #1. Callers that hold a real pull\n\t// request fall back to its id instead, and the one that asks whether a pasted url names a pull request\n\t// needs \"no\" for an answer.\n\treturn url.match(/(?:pull|pull-requests|merge_requests|pullrequest)\\/(\\d+)(?:\\b|\\/|$)/)?.[1];\n}\n\nexport function getRepositoryIdentityForPullRequest(\n\tpr: PullRequest,\n\theadRepo: boolean = true,\n): PullRequestRepositoryIdentityDescriptor {\n\tif (headRepo) {\n\t\treturn {\n\t\t\tremote: {\n\t\t\t\turl: pr.refs?.head?.url,\n\t\t\t\tdomain: pr.provider.domain,\n\t\t\t},\n\t\t\tname: `${pr.refs?.head?.owner ?? pr.repository.owner}/${pr.refs?.head?.repo ?? pr.repository.repo}`,\n\t\t\tprovider: {\n\t\t\t\tid: pr.provider.id,\n\t\t\t\tdomain: pr.provider.domain,\n\t\t\t\trepoDomain: pr.refs?.head?.owner ?? pr.repository.owner,\n\t\t\t\trepoName: pr.refs?.head?.repo ?? pr.repository.repo,\n\t\t\t},\n\t\t};\n\t}\n\n\treturn {\n\t\tremote: {\n\t\t\turl: pr.refs?.base?.url ?? pr.url,\n\t\t\tdomain: pr.provider.domain,\n\t\t},\n\t\tname: `${pr.refs?.base?.owner ?? pr.repository.owner}/${pr.refs?.base?.repo ?? pr.repository.repo}`,\n\t\tprovider: {\n\t\t\tid: pr.provider.id,\n\t\t\tdomain: pr.provider.domain,\n\t\t\trepoDomain: pr.refs?.base?.owner ?? pr.repository.owner,\n\t\t\trepoName: pr.refs?.base?.repo ?? pr.repository.repo,\n\t\t\trepoOwnerDomain: pr.refs?.base?.owner ?? pr.repository.owner,\n\t\t},\n\t};\n}\n\nexport function isMaybeNonSpecificPullRequestSearchUrl(search: string): boolean {\n\treturn getPullRequestIdentityFromMaybeUrl(search) != null;\n}\n\n/**\n * Deliberately leaves `projection` out: this copy drops `filesChanged`, `repository` and the class-only check rollup,\n * commit count and `viewerCanUpdate`, so a tag would have field presence report as fetched what the copy no longer has.\n */\nexport function serializePullRequest(value: PullRequest): PullRequestShape {\n\tconst serialized: PullRequestShape = {\n\t\ttype: value.type,\n\t\tprovider: {\n\t\t\tid: value.provider.id,\n\t\t\tname: value.provider.name,\n\t\t\tdomain: value.provider.domain,\n\t\t\ticon: value.provider.icon,\n\t\t},\n\t\tid: value.id,\n\t\tnodeId: value.nodeId,\n\t\tnumber: value.number,\n\t\ttitle: value.title,\n\t\tbody: value.body,\n\t\turl: value.url,\n\t\tcreatedDate: value.createdDate,\n\t\tupdatedDate: value.updatedDate,\n\t\tclosedDate: value.closedDate,\n\t\tclosed: value.closed,\n\t\tauthor: {\n\t\t\tid: value.author.id,\n\t\t\tname: value.author.name,\n\t\t\tusername: value.author.username,\n\t\t\tavatarUrl: value.author.avatarUrl,\n\t\t\turl: value.author.url,\n\t\t},\n\t\tstate: value.state,\n\t\tmergedDate: value.mergedDate,\n\t\tmergeableState: value.mergeableState,\n\t\trefs: value.refs\n\t\t\t? {\n\t\t\t\t\thead: {\n\t\t\t\t\t\texists: value.refs.head.exists,\n\t\t\t\t\t\towner: value.refs.head.owner,\n\t\t\t\t\t\trepo: value.refs.head.repo,\n\t\t\t\t\t\tsha: value.refs.head.sha,\n\t\t\t\t\t\tbranch: value.refs.head.branch,\n\t\t\t\t\t\turl: value.refs.head.url,\n\t\t\t\t\t\tcloneHttps: value.refs.head.cloneHttps,\n\t\t\t\t\t\tcloneSsh: value.refs.head.cloneSsh,\n\t\t\t\t\t\tisFork: value.refs.head.isFork,\n\t\t\t\t\t},\n\t\t\t\t\tbase: {\n\t\t\t\t\t\texists: value.refs.base.exists,\n\t\t\t\t\t\towner: value.refs.base.owner,\n\t\t\t\t\t\trepo: value.refs.base.repo,\n\t\t\t\t\t\tsha: value.refs.base.sha,\n\t\t\t\t\t\tbranch: value.refs.base.branch,\n\t\t\t\t\t\turl: value.refs.base.url,\n\t\t\t\t\t\tcloneHttps: value.refs.base.cloneHttps,\n\t\t\t\t\t\tcloneSsh: value.refs.base.cloneSsh,\n\t\t\t\t\t\tisFork: value.refs.base.isFork,\n\t\t\t\t\t},\n\t\t\t\t\tisCrossRepository: value.refs.isCrossRepository,\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tisDraft: value.isDraft,\n\t\tadditions: value.additions,\n\t\tdeletions: value.deletions,\n\t\tcommentsCount: value.commentsCount,\n\t\tthumbsUpCount: value.thumbsUpCount,\n\t\treviewDecision: value.reviewDecision,\n\t\treviewRequests: value.reviewRequests,\n\t\tlatestReviews: value.latestReviews,\n\t\tassignees: value.assignees,\n\t\tauthoredByMe: value.authoredByMe,\n\t\tviewer: value.viewer != null ? { id: value.viewer.id, username: value.viewer.username } : undefined,\n\t\tproject: value.project\n\t\t\t? {\n\t\t\t\t\tid: value.project.id,\n\t\t\t\t\tname: value.project.name,\n\t\t\t\t\tresourceId: value.project.resourceId,\n\t\t\t\t\tresourceName: value.project.resourceName,\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tstack: value.stack\n\t\t\t? {\n\t\t\t\t\tid: value.stack.id,\n\t\t\t\t\tnumber: value.stack.number,\n\t\t\t\t\tsize: value.stack.size,\n\t\t\t\t\tposition: value.stack.position,\n\t\t\t\t\tbaseRef: value.stack.baseRef,\n\t\t\t\t}\n\t\t\t: undefined,\n\t};\n\treturn serialized;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pullRequest.utils.js","names":[],"sources":["../../../../git/src/utils/pullRequest.utils.ts"],"sourcesContent":["import type {\n\tPullRequest,\n\tPullRequestComparisonRefs,\n\tPullRequestRefs,\n\tPullRequestRepositoryIdentityDescriptor,\n\tPullRequestShape,\n\tPullRequestSortField,\n\tPullRequestSorting,\n\tPullRequestStackInfo,\n} from '../models/pullRequest.js';\nimport { shortenRevision } from './revision.utils.js';\n\n/** How many pull requests a merge action affects — unstacked is always 1; a stacked merge lands either\n * just this layer and everything below it (`position`), or the whole stack (`wholeStack`). The one\n * source every merge-confirmation and merge-action label counts from, so they can't drift apart.\n * Takes only the two fields it needs (not the full {@link PullRequestStackInfo}) since callers on the\n * webview side carry narrower serialized stack shapes. */\nexport function getStackedMergeCount(\n\tstack: Pick<PullRequestStackInfo, 'position' | 'size'> | undefined,\n\toptions?: { wholeStack?: boolean },\n): number {\n\tif (stack == null) return 1;\n\treturn options?.wholeStack ? stack.size : stack.position;\n}\n\n/**\n * How each sort field is read off a {@link PullRequestShape}, for the filtered PR search, which MERGES its\n * relationship × state facets in the facade and so has to order the union itself instead of trusting the\n * per-facet server order. Only the fields the shape carries appear — the same rule as `getIssueComparator`, and\n * the reason {@link PullRequestSortField} is just these two.\n */\nconst pullRequestSortValues: Partial<\n\tRecord<PullRequestSortField, (pr: PullRequestShape) => number | Date | string | undefined>\n> = {\n\tcreated: pr => pr.createdDate,\n\tupdated: pr => pr.updatedDate,\n};\n\n/**\n * A comparator for one sort key over normalized pull requests, or `undefined` when the field isn't derivable\n * from a {@link PullRequestShape} — the signal that the key is only honorable on a SINGLE-origin read where the\n * provider already ordered the page. Missing values sort LAST in both directions (partitioned before any\n * arithmetic so two missing values compare equal, exactly as `getIssueComparator` does).\n *\n * Note it orders whatever it is handed. Sorting a page already capped at the result ceiling does not make it the\n * top N.\n */\nexport function getPullRequestComparator(\n\tsort: PullRequestSorting,\n): ((a: PullRequestShape, b: PullRequestShape) => number) | undefined {\n\tconst [field, direction] = sort.split(':') as [PullRequestSortField, 'asc' | 'desc'];\n\tconst getValue = pullRequestSortValues[field];\n\tif (getValue == null) return undefined;\n\n\treturn (a, b) => {\n\t\tconst left = toComparable(getValue(a));\n\t\tconst right = toComparable(getValue(b));\n\t\tif (left == null || right == null) {\n\t\t\tif (left == null && right == null) return 0;\n\n\t\t\treturn left == null ? 1 : -1;\n\t\t}\n\n\t\tconst ordered = left < right ? -1 : left > right ? 1 : 0;\n\t\treturn direction === 'asc' ? ordered : -ordered;\n\t};\n}\n\nfunction toComparable(value: number | Date | string | undefined): number | string | undefined {\n\treturn value instanceof Date ? value.getTime() : value;\n}\n\nexport interface PullRequestUrlIdentity<TProvider extends string = string> {\n\tprovider?: TProvider;\n\n\townerAndRepo?: string;\n\tprNumber: string;\n}\n\nexport function getComparisonRefsForPullRequest(repoPath: string, prRefs: PullRequestRefs): PullRequestComparisonRefs {\n\tconst refs: PullRequestComparisonRefs = {\n\t\trepoPath: repoPath,\n\t\tbase: { ref: prRefs.base.sha, label: `${prRefs.base.branch} (${shortenRevision(prRefs.base.sha)})` },\n\t\thead: { ref: prRefs.head.sha, label: prRefs.head.branch },\n\t};\n\treturn refs;\n}\n\nexport function getPullRequestIdentityFromMaybeUrl(search: string): PullRequestUrlIdentity | undefined {\n\tlet prNumber: string | undefined = undefined;\n\n\tlet match = search.match(/(?:\\/)(\\d+)/); // any number starting with \"/\"\n\tif (match != null) {\n\t\tprNumber = match[1];\n\t}\n\n\tif (prNumber == null) {\n\t\tmatch = search.match(/^#?(\\d+)$/); // just a number or with a leading \"#\"\n\t\tif (match != null) {\n\t\t\tprNumber = match[1];\n\t\t}\n\t}\n\n\treturn prNumber == null ? undefined : { ownerAndRepo: undefined, prNumber: prNumber, provider: undefined };\n}\n\n/** A pull request's display number from its url, or `undefined` for a url naming no pull request. Anchors\n * on the provider's pull request path segment (GitHub `pull`, Bitbucket `pull-requests`, GitLab\n * `merge_requests`, Azure `pullrequest`) so a digit-leading owner (`github.com/1Password/x/pull/123`)\n * can't win. */\nexport function getPullRequestNumberFromUrl(url: string): string | undefined {\n\t// No loose fallback: `getPullRequestIdentityFromMaybeUrl` scans for any `/<digits>`, which reads a bare\n\t// repository url like `github.com/1Password/sdk` as pull request #1. Callers that hold a real pull\n\t// request fall back to its id instead, and the one that asks whether a pasted url names a pull request\n\t// needs \"no\" for an answer.\n\treturn url.match(/(?:pull|pull-requests|merge_requests|pullrequest)\\/(\\d+)(?:\\b|\\/|$)/)?.[1];\n}\n\nexport function getRepositoryIdentityForPullRequest(\n\tpr: PullRequest,\n\theadRepo: boolean = true,\n): PullRequestRepositoryIdentityDescriptor {\n\tif (headRepo) {\n\t\treturn {\n\t\t\tremote: {\n\t\t\t\turl: pr.refs?.head?.url,\n\t\t\t\tdomain: pr.provider.domain,\n\t\t\t},\n\t\t\tname: `${pr.refs?.head?.owner ?? pr.repository.owner}/${pr.refs?.head?.repo ?? pr.repository.repo}`,\n\t\t\tprovider: {\n\t\t\t\tid: pr.provider.id,\n\t\t\t\tdomain: pr.provider.domain,\n\t\t\t\trepoDomain: pr.refs?.head?.owner ?? pr.repository.owner,\n\t\t\t\trepoName: pr.refs?.head?.repo ?? pr.repository.repo,\n\t\t\t},\n\t\t};\n\t}\n\n\treturn {\n\t\tremote: {\n\t\t\turl: pr.refs?.base?.url ?? pr.url,\n\t\t\tdomain: pr.provider.domain,\n\t\t},\n\t\tname: `${pr.refs?.base?.owner ?? pr.repository.owner}/${pr.refs?.base?.repo ?? pr.repository.repo}`,\n\t\tprovider: {\n\t\t\tid: pr.provider.id,\n\t\t\tdomain: pr.provider.domain,\n\t\t\trepoDomain: pr.refs?.base?.owner ?? pr.repository.owner,\n\t\t\trepoName: pr.refs?.base?.repo ?? pr.repository.repo,\n\t\t\trepoOwnerDomain: pr.refs?.base?.owner ?? pr.repository.owner,\n\t\t},\n\t};\n}\n\nexport function isMaybeNonSpecificPullRequestSearchUrl(search: string): boolean {\n\treturn getPullRequestIdentityFromMaybeUrl(search) != null;\n}\n\n/**\n * Deliberately leaves `projection` out: this copy drops `filesChanged`, `repository` and the class-only check rollup,\n * commit count and `viewerCanUpdate`, so a tag would have field presence report as fetched what the copy no longer has.\n */\nexport function serializePullRequest(value: PullRequest): PullRequestShape {\n\tconst serialized: PullRequestShape = {\n\t\ttype: value.type,\n\t\tprovider: {\n\t\t\tid: value.provider.id,\n\t\t\tname: value.provider.name,\n\t\t\tdomain: value.provider.domain,\n\t\t\ticon: value.provider.icon,\n\t\t},\n\t\tid: value.id,\n\t\tnodeId: value.nodeId,\n\t\tnumber: value.number,\n\t\ttitle: value.title,\n\t\tbody: value.body,\n\t\turl: value.url,\n\t\tcreatedDate: value.createdDate,\n\t\tupdatedDate: value.updatedDate,\n\t\tclosedDate: value.closedDate,\n\t\tclosed: value.closed,\n\t\tauthor: {\n\t\t\tid: value.author.id,\n\t\t\tname: value.author.name,\n\t\t\tusername: value.author.username,\n\t\t\tavatarUrl: value.author.avatarUrl,\n\t\t\turl: value.author.url,\n\t\t},\n\t\tstate: value.state,\n\t\tmergedDate: value.mergedDate,\n\t\tmergeableState: value.mergeableState,\n\t\trefs: value.refs\n\t\t\t? {\n\t\t\t\t\thead: {\n\t\t\t\t\t\texists: value.refs.head.exists,\n\t\t\t\t\t\towner: value.refs.head.owner,\n\t\t\t\t\t\trepo: value.refs.head.repo,\n\t\t\t\t\t\tsha: value.refs.head.sha,\n\t\t\t\t\t\tbranch: value.refs.head.branch,\n\t\t\t\t\t\turl: value.refs.head.url,\n\t\t\t\t\t\tcloneHttps: value.refs.head.cloneHttps,\n\t\t\t\t\t\tcloneSsh: value.refs.head.cloneSsh,\n\t\t\t\t\t\tisFork: value.refs.head.isFork,\n\t\t\t\t\t},\n\t\t\t\t\tbase: {\n\t\t\t\t\t\texists: value.refs.base.exists,\n\t\t\t\t\t\towner: value.refs.base.owner,\n\t\t\t\t\t\trepo: value.refs.base.repo,\n\t\t\t\t\t\tsha: value.refs.base.sha,\n\t\t\t\t\t\tbranch: value.refs.base.branch,\n\t\t\t\t\t\turl: value.refs.base.url,\n\t\t\t\t\t\tcloneHttps: value.refs.base.cloneHttps,\n\t\t\t\t\t\tcloneSsh: value.refs.base.cloneSsh,\n\t\t\t\t\t\tisFork: value.refs.base.isFork,\n\t\t\t\t\t},\n\t\t\t\t\tisCrossRepository: value.refs.isCrossRepository,\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tisDraft: value.isDraft,\n\t\tadditions: value.additions,\n\t\tdeletions: value.deletions,\n\t\tcommentsCount: value.commentsCount,\n\t\tthumbsUpCount: value.thumbsUpCount,\n\t\treviewDecision: value.reviewDecision,\n\t\treviewRequests: value.reviewRequests,\n\t\tlatestReviews: value.latestReviews,\n\t\tassignees: value.assignees,\n\t\tauthoredByMe: value.authoredByMe,\n\t\tviewer: value.viewer != null ? { id: value.viewer.id, username: value.viewer.username } : undefined,\n\t\tviewerUnresolved: value.viewerUnresolved,\n\t\tproject: value.project\n\t\t\t? {\n\t\t\t\t\tid: value.project.id,\n\t\t\t\t\tname: value.project.name,\n\t\t\t\t\tresourceId: value.project.resourceId,\n\t\t\t\t\tresourceName: value.project.resourceName,\n\t\t\t\t}\n\t\t\t: undefined,\n\t\tstack: value.stack\n\t\t\t? {\n\t\t\t\t\tid: value.stack.id,\n\t\t\t\t\tnumber: value.stack.number,\n\t\t\t\t\tsize: value.stack.size,\n\t\t\t\t\tposition: value.stack.position,\n\t\t\t\t\tbaseRef: value.stack.baseRef,\n\t\t\t\t}\n\t\t\t: undefined,\n\t};\n\treturn serialized;\n}\n"],"mappings":"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"}
|
|
@@ -313,7 +313,7 @@ export declare abstract class GitHostIntegration<ID extends IntegrationIds = Int
|
|
|
313
313
|
/** Each row's viewer, in order, where the provider sets one (see {@link getIssueViewers}). */
|
|
314
314
|
viewers?: ({
|
|
315
315
|
id: string;
|
|
316
|
-
} | undefined)[];
|
|
316
|
+
} | null | undefined)[];
|
|
317
317
|
}) | undefined>>;
|
|
318
318
|
/**
|
|
319
319
|
* Repo-scoped "my issues" read returning the normalized {@link IssueShape} the ProviderBackend facade
|
|
@@ -383,23 +383,24 @@ export declare abstract class GitHostIntegration<ID extends IntegrationIds = Int
|
|
|
383
383
|
/**
|
|
384
384
|
* The current account as each of `pullRequests` identifies its members, in order: what a raw row's
|
|
385
385
|
* `authoredByMe` and `viewer` are resolved against when it's mapped. Most hosts give a person one id, so every
|
|
386
|
-
* row gets the account itself; Azure DevOps answers per organization (see `AzureDevOpsIntegrationBase`)
|
|
386
|
+
* row gets the account itself; Azure DevOps answers per organization (see `AzureDevOpsIntegrationBase`), with
|
|
387
|
+
* `null` for a row whose organization's identity couldn't be read, which marks it `viewerUnresolved`.
|
|
387
388
|
* Throws only when the account itself can't be read. Azure DevOps never throws: a session it can't resolve leaves
|
|
388
|
-
*
|
|
389
|
+
* every row it would have asked an organization for `null` too.
|
|
389
390
|
*/
|
|
390
391
|
getPullRequestViewers(pullRequests: readonly (ProviderPullRequest | PullRequest)[], connectionId?: string): Promise<({
|
|
391
392
|
id: string;
|
|
392
393
|
username?: string;
|
|
393
|
-
} | undefined)[]>;
|
|
394
|
+
} | null | undefined)[]>;
|
|
394
395
|
/**
|
|
395
396
|
* The current account as each of `issues`, read with `session`, identifies its members, in order, where that can
|
|
396
397
|
* differ from the account itself: what a raw row's {@link IssueShape.viewer} is set to when it's mapped. Only
|
|
397
398
|
* Azure DevOps sets one, per organization (see `AzureDevOpsIntegrationBase`); `undefined` leaves every row without.
|
|
398
|
-
* Never throws: a viewer that can't be resolved
|
|
399
|
+
* Never throws: a viewer that can't be resolved is `null`, which marks the row {@link IssueShape.viewerUnresolved}.
|
|
399
400
|
*/
|
|
400
401
|
protected getIssueViewers(_session: ProviderAuthenticationSession, _issues: readonly ProviderIssue[]): Promise<({
|
|
401
402
|
id: string;
|
|
402
|
-
} | undefined)[] | undefined>;
|
|
403
|
+
} | null | undefined)[] | undefined>;
|
|
403
404
|
/**
|
|
404
405
|
* Parses a Repo/Project paging cursor into its `cursors` bundle. Guards against valid JSON whose
|
|
405
406
|
* `cursors` is a truthy non-array (e.g. `{ "cursors": "..." }`), which would otherwise bypass the
|
|
@@ -1194,9 +1194,10 @@ var GitHostIntegration = class extends IntegrationBase {
|
|
|
1194
1194
|
/**
|
|
1195
1195
|
* The current account as each of `pullRequests` identifies its members, in order: what a raw row's
|
|
1196
1196
|
* `authoredByMe` and `viewer` are resolved against when it's mapped. Most hosts give a person one id, so every
|
|
1197
|
-
* row gets the account itself; Azure DevOps answers per organization (see `AzureDevOpsIntegrationBase`)
|
|
1197
|
+
* row gets the account itself; Azure DevOps answers per organization (see `AzureDevOpsIntegrationBase`), with
|
|
1198
|
+
* `null` for a row whose organization's identity couldn't be read, which marks it `viewerUnresolved`.
|
|
1198
1199
|
* Throws only when the account itself can't be read. Azure DevOps never throws: a session it can't resolve leaves
|
|
1199
|
-
*
|
|
1200
|
+
* every row it would have asked an organization for `null` too.
|
|
1200
1201
|
*/
|
|
1201
1202
|
async getPullRequestViewers(pullRequests, connectionId) {
|
|
1202
1203
|
const account = await this.getCurrentAccount({ connectionId });
|
|
@@ -1210,7 +1211,7 @@ var GitHostIntegration = class extends IntegrationBase {
|
|
|
1210
1211
|
* The current account as each of `issues`, read with `session`, identifies its members, in order, where that can
|
|
1211
1212
|
* differ from the account itself: what a raw row's {@link IssueShape.viewer} is set to when it's mapped. Only
|
|
1212
1213
|
* Azure DevOps sets one, per organization (see `AzureDevOpsIntegrationBase`); `undefined` leaves every row without.
|
|
1213
|
-
* Never throws: a viewer that can't be resolved
|
|
1214
|
+
* Never throws: a viewer that can't be resolved is `null`, which marks the row {@link IssueShape.viewerUnresolved}.
|
|
1214
1215
|
*/
|
|
1215
1216
|
getIssueViewers(_session, _issues) {
|
|
1216
1217
|
return Promise.resolve(void 0);
|