Skip to content

Commit 8f6eb31

Browse files
authored
Merge branch 'atlassian-api:master' into master
2 parents 4502975 + 6a65477 commit 8f6eb31

5 files changed

Lines changed: 75 additions & 0 deletions

File tree

‎atlassian/bitbucket/__init__.py‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -838,6 +838,16 @@ def get_project_audit_log(self, project_key, start=0, limit=None):
838838
return self._get_paged(url, params=params)
839839

840840
def _url_repos(self, project_key, api_root=None, api_version=None):
841+
"""Return the repository collection URL for a project or personal owner.
842+
843+
Bitbucket Server/Data Center addresses personal repositories through a
844+
user-centric route. Pass the owner's user slug with a leading ``~``
845+
(for example, ``~alice``) wherever a ``project_key`` is accepted by a
846+
repository method. Project repositories continue to use the existing
847+
``projects/{projectKey}/repos`` route.
848+
"""
849+
if not self.cloud and str(project_key).startswith("~"):
850+
return self.resource_url(f"users/{project_key}/repos", api_root, api_version)
841851
return f"{self._url_project(project_key, api_root, api_version)}/repos"
842852

843853
def repo_list(self, project_key, start=0, limit=25):

‎atlassian/bitbucket/server/__init__.py‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from .base import BitbucketServerBase
44
from .globalPermissions import Groups, Users
55
from .projects import Projects
6+
from .projects.repos import Repositories
67

78

89
class Server(BitbucketServerBase):
@@ -44,3 +45,13 @@ def projects(self):
4445
Reference: https://docs.atlassian.com/bitbucket-server/rest/7.8.0/bitbucket-rest.html#idp147
4546
"""
4647
return self.__projects
48+
49+
def personal_repositories(self, username):
50+
"""Return repositories owned by a Bitbucket Server/Data Center user.
51+
52+
``username`` may be supplied with or without the leading ``~``. The
53+
returned collection has the same API as ``project.repos`` and uses
54+
Bitbucket's user-centric ``/users/{userSlug}/repos`` endpoint.
55+
"""
56+
user_slug = username if username.startswith("~") else f"~{username}"
57+
return Repositories(self._sub_url(f"users/{user_slug}/repos"), **self._new_session_args)

‎docs/bitbucket.rst‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,32 @@ already a Python dictionary.
4040
objects from individual requests. Do not enable it for the high-level paginated
4141
methods above; use their yielded dictionaries instead.
4242

43+
Personal repositories (Server/Data Center)
44+
------------------------------------------
45+
46+
Repository methods accept a personal-project user slug in place of a project
47+
key. Prefix the Bitbucket username with ``~`` and the legacy client uses the
48+
user-centric ``/users/{userSlug}/repos/{repositorySlug}`` endpoint. This works
49+
for pull-request settings and every other repository method that accepts
50+
``project_key`` and ``repository_slug``.
51+
52+
.. code-block:: python
53+
54+
owner = "~alice"
55+
settings = bitbucket.get_pull_request_settings(owner, "personal-repository")
56+
bitbucket.set_pull_request_settings(owner, "personal-repository", settings)
57+
58+
For the object-oriented Server/Data Center client, use
59+
``personal_repositories()``. It accepts either ``"alice"`` or ``"~alice"``.
60+
61+
.. code-block:: python
62+
63+
from atlassian.bitbucket.server import Server
64+
65+
bitbucket = Server("https://bitbucket.example.com", username="admin", password="token")
66+
repository = bitbucket.personal_repositories("alice").get("personal-repository")
67+
print(repository.name)
68+
4369
Hook scripts (Data Center 8+)
4470
-----------------------------
4571

‎tests/test_bitbucket_server.py‎

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,25 @@ def test_configure_repo_hook_script(self, mock_put):
133133
mock_put.assert_called_once_with(
134134
"rest/api/latest/projects/PROJ/repos/repository/hook-scripts/12", data={"triggerIds": []}
135135
)
136+
137+
138+
class TestPersonalRepositories(TestCase):
139+
def setUp(self):
140+
self.bitbucket = Bitbucket("https://bitbucket.example.com", username="admin", password="password")
141+
142+
def test_personal_repository_urls_use_the_user_centric_route(self):
143+
self.assertEqual(
144+
self.bitbucket._url_repo("~alice", "example"),
145+
"rest/api/1.0/users/~alice/repos/example",
146+
)
147+
self.assertEqual(self.bitbucket._url_repos("~alice"), "rest/api/1.0/users/~alice/repos")
148+
149+
@patch.object(Bitbucket, "post")
150+
def test_pull_request_settings_support_personal_repositories(self, mock_post):
151+
settings = {"requiredApprovals": 2}
152+
153+
self.bitbucket.set_pull_request_settings("~alice", "example", settings)
154+
155+
mock_post.assert_called_once_with(
156+
"rest/api/1.0/users/~alice/repos/example/settings/pull-requests", data=settings
157+
)

‎tests/test_bitbucket_server_oo.py‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@
1818

1919
@pytest.mark.skipif(sys.version_info < (3, 4), reason="requires python3.4")
2020
class TestBasic:
21+
def test_personal_repositories_accepts_a_username_or_user_slug(self):
22+
expected_url = f"{BITBUCKET.url}/users/~alice/repos"
23+
24+
assert BITBUCKET.personal_repositories("alice").url == expected_url
25+
assert BITBUCKET.personal_repositories("~alice").url == expected_url
26+
2127
def test_global_permissions(self):
2228
result = list(BITBUCKET.groups.each())
2329
assert [x.name for x in result] == ["group_a", "group_b", "group_c", "group_d"], "Each global group"

0 commit comments

Comments
 (0)