From ea589f2ca5363894a59ed79866e7d1c2d3236181 Mon Sep 17 00:00:00 2001 From: xakepnz Date: Mon, 23 Sep 2024 22:07:35 +1200 Subject: [PATCH 01/11] feat: introduce related_issues to merge requests --- docs/gl_objects/merge_requests.rst | 4 ++++ gitlab/v4/objects/merge_requests.py | 29 +++++++++++++++++++++++ tests/unit/objects/test_merge_requests.py | 8 +++++++ 3 files changed, 41 insertions(+) diff --git a/docs/gl_objects/merge_requests.rst b/docs/gl_objects/merge_requests.rst index 95364073d..8264669e6 100644 --- a/docs/gl_objects/merge_requests.rst +++ b/docs/gl_objects/merge_requests.rst @@ -144,6 +144,10 @@ List the changes of a MR:: changes = mr.changes() +List issues related to this merge request:: + + related_issues = mr.related_issues() + List issues that will close on merge:: mr.closes_issues() diff --git a/gitlab/v4/objects/merge_requests.py b/gitlab/v4/objects/merge_requests.py index fb25ab5ae..e29ab2b28 100644 --- a/gitlab/v4/objects/merge_requests.py +++ b/gitlab/v4/objects/merge_requests.py @@ -197,6 +197,35 @@ def cancel_merge_when_pipeline_succeeds(self, **kwargs: Any) -> Dict[str, str]: assert isinstance(server_data, dict) return server_data + @cli.register_custom_action(cls_names="ProjectMergeRequest") + @exc.on_http_error(exc.GitlabListError) + def related_issues(self, **kwargs: Any) -> RESTObjectList: + """List issues related to this merge request." + + Args: + all: If True, return all the items, without pagination + per_page: Number of items to retrieve per request + page: ID of the page to return (starts with page 1) + **kwargs: Extra options to send to the server (e.g. sudo) + + Raises: + GitlabAuthenticationError: If authentication is not correct + GitlabListError: If the list could not be retrieved + + Returns: + List of issues + """ + + path = f"{self.manager.path}/{self.encoded_id}/related_issues" + data_list = self.manager.gitlab.http_list(path, iterator=True, **kwargs) + + if TYPE_CHECKING: + assert isinstance(data_list, gitlab.GitlabList) + + manager = ProjectIssueManager(self.manager.gitlab, parent=self.manager._parent) + + return RESTObjectList(manager, ProjectIssue, data_list) + @cli.register_custom_action(cls_names="ProjectMergeRequest") @exc.on_http_error(exc.GitlabListError) def closes_issues(self, **kwargs: Any) -> RESTObjectList: diff --git a/tests/unit/objects/test_merge_requests.py b/tests/unit/objects/test_merge_requests.py index 6f8a6a7de..62538931a 100644 --- a/tests/unit/objects/test_merge_requests.py +++ b/tests/unit/objects/test_merge_requests.py @@ -40,6 +40,9 @@ "web_url": "http://gitlab.example.com//kenyatta_oconnell", } ], + "related_issues": [ + 1, 2 + ] } reviewers_content = [ @@ -93,6 +96,11 @@ def resp_get_merge_request_reviewers(): yield rsps +def test_list_related_issues(project, resp_list_merge_requests): + mrs = project.mergerequests.list() + assert isinstance(mrs[0], ProjectMergeRequest) + assert mrs[0].related_issues == mr_content["related_issues"] + def test_list_project_merge_requests(project, resp_list_merge_requests): mrs = project.mergerequests.list() assert isinstance(mrs[0], ProjectMergeRequest) From 73c13d22e6e04b10364d1c26ad3e63b47da08b8f Mon Sep 17 00:00:00 2001 From: xakepnz Date: Mon, 23 Sep 2024 22:24:25 +1200 Subject: [PATCH 02/11] chore: fix black lint errors Ensure black lint check passes following PEP-8 --- tests/unit/objects/test_merge_requests.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/unit/objects/test_merge_requests.py b/tests/unit/objects/test_merge_requests.py index 62538931a..b3eed90fd 100644 --- a/tests/unit/objects/test_merge_requests.py +++ b/tests/unit/objects/test_merge_requests.py @@ -40,9 +40,7 @@ "web_url": "http://gitlab.example.com//kenyatta_oconnell", } ], - "related_issues": [ - 1, 2 - ] + "related_issues": [1, 2], } reviewers_content = [ @@ -101,6 +99,7 @@ def test_list_related_issues(project, resp_list_merge_requests): assert isinstance(mrs[0], ProjectMergeRequest) assert mrs[0].related_issues == mr_content["related_issues"] + def test_list_project_merge_requests(project, resp_list_merge_requests): mrs = project.mergerequests.list() assert isinstance(mrs[0], ProjectMergeRequest) From 0b74c5956bcae89badce33016b1193fb0608f070 Mon Sep 17 00:00:00 2001 From: xakepnz Date: Mon, 23 Sep 2024 22:51:39 +1200 Subject: [PATCH 03/11] chore: revert related_issues test --- tests/unit/objects/test_merge_requests.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/unit/objects/test_merge_requests.py b/tests/unit/objects/test_merge_requests.py index b3eed90fd..6f8a6a7de 100644 --- a/tests/unit/objects/test_merge_requests.py +++ b/tests/unit/objects/test_merge_requests.py @@ -40,7 +40,6 @@ "web_url": "http://gitlab.example.com//kenyatta_oconnell", } ], - "related_issues": [1, 2], } reviewers_content = [ @@ -94,12 +93,6 @@ def resp_get_merge_request_reviewers(): yield rsps -def test_list_related_issues(project, resp_list_merge_requests): - mrs = project.mergerequests.list() - assert isinstance(mrs[0], ProjectMergeRequest) - assert mrs[0].related_issues == mr_content["related_issues"] - - def test_list_project_merge_requests(project, resp_list_merge_requests): mrs = project.mergerequests.list() assert isinstance(mrs[0], ProjectMergeRequest) From 9aba4a127eb51eed1f417c26faa99be90abbec8d Mon Sep 17 00:00:00 2001 From: xakepnz Date: Mon, 23 Sep 2024 23:14:50 +1200 Subject: [PATCH 04/11] test: update merge requests with related_issues Add related_issues mock endpoint call and resp test --- tests/unit/objects/test_merge_requests.py | 104 ++++++++++++++++++++++ 1 file changed, 104 insertions(+) diff --git a/tests/unit/objects/test_merge_requests.py b/tests/unit/objects/test_merge_requests.py index 6f8a6a7de..57b5b0597 100644 --- a/tests/unit/objects/test_merge_requests.py +++ b/tests/unit/objects/test_merge_requests.py @@ -13,6 +13,7 @@ ProjectDeploymentMergeRequest, ProjectMergeRequest, ProjectMergeRequestReviewerDetail, + ProjectIssue, ) mr_content = { @@ -57,6 +58,78 @@ } ] +related_issues = [ + { + "id": 1, + "iid": 1, + "project_id": 1, + "title": "Fake Title for Merge Requests via API", + "description": "Something here", + "state": "closed", + "created_at": "2024-05-14T04:01:40.042Z", + "updated_at": "2024-06-13T05:29:13.661Z", + "closed_at": "2024-06-13T05:29:13.602Z", + "closed_by": { + "id": 2, + "name": "Sam Bauch", + "username": "kenyatta_oconnell", + "state": "active", + "avatar_url": "https://www.gravatar.com/avatar/956c92487c6f6f7616b536927e22c9a0?s=80&d=identicon", + "web_url": "http://gitlab.example.com//kenyatta_oconnell", + }, + "labels": [ + "FakeCategory", + "fake:ml", + ], + "assignees": [ + { + "id": 2, + "name": "Sam Bauch", + "username": "kenyatta_oconnell", + "state": "active", + "avatar_url": "https://www.gravatar.com/avatar/956c92487c6f6f7616b536927e22c9a0?s=80&d=identicon", + "web_url": "http://gitlab.example.com//kenyatta_oconnell", + } + ], + "author": { + "id": 2, + "name": "Sam Bauch", + "username": "kenyatta_oconnell", + "state": "active", + "avatar_url": "https://www.gravatar.com/avatar/956c92487c6f6f7616b536927e22c9a0?s=80&d=identicon", + "web_url": "http://gitlab.example.com//kenyatta_oconnell", + }, + "type": "ISSUE", + "assignee": { + "id": 4459593, + "username": "fakeuser", + "name": "Fake User", + "state": "active", + "locked": False, + "avatar_url": "https://example.com/uploads/-/system/user/avatar/4459593/avatar.png", + "web_url": "https://example.com/fakeuser", + }, + "user_notes_count": 9, + "merge_requests_count": 0, + "upvotes": 1, + "downvotes": 0, + "due_date": None, + "confidential": False, + "discussion_locked": None, + "issue_type": "issue", + "web_url": "https://example.com/fakeorg/fakeproject/-/issues/461536", + "time_stats": { + "time_estimate": 0, + "total_time_spent": 0, + "human_time_estimate": None, + "human_total_time_spent": None, + }, + "task_completion_status": {"count": 0, "completed_count": 0}, + "weight": None, + "blocking_issues_count": 0, + } +] + @pytest.fixture def resp_list_merge_requests(): @@ -93,6 +166,28 @@ def resp_get_merge_request_reviewers(): yield rsps +@pytest.fixture +def resp_list_merge_requests_related_issues(): + with responses.RequestsMock() as rsps: + rsps.add( + method=responses.GET, + url=re.compile( + r"http://localhost/api/v4/projects/1/(deployments/1/)?merge_requests" + ), + json=[mr_content], + content_type="application/json", + status=200, + ) + rsps.add( + method=responses.GET, + url="http://localhost/api/v4/projects/1/merge_requests/1/related_issues", + json=related_issues, + content_type="application/json", + status=200, + ) + yield rsps + + def test_list_project_merge_requests(project, resp_list_merge_requests): mrs = project.mergerequests.list() assert isinstance(mrs[0], ProjectMergeRequest) @@ -115,3 +210,12 @@ def test_get_merge_request_reviewers(project, resp_get_merge_request_reviewers): assert mr.reviewers[0]["name"] == reviewers_details[0].user["name"] assert reviewers_details[0].state == "unreviewed" assert reviewers_details[0].created_at == "2022-07-27T17:03:27.684Z" + + +def test_list_related_issues(project, resp_list_merge_requests_related_issues): + mr = project.mergerequests.get(1) + this_mr_related_issue = mr.related_issues.list() + assert isinstance(mr, ProjectMergeRequest) + assert isinstance(this_mr_related_issue, list) + assert isinstance(this_mr_related_issue[0], ProjectIssue) + assert this_mr_related_issue[0]["title"] == related_issues[0]["title"] From 7f4a0556c8040ce14a45b88399fd1be44e378e06 Mon Sep 17 00:00:00 2001 From: xakepnz Date: Mon, 23 Sep 2024 23:24:21 +1200 Subject: [PATCH 05/11] chore: update related_issues test attrs & request Update title attr and ensure GET request is mocked --- tests/unit/objects/test_merge_requests.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/unit/objects/test_merge_requests.py b/tests/unit/objects/test_merge_requests.py index 57b5b0597..dd7e389c2 100644 --- a/tests/unit/objects/test_merge_requests.py +++ b/tests/unit/objects/test_merge_requests.py @@ -171,9 +171,7 @@ def resp_list_merge_requests_related_issues(): with responses.RequestsMock() as rsps: rsps.add( method=responses.GET, - url=re.compile( - r"http://localhost/api/v4/projects/1/(deployments/1/)?merge_requests" - ), + url="http://localhost/api/v4/projects/1/merge_requests/1", json=[mr_content], content_type="application/json", status=200, @@ -214,8 +212,8 @@ def test_get_merge_request_reviewers(project, resp_get_merge_request_reviewers): def test_list_related_issues(project, resp_list_merge_requests_related_issues): mr = project.mergerequests.get(1) - this_mr_related_issue = mr.related_issues.list() + this_mrs_related_issues = mr.related_issues.list() assert isinstance(mr, ProjectMergeRequest) - assert isinstance(this_mr_related_issue, list) - assert isinstance(this_mr_related_issue[0], ProjectIssue) - assert this_mr_related_issue[0]["title"] == related_issues[0]["title"] + assert isinstance(this_mrs_related_issues, list) + assert isinstance(this_mrs_related_issues[0], ProjectIssue) + assert this_mr_related_issue[0].title == related_issues[0]["title"] From a2d54ea208fa1ea0d6c79d507d1620d174708222 Mon Sep 17 00:00:00 2001 From: xakepnz Date: Mon, 23 Sep 2024 23:38:08 +1200 Subject: [PATCH 06/11] test: update merge_requests ProjectIssue obj --- tests/unit/objects/test_merge_requests.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/unit/objects/test_merge_requests.py b/tests/unit/objects/test_merge_requests.py index dd7e389c2..addd20103 100644 --- a/tests/unit/objects/test_merge_requests.py +++ b/tests/unit/objects/test_merge_requests.py @@ -75,7 +75,7 @@ "username": "kenyatta_oconnell", "state": "active", "avatar_url": "https://www.gravatar.com/avatar/956c92487c6f6f7616b536927e22c9a0?s=80&d=identicon", - "web_url": "http://gitlab.example.com//kenyatta_oconnell", + "web_url": "http://gitlab.example.com/kenyatta_oconnell", }, "labels": [ "FakeCategory", @@ -88,7 +88,7 @@ "username": "kenyatta_oconnell", "state": "active", "avatar_url": "https://www.gravatar.com/avatar/956c92487c6f6f7616b536927e22c9a0?s=80&d=identicon", - "web_url": "http://gitlab.example.com//kenyatta_oconnell", + "web_url": "http://gitlab.example.com/kenyatta_oconnell", } ], "author": { @@ -211,9 +211,9 @@ def test_get_merge_request_reviewers(project, resp_get_merge_request_reviewers): def test_list_related_issues(project, resp_list_merge_requests_related_issues): - mr = project.mergerequests.get(1) - this_mrs_related_issues = mr.related_issues.list() - assert isinstance(mr, ProjectMergeRequest) - assert isinstance(this_mrs_related_issues, list) - assert isinstance(this_mrs_related_issues[0], ProjectIssue) - assert this_mr_related_issue[0].title == related_issues[0]["title"] + mrs = project.mergerequests.list() + this_mr_related_issues = mrs[0].related_issues.list() + assert isinstance(mrs[0], ProjectMergeRequest) + assert isinstance(this_mr_related_issues, list) + assert isinstance(this_mr_related_issues[0], ProjectIssue) + assert this_mr_related_issues[0].title == related_issues[0]["title"] From 6f7804c5b738128843b5e42cfe74cd3111455497 Mon Sep 17 00:00:00 2001 From: xakepnz Date: Mon, 23 Sep 2024 23:46:41 +1200 Subject: [PATCH 07/11] test: update URL request for related_issues Ensure related_issues URL calls match expected mocks --- tests/unit/objects/test_merge_requests.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/unit/objects/test_merge_requests.py b/tests/unit/objects/test_merge_requests.py index addd20103..56e968629 100644 --- a/tests/unit/objects/test_merge_requests.py +++ b/tests/unit/objects/test_merge_requests.py @@ -172,13 +172,13 @@ def resp_list_merge_requests_related_issues(): rsps.add( method=responses.GET, url="http://localhost/api/v4/projects/1/merge_requests/1", - json=[mr_content], + json=mr_content, content_type="application/json", status=200, ) rsps.add( method=responses.GET, - url="http://localhost/api/v4/projects/1/merge_requests/1/related_issues", + url="http://localhost/api/v4/projects/3/merge_requests/1/related_issues", json=related_issues, content_type="application/json", status=200, @@ -211,9 +211,9 @@ def test_get_merge_request_reviewers(project, resp_get_merge_request_reviewers): def test_list_related_issues(project, resp_list_merge_requests_related_issues): - mrs = project.mergerequests.list() - this_mr_related_issues = mrs[0].related_issues.list() - assert isinstance(mrs[0], ProjectMergeRequest) + mr = project.mergerequests.get(1) + this_mr_related_issues = mr.related_issues.list() + assert isinstance(mr, ProjectMergeRequest) assert isinstance(this_mr_related_issues, list) assert isinstance(this_mr_related_issues[0], ProjectIssue) assert this_mr_related_issues[0].title == related_issues[0]["title"] From febc0bf3291d02e5f5fb05d15e98b68661bed920 Mon Sep 17 00:00:00 2001 From: xakepnz Date: Mon, 23 Sep 2024 23:52:40 +1200 Subject: [PATCH 08/11] chore: ensure related_issues returns expected list --- tests/unit/objects/test_merge_requests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/objects/test_merge_requests.py b/tests/unit/objects/test_merge_requests.py index 56e968629..b0db2e13a 100644 --- a/tests/unit/objects/test_merge_requests.py +++ b/tests/unit/objects/test_merge_requests.py @@ -212,7 +212,7 @@ def test_get_merge_request_reviewers(project, resp_get_merge_request_reviewers): def test_list_related_issues(project, resp_list_merge_requests_related_issues): mr = project.mergerequests.get(1) - this_mr_related_issues = mr.related_issues.list() + this_mr_related_issues = mr.related_issues() assert isinstance(mr, ProjectMergeRequest) assert isinstance(this_mr_related_issues, list) assert isinstance(this_mr_related_issues[0], ProjectIssue) From cd5a5d10401fbe3808fa06e80487c549c08e648c Mon Sep 17 00:00:00 2001 From: xakepnz Date: Mon, 23 Sep 2024 23:57:42 +1200 Subject: [PATCH 09/11] chore: test mock url matches Ensure related_issues mock request matches the same project & MR mock request --- tests/unit/objects/test_merge_requests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit/objects/test_merge_requests.py b/tests/unit/objects/test_merge_requests.py index b0db2e13a..d0287b89f 100644 --- a/tests/unit/objects/test_merge_requests.py +++ b/tests/unit/objects/test_merge_requests.py @@ -178,7 +178,7 @@ def resp_list_merge_requests_related_issues(): ) rsps.add( method=responses.GET, - url="http://localhost/api/v4/projects/3/merge_requests/1/related_issues", + url="http://localhost/api/v4/projects/1/merge_requests/1/related_issues", json=related_issues, content_type="application/json", status=200, From fd42631800607d62bd98fec4922e3a8a2eda5ca6 Mon Sep 17 00:00:00 2001 From: xakepnz Date: Tue, 24 Sep 2024 00:14:37 +1200 Subject: [PATCH 10/11] chore: add RESTObjectList instance check --- tests/unit/objects/test_merge_requests.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/unit/objects/test_merge_requests.py b/tests/unit/objects/test_merge_requests.py index d0287b89f..93f9e848f 100644 --- a/tests/unit/objects/test_merge_requests.py +++ b/tests/unit/objects/test_merge_requests.py @@ -15,6 +15,7 @@ ProjectMergeRequestReviewerDetail, ProjectIssue, ) +from gitlab.base import RESTObjectList mr_content = { "id": 1, @@ -214,6 +215,6 @@ def test_list_related_issues(project, resp_list_merge_requests_related_issues): mr = project.mergerequests.get(1) this_mr_related_issues = mr.related_issues() assert isinstance(mr, ProjectMergeRequest) - assert isinstance(this_mr_related_issues, list) + assert isinstance(this_mr_related_issues, RESTObjectList) assert isinstance(this_mr_related_issues[0], ProjectIssue) assert this_mr_related_issues[0].title == related_issues[0]["title"] From 412d92d08c88d099f8bb361eb9e62db365674448 Mon Sep 17 00:00:00 2001 From: xakepnz Date: Tue, 24 Sep 2024 00:32:06 +1200 Subject: [PATCH 11/11] chore: ensure related_issues returns expected results RESTObjectList iters an expected ProjectIssue obj --- tests/unit/objects/test_merge_requests.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/unit/objects/test_merge_requests.py b/tests/unit/objects/test_merge_requests.py index 93f9e848f..400b24b34 100644 --- a/tests/unit/objects/test_merge_requests.py +++ b/tests/unit/objects/test_merge_requests.py @@ -9,13 +9,13 @@ import pytest import responses +from gitlab.base import RESTObjectList from gitlab.v4.objects import ( ProjectDeploymentMergeRequest, + ProjectIssue, ProjectMergeRequest, ProjectMergeRequestReviewerDetail, - ProjectIssue, ) -from gitlab.base import RESTObjectList mr_content = { "id": 1, @@ -214,7 +214,8 @@ def test_get_merge_request_reviewers(project, resp_get_merge_request_reviewers): def test_list_related_issues(project, resp_list_merge_requests_related_issues): mr = project.mergerequests.get(1) this_mr_related_issues = mr.related_issues() + the_issue = next(iter(this_mr_related_issues)) assert isinstance(mr, ProjectMergeRequest) assert isinstance(this_mr_related_issues, RESTObjectList) - assert isinstance(this_mr_related_issues[0], ProjectIssue) - assert this_mr_related_issues[0].title == related_issues[0]["title"] + assert isinstance(the_issue, ProjectIssue) + assert the_issue.title == related_issues[0]["title"] pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy