From 01af0ff18a79f098c229d5356e6d896cb3b5baac Mon Sep 17 00:00:00 2001 From: Sjoerd Langkemper Date: Sun, 21 Jan 2024 20:41:04 +0100 Subject: [PATCH 1/3] feat(api): allow updating protected branches Closes #2390 --- docs/gl_objects/protected_branches.rst | 5 +++++ gitlab/v4/objects/branches.py | 13 ++++++++++--- tests/functional/api/test_projects.py | 12 +++++++++++- 3 files changed, 26 insertions(+), 4 deletions(-) diff --git a/docs/gl_objects/protected_branches.rst b/docs/gl_objects/protected_branches.rst index 15e8948d8..8c4da9bc5 100644 --- a/docs/gl_objects/protected_branches.rst +++ b/docs/gl_objects/protected_branches.rst @@ -27,6 +27,11 @@ Get a single protected branch:: p_branch = project.protectedbranches.get('main') +Update a protected branch: + + p_branch.allow_force_push = True + p_branch.save() + Create a protected branch:: p_branch = project.protectedbranches.create({ diff --git a/gitlab/v4/objects/branches.py b/gitlab/v4/objects/branches.py index 9befe79a4..de7a046d3 100644 --- a/gitlab/v4/objects/branches.py +++ b/gitlab/v4/objects/branches.py @@ -1,7 +1,13 @@ from typing import Any, cast, Union from gitlab.base import RESTManager, RESTObject -from gitlab.mixins import NoUpdateMixin, ObjectDeleteMixin +from gitlab.mixins import ( + CRUDMixin, + NoUpdateMixin, + ObjectDeleteMixin, + SaveMixin, + UpdateMethod, +) from gitlab.types import RequiredOptional __all__ = [ @@ -28,11 +34,11 @@ def get( return cast(ProjectBranch, super().get(id=id, lazy=lazy, **kwargs)) -class ProjectProtectedBranch(ObjectDeleteMixin, RESTObject): +class ProjectProtectedBranch(SaveMixin, ObjectDeleteMixin, RESTObject): _id_attr = "name" -class ProjectProtectedBranchManager(NoUpdateMixin, RESTManager): +class ProjectProtectedBranchManager(CRUDMixin, RESTManager): _path = "/projects/{project_id}/protected_branches" _obj_cls = ProjectProtectedBranch _from_parent_attrs = {"project_id": "id"} @@ -49,6 +55,7 @@ class ProjectProtectedBranchManager(NoUpdateMixin, RESTManager): "code_owner_approval_required", ), ) + _update_method = UpdateMethod.PATCH def get( self, id: Union[str, int], lazy: bool = False, **kwargs: Any diff --git a/tests/functional/api/test_projects.py b/tests/functional/api/test_projects.py index ff9109c68..0d85de412 100644 --- a/tests/functional/api/test_projects.py +++ b/tests/functional/api/test_projects.py @@ -259,11 +259,21 @@ def test_project_pages_domains(gl, project): def test_project_protected_branches(project): - p_b = project.protectedbranches.create({"name": "*-stable"}) + p_b = project.protectedbranches.create( + { + "name": "*-stable", + "allow_force_push": False, + } + ) assert p_b.name == "*-stable" + assert not p_b.allow_force_push assert p_b in project.protectedbranches.list() + p_b.allow_force_push = True + p_b.save() + p_b = project.protectedbranches.get("*-stable") + assert p_b.allow_force_push p_b.delete() assert p_b not in project.protectedbranches.list() From 908a75f32b86693b6ccd9c1560d1da1340a6f065 Mon Sep 17 00:00:00 2001 From: Sjoerd Langkemper Date: Tue, 30 Jan 2024 09:56:45 +0100 Subject: [PATCH 2/3] fix(api): wait for save to finish with wait_for_sidekiq --- tests/functional/api/test_projects.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/functional/api/test_projects.py b/tests/functional/api/test_projects.py index 0d85de412..7b3b445fe 100644 --- a/tests/functional/api/test_projects.py +++ b/tests/functional/api/test_projects.py @@ -258,7 +258,7 @@ def test_project_pages_domains(gl, project): assert domain not in project.pagesdomains.list() -def test_project_protected_branches(project): +def test_project_protected_branches(project, wait_for_sidekiq): p_b = project.protectedbranches.create( { "name": "*-stable", @@ -272,6 +272,8 @@ def test_project_protected_branches(project): p_b.allow_force_push = True p_b.save() + wait_for_sidekiq(timeout=60) + p_b = project.protectedbranches.get("*-stable") assert p_b.allow_force_push p_b.delete() From 520f937039083817190a555f63f6de257f7de497 Mon Sep 17 00:00:00 2001 From: Sjoerd Langkemper Date: Tue, 30 Jan 2024 11:15:37 +0100 Subject: [PATCH 3/3] fix(test): only test for updating protected branch from Gitlab 15.6 --- tests/functional/api/test_projects.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/tests/functional/api/test_projects.py b/tests/functional/api/test_projects.py index 7b3b445fe..77bb8348b 100644 --- a/tests/functional/api/test_projects.py +++ b/tests/functional/api/test_projects.py @@ -258,7 +258,13 @@ def test_project_pages_domains(gl, project): assert domain not in project.pagesdomains.list() -def test_project_protected_branches(project, wait_for_sidekiq): +def test_project_protected_branches(project, wait_for_sidekiq, gitlab_version): + # Updating a protected branch is possible from Gitlab 15.6 + # https://docs.gitlab.com/ee/api/protected_branches.html#update-a-protected-branch + can_update_prot_branch = gitlab_version.major > 15 or ( + gitlab_version.major == 15 and gitlab_version.minor >= 6 + ) + p_b = project.protectedbranches.create( { "name": "*-stable", @@ -269,13 +275,14 @@ def test_project_protected_branches(project, wait_for_sidekiq): assert not p_b.allow_force_push assert p_b in project.protectedbranches.list() - p_b.allow_force_push = True - p_b.save() - - wait_for_sidekiq(timeout=60) + if can_update_prot_branch: + p_b.allow_force_push = True + p_b.save() + wait_for_sidekiq(timeout=60) p_b = project.protectedbranches.get("*-stable") - assert p_b.allow_force_push + if can_update_prot_branch: + assert p_b.allow_force_push p_b.delete() assert p_b not in project.protectedbranches.list()