Skip to content

Commit c220db8

Browse files
committed
Add: Add async GitHub API to create teams
1 parent eb43910 commit c220db8

File tree

2 files changed

+123
-2
lines changed

2 files changed

+123
-2
lines changed

pontos/github/api/teams.py

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,18 @@
1515
# You should have received a copy of the GNU General Public License
1616
# along with this program. If not, see <http://www.gnu.org/licenses/>.
1717

18-
from typing import Iterable
18+
from enum import Enum
19+
from typing import Iterable, Optional
1920

2021
from pontos.github.api.client import GitHubAsyncREST
2122
from pontos.github.api.helper import JSON_OBJECT
2223

2324

25+
class TeamPrivacy(Enum):
26+
SECRET = "secret"
27+
CLOSED = "closed"
28+
29+
2430
class GitHubAsyncRESTTeams(GitHubAsyncREST):
2531
async def get_all(self, organization: str) -> Iterable[JSON_OBJECT]:
2632
"""
@@ -46,3 +52,60 @@ async def get_all(self, organization: str) -> Iterable[JSON_OBJECT]:
4652
teams.extend(response.json())
4753

4854
return teams
55+
56+
async def create(
57+
self,
58+
organization: str,
59+
name: str,
60+
*,
61+
description: Optional[str] = None,
62+
maintainers: Optional[Iterable[str]] = None,
63+
repo_names: Optional[Iterable[str]] = None,
64+
privacy: Optional[TeamPrivacy] = None,
65+
parent_team_id: Optional[str] = None,
66+
) -> JSON_OBJECT:
67+
"""
68+
Create a new team in an organization
69+
70+
https://docs.github.com/en/rest/teams/teams#create-a-team
71+
72+
Args:
73+
organization: GitHub organization to use
74+
name: The name of the new team.
75+
description: The description of the team.
76+
maintainers: List GitHub IDs for organization members who will
77+
become team maintainers.
78+
repo_names: The full name (e.g., "organization-name/repository-name"
79+
) of repositories to add the team to.
80+
privacy: The level of privacy this team should have. The options
81+
are:
82+
For a non-nested team:
83+
* secret - only visible to organization owners and members
84+
of this team.
85+
* closed - visible to all members of this organization.
86+
Default: secret
87+
88+
For a parent or child team:
89+
* closed - visible to all members of this organization.
90+
Default for child team: closed
91+
parent_team_id: The ID of a team to set as the parent team.
92+
93+
Raises:
94+
`httpx.HTTPStatusError` if there was an error in the request
95+
"""
96+
api = f"/orgs/{organization}/teams"
97+
data = {"name": name}
98+
if description:
99+
data["description"] = description
100+
if maintainers:
101+
data["maintainers"] = list(maintainers)
102+
if repo_names:
103+
data["repo_names"] = list(repo_names)
104+
if privacy:
105+
data["privacy"] = privacy.value
106+
if parent_team_id:
107+
data["parent_team_id"] = parent_team_id
108+
109+
response = await self._client.post(api, data=data)
110+
response.raise_for_status()
111+
return response.json()

tests/github/api/test_teams.py

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,11 @@
1414
#
1515
# You should have received a copy of the GNU General Public License
1616
# along with this program. If not, see <http://www.gnu.org/licenses/>.
17+
from unittest.mock import MagicMock
1718

18-
from pontos.github.api.teams import GitHubAsyncRESTTeams
19+
import httpx
20+
21+
from pontos.github.api.teams import GitHubAsyncRESTTeams, TeamPrivacy
1922
from tests import AsyncIteratorMock
2023
from tests.github.api import GitHubAsyncRESTTestCase, create_response
2124

@@ -42,3 +45,58 @@ async def test_get_all(self):
4245
"/orgs/foo/teams",
4346
params={"per_page": "100"},
4447
)
48+
49+
async def test_create(self):
50+
response = create_response()
51+
self.client.post.return_value = response
52+
53+
await self.api.create(
54+
"foo",
55+
"bar",
56+
description="A description",
57+
maintainers=["foo", "bar"],
58+
repo_names=["foo/bar", "foo/baz"],
59+
privacy=TeamPrivacy.CLOSED,
60+
parent_team_id="123",
61+
)
62+
63+
self.client.post.assert_awaited_once_with(
64+
"/orgs/foo/teams",
65+
data={
66+
"name": "bar",
67+
"description": "A description",
68+
"maintainers": ["foo", "bar"],
69+
"repo_names": ["foo/bar", "foo/baz"],
70+
"privacy": "closed",
71+
"parent_team_id": "123",
72+
},
73+
)
74+
75+
async def test_create_failure(self):
76+
response = create_response()
77+
self.client.post.side_effect = httpx.HTTPStatusError(
78+
"404", request=MagicMock(), response=response
79+
)
80+
81+
with self.assertRaises(httpx.HTTPStatusError):
82+
await self.api.create(
83+
"foo",
84+
"bar",
85+
description="A description",
86+
maintainers=["foo", "bar"],
87+
repo_names=["foo/bar", "foo/baz"],
88+
privacy=TeamPrivacy.CLOSED,
89+
parent_team_id="123",
90+
)
91+
92+
self.client.post.assert_awaited_once_with(
93+
"/orgs/foo/teams",
94+
data={
95+
"name": "bar",
96+
"description": "A description",
97+
"maintainers": ["foo", "bar"],
98+
"repo_names": ["foo/bar", "foo/baz"],
99+
"privacy": "closed",
100+
"parent_team_id": "123",
101+
},
102+
)

0 commit comments

Comments
 (0)