Skip to content

Add pr create command - #67

Merged
mkajander merged 3 commits into
mainfrom
feat/pr-create
Sep 23, 2026
Merged

mkajander merged 3 commits into
mainfrom
feat/pr-create

Conversation

@mkajander

@mkajander mkajander commented Sep 23, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This change adds bbt pr create. It also fixes two problems in shared code that a review of the new command found.

bbt pr create

bbt pr create [-t/--title <text>] [--body <text>|--body-file <path>]
              [-s/--source <branch>] [-d/--destination <branch>]
              [-r/--reviewer <id>]... [--close-source-branch] [--draft]
  • The source defaults to the current git branch. The branch must already be on Bitbucket.
  • The request has no destination when --destination is not set. Bitbucket then uses the repository main branch.
  • The title defaults to the latest commit subject on origin/<source>. If that ref does not exist, the command uses the local branch. The command uses a local title only when the checkout origin is the target repository. In other cases, --title is necessary.
  • --reviewer accepts a UUID in braces ({...}) or an Atlassian account id. You can use it more than one time.
  • --quiet prints the PR id. --json prints the same object as pr view --json.

Retry of write requests

Before this change, the client retried POST requests after 502/503/504, timeouts, and network errors. Bitbucket can apply a request before the response fails. A retry can then create a duplicate pull request or comment.

Now POST and PATCH requests retry only on 429. After other failures, the command stops and tells the user to check the current state. GET, PUT, and DELETE requests retry as before. The new BitbucketRetryPolicy applies to BitbucketClient and to bbt api.

Error output

BbtAsyncCommand now removes control characters from all error messages before it writes them to stderr. Error text can contain user input or API text, so this stops terminal escape codes.

Arguments that start with whitespace

Spectre.Cli 0.49.0 hangs when an argument starts with whitespace. All commands had this problem. For example, bbt pr view " " hangs, and --body "$(cat notes.md)" hangs when the file starts with a blank line. Version 0.49.0 is the latest release.

Program.cs now removes leading whitespace from each argument before Spectre parses it. Spectre already trims option values, so a value that works today does not change. A whitespace-only argument becomes empty, and Spectre shows its "no value provided" error.

pr create also rejects an empty --body-file path, as the Copilot review asked.

Tests

  • dotnet build -warnaserror: 0 warnings, 0 errors.
  • dotnet test: 33 passed. New tests cover the create request body, the retry rules for POST and GET, and the argument trim.
  • Manual checks: the CLI shows the help text and the validation errors. Commands with a whitespace-only argument or a body that starts with a newline now stop at once. The title guess stops when the checkout is a different repository. An escape sequence in --source does not get to stderr.
  • I did not create a pull request on a real Bitbucket repository.

Add `bbt pr create` to open a pull request from a branch. The source
defaults to the current branch. The destination defaults to the
repository main branch. The title defaults to the latest commit subject
on `origin/<source>`, then on the local branch. The command uses a local
title only when the checkout origin is the target repository.

Do not resend POST or PATCH requests after a gateway error, a timeout,
or a lost connection. Bitbucket can apply such a request before the
failure, so a retry can create a duplicate pull request or comment.
These requests retry only on 429. The change applies to BitbucketClient
and to `bbt api`.

Remove control characters from all error messages before they go to
stderr, so user input and API text cannot send terminal escape codes.
Copilot AI lite review requested due to automatic review settings September 23, 2026 22:16

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The new pr create command is missing validation for an empty/whitespace --body-file path, which can currently fail at runtime instead of producing a CLI validation error.

Get a fresh assessment by requesting another Copilot review.

Review effort: Lite
Findings: 1 Medium severity

Open (1)
What changed in this PR

Adds a new bbt pr create CLI command for creating Bitbucket Cloud pull requests, and hardens shared infrastructure uncovered during implementation (safer retry behavior for non-idempotent requests and sanitized error output).

Changes:

  • Add bbt pr create including title derivation from pushed branch tip, optional description/reviewers, and structured output modes.
  • Introduce BitbucketRetryPolicy and apply it to both BitbucketClient and bbt api retry logic (POST/PATCH retry only on 429; idempotent methods retry on gateway errors/timeouts as before).
  • Sanitize all command error output to prevent terminal control-sequence injection; add tests and documentation for the new PR-create contract.
