Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions bert_e/git_host/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,10 @@ def key(self) -> str:
class AbstractComment(metaclass=ABCMeta):
"""Abstract class defining the interface of a pull requests's comment."""

@abstractmethod
def edit(self, text: str) -> None:
"""Replace the text of the comment."""

@abstractmethod
def delete(self) -> None:
"""Delete the comment."""
Expand Down
10 changes: 10 additions & 0 deletions bert_e/git_host/bitbucket/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -489,6 +489,16 @@
pull_request_id=self.data['pullrequest']['id'],
comment_id=self.id)

def edit(self, text):
# Bitbucket Cloud only supports PUT to update a comment
url = self.GET_URL.format(

Check warning on line 494 in bert_e/git_host/bitbucket/__init__.py

View check run for this annotation

Codecov / codecov/patch

bert_e/git_host/bitbucket/__init__.py#L494

Added line #L494 was not covered by tests
full_name=self.full_name(),
pull_request_id=self.data['pullrequest']['id'],
comment_id=self.id)
response = self.client.put(

Check warning on line 498 in bert_e/git_host/bitbucket/__init__.py

View check run for this annotation

Codecov / codecov/patch

bert_e/git_host/bitbucket/__init__.py#L498

Added line #L498 was not covered by tests
url, data=json.dumps({'content': {'raw': text}}))
self.data = self.load(response).data

Check warning on line 500 in bert_e/git_host/bitbucket/__init__.py

View check run for this annotation

Codecov / codecov/patch

bert_e/git_host/bitbucket/__init__.py#L500

Added line #L500 was not covered by tests

@classmethod
def create(cls, client, data, **kwargs):
return super().create(client, {'content': {'raw': data}}, **kwargs)
Expand Down
4 changes: 4 additions & 0 deletions bert_e/git_host/github/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1015,6 +1015,10 @@
def id(self) -> int:
return self.data['id']

def edit(self, text: str) -> 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.

The new edit methods for GitHub and Bitbucket have no tests. Only the mock and FakeComment are tested. Add a unit test that checks the request (method, URL, payload) and that self.data gets updated.

— Claude Code

self.data = self.client.patch(

Check warning on line 1019 in bert_e/git_host/github/__init__.py

View check run for this annotation

Codecov / codecov/patch

bert_e/git_host/github/__init__.py#L1019

Added line #L1019 was not covered by tests
self.data['url'], data=json.dumps({'body': text}))

def delete(self) -> None:
self.client.delete(self.data['url'])

Expand Down
5 changes: 5 additions & 0 deletions bert_e/git_host/mock.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,6 +406,11 @@ def comments(self):

class CommentController(Controller, base.AbstractComment):

def edit(self, text):
self.controlled.content = {
"raw": text, "markup": "markdown", "html": text}
self.controlled.updated_on = datetime.now()

def delete(self):
self.controlled.delete()

Expand Down
18 changes: 18 additions & 0 deletions bert_e/templates/pr_status_comment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{{ marker }}
## Bert-E status: {{ state }}
{% if status %}
Result: **{{ status }}**
{% endif %}
{% if integration_prs %}

Integration pull requests:
{% for pr in integration_prs -%}
* #{{ pr.id }}: `{{ pr.src }}` → `{{ pr.dst }}`
{% endfor %}
{% endif %}
{% if active_options %}

*Options set:* **{{ active_options|join(', ') }}**
{% endif %}

*This comment is updated at each step; see the comments below for details.*
18 changes: 9 additions & 9 deletions bert_e/tests/test_bert_e.py
Original file line number Diff line number Diff line change
Expand Up @@ -1387,7 +1387,7 @@ def test_request_integration_branch_creation(self):
with self.assertRaises(exns.RequestIntegrationBranches):
self.handle(
pr.id, settings=settings, options=options, backtrace=True)
self.assertEqual(len(list(pr.get_comments())), 2)
self.assertEqual(len(list(pr.get_comments())), 3)
self.assertIn(
'Request integration branches', self.get_last_pr_comment(pr))
self.assertIn(
Expand All @@ -1397,7 +1397,7 @@ def test_request_integration_branch_creation(self):
with self.assertRaises(exns.BuildNotStarted):
self.handle(
pr.id, settings=settings, options=options, backtrace=True)
self.assertEqual(len(list(pr.get_comments())), 4)
self.assertEqual(len(list(pr.get_comments())), 5)
self.assertIn('Integration data created', self.get_last_pr_comment(pr))
self.assertIn(
'create_integration_branches', self.get_last_pr_comment(pr))
Expand Down Expand Up @@ -1444,7 +1444,7 @@ def test_request_integration_branch_by_creating_pull_requests(self):
with self.assertRaises(exns.BuildNotStarted):
self.handle(
pr.id, settings=settings, options=options, backtrace=True)
self.assertEqual(len(list(pr.get_comments())), 4)
self.assertEqual(len(list(pr.get_comments())), 5)
self.assertIn('Integration data created', self.get_last_pr_comment(pr))

options = self.bypass_all
Expand Down Expand Up @@ -1493,10 +1493,10 @@ def test_creation_integration_branch_by_approve(self):
with self.assertRaises(exns.ApprovalRequired):
self.handle(pr.id, options=options, backtrace=True)

self.assertEqual(len(list(pr.get_comments())), 3)
self.assertEqual(len(list(pr.get_comments())), 4)

self.assertIn(
'Integration data created', list(pr.get_comments())[-2].text)
'Integration data created', list(pr.get_comments())[-3].text)

self.assertIn(
'Waiting for approval', self.get_last_pr_comment(pr))
Expand Down Expand Up @@ -3533,7 +3533,7 @@ def test_bypass_author_comment_check(self):
""" # noqa
pr = self.create_pr('feature/TEST-0042', 'development/10')
self.handle(pr.id, settings=settings)
self.assertIs(len(list(pr.get_comments())), 2)
self.assertIs(len(list(pr.get_comments())), 3)
self.assertIn('bypass_jira_check', self.get_last_pr_comment(pr))
settings = """
repository_owner: {owner}
Expand All @@ -3555,7 +3555,7 @@ def test_bypass_author_comment_check(self):
""" # noqa
pr = self.create_pr('feature/TEST-0043', 'development/10')
self.handle(pr.id, settings=settings)
self.assertIs(len(list(pr.get_comments())), 2)
self.assertIs(len(list(pr.get_comments())), 3)
self.assertIn('bypass_author_approval', self.get_last_pr_comment(pr))

settings = """
Expand All @@ -3578,7 +3578,7 @@ def test_bypass_author_comment_check(self):
""" # noqa
pr = self.create_pr('feature/TEST-0044', 'development/10')
self.handle(pr.id, settings=settings)
self.assertIs(len(list(pr.get_comments())), 2)
self.assertIs(len(list(pr.get_comments())), 3)
self.assertIn('bypass_peer_approval', self.get_last_pr_comment(pr))

settings = """
Expand All @@ -3601,7 +3601,7 @@ def test_bypass_author_comment_check(self):
""" # noqa
pr = self.create_pr('feature/TEST-0045', 'development/10')
self.handle(pr.id, settings=settings)
self.assertIs(len(list(pr.get_comments())), 2)
self.assertIs(len(list(pr.get_comments())), 3)
self.assertIn('bypass_build_status', self.get_last_pr_comment(pr))

def test_bypass_author_jira(self):
Expand Down
93 changes: 93 additions & 0 deletions bert_e/tests/test_pr_status_comment.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
"""Tests of the pinned status comment maintained by notify_user."""
from types import SimpleNamespace

Check warning on line 2 in bert_e/tests/test_pr_status_comment.py

View check run for this annotation

Codecov / codecov/patch

bert_e/tests/test_pr_status_comment.py#L2

Added line #L2 was not covered by tests

from bert_e import exceptions
from bert_e.workflow.pr_utils import (

Check warning on line 5 in bert_e/tests/test_pr_status_comment.py

View check run for this annotation

Codecov / codecov/patch

bert_e/tests/test_pr_status_comment.py#L4-L5

Added lines #L4 - L5 were not covered by tests
STATUS_COMMENT_MARKER, find_comment, find_status_comment, notify_user,
update_status_comment,
)


class FakeComment:
def __init__(self, author, text):
self.author = author
self.text = text

Check warning on line 14 in bert_e/tests/test_pr_status_comment.py

View check run for this annotation

Codecov / codecov/patch

bert_e/tests/test_pr_status_comment.py#L11-L14

Added lines #L11 - L14 were not covered by tests

def edit(self, text):
self.text = text

Check warning on line 17 in bert_e/tests/test_pr_status_comment.py

View check run for this annotation

Codecov / codecov/patch

bert_e/tests/test_pr_status_comment.py#L16-L17

Added lines #L16 - L17 were not covered by tests


class FakePR:
def __init__(self):
self.comments = []

Check warning on line 22 in bert_e/tests/test_pr_status_comment.py

View check run for this annotation

Codecov / codecov/patch

bert_e/tests/test_pr_status_comment.py#L20-L22

Added lines #L20 - L22 were not covered by tests

def add_comment(self, msg):
self.comments.append(FakeComment('bert-e', msg))

Check warning on line 25 in bert_e/tests/test_pr_status_comment.py

View check run for this annotation

Codecov / codecov/patch

bert_e/tests/test_pr_status_comment.py#L24-L25

Added lines #L24 - L25 were not covered by tests

def set_bot_status(self, *args, **kwargs):
pass

Check warning on line 28 in bert_e/tests/test_pr_status_comment.py

View check run for this annotation

Codecov / codecov/patch

bert_e/tests/test_pr_status_comment.py#L27-L28

Added lines #L27 - L28 were not covered by tests


SETTINGS = SimpleNamespace(robot='bert-e', no_comment=False,

Check warning on line 31 in bert_e/tests/test_pr_status_comment.py

View check run for this annotation

Codecov / codecov/patch

bert_e/tests/test_pr_status_comment.py#L31

Added line #L31 was not covered by tests
interactive=False, send_bot_status=False)


def _conflict():
src = SimpleNamespace(name='x')
dst = SimpleNamespace(name='development/1.1', allow_prefixes=['feature'])
return exceptions.IncompatibleSourceBranchPrefix(

Check warning on line 38 in bert_e/tests/test_pr_status_comment.py

View check run for this annotation

Codecov / codecov/patch

bert_e/tests/test_pr_status_comment.py#L35-L38

Added lines #L35 - L38 were not covered by tests
active_options=[], source=src, destination=dst)


def test_status_comment_created_once_and_updated():
pr = FakePR()
err = _conflict()
notify_user(SETTINGS, pr, err)
assert len(pr.comments) == 2

Check warning on line 46 in bert_e/tests/test_pr_status_comment.py

View check run for this annotation

Codecov / codecov/patch

bert_e/tests/test_pr_status_comment.py#L42-L46

Added lines #L42 - L46 were not covered by tests
# the pinned status comment comes first
assert pr.comments[0] is find_status_comment(pr, 'bert-e')
assert 'IncompatibleSourceBranchPrefix' in pr.comments[0].text

Check warning on line 49 in bert_e/tests/test_pr_status_comment.py

View check run for this annotation

Codecov / codecov/patch

bert_e/tests/test_pr_status_comment.py#L48-L49

Added lines #L48 - L49 were not covered by tests

other = exceptions.MissingJiraId(

Check warning on line 51 in bert_e/tests/test_pr_status_comment.py

View check run for this annotation

Codecov / codecov/patch

bert_e/tests/test_pr_status_comment.py#L51

Added line #L51 was not covered by tests
active_options=[], source_branch='x', dest_branch='b')
update_status_comment(SETTINGS, pr, other)
assert len(pr.comments) == 2
assert 'MissingJiraId' in pr.comments[0].text

Check warning on line 55 in bert_e/tests/test_pr_status_comment.py

View check run for this annotation

Codecov / codecov/patch

bert_e/tests/test_pr_status_comment.py#L53-L55

Added lines #L53 - L55 were not covered by tests


def test_informational_message_leaves_status_untouched():
pr = FakePR()
update_status_comment(SETTINGS, pr, _conflict())
before = pr.comments[0].text
update_status_comment(SETTINGS, pr, exceptions.HelpMessage(

Check warning on line 62 in bert_e/tests/test_pr_status_comment.py

View check run for this annotation

Codecov / codecov/patch

bert_e/tests/test_pr_status_comment.py#L58-L62

Added lines #L58 - L62 were not covered by tests
options={}, commands={}, active_options=[]))
assert pr.comments[0].text == before

Check warning on line 64 in bert_e/tests/test_pr_status_comment.py

View check run for this annotation

Codecov / codecov/patch

bert_e/tests/test_pr_status_comment.py#L64

Added line #L64 was not covered by tests


def test_find_comment_skips_status_comment():
pr = FakePR()
pr.add_comment('hello')
pr.add_comment(STATUS_COMMENT_MARKER + ' status')
assert find_comment(pr, 'bert-e', 'hello', -1) is pr.comments[0]

Check warning on line 71 in bert_e/tests/test_pr_status_comment.py

View check run for this annotation

Codecov / codecov/patch

bert_e/tests/test_pr_status_comment.py#L67-L71

Added lines #L67 - L71 were not covered by tests


def test_integration_prs_kept_between_updates():
pr = FakePR()
update_status_comment(SETTINGS, pr, _conflict())
child = SimpleNamespace(id=7, src_branch='w/1.1/x', name='w/1.1/x',

Check warning on line 77 in bert_e/tests/test_pr_status_comment.py

View check run for this annotation

Codecov / codecov/patch

bert_e/tests/test_pr_status_comment.py#L74-L77

Added lines #L74 - L77 were not covered by tests
dst_branch='development/1.1')
info = exceptions.IntegrationDataCreated(

Check warning on line 79 in bert_e/tests/test_pr_status_comment.py

View check run for this annotation

Codecov / codecov/patch

bert_e/tests/test_pr_status_comment.py#L79

Added line #L79 was not covered by tests
active_options=[], child_prs=[child, child], wbranches=[child, child],
ignored=[], githost='mock', owner='o', slug='r', bert_e='bert-e')
update_status_comment(SETTINGS, pr, info)
assert '#7' in pr.comments[0].text
assert 'IncompatibleSourceBranchPrefix' in pr.comments[0].text
update_status_comment(SETTINGS, pr, _conflict())
assert '#7' in pr.comments[0].text

Check warning on line 86 in bert_e/tests/test_pr_status_comment.py

View check run for this annotation

Codecov / codecov/patch

bert_e/tests/test_pr_status_comment.py#L82-L86

Added lines #L82 - L86 were not covered by tests


def test_no_comment_setting_skips():
pr = FakePR()
settings = SimpleNamespace(**{**vars(SETTINGS), 'no_comment': True})
update_status_comment(settings, pr, _conflict())
assert pr.comments == []

Check warning on line 93 in bert_e/tests/test_pr_status_comment.py

View check run for this annotation

Codecov / codecov/patch

bert_e/tests/test_pr_status_comment.py#L89-L93

Added lines #L89 - L93 were not covered by tests
31 changes: 31 additions & 0 deletions bert_e/tests/unit/test_status_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
"""Unit tests for the pinned pull request status comment template."""
from bert_e.lib.template_loader import render
from bert_e.workflow.pr_utils import STATUS_COMMENT_MARKER, STATUS_PR_RE


def _render(**kwargs):
params = dict(marker=STATUS_COMMENT_MARKER, state='Conflict', code=1,
status=None, integration_prs=[], active_options=None)
params.update(kwargs)
return render('pr_status_comment.md', **params)


def test_starts_with_marker_and_shows_state():
text = _render()
assert text.startswith(STATUS_COMMENT_MARKER)
assert 'Conflict' in text


def test_lists_integration_prs_parseable():
text = _render(integration_prs=[
{'id': 12, 'src': 'w/1.1/feature/x', 'dst': 'development/1.1'},
{'id': 13, 'src': 'w/2.0/feature/x', 'dst': 'development/2.0'}])
found = [m.groupdict() for m in STATUS_PR_RE.finditer(text)]
assert [f['id'] for f in found] == ['12', '13']
assert found[1]['dst'] == 'development/2.0'


def test_result_and_options():
text = _render(status='failure', active_options=['after_pull_request'])
assert 'failure' in text
assert 'after_pull_request' in text
87 changes: 87 additions & 0 deletions bert_e/workflow/pr_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,27 @@
"""Pull Requests messaging utility functions."""
import itertools
import logging
import re

import requests

from bert_e import exceptions
from bert_e.git_host import base as git_host_base
from bert_e.git_host.base import AbstractComment, AbstractPullRequest
from bert_e.lib.cli import confirm
from bert_e.lib.template_loader import render

LOG = logging.getLogger(__name__)

STATUS_COMMENT_MARKER = '<!-- bert-e-status -->'
STATUS_STATE_RE = re.compile(r'^## Bert-E status: (?P<state>.*)$',
re.MULTILINE)
STATUS_RESULT_RE = re.compile(r'^Result: \*\*(?P<status>.*)\*\*$',
re.MULTILINE)
STATUS_PR_RE = re.compile(
r'^\* #(?P<id>\d+): `(?P<src>[^`]+)` \u2192 `(?P<dst>[^`]+)`',
re.MULTILINE)


def find_comment(pull_request: AbstractPullRequest, username=None,
startswith=None, max_history=None) -> AbstractComment:
Expand All @@ -43,6 +57,8 @@
for comment in comments:
if comment.author != username:
continue
if comment.text.startswith(STATUS_COMMENT_MARKER):
continue
if startswith and not comment.text.startswith(startswith):
if max_history == -1:
return
Expand Down Expand Up @@ -98,10 +114,81 @@
)


def find_status_comment(pull_request: AbstractPullRequest, username):
"""Return the pinned status comment posted by the bot, if any."""
for comment in pull_request.comments:
if comment.author == username and \
comment.text.startswith(STATUS_COMMENT_MARKER):
return comment
return None


def _integration_pull_requests(comment, previous_text=None):
"""List the integration pull requests known for a status comment.

Use those carried by the message when available, otherwise keep the
ones listed in the previous status comment.
"""
child_prs = comment.kwargs.get('child_prs')
if child_prs:
return [{'id': pr.id, 'dst': pr.dst_branch, 'src': pr.src_branch}
for pr in child_prs]
if previous_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.

🟡 Warning — Stale integration PR links stay pinned and point users at closed PRs.

When the current message has no child_prs, _integration_pull_requests copies the list from the previous status comment's text. Only IntegrationDataCreated ever passes child_prs, and it is sent only when a PR is newly created and there are at least 2 wbranches. So the list never shrinks or refreshes. After /reset, a declined or recreated integration PR, or a PR whose cascade drops to one branch, the comment keeps listing the old PR numbers indefinitely.

return [
{'id': m.group('id'), 'dst': m.group('dst'),
'src': m.group('src')}
for m in STATUS_PR_RE.finditer(previous_text)
]
return []


def update_status_comment(settings, pull_request: AbstractPullRequest,
comment: exceptions.TemplateException):
"""Create or update the single comment showing the latest bot state.

The comment is edited in place so that the current status is always at
the same (early) position in the pull request conversation, and the
description of the pull request is left untouched.
"""
if settings.no_comment or settings.interactive:
return

Check warning on line 154 in bert_e/workflow/pr_utils.py

View check run for this annotation

Codecov / codecov/patch

bert_e/workflow/pr_utils.py#L154

Added line #L154 was not covered by tests
status = getattr(comment, 'status', None)
child_prs = comment.kwargs.get('child_prs')
if status is None and not child_prs:
# informational messages (greetings, help...) do not change the
# state of the pull request
return
existing = find_status_comment(pull_request, settings.robot)

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, PullRequest.comments is cached in _comments and add_comment does not update that cache. If one job calls notify_user twice with a status (e.g. IntegrationDataCreated then BuildNotStarted, once the issue above is fixed), find_status_comment won't see the comment it just created and posts a second one. The mock does not cache, so the tests miss this. Clear or append to _comments after adding the status comment.

— Claude Code

state, code = comment.title, comment.code
if status is None:
# only the integration pull requests changed: keep the state
if existing is None:
return

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 — Integration PR list missing on most PRs, defeating half the feature.

The new if existing is None: return throws away the child_prs of an IntegrationDataCreated message whenever no status comment exists yet. That is the normal case on a clean PR. InitMessage carries no status, so the first run creates no status comment. When every check passes, the next message is notify_integration_data (gitwaterflow/init.py:198-200), which hits this return. Later status messages such as ApprovalRequired have no child_prs, and there is no earlier comment text for _integration_pull_requests to copy from, so the status comment gets created with no integration PR list. IntegrationDataCreated is sent only when a w/ branch or PR is newly created, so later runs never recover the list. The list therefore appears only on PRs that hit a status-bearing error before their integration PRs were created. test_integration_prs_kept_between_updates hides this because it calls update_status_comment(..., _conflict()) first to seed a status comment. Fix: create the comment here with a neutral state instead of returning.

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 a fresh PR with automatic integration branch creation, IntegrationDataCreated is the first message that matters, and it has no status. No status comment exists yet, so this returns and the child PR list is lost. IntegrationDataCreated is sent only when the branches are created, and later messages have no child_prs, so the integration PRs are never shown in the common path. Create the comment here instead of returning, with a neutral state such as comment.title and no result, and add a test that sends IntegrationDataCreated with no existing status comment.

— Claude Code

m = STATUS_STATE_RE.search(existing.text)
state = m.group('state') if m else state
m = STATUS_RESULT_RE.search(existing.text)
status = m.group('status') if m else None
code = None
prs = _integration_pull_requests(
comment, existing.text if existing else None)
text = render('pr_status_comment.md', marker=STATUS_COMMENT_MARKER,
state=state, code=code, status=status,
integration_prs=prs,
active_options=comment.kwargs.get('active_options'))
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.

On PRs that already have bot comments, the first run after deploy posts the status comment at the bottom instead of near the top. It then becomes the last bot comment, so for messages with dont_repeat_if_in_history=-1 (the default), find_comment(..., max_history=-1) sees a non-matching comment first, returns None, and the previous message gets posted again. Create the status comment only when the PR has no bot comment yet, or make find_comment skip comments that start with STATUS_COMMENT_MARKER.

— Claude Code

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 comment is created the first time a message has a status, not before the first Bert-E message. On new PRs it lands after the greeting (InitMessage has no status). On PRs that already exist when this is deployed, it lands at the bottom of the thread and stays there, so it is not "pinned" early. Either create it from send_greetings before the InitMessage, or change the PR description and docstring to match what the code does.

— Claude Code

pull_request.add_comment(text)
Comment thread
upsun-dispatch[bot] marked this conversation as resolved.
elif existing.text.strip() != text.strip():
existing.edit(text)


def notify_user(settings, pull_request: AbstractPullRequest,
comment: exceptions.TemplateException):
"""Notify user by sending a comment or a build status in a pull request."""
try:
try:

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 bot notification now adds an extra comment at position 0, but the existing integration tests in test_bert_e.py were not updated. They count comments (assertIs(len(list(pr.get_comments())), 1) at L1354, plus L1390/1400/1551/1590-1613/3536-3604), and test_init_message reads pr.comments[0] expecting the greeting. These should fail in the TestBertE jobs. Update those assertions, and add an integration test that runs through the mock host instead of only FakePR.

— Claude Code

update_status_comment(settings, pull_request, comment)
Comment thread
upsun-dispatch[bot] marked this conversation as resolved.
Comment thread
upsun-dispatch[bot] marked this conversation as resolved.
except (requests.HTTPError, git_host_base.Error):
LOG.warning("Could not update the status comment", exc_info=True)

Check warning on line 191 in bert_e/workflow/pr_utils.py

View check run for this annotation

Codecov / codecov/patch

bert_e/workflow/pr_utils.py#L190-L191

Added lines #L190 - L191 were not covered by tests
_send_bot_status(settings, pull_request, comment)
_send_comment(settings, pull_request, str(comment),
comment.dont_repeat_if_in_history)
Expand Down
Loading