@gitkraken/core-gitlens 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -1
- package/dist/git/cache.d.ts +18 -5
- package/dist/git/cache.js +26 -8
- package/dist/git/cache.js.map +1 -1
- package/dist/git/context.d.ts +5 -1
- package/dist/git/context.js.map +1 -1
- package/dist/git/errors.d.ts +28 -1
- package/dist/git/errors.js +45 -1
- package/dist/git/errors.js.map +1 -1
- package/dist/git/providers/branches.d.ts +5 -1
- package/dist/git/providers/commits.d.ts +24 -1
- package/dist/git/providers/config.d.ts +7 -1
- package/dist/git/providers/operations.d.ts +6 -0
- package/dist/git/providers/provider.d.ts +17 -0
- package/dist/git/providers/refs.d.ts +38 -3
- package/dist/git/providers/revision.d.ts +5 -1
- package/dist/git/providers/staging.d.ts +12 -0
- package/dist/git/providers/worktrees.d.ts +23 -3
- package/dist/git/run.types.d.ts +6 -0
- package/dist/git-cli/cliGitProvider.d.ts +17 -1
- package/dist/git-cli/cliGitProvider.js +37 -1
- package/dist/git-cli/cliGitProvider.js.map +1 -1
- package/dist/git-cli/exec/git.d.ts +12 -2
- package/dist/git-cli/exec/git.js +48 -17
- package/dist/git-cli/exec/git.js.map +1 -1
- package/dist/git-cli/exec/gitQueue.d.ts +4 -1
- package/dist/git-cli/exec/gitQueue.js +1 -1
- package/dist/git-cli/exec/gitQueue.js.map +1 -1
- package/dist/git-cli/providers/branches.d.ts +10 -1
- package/dist/git-cli/providers/branches.js +15 -8
- package/dist/git-cli/providers/branches.js.map +1 -1
- package/dist/git-cli/providers/commits.d.ts +23 -1
- package/dist/git-cli/providers/commits.js +57 -8
- package/dist/git-cli/providers/commits.js.map +1 -1
- package/dist/git-cli/providers/config.js +4 -3
- package/dist/git-cli/providers/config.js.map +1 -1
- package/dist/git-cli/providers/operations.d.ts +1 -0
- package/dist/git-cli/providers/operations.js +39 -3
- package/dist/git-cli/providers/operations.js.map +1 -1
- package/dist/git-cli/providers/patch.js +20 -41
- package/dist/git-cli/providers/patch.js.map +1 -1
- package/dist/git-cli/providers/pausedOperations.js +2 -2
- package/dist/git-cli/providers/pausedOperations.js.map +1 -1
- package/dist/git-cli/providers/refs.d.ts +15 -3
- package/dist/git-cli/providers/refs.js +115 -10
- package/dist/git-cli/providers/refs.js.map +1 -1
- package/dist/git-cli/providers/revision.d.ts +3 -1
- package/dist/git-cli/providers/revision.js +9 -5
- package/dist/git-cli/providers/revision.js.map +1 -1
- package/dist/git-cli/providers/staging.d.ts +8 -0
- package/dist/git-cli/providers/staging.js +59 -7
- package/dist/git-cli/providers/staging.js.map +1 -1
- package/dist/git-cli/providers/worktrees.d.ts +31 -2
- package/dist/git-cli/providers/worktrees.js +75 -7
- package/dist/git-cli/providers/worktrees.js.map +1 -1
- package/dist/ipc/discovery.js +1 -1
- package/dist/plus/agents/providers/claudeCodeTranscript.js +6 -6
- package/dist/plus/agents/providers/claudeCodeTranscript.js.map +1 -1
- package/dist/plus/ai/providers/openAICompatibleProviderBase.js +1 -1
- package/dist/plus/git-github/api/github.d.ts +64 -3
- package/dist/plus/git-github/api/github.js +237 -24
- package/dist/plus/git-github/api/github.js.map +1 -1
- package/dist/plus/git-github/providers/github/branches.d.ts +3 -1
- package/dist/plus/git-github/providers/github/branches.js +2 -1
- package/dist/plus/git-github/providers/github/branches.js.map +1 -1
- package/dist/plus/git-github/providers/github/refs.d.ts +10 -3
- package/dist/plus/git-github/providers/github/refs.js +4 -4
- package/dist/plus/git-github/providers/github/refs.js.map +1 -1
- package/dist/plus/git-github/providers/github/revision.d.ts +3 -1
- package/dist/plus/git-github/providers/github/revision.js +1 -1
- package/dist/plus/git-github/providers/github/revision.js.map +1 -1
- package/dist/plus/integrations/collectionMetadata.d.ts +48 -3
- package/dist/plus/integrations/collectionMetadata.js +138 -8
- package/dist/plus/integrations/collectionMetadata.js.map +1 -1
- package/dist/plus/integrations/errors.d.ts +3 -1
- package/dist/plus/integrations/errors.js +7 -3
- package/dist/plus/integrations/errors.js.map +1 -1
- package/dist/plus/integrations/index.d.ts +6 -3
- package/dist/plus/integrations/index.js.map +1 -1
- package/dist/plus/integrations/integrationService.d.ts +36 -10
- package/dist/plus/integrations/integrationService.js +16 -3
- package/dist/plus/integrations/integrationService.js.map +1 -1
- package/dist/plus/integrations/manager.d.ts +107 -37
- package/dist/plus/integrations/models/gitHostIntegration.d.ts +129 -14
- package/dist/plus/integrations/models/gitHostIntegration.js +142 -18
- package/dist/plus/integrations/models/gitHostIntegration.js.map +1 -1
- package/dist/plus/integrations/models/integration.d.ts +117 -11
- package/dist/plus/integrations/models/integration.js +175 -13
- package/dist/plus/integrations/models/integration.js.map +1 -1
- package/dist/plus/integrations/models/issuesIntegration.d.ts +18 -5
- package/dist/plus/integrations/models/issuesIntegration.js +42 -10
- package/dist/plus/integrations/models/issuesIntegration.js.map +1 -1
- package/dist/plus/integrations/providers/azure/azure.d.ts +1 -1
- package/dist/plus/integrations/providers/azure/azure.js +14 -18
- package/dist/plus/integrations/providers/azure/azure.js.map +1 -1
- package/dist/plus/integrations/providers/azure/models.d.ts +29 -0
- package/dist/plus/integrations/providers/azure/models.js +112 -1
- package/dist/plus/integrations/providers/azure/models.js.map +1 -1
- package/dist/plus/integrations/providers/azureDevOps.d.ts +73 -3
- package/dist/plus/integrations/providers/azureDevOps.js +117 -3
- package/dist/plus/integrations/providers/azureDevOps.js.map +1 -1
- package/dist/plus/integrations/providers/azureDevOpsServer.js +2 -1
- package/dist/plus/integrations/providers/azureDevOpsServer.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket/bitbucket.d.ts +61 -0
- package/dist/plus/integrations/providers/bitbucket/bitbucket.js +165 -23
- package/dist/plus/integrations/providers/bitbucket/bitbucket.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket/models.d.ts +6 -1
- package/dist/plus/integrations/providers/bitbucket/models.js +4 -3
- package/dist/plus/integrations/providers/bitbucket/models.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js +2 -2
- package/dist/plus/integrations/providers/bitbucket-server/pullRequestSearch.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket-server.d.ts +48 -2
- package/dist/plus/integrations/providers/bitbucket-server.js +51 -1
- package/dist/plus/integrations/providers/bitbucket-server.js.map +1 -1
- package/dist/plus/integrations/providers/bitbucket.d.ts +45 -2
- package/dist/plus/integrations/providers/bitbucket.js +41 -2
- package/dist/plus/integrations/providers/bitbucket.js.map +1 -1
- package/dist/plus/integrations/providers/github.d.ts +49 -5
- package/dist/plus/integrations/providers/github.js +102 -7
- package/dist/plus/integrations/providers/github.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab/gitlab.d.ts +35 -0
- package/dist/plus/integrations/providers/gitlab/gitlab.js +132 -15
- package/dist/plus/integrations/providers/gitlab/gitlab.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab/models.d.ts +1 -0
- package/dist/plus/integrations/providers/gitlab/models.js +1 -1
- package/dist/plus/integrations/providers/gitlab/models.js.map +1 -1
- package/dist/plus/integrations/providers/gitlab.d.ts +49 -2
- package/dist/plus/integrations/providers/gitlab.js +80 -4
- package/dist/plus/integrations/providers/gitlab.js.map +1 -1
- package/dist/plus/integrations/providers/jira-server.d.ts +3 -3
- package/dist/plus/integrations/providers/jira-server.js +5 -8
- package/dist/plus/integrations/providers/jira-server.js.map +1 -1
- package/dist/plus/integrations/providers/jira.d.ts +9 -0
- package/dist/plus/integrations/providers/jira.js +13 -1
- package/dist/plus/integrations/providers/jira.js.map +1 -1
- package/dist/plus/integrations/providers/linear.js +1 -1
- package/dist/plus/integrations/providers/models.d.ts +13 -2
- package/dist/plus/integrations/providers/models.js +11 -1
- package/dist/plus/integrations/providers/models.js.map +1 -1
- package/dist/plus/integrations/providers/providerErrors.d.ts +9 -1
- package/dist/plus/integrations/providers/providerErrors.js +10 -1
- package/dist/plus/integrations/providers/providerErrors.js.map +1 -1
- package/dist/plus/integrations/providers/providersApi.d.ts +60 -1
- package/dist/plus/integrations/providers/providersApi.js +137 -2
- package/dist/plus/integrations/providers/providersApi.js.map +1 -1
- package/dist/plus/integrations/providers/utils/providerPaging.d.ts +42 -0
- package/dist/plus/integrations/providers/utils/providerPaging.js +58 -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/broaden.js +1 -1
- package/dist/plus/integrations/reads/context.d.ts +1 -1
- package/dist/plus/integrations/reads/counts.js +1 -1
- package/dist/plus/integrations/reads/currentAccount.d.ts +35 -0
- package/dist/plus/integrations/reads/currentAccount.js +46 -0
- package/dist/plus/integrations/reads/currentAccount.js.map +1 -0
- package/dist/plus/integrations/reads/drains.d.ts +5 -2
- package/dist/plus/integrations/reads/drains.js +8 -4
- package/dist/plus/integrations/reads/drains.js.map +1 -1
- package/dist/plus/integrations/reads/hierarchy.js +1 -1
- package/dist/plus/integrations/reads/hierarchy.utils.js +1 -1
- package/dist/plus/integrations/reads/issueBatch.d.ts +72 -12
- package/dist/plus/integrations/reads/issueBatch.js +193 -48
- package/dist/plus/integrations/reads/issueBatch.js.map +1 -1
- package/dist/plus/integrations/reads/issueTracker.js +1 -1
- package/dist/plus/integrations/reads/issues.js +1 -1
- package/dist/plus/integrations/reads/pullRequestBatch.d.ts +57 -0
- package/dist/plus/integrations/reads/pullRequestBatch.js +80 -0
- package/dist/plus/integrations/reads/pullRequestBatch.js.map +1 -0
- package/dist/plus/integrations/reads/pullRequestBranches.d.ts +58 -0
- package/dist/plus/integrations/reads/pullRequestBranches.js +111 -0
- package/dist/plus/integrations/reads/pullRequestBranches.js.map +1 -0
- package/dist/plus/integrations/reads/pullRequests.js +3 -3
- package/dist/plus/integrations/reads/pullRequests.js.map +1 -1
- package/dist/plus/integrations/reads/resolveRepository.js +1 -1
- package/dist/plus/integrations/reads/sweeps.js +4 -4
- package/dist/plus/integrations/reads/sweeps.js.map +1 -1
- package/dist/plus/integrations/results.d.ts +87 -6
- package/dist/plus/integrations/results.js +9 -2
- package/dist/plus/integrations/results.js.map +1 -1
- package/dist/utils/env/node/exec.js +3 -3
- package/dist/utils/env/node/exec.js.map +1 -1
- package/docs/integrations.md +175 -35
- package/docs/kepler-git-write-api-parity.md +239 -0
- package/docs/kepler-read-api-parity.md +75 -28
- package/package.json +1 -1
- package/dist/plus/integrations/reads/trackerIssue.d.ts +0 -33
- package/dist/plus/integrations/reads/trackerIssue.js +0 -60
- package/dist/plus/integrations/reads/trackerIssue.js.map +0 -1
package/docs/integrations.md
CHANGED
|
@@ -113,42 +113,87 @@ provider before calling the token backend; never reuse an id discovered under a
|
|
|
113
113
|
Every read returns `ProviderResult<T>` (`items` + `warnings` + `fetchFailed?`), and every paged read extends
|
|
114
114
|
it with `page` + `hasMore` + `cursor?`. **No read throws for a provider-side failure** — see §6.
|
|
115
115
|
|
|
116
|
-
| Method | Returns | Scope
|
|
117
|
-
| ---------------------------- | ------------------------- |
|
|
118
|
-
| `listOrgs` | `ProviderOrganization` | Orgs / workspaces / groups / Bitbucket DC projects; issue-tracker resources (Jira sites, …).
|
|
119
|
-
| `listProjects` | `ProviderOrganization` | The project tier: Azure DevOps, and issue-tracker projects.
|
|
120
|
-
| `listRepos` | `ProviderRepositoryShape` | Repos of an `org`, or account-wide user-affiliated repos when `org` is omitted.
|
|
121
|
-
| `listPullRequestsPage` | `PullRequestShape` | With `repos`: those repos' PRs. Without: the user's PRs account-wide.
|
|
122
|
-
| `searchPullRequestsPage` | `PullRequestShape` | PRs involving the user that match structured criteria, optionally repo/org-scoped.
|
|
123
|
-
| `countPullRequests` | `PullRequestCountResult` | How many PRs match each scope, fetching none where the provider can count. See §5.1.
|
|
124
|
-
| `listIssuesPage` | `IssueShape` | Same split, for a **git host**'s issues.
|
|
125
|
-
| `searchIssuesPage` | `IssueShape` | Issues matching structured criteria over a repo/org scope — **no** `@me` binding.
|
|
126
|
-
| `countIssues` | `IssueCountResult` | How many match each scope, fetching none of them. See §5.1.
|
|
127
|
-
| `getIssuesBatch` | `IssueBatchResult` | Resolves N
|
|
128
|
-
| `
|
|
129
|
-
| `
|
|
130
|
-
| `
|
|
131
|
-
| `
|
|
132
|
-
| `
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
116
|
+
| Method | Returns | Scope |
|
|
117
|
+
| ---------------------------- | ------------------------- | -------------------------------------------------------------------------------------------- |
|
|
118
|
+
| `listOrgs` | `ProviderOrganization` | Orgs / workspaces / groups / Bitbucket DC projects; issue-tracker resources (Jira sites, …). |
|
|
119
|
+
| `listProjects` | `ProviderOrganization` | The project tier: Azure DevOps, and issue-tracker projects. |
|
|
120
|
+
| `listRepos` | `ProviderRepositoryShape` | Repos of an `org`, or account-wide user-affiliated repos when `org` is omitted. |
|
|
121
|
+
| `listPullRequestsPage` | `PullRequestShape` | With `repos`: those repos' PRs. Without: the user's PRs account-wide. |
|
|
122
|
+
| `searchPullRequestsPage` | `PullRequestShape` | PRs involving the user that match structured criteria, optionally repo/org-scoped. |
|
|
123
|
+
| `countPullRequests` | `PullRequestCountResult` | How many PRs match each scope, fetching none where the provider can count. See §5.1. |
|
|
124
|
+
| `listIssuesPage` | `IssueShape` | Same split, for a **git host**'s issues. |
|
|
125
|
+
| `searchIssuesPage` | `IssueShape` | Issues matching structured criteria over a repo/org scope — **no** `@me` binding. |
|
|
126
|
+
| `countIssues` | `IssueCountResult` | How many match each scope, fetching none of them. See §5.1. |
|
|
127
|
+
| `getIssuesBatch` | `IssueBatchResult` | Resolves N issues by coordinate or tracker identifier; an absence is proven. |
|
|
128
|
+
| `getPullRequestsBatch` | `PullRequestBatchResult` | Resolves N PRs by `(owner, repo, number)`, in any state; an absence is proven. |
|
|
129
|
+
| `getPullRequestsForBranches` | `PullRequestBranchResult` | Each branch's PRs, in any state and fork-aware; an empty list is a proven none. |
|
|
130
|
+
| `listIssueTrackerIssuesPage` | `IssueShape` | Jira (Cloud + Data Center) / Linear / Trello (issues live under resource → project). |
|
|
131
|
+
| `sweepPullRequests` | `ProviderSweepResult` | Drains **every** page across providers (`maxPages`, default 100). |
|
|
132
|
+
| `sweepClosedPullRequests` | `ProviderSweepResult` | Same, pinned to `['closed','merged']`. |
|
|
133
|
+
| `broadenIssues` | `ProviderBroadenResult` | Per-org fan-out for every visible issue, unfiltered by assignee. |
|
|
134
|
+
| `resolveRepository` | `ResolveRepositoryResult` | Remote URL → canonical provider identity (the `gk repo resolve` equivalent). |
|
|
135
|
+
| `getCurrentAccount` | `CurrentAccountResult` | Who a git host connection is signed in as; trackers refuse. |
|
|
136
|
+
| `getSupportedFilters` | filter capability table | Static, connection-free. See §7. |
|
|
135
137
|
|
|
136
138
|
A provider that cannot serve a surface says so explicitly — a warning explaining that the operation is
|
|
137
139
|
unsupported plus `fetchFailed`, never a silent empty page. That distinction is the whole point of the result
|
|
138
140
|
shape: an empty `items` with no warning means "this account genuinely has nothing".
|
|
139
141
|
|
|
140
|
-
`
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
142
|
+
`getIssuesBatch` takes the target form its provider addresses an issue by: `{ key, owner, repo, number, project? }` on
|
|
143
|
+
GitHub/GHE, GitLab and Azure DevOps, and `{ key, resourceId, resourceUrl?, identifier }` on Jira (Cloud and Data
|
|
144
|
+
Center) and Linear; a call carrying the other form is refused whole. GitHub/GHE resolve up to 25 coordinates per
|
|
145
|
+
request; GitLab, Azure DevOps and the trackers cost one request per target. Azure DevOps requires `project` and
|
|
146
|
+
ignores `repo`, since work items belong to the project. Rows take the repository-scoped `listIssuesPage` conversion,
|
|
147
|
+
except that an Azure DevOps row has no `project`, which only the account-wide read fills from project discovery. What
|
|
148
|
+
counts as a proven absence is per host. On GitLab it is a null project or issue, and a miss costs a second request to
|
|
149
|
+
confirm it, since provider-apis reports a reply carrying only GraphQL errors the same way; a 404 or an empty response
|
|
150
|
+
fails the target. On Azure DevOps it is Azure's own 404 body naming the work item (`WorkItemUnauthorizedAccessException`,
|
|
151
|
+
which Azure also uses for a work item this connection cannot read) or the project
|
|
152
|
+
(`ProjectDoesNotExistWithNameException`); an HTML 404, a 410 or any other `typeKey` fails the target. Bitbucket and
|
|
153
|
+
Bitbucket DC have no issues and refuse. A tracker target's `resourceId` is trusted, so the read performs no resource
|
|
154
|
+
discovery. Jira Cloud also requires `resourceUrl`, the site URL returned by `listOrgs`; the REST response only supplies
|
|
155
|
+
an API `self` link, so the caller provides the already-known site identity. Linear does not need it, and neither does
|
|
156
|
+
Jira Data Center, whose browser link is built from the connection's own base URL. A key asked of several resources is
|
|
157
|
+
one call, with one target per resource.
|
|
158
|
+
|
|
159
|
+
For Jira Data Center a target's `resourceId` is the host — the instance's single resource, as `listOrgs` reports it —
|
|
160
|
+
and the call takes the `domain` its siblings take to select the instance. Unlike them it never falls back to the
|
|
161
|
+
primary connection: a self-managed tracker requires a `domain` or a `connectionId` with a configured host, and the
|
|
162
|
+
whole call is refused (warning + `fetchFailed`) otherwise. Two self-hosted instances routinely share project and
|
|
163
|
+
issue keys, and this read's `issue: undefined` is a proven absence a caller may cache, so an answer from whichever
|
|
164
|
+
host happens to be primary would be cached under a key that names a different instance. For the same reason, a call
|
|
165
|
+
in which any target's `resourceId` names a different host than the one the read resolves to is refused whole rather
|
|
166
|
+
than read.
|
|
167
|
+
|
|
168
|
+
`getPullRequestsBatch` is the pull request counterpart of `getIssuesBatch`, with the same absence/failure contract,
|
|
169
|
+
and it serves every git host. Azure DevOps also requires `project` on each target. GitHub/GHE resolve up to 25
|
|
170
|
+
targets per request; every other host costs one request per target, and GitLab a second one to confirm a miss. A
|
|
171
|
+
target GitHub refuses on its own, e.g. in an org enforcing SAML SSO the token isn't authorized for, fails only that
|
|
172
|
+
target. Its rows carry the same fields as the list reads' rows, except on Bitbucket Cloud — which has no single pull
|
|
173
|
+
request read in provider-apis, so those rows come from GitLens' own REST read and lack `commentsCount`, `isDraft`
|
|
174
|
+
and the clone URLs. On GitLab, a miss the confirming read then contradicts fails the target rather than answering
|
|
175
|
+
with the confirming read's own, differently-identified row. It is uncached and bypasses the
|
|
176
|
+
host's `IntegrationCacheProvider.getPullRequest`, so the caller owns caching the answer.
|
|
177
|
+
|
|
178
|
+
`getPullRequestsForBranches` answers "which pull requests have this branch as their head" without the user's
|
|
179
|
+
relationship to them, so unlike the sweeps it finds a teammate's pull request from the user's branch. A target names
|
|
180
|
+
the repository the pull requests are opened against, the branch's short name and, for a branch in a fork,
|
|
181
|
+
`headOwner`; one equal to the target's owner means the base repository. A pull request matches only when its head
|
|
182
|
+
repository is that base repository or that fork, so a `main` never claims every fork's `main`. The match is on the
|
|
183
|
+
head branch name in every state, so a merged pull request whose branch was deleted is still found. Each target
|
|
184
|
+
returns up to 10, most recently updated first. An empty list without `truncated` is a proven none, a missing base
|
|
185
|
+
repository included; `truncated` means more may match than were returned. GitHub/GHE answer up to 25 targets per
|
|
186
|
+
request, and every other host costs one request per target. GitLab and Azure DevOps, where that request only finds
|
|
187
|
+
the matching numbers, then resolve each match (typically 0–1 per branch) through `getPullRequestsBatch`'s own read,
|
|
188
|
+
so their rows are exactly its rows; a match that read can't check fails its whole branch. Rows carry the list reads'
|
|
189
|
+
fields on GitHub/GHE and Bitbucket DC and the by-id read's on Bitbucket Cloud. Bitbucket DC and Azure DevOps refuse a
|
|
190
|
+
`headOwner` naming another owner, since neither can find a fork by its owner. It is uncached and bypasses
|
|
191
|
+
`IntegrationCacheProvider.getPullRequestForBranch`.
|
|
192
|
+
|
|
193
|
+
`getCurrentAccount` answers who a git host connection is signed in as. It returns a single `account?` rather
|
|
194
|
+
than `items`, and `account` is never absent without a warning: no session, a failed request, or an issue tracker,
|
|
195
|
+
which has only a per-resource account and refuses (see §8). It goes through the host-supplied
|
|
196
|
+
`IntegrationManagerCacheProvider.getCurrentAccount` cache rather than adding a second one.
|
|
152
197
|
|
|
153
198
|
## 5. Paging
|
|
154
199
|
|
|
@@ -361,7 +406,7 @@ prove from structured errors:
|
|
|
361
406
|
|
|
362
407
|
| `kind` | Meaning | Reasonable response |
|
|
363
408
|
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
|
|
364
|
-
| `auth` | Token rejected (401/403 that isn't a throttle). | Prompt to reconnect that connection.
|
|
409
|
+
| `auth` | Token rejected (401/403 that isn't a throttle). | Prompt to reconnect that connection. A scoped one is narrower: see `scope` below. |
|
|
365
410
|
| `rate-limit` | Throttled (429, or a 403 whose body says so). | Back off and retry; keep the last snapshot. |
|
|
366
411
|
| `not-found` | 404/410/422 on the requested scope. | Drop that scope; don't reconnect. |
|
|
367
412
|
| `no-connection` | The requested `connectionId`/`domain` doesn't resolve. | Re-resolve the target or re-authenticate. |
|
|
@@ -373,6 +418,95 @@ Conversely, `other` is intentionally not a complete failure taxonomy. Treat `mes
|
|
|
373
418
|
text rather than a stable protocol; use `fetchFailed`, `page.truncated`, and `page.allPages` for completeness
|
|
374
419
|
and keep unknown failures conservative.
|
|
375
420
|
|
|
421
|
+
### `scope` — which part of the read failed
|
|
422
|
+
|
|
423
|
+
A fan-out read records a failure against the organization, project or repository it happened in.
|
|
424
|
+
`ProviderWarning.scope` forwards that attribution (`resourceId`, `projectId`, `repositoryId`, whichever the
|
|
425
|
+
provider reported), so a consumer can tell "one organization refused this token" from "the connection's token
|
|
426
|
+
is dead" without parsing `message`:
|
|
427
|
+
|
|
428
|
+
```ts
|
|
429
|
+
if (warning.kind === 'auth' && warning.scope == null) {
|
|
430
|
+
promptToReconnect(warning.providerId, warning.connectionId);
|
|
431
|
+
} else if (warning.kind === 'auth') {
|
|
432
|
+
// One organization/project/repository refused the credential, e.g. an Azure DevOps organization with
|
|
433
|
+
// third-party OAuth access disabled, one in another Entra tenant, or a Conditional Access policy.
|
|
434
|
+
// Reconnecting cannot fix that, so mark only that scope unavailable and keep the others.
|
|
435
|
+
markScopeUnavailable(warning.providerId, warning.connectionId, warning.scope);
|
|
436
|
+
}
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
`kind` and `isAuth` do not change with it: a scoped 401 is still an authentication failure, and `scope` says
|
|
440
|
+
how far it reaches. **Its absence means account-wide or unattributed**, so a consumer that ignores the field
|
|
441
|
+
keeps its existing behavior. It is set only on warnings derived from a structured scope failure, and names at
|
|
442
|
+
least one ID when present; a failure attributed to nothing below the provider carries none. A warning built
|
|
443
|
+
from a caught exception never carries one, even when that call targeted a single organization, and an omission
|
|
444
|
+
keeps its attribution in `omission.scope` instead. The batch reads (`getIssuesBatch`, `getPullRequestsBatch`,
|
|
445
|
+
`getPullRequestsForBranches`) are the exception: a refused target's warning names the scope its target names —
|
|
446
|
+
the Azure DevOps organization and project, the repository on other git hosts, or the tracker's resource.
|
|
447
|
+
|
|
448
|
+
A scoped `auth` failure also means **the credential itself was accepted**. A dead token can come back as
|
|
449
|
+
nothing but scoped refusals wherever a read reaches its scopes without an uncached request to the connection
|
|
450
|
+
first: discovery served from a per-token cache (Azure DevOps, Bitbucket and Jira Cloud cache the account, its
|
|
451
|
+
organizations, workspaces or sites, and their projects), or an SDK fan-out across the requested repositories
|
|
452
|
+
(Bitbucket Data Center). So when a read's only auth failures are scoped, those providers confirm the credential
|
|
453
|
+
with one uncached check before reporting them; a batch read does so only when every target was refused, since a
|
|
454
|
+
target that answered already proved the credential. A refused credential fails the whole read instead: an
|
|
455
|
+
unscoped `auth` warning, `fetchFailed`, no results served from the cache, and the usual connection recovery.
|
|
456
|
+
A refusal the provider pins on the credential itself, like Bitbucket's or Jira Cloud's for a token missing the
|
|
457
|
+
OAuth scopes the read needs, is published unscoped too, once for the connection, because a reconnect
|
|
458
|
+
(consenting to them again) is what fixes it; the scopes that answered keep their results.
|
|
459
|
+
|
|
460
|
+
The promise holds for a read that carries no unscoped `auth` warning of its own: one that does already asks for a
|
|
461
|
+
reconnect, and its other scoped refusals are not checked. Two cases stay scoped even then. A check that could not
|
|
462
|
+
complete or was denied (a network error, a throttle, a `403`, Bitbucket Data Center refusing a credential it
|
|
463
|
+
authenticated, or a Bitbucket Data Center project access token, whose user the check cannot find) proves nothing,
|
|
464
|
+
so the warnings are published unconfirmed and carry no `cause`, and the next read checks again: a credential the
|
|
465
|
+
check can never confirm, like a project access token, costs one check on every read that has scoped refusals. And a
|
|
466
|
+
credential confirmed within the last minute is not checked again, so a scope that keeps refusing it costs at most
|
|
467
|
+
one extra check a minute, and a revocation can take up to a minute to surface as a connection failure.
|
|
468
|
+
|
|
469
|
+
`scope.resourceId` is the resource as the read addressed it: its id on most reads, its name on the few that
|
|
470
|
+
address it by name (Azure DevOps' repo-scoped reads, Bitbucket's workspace reads). Match it against both
|
|
471
|
+
`ProviderOrganization.id` and `name`.
|
|
472
|
+
|
|
473
|
+
Warnings also dedup on `scope` and `cause`, so failures of two scopes stay two warnings.
|
|
474
|
+
|
|
475
|
+
### `cause` — why a sound credential was refused
|
|
476
|
+
|
|
477
|
+
A scoped `auth` warning can also say **why** the scope refused, so a consumer recommends the fix instead of a
|
|
478
|
+
reconnect. `ProviderWarning.cause` carries a closed `reason` to switch on (also exported as
|
|
479
|
+
`ProviderWarningCauseReason`), the provider's own `code` when it reports one, and a `remedyUrl` when this layer
|
|
480
|
+
can address the setting behind the refusal. `message` says the same in prose.
|
|
481
|
+
|
|
482
|
+
```ts
|
|
483
|
+
switch (warning.cause?.reason) {
|
|
484
|
+
case 'oauth-app-not-allowed':
|
|
485
|
+
// An admin enables the org's third-party OAuth policy at `remedyUrl`, or the user connects with a PAT.
|
|
486
|
+
suggestAllowingOAuthApps(warning.scope, warning.cause.remedyUrl);
|
|
487
|
+
break;
|
|
488
|
+
case 'access-denied':
|
|
489
|
+
suggestRequestingAccess(warning.scope);
|
|
490
|
+
break;
|
|
491
|
+
case 'conditional-access':
|
|
492
|
+
suggestAskingTheTenantAdmin(warning.scope);
|
|
493
|
+
break;
|
|
494
|
+
}
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
| `cause.reason` | Means | Fixed by |
|
|
498
|
+
| ----------------------- | ---------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
499
|
+
| `oauth-app-not-allowed` | The organization does not let third-party OAuth apps in. | An organization admin enabling **Third-party application access via OAuth** (Azure DevOps; off by default for new organizations), or a PAT, which the policy does not govern. |
|
|
500
|
+
| `access-denied` | The account has no access to that organization or project (not a member, no permission). | Someone who administers it granting access. |
|
|
501
|
+
| `conditional-access` | A Microsoft Entra Conditional Access policy blocked the request (`VS403463`). | The tenant admin exempting the request. |
|
|
502
|
+
|
|
503
|
+
It is set **only on a scoped `auth` warning whose credential was confirmed** (see `scope` above), because until
|
|
504
|
+
then these refusals look exactly like a dead credential: Azure DevOps answers a third-party OAuth app its
|
|
505
|
+
organization disallows with the same bare `401` it gives an expired token. Only Azure DevOps names causes today,
|
|
506
|
+
from answers captured against the live service. **Its absence proves nothing**: a refusal this layer cannot name
|
|
507
|
+
still carries the provider's own explanation, when it gave one, in `message`, e.g. an organization that only
|
|
508
|
+
allowlists global personal access tokens.
|
|
509
|
+
|
|
376
510
|
### `omission` — succeeded, but withheld results
|
|
377
511
|
|
|
378
512
|
`other` covers two facts with **opposite remedies**: a request that failed, and a request that succeeded while
|
|
@@ -583,12 +717,14 @@ Derived from the provider models and `providersMetadata`. ✓ supported · ✗ r
|
|
|
583
717
|
| Issues, account-wide | ✓ | ✓ | ✗ | ✗ | ✓ | — | — | — |
|
|
584
718
|
| `searchIssuesPage` | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
|
|
585
719
|
| `countIssues` | ✓ | ✓ | ✗ | ✗ | ✗ | ✗ | ✗ | ✗ |
|
|
586
|
-
| `getIssuesBatch` | ✓ | ✓ | ✗ | ✗ |
|
|
587
|
-
| `
|
|
720
|
+
| `getIssuesBatch` | ✓ | ✓ | ✗ | ✗ | ✓ | ✓ | ✓ | ✗ |
|
|
721
|
+
| `getPullRequestsBatch` | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ | ✗ | ✗ |
|
|
722
|
+
| `getPullRequestsForBranches` | ✓ | ✓ | ✓ | ✓¹ | ✓¹ | ✗ | ✗ | ✗ |
|
|
588
723
|
| Issues by `org`/`project` | ✗ | ✗ | ✗ | ✗ | ✓ | ✓ | ✓ | ✓ |
|
|
589
724
|
| `listIssueTrackerIssuesPage` | — | — | — | — | — | ✓ | ✓ | ✓ |
|
|
590
725
|
| `broadenIssues` | ✓ | ✓ | ✗ | ✗ | ✓ | ✗ | ✗ | ✗ |
|
|
591
726
|
| `resolveRepository` | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ | ✗ | ✗ |
|
|
727
|
+
| `getCurrentAccount` | ✓ | ✓ | ✓ | ✓ | ✓ | ✗ | ✗ | ✗ |
|
|
592
728
|
|
|
593
729
|
Bitbucket Data Center exposes its projects through `listOrgs`: both `id` and `name` are the project key.
|
|
594
730
|
Pass that key as `org` to `listRepos` to select a project, or omit `org` to enumerate all accessible repositories,
|
|
@@ -601,11 +737,15 @@ HTTPS links are rebuilt from the configured URL and an SSH link, whose host and
|
|
|
601
737
|
|
|
602
738
|
Jira Data Center inherits Jira Cloud's row. Its reads are addressed per host, so `domain` selects the instance and
|
|
603
739
|
every read below is scoped to that one connection; a paged read that omits it gets the primary configured host,
|
|
604
|
-
while `
|
|
740
|
+
while `getIssuesBatch` refuses instead (see §4). `listOrgs` returns exactly one resource — the
|
|
605
741
|
instance itself, synthesized from the configured host rather than fetched — and its projects carry the display name
|
|
606
742
|
as `key`, because `/rest/api/2/project` reports no project key; reads address the project by id regardless. No
|
|
607
743
|
autolinks are registered for the same reason: an autolink prefix has to be the project key.
|
|
608
744
|
|
|
745
|
+
¹ Branches in the base repository only: a target whose `headOwner` names another owner is refused, since Bitbucket DC
|
|
746
|
+
finds a branch's pull requests only through the repository the branch lives in, and an Azure DevOps fork shares its
|
|
747
|
+
organization.
|
|
748
|
+
|
|
609
749
|
Repo-scoped PR filters: GitHub/GHE `Author, Assignee, ReviewRequested, Mention` · GitLab `Author, Assignee,
|
|
610
750
|
ReviewRequested` · Bitbucket + Bitbucket DC `Author, ReviewRequested` · Azure `Author, Assignee,
|
|
611
751
|
ReviewRequested`.
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# Kepler git write-API parity
|
|
2
|
+
|
|
3
|
+
Decision record for the git WRITE-path gaps Kepler hit while routing every one of its git calls through
|
|
4
|
+
`@gitkraken/core-gitlens` (gitkraken/kepler, branch `kepler/migrate-raw-git-spawns`). It is the sibling of
|
|
5
|
+
[`kepler-read-api-parity.md`](./kepler-read-api-parity.md), which covers provider reads; this one covers the
|
|
6
|
+
`git` sub-providers and the raw-command escape hatch.
|
|
7
|
+
|
|
8
|
+
The shape of the problem: Kepler drives three libraries (`@gitkraken/sync-tools`, `conflict-tools`,
|
|
9
|
+
`compose-tools`) that take a `{ exec }` git port plus optional typed ops, and know nothing of core; the host
|
|
10
|
+
supplies a typed op only where a core call serves it exactly. Kepler also has its own worktree, branch and
|
|
11
|
+
sync services. After the migration every command runs through core's executor, so it already shares the queue, environment, binary
|
|
12
|
+
resolution and logging. What it could NOT do is use a typed sub-provider method for a set of commands core had
|
|
13
|
+
no method for, or had one whose contract did not fit. Each such site stayed on `provider.git.run` with a
|
|
14
|
+
comment naming the missing API. This document is the list of those APIs, what was added for each, and what was
|
|
15
|
+
deliberately left alone.
|
|
16
|
+
|
|
17
|
+
Verdict legend: **added** (a typed method now exists) · **extended** (an existing method gained the missing
|
|
18
|
+
option) · **deferred** (left on the raw escape hatch on purpose, with the reason).
|
|
19
|
+
|
|
20
|
+
## 1. Compare-and-swap ref updates — added
|
|
21
|
+
|
|
22
|
+
`refs.updateReference` ran `git update-ref <ref> <sha>` and swallowed every failure (logged, resolved
|
|
23
|
+
`undefined`), and there was no delete form. `@gitkraken/sync-tools` (0.4.0) publishes, applies and discards a
|
|
24
|
+
sync result itself (`applyPublishedSync`, `discardPublishedSync`), and every ref move in that flow is a
|
|
25
|
+
compare-and-swap: the real branch advances only if nothing else moved it since the library last read it. The
|
|
26
|
+
library asks its host for that through a typed `updateRef(ref, sha, { previousSha, mustNotExist, remove })`
|
|
27
|
+
op, and git's own `update-ref <ref> <new> <old>` is what makes it atomic. A writer that cannot refuse is a
|
|
28
|
+
clobber, so without this a host could only serve the op through the raw escape hatch.
|
|
29
|
+
|
|
30
|
+
- `updateReference(repoPath, ref, sha, options?: { expected?: string | 'absent' }, cancellation?)` now passes
|
|
31
|
+
the old value to git when `expected` is a sha, and the empty old value when it is `'absent'` (create only if
|
|
32
|
+
the ref does not exist yet). It THROWS a typed `ReferenceUpdateError` — reasons `conflict` (the ref moved,
|
|
33
|
+
or exists when it must not), `invalidRef`, `invalidObject`, `notFound` — instead of swallowing.
|
|
34
|
+
- `deleteReference(repoPath, ref, options?: { expected?: string }, cancellation?)` runs
|
|
35
|
+
`update-ref -d --no-deref <ref> [<expected>]` with the same error — `--no-deref` so a symbolic ref is itself
|
|
36
|
+
deleted rather than the ref it points to — and refuses `HEAD` (`checkedOut`). `update-ref -d` has none of
|
|
37
|
+
`git branch -d`'s guards or cleanup, so for a local branch (`refs/heads/<name>`) `deleteReference` supplies
|
|
38
|
+
them: it refuses a branch checked out in any worktree (`checkedOut`, read from `git worktree list`, not the
|
|
39
|
+
cached list), and removes the `branch.<name>` config section and GitLens's per-branch metadata with the ref.
|
|
40
|
+
Only `git branch -d`'s merged check is left out, since a compare-and-swap caller has already decided.
|
|
41
|
+
- Both fire the cache and repository hooks a branch, remote-tracking, tag or `HEAD` move fires; a ref in another
|
|
42
|
+
namespace (`refs/kepler/...`) announces nothing, since nothing core caches can observe it and an `unknown`
|
|
43
|
+
change would make a host refresh everything.
|
|
44
|
+
|
|
45
|
+
The sync-tools op maps onto these one-to-one:
|
|
46
|
+
|
|
47
|
+
| `updateRef` option | core call |
|
|
48
|
+
| ------------------ | ---------------------------------------------------------------- |
|
|
49
|
+
| `previousSha` | `updateReference(repoPath, ref, sha, { expected: previousSha })` |
|
|
50
|
+
| `mustNotExist` | `updateReference(repoPath, ref, sha, { expected: 'absent' })` |
|
|
51
|
+
| `remove` | `deleteReference(repoPath, ref, { expected: previousSha })` |
|
|
52
|
+
| none | `updateReference(repoPath, ref, sha)` |
|
|
53
|
+
|
|
54
|
+
`'absent'` against an existing ref rejects as `conflict` and leaves the ref where it was. Deleting a ref that
|
|
55
|
+
is already gone rejects as `notFound` when `expected` is given (the caller named a value it expected to
|
|
56
|
+
remove), and resolves when it is not.
|
|
57
|
+
|
|
58
|
+
The library reads any rejection as the ref's answer, so the host must tell a cancellation apart from a
|
|
59
|
+
refusal. A cancelled call rejects with core's `CancellationError` (`name === 'CancellationError'`), never a
|
|
60
|
+
`ReferenceUpdateError`, and that includes a signal already aborted when the call is made; a host adapting to
|
|
61
|
+
a library that expects `AbortError` maps it by name. A cancel that lands while git is running says nothing
|
|
62
|
+
about whether the ref moved, so re-read it before acting on the outcome.
|
|
63
|
+
|
|
64
|
+
**Breaking:** a caller that relied on a failed `updateReference` resolving silently now gets a rejection. No
|
|
65
|
+
caller in this repository did.
|
|
66
|
+
|
|
67
|
+
## 2. Who clears after a write, and telling core about a raw one — changed / added
|
|
68
|
+
|
|
69
|
+
A typed mutator announces its write through `hooks.cache.onReset`, and core used to clear nothing itself on
|
|
70
|
+
that path: each host's handler was expected to forward to `Cache.clearCaches`. Two things followed. A host
|
|
71
|
+
with no handler kept serving pre-write reads after every typed write. And `clearCaches` only soft-invalidates
|
|
72
|
+
a shared entry that is still in flight, so even a wired host could hand a caller that arrived after the write
|
|
73
|
+
a read that started before it; GitLens also dropped the executor's pending commands on every reset, Kepler did
|
|
74
|
+
not.
|
|
75
|
+
|
|
76
|
+
A consumer that mutates through `provider.git.run` (a rebase driven by a library, a `clean`, a ref bookkeeping
|
|
77
|
+
write) had nothing to call at all, and typed reads served the pre-mutation answer until a file watcher caught
|
|
78
|
+
up, or forever with no watcher. Kepler classified verbs itself and called `clearCaches` after each one. The
|
|
79
|
+
sharpest case: it fetches PR heads through a raw `fetch` (it needs a per-process credential environment the
|
|
80
|
+
typed fetch cannot carry), and a typed `refs.validateReference` right after it served the pre-fetch tip for up
|
|
81
|
+
to 60s. `clearCaches` fixed that read but fired none of the host's hooks, so nothing else in the host learned
|
|
82
|
+
the refs moved.
|
|
83
|
+
|
|
84
|
+
- The provider wraps `onReset` when it is constructed. On every reset it hard-evicts its own caches for those
|
|
85
|
+
types (`Cache.evictCaches`, so a later caller never joins pre-write work), drops pending commands, then calls
|
|
86
|
+
the host's handler. Clears driven by a file watcher reach `clearCaches` directly and keep sharing in-flight
|
|
87
|
+
reads, which is what stops a burst of file events from spawning duplicate reads. A host's handler now only
|
|
88
|
+
has host-side state to update; forwarding to `clearCaches` as well is redundant but harmless.
|
|
89
|
+
- `provider.notifyChanged(repoPath, changes: RepositoryChange[], options?: { cache?: CachedGitTypes[] | 'all' })`
|
|
90
|
+
fires the same `cache.onReset` (all types by default) and `repository.onChanged` a typed write would, so a
|
|
91
|
+
raw mutation gets exactly the same treatment, host listeners included.
|
|
92
|
+
|
|
93
|
+
## 3. Worktree administration — added / extended
|
|
94
|
+
|
|
95
|
+
- `worktrees.pruneWorktrees(repoPath, options?: { expire? })` — `git worktree prune`. Kepler prunes
|
|
96
|
+
after a directory it removed by hand, and before reusing a path git still lists. Like `deleteWorktree`, it
|
|
97
|
+
unregisters each worktree it removed from the cache.
|
|
98
|
+
- `worktrees.lockWorktree(repoPath, path, options?: { reason? })` — `git worktree lock --reason`. The reason
|
|
99
|
+
is how Kepler marks a worktree as task-owned; only `unlockWorktree` existed.
|
|
100
|
+
- `worktrees.createWorktree(repoPath, path, options?, runOptions?)` and
|
|
101
|
+
`deleteWorktree(repoPath, path, options?, runOptions?)` — gained run options. A large worktree's checkout or
|
|
102
|
+
removal legitimately outlasts the default per-command timeout, and a caller may need to cancel either. A
|
|
103
|
+
cancelled call rejects as `CancellationError`, not a worktree error. The thrown `WorktreeDeleteError` keeps git's
|
|
104
|
+
raw output reachable on `original`, which is what a platform-specific retry classifier needs.
|
|
105
|
+
|
|
106
|
+
## 4. `git clean`, and the staging sub-provider's missing hooks — added / fixed
|
|
107
|
+
|
|
108
|
+
- `staging.clean(repoPath, options?: { paths?, directories?, force?, ignored? })` — the only way to
|
|
109
|
+
discard untracked files; `ops.restore` cannot.
|
|
110
|
+
- Every staging mutation (`stageFile(s)`, `stageDirectory`, `stageAll`, `unstage*`, `removeFile(s)`, `clean`)
|
|
111
|
+
now fires `onReset('status', 'diff', 'tracking')` and the index change, except when it targets a temporary
|
|
112
|
+
index, which is not the repository's. Before this, a consumer that staged a conflict resolution through the
|
|
113
|
+
typed API and then read `getConflictingFiles()` could be answered from the index as it stood before the
|
|
114
|
+
stage.
|
|
115
|
+
|
|
116
|
+
## 5. Upstream and hooks config keys — added
|
|
117
|
+
|
|
118
|
+
Kepler writes `branch.<name>.remote` / `branch.<name>.merge` (to set an upstream whose remote ref does not
|
|
119
|
+
exist yet, which `--set-upstream-to` refuses) and reads `core.hooksPath`. All three are now documented members
|
|
120
|
+
of `GitConfigKeys`, so `config.getConfig` / `setConfig` serve them with the usual cache. Writing either
|
|
121
|
+
upstream key also resets the cached branch list, which reports the upstream.
|
|
122
|
+
|
|
123
|
+
## 6. `git pull --ff-only` — extended
|
|
124
|
+
|
|
125
|
+
`ops.pull` gained `fastForward: 'only'`, spelled as `ops.merge` spells it. Kepler advances a local base branch
|
|
126
|
+
before forking a task worktree from it, and must not create a merge commit or start a rebase in a checkout it
|
|
127
|
+
does not own. A refused fast-forward is a `PullError` with the new `noFastForward` reason (the name
|
|
128
|
+
`FetchError` already uses); before this it fell through to `other`. A base branch checked out nowhere has no
|
|
129
|
+
working tree to pull into, so it is advanced by fetching `<upstream>:<branch>`, which git refuses unless it
|
|
130
|
+
fast-forwards; without the option that path only fetches. That fetch runs without `--update-head-ok`: "checked
|
|
131
|
+
out nowhere" comes from the cached worktree list, so git's own refusal is what keeps a branch that is in fact
|
|
132
|
+
checked out from moving. A branch with no upstream is `PullError` reason `noUpstream`, on this path and for a
|
|
133
|
+
checked-out pull alike. `merge`'s `true` / `false` are not offered: a pull configured to rebase ignores `--ff`
|
|
134
|
+
/ `--no-ff`.
|
|
135
|
+
|
|
136
|
+
## 7. A commit from a tree with several parents and an author — added
|
|
137
|
+
|
|
138
|
+
A compose or stack engine writes merge commits and replays commits with their original author, which the
|
|
139
|
+
single-parent, identity-less `commits.createUnreachableCommitFromTree` could not.
|
|
140
|
+
|
|
141
|
+
- `commits.createCommitFromTree(repoPath, tree, { parents, message, author?, committer?, sign?, source? })` runs
|
|
142
|
+
`commit-tree` with the message on stdin and the identity in the per-call environment, returning the sha.
|
|
143
|
+
With `sign` it reports a signing failure as `SigningError` and fires the signing hooks.
|
|
144
|
+
- It is the only path that writes a commit object. `createUnreachableCommitFromTree` is removed, and the patch
|
|
145
|
+
sub-provider's commits (`createUnreachableCommitForPatch`, `createUnreachableCommitsFromPatches`,
|
|
146
|
+
`createEmptyInitialCommit`) go through it with unchanged results.
|
|
147
|
+
|
|
148
|
+
## 8. `git init` — added
|
|
149
|
+
|
|
150
|
+
`GitProvider.clone` existed; `init(path, options?: { defaultBranch?, bare? })` did not. Kepler creates a
|
|
151
|
+
repository for a folder the user adds.
|
|
152
|
+
|
|
153
|
+
## 9. Forced ref reads — added
|
|
154
|
+
|
|
155
|
+
After a change core neither made nor was told about (another process moving a branch, a raw `fetch` the
|
|
156
|
+
consumer has not reported yet), an ordinary read can answer from cache until its TTL runs out. `notifyChanged`
|
|
157
|
+
is the fix when the consumer made the change; `force` is for a read that must be current regardless.
|
|
158
|
+
|
|
159
|
+
- `refs.validateReference(repoPath, ref, { relativePath?, force? }, cancellation?)`,
|
|
160
|
+
`refs.getReference(repoPath, ref, { force? }, cancellation?)`,
|
|
161
|
+
`branches.getBranch(repoPath, name?, { force? }, cancellation?)` and
|
|
162
|
+
`revision.resolveRevision(repoPath, ref, pathOrUri?, { force? })`. A forced read drops its cache entry before
|
|
163
|
+
reading, so it neither returns the cached answer nor joins a read already in flight (a fresh entry gets a
|
|
164
|
+
fresh cancellation aggregate, whose id is part of the executor's dedup key), and it stores the fresh answer
|
|
165
|
+
for later unforced reads. `getStatus({ force })` and `getPausedOperationStatus({ force })` are the precedent.
|
|
166
|
+
- `getBranch({ force })` evicts the whole branch cascade first: branch lists, ref tips, merge bases, commit
|
|
167
|
+
counts and resolved revisions, the set a branch move clears, since each can be derived from a ref that moved.
|
|
168
|
+
`getReference({ force })` forces its validation and branch lookup; tags are not forced.
|
|
169
|
+
- `validateReference`'s `relativePath` moved into the options object, and `getBranch` / `getReference` take
|
|
170
|
+
options before `cancellation`, matching `getStatus`.
|
|
171
|
+
|
|
172
|
+
## Overlaps with existing APIs, and how each was settled
|
|
173
|
+
|
|
174
|
+
- **Refs containing a sha.** `branches.getBranchesWithCommits(repoPath, [sha], undefined, { all, mode })` and
|
|
175
|
+
`tags.getTagsWithCommit` already answer it, so `getRefTips` did not gain `--contains` / `--points-at`
|
|
176
|
+
filters. Kepler's one use (is a sha on any other local or remote branch) is `getBranchesWithCommits`.
|
|
177
|
+
- **Config keys.** Added to the documented union rather than served by a separate untyped
|
|
178
|
+
`getConfigValue` / `setConfigValue`, which would have been a second way to read every key.
|
|
179
|
+
- **Commit objects.** `createCommitFromTree` replaced `createUnreachableCommitFromTree` and the patch
|
|
180
|
+
sub-provider's own `commit-tree` calls, rather than sitting beside them.
|
|
181
|
+
- **Deleting refs.** `deleteReference` stays beside `branches.deleteLocalBranch` and `tags.deleteTag` on
|
|
182
|
+
purpose. `deleteLocalBranch` keeps `git branch -d`'s merged check, which the delete flow's force-retry relies
|
|
183
|
+
on, and takes several names; `deleteTag` reports a `TagError` the UI renders. `deleteReference` is the
|
|
184
|
+
compare-and-swap form for any namespace, and shares the branch cleanup with `deleteLocalBranch`.
|
|
185
|
+
- **Clearing caches.** `evictCaches` stays beside `clearCaches`: a write hard-evicts, a watcher clear keeps
|
|
186
|
+
sharing in-flight reads (see the decisions below).
|
|
187
|
+
|
|
188
|
+
## Deferred, deliberately
|
|
189
|
+
|
|
190
|
+
- **Index and object plumbing** (`read-tree`, `write-tree`, `update-index --index-info`, `mktree`,
|
|
191
|
+
`hash-object -w --stdin`, `cat-file -p`). The libraries drive these through `exec` with a scratch
|
|
192
|
+
`GIT_INDEX_FILE` and parse the results themselves; a typed surface would re-encode the same argv with more
|
|
193
|
+
room to drift. Revisit when a second consumer needs them.
|
|
194
|
+
- **A reflog read filtered by message.** Kepler reads `git reflog <branch> --grep-reflog='branch: Created from'`
|
|
195
|
+
to recover a branch's creation point. `getIncomingActivity` walks `HEAD`'s reflog for a different purpose;
|
|
196
|
+
bolting a grep onto it would change its paging. Worth its own method on `branches` once the base-branch
|
|
197
|
+
inference core already does privately is unified with it.
|
|
198
|
+
- **Generic `for-each-ref` with a caller-supplied format.** The `RefRecord` shape is private on purpose.
|
|
199
|
+
- **A typed `worktree remove` for every consumer.** Kept the raw form where a consumer classifies platform
|
|
200
|
+
failures from stderr; §3's `original` makes the typed form usable for that too.
|
|
201
|
+
|
|
202
|
+
## Bridging core into the tools libraries
|
|
203
|
+
|
|
204
|
+
The libraries take their own port and know nothing of core, so a host serving one through core reshapes what
|
|
205
|
+
core rejects with:
|
|
206
|
+
|
|
207
|
+
- **Cancellation.** Core rejects with `CancellationError` (`name === 'CancellationError'`); a library that
|
|
208
|
+
expects `AbortError` gets it mapped by name.
|
|
209
|
+
- **"Git answered no" versus a structural failure.** sync-tools tells them apart by whether `err.code` is a
|
|
210
|
+
number, and compose-tools reads `err.stderr`: the shape of Node's `execFile` error. Core's `GitError`
|
|
211
|
+
carries `stderr` but reports the exit as `exitCode`, which is a number or numeric string for a real exit and
|
|
212
|
+
an errno string (`'ENOENT'`) when git never started. A typed method's own error, such as
|
|
213
|
+
`ReferenceUpdateError`, keeps that `GitError` on `original`.
|
|
214
|
+
|
|
215
|
+
## Decisions worth recording, because each closes off a plausible-looking alternative
|
|
216
|
+
|
|
217
|
+
- `updateReference` throws rather than gaining an `errors: 'throw'` option. A ref writer whose failures are
|
|
218
|
+
invisible by default is the bug, not a mode.
|
|
219
|
+
- `'absent'` rather than `expected: ''`. The empty old value is git's encoding of "must not exist"; a caller
|
|
220
|
+
spelling it as an empty string reads like a mistake, and an argv filter that drops empty strings would turn
|
|
221
|
+
a create into an unconditional overwrite.
|
|
222
|
+
- New config keys join `GitConfigKeys` rather than widening it to `string` or adding an untyped read. The
|
|
223
|
+
union's value is that every listed key is documented; an escape hatch would keep the autocomplete and lose
|
|
224
|
+
the guarantee.
|
|
225
|
+
- `deleteReference` gives a branch `git branch -d`'s guard and cleanup rather than refusing branches. A
|
|
226
|
+
compare-and-swap delete of a branch is legitimate (sync-tools' port contract exercises one), and refusing it
|
|
227
|
+
would push the caller back to a raw `update-ref -d` that orphans the same state.
|
|
228
|
+
- A write hard-evicts while a watcher clear keeps sharing in-flight reads, rather than one policy for both. A
|
|
229
|
+
write is a known point after which an older read is wrong; a watcher tick has no such ordering, and sharing
|
|
230
|
+
the in-flight read is what keeps a burst of file events from multiplying git processes.
|
|
231
|
+
- `notifyChanged` on the provider rather than an option on `git.run`. The executor has no context and no
|
|
232
|
+
hooks; the provider does. A consumer that runs a raw mutation knows what it changed.
|
|
233
|
+
- Staging hooks skip the temporary-index case rather than firing unconditionally. A scratch index is not the
|
|
234
|
+
repository's; announcing an index change for it would invalidate status for nothing.
|
|
235
|
+
|
|
236
|
+
**Kepler-side follow-up**, once a core release carries these: serve sync-tools' `updateRef` op through
|
|
237
|
+
`updateReference` / `deleteReference` (mapping in §1), delete the review ref with `deleteReference`, drop the
|
|
238
|
+
verb classifier in `core-git-port.ts` in favour of `notifyChanged`, and retire the remaining
|
|
239
|
+
`TODO(core-gitlens)` residuals.
|