File Description
tests/​Bbt.Core.Tests/​Bitbucket/​BitbucketClientRetryTests.cs Adds coverage for new retry rules (POST vs GET).
tests/​Bbt.Core.Tests/​Bitbucket/​BitbucketClientCreatePullRequestTests.cs Verifies PR-create JSON body serialization (full + omitted optional fields).
src/​Bbt/​Program.cs Registers bbt pr create in the CLI.
src/​Bbt/​Infrastructure/​BbtAsyncCommand.cs Sanitizes all stderr error output via TerminalSanitizer.
src/​Bbt/​Commands/​Pr/​PrCreateCommand.cs Implements bbt pr create command, including title derivation and request construction.
src/​Bbt/​Commands/​Llms/​LlmsCommand.cs Documents the new command in the LLM “capabilities” output.
src/​Bbt/​Commands/​Api/​ApiCommand.cs Applies BitbucketRetryPolicy to raw API retry behavior.
src/​Bbt.Core/​Git/​GitClient.cs Adds helper to read latest commit subject for a revision.
src/​Bbt.Core/​Bitbucket/​Models/​CreatePullRequestRequest.cs Adds request DTOs for creating pull requests (endpoint/reviewer models).
src/​Bbt.Core/​Bitbucket/​BitbucketRetryPolicy.cs Centralizes retry rules and “outcome unknown” exception creation.
src/​Bbt.Core/​Bitbucket/​BitbucketClient.cs Adds PR-create API call and updates retry logic to use new policy.
README.md Updates CLI docs for pr create and retry behavior notes.
docs/​contracts/​bitbucket-cloud-v0.1.md Adds contract documentation for PR-create endpoint and request rules.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/Bbt/Commands/Pr/PrCreateCommand.cs
Validate the path before the command reads the file, the same as the --title, --source, and --destination checks.
Copilot AI review requested due to automatic review settings September 23, 2026 22:54

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🔵 Needs a closer look

The new pr create option validation/help text has correctness/documentation mismatches (notably --body/--body-file handling) that should be resolved before approval.

Review effort: Lite
Findings: None

Resolved since last review (1)
Previously missed (5)

In code that hasn't changed since last review

Low severity Docs say POST-only retry, but PATCH is also non-idempotent

README.md:117

This note says only POST requests are treated as write requests for the retry policy, but the new BitbucketRetryPolicy also treats PATCH as non-idempotent (no retry except 429). Update the wording here to match the implemented behavior.

Low severity LLM catalog incorrectly says pr create always defaults title

src/​Bbt/​Commands/​Llms/​LlmsCommand.cs:83

The LLM command catalog says the title always defaults to the latest commit subject, but pr create only derives a default title when the current checkout’s origin matches the target repository; otherwise --title is required. Adjust the wording to avoid misleading automation that consumes this catalog.

Low severity --title help overstates when a default title is available

src/​Bbt/​Commands/​Pr/​PrCreateCommand.cs:21

--title help text implies a default is always available, but TryDeriveTitleAsync intentionally returns null unless the current checkout’s origin matches the target repo (and the branch exists locally/remotely). Consider reflecting that constraint in the option description so bbt pr create --help matches the actual behavior.

Low severity pr create description should note title may require --title

src/​Bbt/​Program.cs:32

This description implies the title default is always available, but pr create requires --title when it cannot safely derive a title (e.g., checkout origin doesn’t match the target repo). Consider updating this one-liner to reflect that limitation.

Low severity Test name mismatches 503 ServiceUnavailable response

tests/​Bbt.Core.Tests/​Bitbucket/​BitbucketClientRetryTests.cs:51

Test name says GatewayError but the first response is ServiceUnavailable (503). Renaming the test would better reflect what’s being exercised and make failures easier to interpret.

Spectre.Cli 0.49.0 hangs when an argument starts with whitespace. For
example, `bbt pr view " "` hangs, and `--body "$(cat notes.md)"` hangs
when the file starts with a blank line. Version 0.49.0 is the latest
release, so an upgrade does not fix it.

Spectre trims option values, so this change does not alter a value that
parses today. A whitespace-only argument becomes empty, and Spectre
then shows its "no value provided" error.
Copilot AI review requested due to automatic review settings September 23, 2026 23:22
@mkajander
mkajander merged commit 11a1146 into main Sep 23, 2026
5 checks passed
@mkajander
mkajander deleted the feat/pr-create branch September 23, 2026 23:24

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟢 Approval recommended

The changes are cohesive, align with the stated PR behavior, and are backed by targeted new tests for request body shape, retry semantics, and argument trimming.

Review effort: Lite
Findings: None

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants