Skip to content

Commit 563c053

Browse files
authored
Check if the blocking thread is already present and skip comment if yes
1 parent 56c73d1 commit 563c053

File tree

2 files changed

+59
-3
lines changed

2 files changed

+59
-3
lines changed

mcp_server/gitlab_tools.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,9 +262,28 @@ async def add_blocking_merge_request_comment(
262262
"""
263263
Adds a blocking (unresolved) comment/discussion to an existing merge request.
264264
This will block the MR from being merged until the discussion is resolved.
265+
Checks if the exact same comment already exists (resolved or unresolved) before adding.
265266
"""
266267
try:
267268
mr = await _get_merge_request_from_url(merge_request_url)
269+
270+
def check_existing_comment():
271+
discussions = mr._raw_pr.discussions.list(get_all=True)
272+
273+
blocking_comment_message = comment.strip()
274+
275+
for discussion in discussions:
276+
notes = discussion.attributes.get("notes", [])
277+
# Check first note in discussion for exact match (regardless of resolved status)
278+
if notes and notes[0].get("body", "").strip() == blocking_comment_message:
279+
return True
280+
281+
return False
282+
283+
exists = await asyncio.to_thread(check_existing_comment)
284+
if exists:
285+
return f"Comment already exists in merge request {merge_request_url}, not adding duplicate"
286+
268287
# Discussions are created unresolved by default, which blocks the MR
269288
await asyncio.to_thread(
270289
mr._raw_pr.discussions.create,

mcp_server/tests/unit/test_gitlab_tools.py

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -241,9 +241,9 @@ async def test_add_blocking_merge_request_comment():
241241
flexmock(
242242
id=123,
243243
_raw_pr=flexmock(
244-
discussions=flexmock().should_receive("create").with_args({"body": comment}).and_return(
245-
flexmock(id=1),
246-
).mock(),
244+
discussions=flexmock()
245+
.should_receive("list").with_args(get_all=True).and_return([]).mock()
246+
.should_receive("create").with_args({"body": comment}).and_return(flexmock(id=1)).mock(),
247247
),
248248
),
249249
).mock()
@@ -257,6 +257,43 @@ async def test_add_blocking_merge_request_comment():
257257
assert result == f"Successfully added blocking comment to merge request {merge_request_url}"
258258

259259

260+
@pytest.mark.parametrize("resolved_status", [False, True])
261+
@pytest.mark.asyncio
262+
async def test_add_blocking_merge_request_comment_already_exists(resolved_status):
263+
merge_request_url = "https://gitlab.com/redhat/rhel/rpms/bash/-/merge_requests/123"
264+
comment = "**Blocking Merge Request**\n\nTest comment"
265+
266+
existing_discussion = flexmock(
267+
id="disc1",
268+
attributes={
269+
"notes": [{"body": "**Blocking Merge Request**\n\nTest comment"}],
270+
"resolved": resolved_status,
271+
}
272+
)
273+
274+
flexmock(GitlabService).should_receive("get_project_from_url").with_args(
275+
url=merge_request_url.rsplit("/-/merge_requests/", 1)[0],
276+
).and_return(
277+
flexmock().should_receive("get_pr").and_return(
278+
flexmock(
279+
id=123,
280+
_raw_pr=flexmock(
281+
discussions=flexmock()
282+
.should_receive("list").with_args(get_all=True).and_return([existing_discussion]).mock()
283+
),
284+
),
285+
).mock()
286+
)
287+
288+
result = await add_blocking_merge_request_comment(
289+
merge_request_url=merge_request_url,
290+
comment=comment
291+
)
292+
293+
assert "already exists" in result
294+
assert merge_request_url in result
295+
296+
260297
@pytest.mark.asyncio
261298
async def test_add_blocking_merge_request_comment_invalid_url():
262299
merge_request_url = "https://github.com/user/repo/pull/123"

0 commit comments

Comments
 (0)