Skip to content

fix(bitbucket): send inline comment ranges with start_to - #3384

Merged
IsmaelMartinez merged 1 commit into
The-PR-Agent:mainfrom
MaxFreedomPollard:fix/bitbucket-inline-comment-range
Sep 15, 2026
Merged

IsmaelMartinez merged 1 commit into
The-PR-Agent:mainfrom
MaxFreedomPollard:fix/bitbucket-inline-comment-range

Conversation

@MaxFreedomPollard

Copy link
Copy Markdown
Contributor

Fixes #3285.

What

pr_agent/git_providers/bitbucket_provider.py: publish_inline_comments now carries the end line of a multi-line comment through to the POST. The request body moved into a new private _post_inline_comment, which sends {"start_to": <start>, "to": <end>} when there is a real span and the existing {"to": <line>} when there is not. publish_inline_comment keeps its signature and its line-text resolution and calls the same helper. Truncation to max_comment_length moved into the helper, so the split does not duplicate it across the two entry points. The stale comment claiming Bitbucket has no range support is gone, and the error log names the range it failed to post.

tests/unittest/test_bitbucket_provider.py: seven new tests on TestBitbucketProvider, from four test functions. One asserts the exact range payload for a 10 to 16 suggestion, one asserts the single-line payload byte for byte, one is parametrized over the four non-span cases (end equal to start, end below start, end null, end key absent), and one pins the comment-length truncation on the multi-line path. _code_suggestion gained an optional end_line.

Why

On main the end line reaches publish_inline_comments in the comment dict and is never read:

pr_agent/git_providers/bitbucket_provider.py:499
            elif 'start_line' in comment:  # multi-line comment
                # note that bitbucket does not seem to support range - only a comment on a single line - ...
                from_line = comment['start_line']

and the payload can only express one line (bitbucket_provider.py:451). The end line exists one call earlier: publish_code_suggestions builds "line": relevant_lines_end, "start_line": relevant_lines_start at bitbucket_provider.py:203-208.

So a suggestion about lines 10 to 16 is posted as a comment on line 10, and a remark about a whole function reads as a remark about its signature. This is the default path on Bitbucket Cloud, not an opt-in one: pr_code_suggestions.py:336-337 renders the markdown table only when gfm_markdown is supported, and BitbucketProvider.is_supported returns False for it (bitbucket_provider.py:226-228), so stock /improve always takes the inline path there.

The community thread cited in that comment is from 2022 and was accurate then: a comment anchored to its single from line. Atlassian closed BCLOUD-5547 "Multi-line comments & code suggestions" on 24 September 2025 with the statement that Bitbucket Cloud now supports multi-line comments and multi-line code suggestions in pull requests, so the comment is out of date. #3285 reports checking the start_to and to payload against a live pull request on 2026-09-10 and seeing the comment render across the range; that check is the reporter's; every test here mocks requests.request.

What this leaves alone. Bitbucket Data Center really does anchor an inline comment to a single line, so bitbucket_server_provider.py is untouched and keeps its own note. publish_inline_comment keeps exactly the parameters the base contract check in tests/unittest/test_git_provider_method_contract.py compares, so no provider signature widens. Single-line comments still send the same JSON string with the same key order. An inverted or zero-width range is not a span, so it is posted as a single line; publish_code_suggestions already drops end < start at bitbucket_provider.py:194-200, so the remaining case is end equal to start. The return contract of publish_inline_comments is unchanged, and the truncation to max_comment_length still applies on both paths.

Testing

PYTHONPATH=. uv run pytest tests/unittest/test_bitbucket_provider.py on this branch: 105 passed. Main is 98.

The same file with only the change to pr_agent/git_providers/bitbucket_provider.py reverted: 2 failed, 103 passed. The two are test_publish_code_suggestions_anchors_a_multi_line_suggestion_to_the_whole_range and test_publish_inline_comments_truncates_a_multi_line_body, both sending {"to": <start>, "path": ...} where {"start_to": <start>, "to": <end>, "path": ...} was expected. The other five pass on main by design; they pin behaviour this change must not move.

PYTHONPATH=. uv run pytest tests/unittest: 8263 passed, 33 skipped, 1 xfailed in 97.6s.

uv run ruff check --fix pr_agent/git_providers/bitbucket_provider.py tests/unittest/test_bitbucket_provider.py: all checks passed, nothing to fix. pre-commit was not run locally; the hook-relevant checks were done by hand on both files: LF line endings, no trailing whitespace, exactly one final newline, and no added line over 120 characters.

publish_code_suggestions already computes the span of a suggestion, but
publish_inline_comments kept only start_line and dropped the end, so every
multi-line suggestion was posted against its first line. The POST body now
moves into a private _post_inline_comment helper that emits
{"start_to": from, "to": to} when there is a real span and the existing
single-line {"to": ...} form otherwise, which keeps the public
publish_inline_comment signature identical to the base contract. An equal or
inverted range is not a span, so it is posted as a single line. Bitbucket Data
Center is untouched because its API really does anchor inline comments to one
line.
@qodo-free-for-open-source-projects

