@gitkraken/core-gitlens 0.9.3 → 0.9.5
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 +34 -1
- package/dist/git/models/issue.d.ts +25 -2
- package/dist/git/models/issue.js +3 -1
- package/dist/git/models/issue.js.map +1 -1
- package/dist/git/models/pullRequest.d.ts +55 -5
- package/dist/git/models/pullRequest.js +5 -1
- package/dist/git/models/pullRequest.js.map +1 -1
- package/dist/git/utils/issue.utils.d.ts +4 -0
- package/dist/git/utils/issue.utils.js +4 -0
- package/dist/git/utils/issue.utils.js.map +1 -1
- package/dist/git/utils/pullRequest.utils.d.ts +4 -0
- package/dist/git/utils/pullRequest.utils.js +8 -0
- package/dist/git/utils/pullRequest.utils.js.map +1 -1
- package/dist/plus/git-github/api/github.d.ts +64 -4
- package/dist/plus/git-github/api/github.js +232 -15
- package/dist/plus/git-github/api/github.js.map +1 -1
- package/dist/plus/git-github/models.d.ts +48 -6
- package/dist/plus/git-github/models.js +11 -10
- package/dist/plus/git-github/models.js.map +1 -1
- package/dist/plus/integrations/fieldPresence.d.ts +75 -0
- package/dist/plus/integrations/fieldPresence.js +381 -0
- package/dist/plus/integrations/fieldPresence.js.map +1 -0
- package/dist/plus/integrations/index.d.ts +6 -4
- package/dist/plus/integrations/index.js +2 -1
- package/dist/plus/integrations/index.js.map +1 -1
- package/dist/plus/integrations/integrationService.d.ts +13 -4
- package/dist/plus/integrations/integrationService.js.map +1 -1
- package/dist/plus/integrations/manager.d.ts +62 -7
- package/dist/plus/integrations/models/gitHostIntegration.d.ts +103 -9
- package/dist/plus/integrations/models/gitHostIntegration.js +116 -5
- package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
- package/dist/plus/integrations/models/integration.d.ts +91 -4
- package/dist/plus/integrations/models/integration.js +56 -7
- package/dist/plus/integrations/models/integration.js.map +1 -1
- package/dist/plus/integrations/models/issueReads.d.ts +14 -0
- package/dist/plus/integrations/models/issuesIntegration.d.ts +44 -3
- package/dist/plus/integrations/models/issuesIntegration.js +51 -1
- package/dist/plus/integrations/models/issuesIntegration.js.map +1 -1
- package/dist/plus/integrations/providers/azure/azure.js +3 -3
- package/dist/plus/integrations/providers/azure/azure.js.map +1 -1
- package/dist/plus/integrations/providers/azure/models.d.ts +36 -4
- package/dist/plus/integrations/providers/azure/models.js +118 -8
- package/dist/plus/integrations/providers/azure/models.js.map +1 -1
- package/dist/plus/integrations/providers/azureDevOps.d.ts +102 -5
- package/dist/plus/integrations/providers/azureDevOps.js +264 -45
- package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
- package/dist/plus/integrations/providers/azureDevOpsServer.d.ts +30 -6
- package/dist/plus/integrations/providers/azureDevOpsServer.js +82 -21
- package/dist/plus/integrations/providers/azureDevOpsServer.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket/bitbucket.d.ts +21 -1
- package/dist/plus/integrations/providers/bitbucket/bitbucket.js +74 -10
- package/dist/plus/integrations/providers/bitbucket/bitbucket.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket/models.d.ts +45 -8
- package/dist/plus/integrations/providers/bitbucket/models.js +32 -9
- package/dist/plus/integrations/providers/bitbucket/models.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket-server/models.d.ts +2 -6
- package/dist/plus/integrations/providers/bitbucket-server/models.js +1 -3
- package/dist/plus/integrations/providers/bitbucket-server/models.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.d.ts +3 -1
- package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js +4 -1
- package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket-server.d.ts +2 -2
- package/dist/plus/integrations/providers/bitbucket-server.js +7 -5
- package/dist/plus/integrations/providers/bitbucket-server.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket.d.ts +22 -2
- package/dist/plus/integrations/providers/bitbucket.js +29 -6
- package/dist/plus/integrations/providers/bitbucket.js.map +1 -1
- package/dist/plus/integrations/providers/github.d.ts +40 -3
- package/dist/plus/integrations/providers/github.js +133 -11
- package/dist/plus/integrations/providers/github.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab/gitlab.d.ts +34 -1
- package/dist/plus/integrations/providers/gitlab/gitlab.js +118 -4
- package/dist/plus/integrations/providers/gitlab/gitlab.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab/models.d.ts +70 -5
- package/dist/plus/integrations/providers/gitlab/models.js +106 -13
- package/dist/plus/integrations/providers/gitlab/models.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab.d.ts +31 -2
- package/dist/plus/integrations/providers/gitlab.js +48 -8
- package/dist/plus/integrations/providers/gitlab.js.map +1 -1
- package/dist/plus/integrations/providers/jira-server.d.ts +3 -2
- package/dist/plus/integrations/providers/jira-server.js +18 -9
- package/dist/plus/integrations/providers/jira-server.js.map +1 -1
- package/dist/plus/integrations/providers/jira.d.ts +26 -2
- package/dist/plus/integrations/providers/jira.js +120 -9
- package/dist/plus/integrations/providers/jira.js.map +1 -1
- package/dist/plus/integrations/providers/jiraIssueByKey.d.ts +79 -0
- package/dist/plus/integrations/providers/jiraIssueByKey.js +58 -7
- package/dist/plus/integrations/providers/jiraIssueByKey.js.map +1 -1
- package/dist/plus/integrations/providers/linear.d.ts +19 -1
- package/dist/plus/integrations/providers/linear.js +105 -7
- package/dist/plus/integrations/providers/linear.js.map +1 -1
- package/dist/plus/integrations/providers/linearIssuesEtag.d.ts +42 -0
- package/dist/plus/integrations/providers/linearIssuesEtag.js +94 -0
- package/dist/plus/integrations/providers/linearIssuesEtag.js.map +1 -0
- package/dist/plus/integrations/providers/models.d.ts +70 -8
- package/dist/plus/integrations/providers/models.js +59 -21
- package/dist/plus/integrations/providers/models.js.map +1 -1
- package/dist/plus/integrations/providers/providerErrors.js +8 -1
- package/dist/plus/integrations/providers/providerErrors.js.map +1 -1
- package/dist/plus/integrations/providers/providersApi.d.ts +70 -4
- package/dist/plus/integrations/providers/providersApi.js +148 -4
- package/dist/plus/integrations/providers/providersApi.js.map +1 -1
- package/dist/plus/integrations/providers/pullRequestReviews.d.ts +13 -0
- package/dist/plus/integrations/providers/pullRequestReviews.js +30 -6
- package/dist/plus/integrations/providers/pullRequestReviews.js.map +1 -1
- package/dist/plus/integrations/providers/trello.js +11 -7
- package/dist/plus/integrations/providers/trello.js.map +1 -1
- package/dist/plus/integrations/providers/utils/providerPaging.d.ts +11 -0
- package/dist/plus/integrations/providers/utils/providerPaging.js +47 -1
- package/dist/plus/integrations/providers/utils/providerPaging.js.map +1 -1
- package/dist/plus/integrations/providers/utils.d.ts +1 -1
- package/dist/plus/integrations/reads/batchEtags.d.ts +69 -0
- package/dist/plus/integrations/reads/batchEtags.js +114 -0
- package/dist/plus/integrations/reads/batchEtags.js.map +1 -0
- package/dist/plus/integrations/reads/counts.js +2 -2
- package/dist/plus/integrations/reads/counts.js.map +1 -1
- package/dist/plus/integrations/reads/currentAccount.js +2 -2
- package/dist/plus/integrations/reads/currentAccount.js.map +1 -1
- package/dist/plus/integrations/reads/cursors.d.ts +8 -0
- package/dist/plus/integrations/reads/cursors.js +5 -3
- package/dist/plus/integrations/reads/cursors.js.map +1 -1
- package/dist/plus/integrations/reads/drains.d.ts +13 -4
- package/dist/plus/integrations/reads/drains.js +29 -5
- package/dist/plus/integrations/reads/drains.js.map +1 -1
- package/dist/plus/integrations/reads/etag.d.ts +26 -0
- package/dist/plus/integrations/reads/etag.js +108 -0
- package/dist/plus/integrations/reads/etag.js.map +1 -0
- package/dist/plus/integrations/reads/filters.d.ts +8 -0
- package/dist/plus/integrations/reads/filters.js +2 -1
- package/dist/plus/integrations/reads/filters.js.map +1 -1
- package/dist/plus/integrations/reads/hierarchy.js +3 -3
- package/dist/plus/integrations/reads/hierarchy.js.map +1 -1
- package/dist/plus/integrations/reads/issueBatch.d.ts +47 -16
- package/dist/plus/integrations/reads/issueBatch.js +55 -87
- package/dist/plus/integrations/reads/issueBatch.js.map +1 -1
- package/dist/plus/integrations/reads/issueTracker.d.ts +10 -2
- package/dist/plus/integrations/reads/issueTracker.js +23 -6
- package/dist/plus/integrations/reads/issueTracker.js.map +1 -1
- package/dist/plus/integrations/reads/issues.d.ts +1 -1
- package/dist/plus/integrations/reads/issues.js +4 -4
- package/dist/plus/integrations/reads/issues.js.map +1 -1
- package/dist/plus/integrations/reads/pullRequestBatch.d.ts +44 -6
- package/dist/plus/integrations/reads/pullRequestBatch.js +31 -34
- package/dist/plus/integrations/reads/pullRequestBatch.js.map +1 -1
- package/dist/plus/integrations/reads/pullRequestBranches.d.ts +5 -2
- package/dist/plus/integrations/reads/pullRequestBranches.js +4 -3
- package/dist/plus/integrations/reads/pullRequestBranches.js.map +1 -1
- package/dist/plus/integrations/reads/pullRequests.js +8 -4
- package/dist/plus/integrations/reads/pullRequests.js.map +1 -1
- package/dist/plus/integrations/reads/sweeps.js +8 -4
- package/dist/plus/integrations/reads/sweeps.js.map +1 -1
- package/dist/plus/integrations/reads/warnings.d.ts +23 -8
- package/dist/plus/integrations/reads/warnings.js +43 -19
- package/dist/plus/integrations/reads/warnings.js.map +1 -1
- package/dist/plus/integrations/results.d.ts +12 -4
- package/dist/plus/integrations/results.js +2 -0
- package/dist/plus/integrations/results.js.map +1 -1
- package/docs/integrations.md +389 -23
- package/docs/kepler-read-api-parity.md +16 -2
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"models.js","names":[],"sources":["../../../../../../plus/integrations/src/providers/bitbucket/models.ts"],"sourcesContent":["import type { IssueRepository } from '@gitlens/git/models/issue.js';\nimport { Issue, RepositoryAccessLevel } from '@gitlens/git/models/issue.js';\nimport type { IssueOrPullRequestState } from '@gitlens/git/models/issueOrPullRequest.js';\nimport type { PullRequestMember, PullRequestReviewer } from '@gitlens/git/models/pullRequest.js';\nimport {\n\tPullRequest,\n\tPullRequestMergeableState,\n\tPullRequestReviewDecision,\n\tPullRequestReviewState,\n} from '@gitlens/git/models/pullRequest.js';\nimport type { Provider } from '@gitlens/git/models/remoteProvider.js';\nimport type { ResourceDescriptor } from '@gitlens/git/models/resourceDescriptor.js';\n\nexport interface BitbucketRepositoryDescriptor extends ResourceDescriptor {\n\towner: string;\n\tname: string;\n}\n\nexport interface BitbucketWorkspaceDescriptor extends ResourceDescriptor {\n\tid: string;\n\tname: string;\n\tslug: string;\n}\n\nexport type BitbucketPullRequestState = 'OPEN' | 'DECLINED' | 'MERGED' | 'SUPERSEDED';\n\ninterface BitbucketLink {\n\thref: string;\n\tname?: string;\n}\n\ninterface BitbucketUser {\n\ttype: 'user';\n\tuuid: string;\n\tdisplay_name: string;\n\taccount_id?: string;\n\tnickname?: string;\n\tlinks: {\n\t\tself: BitbucketLink;\n\t\tavatar: BitbucketLink;\n\t\thtml: BitbucketLink;\n\t};\n}\n\ninterface BitbucketWorkspace {\n\ttype: 'workspace';\n\tuuid: string;\n\tname: string;\n\tslug: string;\n\tlinks: {\n\t\tself: BitbucketLink;\n\t\thtml: BitbucketLink;\n\t\tavatar: BitbucketLink;\n\t};\n}\n\ninterface BitbucketProject {\n\ttype: 'project';\n\tkey: string;\n\tuuid: string;\n\tname: string;\n\tlinks: {\n\t\tself: BitbucketLink;\n\t\thtml: BitbucketLink;\n\t\tavatar: BitbucketLink;\n\t};\n}\n\ninterface BitbucketPullRequestParticipant {\n\ttype: 'participant';\n\tuser: BitbucketUser;\n\trole: 'PARTICIPANT' | 'REVIEWER';\n\tapproved: boolean;\n\tstate: null | 'approved' | 'changes_requested';\n\tparticipated_on: null | string;\n}\n\nexport interface BitbucketRepository {\n\ttype: 'repository';\n\tuuid: string;\n\tfull_name: string;\n\tname: string;\n\tslug: string;\n\tdescription?: string;\n\tis_private: boolean;\n\tparent: null | BitbucketRepository;\n\tscm: 'git';\n\towner: BitbucketUser;\n\tworkspace: BitbucketWorkspace;\n\tproject: BitbucketProject;\n\tcreated_on: string;\n\tupdated_on: string;\n\tsize: number;\n\tlanguage: string;\n\thas_issues: boolean;\n\thas_wiki: boolean;\n\tfork_policy: 'allow_forks' | 'no_public_forks' | 'no_forks';\n\twebsite: string;\n\tmainbranch?: BitbucketBranch;\n\tlinks: {\n\t\tself: BitbucketLink;\n\t\thtml: BitbucketLink;\n\t\tavatar: BitbucketLink;\n\t};\n}\n\ninterface BitbucketCommitAuthor {\n\ttype: 'author';\n\traw: string;\n\tuser: BitbucketUser;\n}\n\ntype BitbucketMergeStrategy =\n\t| 'merge_commit'\n\t| 'squash'\n\t| 'fast_forward'\n\t| 'squash_fast_forward'\n\t| 'rebase_fast_forward'\n\t| 'rebase_merge';\n\ninterface BitbucketBranch {\n\tname: string;\n\tmerge_strategies?: BitbucketMergeStrategy[];\n\tdefault_merge_strategy?: BitbucketMergeStrategy;\n}\n\n// It parses a raw author sitring like \"Sergei Shmakov GK <sergei.shmakov@gitkraken.com>\" to name and email\nconst parseRawBitbucketAuthorRegex = /^(.*) <(.*)>$/;\nexport function parseRawBitbucketAuthor(raw: string): { name: string; email: string } {\n\tconst match = raw.match(parseRawBitbucketAuthorRegex);\n\tif (match) {\n\t\treturn { name: match[1], email: match[2] };\n\t}\n\treturn { name: raw, email: '' };\n}\n\nexport interface BitbucketCommit extends BitbucketBriefCommit {\n\tauthor: BitbucketCommitAuthor;\n\tdate: string;\n\tlinks: {\n\t\tapprove: BitbucketLink;\n\t\tcomments: BitbucketLink;\n\t\tdiff: BitbucketLink;\n\t\thtml: BitbucketLink;\n\t\tself: BitbucketLink;\n\t\tstatuses: BitbucketLink;\n\t};\n\tmessage: string;\n\tparents: BitbucketBriefCommit[];\n\tparticipants: BitbucketPullRequestParticipant[];\n\trendered: {\n\t\tmessage: string;\n\t};\n\trepository: BitbucketRepository;\n\tsummary: {\n\t\ttype: 'rendered';\n\t\traw: string;\n\t\tmarkup: string;\n\t\thtml: string;\n\t};\n}\n\ninterface BitbucketBriefCommit {\n\ttype: 'commit';\n\thash: string;\n\tlinks: {\n\t\tself: BitbucketLink;\n\t\thtml: BitbucketLink;\n\t};\n}\n\nexport type BitbucketIssueState =\n\t| 'submitted'\n\t| 'new'\n\t| 'open'\n\t| 'resolved'\n\t| 'on hold'\n\t| 'invalid'\n\t| 'duplicate'\n\t| 'wontfix'\n\t| 'closed';\n\nexport interface BitbucketPullRequest {\n\ttype: 'pullrequest';\n\tid: number;\n\ttitle: string;\n\tdescription: string;\n\tstate: BitbucketPullRequestState;\n\tmerge_commit: null | BitbucketBriefCommit;\n\tcomment_count: number;\n\ttask_count: number;\n\tclose_source_branch: boolean;\n\tclosed_by: BitbucketUser | null;\n\tauthor: BitbucketUser;\n\treason: string;\n\tcreated_on: string;\n\tupdated_on: string;\n\tdestination: {\n\t\tbranch: BitbucketBranch;\n\t\tcommit: BitbucketBriefCommit;\n\t\trepository: BitbucketRepository;\n\t};\n\tsource: {\n\t\tbranch: BitbucketBranch;\n\t\tcommit: BitbucketBriefCommit;\n\t\trepository: BitbucketRepository;\n\t};\n\tsummary: {\n\t\ttype: 'rendered';\n\t\traw: string;\n\t\tmarkup: string;\n\t\thtml: string;\n\t};\n\treviewers?: BitbucketUser[];\n\tparticipants?: BitbucketPullRequestParticipant[];\n\tlinks: {\n\t\tself: BitbucketLink;\n\t\thtml: BitbucketLink;\n\t\tcommits: BitbucketLink;\n\t\tapprove: BitbucketLink;\n\t\t'request-changes': BitbucketLink;\n\t\tdiff: BitbucketLink;\n\t\tdiffstat: BitbucketLink;\n\t\tcomments: BitbucketLink;\n\t\tactivity: BitbucketLink;\n\t\tmerge: BitbucketLink;\n\t\tdecline: BitbucketLink;\n\t\tstatuses: BitbucketLink;\n\t};\n}\n\nexport interface BitbucketIssue {\n\ttype: string;\n\tid: number;\n\ttitle: string;\n\treporter: BitbucketUser;\n\tassignee?: BitbucketUser;\n\tstate: BitbucketIssueState;\n\tcreated_on: string;\n\tupdated_on: string;\n\trepository: BitbucketRepository;\n\tvotes?: number;\n\tcontent: {\n\t\traw: string;\n\t\tmarkup: string;\n\t\thtml: string;\n\t};\n\tlinks: {\n\t\tself: BitbucketLink;\n\t\thtml: BitbucketLink;\n\t\tcomments: BitbucketLink;\n\t\tattachments: BitbucketLink;\n\t\twatch: BitbucketLink;\n\t\tvote: BitbucketLink;\n\t};\n}\n\nexport function bitbucketPullRequestStateToState(state: BitbucketPullRequestState): IssueOrPullRequestState {\n\tswitch (state) {\n\t\tcase 'DECLINED':\n\t\tcase 'SUPERSEDED':\n\t\t\treturn 'closed';\n\t\tcase 'MERGED':\n\t\t\treturn 'merged';\n\t\tcase 'OPEN':\n\t\tdefault:\n\t\t\treturn 'opened';\n\t}\n}\n\nexport function bitbucketIssueStateToState(state: BitbucketIssueState): IssueOrPullRequestState {\n\tswitch (state) {\n\t\tcase 'resolved':\n\t\tcase 'invalid':\n\t\tcase 'duplicate':\n\t\tcase 'wontfix':\n\t\tcase 'closed':\n\t\t\treturn 'closed';\n\t\tcase 'submitted':\n\t\tcase 'new':\n\t\tcase 'open':\n\t\tcase 'on hold':\n\t\tdefault:\n\t\t\treturn 'opened';\n\t}\n}\n\nexport function isClosedBitbucketPullRequestState(state: BitbucketPullRequestState): boolean {\n\treturn bitbucketPullRequestStateToState(state) !== 'opened';\n}\n\nexport function isClosedBitbucketIssueState(state: BitbucketIssueState): boolean {\n\treturn bitbucketIssueStateToState(state) !== 'opened';\n}\n\nexport function fromBitbucketUser(user: BitbucketUser): PullRequestMember {\n\treturn {\n\t\tavatarUrl: user.links.avatar.href,\n\t\tname: user.display_name,\n\t\tusername: user.nickname,\n\t\turl: user.links.html.href,\n\t\tid: user.uuid,\n\t};\n}\n\nexport function fromBitbucketParticipantToReviewer(\n\tprt: BitbucketPullRequestParticipant,\n\tclosedBy: BitbucketUser | null,\n\tprState: BitbucketPullRequestState,\n): PullRequestReviewer {\n\treturn {\n\t\treviewer: fromBitbucketUser(prt.user),\n\t\tstate: prt.approved\n\t\t\t? PullRequestReviewState.Approved\n\t\t\t: prt.state === 'changes_requested'\n\t\t\t\t? PullRequestReviewState.ChangesRequested\n\t\t\t\t: prt.participated_on != null\n\t\t\t\t\t? PullRequestReviewState.Commented\n\t\t\t\t\t: prt.user.uuid === closedBy?.uuid && prState === 'DECLINED'\n\t\t\t\t\t\t? PullRequestReviewState.Dismissed\n\t\t\t\t\t\t: PullRequestReviewState.ReviewRequested,\n\t};\n}\n\nfunction getBitbucketReviewDecision(pr: BitbucketPullRequest): PullRequestReviewDecision | undefined {\n\tif (!pr.participants?.length && pr.reviewers?.length) {\n\t\treturn PullRequestReviewDecision.ReviewRequired;\n\t}\n\tif (!pr.participants) {\n\t\treturn undefined;\n\t}\n\n\tlet hasReviews = false;\n\tlet hasChangeRequests = false;\n\tlet hasApprovals = false;\n\tfor (const prt of pr.participants) {\n\t\tif (prt.participated_on != null) {\n\t\t\thasReviews = true;\n\t\t}\n\t\tif (prt.approved) {\n\t\t\thasApprovals = true;\n\t\t}\n\t\tif (prt.state === 'changes_requested') {\n\t\t\thasChangeRequests = true;\n\t\t}\n\t}\n\tif (hasChangeRequests) return PullRequestReviewDecision.ChangesRequested;\n\tif (hasApprovals) return PullRequestReviewDecision.Approved;\n\tif (hasReviews) return undefined; // not approved, not rejected, but reviewed\n\treturn PullRequestReviewDecision.ReviewRequired; // nobody has reviewed yet.\n}\n\nfunction fromBitbucketRepository(repo: BitbucketRepository): IssueRepository {\n\treturn {\n\t\towner: repo.full_name.split('/')[0],\n\t\trepo: repo.name,\n\t\tid: repo.uuid,\n\t\t// TODO: Remove this assumption once actual access level is available\n\t\taccessLevel: RepositoryAccessLevel.Write,\n\t};\n}\n\nexport function fromBitbucketIssue(issue: BitbucketIssue, provider: Provider): Issue {\n\treturn new Issue(\n\t\tprovider,\n\t\tissue.id.toString(),\n\t\tissue.id.toString(),\n\t\tissue.title,\n\t\tissue.links.html.href,\n\t\tnew Date(issue.created_on),\n\t\tnew Date(issue.updated_on),\n\t\tisClosedBitbucketIssueState(issue.state),\n\t\tbitbucketIssueStateToState(issue.state),\n\t\tfromBitbucketUser(issue.reporter),\n\t\tissue.assignee ? [fromBitbucketUser(issue.assignee)] : [],\n\t\tfromBitbucketRepository(issue.repository),\n\t\tundefined, // closedDate\n\t\tundefined, // labels\n\t\tundefined, // commentsCount\n\t\tissue.votes, // thumbsUpCount\n\t\tissue.content.html, // body\n\t\t!issue.repository?.project\n\t\t\t? undefined\n\t\t\t: {\n\t\t\t\t\tid: issue.repository.project.uuid,\n\t\t\t\t\tname: issue.repository.project.name,\n\t\t\t\t\tresourceId: issue.repository.project.uuid,\n\t\t\t\t\tresourceName: issue.repository.project.name,\n\t\t\t\t},\n\t);\n}\n\nexport function fromBitbucketPullRequest(\n\tpr: BitbucketPullRequest,\n\tprovider: Provider,\n\toptions?: { currentAccount?: { id: string; username?: string } },\n): PullRequest {\n\tconst author = fromBitbucketUser(pr.author);\n\treturn new PullRequest(\n\t\tprovider,\n\t\tauthor,\n\t\tpr.id.toString(),\n\t\tpr.id.toString(),\n\t\tpr.title,\n\t\tpr.links.html.href,\n\t\tfromBitbucketRepository(pr.destination.repository),\n\t\tbitbucketPullRequestStateToState(pr.state),\n\t\tnew Date(pr.created_on),\n\t\tnew Date(pr.updated_on),\n\t\tpr.closed_by ? new Date(pr.updated_on) : undefined,\n\t\tpr.state === 'MERGED' ? new Date(pr.updated_on) : undefined,\n\t\t// TODO: Remove this assumption once actual mergeable state is available\n\t\tPullRequestMergeableState.Mergeable, // mergeableState\n\t\tundefined, // viewerCanUpdate\n\t\t{\n\t\t\tbase: {\n\t\t\t\tbranch: pr.destination.branch.name,\n\t\t\t\tsha: pr.destination.commit.hash,\n\t\t\t\trepo: pr.destination.repository.name,\n\t\t\t\towner: pr.destination.repository.full_name.split('/')[0],\n\t\t\t\texists: true,\n\t\t\t\turl: pr.destination.repository.links.html.href,\n\t\t\t},\n\t\t\thead: {\n\t\t\t\tbranch: pr.source.branch.name,\n\t\t\t\tsha: pr.source.commit.hash,\n\t\t\t\trepo: pr.source.repository.name,\n\t\t\t\towner: pr.source.repository.full_name.split('/')[0],\n\t\t\t\texists: true,\n\t\t\t\turl: pr.source.repository.links.html.href,\n\t\t\t},\n\t\t\tisCrossRepository: pr.source.repository.uuid !== pr.destination.repository.uuid,\n\t\t},\n\t\tundefined, // isDraft\n\t\tundefined, // additions\n\t\tundefined, // deletions\n\t\tundefined, // commentsCount\n\t\tundefined, // thumbsCount\n\t\tgetBitbucketReviewDecision(pr),\n\t\tpr.participants // reviewRequests:PullRequestReviewer[]\n\t\t\t?.filter(prt => prt.role === 'REVIEWER')\n\t\t\t.map(prt => fromBitbucketParticipantToReviewer(prt, pr.closed_by, pr.state))\n\t\t\t.filter(rv => rv.state === PullRequestReviewState.ReviewRequested),\n\t\tpr.participants // latestReviews:PullRequestReviewer[]\n\t\t\t?.filter(prt => prt.participated_on != null)\n\t\t\t.map(prt => fromBitbucketParticipantToReviewer(prt, pr.closed_by, pr.state)),\n\t\tundefined, // assignees:PullRequestMember[] -- it looks like there is no such thing as assignees on Bitbucket\n\t\tundefined, // PullRequestStatusCheckRollupState\n\t\tundefined, // IssueProject\n\t\tundefined, // version\n\t\tundefined, // commitCount\n\t\tundefined, // stack\n\t\tundefined, // filesChanged\n\t\tpr.description ?? undefined,\n\t\tpr.id,\n\t\toptions?.currentAccount != null ? author.id === options.currentAccount.id : undefined,\n\t);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"models.js","names":[],"sources":["../../../../../../plus/integrations/src/providers/bitbucket/models.ts"],"sourcesContent":["import type { IssueProjection, IssueRepository } from '@gitlens/git/models/issue.js';\nimport { Issue } from '@gitlens/git/models/issue.js';\nimport type { IssueOrPullRequestState } from '@gitlens/git/models/issueOrPullRequest.js';\nimport type { PullRequestMember, PullRequestProjection, PullRequestReviewer } from '@gitlens/git/models/pullRequest.js';\nimport { PullRequest, PullRequestReviewDecision, PullRequestReviewState } from '@gitlens/git/models/pullRequest.js';\nimport type { Provider } from '@gitlens/git/models/remoteProvider.js';\nimport type { ResourceDescriptor } from '@gitlens/git/models/resourceDescriptor.js';\nimport type { PullRequestEtagFields, PullRequestEtagInclude } from '../../models/integration.js';\n\nexport interface BitbucketRepositoryDescriptor extends ResourceDescriptor {\n\towner: string;\n\tname: string;\n}\n\nexport interface BitbucketWorkspaceDescriptor extends ResourceDescriptor {\n\tid: string;\n\tname: string;\n\tslug: string;\n}\n\nexport type BitbucketPullRequestState = 'OPEN' | 'DECLINED' | 'MERGED' | 'SUPERSEDED';\n\ninterface BitbucketLink {\n\thref: string;\n\tname?: string;\n}\n\n// Bitbucket's `account` schema: a person (`user`) or an app/bot (`app_user`, e.g. a review bot on a PR).\n// An `app_user` has no `links.html` and no `nickname`, and the schema requires none of the links.\ninterface BitbucketUser {\n\ttype: 'user' | 'app_user';\n\tuuid: string;\n\tdisplay_name: string;\n\taccount_id?: string;\n\tnickname?: string;\n\tlinks?: {\n\t\tself?: BitbucketLink;\n\t\tavatar?: BitbucketLink;\n\t\thtml?: BitbucketLink;\n\t};\n}\n\ninterface BitbucketWorkspace {\n\ttype: 'workspace';\n\tuuid: string;\n\tname: string;\n\tslug: string;\n\tlinks: {\n\t\tself: BitbucketLink;\n\t\thtml: BitbucketLink;\n\t\tavatar: BitbucketLink;\n\t};\n}\n\ninterface BitbucketProject {\n\ttype: 'project';\n\tkey: string;\n\tuuid: string;\n\tname: string;\n\tlinks: {\n\t\tself: BitbucketLink;\n\t\thtml: BitbucketLink;\n\t\tavatar: BitbucketLink;\n\t};\n}\n\ninterface BitbucketPullRequestParticipant {\n\ttype: 'participant';\n\tuser: BitbucketUser;\n\trole: 'PARTICIPANT' | 'REVIEWER';\n\tapproved: boolean;\n\tstate: null | 'approved' | 'changes_requested';\n\tparticipated_on: null | string;\n}\n\nexport interface BitbucketRepository {\n\ttype: 'repository';\n\tuuid: string;\n\tfull_name: string;\n\tname: string;\n\tslug: string;\n\tdescription?: string;\n\tis_private: boolean;\n\tparent: null | BitbucketRepository;\n\tscm: 'git';\n\towner: BitbucketUser;\n\tworkspace: BitbucketWorkspace;\n\tproject: BitbucketProject;\n\tcreated_on: string;\n\tupdated_on: string;\n\tsize: number;\n\tlanguage: string;\n\thas_issues: boolean;\n\thas_wiki: boolean;\n\tfork_policy: 'allow_forks' | 'no_public_forks' | 'no_forks';\n\twebsite: string;\n\tmainbranch?: BitbucketBranch;\n\tlinks: {\n\t\tself: BitbucketLink;\n\t\thtml: BitbucketLink;\n\t\tavatar: BitbucketLink;\n\t};\n}\n\ninterface BitbucketCommitAuthor {\n\ttype: 'author';\n\traw: string;\n\tuser: BitbucketUser;\n}\n\ntype BitbucketMergeStrategy =\n\t| 'merge_commit'\n\t| 'squash'\n\t| 'fast_forward'\n\t| 'squash_fast_forward'\n\t| 'rebase_fast_forward'\n\t| 'rebase_merge';\n\ninterface BitbucketBranch {\n\tname: string;\n\tmerge_strategies?: BitbucketMergeStrategy[];\n\tdefault_merge_strategy?: BitbucketMergeStrategy;\n}\n\n// It parses a raw author sitring like \"Sergei Shmakov GK <sergei.shmakov@gitkraken.com>\" to name and email\nconst parseRawBitbucketAuthorRegex = /^(.*) <(.*)>$/;\nexport function parseRawBitbucketAuthor(raw: string): { name: string; email: string } {\n\tconst match = raw.match(parseRawBitbucketAuthorRegex);\n\tif (match) {\n\t\treturn { name: match[1], email: match[2] };\n\t}\n\treturn { name: raw, email: '' };\n}\n\nexport interface BitbucketCommit extends BitbucketBriefCommit {\n\tauthor: BitbucketCommitAuthor;\n\tdate: string;\n\tlinks: {\n\t\tapprove: BitbucketLink;\n\t\tcomments: BitbucketLink;\n\t\tdiff: BitbucketLink;\n\t\thtml: BitbucketLink;\n\t\tself: BitbucketLink;\n\t\tstatuses: BitbucketLink;\n\t};\n\tmessage: string;\n\tparents: BitbucketBriefCommit[];\n\tparticipants: BitbucketPullRequestParticipant[];\n\trendered: {\n\t\tmessage: string;\n\t};\n\trepository: BitbucketRepository;\n\tsummary: {\n\t\ttype: 'rendered';\n\t\traw: string;\n\t\tmarkup: string;\n\t\thtml: string;\n\t};\n}\n\ninterface BitbucketBriefCommit {\n\ttype: 'commit';\n\thash: string;\n\tlinks: {\n\t\tself: BitbucketLink;\n\t\thtml: BitbucketLink;\n\t};\n}\n\nexport type BitbucketIssueState =\n\t| 'submitted'\n\t| 'new'\n\t| 'open'\n\t| 'resolved'\n\t| 'on hold'\n\t| 'invalid'\n\t| 'duplicate'\n\t| 'wontfix'\n\t| 'closed';\n\nexport interface BitbucketPullRequest {\n\ttype: 'pullrequest';\n\tid: number;\n\ttitle: string;\n\tdescription: string;\n\tstate: BitbucketPullRequestState;\n\tdraft?: boolean;\n\tmerge_commit: null | BitbucketBriefCommit;\n\tcomment_count: number;\n\ttask_count: number;\n\tclose_source_branch: boolean;\n\tclosed_by: BitbucketUser | null;\n\tauthor: BitbucketUser;\n\treason: string;\n\tcreated_on: string;\n\tupdated_on: string;\n\tdestination: {\n\t\tbranch: BitbucketBranch;\n\t\tcommit: BitbucketBriefCommit;\n\t\trepository: BitbucketRepository;\n\t};\n\tsource: {\n\t\tbranch: BitbucketBranch;\n\t\tcommit: BitbucketBriefCommit;\n\t\trepository: BitbucketRepository;\n\t};\n\tsummary: {\n\t\ttype: 'rendered';\n\t\traw: string;\n\t\tmarkup: string;\n\t\thtml: string;\n\t};\n\treviewers?: BitbucketUser[];\n\tparticipants?: BitbucketPullRequestParticipant[];\n\tlinks: {\n\t\tself: BitbucketLink;\n\t\thtml: BitbucketLink;\n\t\tcommits: BitbucketLink;\n\t\tapprove: BitbucketLink;\n\t\t'request-changes': BitbucketLink;\n\t\tdiff: BitbucketLink;\n\t\tdiffstat: BitbucketLink;\n\t\tcomments: BitbucketLink;\n\t\tactivity: BitbucketLink;\n\t\tmerge: BitbucketLink;\n\t\tdecline: BitbucketLink;\n\t\tstatuses: BitbucketLink;\n\t};\n}\n\nexport interface BitbucketIssue {\n\ttype: string;\n\tid: number;\n\ttitle: string;\n\treporter: BitbucketUser;\n\tassignee?: BitbucketUser;\n\tstate: BitbucketIssueState;\n\tcreated_on: string;\n\tupdated_on: string;\n\trepository: BitbucketRepository;\n\tvotes?: number;\n\tcontent: {\n\t\traw: string;\n\t\tmarkup: string;\n\t\thtml: string;\n\t};\n\tlinks: {\n\t\tself: BitbucketLink;\n\t\thtml: BitbucketLink;\n\t\tcomments: BitbucketLink;\n\t\tattachments: BitbucketLink;\n\t\twatch: BitbucketLink;\n\t\tvote: BitbucketLink;\n\t};\n}\n\nexport function bitbucketPullRequestStateToState(state: BitbucketPullRequestState): IssueOrPullRequestState {\n\tswitch (state) {\n\t\tcase 'DECLINED':\n\t\tcase 'SUPERSEDED':\n\t\t\treturn 'closed';\n\t\tcase 'MERGED':\n\t\t\treturn 'merged';\n\t\tcase 'OPEN':\n\t\tdefault:\n\t\t\treturn 'opened';\n\t}\n}\n\nexport function bitbucketIssueStateToState(state: BitbucketIssueState): IssueOrPullRequestState {\n\tswitch (state) {\n\t\tcase 'resolved':\n\t\tcase 'invalid':\n\t\tcase 'duplicate':\n\t\tcase 'wontfix':\n\t\tcase 'closed':\n\t\t\treturn 'closed';\n\t\tcase 'submitted':\n\t\tcase 'new':\n\t\tcase 'open':\n\t\tcase 'on hold':\n\t\tdefault:\n\t\t\treturn 'opened';\n\t}\n}\n\nexport function isClosedBitbucketPullRequestState(state: BitbucketPullRequestState): boolean {\n\treturn bitbucketPullRequestStateToState(state) !== 'opened';\n}\n\nexport function isClosedBitbucketIssueState(state: BitbucketIssueState): boolean {\n\treturn bitbucketIssueStateToState(state) !== 'opened';\n}\n\nexport function fromBitbucketUser(user: BitbucketUser): PullRequestMember {\n\treturn {\n\t\tavatarUrl: user.links?.avatar?.href,\n\t\tname: user.display_name,\n\t\tusername: user.nickname,\n\t\turl: user.links?.html?.href,\n\t\tid: user.uuid,\n\t};\n}\n\nexport function fromBitbucketParticipantToReviewer(\n\tprt: BitbucketPullRequestParticipant,\n\tclosedBy: BitbucketUser | null,\n\tprState: BitbucketPullRequestState,\n): PullRequestReviewer {\n\treturn {\n\t\treviewer: fromBitbucketUser(prt.user),\n\t\tstate: prt.approved\n\t\t\t? PullRequestReviewState.Approved\n\t\t\t: prt.state === 'changes_requested'\n\t\t\t\t? PullRequestReviewState.ChangesRequested\n\t\t\t\t: prt.participated_on != null\n\t\t\t\t\t? PullRequestReviewState.Commented\n\t\t\t\t\t: prt.user.uuid === closedBy?.uuid && prState === 'DECLINED'\n\t\t\t\t\t\t? PullRequestReviewState.Dismissed\n\t\t\t\t\t\t: PullRequestReviewState.ReviewRequested,\n\t};\n}\n\n/**\n * The review decision a Bitbucket Cloud row carries, derived from its participants and reviewers. Reads only the\n * participants' `participated_on`, `approved` and `state` and whether there are reviewers, which is what the cheap etag\n * read selects for it.\n */\nexport function getBitbucketReviewDecision(pr: {\n\tparticipants?: readonly Pick<BitbucketPullRequestParticipant, 'approved' | 'state' | 'participated_on'>[];\n\treviewers?: readonly unknown[];\n}): PullRequestReviewDecision | undefined {\n\tif (!pr.participants?.length && pr.reviewers?.length) {\n\t\treturn PullRequestReviewDecision.ReviewRequired;\n\t}\n\tif (!pr.participants) {\n\t\treturn undefined;\n\t}\n\n\tlet hasReviews = false;\n\tlet hasChangeRequests = false;\n\tlet hasApprovals = false;\n\tfor (const prt of pr.participants) {\n\t\tif (prt.participated_on != null) {\n\t\t\thasReviews = true;\n\t\t}\n\t\tif (prt.approved) {\n\t\t\thasApprovals = true;\n\t\t}\n\t\tif (prt.state === 'changes_requested') {\n\t\t\thasChangeRequests = true;\n\t\t}\n\t}\n\tif (hasChangeRequests) return PullRequestReviewDecision.ChangesRequested;\n\tif (hasApprovals) return PullRequestReviewDecision.Approved;\n\tif (hasReviews) return undefined; // not approved, not rejected, but reviewed\n\treturn PullRequestReviewDecision.ReviewRequired; // nobody has reviewed yet.\n}\n\nfunction fromBitbucketRepository(repo: BitbucketRepository): IssueRepository {\n\treturn {\n\t\towner: repo.full_name.split('/')[0],\n\t\trepo: repo.name,\n\t\tid: repo.uuid,\n\t};\n}\n\nexport function fromBitbucketIssue(issue: BitbucketIssue, provider: Provider, projection?: IssueProjection): Issue {\n\treturn new Issue(\n\t\tprovider,\n\t\tissue.id.toString(),\n\t\tissue.id.toString(),\n\t\tissue.title,\n\t\tissue.links.html.href,\n\t\tnew Date(issue.created_on),\n\t\tnew Date(issue.updated_on),\n\t\tisClosedBitbucketIssueState(issue.state),\n\t\tbitbucketIssueStateToState(issue.state),\n\t\tfromBitbucketUser(issue.reporter),\n\t\tissue.assignee ? [fromBitbucketUser(issue.assignee)] : [],\n\t\tfromBitbucketRepository(issue.repository),\n\t\tundefined, // closedDate\n\t\tundefined, // labels\n\t\tundefined, // commentsCount\n\t\tissue.votes, // thumbsUpCount\n\t\tissue.content.html, // body\n\t\t!issue.repository?.project\n\t\t\t? undefined\n\t\t\t: {\n\t\t\t\t\tid: issue.repository.project.uuid,\n\t\t\t\t\tname: issue.repository.project.name,\n\t\t\t\t\tresourceId: issue.repository.project.uuid,\n\t\t\t\t\tresourceName: issue.repository.project.name,\n\t\t\t\t},\n\t\tundefined, // number\n\t\tundefined, // issueType\n\t\tundefined, // providerState\n\t\tundefined, // bodyFormat\n\t\tundefined, // iterations\n\t\tprojection,\n\t);\n}\n\nexport function fromBitbucketPullRequest(\n\tpr: BitbucketPullRequest,\n\tprovider: Provider,\n\toptions?: { currentAccount?: { id: string; username?: string }; projection?: PullRequestProjection },\n): PullRequest {\n\tconst author = fromBitbucketUser(pr.author);\n\treturn new PullRequest(\n\t\tprovider,\n\t\tauthor,\n\t\tpr.id.toString(),\n\t\tpr.id.toString(),\n\t\tpr.title,\n\t\tpr.links.html.href,\n\t\tfromBitbucketRepository(pr.destination.repository),\n\t\tbitbucketPullRequestStateToState(pr.state),\n\t\tnew Date(pr.created_on),\n\t\tnew Date(pr.updated_on),\n\t\tpr.closed_by ? new Date(pr.updated_on) : undefined,\n\t\tpr.state === 'MERGED' ? new Date(pr.updated_on) : undefined,\n\t\tundefined, // mergeableState: not read\n\t\tundefined, // viewerCanUpdate\n\t\t{\n\t\t\tbase: {\n\t\t\t\tbranch: pr.destination.branch.name,\n\t\t\t\tsha: pr.destination.commit.hash,\n\t\t\t\trepo: pr.destination.repository.name,\n\t\t\t\towner: pr.destination.repository.full_name.split('/')[0],\n\t\t\t\texists: true,\n\t\t\t\turl: pr.destination.repository.links.html.href,\n\t\t\t},\n\t\t\thead: {\n\t\t\t\tbranch: pr.source.branch.name,\n\t\t\t\tsha: pr.source.commit.hash,\n\t\t\t\trepo: pr.source.repository.name,\n\t\t\t\towner: pr.source.repository.full_name.split('/')[0],\n\t\t\t\texists: true,\n\t\t\t\turl: pr.source.repository.links.html.href,\n\t\t\t},\n\t\t\tisCrossRepository: pr.source.repository.uuid !== pr.destination.repository.uuid,\n\t\t},\n\t\tpr.draft,\n\t\tundefined, // additions\n\t\tundefined, // deletions\n\t\tundefined, // commentsCount\n\t\tundefined, // thumbsCount\n\t\tgetBitbucketReviewDecision(pr),\n\t\tpr.participants // reviewRequests:PullRequestReviewer[]\n\t\t\t?.filter(prt => prt.role === 'REVIEWER')\n\t\t\t.map(prt => fromBitbucketParticipantToReviewer(prt, pr.closed_by, pr.state))\n\t\t\t.filter(rv => rv.state === PullRequestReviewState.ReviewRequested),\n\t\tpr.participants // latestReviews:PullRequestReviewer[]\n\t\t\t?.filter(prt => prt.participated_on != null)\n\t\t\t.map(prt => fromBitbucketParticipantToReviewer(prt, pr.closed_by, pr.state)),\n\t\tundefined, // assignees:PullRequestMember[] -- it looks like there is no such thing as assignees on Bitbucket\n\t\tundefined, // PullRequestStatusCheckRollupState\n\t\tundefined, // IssueProject\n\t\tundefined, // version\n\t\tundefined, // commitCount\n\t\tundefined, // stack\n\t\tundefined, // filesChanged\n\t\tpr.description ?? undefined,\n\t\tpr.id,\n\t\toptions?.currentAccount != null ? author.id === options.currentAccount.id : undefined,\n\t\toptions?.projection,\n\t\toptions?.currentAccount,\n\t);\n}\n\n/** The most pull request ids one etag read asks for: Bitbucket Cloud's largest page of pull requests. */\nexport const bitbucketEtagFieldsMaxIds = 50;\n\n/**\n * A pull request as the cheap etag read selects it (`BitbucketApi.getPullRequestsEtagFields`): only the fields\n * {@link fromBitbucketPullRequest} maps into a full row's etag inputs. `participants` and `reviewers` are selected\n * only for the `reviewDecision` include.\n */\nexport interface BitbucketPullRequestEtagNode {\n\tid: number;\n\tstate: BitbucketPullRequestState;\n\tupdated_on: string;\n\tdraft?: boolean;\n\tsource: { commit: { hash: string } };\n\tparticipants?: Pick<BitbucketPullRequestParticipant, 'approved' | 'state' | 'participated_on'>[];\n\treviewers?: unknown[];\n}\n\n/**\n * A cheap etag read's pull request in the vocabulary {@link fromBitbucketPullRequest}'s row ends in, so both reads\n * compute the same etag. That row reads neither a mergeability nor a check rollup, so neither does this.\n */\nexport function toBitbucketPullRequestEtagFields(\n\tnode: BitbucketPullRequestEtagNode,\n\tetagIncludes: readonly PullRequestEtagInclude[],\n): PullRequestEtagFields {\n\tconst fields: PullRequestEtagFields = {\n\t\tstate: bitbucketPullRequestStateToState(node.state),\n\t\tisDraft: node.draft,\n\t\tupdatedDate: new Date(node.updated_on),\n\t\theadSha: node.source.commit.hash,\n\t};\n\n\tif (etagIncludes.includes('reviewDecision')) {\n\t\t// The full read always has both lists, and the decision tells a missing list from an empty one, so a row\n\t\t// without them can't be compared: it rejects, and the full read answers instead.\n\t\tif (node.participants == null || node.reviewers == null) {\n\t\t\tthrow new Error(`Bitbucket returned pull request ${node.id} without its participants or reviewers`);\n\t\t}\n\n\t\tfields.reviewDecision = getBitbucketReviewDecision(node);\n\t}\n\n\treturn fields;\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { ProviderPullRequest } from "../models.js";
|
|
2
|
-
import {
|
|
2
|
+
import { GitPullRequestReviewState as GitPullRequestReviewState$1, GitPullRequestState as GitPullRequestState$1 } from "@gitkraken/provider-apis";
|
|
3
3
|
//#region ../plus/integrations/src/providers/bitbucket-server/models.d.ts
|
|
4
|
-
type GitPullRequestMergeableState = GitPullRequestMergeableState$1;
|
|
5
4
|
type GitPullRequestReviewState = GitPullRequestReviewState$1;
|
|
6
5
|
type GitPullRequestState = GitPullRequestState$1;
|
|
7
6
|
declare const GitPullRequestState: {
|
|
@@ -15,9 +14,6 @@ declare const GitPullRequestReviewState: {
|
|
|
15
14
|
readonly Commented: GitPullRequestReviewState;
|
|
16
15
|
readonly ReviewRequested: GitPullRequestReviewState;
|
|
17
16
|
};
|
|
18
|
-
declare const GitPullRequestMergeableState: {
|
|
19
|
-
readonly Unknown: GitPullRequestMergeableState;
|
|
20
|
-
};
|
|
21
17
|
export interface BitbucketServerLink {
|
|
22
18
|
href: string;
|
|
23
19
|
}
|
|
@@ -145,5 +141,5 @@ export declare const summarizeReviewDecision: (reviews: {
|
|
|
145
141
|
}[] | null) => GitPullRequestReviewState | null;
|
|
146
142
|
export declare const normalizeBitbucketServerPullRequest: (pr: BitbucketServerPullRequest) => ProviderPullRequest;
|
|
147
143
|
//#endregion
|
|
148
|
-
export {
|
|
144
|
+
export { GitPullRequestReviewState, GitPullRequestState };
|
|
149
145
|
//# sourceMappingURL=models.d.ts.map
|
|
@@ -10,7 +10,6 @@ const GitPullRequestReviewState = {
|
|
|
10
10
|
Commented: "COMMENTED",
|
|
11
11
|
ReviewRequested: "REVIEW_REQUESTED"
|
|
12
12
|
};
|
|
13
|
-
const GitPullRequestMergeableState = { Unknown: "UNKNOWN" };
|
|
14
13
|
const normalizeUser = (user) => ({
|
|
15
14
|
name: user.displayName,
|
|
16
15
|
email: user.emailAddress,
|
|
@@ -101,12 +100,11 @@ const normalizeBitbucketServerPullRequest = (pr) => {
|
|
|
101
100
|
} : null
|
|
102
101
|
},
|
|
103
102
|
headCommit: null,
|
|
104
|
-
mergeableState: GitPullRequestMergeableState.Unknown,
|
|
105
103
|
permissions: null,
|
|
106
104
|
version: pr.version
|
|
107
105
|
};
|
|
108
106
|
};
|
|
109
107
|
//#endregion
|
|
110
|
-
export {
|
|
108
|
+
export { GitPullRequestReviewState, GitPullRequestState, normalizeBitbucketServerPullRequest, summarizeReviewDecision };
|
|
111
109
|
|
|
112
110
|
//# sourceMappingURL=models.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"models.js","names":[],"sources":["../../../../../../plus/integrations/src/providers/bitbucket-server/models.ts"],"sourcesContent":["import type {\n\tGitPullRequestMergeableState as GitPullRequestMergeableStateType,\n\tGitPullRequestReviewState as GitPullRequestReviewStateType,\n\tGitPullRequestState as GitPullRequestStateType,\n} from '@gitkraken/provider-apis';\nimport type { ProviderAccount, ProviderPullRequest } from '../models.js';\n\ntype GitPullRequestMergeableState = GitPullRequestMergeableStateType;\ntype GitPullRequestReviewState = GitPullRequestReviewStateType;\ntype GitPullRequestState = GitPullRequestStateType;\n\n// Local runtime copies of the `@gitkraken/provider-apis` PR string enums, duplicated for the same\n// CJS-from-ESM reason as the enums in `../models.ts`. Exported so the enum-parity test can guard them\n// against upstream drift. `GitPullRequestMergeableState` is an intentional subset: Bitbucket Server\n// only ever normalizes to `Unknown`, so the parity test asserts each local entry matches the SDK\n// rather than a full mirror.\nexport const GitPullRequestState = {\n\tOpen: 'OPEN' as GitPullRequestState,\n\tClosed: 'CLOSED' as GitPullRequestState,\n\tMerged: 'MERGED' as GitPullRequestState,\n} as const;\n\nexport const GitPullRequestReviewState = {\n\tApproved: 'APPROVED' as GitPullRequestReviewState,\n\tChangesRequested: 'CHANGES_REQUESTED' as GitPullRequestReviewState,\n\tCommented: 'COMMENTED' as GitPullRequestReviewState,\n\tReviewRequested: 'REVIEW_REQUESTED' as GitPullRequestReviewState,\n} as const;\n\nexport const GitPullRequestMergeableState = {\n\tUnknown: 'UNKNOWN' as GitPullRequestMergeableState,\n} as const;\n\nexport interface BitbucketServerLink {\n\thref: string;\n}\n\nexport interface NamedBitbucketServerLink<T extends string = string> extends BitbucketServerLink {\n\tname: T;\n}\n\nexport interface BitbucketServerPagedResponse<T> {\n\tvalues: T[];\n\tsize: number;\n\tlimit: number;\n\tisLastPage: boolean;\n\tnextPageStart: number;\n\tstart: number;\n}\n\nexport interface BitbucketServerPullRequestRef {\n\tid: string;\n\tdisplayId: string;\n\tlatestCommit: string;\n\ttype: string;\n\trepository: {\n\t\tslug: string;\n\t\tid: number;\n\t\tname: string;\n\t\thierarchyId: string;\n\t\tscmId: string;\n\t\tstate: string;\n\t\tstatusMessage: string;\n\t\tforkable: boolean;\n\t\tproject: {\n\t\t\tkey: string;\n\t\t\tid: number;\n\t\t\tname: string;\n\t\t\tpublic: boolean;\n\t\t\ttype: string;\n\t\t\tlinks: {\n\t\t\t\tself: BitbucketServerLink[];\n\t\t\t};\n\t\t};\n\t\tpublic: boolean;\n\t\tarchived: boolean;\n\t\tlinks: {\n\t\t\tclone: NamedBitbucketServerLink[];\n\t\t\tself: BitbucketServerLink[];\n\t\t};\n\t};\n}\n\nexport interface BitbucketAuthor {\n\tname: string;\n\temailAddress: string;\n\tid: undefined;\n}\n\nexport interface BitbucketServerUser {\n\tname: string;\n\temailAddress: string;\n\tactive: boolean;\n\tdisplayName: string;\n\tid: number;\n\tslug: string;\n\ttype: string;\n\tlinks: {\n\t\tself: BitbucketServerLink[];\n\t};\n\tavatarUrl?: string;\n}\n\nexport interface BitbucketServerPullRequestUser {\n\tuser: BitbucketServerUser;\n\tlastReviewedCommit?: string;\n\trole: 'REVIEWER' | 'AUTHOR' | 'PARTICIPANT';\n\tapproved: boolean;\n\tstatus: 'UNAPPROVED' | 'NEEDS_WORK' | 'APPROVED';\n}\n\nexport interface BitbucketServerBriefCommit {\n\tdisplayId: string;\n\tid: string;\n}\n\nexport interface BitbucketServerCommit extends BitbucketServerBriefCommit {\n\tauthor: BitbucketServerUser | BitbucketAuthor;\n\tauthorTimestamp: number;\n\tcommitter: BitbucketServerUser | BitbucketAuthor;\n\tcommitterTimestamp: number;\n\tmessage: string;\n\tparents: (BitbucketServerCommit | BitbucketServerBriefCommit)[];\n}\n\nexport interface BitbucketServerPullRequest {\n\tid: number;\n\tversion: number;\n\ttitle: string;\n\tdescription: string;\n\t/**\n\t * `SUPERSEDED` is not in the published schema, but a server can still report it for a pull request closed by a\n\t * newer one (the Bitbucket SDK maps it too); it is a closed pull request, like `DECLINED`.\n\t */\n\tstate: 'OPEN' | 'MERGED' | 'DECLINED' | 'SUPERSEDED';\n\t/**\n\t * Drafts shipped in Bitbucket Data Center 8.18 (8.17 exposed the field experimentally); absent means the server\n\t * has no drafts, so not a draft.\n\t */\n\tdraft?: boolean;\n\topen: boolean;\n\tclosed: boolean;\n\tcreatedDate: number;\n\tupdatedDate: number;\n\tclosedDate: number | null;\n\tfromRef: BitbucketServerPullRequestRef;\n\ttoRef: BitbucketServerPullRequestRef;\n\tlocked: boolean;\n\tauthor: BitbucketServerPullRequestUser;\n\treviewers: BitbucketServerPullRequestUser[];\n\tparticipants: BitbucketServerPullRequestUser[];\n\tproperties: {\n\t\tmergeResult: {\n\t\t\toutcome: string;\n\t\t\tcurrent: boolean;\n\t\t};\n\t\tresolvedTaskCount: number;\n\t\tcommentCount: number;\n\t\topenTaskCount: number;\n\t};\n\tlinks: {\n\t\tself: BitbucketServerLink[];\n\t};\n}\n\nconst normalizeUser = (user: BitbucketServerUser): ProviderAccount => ({\n\tname: user.displayName,\n\temail: user.emailAddress,\n\tavatarUrl: user.avatarUrl ?? null,\n\tid: user.id.toString(),\n\tusername: user.name,\n\turl: user.links.self[0].href,\n});\n\nconst reviewDecisionWeightByReviewState = {\n\t[GitPullRequestReviewState.Approved]: 0,\n\t[GitPullRequestReviewState.Commented]: 1,\n\t[GitPullRequestReviewState.ReviewRequested]: 2,\n\t[GitPullRequestReviewState.ChangesRequested]: 3,\n};\n\nexport const summarizeReviewDecision = (\n\treviews: { state: GitPullRequestReviewState }[] | null,\n): GitPullRequestReviewState | null => {\n\tif (!reviews || reviews.length === 0) {\n\t\treturn null;\n\t}\n\n\treturn reviews.reduce(\n\t\t(prev: GitPullRequestReviewState, review) =>\n\t\t\treviewDecisionWeightByReviewState[review.state] > reviewDecisionWeightByReviewState[prev]\n\t\t\t\t? review.state\n\t\t\t\t: prev,\n\t\tGitPullRequestReviewState.Approved,\n\t);\n};\n\nexport const normalizeBitbucketServerPullRequest = (pr: BitbucketServerPullRequest): ProviderPullRequest => {\n\tconst bitbucketStateToGitState = {\n\t\tOPEN: GitPullRequestState.Open,\n\t\tMERGED: GitPullRequestState.Merged,\n\t\tDECLINED: GitPullRequestState.Closed,\n\t\tSUPERSEDED: GitPullRequestState.Closed,\n\t};\n\n\tconst reviewerStatusToGitState = {\n\t\tUNAPPROVED: GitPullRequestReviewState.ReviewRequested,\n\t\tNEEDS_WORK: GitPullRequestReviewState.ChangesRequested,\n\t\tAPPROVED: GitPullRequestReviewState.Approved,\n\t};\n\n\tconst reviews = pr.reviewers.map(reviewer => ({\n\t\treviewer: normalizeUser(reviewer.user),\n\t\tstate: reviewerStatusToGitState[reviewer.status],\n\t}));\n\n\tconst baseSSHUrl = pr.toRef.repository.links.clone.find(link => link.name === 'ssh')?.href ?? null;\n\tlet baseHTTPSUrl = pr.toRef.repository.links.clone.find(link => link.name === 'https')?.href ?? null;\n\tif (!baseHTTPSUrl) {\n\t\tbaseHTTPSUrl = pr.toRef.repository.links.clone.find(link => link.name === 'http')?.href ?? null;\n\t}\n\n\tconst headSSHUrl = pr.fromRef.repository.links.clone.find(link => link.name === 'ssh')?.href ?? null;\n\tlet headHTTPSUrl = pr.fromRef.repository.links.clone.find(link => link.name === 'https')?.href ?? null;\n\tif (!headHTTPSUrl) {\n\t\theadHTTPSUrl = pr.fromRef.repository.links.clone.find(link => link.name === 'http')?.href ?? null;\n\t}\n\n\treturn {\n\t\tid: pr.id.toString(),\n\t\tnumber: pr.id,\n\t\ttitle: pr.title,\n\t\tdescription: pr.description ?? null,\n\t\turl: pr.links.self[0].href,\n\t\tstate: bitbucketStateToGitState[pr.state],\n\t\tisCrossRepository: pr.toRef.repository.id !== pr.fromRef.repository.id,\n\t\tisDraft: pr.draft === true,\n\t\tcreatedDate: new Date(pr.createdDate),\n\t\tupdatedDate: new Date(pr.updatedDate),\n\t\tclosedDate: pr.closedDate ? new Date(pr.closedDate) : null,\n\t\tmergedDate: pr.state === 'MERGED' && pr.closedDate ? new Date(pr.closedDate) : null,\n\t\tbaseRef: {\n\t\t\tname: pr.toRef.displayId,\n\t\t\toid: pr.toRef.latestCommit,\n\t\t},\n\t\theadRef: {\n\t\t\tname: pr.fromRef.displayId,\n\t\t\toid: pr.fromRef.latestCommit,\n\t\t},\n\t\tcommentCount: pr.properties?.commentCount,\n\t\tupvoteCount: null,\n\t\tcommitCount: null,\n\t\tfileCount: null,\n\t\tadditions: null,\n\t\tdeletions: null,\n\t\tauthor: normalizeUser(pr.author.user),\n\t\tassignees: null,\n\t\treviews: reviews,\n\t\treviewDecision: summarizeReviewDecision(reviews),\n\t\trepository: {\n\t\t\tid: pr.toRef.repository.id.toString(),\n\t\t\tname: pr.toRef.repository.name,\n\t\t\towner: {\n\t\t\t\tlogin: pr.toRef.repository.project.key,\n\t\t\t},\n\t\t\tremoteInfo:\n\t\t\t\tbaseHTTPSUrl && baseSSHUrl\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tcloneUrlHTTPS: baseHTTPSUrl,\n\t\t\t\t\t\t\tcloneUrlSSH: baseSSHUrl,\n\t\t\t\t\t\t}\n\t\t\t\t\t: null,\n\t\t},\n\t\theadRepository: {\n\t\t\tid: pr.fromRef.repository.id.toString(),\n\t\t\tname: pr.fromRef.repository.name,\n\t\t\towner: {\n\t\t\t\tlogin: pr.fromRef.repository.project.key,\n\t\t\t},\n\t\t\tremoteInfo:\n\t\t\t\theadHTTPSUrl && headSSHUrl\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tcloneUrlHTTPS: headHTTPSUrl,\n\t\t\t\t\t\t\tcloneUrlSSH: headSSHUrl,\n\t\t\t\t\t\t}\n\t\t\t\t\t: null,\n\t\t},\n\t\theadCommit: null,\n\t\tmergeableState: GitPullRequestMergeableState.Unknown,\n\t\tpermissions: null,\n\t\tversion: pr.version,\n\t};\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"models.js","names":[],"sources":["../../../../../../plus/integrations/src/providers/bitbucket-server/models.ts"],"sourcesContent":["import type {\n\tGitPullRequestReviewState as GitPullRequestReviewStateType,\n\tGitPullRequestState as GitPullRequestStateType,\n} from '@gitkraken/provider-apis';\nimport type { ProviderAccount, ProviderPullRequest } from '../models.js';\n\ntype GitPullRequestReviewState = GitPullRequestReviewStateType;\ntype GitPullRequestState = GitPullRequestStateType;\n\n// Local runtime copies of the `@gitkraken/provider-apis` PR string enums, duplicated for the same\n// CJS-from-ESM reason as the enums in `../models.ts`. Exported so the enum-parity test can guard them\n// against upstream drift.\nexport const GitPullRequestState = {\n\tOpen: 'OPEN' as GitPullRequestState,\n\tClosed: 'CLOSED' as GitPullRequestState,\n\tMerged: 'MERGED' as GitPullRequestState,\n} as const;\n\nexport const GitPullRequestReviewState = {\n\tApproved: 'APPROVED' as GitPullRequestReviewState,\n\tChangesRequested: 'CHANGES_REQUESTED' as GitPullRequestReviewState,\n\tCommented: 'COMMENTED' as GitPullRequestReviewState,\n\tReviewRequested: 'REVIEW_REQUESTED' as GitPullRequestReviewState,\n} as const;\n\nexport interface BitbucketServerLink {\n\thref: string;\n}\n\nexport interface NamedBitbucketServerLink<T extends string = string> extends BitbucketServerLink {\n\tname: T;\n}\n\nexport interface BitbucketServerPagedResponse<T> {\n\tvalues: T[];\n\tsize: number;\n\tlimit: number;\n\tisLastPage: boolean;\n\tnextPageStart: number;\n\tstart: number;\n}\n\nexport interface BitbucketServerPullRequestRef {\n\tid: string;\n\tdisplayId: string;\n\tlatestCommit: string;\n\ttype: string;\n\trepository: {\n\t\tslug: string;\n\t\tid: number;\n\t\tname: string;\n\t\thierarchyId: string;\n\t\tscmId: string;\n\t\tstate: string;\n\t\tstatusMessage: string;\n\t\tforkable: boolean;\n\t\tproject: {\n\t\t\tkey: string;\n\t\t\tid: number;\n\t\t\tname: string;\n\t\t\tpublic: boolean;\n\t\t\ttype: string;\n\t\t\tlinks: {\n\t\t\t\tself: BitbucketServerLink[];\n\t\t\t};\n\t\t};\n\t\tpublic: boolean;\n\t\tarchived: boolean;\n\t\tlinks: {\n\t\t\tclone: NamedBitbucketServerLink[];\n\t\t\tself: BitbucketServerLink[];\n\t\t};\n\t};\n}\n\nexport interface BitbucketAuthor {\n\tname: string;\n\temailAddress: string;\n\tid: undefined;\n}\n\nexport interface BitbucketServerUser {\n\tname: string;\n\temailAddress: string;\n\tactive: boolean;\n\tdisplayName: string;\n\tid: number;\n\tslug: string;\n\ttype: string;\n\tlinks: {\n\t\tself: BitbucketServerLink[];\n\t};\n\tavatarUrl?: string;\n}\n\nexport interface BitbucketServerPullRequestUser {\n\tuser: BitbucketServerUser;\n\tlastReviewedCommit?: string;\n\trole: 'REVIEWER' | 'AUTHOR' | 'PARTICIPANT';\n\tapproved: boolean;\n\tstatus: 'UNAPPROVED' | 'NEEDS_WORK' | 'APPROVED';\n}\n\nexport interface BitbucketServerBriefCommit {\n\tdisplayId: string;\n\tid: string;\n}\n\nexport interface BitbucketServerCommit extends BitbucketServerBriefCommit {\n\tauthor: BitbucketServerUser | BitbucketAuthor;\n\tauthorTimestamp: number;\n\tcommitter: BitbucketServerUser | BitbucketAuthor;\n\tcommitterTimestamp: number;\n\tmessage: string;\n\tparents: (BitbucketServerCommit | BitbucketServerBriefCommit)[];\n}\n\nexport interface BitbucketServerPullRequest {\n\tid: number;\n\tversion: number;\n\ttitle: string;\n\tdescription: string;\n\t/**\n\t * `SUPERSEDED` is not in the published schema, but a server can still report it for a pull request closed by a\n\t * newer one (the Bitbucket SDK maps it too); it is a closed pull request, like `DECLINED`.\n\t */\n\tstate: 'OPEN' | 'MERGED' | 'DECLINED' | 'SUPERSEDED';\n\t/**\n\t * Drafts shipped in Bitbucket Data Center 8.18 (8.17 exposed the field experimentally); absent means the server\n\t * has no drafts, so not a draft.\n\t */\n\tdraft?: boolean;\n\topen: boolean;\n\tclosed: boolean;\n\tcreatedDate: number;\n\tupdatedDate: number;\n\tclosedDate: number | null;\n\tfromRef: BitbucketServerPullRequestRef;\n\ttoRef: BitbucketServerPullRequestRef;\n\tlocked: boolean;\n\tauthor: BitbucketServerPullRequestUser;\n\treviewers: BitbucketServerPullRequestUser[];\n\tparticipants: BitbucketServerPullRequestUser[];\n\tproperties: {\n\t\tmergeResult: {\n\t\t\toutcome: string;\n\t\t\tcurrent: boolean;\n\t\t};\n\t\tresolvedTaskCount: number;\n\t\tcommentCount: number;\n\t\topenTaskCount: number;\n\t};\n\tlinks: {\n\t\tself: BitbucketServerLink[];\n\t};\n}\n\nconst normalizeUser = (user: BitbucketServerUser): ProviderAccount => ({\n\tname: user.displayName,\n\temail: user.emailAddress,\n\tavatarUrl: user.avatarUrl ?? null,\n\tid: user.id.toString(),\n\tusername: user.name,\n\turl: user.links.self[0].href,\n});\n\nconst reviewDecisionWeightByReviewState = {\n\t[GitPullRequestReviewState.Approved]: 0,\n\t[GitPullRequestReviewState.Commented]: 1,\n\t[GitPullRequestReviewState.ReviewRequested]: 2,\n\t[GitPullRequestReviewState.ChangesRequested]: 3,\n};\n\nexport const summarizeReviewDecision = (\n\treviews: { state: GitPullRequestReviewState }[] | null,\n): GitPullRequestReviewState | null => {\n\tif (!reviews || reviews.length === 0) {\n\t\treturn null;\n\t}\n\n\treturn reviews.reduce(\n\t\t(prev: GitPullRequestReviewState, review) =>\n\t\t\treviewDecisionWeightByReviewState[review.state] > reviewDecisionWeightByReviewState[prev]\n\t\t\t\t? review.state\n\t\t\t\t: prev,\n\t\tGitPullRequestReviewState.Approved,\n\t);\n};\n\nexport const normalizeBitbucketServerPullRequest = (pr: BitbucketServerPullRequest): ProviderPullRequest => {\n\tconst bitbucketStateToGitState = {\n\t\tOPEN: GitPullRequestState.Open,\n\t\tMERGED: GitPullRequestState.Merged,\n\t\tDECLINED: GitPullRequestState.Closed,\n\t\tSUPERSEDED: GitPullRequestState.Closed,\n\t};\n\n\tconst reviewerStatusToGitState = {\n\t\tUNAPPROVED: GitPullRequestReviewState.ReviewRequested,\n\t\tNEEDS_WORK: GitPullRequestReviewState.ChangesRequested,\n\t\tAPPROVED: GitPullRequestReviewState.Approved,\n\t};\n\n\tconst reviews = pr.reviewers.map(reviewer => ({\n\t\treviewer: normalizeUser(reviewer.user),\n\t\tstate: reviewerStatusToGitState[reviewer.status],\n\t}));\n\n\tconst baseSSHUrl = pr.toRef.repository.links.clone.find(link => link.name === 'ssh')?.href ?? null;\n\tlet baseHTTPSUrl = pr.toRef.repository.links.clone.find(link => link.name === 'https')?.href ?? null;\n\tif (!baseHTTPSUrl) {\n\t\tbaseHTTPSUrl = pr.toRef.repository.links.clone.find(link => link.name === 'http')?.href ?? null;\n\t}\n\n\tconst headSSHUrl = pr.fromRef.repository.links.clone.find(link => link.name === 'ssh')?.href ?? null;\n\tlet headHTTPSUrl = pr.fromRef.repository.links.clone.find(link => link.name === 'https')?.href ?? null;\n\tif (!headHTTPSUrl) {\n\t\theadHTTPSUrl = pr.fromRef.repository.links.clone.find(link => link.name === 'http')?.href ?? null;\n\t}\n\n\treturn {\n\t\tid: pr.id.toString(),\n\t\tnumber: pr.id,\n\t\ttitle: pr.title,\n\t\tdescription: pr.description ?? null,\n\t\turl: pr.links.self[0].href,\n\t\tstate: bitbucketStateToGitState[pr.state],\n\t\tisCrossRepository: pr.toRef.repository.id !== pr.fromRef.repository.id,\n\t\tisDraft: pr.draft === true,\n\t\tcreatedDate: new Date(pr.createdDate),\n\t\tupdatedDate: new Date(pr.updatedDate),\n\t\tclosedDate: pr.closedDate ? new Date(pr.closedDate) : null,\n\t\tmergedDate: pr.state === 'MERGED' && pr.closedDate ? new Date(pr.closedDate) : null,\n\t\tbaseRef: {\n\t\t\tname: pr.toRef.displayId,\n\t\t\toid: pr.toRef.latestCommit,\n\t\t},\n\t\theadRef: {\n\t\t\tname: pr.fromRef.displayId,\n\t\t\toid: pr.fromRef.latestCommit,\n\t\t},\n\t\tcommentCount: pr.properties?.commentCount,\n\t\tupvoteCount: null,\n\t\tcommitCount: null,\n\t\tfileCount: null,\n\t\tadditions: null,\n\t\tdeletions: null,\n\t\tauthor: normalizeUser(pr.author.user),\n\t\tassignees: null,\n\t\treviews: reviews,\n\t\treviewDecision: summarizeReviewDecision(reviews),\n\t\trepository: {\n\t\t\tid: pr.toRef.repository.id.toString(),\n\t\t\tname: pr.toRef.repository.name,\n\t\t\towner: {\n\t\t\t\tlogin: pr.toRef.repository.project.key,\n\t\t\t},\n\t\t\tremoteInfo:\n\t\t\t\tbaseHTTPSUrl && baseSSHUrl\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tcloneUrlHTTPS: baseHTTPSUrl,\n\t\t\t\t\t\t\tcloneUrlSSH: baseSSHUrl,\n\t\t\t\t\t\t}\n\t\t\t\t\t: null,\n\t\t},\n\t\theadRepository: {\n\t\t\tid: pr.fromRef.repository.id.toString(),\n\t\t\tname: pr.fromRef.repository.name,\n\t\t\towner: {\n\t\t\t\tlogin: pr.fromRef.repository.project.key,\n\t\t\t},\n\t\t\tremoteInfo:\n\t\t\t\theadHTTPSUrl && headSSHUrl\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tcloneUrlHTTPS: headHTTPSUrl,\n\t\t\t\t\t\t\tcloneUrlSSH: headSSHUrl,\n\t\t\t\t\t\t}\n\t\t\t\t\t: null,\n\t\t},\n\t\theadCommit: null,\n\t\tpermissions: null,\n\t\tversion: pr.version,\n\t};\n};\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Provider } from "../../../../git/models/remoteProvider.js";
|
|
2
|
-
import { PullRequestSearchCriteria } from "../../../../git/models/pullRequest.js";
|
|
2
|
+
import { PullRequestProjection, PullRequestSearchCriteria } from "../../../../git/models/pullRequest.js";
|
|
3
3
|
import { TokenWithInfo } from "../../authentication/models.js";
|
|
4
4
|
import { GitSelfManagedHostIntegrationId } from "../../constants.js";
|
|
5
5
|
import { ProviderPullRequestCount, ProviderPullRequestSearchPage } from "../../models/pullRequestReads.js";
|
|
@@ -43,6 +43,8 @@ export declare function searchBitbucketServerPullRequestsPage(request: ProviderR
|
|
|
43
43
|
provider: Provider;
|
|
44
44
|
cursor?: string;
|
|
45
45
|
pageSize?: number;
|
|
46
|
+
/** The calling read, stamped on every row. */
|
|
47
|
+
projection?: PullRequestProjection;
|
|
46
48
|
}, cancellation?: AbortSignal): Promise<ProviderPullRequestSearchPage>;
|
|
47
49
|
/**
|
|
48
50
|
* How many pull requests match `criteria`: the same facets, predicates and identity the search uses, so the count
|
|
@@ -118,7 +118,10 @@ async function searchBitbucketServerPullRequestsPage(request, token, options, ca
|
|
|
118
118
|
truncated
|
|
119
119
|
};
|
|
120
120
|
return {
|
|
121
|
-
values: values.map((pr) => fromProviderPullRequest(pr, options.provider, {
|
|
121
|
+
values: values.map((pr) => fromProviderPullRequest(pr, options.provider, {
|
|
122
|
+
currentAccount: options.currentUser?.id != null ? { id: options.currentUser.id } : void 0,
|
|
123
|
+
projection: options.projection
|
|
124
|
+
})).sort(comparator),
|
|
122
125
|
cursor: hasMore ? JSON.stringify({
|
|
123
126
|
key,
|
|
124
127
|
page: cursor.page + 1,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pullRequestSearch.js","names":[],"sources":["../../../../../../plus/integrations/src/providers/bitbucket-server/pullRequestSearch.ts"],"sourcesContent":["import type { CollectionScope, CollectionScopeFailure, CollectionScopeFailureKind } from '@gitkraken/provider-apis';\nimport type {\n\tPullRequestSearchCriteria,\n\tPullRequestSorting,\n\tPullRequestStateFilter,\n} from '@gitlens/git/models/pullRequest.js';\nimport { defaultPullRequestSort, PullRequestFilter } from '@gitlens/git/models/pullRequest.js';\nimport type { Provider } from '@gitlens/git/models/remoteProvider.js';\nimport { getPullRequestComparator } from '@gitlens/git/utils/pullRequest.utils.js';\nimport { CancellationError, isCancellationError } from '@gitlens/utils/cancellation.js';\nimport { getNonce, sha256 } from '@gitlens/utils/crypto.js';\nimport { Logger } from '@gitlens/utils/logger.js';\nimport { mapSettledBounded } from '@gitlens/utils/promise.js';\nimport type { TokenWithInfo } from '../../authentication/models.js';\nimport { toCollectionScopeFailure } from '../../collectionMetadata.js';\nimport type { GitSelfManagedHostIntegrationId } from '../../constants.js';\nimport { AuthenticationError, AuthenticationErrorReason } from '../../errors.js';\nimport type { ProviderPullRequestCount, ProviderPullRequestSearchPage } from '../../models/pullRequestReads.js';\nimport type { ProviderPullRequest, ProviderRepoInput, ProviderRequestFunction } from '../models.js';\nimport { fromProviderPullRequest } from '../models.js';\nimport { throwProviderError } from '../providerErrors.js';\nimport type {\n\tBitbucketServerPagedResponse,\n\tBitbucketServerPullRequest,\n\tBitbucketServerPullRequestUser,\n\tBitbucketServerUser,\n} from './models.js';\nimport { normalizeBitbucketServerPullRequest } from './models.js';\n\ntype Token = TokenWithInfo<GitSelfManagedHostIntegrationId.BitbucketServer>;\ntype BitbucketServerPullRequestState = BitbucketServerPullRequest['state'];\n\n/**\n * The relationships Bitbucket Data Center can express, in the canonical order its facets (and so its cursor) are\n * built in. A Bitbucket pull request has no assignee, and none of its pull-request endpoints filter by mention.\n */\nconst relationships = [\n\tPullRequestFilter.Author,\n\tPullRequestFilter.ReviewRequested,\n\tPullRequestFilter.Reviewed,\n] as const;\ntype Relationship = (typeof relationships)[number];\n\n/** The current user, which both the server-side participant filters and their client-side re-check identify. */\nexport interface BitbucketServerSearchUser {\n\tid: string;\n\tusername: string;\n}\n\n/**\n * One provider query of the search: a repository or the current user's dashboard, times one relationship.\n *\n * A repository facet reads `/projects/{key}/repos/{slug}/pull-requests`, which filters participants, text and draft\n * state server-side, so a page narrowed to a few repositories holds only matches. Without repositories a relationship\n * reads `/dashboard/pull-requests`, the only cross-repository pull-request list Bitbucket Data Center has; it can't\n * filter text or draft state, so those are re-checked on its rows. There is no project-wide list at all, which is\n * why the capability declares no organization scope.\n *\n * States are not a facet axis: every facet asks the server for the one requested state, or for every state when\n * several are requested, and keeps the requested ones — reading the unrequested rows rather than spending one more\n * request per state.\n */\ninterface Facet {\n\trepo?: ProviderRepoInput;\n\trelationship?: Relationship;\n\t/**\n\t * The dashboard role a `Reviewed` facet reads. The dashboard only applies `participantStatus` together with\n\t * `role` — without one it returns every pull request the user is involved in, authored ones included, whatever\n\t * the status — so `Reviewed` is read as two facets, the reviewer list and the (non-reviewer) participant list,\n\t * each filtered by status server-side. Absent for every other facet.\n\t */\n\trole?: DashboardRole;\n}\n\ntype DashboardRole = 'REVIEWER' | 'PARTICIPANT';\n\ninterface SearchOptions {\n\tbaseUrl: string;\n\trepos?: ProviderRepoInput[];\n\t/** Refused when set: Bitbucket Data Center has no project-wide pull-request list to scope it to. */\n\torg?: string;\n\tcriteria?: PullRequestSearchCriteria;\n\t/** Required when `criteria.relationships` is non-empty. */\n\tcurrentUser?: BitbucketServerSearchUser;\n}\n\n/** A resolved query, shared by every facet of one search or count. */\ninterface Query extends SearchOptions {\n\tfacets: Facet[];\n\t/** The requested relationships, in canonical order — the order {@link ownsRow} gives a shared row to. */\n\trelationships: Relationship[];\n\t/** The requested states, or `undefined` for every state. */\n\tstates: Set<BitbucketServerPullRequestState> | undefined;\n\tsort: PullRequestSorting;\n}\n\n/** Bitbucket answers an unspecified page size with 25; a search page asks for this many per facet instead. */\nconst defaultSearchPageSize = 30;\n/**\n * The server's own cap on a page (`page.max.pullrequests`, 1000 unless an administrator lowered it), and the one\n * page a count reads per facet: past it the count is a floor rather than more of a customer-run server's capacity\n * spent on a figure the caller uses as a cost hint.\n */\nconst maxPageSize = 1000;\n/** Matches the SDK's own cap on concurrent Bitbucket Data Center pull-request requests. */\nconst facetConcurrency = 5;\n\n/** The server states each facade state covers. `closed` is two, so it can't be sent as one `state` filter. */\nconst pullRequestStates: Record<Exclude<PullRequestStateFilter, 'all'>, BitbucketServerPullRequestState[]> = {\n\topen: ['OPEN'],\n\tclosed: ['DECLINED', 'SUPERSEDED'],\n\tmerged: ['MERGED'],\n};\n\nconst orderParams: Partial<Record<PullRequestSorting, string>> = {\n\t'updated:desc': 'NEWEST',\n\t'updated:asc': 'OLDEST',\n};\n\n/**\n * Pull requests matching `criteria` over the requested repositories, or over the current user's relationships when\n * none are given.\n *\n * Every facet reads its own page, and the merged page is re-ordered as a whole. Each facet keeps its own\n * `nextPageStart` in the cursor, which is bound to this connection, installation and query: a cursor handed back\n * under anything else is refused rather than read as page 1 of a different search. A pull request several\n * relationships match is served by exactly one of them, the first in canonical order (see {@link ownsRow}), so facets\n * that advance independently never serve it twice across pages and the cursor carries no history of what it emitted.\n *\n * Every criterion the server applies is applied again to the rows it returns, so a server that ignores a parameter\n * (one older than 8.18, which shipped drafts, has no `draft`) narrows the page instead of silently widening it.\n *\n * A facet that fails is reported in `metadata` while its siblings still answer, and keeps its offset, so the next page\n * retries the page it missed — a transient failure recovers the rows it cost. A facet that fails its retry too is\n * dropped, and reported on every later page, which no longer reads it; one retry keeps a facet that will never answer\n * from holding `hasMore` open forever. If every facet fails on the first page, the first failure is thrown instead.\n */\nexport async function searchBitbucketServerPullRequestsPage(\n\trequest: ProviderRequestFunction,\n\ttoken: Token,\n\toptions: SearchOptions & { connectionId: string; provider: Provider; cursor?: string; pageSize?: number },\n\tcancellation?: AbortSignal,\n): Promise<ProviderPullRequestSearchPage> {\n\tconst query = toQuery(options);\n\tconst comparator = getPullRequestComparator(query.sort)!;\n\tconst key = await getCursorKey(options.connectionId, query);\n\tconst cursor = await parseCursor(options.cursor, key, query.facets);\n\tconst active = query.facets.flatMap((facet, index) =>\n\t\tcursor.starts[index] != null ? [{ facet: facet, start: cursor.starts[index], index: index }] : [],\n\t);\n\t// A facet dropped on an earlier page is gone from this one's reads, and the hole is still in the result.\n\tconst failed = [...cursor.failed];\n\tconst failures = failed.map(f => toEarlierFailure(token, query.facets[f.facet], f.kind));\n\tconst retrying: number[] = [];\n\tif (active.length === 0) {\n\t\treturn {\n\t\t\tvalues: [],\n\t\t\thasMore: false,\n\t\t\tpage: cursor.page,\n\t\t\ttruncated: cursor.truncated,\n\t\t\tmetadata: toMetadata(failures),\n\t\t};\n\t}\n\n\tconst limit = Math.min(maxPageSize, Math.max(1, Math.trunc(options.pageSize ?? defaultSearchPageSize)));\n\tconst results = await mapSettledBounded(active, facetConcurrency, ({ facet, start }) =>\n\t\treadFacetPage(request, token, query, facet, start, limit, false, cancellation),\n\t);\n\tconst rejected = results.filter((r): r is PromiseRejectedResult => r.status === 'rejected');\n\tconst cancelled = rejected.find(r => isCancellationError(r.reason));\n\tif (cancelled != null) throw cancelled.reason;\n\n\t// A rejected credential is the connection failing rather than one scope, so it is thrown on any page: the\n\t// integration's session recovery then runs once, from the thrown error, and the failure is never carried in the\n\t// cursor where every later page would report it again. (A repository refusing the token isn't one; see\n\t// `toFacetError`.)\n\tconst credential = rejected.find(r => r.reason instanceof AuthenticationError);\n\tif (credential != null) throw credential.reason;\n\t// Only a first page on which every facet failed is a failed read. On a later page an earlier one already proved\n\t// some facet answered, so the rows it served stand and this page's failures join the partial-result report.\n\tif (cursor.page === 1 && rejected.length === results.length) throw rejected[0].reason;\n\n\tconst nextStarts: (number | null)[] = cursor.starts.map(() => null);\n\tconst values: ProviderPullRequest[] = [];\n\tlet truncated = cursor.truncated;\n\tfor (let i = 0; i < results.length; i++) {\n\t\tconst { facet, index } = active[i];\n\t\tconst result = results[i];\n\t\tif (result.status === 'rejected') {\n\t\t\tconst failure = toCollectionScopeFailure(toCollectionScope(token, facet), result.reason);\n\t\t\tfailures.push(failure);\n\t\t\tif (cursor.retrying.includes(index)) {\n\t\t\t\t// Its retry failed too: dropped, and carried so every later page still reports the hole.\n\t\t\t\tfailed.push({ facet: index, kind: failure.kind });\n\t\t\t} else {\n\t\t\t\t// Kept at the offset it missed, so the next page retries it.\n\t\t\t\tnextStarts[index] = active[i].start;\n\t\t\t\tretrying.push(index);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tnextStarts[index] = result.value.next;\n\t\ttruncated ||= result.value.stalled;\n\t\tfor (const { raw, normalized } of result.value.matches) {\n\t\t\t// Another relationship owns a row they both match, and serves it from its own facet on whichever page\n\t\t\t// reaches it — which also settles two facets reaching it on this one.\n\t\t\tif (!ownsRow(raw, facet, query)) continue;\n\n\t\t\tvalues.push(normalized);\n\t\t}\n\t}\n\n\tconst hasMore = nextStarts.some(start => start != null);\n\t// Written on every continuation, complete or not, so removing it can't pass an incomplete read off as complete.\n\tconst state = { failed: failed, retrying: retrying, truncated: truncated };\n\treturn {\n\t\tvalues: values\n\t\t\t.map(pr =>\n\t\t\t\tfromProviderPullRequest(pr, options.provider, {\n\t\t\t\t\tcurrentAccount: options.currentUser?.id != null ? { id: options.currentUser.id } : undefined,\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.sort(comparator),\n\t\tcursor: hasMore\n\t\t\t? JSON.stringify({\n\t\t\t\t\tkey: key,\n\t\t\t\t\tpage: cursor.page + 1,\n\t\t\t\t\tstarts: nextStarts,\n\t\t\t\t\tstate: { ...state, signature: await signState(key, cursor.page + 1, nextStarts, state) },\n\t\t\t\t})\n\t\t\t: undefined,\n\t\thasMore: hasMore,\n\t\tpage: cursor.page,\n\t\ttruncated: truncated,\n\t\tmetadata: toMetadata(failures),\n\t};\n}\n\nfunction toMetadata(failures: CollectionScopeFailure[]): ProviderPullRequestSearchPage['metadata'] {\n\treturn failures.length > 0 ? { completeness: 'partial', failures: failures } : undefined;\n}\n\n/**\n * A facet failure carried over from an earlier page, rebuilt from the query rather than from the cursor: the cursor\n * records only which facet failed and how, so it can't name a scope or a message the read never produced.\n */\nfunction toEarlierFailure(token: Token, facet: Facet, kind: CollectionScopeFailureKind): CollectionScopeFailure {\n\treturn {\n\t\tscope: toCollectionScope(token, facet),\n\t\tkind: kind,\n\t\tmessage: 'Failed on an earlier page of this search, so later pages did not read it',\n\t};\n}\n\n/**\n * How many pull requests match `criteria`: the same facets, predicates and identity the search uses, so the count\n * is the number of distinct rows the search would return — the union of the requested states, not the largest of\n * them, since Bitbucket has no per-search ceiling for a maximum to stay under.\n *\n * Bitbucket Data Center has no count query and reports no total, so each facet reads one page of up to\n * {@link maxPageSize} and the count is a floor (`lowerBound`) when any facet had more. Unlike the search, one failed\n * facet fails the whole count: a count missing a facet is a wrong number rather than a partial one.\n */\nexport async function countBitbucketServerPullRequests(\n\trequest: ProviderRequestFunction,\n\ttoken: Token,\n\toptions: SearchOptions,\n\tcancellation?: AbortSignal,\n): Promise<ProviderPullRequestCount> {\n\tconst query = toQuery(options);\n\tconst seen = new Set<string>();\n\tlet lowerBound = false;\n\t// One facet at a time: the facade already counts several scopes concurrently.\n\tfor (const facet of query.facets) {\n\t\tconst result = await readFacetPage(request, token, query, facet, 0, maxPageSize, true, cancellation);\n\t\tfor (const { raw } of result.matches) {\n\t\t\tseen.add(toIdentity(raw));\n\t\t}\n\t\tlowerBound ||= result.next != null || result.stalled;\n\t}\n\n\treturn { count: seen.size, lowerBound: lowerBound || undefined };\n}\n\n/**\n * Resolves the criteria into the facets and predicates every page applies, refusing — by throwing, which the read\n * reports as a failed request — anything the capability table does not declare. The facade validates the same\n * table first, so reaching a refusal here means a caller bypassed it; refusing rather than dropping the criterion\n * keeps that caller from reading a wider set than it asked for.\n */\nfunction toQuery(options: SearchOptions): Query {\n\tif (options.org != null && options.org.length > 0) {\n\t\tthrow new Error('Bitbucket Data Center cannot scope a pull request search to a project');\n\t}\n\n\tconst criteria = options.criteria;\n\t// No endpoint filters by date, and filtering the rows read would page through everything before the cutoff.\n\tif (criteria?.updatedAfter != null || criteria?.createdAfter != null) {\n\t\tthrow new Error('Bitbucket Data Center cannot filter a pull request search by date');\n\t}\n\n\tconst sort = criteria?.sort ?? defaultPullRequestSort;\n\tif (orderParams[sort] == null) {\n\t\tthrow new Error(`Bitbucket Data Center cannot order a pull request search by '${sort}'`);\n\t}\n\n\tconst requested = criteria?.relationships ?? [];\n\tconst unsupported = requested.find(r => !(relationships as readonly PullRequestFilter[]).includes(r));\n\tif (unsupported != null) {\n\t\tthrow new Error(`Bitbucket Data Center cannot search pull requests by the '${unsupported}' relationship`);\n\t}\n\n\tconst facetRelationships = relationships.filter(r => requested.includes(r));\n\tif (facetRelationships.length > 0 && options.currentUser == null) {\n\t\tthrow new Error('A Bitbucket Data Center relationship search requires the current user');\n\t}\n\n\tconst requestedStates: PullRequestStateFilter[] = criteria?.states?.length ? criteria.states : ['open'];\n\tconst states = requestedStates.includes('all')\n\t\t? undefined\n\t\t: new Set(requestedStates.flatMap(s => pullRequestStates[s as Exclude<PullRequestStateFilter, 'all'>]));\n\n\t// Sorted and deduplicated so the facets, and so the cursor, don't depend on the order repositories were passed.\n\tconst repos = [...new Map((options.repos ?? []).map(r => [repoKey(r), r])).entries()]\n\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t.map(([, repo]) => repo);\n\tfor (const repo of repos) {\n\t\tfor (const segment of [repo.namespace, repo.name]) {\n\t\t\tif (!segment || segment === '.' || segment === '..') {\n\t\t\t\tthrow new Error('Invalid Bitbucket Data Center repository for a pull request search');\n\t\t\t}\n\t\t}\n\t}\n\n\tlet facets: Facet[];\n\tif (repos.length > 0) {\n\t\tconst scoped = facetRelationships.length > 0 ? facetRelationships : [undefined];\n\t\tfacets = repos.flatMap(repo => scoped.map(relationship => ({ repo: repo, relationship: relationship })));\n\t} else if (facetRelationships.length > 0) {\n\t\tfacets = facetRelationships.flatMap<Facet>(relationship =>\n\t\t\trelationship === PullRequestFilter.Reviewed\n\t\t\t\t? [\n\t\t\t\t\t\t{ relationship: relationship, role: 'REVIEWER' },\n\t\t\t\t\t\t{ relationship: relationship, role: 'PARTICIPANT' },\n\t\t\t\t\t]\n\t\t\t\t: [{ relationship: relationship }],\n\t\t);\n\t} else {\n\t\tthrow new Error('A Bitbucket Data Center pull request search must be scoped by repositories or a relationship');\n\t}\n\n\treturn { ...options, facets: facets, relationships: facetRelationships, states: states, sort: sort };\n}\n\n/** Project keys and repository slugs resolve case-insensitively, so two spellings name one repository. */\nfunction repoKey(repo: ProviderRepoInput): string {\n\treturn `${repo.namespace}/${repo.name}`.toLowerCase();\n}\n\n/**\n * A facet's classified failure, with the one correction the provider-wide classification can't make: a 403 on a\n * REPOSITORY is Bitbucket refusing that repository (the token lacks `REPO_READ` there), not the credential failing.\n *\n * Made here, where every read of a facet passes, so the search and the count can't disagree about it on any path —\n * a sibling repository's failure, a first page where every repository failed, or a count. Left an\n * `AuthenticationError`, it would reach the integration's exception handling and mark a connection that works\n * everywhere else for recovery and toward disconnecting; as a plain error naming the repository it is reported as\n * that scope's failure alone. A 401 anywhere, and a 403 on the user's own dashboard, stay the credential failing.\n */\nfunction toFacetError(ex: unknown, facet: Facet): unknown {\n\tif (!(ex instanceof AuthenticationError) || facet.repo == null) return ex;\n\tif (ex.reason !== AuthenticationErrorReason.Forbidden) return ex;\n\n\treturn new Error(\n\t\t`Bitbucket Data Center refused access to ${facet.repo.namespace}/${facet.repo.name}: ${(ex.original ?? ex).message}`,\n\t\t{ cause: ex },\n\t);\n}\n\n/** A pull request's identity across every facet and endpoint: its id is only unique within its repository. */\nfunction toIdentity(pr: BitbucketServerPullRequest): string {\n\treturn `${pr.toRef.repository.id}/${pr.id}`;\n}\n\n/**\n * Binds a cursor to everything that decides what it continues: the connection and installation it was read from,\n * the facets and every criterion. Hashed, so neither the query nor the address is published inside the cursor.\n */\nfunction getCursorKey(connectionId: string, query: Query): Promise<string> {\n\treturn sha256(\n\t\tJSON.stringify([\n\t\t\tconnectionId,\n\t\t\tquery.baseUrl,\n\t\t\tquery.facets.map(f => [f.repo != null ? repoKey(f.repo) : null, f.relationship ?? null, f.role ?? null]),\n\t\t\tquery.states != null ? [...query.states].sort() : null,\n\t\t\tquery.criteria?.text?.trim() ?? '',\n\t\t\tquery.criteria?.draft ?? null,\n\t\t\tquery.criteria?.includeArchived === true,\n\t\t\t// Both: the server filters participants by username and the rows are re-checked by id or username, so a\n\t\t\t// renamed account is a different query even under the same id.\n\t\t\tquery.currentUser != null ? [query.currentUser.id, query.currentUser.username] : null,\n\t\t\tquery.sort,\n\t\t]),\n\t);\n}\n\n/**\n * Signs a continuation — its page, every facet's offset, which facets failed, and whether a facet stalled — so an\n * edited cursor can't pass for complete: ending a facet early by nulling its offset, or claiming a failure its read\n * never had. The key only binds a cursor to its query and travels inside it; this is keyed by a secret that never\n * leaves this process, so a signature can't be recomputed outside it. A cursor that outlives the process keeps\n * continuing, and reports its read as unconfirmed rather than as complete (see {@link parseCursor}).\n */\nconst stateSecret = getNonce();\n\nfunction signState(\n\tkey: string,\n\tpage: number,\n\tstarts: (number | null)[],\n\tstate: Pick<SearchCursor, 'failed' | 'retrying' | 'truncated'>,\n): Promise<string> {\n\treturn sha256(JSON.stringify([stateSecret, key, page, starts, state.failed, state.retrying, state.truncated]));\n}\n\n/** The failure kinds a cursor may carry — the SDK's closed set, so a cursor can't name one the facade never maps. */\nconst failureKinds: ReadonlySet<string> = new Set<CollectionScopeFailureKind>([\n\t'authentication',\n\t'rate-limit',\n\t'not-found',\n\t'network',\n\t'provider',\n\t'unknown',\n]);\n\ninterface SearchCursor {\n\tpage: number;\n\tstarts: (number | null)[];\n\ttruncated: boolean;\n\t/** The facets dropped after failing their retry, by index, and how. They are never read again. */\n\tfailed: { facet: number; kind: CollectionScopeFailureKind }[];\n\t/** The facets that failed on the previous page and are retried at the offset they missed, by index. */\n\tretrying: number[];\n}\n\n/**\n * Parses a cursor this module wrote for the same connection and query.\n *\n * The key binds a cursor to its connection, installation and query, but travels inside it, so the offsets can be\n * edited; the signature below covers them, so an edited cursor still reads but can't report its read as complete. The completeness state is\n * the part that could be turned against it, so it is signed and written on every continuation. A state that is\n * missing or doesn't verify is not refused, since that is also what a cursor from an earlier process looks like, and\n * failing a read that still works helps no one; but it can't be passed off as complete either — it degrades to\n * `truncated`, \"completeness not confirmed\", without the failures it can't prove. A failure is rebuilt from the facet\n * it names regardless, so even a verified one can't name a scope or text the read never produced.\n */\nasync function parseCursor(cursor: string | undefined, key: string, facets: Facet[]): Promise<SearchCursor> {\n\tconst facetCount = facets.length;\n\tif (cursor == null || cursor === '{}') {\n\t\treturn {\n\t\t\tpage: 1,\n\t\t\tstarts: new Array<number | null>(facetCount).fill(0),\n\t\t\ttruncated: false,\n\t\t\tfailed: [],\n\t\t\tretrying: [],\n\t\t};\n\t}\n\n\tlet parsed: { key?: unknown; page?: unknown; starts?: unknown; state?: unknown } | undefined;\n\ttry {\n\t\tparsed = (JSON.parse(cursor) as typeof parsed) ?? undefined;\n\t} catch {}\n\n\tconst starts = parsed?.starts;\n\tif (\n\t\tparsed == null ||\n\t\tparsed.key !== key ||\n\t\ttypeof parsed.page !== 'number' ||\n\t\t!Number.isSafeInteger(parsed.page) ||\n\t\tparsed.page < 2 ||\n\t\t!Array.isArray(starts) ||\n\t\tstarts.length !== facetCount ||\n\t\t// 0 is a facet retrying the first page it missed; every other offset is past a page already read.\n\t\t!starts.every(start => start === null || (Number.isSafeInteger(start) && (start as number) >= 0)) ||\n\t\t!starts.some(start => start !== null)\n\t) {\n\t\tthrow new Error('Invalid Bitbucket Data Center pull request search cursor for this connection or query');\n\t}\n\n\treturn {\n\t\tpage: parsed.page,\n\t\tstarts: starts as (number | null)[],\n\t\t...(await parseState(parsed.state, key, parsed.page, starts as (number | null)[])),\n\t};\n}\n\n/**\n * The signed completeness state of a continuation, verified together with its page and offsets. Every continuation\n * carries one, so a state that is missing, malformed, not signed by this process, or signed for other offsets says\n * the read's completeness can't be confirmed — never that it was whole.\n */\nasync function parseState(\n\tstate: unknown,\n\tkey: string,\n\tpage: number,\n\tstarts: (number | null)[],\n): Promise<Pick<SearchCursor, 'failed' | 'retrying' | 'truncated'>> {\n\tconst unconfirmed = { failed: [], retrying: [], truncated: true };\n\tif (state == null || typeof state !== 'object') return unconfirmed;\n\n\tconst { failed, retrying, truncated, signature } = state as {\n\t\tfailed?: unknown;\n\t\tretrying?: unknown;\n\t\ttruncated?: unknown;\n\t\tsignature?: unknown;\n\t};\n\tif (\n\t\ttypeof truncated !== 'boolean' ||\n\t\t!Array.isArray(retrying) ||\n\t\t// A retried facet is read again, so it must still have the offset it missed.\n\t\t!retrying.every(i => Number.isSafeInteger(i) && i >= 0 && i < starts.length && starts[i as number] !== null) ||\n\t\t!Array.isArray(failed) ||\n\t\t!failed.every(\n\t\t\t(f: { facet?: unknown; kind?: unknown } | null) =>\n\t\t\t\tf != null &&\n\t\t\t\tNumber.isSafeInteger(f.facet) &&\n\t\t\t\t(f.facet as number) >= 0 &&\n\t\t\t\t(f.facet as number) < starts.length &&\n\t\t\t\t// A failed facet is never read again, so it has no offset left to continue from.\n\t\t\t\tstarts[f.facet as number] === null &&\n\t\t\t\ttypeof f.kind === 'string' &&\n\t\t\t\tfailureKinds.has(f.kind),\n\t\t)\n\t) {\n\t\treturn unconfirmed;\n\t}\n\n\tconst verified = { failed: failed as SearchCursor['failed'], retrying: retrying as number[], truncated: truncated };\n\treturn signature === (await signState(key, page, starts, verified)) ? verified : unconfirmed;\n}\n\nfunction toCollectionScope(token: Token, facet: Facet): CollectionScope {\n\treturn facet.repo != null\n\t\t? { providerId: token.providerId, repositoryId: `${facet.repo.namespace}/${facet.repo.name}` }\n\t\t: { providerId: token.providerId };\n}\n\ninterface FacetPage {\n\t/**\n\t * The rows that match the query AND map to a pull request, with their mapping. Mapped here rather than by each\n\t * caller, so the count skips exactly the rows the search can't show and the two can't disagree about them.\n\t */\n\tmatches: { raw: BitbucketServerPullRequest; normalized: ProviderPullRequest }[];\n\t/** The next page's `start`, or `null` when this facet is exhausted or can't be continued. */\n\tnext: number | null;\n\t/** The server reported another page but no offset past this one to reach it. */\n\tstalled: boolean;\n}\n\nasync function readFacetPage(\n\trequest: ProviderRequestFunction,\n\ttoken: Token,\n\tquery: Query,\n\tfacet: Facet,\n\tstart: number,\n\tlimit: number,\n\tcountOnly: boolean,\n\tcancellation: AbortSignal | undefined,\n): Promise<FacetPage> {\n\tif (cancellation?.aborted) throw new CancellationError();\n\n\tlet body: BitbucketServerPagedResponse<BitbucketServerPullRequest> | undefined;\n\ttry {\n\t\t({ body } = await request<BitbucketServerPagedResponse<BitbucketServerPullRequest>>({\n\t\t\turl: toFacetUrl(query, facet, start, limit, countOnly),\n\t\t\theaders: { Authorization: `Bearer ${token.accessToken}` },\n\t\t\t// Aborts the request itself, so a cancelled search doesn't wait on up to a page of 1,000 per facet.\n\t\t\tsignal: cancellation,\n\t\t}));\n\t\tif (\n\t\t\tbody == null ||\n\t\t\t!Array.isArray(body.values) ||\n\t\t\ttypeof body.isLastPage !== 'boolean' ||\n\t\t\tbody.start !== start\n\t\t) {\n\t\t\tthrow new Error('Invalid Bitbucket Data Center pull request page');\n\t\t}\n\t} catch (ex) {\n\t\t// A request the signal aborted is the cancellation, never a failed facet whose siblings answered.\n\t\tif (isCancellationError(ex)) throw ex;\n\t\tif (cancellation?.aborted) throw new CancellationError(ex instanceof Error ? ex : undefined);\n\n\t\ttry {\n\t\t\tthrowProviderError(token, ex);\n\t\t} catch (classified) {\n\t\t\tthrow toFacetError(classified, facet);\n\t\t}\n\t}\n\tif (cancellation?.aborted) throw new CancellationError();\n\n\tconst next = body.nextPageStart;\n\tconst more = !body.isLastPage && Number.isSafeInteger(next) && next > start;\n\tconst matches: FacetPage['matches'] = [];\n\tfor (const raw of body.values) {\n\t\tif (!matchesFacet(raw, facet, query)) continue;\n\n\t\ttry {\n\t\t\tmatches.push({ raw: raw, normalized: normalizeBitbucketServerPullRequest(raw) });\n\t\t} catch (ex) {\n\t\t\tLogger.warn(`Skipped an unmappable Bitbucket Data Center pull request; id=${raw.id}, ex=${String(ex)}`);\n\t\t}\n\t}\n\n\treturn {\n\t\tmatches: matches,\n\t\tnext: more ? next : null,\n\t\tstalled: !body.isLastPage && !more,\n\t};\n}\n\nfunction toFacetUrl(query: Query, facet: Facet, start: number, limit: number, countOnly: boolean): string {\n\tconst criteria = query.criteria;\n\t// One requested state goes to the server; several — including `closed`, which is DECLINED and SUPERSEDED — are\n\t// read as every state and kept by `matchesFacet`.\n\tconst state = query.states?.size === 1 ? [...query.states][0] : undefined;\n\tlet url: URL;\n\tif (facet.repo != null) {\n\t\turl = new URL(\n\t\t\t`${query.baseUrl}/projects/${encodeURIComponent(facet.repo.namespace)}/repos/${encodeURIComponent(\n\t\t\t\tfacet.repo.name,\n\t\t\t)}/pull-requests`,\n\t\t);\n\t\turl.searchParams.set('state', state ?? 'ALL');\n\t\tconst text = criteria?.text?.trim();\n\t\tif (text) {\n\t\t\turl.searchParams.set('filterText', text);\n\t\t}\n\t\tif (criteria?.draft != null) {\n\t\t\turl.searchParams.set('draft', String(criteria.draft));\n\t\t}\n\t\tif (facet.relationship != null) {\n\t\t\turl.searchParams.set('username.1', query.currentUser!.username);\n\t\t\tswitch (facet.relationship) {\n\t\t\t\tcase PullRequestFilter.Author:\n\t\t\t\t\turl.searchParams.set('role.1', 'AUTHOR');\n\t\t\t\t\tbreak;\n\t\t\t\tcase PullRequestFilter.ReviewRequested:\n\t\t\t\t\turl.searchParams.set('role.1', 'REVIEWER');\n\t\t\t\t\turl.searchParams.set('approved.1', 'false');\n\t\t\t\t\tbreak;\n\t\t\t\tcase PullRequestFilter.Reviewed:\n\t\t\t\t\t// Any role: a participant who isn't a listed reviewer can still approve or ask for changes.\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t// Properties carry the comment count a search row shows and a count never reads.\n\t\tif (countOnly) {\n\t\t\turl.searchParams.set('withProperties', 'false');\n\t\t}\n\t} else {\n\t\turl = new URL(`${query.baseUrl}/dashboard/pull-requests`);\n\t\t// The dashboard reads every state when `state` is omitted, and documents no `ALL`.\n\t\tif (state != null) {\n\t\t\turl.searchParams.set('state', state);\n\t\t}\n\t\tswitch (facet.relationship) {\n\t\t\tcase PullRequestFilter.Author:\n\t\t\t\turl.searchParams.set('role', 'AUTHOR');\n\t\t\t\tbreak;\n\t\t\tcase PullRequestFilter.ReviewRequested:\n\t\t\t\turl.searchParams.set('role', 'REVIEWER');\n\t\t\t\turl.searchParams.set('participantStatus', 'UNAPPROVED');\n\t\t\t\tbreak;\n\t\t\tcase PullRequestFilter.Reviewed:\n\t\t\t\t// The status only filters alongside a role (see `Facet.role`), so each of the two lists is its own facet.\n\t\t\t\turl.searchParams.set('role', facet.role!);\n\t\t\t\turl.searchParams.set('participantStatus', 'APPROVED,NEEDS_WORK');\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\turl.searchParams.set('order', orderParams[query.sort]!);\n\turl.searchParams.set('start', String(start));\n\turl.searchParams.set('limit', String(limit));\n\treturn url.toString();\n}\n\n/**\n * Re-applies every constraint of the query to a row the server returned, so what the server was asked to filter and\n * what it actually filtered can't differ in the result: the dashboard has no text or draft filter, a server older\n * than 8.18 ignores `draft`, several states are read as every state, a reviewer filter can't tell a pending review\n * from one that asked for changes, and no endpoint excludes archived repositories.\n */\nfunction matchesFacet(pr: BitbucketServerPullRequest, facet: Facet, query: Query): boolean {\n\tconst repository = pr.toRef?.repository;\n\t// Without both there is no identity to deduplicate or count it by.\n\tif (pr.id == null || repository?.id == null) return false;\n\tif (query.states != null && !query.states.has(pr.state)) return false;\n\tif (facet.repo != null && `${repository.project?.key}/${repository.slug}`.toLowerCase() !== repoKey(facet.repo)) {\n\t\treturn false;\n\t}\n\n\tconst criteria = query.criteria;\n\tif (criteria?.includeArchived !== true && repository.archived === true) return false;\n\tif (criteria?.draft != null && (pr.draft === true) !== criteria.draft) return false;\n\n\tconst text = criteria?.text?.trim().toLowerCase();\n\tif (text && !pr.title?.toLowerCase().includes(text) && !pr.description?.toLowerCase().includes(text)) {\n\t\treturn false;\n\t}\n\n\treturn facet.relationship == null || matchesRelationship(pr, facet.relationship, query.currentUser!, facet.role);\n}\n\n/**\n * Whether `facet` is the one that serves `pr`: the first requested relationship the pull request matches, in canonical\n * order. A pull request I authored and reviewed is served by the author facet alone, so the reviewed facet skips it\n * on whichever page it reaches it. Between the two `Reviewed` dashboard facets the reviewer list wins, should a\n * server ever list the user in both.\n *\n * Stateless, which is the point: two facets reach a shared row pages apart, and remembering what earlier pages emitted\n * would make the cursor grow with every row read. The rule only needs the row itself, and the count applies the same\n * union through its own deduplication, so list and count agree. One thing no page-based read can settle is a pull\n * request whose review state changes between two pages — it can then match a different relationship on each and be\n * served by both, just as a row updated mid-read can move between offsets.\n */\nfunction ownsRow(pr: BitbucketServerPullRequest, facet: Facet, query: Query): boolean {\n\tif (facet.relationship == null) return true;\n\n\tconst user = query.currentUser!;\n\tconst owner = query.relationships.find(r => matchesRelationship(pr, r, user));\n\tif (owner !== facet.relationship) return false;\n\tif (facet.role == null) return true;\n\n\tconst ownerRole: DashboardRole = matchesRelationship(pr, facet.relationship, user, 'REVIEWER')\n\t\t? 'REVIEWER'\n\t\t: 'PARTICIPANT';\n\treturn ownerRole === facet.role;\n}\n\n/** `role` narrows `Reviewed` to one participant list; every other relationship ignores it. */\nfunction matchesRelationship(\n\tpr: BitbucketServerPullRequest,\n\trelationship: Relationship,\n\tuser: BitbucketServerSearchUser,\n\trole?: DashboardRole,\n): boolean {\n\tconst isCurrentUser = (candidate: BitbucketServerUser | undefined): boolean =>\n\t\tcandidate != null &&\n\t\t(String(candidate.id) === user.id || candidate.name?.toLowerCase() === user.username.toLowerCase());\n\tconst hasStatus = (participants: BitbucketServerPullRequestUser[] | undefined, statuses: string[]): boolean =>\n\t\tparticipants?.some(p => isCurrentUser(p.user) && statuses.includes(p.status)) ?? false;\n\n\tswitch (relationship) {\n\t\tcase PullRequestFilter.Author:\n\t\t\treturn isCurrentUser(pr.author?.user);\n\t\tcase PullRequestFilter.ReviewRequested:\n\t\t\treturn hasStatus(pr.reviewers, ['UNAPPROVED']);\n\t\tcase PullRequestFilter.Reviewed:\n\t\t\treturn (\n\t\t\t\t(role !== 'PARTICIPANT' && hasStatus(pr.reviewers, ['APPROVED', 'NEEDS_WORK'])) ||\n\t\t\t\t(role !== 'REVIEWER' && hasStatus(pr.participants, ['APPROVED', 'NEEDS_WORK']))\n\t\t\t);\n\t}\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pullRequestSearch.js","names":[],"sources":["../../../../../../plus/integrations/src/providers/bitbucket-server/pullRequestSearch.ts"],"sourcesContent":["import type { CollectionScope, CollectionScopeFailure, CollectionScopeFailureKind } from '@gitkraken/provider-apis';\nimport type {\n\tPullRequestProjection,\n\tPullRequestSearchCriteria,\n\tPullRequestSorting,\n\tPullRequestStateFilter,\n} from '@gitlens/git/models/pullRequest.js';\nimport { defaultPullRequestSort, PullRequestFilter } from '@gitlens/git/models/pullRequest.js';\nimport type { Provider } from '@gitlens/git/models/remoteProvider.js';\nimport { getPullRequestComparator } from '@gitlens/git/utils/pullRequest.utils.js';\nimport { CancellationError, isCancellationError } from '@gitlens/utils/cancellation.js';\nimport { getNonce, sha256 } from '@gitlens/utils/crypto.js';\nimport { Logger } from '@gitlens/utils/logger.js';\nimport { mapSettledBounded } from '@gitlens/utils/promise.js';\nimport type { TokenWithInfo } from '../../authentication/models.js';\nimport { toCollectionScopeFailure } from '../../collectionMetadata.js';\nimport type { GitSelfManagedHostIntegrationId } from '../../constants.js';\nimport { AuthenticationError, AuthenticationErrorReason } from '../../errors.js';\nimport type { ProviderPullRequestCount, ProviderPullRequestSearchPage } from '../../models/pullRequestReads.js';\nimport type { ProviderPullRequest, ProviderRepoInput, ProviderRequestFunction } from '../models.js';\nimport { fromProviderPullRequest } from '../models.js';\nimport { throwProviderError } from '../providerErrors.js';\nimport type {\n\tBitbucketServerPagedResponse,\n\tBitbucketServerPullRequest,\n\tBitbucketServerPullRequestUser,\n\tBitbucketServerUser,\n} from './models.js';\nimport { normalizeBitbucketServerPullRequest } from './models.js';\n\ntype Token = TokenWithInfo<GitSelfManagedHostIntegrationId.BitbucketServer>;\ntype BitbucketServerPullRequestState = BitbucketServerPullRequest['state'];\n\n/**\n * The relationships Bitbucket Data Center can express, in the canonical order its facets (and so its cursor) are\n * built in. A Bitbucket pull request has no assignee, and none of its pull-request endpoints filter by mention.\n */\nconst relationships = [\n\tPullRequestFilter.Author,\n\tPullRequestFilter.ReviewRequested,\n\tPullRequestFilter.Reviewed,\n] as const;\ntype Relationship = (typeof relationships)[number];\n\n/** The current user, which both the server-side participant filters and their client-side re-check identify. */\nexport interface BitbucketServerSearchUser {\n\tid: string;\n\tusername: string;\n}\n\n/**\n * One provider query of the search: a repository or the current user's dashboard, times one relationship.\n *\n * A repository facet reads `/projects/{key}/repos/{slug}/pull-requests`, which filters participants, text and draft\n * state server-side, so a page narrowed to a few repositories holds only matches. Without repositories a relationship\n * reads `/dashboard/pull-requests`, the only cross-repository pull-request list Bitbucket Data Center has; it can't\n * filter text or draft state, so those are re-checked on its rows. There is no project-wide list at all, which is\n * why the capability declares no organization scope.\n *\n * States are not a facet axis: every facet asks the server for the one requested state, or for every state when\n * several are requested, and keeps the requested ones — reading the unrequested rows rather than spending one more\n * request per state.\n */\ninterface Facet {\n\trepo?: ProviderRepoInput;\n\trelationship?: Relationship;\n\t/**\n\t * The dashboard role a `Reviewed` facet reads. The dashboard only applies `participantStatus` together with\n\t * `role` — without one it returns every pull request the user is involved in, authored ones included, whatever\n\t * the status — so `Reviewed` is read as two facets, the reviewer list and the (non-reviewer) participant list,\n\t * each filtered by status server-side. Absent for every other facet.\n\t */\n\trole?: DashboardRole;\n}\n\ntype DashboardRole = 'REVIEWER' | 'PARTICIPANT';\n\ninterface SearchOptions {\n\tbaseUrl: string;\n\trepos?: ProviderRepoInput[];\n\t/** Refused when set: Bitbucket Data Center has no project-wide pull-request list to scope it to. */\n\torg?: string;\n\tcriteria?: PullRequestSearchCriteria;\n\t/** Required when `criteria.relationships` is non-empty. */\n\tcurrentUser?: BitbucketServerSearchUser;\n}\n\n/** A resolved query, shared by every facet of one search or count. */\ninterface Query extends SearchOptions {\n\tfacets: Facet[];\n\t/** The requested relationships, in canonical order — the order {@link ownsRow} gives a shared row to. */\n\trelationships: Relationship[];\n\t/** The requested states, or `undefined` for every state. */\n\tstates: Set<BitbucketServerPullRequestState> | undefined;\n\tsort: PullRequestSorting;\n}\n\n/** Bitbucket answers an unspecified page size with 25; a search page asks for this many per facet instead. */\nconst defaultSearchPageSize = 30;\n/**\n * The server's own cap on a page (`page.max.pullrequests`, 1000 unless an administrator lowered it), and the one\n * page a count reads per facet: past it the count is a floor rather than more of a customer-run server's capacity\n * spent on a figure the caller uses as a cost hint.\n */\nconst maxPageSize = 1000;\n/** Matches the SDK's own cap on concurrent Bitbucket Data Center pull-request requests. */\nconst facetConcurrency = 5;\n\n/** The server states each facade state covers. `closed` is two, so it can't be sent as one `state` filter. */\nconst pullRequestStates: Record<Exclude<PullRequestStateFilter, 'all'>, BitbucketServerPullRequestState[]> = {\n\topen: ['OPEN'],\n\tclosed: ['DECLINED', 'SUPERSEDED'],\n\tmerged: ['MERGED'],\n};\n\nconst orderParams: Partial<Record<PullRequestSorting, string>> = {\n\t'updated:desc': 'NEWEST',\n\t'updated:asc': 'OLDEST',\n};\n\n/**\n * Pull requests matching `criteria` over the requested repositories, or over the current user's relationships when\n * none are given.\n *\n * Every facet reads its own page, and the merged page is re-ordered as a whole. Each facet keeps its own\n * `nextPageStart` in the cursor, which is bound to this connection, installation and query: a cursor handed back\n * under anything else is refused rather than read as page 1 of a different search. A pull request several\n * relationships match is served by exactly one of them, the first in canonical order (see {@link ownsRow}), so facets\n * that advance independently never serve it twice across pages and the cursor carries no history of what it emitted.\n *\n * Every criterion the server applies is applied again to the rows it returns, so a server that ignores a parameter\n * (one older than 8.18, which shipped drafts, has no `draft`) narrows the page instead of silently widening it.\n *\n * A facet that fails is reported in `metadata` while its siblings still answer, and keeps its offset, so the next page\n * retries the page it missed — a transient failure recovers the rows it cost. A facet that fails its retry too is\n * dropped, and reported on every later page, which no longer reads it; one retry keeps a facet that will never answer\n * from holding `hasMore` open forever. If every facet fails on the first page, the first failure is thrown instead.\n */\nexport async function searchBitbucketServerPullRequestsPage(\n\trequest: ProviderRequestFunction,\n\ttoken: Token,\n\toptions: SearchOptions & {\n\t\tconnectionId: string;\n\t\tprovider: Provider;\n\t\tcursor?: string;\n\t\tpageSize?: number;\n\t\t/** The calling read, stamped on every row. */\n\t\tprojection?: PullRequestProjection;\n\t},\n\tcancellation?: AbortSignal,\n): Promise<ProviderPullRequestSearchPage> {\n\tconst query = toQuery(options);\n\tconst comparator = getPullRequestComparator(query.sort)!;\n\tconst key = await getCursorKey(options.connectionId, query);\n\tconst cursor = await parseCursor(options.cursor, key, query.facets);\n\tconst active = query.facets.flatMap((facet, index) =>\n\t\tcursor.starts[index] != null ? [{ facet: facet, start: cursor.starts[index], index: index }] : [],\n\t);\n\t// A facet dropped on an earlier page is gone from this one's reads, and the hole is still in the result.\n\tconst failed = [...cursor.failed];\n\tconst failures = failed.map(f => toEarlierFailure(token, query.facets[f.facet], f.kind));\n\tconst retrying: number[] = [];\n\tif (active.length === 0) {\n\t\treturn {\n\t\t\tvalues: [],\n\t\t\thasMore: false,\n\t\t\tpage: cursor.page,\n\t\t\ttruncated: cursor.truncated,\n\t\t\tmetadata: toMetadata(failures),\n\t\t};\n\t}\n\n\tconst limit = Math.min(maxPageSize, Math.max(1, Math.trunc(options.pageSize ?? defaultSearchPageSize)));\n\tconst results = await mapSettledBounded(active, facetConcurrency, ({ facet, start }) =>\n\t\treadFacetPage(request, token, query, facet, start, limit, false, cancellation),\n\t);\n\tconst rejected = results.filter((r): r is PromiseRejectedResult => r.status === 'rejected');\n\tconst cancelled = rejected.find(r => isCancellationError(r.reason));\n\tif (cancelled != null) throw cancelled.reason;\n\n\t// A rejected credential is the connection failing rather than one scope, so it is thrown on any page: the\n\t// integration's session recovery then runs once, from the thrown error, and the failure is never carried in the\n\t// cursor where every later page would report it again. (A repository refusing the token isn't one; see\n\t// `toFacetError`.)\n\tconst credential = rejected.find(r => r.reason instanceof AuthenticationError);\n\tif (credential != null) throw credential.reason;\n\t// Only a first page on which every facet failed is a failed read. On a later page an earlier one already proved\n\t// some facet answered, so the rows it served stand and this page's failures join the partial-result report.\n\tif (cursor.page === 1 && rejected.length === results.length) throw rejected[0].reason;\n\n\tconst nextStarts: (number | null)[] = cursor.starts.map(() => null);\n\tconst values: ProviderPullRequest[] = [];\n\tlet truncated = cursor.truncated;\n\tfor (let i = 0; i < results.length; i++) {\n\t\tconst { facet, index } = active[i];\n\t\tconst result = results[i];\n\t\tif (result.status === 'rejected') {\n\t\t\tconst failure = toCollectionScopeFailure(toCollectionScope(token, facet), result.reason);\n\t\t\tfailures.push(failure);\n\t\t\tif (cursor.retrying.includes(index)) {\n\t\t\t\t// Its retry failed too: dropped, and carried so every later page still reports the hole.\n\t\t\t\tfailed.push({ facet: index, kind: failure.kind });\n\t\t\t} else {\n\t\t\t\t// Kept at the offset it missed, so the next page retries it.\n\t\t\t\tnextStarts[index] = active[i].start;\n\t\t\t\tretrying.push(index);\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tnextStarts[index] = result.value.next;\n\t\ttruncated ||= result.value.stalled;\n\t\tfor (const { raw, normalized } of result.value.matches) {\n\t\t\t// Another relationship owns a row they both match, and serves it from its own facet on whichever page\n\t\t\t// reaches it — which also settles two facets reaching it on this one.\n\t\t\tif (!ownsRow(raw, facet, query)) continue;\n\n\t\t\tvalues.push(normalized);\n\t\t}\n\t}\n\n\tconst hasMore = nextStarts.some(start => start != null);\n\t// Written on every continuation, complete or not, so removing it can't pass an incomplete read off as complete.\n\tconst state = { failed: failed, retrying: retrying, truncated: truncated };\n\treturn {\n\t\tvalues: values\n\t\t\t.map(pr =>\n\t\t\t\tfromProviderPullRequest(pr, options.provider, {\n\t\t\t\t\tcurrentAccount: options.currentUser?.id != null ? { id: options.currentUser.id } : undefined,\n\t\t\t\t\tprojection: options.projection,\n\t\t\t\t}),\n\t\t\t)\n\t\t\t.sort(comparator),\n\t\tcursor: hasMore\n\t\t\t? JSON.stringify({\n\t\t\t\t\tkey: key,\n\t\t\t\t\tpage: cursor.page + 1,\n\t\t\t\t\tstarts: nextStarts,\n\t\t\t\t\tstate: { ...state, signature: await signState(key, cursor.page + 1, nextStarts, state) },\n\t\t\t\t})\n\t\t\t: undefined,\n\t\thasMore: hasMore,\n\t\tpage: cursor.page,\n\t\ttruncated: truncated,\n\t\tmetadata: toMetadata(failures),\n\t};\n}\n\nfunction toMetadata(failures: CollectionScopeFailure[]): ProviderPullRequestSearchPage['metadata'] {\n\treturn failures.length > 0 ? { completeness: 'partial', failures: failures } : undefined;\n}\n\n/**\n * A facet failure carried over from an earlier page, rebuilt from the query rather than from the cursor: the cursor\n * records only which facet failed and how, so it can't name a scope or a message the read never produced.\n */\nfunction toEarlierFailure(token: Token, facet: Facet, kind: CollectionScopeFailureKind): CollectionScopeFailure {\n\treturn {\n\t\tscope: toCollectionScope(token, facet),\n\t\tkind: kind,\n\t\tmessage: 'Failed on an earlier page of this search, so later pages did not read it',\n\t};\n}\n\n/**\n * How many pull requests match `criteria`: the same facets, predicates and identity the search uses, so the count\n * is the number of distinct rows the search would return — the union of the requested states, not the largest of\n * them, since Bitbucket has no per-search ceiling for a maximum to stay under.\n *\n * Bitbucket Data Center has no count query and reports no total, so each facet reads one page of up to\n * {@link maxPageSize} and the count is a floor (`lowerBound`) when any facet had more. Unlike the search, one failed\n * facet fails the whole count: a count missing a facet is a wrong number rather than a partial one.\n */\nexport async function countBitbucketServerPullRequests(\n\trequest: ProviderRequestFunction,\n\ttoken: Token,\n\toptions: SearchOptions,\n\tcancellation?: AbortSignal,\n): Promise<ProviderPullRequestCount> {\n\tconst query = toQuery(options);\n\tconst seen = new Set<string>();\n\tlet lowerBound = false;\n\t// One facet at a time: the facade already counts several scopes concurrently.\n\tfor (const facet of query.facets) {\n\t\tconst result = await readFacetPage(request, token, query, facet, 0, maxPageSize, true, cancellation);\n\t\tfor (const { raw } of result.matches) {\n\t\t\tseen.add(toIdentity(raw));\n\t\t}\n\t\tlowerBound ||= result.next != null || result.stalled;\n\t}\n\n\treturn { count: seen.size, lowerBound: lowerBound || undefined };\n}\n\n/**\n * Resolves the criteria into the facets and predicates every page applies, refusing — by throwing, which the read\n * reports as a failed request — anything the capability table does not declare. The facade validates the same\n * table first, so reaching a refusal here means a caller bypassed it; refusing rather than dropping the criterion\n * keeps that caller from reading a wider set than it asked for.\n */\nfunction toQuery(options: SearchOptions): Query {\n\tif (options.org != null && options.org.length > 0) {\n\t\tthrow new Error('Bitbucket Data Center cannot scope a pull request search to a project');\n\t}\n\n\tconst criteria = options.criteria;\n\t// No endpoint filters by date, and filtering the rows read would page through everything before the cutoff.\n\tif (criteria?.updatedAfter != null || criteria?.createdAfter != null) {\n\t\tthrow new Error('Bitbucket Data Center cannot filter a pull request search by date');\n\t}\n\n\tconst sort = criteria?.sort ?? defaultPullRequestSort;\n\tif (orderParams[sort] == null) {\n\t\tthrow new Error(`Bitbucket Data Center cannot order a pull request search by '${sort}'`);\n\t}\n\n\tconst requested = criteria?.relationships ?? [];\n\tconst unsupported = requested.find(r => !(relationships as readonly PullRequestFilter[]).includes(r));\n\tif (unsupported != null) {\n\t\tthrow new Error(`Bitbucket Data Center cannot search pull requests by the '${unsupported}' relationship`);\n\t}\n\n\tconst facetRelationships = relationships.filter(r => requested.includes(r));\n\tif (facetRelationships.length > 0 && options.currentUser == null) {\n\t\tthrow new Error('A Bitbucket Data Center relationship search requires the current user');\n\t}\n\n\tconst requestedStates: PullRequestStateFilter[] = criteria?.states?.length ? criteria.states : ['open'];\n\tconst states = requestedStates.includes('all')\n\t\t? undefined\n\t\t: new Set(requestedStates.flatMap(s => pullRequestStates[s as Exclude<PullRequestStateFilter, 'all'>]));\n\n\t// Sorted and deduplicated so the facets, and so the cursor, don't depend on the order repositories were passed.\n\tconst repos = [...new Map((options.repos ?? []).map(r => [repoKey(r), r])).entries()]\n\t\t.sort(([a], [b]) => a.localeCompare(b))\n\t\t.map(([, repo]) => repo);\n\tfor (const repo of repos) {\n\t\tfor (const segment of [repo.namespace, repo.name]) {\n\t\t\tif (!segment || segment === '.' || segment === '..') {\n\t\t\t\tthrow new Error('Invalid Bitbucket Data Center repository for a pull request search');\n\t\t\t}\n\t\t}\n\t}\n\n\tlet facets: Facet[];\n\tif (repos.length > 0) {\n\t\tconst scoped = facetRelationships.length > 0 ? facetRelationships : [undefined];\n\t\tfacets = repos.flatMap(repo => scoped.map(relationship => ({ repo: repo, relationship: relationship })));\n\t} else if (facetRelationships.length > 0) {\n\t\tfacets = facetRelationships.flatMap<Facet>(relationship =>\n\t\t\trelationship === PullRequestFilter.Reviewed\n\t\t\t\t? [\n\t\t\t\t\t\t{ relationship: relationship, role: 'REVIEWER' },\n\t\t\t\t\t\t{ relationship: relationship, role: 'PARTICIPANT' },\n\t\t\t\t\t]\n\t\t\t\t: [{ relationship: relationship }],\n\t\t);\n\t} else {\n\t\tthrow new Error('A Bitbucket Data Center pull request search must be scoped by repositories or a relationship');\n\t}\n\n\treturn { ...options, facets: facets, relationships: facetRelationships, states: states, sort: sort };\n}\n\n/** Project keys and repository slugs resolve case-insensitively, so two spellings name one repository. */\nfunction repoKey(repo: ProviderRepoInput): string {\n\treturn `${repo.namespace}/${repo.name}`.toLowerCase();\n}\n\n/**\n * A facet's classified failure, with the one correction the provider-wide classification can't make: a 403 on a\n * REPOSITORY is Bitbucket refusing that repository (the token lacks `REPO_READ` there), not the credential failing.\n *\n * Made here, where every read of a facet passes, so the search and the count can't disagree about it on any path —\n * a sibling repository's failure, a first page where every repository failed, or a count. Left an\n * `AuthenticationError`, it would reach the integration's exception handling and mark a connection that works\n * everywhere else for recovery and toward disconnecting; as a plain error naming the repository it is reported as\n * that scope's failure alone. A 401 anywhere, and a 403 on the user's own dashboard, stay the credential failing.\n */\nfunction toFacetError(ex: unknown, facet: Facet): unknown {\n\tif (!(ex instanceof AuthenticationError) || facet.repo == null) return ex;\n\tif (ex.reason !== AuthenticationErrorReason.Forbidden) return ex;\n\n\treturn new Error(\n\t\t`Bitbucket Data Center refused access to ${facet.repo.namespace}/${facet.repo.name}: ${(ex.original ?? ex).message}`,\n\t\t{ cause: ex },\n\t);\n}\n\n/** A pull request's identity across every facet and endpoint: its id is only unique within its repository. */\nfunction toIdentity(pr: BitbucketServerPullRequest): string {\n\treturn `${pr.toRef.repository.id}/${pr.id}`;\n}\n\n/**\n * Binds a cursor to everything that decides what it continues: the connection and installation it was read from,\n * the facets and every criterion. Hashed, so neither the query nor the address is published inside the cursor.\n */\nfunction getCursorKey(connectionId: string, query: Query): Promise<string> {\n\treturn sha256(\n\t\tJSON.stringify([\n\t\t\tconnectionId,\n\t\t\tquery.baseUrl,\n\t\t\tquery.facets.map(f => [f.repo != null ? repoKey(f.repo) : null, f.relationship ?? null, f.role ?? null]),\n\t\t\tquery.states != null ? [...query.states].sort() : null,\n\t\t\tquery.criteria?.text?.trim() ?? '',\n\t\t\tquery.criteria?.draft ?? null,\n\t\t\tquery.criteria?.includeArchived === true,\n\t\t\t// Both: the server filters participants by username and the rows are re-checked by id or username, so a\n\t\t\t// renamed account is a different query even under the same id.\n\t\t\tquery.currentUser != null ? [query.currentUser.id, query.currentUser.username] : null,\n\t\t\tquery.sort,\n\t\t]),\n\t);\n}\n\n/**\n * Signs a continuation — its page, every facet's offset, which facets failed, and whether a facet stalled — so an\n * edited cursor can't pass for complete: ending a facet early by nulling its offset, or claiming a failure its read\n * never had. The key only binds a cursor to its query and travels inside it; this is keyed by a secret that never\n * leaves this process, so a signature can't be recomputed outside it. A cursor that outlives the process keeps\n * continuing, and reports its read as unconfirmed rather than as complete (see {@link parseCursor}).\n */\nconst stateSecret = getNonce();\n\nfunction signState(\n\tkey: string,\n\tpage: number,\n\tstarts: (number | null)[],\n\tstate: Pick<SearchCursor, 'failed' | 'retrying' | 'truncated'>,\n): Promise<string> {\n\treturn sha256(JSON.stringify([stateSecret, key, page, starts, state.failed, state.retrying, state.truncated]));\n}\n\n/** The failure kinds a cursor may carry — the SDK's closed set, so a cursor can't name one the facade never maps. */\nconst failureKinds: ReadonlySet<string> = new Set<CollectionScopeFailureKind>([\n\t'authentication',\n\t'rate-limit',\n\t'not-found',\n\t'network',\n\t'provider',\n\t'unknown',\n]);\n\ninterface SearchCursor {\n\tpage: number;\n\tstarts: (number | null)[];\n\ttruncated: boolean;\n\t/** The facets dropped after failing their retry, by index, and how. They are never read again. */\n\tfailed: { facet: number; kind: CollectionScopeFailureKind }[];\n\t/** The facets that failed on the previous page and are retried at the offset they missed, by index. */\n\tretrying: number[];\n}\n\n/**\n * Parses a cursor this module wrote for the same connection and query.\n *\n * The key binds a cursor to its connection, installation and query, but travels inside it, so the offsets can be\n * edited; the signature below covers them, so an edited cursor still reads but can't report its read as complete. The completeness state is\n * the part that could be turned against it, so it is signed and written on every continuation. A state that is\n * missing or doesn't verify is not refused, since that is also what a cursor from an earlier process looks like, and\n * failing a read that still works helps no one; but it can't be passed off as complete either — it degrades to\n * `truncated`, \"completeness not confirmed\", without the failures it can't prove. A failure is rebuilt from the facet\n * it names regardless, so even a verified one can't name a scope or text the read never produced.\n */\nasync function parseCursor(cursor: string | undefined, key: string, facets: Facet[]): Promise<SearchCursor> {\n\tconst facetCount = facets.length;\n\tif (cursor == null || cursor === '{}') {\n\t\treturn {\n\t\t\tpage: 1,\n\t\t\tstarts: new Array<number | null>(facetCount).fill(0),\n\t\t\ttruncated: false,\n\t\t\tfailed: [],\n\t\t\tretrying: [],\n\t\t};\n\t}\n\n\tlet parsed: { key?: unknown; page?: unknown; starts?: unknown; state?: unknown } | undefined;\n\ttry {\n\t\tparsed = (JSON.parse(cursor) as typeof parsed) ?? undefined;\n\t} catch {}\n\n\tconst starts = parsed?.starts;\n\tif (\n\t\tparsed == null ||\n\t\tparsed.key !== key ||\n\t\ttypeof parsed.page !== 'number' ||\n\t\t!Number.isSafeInteger(parsed.page) ||\n\t\tparsed.page < 2 ||\n\t\t!Array.isArray(starts) ||\n\t\tstarts.length !== facetCount ||\n\t\t// 0 is a facet retrying the first page it missed; every other offset is past a page already read.\n\t\t!starts.every(start => start === null || (Number.isSafeInteger(start) && (start as number) >= 0)) ||\n\t\t!starts.some(start => start !== null)\n\t) {\n\t\tthrow new Error('Invalid Bitbucket Data Center pull request search cursor for this connection or query');\n\t}\n\n\treturn {\n\t\tpage: parsed.page,\n\t\tstarts: starts as (number | null)[],\n\t\t...(await parseState(parsed.state, key, parsed.page, starts as (number | null)[])),\n\t};\n}\n\n/**\n * The signed completeness state of a continuation, verified together with its page and offsets. Every continuation\n * carries one, so a state that is missing, malformed, not signed by this process, or signed for other offsets says\n * the read's completeness can't be confirmed — never that it was whole.\n */\nasync function parseState(\n\tstate: unknown,\n\tkey: string,\n\tpage: number,\n\tstarts: (number | null)[],\n): Promise<Pick<SearchCursor, 'failed' | 'retrying' | 'truncated'>> {\n\tconst unconfirmed = { failed: [], retrying: [], truncated: true };\n\tif (state == null || typeof state !== 'object') return unconfirmed;\n\n\tconst { failed, retrying, truncated, signature } = state as {\n\t\tfailed?: unknown;\n\t\tretrying?: unknown;\n\t\ttruncated?: unknown;\n\t\tsignature?: unknown;\n\t};\n\tif (\n\t\ttypeof truncated !== 'boolean' ||\n\t\t!Array.isArray(retrying) ||\n\t\t// A retried facet is read again, so it must still have the offset it missed.\n\t\t!retrying.every(i => Number.isSafeInteger(i) && i >= 0 && i < starts.length && starts[i as number] !== null) ||\n\t\t!Array.isArray(failed) ||\n\t\t!failed.every(\n\t\t\t(f: { facet?: unknown; kind?: unknown } | null) =>\n\t\t\t\tf != null &&\n\t\t\t\tNumber.isSafeInteger(f.facet) &&\n\t\t\t\t(f.facet as number) >= 0 &&\n\t\t\t\t(f.facet as number) < starts.length &&\n\t\t\t\t// A failed facet is never read again, so it has no offset left to continue from.\n\t\t\t\tstarts[f.facet as number] === null &&\n\t\t\t\ttypeof f.kind === 'string' &&\n\t\t\t\tfailureKinds.has(f.kind),\n\t\t)\n\t) {\n\t\treturn unconfirmed;\n\t}\n\n\tconst verified = { failed: failed as SearchCursor['failed'], retrying: retrying as number[], truncated: truncated };\n\treturn signature === (await signState(key, page, starts, verified)) ? verified : unconfirmed;\n}\n\nfunction toCollectionScope(token: Token, facet: Facet): CollectionScope {\n\treturn facet.repo != null\n\t\t? { providerId: token.providerId, repositoryId: `${facet.repo.namespace}/${facet.repo.name}` }\n\t\t: { providerId: token.providerId };\n}\n\ninterface FacetPage {\n\t/**\n\t * The rows that match the query AND map to a pull request, with their mapping. Mapped here rather than by each\n\t * caller, so the count skips exactly the rows the search can't show and the two can't disagree about them.\n\t */\n\tmatches: { raw: BitbucketServerPullRequest; normalized: ProviderPullRequest }[];\n\t/** The next page's `start`, or `null` when this facet is exhausted or can't be continued. */\n\tnext: number | null;\n\t/** The server reported another page but no offset past this one to reach it. */\n\tstalled: boolean;\n}\n\nasync function readFacetPage(\n\trequest: ProviderRequestFunction,\n\ttoken: Token,\n\tquery: Query,\n\tfacet: Facet,\n\tstart: number,\n\tlimit: number,\n\tcountOnly: boolean,\n\tcancellation: AbortSignal | undefined,\n): Promise<FacetPage> {\n\tif (cancellation?.aborted) throw new CancellationError();\n\n\tlet body: BitbucketServerPagedResponse<BitbucketServerPullRequest> | undefined;\n\ttry {\n\t\t({ body } = await request<BitbucketServerPagedResponse<BitbucketServerPullRequest>>({\n\t\t\turl: toFacetUrl(query, facet, start, limit, countOnly),\n\t\t\theaders: { Authorization: `Bearer ${token.accessToken}` },\n\t\t\t// Aborts the request itself, so a cancelled search doesn't wait on up to a page of 1,000 per facet.\n\t\t\tsignal: cancellation,\n\t\t}));\n\t\tif (\n\t\t\tbody == null ||\n\t\t\t!Array.isArray(body.values) ||\n\t\t\ttypeof body.isLastPage !== 'boolean' ||\n\t\t\tbody.start !== start\n\t\t) {\n\t\t\tthrow new Error('Invalid Bitbucket Data Center pull request page');\n\t\t}\n\t} catch (ex) {\n\t\t// A request the signal aborted is the cancellation, never a failed facet whose siblings answered.\n\t\tif (isCancellationError(ex)) throw ex;\n\t\tif (cancellation?.aborted) throw new CancellationError(ex instanceof Error ? ex : undefined);\n\n\t\ttry {\n\t\t\tthrowProviderError(token, ex);\n\t\t} catch (classified) {\n\t\t\tthrow toFacetError(classified, facet);\n\t\t}\n\t}\n\tif (cancellation?.aborted) throw new CancellationError();\n\n\tconst next = body.nextPageStart;\n\tconst more = !body.isLastPage && Number.isSafeInteger(next) && next > start;\n\tconst matches: FacetPage['matches'] = [];\n\tfor (const raw of body.values) {\n\t\tif (!matchesFacet(raw, facet, query)) continue;\n\n\t\ttry {\n\t\t\tmatches.push({ raw: raw, normalized: normalizeBitbucketServerPullRequest(raw) });\n\t\t} catch (ex) {\n\t\t\tLogger.warn(`Skipped an unmappable Bitbucket Data Center pull request; id=${raw.id}, ex=${String(ex)}`);\n\t\t}\n\t}\n\n\treturn {\n\t\tmatches: matches,\n\t\tnext: more ? next : null,\n\t\tstalled: !body.isLastPage && !more,\n\t};\n}\n\nfunction toFacetUrl(query: Query, facet: Facet, start: number, limit: number, countOnly: boolean): string {\n\tconst criteria = query.criteria;\n\t// One requested state goes to the server; several — including `closed`, which is DECLINED and SUPERSEDED — are\n\t// read as every state and kept by `matchesFacet`.\n\tconst state = query.states?.size === 1 ? [...query.states][0] : undefined;\n\tlet url: URL;\n\tif (facet.repo != null) {\n\t\turl = new URL(\n\t\t\t`${query.baseUrl}/projects/${encodeURIComponent(facet.repo.namespace)}/repos/${encodeURIComponent(\n\t\t\t\tfacet.repo.name,\n\t\t\t)}/pull-requests`,\n\t\t);\n\t\turl.searchParams.set('state', state ?? 'ALL');\n\t\tconst text = criteria?.text?.trim();\n\t\tif (text) {\n\t\t\turl.searchParams.set('filterText', text);\n\t\t}\n\t\tif (criteria?.draft != null) {\n\t\t\turl.searchParams.set('draft', String(criteria.draft));\n\t\t}\n\t\tif (facet.relationship != null) {\n\t\t\turl.searchParams.set('username.1', query.currentUser!.username);\n\t\t\tswitch (facet.relationship) {\n\t\t\t\tcase PullRequestFilter.Author:\n\t\t\t\t\turl.searchParams.set('role.1', 'AUTHOR');\n\t\t\t\t\tbreak;\n\t\t\t\tcase PullRequestFilter.ReviewRequested:\n\t\t\t\t\turl.searchParams.set('role.1', 'REVIEWER');\n\t\t\t\t\turl.searchParams.set('approved.1', 'false');\n\t\t\t\t\tbreak;\n\t\t\t\tcase PullRequestFilter.Reviewed:\n\t\t\t\t\t// Any role: a participant who isn't a listed reviewer can still approve or ask for changes.\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\t// Properties carry the comment count a search row shows and a count never reads.\n\t\tif (countOnly) {\n\t\t\turl.searchParams.set('withProperties', 'false');\n\t\t}\n\t} else {\n\t\turl = new URL(`${query.baseUrl}/dashboard/pull-requests`);\n\t\t// The dashboard reads every state when `state` is omitted, and documents no `ALL`.\n\t\tif (state != null) {\n\t\t\turl.searchParams.set('state', state);\n\t\t}\n\t\tswitch (facet.relationship) {\n\t\t\tcase PullRequestFilter.Author:\n\t\t\t\turl.searchParams.set('role', 'AUTHOR');\n\t\t\t\tbreak;\n\t\t\tcase PullRequestFilter.ReviewRequested:\n\t\t\t\turl.searchParams.set('role', 'REVIEWER');\n\t\t\t\turl.searchParams.set('participantStatus', 'UNAPPROVED');\n\t\t\t\tbreak;\n\t\t\tcase PullRequestFilter.Reviewed:\n\t\t\t\t// The status only filters alongside a role (see `Facet.role`), so each of the two lists is its own facet.\n\t\t\t\turl.searchParams.set('role', facet.role!);\n\t\t\t\turl.searchParams.set('participantStatus', 'APPROVED,NEEDS_WORK');\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\turl.searchParams.set('order', orderParams[query.sort]!);\n\turl.searchParams.set('start', String(start));\n\turl.searchParams.set('limit', String(limit));\n\treturn url.toString();\n}\n\n/**\n * Re-applies every constraint of the query to a row the server returned, so what the server was asked to filter and\n * what it actually filtered can't differ in the result: the dashboard has no text or draft filter, a server older\n * than 8.18 ignores `draft`, several states are read as every state, a reviewer filter can't tell a pending review\n * from one that asked for changes, and no endpoint excludes archived repositories.\n */\nfunction matchesFacet(pr: BitbucketServerPullRequest, facet: Facet, query: Query): boolean {\n\tconst repository = pr.toRef?.repository;\n\t// Without both there is no identity to deduplicate or count it by.\n\tif (pr.id == null || repository?.id == null) return false;\n\tif (query.states != null && !query.states.has(pr.state)) return false;\n\tif (facet.repo != null && `${repository.project?.key}/${repository.slug}`.toLowerCase() !== repoKey(facet.repo)) {\n\t\treturn false;\n\t}\n\n\tconst criteria = query.criteria;\n\tif (criteria?.includeArchived !== true && repository.archived === true) return false;\n\tif (criteria?.draft != null && (pr.draft === true) !== criteria.draft) return false;\n\n\tconst text = criteria?.text?.trim().toLowerCase();\n\tif (text && !pr.title?.toLowerCase().includes(text) && !pr.description?.toLowerCase().includes(text)) {\n\t\treturn false;\n\t}\n\n\treturn facet.relationship == null || matchesRelationship(pr, facet.relationship, query.currentUser!, facet.role);\n}\n\n/**\n * Whether `facet` is the one that serves `pr`: the first requested relationship the pull request matches, in canonical\n * order. A pull request I authored and reviewed is served by the author facet alone, so the reviewed facet skips it\n * on whichever page it reaches it. Between the two `Reviewed` dashboard facets the reviewer list wins, should a\n * server ever list the user in both.\n *\n * Stateless, which is the point: two facets reach a shared row pages apart, and remembering what earlier pages emitted\n * would make the cursor grow with every row read. The rule only needs the row itself, and the count applies the same\n * union through its own deduplication, so list and count agree. One thing no page-based read can settle is a pull\n * request whose review state changes between two pages — it can then match a different relationship on each and be\n * served by both, just as a row updated mid-read can move between offsets.\n */\nfunction ownsRow(pr: BitbucketServerPullRequest, facet: Facet, query: Query): boolean {\n\tif (facet.relationship == null) return true;\n\n\tconst user = query.currentUser!;\n\tconst owner = query.relationships.find(r => matchesRelationship(pr, r, user));\n\tif (owner !== facet.relationship) return false;\n\tif (facet.role == null) return true;\n\n\tconst ownerRole: DashboardRole = matchesRelationship(pr, facet.relationship, user, 'REVIEWER')\n\t\t? 'REVIEWER'\n\t\t: 'PARTICIPANT';\n\treturn ownerRole === facet.role;\n}\n\n/** `role` narrows `Reviewed` to one participant list; every other relationship ignores it. */\nfunction matchesRelationship(\n\tpr: BitbucketServerPullRequest,\n\trelationship: Relationship,\n\tuser: BitbucketServerSearchUser,\n\trole?: DashboardRole,\n): boolean {\n\tconst isCurrentUser = (candidate: BitbucketServerUser | undefined): boolean =>\n\t\tcandidate != null &&\n\t\t(String(candidate.id) === user.id || candidate.name?.toLowerCase() === user.username.toLowerCase());\n\tconst hasStatus = (participants: BitbucketServerPullRequestUser[] | undefined, statuses: string[]): boolean =>\n\t\tparticipants?.some(p => isCurrentUser(p.user) && statuses.includes(p.status)) ?? false;\n\n\tswitch (relationship) {\n\t\tcase PullRequestFilter.Author:\n\t\t\treturn isCurrentUser(pr.author?.user);\n\t\tcase PullRequestFilter.ReviewRequested:\n\t\t\treturn hasStatus(pr.reviewers, ['UNAPPROVED']);\n\t\tcase PullRequestFilter.Reviewed:\n\t\t\treturn (\n\t\t\t\t(role !== 'PARTICIPANT' && hasStatus(pr.reviewers, ['APPROVED', 'NEEDS_WORK'])) ||\n\t\t\t\t(role !== 'REVIEWER' && hasStatus(pr.participants, ['APPROVED', 'NEEDS_WORK']))\n\t\t\t);\n\t}\n}\n"],"mappings":"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"}
|
|
@@ -11,15 +11,15 @@ import { AuthenticationSessionLike, ProviderAuthenticationSession } from "../aut
|
|
|
11
11
|
import { GitSelfManagedHostIntegrationId } from "../constants.js";
|
|
12
12
|
import { ProviderOrganization } from "../results.js";
|
|
13
13
|
import { ProviderPullRequestCount, ProviderPullRequestSearchPage } from "../models/pullRequestReads.js";
|
|
14
|
+
import { ProviderHierarchyResult, ProviderPullRequest, ProviderRepoInput, ProviderRepository } from "./models.js";
|
|
14
15
|
import { ProvidersApi } from "./providersApi.js";
|
|
15
16
|
import { GitHostIntegration, SearchMyPullRequestsOptions, SearchPullRequestsOptions } from "../models/gitHostIntegration.js";
|
|
16
17
|
import "../models/integration.js";
|
|
17
|
-
import {
|
|
18
|
+
import { BitbucketRepositoryDescriptor } from "./bitbucket/models.js";
|
|
18
19
|
import { IntegrationConnectionChangeEvent } from "../integrationService.js";
|
|
19
20
|
import { IntegrationAuthenticationService } from "../authentication/integrationAuthenticationService.js";
|
|
20
21
|
import { IntegrationAuthenticationProviderDescriptor } from "../authentication/integrationAuthenticationProvider.js";
|
|
21
22
|
import { IntegrationServiceContext } from "../context.js";
|
|
22
|
-
import { BitbucketRepositoryDescriptor } from "./bitbucket/models.js";
|
|
23
23
|
//#region ../plus/integrations/src/providers/bitbucket-server.d.ts
|
|
24
24
|
export declare class BitbucketServerIntegration extends GitHostIntegration<GitSelfManagedHostIntegrationId.BitbucketServer, BitbucketRepositoryDescriptor> {
|
|
25
25
|
private readonly _domain;
|
|
@@ -61,7 +61,8 @@ var BitbucketServerIntegration = class extends GitHostIntegration {
|
|
|
61
61
|
const tokenWithInfo = toTokenWithInfo(this.id, session);
|
|
62
62
|
return mapSettledBounded(coordinates, 6, (c) => api.getServerPullRequest(this, tokenWithInfo, c.owner, c.repo, String(c.number), this.apiBaseUrlFor(session), {
|
|
63
63
|
currentAccount: options?.currentAccount,
|
|
64
|
-
deferFailure: true
|
|
64
|
+
deferFailure: true,
|
|
65
|
+
projection: "batch"
|
|
65
66
|
}));
|
|
66
67
|
}
|
|
67
68
|
/**
|
|
@@ -93,7 +94,7 @@ var BitbucketServerIntegration = class extends GitHostIntegration {
|
|
|
93
94
|
return (await this.authenticationService.apis.bitbucket)?.getServerPullRequestForCommit(this, toTokenWithInfo(this.id, session), repo.owner, repo.name, rev, this.apiBaseUrlFor(session));
|
|
94
95
|
}
|
|
95
96
|
async getProviderPullRequest(session, resource, id) {
|
|
96
|
-
return (await this.authenticationService.apis.bitbucket)?.getServerPullRequest(this, toTokenWithInfo(this.id, session), resource.owner, resource.name, id, this.apiBaseUrlFor(session));
|
|
97
|
+
return (await this.authenticationService.apis.bitbucket)?.getServerPullRequest(this, toTokenWithInfo(this.id, session), resource.owner, resource.name, id, this.apiBaseUrlFor(session), { projection: "point" });
|
|
97
98
|
}
|
|
98
99
|
getProviderPullRequestIdentityFromMaybeUrl(search) {
|
|
99
100
|
return getBitbucketServerPullRequestIdentityFromMaybeUrl(search, this.id);
|
|
@@ -164,7 +165,7 @@ var BitbucketServerIntegration = class extends GitHostIntegration {
|
|
|
164
165
|
if (repos != null) return;
|
|
165
166
|
const api = await this.getProvidersApi();
|
|
166
167
|
if (!api) return;
|
|
167
|
-
return (await api.getBitbucketServerPullRequestsForCurrentUser(toTokenWithInfo(this.id, session), this.apiBaseUrlFor(session), { states: toProviderPullRequestStates(options?.state) }))?.data.map((pr) => fromProviderPullRequest(pr, this));
|
|
168
|
+
return (await api.getBitbucketServerPullRequestsForCurrentUser(toTokenWithInfo(this.id, session), this.apiBaseUrlFor(session), { states: toProviderPullRequestStates(options?.state) }))?.data.map((pr) => fromProviderPullRequest(pr, this, { projection: "search" }));
|
|
168
169
|
}
|
|
169
170
|
async getProviderMyPullRequestsForUser(session, options) {
|
|
170
171
|
const api = await this.getProvidersApi();
|
|
@@ -214,7 +215,7 @@ var BitbucketServerIntegration = class extends GitHostIntegration {
|
|
|
214
215
|
})).values;
|
|
215
216
|
}));
|
|
216
217
|
if (cancellation?.aborted) throw new CancellationError();
|
|
217
|
-
return providerPullRequests.filter((pr) => providerPullRequestMatchesSearch(pr, searchQuery)).map((pr) => fromProviderPullRequest(pr, this));
|
|
218
|
+
return providerPullRequests.filter((pr) => providerPullRequestMatchesSearch(pr, searchQuery)).map((pr) => fromProviderPullRequest(pr, this, { projection: "text-search" }));
|
|
218
219
|
}
|
|
219
220
|
/**
|
|
220
221
|
* The filtered pull-request search, read by this module's own requests rather than the SDK's: the SDK's list
|
|
@@ -231,7 +232,8 @@ var BitbucketServerIntegration = class extends GitHostIntegration {
|
|
|
231
232
|
criteria: options.criteria,
|
|
232
233
|
currentUser: await this.getSearchUser(session, options.criteria, cancellation),
|
|
233
234
|
cursor: options.cursor,
|
|
234
|
-
pageSize: options.pageSize
|
|
235
|
+
pageSize: options.pageSize,
|
|
236
|
+
projection: options.summary ? "search-summary" : "search"
|
|
235
237
|
}, cancellation);
|
|
236
238
|
}
|
|
237
239
|
/**
|