Repository navigation
feat(bitbucket): deliver to Bitbucket Cloud - #20
Merged
Merged
Conversation
A provider of type bitbucket is Bitbucket Cloud: its url defaults to https://bitbucket.org and its API to https://api.bitbucket.org/2.0. Any other url needs an api_url (a test server); Bitbucket Data Center has another API and is not this type. Web URLs such as https://bitbucket.org/acme/billing resolve to the provider, workspace/repository as on the other platforms without nested namespaces, and exclude and match warn about paths deeper than that. Bitbucket has no topics: check refuses topics on an entry whose provider is Bitbucket, with a hint to use match or repo. The JSON Schemas of hub.yml, the plan and doctor reports, and targets.yml follow, and so does the reference.
…quests
A new driver, internal/platform/bitbucket, serves plan for providers of type bitbucket; its write driver refuses with ClassUnsupported until the writer comes, so distribute and doctor stop at such a provider, and setup and the hub's key store say Bitbucket is not supported yet.
The reader authenticates with an API token of a bot account: Bearer for the REST API, Basic x-bitbucket-api-token-auth for git, both masked. Accounts are their uuids in braces (Lookup takes a uuid or an Atlassian account id and refuses anything else: Bitbucket finds no account by name). Probe asks nothing: flavor bitbucket, native drafts, closed_by as the closer, a 60 000-byte body, the marker as a Markdown link reference definition (platform.MarkerInRefDef, whose codec comes with the writer), branch restrictions known at push time only, and 15 reads a minute with two targets at once. Repo and Resolve read workspace/slug and a workspace's repositories through the next links (topics are refused); a repository without a main branch is empty.
ReadFile resolves the ref to a commit, reads the path's metadata, then its raw bytes at that commit, and computes the blob id. Symlinks, submodules, directories and Git LFS files are not regular. Only a path an existing commit lacks is ErrNotFound; a missing repository, ref or commit is ClassUnknown, never an opt-out. PRs lists the sync branches' pull requests in every state through q= (sorted by descending id), maps OPEN, MERGED, DECLINED and SUPERSEDED, takes the closer from closed_by and ClosedAt from updated_on, checks bases other than the default branch, and expands the short head of an open pull request through the commit API. OpenPRsBy sweeps every workspace of the identity by author.
Errors follow Bitbucket's {"type": "error"} body: 401 auth, 403 permission, 404 and 410 not found, 429 or a rate-limit message rate limited with the wait from Retry-After or x-ratelimit-reset, 5xx transient. Tests run on an HTTP test server with answers shaped after the OpenAPI description and anonymous answers of public repositories.
…ition Bitbucket Cloud escapes HTML in descriptions, so the marker's HTML comment would show as text. EncodeFrame writes the same payload in a link reference definition, [touchmark]: # "touchmark:v1 ...", which renderers hide. Find, Strip and Parse read both frames, with CRLF line endings and the backslash escapes Bitbucket adds after a web edit undone. prbody accepts the new frame as Render's marker, keeps it as a marker line and reserves it in the intro.
On a platform without labels the core asks for none: no labels on new pull requests, none recorded as set in the marker, no AddLabels edits when hub.yml gains one, no label writes in the estimates, and no advice about labels in the auto-decline comment. The marker is written in the frame of Caps.Marker (a reference definition on Bitbucket), and doctor reads markers in both frames. A push Bitbucket refuses with "Permission denied to update branch" is blocked:rules:protected-branch. A Bitbucket commit without the account's email is authored by <uuid>@touchmark.invalid. The fake refuses labels where its caps say there are none.
NewWriter builds a real writer. Target reads the repository by its uuid and
the writer's permission from GET /2.0/user/workspaces/{workspace}/
permissions/repositories (write or admin; read or none is ClassPermission
with rule contents or pull-requests). The TargetWriter pushes with the API
token's Basic credentials, opens pull requests (draft flag, the source
branch kept on merge, labels ignored), edits open ones with one PUT that
sends back title, description, draft flag and reviewers, declines after the
PUT so that the closed marker is written first, refuses to reopen or change
a declined pull request, comments, and has no labels to ensure. Probe sets
NoLabels; the writer's Self reads the account's primary confirmed address
for its commits. The Checker reports access per repository, branch
restrictions as unknown, and the token's expiry, scopes and 2fa as unknown.
setup's refusal now says that a hub on Bitbucket Pipelines comes later.
Bitbucket Cloud's declined pull requests can never be edited, and its descriptions show the HTML comments the tick boxes rest on. ClosedImmutable says the first (Bitbucket's Probe sets it); BodyControls derives the second from the marker store.
…ests are immutable With MemoryConfig.ClosedImmutable the optin an open pull request's marker held stands for the ack: a decline holds while the opt-in file hashes the same and lapses when it changes. One without optin holds and is listed in Memory.Unanchored. A forget_declines entry lifts a decline while present (Memory.Forgotten), ticked repropose controls are ignored, and ToAck and ToRevoke stay empty, so no write to a closed pull request is planned.
Without Caps.BodyControls the body shows no control, the paused block asks for a recreate entry in .touchmark/operations.yml, and the footnote names forget_declines (also where closed pull requests are immutable). Only the Bitbucket goldens change.
CapsFor(Bitbucket) matches the driver's Probe: no labels, closed pull requests immutable, the marker as a reference definition, native drafts, a known closer, no workflow permission. EditPR of a declined pull request and its reopening are ClassUnsupported, a person cannot reopen one, a close counts as an edit and a decline.
… immutable Memory gets Caps.ClosedImmutable and reads tick boxes only where descriptions carry them; the open pull request's marker keeps the current optin there (one edit when it is stale); an unanchored decline gets a target warning; a forget_declines entry that lifts a decline while present is reported as applying.
Decline, its lapse on an opt-in change, forget_declines while present, an unanchored decline, touchmark's own closes (no-diff, target-dropped), no labels and no tick boxes; bodies elsewhere stay byte for byte on an opt-in change. The property test runs 30 Bitbucket scenarios, the crash matrix three Bitbucket cases.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Bitbucket Cloud as a delivery platform: a hub on GitHub, GitLab or Gitea/Forgejo can now deliver to repositories on bitbucket.org. A hub that itself lives on Bitbucket (Bitbucket Pipelines) comes later.
Provider type
bitbucket.urldefaults to https://bitbucket.org, the API to https://api.bitbucket.org/2.0, and web URLs of repositories resolve. The reader and the writer are API tokens of two bot accounts. Logins are account UUIDs (writer: "{…}"), because Bitbucket nicknames are neither unique nor searchable.topics:on a Bitbucket entry failscheck: Bitbucket has no topics, so usematch:orrepo:.Driver (
internal/platform/bitbucket).ErrNotFoundonly at a commit that exists; a missing repository or ref is never one.doctorchecks the writer's access. Branch restrictions need admin rights to read, so they show at the push, where a refusal isrules:protected-branch.Core.
New platform capabilities:
Caps.NoLabels. Bitbucket has no pull request labels: none are planned, set or estimated.MarkerInRefDef. Bitbucket escapes HTML, so the marker is a Markdown reference definition,[touchmark]: # "touchmark:v1 …", which renders as nothing. The payload is unchanged, only the frame differs. Both frames are read everywhere, with CRLF and the backslash escapes of a web edit accepted. Descriptions on Bitbucket carry no HTML: no tick boxes, and a plain list in place of<details>.Caps.ClosedImmutable. Declined pull requests cannot be edited, so decline memory needs no writes there:optincurrent (also while it is blocked);forget_declinesentry lifts it while the entry is present;GitHub, GitLab, Gitea and Forgejo are unchanged, and tests prove their bodies and decisions are byte-identical.
Tests.
bitbucketflavor of the fake platform, delivery scenarios on it, a Bitbucket property simulation and new crash-matrix cases.An independent review found no regressions on the existing platforms; its three findings are fixed here.
Not verified live (no account). These are listed in the docs: