Skip to content

Commit 0dbf33a

Browse files
committed
[Bitbucket] Allow to enable/disable forking of an repo atlassian-api#503
1 parent 480cb56 commit 0dbf33a

3 files changed

Lines changed: 62 additions & 0 deletions

File tree

atlassian/bitbucket/__init__.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,40 @@ def update_repo(self, project_key, repository_slug, **params):
10251025
url = self._url_repo(project_key, repository_slug)
10261026
return self.put(url, data=params)
10271027

1028+
def get_repo_forkable(self, project_key, repository_slug):
1029+
"""Return whether a Bitbucket Server/Data Center repository is forkable.
1030+
1031+
:param project_key: Project key, or a ``~user`` personal repository owner.
1032+
:param repository_slug: URL-compatible repository identifier.
1033+
:return: The repository's ``forkable`` flag, or ``None`` when omitted
1034+
by an older Bitbucket version.
1035+
"""
1036+
return (self.get_repo(project_key, repository_slug) or {}).get("forkable")
1037+
1038+
def set_repo_forkable(self, project_key, repository_slug, forkable):
1039+
"""Enable or disable forking for a Server/Data Center repository.
1040+
1041+
The caller requires repository administration permission. This uses the
1042+
repository ``PUT`` endpoint and preserves the behavior of
1043+
:meth:`update_repo` for all other repository fields.
1044+
1045+
:param project_key: Project key, or a ``~user`` personal repository owner.
1046+
:param repository_slug: URL-compatible repository identifier.
1047+
:param forkable: ``True`` to allow forks or ``False`` to prohibit them.
1048+
:return: Updated repository representation.
1049+
"""
1050+
if not isinstance(forkable, bool):
1051+
raise TypeError("forkable must be a boolean")
1052+
return self.update_repo(project_key, repository_slug, forkable=forkable)
1053+
1054+
def enable_repo_forking(self, project_key, repository_slug):
1055+
"""Enable forking for a Server/Data Center repository."""
1056+
return self.set_repo_forkable(project_key, repository_slug, True)
1057+
1058+
def disable_repo_forking(self, project_key, repository_slug):
1059+
"""Disable forking for a Server/Data Center repository."""
1060+
return self.set_repo_forkable(project_key, repository_slug, False)
1061+
10281062
def delete_repo(self, project_key, repository_slug):
10291063
"""
10301064
Delete a specific repository from a project. This operates based on slug not name which may

docs/bitbucket.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,13 @@ Manage code
324324
# The authenticated user must have PROJECT_ADMIN permission for the context project to call this resource.
325325
bitbucket.create_repo(project_key, repository, forkable=False, is_private=True)
326326
327+
# Bitbucket Server/Data Center: inspect or change whether a repository
328+
# accepts forks. These calls require repository administration permission.
329+
is_forkable = bitbucket.get_repo_forkable(project_key, repository)
330+
bitbucket.set_repo_forkable(project_key, repository, forkable=True)
331+
bitbucket.enable_repo_forking(project_key, repository)
332+
bitbucket.disable_repo_forking(project_key, repository)
333+
327334
# Get branches from repo
328335
bitbucket.get_branches(project, repository, filter='', limit=99999, details=True, boost_matches=False)
329336

tests/test_bitbucket_server.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,27 @@ def test_create_hook_script_rejects_unknown_hook_type(self):
118118
with self.assertRaisesRegex(ValueError, "PRE.*POST"):
119119
self.bitbucket.create_hook_script(b"#!/bin/sh", "Invalid", "PRE_RECEIVE")
120120

121+
122+
class TestRepositoryForking(TestCase):
123+
def setUp(self):
124+
self.bitbucket = Bitbucket("https://bitbucket.example.com", username="admin", password="password")
125+
126+
@patch.object(Bitbucket, "get_repo", return_value={"forkable": True})
127+
def test_get_repo_forkable(self, mock_get_repo):
128+
assert self.bitbucket.get_repo_forkable("PRJ", "repo") is True
129+
mock_get_repo.assert_called_once_with("PRJ", "repo")
130+
131+
@patch.object(Bitbucket, "update_repo", return_value={"forkable": False})
132+
def test_set_repo_forkable_uses_repository_put_wrapper(self, mock_update_repo):
133+
result = self.bitbucket.set_repo_forkable("PRJ", "repo", False)
134+
135+
assert result == {"forkable": False}
136+
mock_update_repo.assert_called_once_with("PRJ", "repo", forkable=False)
137+
138+
def test_set_repo_forkable_requires_boolean(self):
139+
with self.assertRaisesRegex(TypeError, "boolean"):
140+
self.bitbucket.set_repo_forkable("PRJ", "repo", "false")
141+
121142
@patch.object(Bitbucket, "put")
122143
def test_configure_project_hook_script(self, mock_put):
123144
self.bitbucket.configure_project_hook_script("PROJ", 12, ["repo:refs_changed"])

0 commit comments

Comments
 (0)