Skip to content

fix: resolve issue #295 - bert-e: pr status should be displayed at all time - #296

Closed
matthiasL-scality wants to merge 5 commits into
mainfrom
fix/issue-295
Closed

matthiasL-scality wants to merge 5 commits into
mainfrom
fix/issue-295

Conversation

@matthiasL-scality

Copy link
Copy Markdown
Contributor

Automated Fix for Issue #295

Issue: bert-e: pr status should be displayed at all time

Description:
TL;DR: authors and reviewers find the status of a pull request fast. This decreases the questions about the status.

Context: Bert-E writes a new comment at each step. These comments mix with the comments of humans and other bots. The status must be asked for and sometines the link to integration branch are hard to find or just not mentionned.

What: the user cannot find the current status of the pull request. Old error comments stay visible after the fix. The user cannot see what is the current status of Bert-e.

How: show the status in a prominent place, as close as possible to the description. Do not change the description. Update the status with the latest state, for example Conflict. Show the name of each integration pull request and branches. If possible, show the build status next to it. For example dependabot changes its message when rebasing.

Done:

the status shows near the description of the pull request

the description of the pull request does not change

the status shows the latest state, for example Conflict, and the name of each integration pull request

optional: the status shows the build status next to the state


Changes Made

This PR was automatically generated by Claude Code based on the issue analysis.

AI Evaluation

  • Relevance: true
  • Confidence: 75%
  • Reason: Feature request bien spécifiée pour améliorer l'affichage du statut des PR dans Bert-E. Critères d'acceptation clairs et cas d'usage défini. Nécessite modifications de l'interface et logique d'affichage.

Files Modified

[
"bert_e/server/api/pr_handler.py",
"bert_e/git_host/github.py",
"bert_e/workflow/gitwaterflow/branches.py",
"bert_e/server/templates/status_message.py",
"bert_e/lib/templates.py"
]

Tests Created

[
"tests/test_pr_status_display.py",
"tests/test_status_message_updates.py",
"tests/integration/test_github_status_display.py"
]


Generated by n8n automation workflow

@matthiasL-scality
matthiasL-scality requested a review from a team as a code owner October 1, 2026 13:08
(c for c in pull_request.comments
if c.author == settings.robot and
c.text.startswith(STATUS_COMMENT_MARKER)), None)
if existing is None:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bitbucket Comment has no update, but the check only fails after the first comment is posted. With status_comment: true on Bitbucket, the first call posts a status comment. Every later call then raises NotImplementedError and only logs a warning, so a stale status stays on the PR forever. Check that update is supported before calling add_comment, or reject the setting for Bitbucket when settings load.

— Claude Code

try:
_update_status_comment(settings, pull_request, comment)
except NotImplementedError:
LOG.warning("Status comment is not supported by this git host")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Only NotImplementedError is caught here. An API error from the new status comment (requests.HTTPError from PATCH/POST) will propagate and skip the normal comment and bot status. That means an optional feature can break the main notification path. Catch and log errors from _update_status_comment more broadly, e.g. requests.HTTPError.

— Claude Code

The pull request description is left untouched: the status lives in a
dedicated comment, edited in place whenever the state changes.
"""
if not getattr(settings, 'status_comment', False) or \

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This path skips settings.interactive, which _send_comment honors. In interactive mode, the status comment is posted or edited without asking for confirmation. Return early when settings.interactive is set, or apply the same confirm() check.

— Claude Code

The pull request description is left untouched: the status lives in a
dedicated comment, edited in place whenever the state changes.
"""
if not getattr(settings, 'status_comment', False) or \

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Every message except Init/Help overwrites the status, including informational ones like PendingHotfixVersionReminder from jira.py. The "status" then shows a reminder instead of the real PR state. Only update the status for messages that carry a state, e.g. comment.status is not None, or use an explicit allow-list.

— Claude Code

comment, (exceptions.InitMessage, exceptions.HelpMessage)):
return
text = render_status_comment(comment)
existing = next(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

On GitHub, pull_request.comments is not cached: it re-lists every page on each access. notify_user already lists comments again in find_comment, so this doubles the comment API calls per notification. That matters on PRs with many comments and for rate limits. Fetch the list once and reuse it.

— Claude Code

@claude

claude Bot commented Oct 1, 2026

Copy link
Copy Markdown
  • Bitbucket has no Comment.update: the first status comment is posted, then every later update fails with a warning, so the status goes stale.
    - Check that update is supported before add_comment, or reject status_comment for Bitbucket when settings load.
    - HTTP errors from the status comment are not caught, so they block the normal comment and bot status.
    - Also catch and log requests.HTTPError (or wider) around _update_status_comment.
    - The status comment skips the settings.interactive confirmation.
    - Return early or ask confirm() the same way _send_comment does.
    - Informational messages (e.g. PendingHotfixVersionReminder) overwrite the status.
    - Only update the status for messages with comment.status is not None, or use an allow-list.
    - Comments are listed twice per notify_user on GitHub (no cache).
    - Fetch the comment list once and reuse it.
    - The issue asks to show integration branches/PRs and build status; the status comment only repeats the last message.
    - Add the integration PR/branch list, or narrow the scope in the PR description.
    - New status_comment setting has no docs and no test that uses the real GitHub/mock Comment.update.
    - Document the setting and add a test through the mock git host.

    Review by Claude Code

@upsun-dispatch

upsun-dispatch Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

📋 PR Summary

This PR adds a single Bert-E status comment that stays up to date and shows the pull request's current state, so users don't have to dig through step-by-step comments. The comment carries a marker, is edited in place when the host supports that (otherwise the old one is deleted and a new one posted), and is left out of regular comment lookups. The latest changes add an include_status option so the greeting check also counts the status comment. They also skip the status update when deleting the old comment fails, instead of posting a duplicate.

Changes
Layer / File(s) Summary
Git host comment editing
bert_e/git_host/base.py Adds an interface for updating an existing comment in place.
bert_e/git_host/bitbucket/__init__.py Implements in-place comment updates for Bitbucket.
bert_e/git_host/github/__init__.py Implements in-place comment updates for GitHub.
bert_e/git_host/mock.py Adds comment update support to the mock host.
Status comment logic
bert_e/workflow/pr_utils.py Adds the status comment marker and the create/update logic. find_comment skips the status comment unless include_status=True. If deleting the old comment fails, a warning is logged and the update is skipped.
bert_e/workflow/gitwaterflow/__init__.py send_greetings counts the status comment as an existing robot comment, so the greeting is not posted again.
bert_e/settings.py Adds settings for the status comment feature.
Tests
bert_e/tests/unit/test_status_comment.py Unit tests for the status comment, including a new test for find_comment with include_status.

@upsun-dispatch upsun-dispatch Bot 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.

Warning

Changes suggested — 🟡 4 warnings · 🔵 1 minor point

🔍 Full review · 6 files reviewed

Verification
  • _update_status_comment only matches comments whose author equals settings.robot, so a user's comment containing the marker cannot hijack the status.
  • The status comment is skipped when no_comment is set and when the new status_comment setting is off (its default is False).
  • The NotImplementedError handler wraps only the status-comment step, so _send_bot_status and _send_comment still run when update is unsupported.
  • send_greetings is not suppressed, because InitMessage is excluded and so the status comment can never come before the greeting.

The new unit tests in bert_e/tests/unit/test_status_comment.py use fake PR and comment classes only. Nothing tests the real GitHub Comment.update, the Bitbucket path (which has no update), or how the status comment interacts with comment dedupe.

Review details
  • Commit: 81516bd
  • Model: claude-opus-5-5

Review 1 of 10 for this pull request · View the full run

Comment thread bert_e/workflow/pr_utils.py Outdated
Comment thread bert_e/workflow/pr_utils.py Outdated
Comment thread bert_e/workflow/pr_utils.py
Comment thread bert_e/workflow/pr_utils.py
Comment thread bert_e/git_host/github/__init__.py Outdated
@codecov

codecov Bot commented Oct 1, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.00000% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.39%. Comparing base (cfe0bc2) to head (14e92fc).

Files with missing lines Patch % Lines
bert_e/workflow/pr_utils.py 81.48% 5 Missing ⚠️
bert_e/git_host/base.py 50.00% 1 Missing ⚠️
bert_e/git_host/mock.py 50.00% 1 Missing ⚠️
bert_e/tests/unit/test_status_comment.py 99.36% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #296      +/-   ##
==========================================
+ Coverage   90.21%   90.39%   +0.17%     
==========================================
  Files          82       83       +1     
  Lines       11293    11490     +197     
==========================================
+ Hits        10188    10386     +198     
+ Misses       1105     1104       -1     
Flag Coverage Δ
integration 87.45% <35.71%> (-0.23%) ⬇️
tests 87.42% <35.71%> (-0.23%) ⬇️
tests-BuildFailedTest 25.70% <21.42%> (-0.02%) ⬇️
tests-QuickTest 32.97% <21.42%> (-0.05%) ⬇️
tests-RepositoryTests 25.38% <21.42%> (-0.02%) ⬇️
tests-TaskQueueTests 49.54% <35.71%> (-0.07%) ⬇️
tests-TestBertE 66.84% <35.71%> (-0.14%) ⬇️
tests-TestQueueing 51.62% <35.71%> (-0.07%) ⬇️
tests-api-mock 14.23% <2.00%> (-0.22%) ⬇️
tests-noqueue 78.19% <35.71%> (-0.19%) ⬇️
tests-noqueue-BuildFailedTest 25.70% <21.42%> (-0.02%) ⬇️
tests-noqueue-QuickTest 32.97% <21.42%> (-0.05%) ⬇️
tests-noqueue-RepositoryTests 25.38% <21.42%> (-0.02%) ⬇️
tests-noqueue-TaskQueueTests 49.54% <35.71%> (-0.07%) ⬇️
tests-noqueue-TestBertE 63.42% <35.71%> (-0.13%) ⬇️
tests-noqueue-TestQueueing 25.40% <21.42%> (-0.02%) ⬇️
tests-server 26.34% <4.50%> (-0.39%) ⬇️
unittests 44.58% <95.50%> (+1.16%) ⬆️
utests 30.51% <95.50%> (+1.41%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@upsun-dispatch upsun-dispatch Bot 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.

Note

Reviewed — No new issues found · 5 still open

🔁 Incremental · 3 files reviewed

Outstanding from earlier reviews:

  • 🟡 #4155716296 — bert_e/workflow/pr_utils.py:130: Bitbucket users see a frozen, wrong status that looks authoritative. — Bitbucket still cannot update the comment (the explicit raise was added in this push), and add_comment still does not refresh the cached _comments.
  • 🟡 #4155716328 — bert_e/workflow/pr_utils.py:120: The always-current status can show the reply to a command instead of the real state. — The exclusion list is unchanged: StatusReport, UnknownCommand and similar replies still replace the status heading.
  • 🟡 #4155716342 — bert_e/workflow/pr_utils.py:137: Duplicate bot comments, the noise this feature is meant to reduce. — The status comment is still created before _send_comment. With the default dont_repeat_if_in_history=-1 it becomes the newest robot comment, so dedupe misses and the message is posted again. The new tests only exercise the 10 case.
  • 🟡 #4155716353 — bert_e/workflow/pr_utils.py:128: Interactive mode no longer gates every comment Bert-E posts. — The status comment still bypasses the settings.interactive confirm.
  • 🔵 #4155716359 — bert_e/git_host/github/__init__.py:1022: Code that later compares created_on on an updated comment would get a string, not a datetime. — Partly fixed: Client.patch now sends PATCH, but Comment.update still stores the raw JSON in self.data without going through schema.Comment.
Verification
  • Client.patch now calls session.patch. Its only callers are Comment.update and AbstractGitHostObject.update, which is used by PullRequest.decline, and GitHub documents both endpoints as PATCH.
  • BertESession.request retries on any HTTP method, so moving from POST to PATCH does not skip the retry-on-429/5xx logic.
  • Bitbucket Comment.update now raises NotImplementedError explicitly, which matches the except NotImplementedError already in notify_user.

This push adds unit tests in bert_e/tests/unit/test_status_comment.py. They check that GitHub's update sends PATCH, that Bitbucket's update raises, that a host without update still posts the regular comment, and how dedupe behaves. The dedupe tests only use dont_repeat_if_in_history=10, so no test covers the default -1 path, where the duplicate-comment problem still happens.

Review details

Review 2 of 10 for this pull request · View the full run

if c.author == settings.robot and
c.text.startswith(STATUS_COMMENT_MARKER)), None)
if existing is None:
pull_request.add_comment(text)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

On Bitbucket the status comment is created here, but every later update() raises NotImplementedError. The comment then stays stuck on the first state forever, and a warning is logged on every notification. That is the stale-status problem this PR is meant to fix.
Check that the host supports updates before creating the comment (e.g. a supports_comment_update attribute on the host/comment class), or skip the feature entirely on hosts that don't.

— Claude Code

(c for c in pull_request.comments
if c.author == settings.robot and
c.text.startswith(STATUS_COMMENT_MARKER)), None)
if existing is None:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This skips the settings.interactive confirmation that _send_comment applies, so in CLI interactive mode the status comment is posted or edited without asking. Return early, or prompt, when settings.interactive is set.

— Claude Code

comment: exceptions.TemplateException):
"""Notify user by sending a comment or a build status in a pull request."""
try:
_update_status_comment(settings, pull_request, 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.

With status_comment on, the first notification posts two comments with the same body: the status comment and the regular one. Every later message is still posted as a regular comment too, so thread noise doesn't go down. Consider skipping the regular comment for messages already shown in the status comment, or at least don't post both on the first notification.

— Claude Code

@claude

claude Bot commented Oct 1, 2026

Copy link
Copy Markdown
  • On Bitbucket the status comment is created but can never be updated, so it shows a stale state forever and logs a warning on every run (bert_e/workflow/pr_utils.py:128)
    - Check that the host supports comment updates before creating the status comment, or turn the feature off on Bitbucket
    - The status comment skips the settings.interactive confirmation (bert_e/workflow/pr_utils.py:127)
    - Return early, or prompt, when interactive is set
    - The first notification posts both the status comment and an identical regular comment, and regular comments keep coming, so noise is not reduced (bert_e/workflow/pr_utils.py:137)
    - Don't post the regular comment for messages already reflected in the status comment
    - Only unit tests with fake PR objects; no workflow-level test runs with status_comment: true against the mock host
    - Add a case in bert_e/tests/test_bert_e.py that checks the init message, command handling after Bert-E's last message, and the dedupe behaviour still work when the status comment exists
    - The new status_comment setting is not documented
    - Add it to the settings docs / example config

    Review by Claude Code

comment: exceptions.TemplateException):
"""Notify user by sending a comment or a build status in a pull request."""
try:
_update_status_comment(settings, pull_request, 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.

The status is only refreshed from notify_user, which only runs for TemplateExceptions. SilentExceptions such as BuildInProgress and NothingToDo never reach this code. So after a conflict is fixed and the build starts, the status comment still says Conflict. That is the stale-error problem issue #295 asks to fix. Also refresh the status when a silent exception is raised (e.g. in bert_e.py / handle_pull_request), or at least when status is set on the exception.

— Claude Code

Comment thread bert_e/workflow/pr_utils.py Outdated
existing.update(text)
except NotImplementedError:
# no in-place edit on this host: replace the stale comment
existing.delete()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

On Bitbucket, update always raises, so every state change deletes the status comment and posts a new one at the bottom, next to the regular comment. That doubles the comments and notifications per event, and the status ends up in the thread instead of near the description. Consider turning the feature off (with a warning) on hosts that cannot edit comments, or add update to Bitbucket (PUT .../comments/{id}).

— Claude Code

@claude

claude Bot commented Oct 1, 2026

Copy link
Copy Markdown
  • The status comment goes stale on silent states: SilentExceptions (BuildInProgress, NothingToDo, ...) never call notify_user, so an old Conflict stays shown after the fix.
    - Also update the status comment when silent exceptions are raised (e.g. in handle_pull_request / bert_e.py).
    - On Bitbucket the fallback deletes and re-posts the status comment at every state change. That doubles the comments and notifications, and the status lands at the bottom of the thread.
    - Implement Comment.update for Bitbucket, or turn the feature off with a warning on hosts that cannot edit comments.

    Review by Claude Code

@upsun-dispatch upsun-dispatch Bot 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.

Warning

Changes suggested — 🟡 1 warning · 🔵 1 minor point · 1 still open

🔁 Incremental · 4 files reviewed

Outstanding from earlier reviews:

  • 🟡 #4155716328 — bert_e/workflow/pr_utils.py:120: The always-current status can show the reply to a command instead of the real state. — Only StatusReport and UnknownCommand were added to the exclusions; other command replies and informational messages still replace the status.
Verification
  • GitHub Comment.update now sends its request through Client.patch, which calls session.patch, and runs the response through self.load(..., SCHEMA), so created_on stays a datetime.
  • Bitbucket add_comment sets _comments = None, so the comments property fetches the list again and a second notify_user in the same job finds the status comment.
  • find_comment skips the marker comment for regular lookups, so dont_repeat_if_in_history=-1 dedupe is no longer broken by a newly created status comment.
  • _update_status_comment now returns early when settings.interactive is set, so the status comment can no longer bypass the confirm() gate.

The diff adds unit tests in bert_e/tests/unit/test_status_comment.py for the interactive skip, the command-reply exclusions, dedupe with -1, Bitbucket cache invalidation, the GitHub update schema and the delete-and-replace fallback. All of them use fakes or mocks. No test covers a Bitbucket DELETE that fails, or send_greetings when a status comment is present.

Review details

Review 3 of 10 for this pull request · View the full run

Comment thread bert_e/workflow/pr_utils.py Outdated
existing.update(text)
except NotImplementedError:
# no in-place edit on this host: replace the stale comment
existing.delete()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Warning — Silent delete failures leave duplicate, conflicting status comments on Bitbucket PRs.

On Bitbucket, the new fallback calls existing.delete() and then add_comment(text) without checking whether the delete worked. Bitbucket Comment.delete goes through AbstractGitHostObject.delete, which calls client.delete(...) and ignores the response. BertESession.request never calls raise_for_status, so a 403, 404 or 5xx on the DELETE fails silently, and a second status comment is posted anyway. On the next state change, next(...) picks the oldest marker comment (get_comments sorts by created_on), which is the stale one that was never deleted. Its delete fails again, and another status comment is added. Each failed delete leaves one more stale status comment on the PR.

Comment thread bert_e/workflow/pr_utils.py Outdated

@upsun-dispatch upsun-dispatch Bot 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.

Warning

Changes suggested — 🟡 1 warning · 2 still open

🔁 Incremental · 2 files reviewed

Outstanding from earlier reviews:

  • 🟡 #4155973742 — bert_e/workflow/pr_utils.py:154: Silent delete failures leave duplicate, conflicting status comments on Bitbucket PRs. — existing.delete() is still unchecked before add_comment, so a failed Bitbucket delete adds another status comment.
  • 🔵 #4155973750 — bert_e/workflow/pr_utils.py:46: The greeting can be re-posted on PRs that already have a bot status. — find_comment still skips the status comment when startswith is None, so send_greetings can post InitMessage again.
Verification
  • InformationException covers InitMessage, IntegrationDataCreated and PendingHotfixVersionReminder, so the hotfix reminder no longer replaces the status.
  • MagicMock(spec=cls) in the test helper passes isinstance against the new exclusion tuple, so the parametrized test really exercises STATUS_COMMENT_EXCLUDED.
  • State messages such as Conflict, Queued, BuildFailed, SuccessMessage and QueueBuildFailedMessage are not in the exclusion tuple and still update the status comment.

The parametrized unit test test_status_comment_not_replaced_by_command_replies in bert_e/tests/unit/test_status_comment.py covers the widened exclusion list. Nothing checks that state messages still update the comment, beyond the existing QueueConflict and Conflict tests.

Review details

Review 4 of 10 for this pull request · View the full run

# Replies to user commands and purely informational messages: they do not
# describe the state of the pull request and must not replace the status.
STATUS_COMMENT_EXCLUDED = (
exceptions.InformationException,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Warning — The status comment never meets the issue's integration-PR listing requirement.

Putting exceptions.InformationException in STATUS_COMMENT_EXCLUDED also leaves out IntegrationDataCreated, which subclasses it (exceptions.py:166). That message is the only template that lists the integration branches with their links and the child pull request numbers (integration_data_created.md). None of the state messages that reach the status comment (Queued, Conflict, BuildFailed, ApprovalRequired…) render those names. So once integration data is created, the status comment never shows the integration pull requests or branches. Issue #295 asks for exactly that ('show the name of each integration pull request and branches'). The new parametrized test also locks the omission in by listing IntegrationDataCreated among the excluded command replies.

if c.author == settings.robot and
c.text.startswith(STATUS_COMMENT_MARKER)), None)
if existing is None:
pull_request.add_comment(text)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The status comment is created on the first non-informational notification, which comes after the init message and possibly other comments. It is not "near the description" as the issue asks.
Consider editing the bot's first comment (the init message) in place, or creating the status comment in send_greetings so it is always the first bot comment.

— Claude Code

Comment thread bert_e/workflow/pr_utils.py Outdated
existing.update(text)
except NotImplementedError:
# no in-place edit on this host: replace the stale comment
existing.delete()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

On Bitbucket this fallback runs on every state change, so the status comment is deleted and re-posted at the bottom of the thread each time. That defeats the "prominent place" goal and spams notifications.
Bitbucket supports editing comments (PUT .../pullrequests/{id}/comments/{comment_id} with {"content": {"raw": ...}}). Implement Comment.update there instead of raising.

— Claude Code

comment: exceptions.TemplateException):
"""Notify user by sending a comment or a build status in a pull request."""
try:
_update_status_comment(settings, pull_request, 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.

The status only refreshes when notify_user is called. Some transitions post nothing, for example a conflict that gets resolved, or a PR waiting on a build. In those cases the status keeps showing the old error, which is the exact problem the issue describes.
Refresh the status at the end of each PR job with the current state, not only as a side effect of notifications.

— Claude Code

pull_request_id=self['id']
)
# invalidate the cache so that the new comment is visible
self._comments = None

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Clearing the cache on every add_comment means the next pull_request.comments access refetches every page of comments. This applies even when status_comment is off, so it adds Bitbucket API calls on every job.
Append the new comment to self._comments instead, if it is already loaded.

— Claude Code

@claude

claude Bot commented Oct 1, 2026

Copy link
Copy Markdown
  • The status comment is not near the description: it is created after the init message and other comments.
      - Edit the bot's first comment in place, or create the status comment in send_greetings.
    - On Bitbucket the status comment is deleted and re-posted at the bottom on every change.
      - Implement Comment.update for Bitbucket with the PUT comment endpoint.
    - The status goes stale when a transition sends no notification (conflict resolved, waiting on build).
      - Refresh the status from the current PR state at the end of each job.
    - Client.patch now sends PATCH instead of POST. This also changes PullRequest.decline on GitHub, and no test covers it.
      - Add a test for decline, or call out the fix in the PR description.
    - Bitbucket add_comment clears the comment cache, which adds a full comment refetch per job even when the feature is off.
      - Append to the cached list instead.
    - The issue asks for each integration branch/PR (and optionally its build status) to be listed. The status only copies the last message.
      - Render the integration branches and PRs in render_status_comment.
    - Tests only use fakes and MagicMock exceptions.
      - Add a test in bert_e/tests/test_bert_e.py that runs the real workflow on the mock host with status_comment=True.

    Review by Claude Code

@upsun-dispatch upsun-dispatch Bot 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.

Note

Reviewed — No new issues found · 2 still open