Copy link
Copy Markdown
Contributor

PR Summary by Qodo

Anchor Bitbucket inline comments to multi-line ranges

🐞 Bug fix 🧪 Tests 🕐 10-20 Minutes

Grey Divider

AI Description

• Preserve multi-line suggestion spans in Bitbucket Cloud inline comment payloads.
• Centralize payload construction and truncation while retaining single-line behavior.
• Cover range, fallback, and truncation behavior with mocked request tests.
Diagram

sequenceDiagram
    participant S as Suggestion Flow
    participant P as Inline Publisher
    participant H as Payload Helper
    participant B as Bitbucket Cloud
    S->>P: Comment with span
    P->>H: Start and end lines
    H->>H: Truncate and validate
    alt Valid range
        H->>B: POST start_to and to
    else Single line
        H->>B: POST to
    end
    B-->>H: API response
Loading
High-Level Assessment

The shared private posting helper is the appropriate approach: it supports range payloads without widening the public provider method signature, preserves byte-for-byte single-line payload behavior, and keeps truncation consistent across entry points. Extending the public method was considered but would conflict with the cross-provider contract, while changing Bitbucket Server would incorrectly assume API parity.

Files changed (2) +86 / -10

Bug fix (1) +17 / -8
bitbucket_provider.pyPost valid inline spans using Bitbucket range fields +17/-8

Post valid inline spans using Bitbucket range fields

• Adds a shared '_post_inline_comment' helper that truncates content and emits 'start_to' plus 'to' for valid multi-line spans. Single-line, missing-end, equal-end, and inverted-end comments retain the existing payload shape, while failures now identify the attempted range.

pr_agent/git_providers/bitbucket_provider.py

Tests (1) +69 / -2
test_bitbucket_provider.pyVerify range payloads and single-line compatibility +69/-2

Verify range payloads and single-line compatibility

• Extends suggestion fixtures with optional end lines and tests exact multi-line and single-line request payloads. Parametrized cases cover invalid or absent ranges, and an additional test confirms body truncation remains active for ranged comments.

tests/unittest/test_bitbucket_provider.py

@qodo-free-for-open-source-projects

qodo-free-for-open-source-projects Bot commented Sep 15, 2026 •

Copy link
Copy Markdown
Contributor

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (1) 📎 Requirement gaps (0) 🎨 UX issues (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Two range comments use narration 📘 Rule violation ⚙ Maintainability
Description
_post_inline_comment says Bitbucket Cloud anchors a span and a non-span is posted, while the
new test comment says a span may become a range and everything else stays single-line. These
descriptions are encountered when changing range selection or extending edge-case tests, so later
readers do not receive imperative guidance about preserving those branches.
Code

pr_agent/git_providers/bitbucket_provider.py[R448-449]

+        # Bitbucket Cloud anchors a span with 'start_to' and 'to'. Anything that is not a real
+        # span is posted as a single-line comment.
Evidence
Compliance rule 2694688 requires newly added behavioral comments to use imperative phrasing. The
cited production comment uses descriptive and passive forms (anchors and is posted), and the
test comment uses narrative forms (may become and stays).

Rule 2694688: Docstrings and comments must use imperative phrasing
pr_agent/git_providers/bitbucket_provider.py[448-449]
tests/unittest/test_bitbucket_provider.py[673-673]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Two newly added comments describe range behavior using narrative or passive phrasing instead of imperative instructions.
## Fix Focus Areas
- pr_agent/git_providers/bitbucket_provider.py[448-449]
- tests/unittest/test_bitbucket_provider.py[673-673]
## Recommended Fix
Rewrite the production comment as direct instructions such as `Anchor genuine spans with start_to and to; post all other cases as single-line comments.` Rewrite the test comment similarly, while preserving its explanation of the valid-span invariant.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


  • Author self-review: I have reviewed the code review findings, and addressed the relevant ones.

Grey Divider

Tip of the day
💡 Did you know, you can reply 'qodo' on any finding to push back, ask questions, or dig deeper

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

@IsmaelMartinez IsmaelMartinez left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks for scoping this exactly as asked on #3285 and for going back to the API for the field names. Approving.

A 10 to 16 span now goes out as {"start_to": 10, "to": 16}, single-line comments send the same JSON as before, and both range tests go red against main. The helper split is the right call given the provider signature contract.

Qodo's one finding is its own imperative-phrasing rule rather than a repository one, so nothing to change. This lands first of the three Bitbucket PRs; #3386 and #3387 merge cleanly on top.

@IsmaelMartinez
IsmaelMartinez merged commit e2935b6 into The-PR-Agent:main Sep 15, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bitbucket Cloud: multi-line inline comments collapse onto their first line (inline.start_to is never sent)

2 participants