🔁 Incremental · 3 files reviewed

Outstanding from earlier reviews:

  • 🟡 #4155973742 — bert_e/workflow/pr_utils.py:140: Silent delete failures leave duplicate, conflicting status comments on Bitbucket PRs. — The new try/except only helps when delete raises. Bitbucket Comment.delete goes to AbstractGitHostObject.delete (base.py:215), which calls client.delete and never checks the response. A 403, 404 or 5xx still passes silently, so add_comment posts a duplicate status comment.
  • 🟡 #4156062443 — bert_e/workflow/pr_utils.py:114: The status comment never meets the issue's integration-PR listing requirement. — InformationException is still in STATUS_COMMENT_EXCLUDED, so IntegrationDataCreated and its list of integration PRs and branches never reach the status comment.
Verification
  • send_greetings now passes include_status=True, so if the status comment is the only robot comment left, the greeting is not posted again.
  • find_comment still skips the status comment for the _send_comment dedupe lookup, because that caller leaves include_status at its default of False.
  • jira.py:222 is the only other find_comment caller, and it passes an explicit startswith, so the new keyword does not change its behaviour.
  • _update_status_comment now returns early on settings.interactive and on every STATUS_COMMENT_EXCLUDED class, including PendingHotfixVersionReminder through InformationException.

This diff adds one unit test, test_find_comment_include_status_finds_status_comment, in bert_e/tests/unit/test_status_comment.py. No test covers the new except Exception branch around existing.delete(), and no test covers a Bitbucket DELETE that fails without raising.

Review details

Review 5 of 10 for this pull request · View the full run

"""Notify user by sending a comment or a build status in a pull request."""
try:
_update_status_comment(settings, pull_request, comment)
except NotImplementedError:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Only NotImplementedError is caught here. If the PATCH, POST or DELETE for the status comment fails (e.g. requests.HTTPError on a 403/5xx), the error escapes notify_user before _send_comment runs, so the main notification is lost. The status comment is an optional extra and must not break the main flow. Catch the HTTP error too (add import requests):

Suggested change
except NotImplementedError:
except (NotImplementedError, requests.HTTPError):
LOG.warning("Could not update the status comment", exc_info=True)



— Claude Code

# no in-place edit on this host: replace the stale comment
try:
existing.delete()
except Exception:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

A bare except Exception hides real bugs, like a broken delete() implementation. Catch the HTTP error only:

Suggested change
except Exception:
except requests.HTTPError:



— Claude Code

f"{comment}")


def _update_status_comment(settings, pull_request: AbstractPullRequest,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

The status only changes when a TemplateException goes through notify_user. States raised as SilentException never call it: BuildInProgress, BuildNotStarted, NothingToDo. So after a user fixes a Conflict and the build starts, the status still says Conflict. Issue #295 is about exactly this stale state. Also update the status from the place where the job result is handled (e.g. the handler that catches SilentException), not only from notify_user.

— Claude Code

except NotImplementedError:
# no in-place edit on this host: replace the stale comment
try:
existing.delete()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

On Bitbucket there is no update, so each state change deletes the status and posts it again. The comment then jumps to the bottom of the thread, which is the opposite of "near the description", and sends a new notification each time. Either implement update for Bitbucket (PUT on the comment endpoint) or document that status_comment is GitHub-only and skip it when update is not supported.

— Claude Code

@claude

claude Bot commented Oct 1, 2026 •

Copy link
Copy Markdown
  • Errors from the status comment break notify_user (pr_utils.py:172): only NotImplementedError is caught, so an HTTP error on PATCH, POST or DELETE skips the main comment
    - Also catch requests.HTTPError and log a warning
    - Bare except Exception around existing.delete() (pr_utils.py:159)
    - Catch requests.HTTPError only
    - The status goes stale after a fix (pr_utils.py:134): SilentException states (BuildInProgress, BuildNotStarted, NothingToDo) never update it, so Conflict stays visible once resolved
    - Also update the status where job results are handled, not only in notify_user
    - On Bitbucket, the delete-and-repost fallback (pr_utils.py:158) moves the status to the bottom of the thread and notifies users on each change
    - Implement update for Bitbucket, or make status_comment GitHub-only and document it
    - The status only repeats the last message; issue bert-e: pr status should be displayed at all time #295 also asks for each integration PR/branch and its build status
    - Render the integration PRs/branches (and build status if available) in the status comment, or do not close bert-e: pr status should be displayed at all time #295 with this PR

    Review by Claude Code

@matthiasL-scality
matthiasL-scality deleted the fix/issue-295 branch October 2, 2026 05:47
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.

1 participant