Skip to content

Commit 8f23f04

Browse files
add manager methods for creating from GH API data (#9)
* add `Installation` manager method for creating from GH API data * add methods to Repo too * update readme and changelog * add tests for repo methods * add success codes so coverage report will print fully * add single repo data test case
1 parent 6b05aa7 commit 8f23f04

File tree

5 files changed

+138
-22
lines changed

5 files changed

+138
-22
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,10 @@ and this project attempts to adhere to [Semantic Versioning](https://semver.org/
1818

1919
## [Unreleased]
2020

21+
### Added
22+
23+
- Added `acreate_from_gh_data`/`create_from_gh_data` manager methods to `Installation` and `Repository` models.
24+
2125
## [0.1.0]
2226

2327
### Added

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,7 @@ async with AsyncGitHubAPI(installation_id=installation.installation_id) as gh:
249249
##### Manager methods
250250
251251
- `acreate_from_event`/`create_from_event`: Create from installation events _(primarily for internal use)_
252+
- `acreate_from_gh_data`/`create_from_gh_data`: Create from GitHub API response data _(primarily for internal use)_
252253
- `aget_from_event`/`get_from_event`: Retrieve installation from webhook events (`gidgethub.sansio.Event`)
253254
254255
##### Model methods
@@ -269,6 +270,7 @@ issues = await repo.aget_issues(params={"state": "open"})
269270
270271
##### Manager methods
271272
273+
- `acreate_from_gh_data`/`create_from_gh_data`: Create from GitHub API response data _(primarily for internal use)_
272274
- `aget_from_event`/`get_from_event`: Retrieve repository from webhook events (`gidgethub.sansio.Event`)
273275
274276
##### Model methods

noxfile.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,8 +108,12 @@ def coverage(session):
108108
try:
109109
session.run("python", "-m", "pytest", "--cov", "--cov-report=")
110110
finally:
111+
# 0 -> OK
112+
# 2 -> code coverage percent unmet
113+
success_codes = [0, 2]
114+
111115
report_cmd = ["python", "-m", "coverage", "report"]
112-
session.run(*report_cmd)
116+
session.run(*report_cmd, success_codes=success_codes)
113117

114118
if summary := os.getenv("GITHUB_STEP_SUMMARY"):
115119
report_cmd.extend(["--skip-covered", "--skip-empty", "--format=markdown"])
@@ -118,10 +122,18 @@ def coverage(session):
118122
output_buffer.write("")
119123
output_buffer.write("### Coverage\n\n")
120124
output_buffer.flush()
121-
session.run(*report_cmd, stdout=output_buffer)
125+
session.run(
126+
*report_cmd, stdout=output_buffer, success_codes=success_codes
127+
)
122128
else:
123129
session.run(
124-
"python", "-m", "coverage", "html", "--skip-covered", "--skip-empty"
130+
"python",
131+
"-m",
132+
"coverage",
133+
"html",
134+
"--skip-covered",
135+
"--skip-empty",
136+
success_codes=success_codes,
125137
)
126138

127139

src/django_github_app/models.py

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -64,34 +64,26 @@ def action(self) -> str | None:
6464

6565
class InstallationManager(models.Manager["Installation"]):
6666
async def acreate_from_event(self, event: sansio.Event):
67-
installation_data = event.data["installation"]
68-
69-
app_id = installation_data["app_id"]
67+
app_id = event.data["installation"]["app_id"]
7068

7169
if str(app_id) == app_settings.APP_ID:
72-
installation = await self.acreate(
73-
installation_id=installation_data["id"],
74-
data=installation_data,
75-
)
70+
installation = await self.acreate_from_gh_data(event.data["installation"])
7671

77-
repository_data = event.data["repositories"]
78-
79-
repositories = [
80-
Repository(
81-
installation=installation,
82-
repository_id=repository["id"],
83-
repository_node_id=repository["node_id"],
84-
full_name=repository["full_name"],
85-
)
86-
for repository in repository_data
87-
]
88-
await Repository.objects.abulk_create(repositories)
72+
await Repository.objects.acreate_from_gh_data(
73+
event.data["repositories"], installation
74+
)
8975

9076
return installation
9177

9278
def create_from_event(self, event: sansio.Event):
9379
return async_to_sync(self.acreate_from_event)(event)
9480

81+
async def acreate_from_gh_data(self, data: dict[str, str]):
82+
return await self.acreate(installation_id=data["id"], data=data)
83+
84+
def create_from_gh_data(self, data: dict[str, str]):
85+
return async_to_sync(self.acreate_from_gh_data)(data)
86+
9587
async def aget_from_event(self, event: sansio.Event):
9688
try:
9789
installation_id = event.data["installation"]["id"]
@@ -147,6 +139,33 @@ def get_access_token(self, gh: abc.GitHubAPI): # pragma: no cover
147139

148140

149141
class RepositoryManager(models.Manager["Repository"]):
142+
async def acreate_from_gh_data(
143+
self, data: dict[str, str] | list[dict[str, str]], installation: Installation
144+
):
145+
if isinstance(data, list):
146+
repositories = [
147+
Repository(
148+
installation=installation,
149+
repository_id=repository["id"],
150+
repository_node_id=repository["node_id"],
151+
full_name=repository["full_name"],
152+
)
153+
for repository in data
154+
]
155+
return await Repository.objects.abulk_create(repositories)
156+
else:
157+
return await self.acreate(
158+
installation=installation,
159+
repository_id=data["id"],
160+
repository_node_id=data["node_id"],
161+
full_name=data["full_name"],
162+
)
163+
164+
def create_from_gh_data(
165+
self, data: dict[str, str] | list[dict[str, str]], installation: Installation
166+
):
167+
return async_to_sync(self.acreate_from_gh_data)(data, installation)
168+
150169
async def aget_from_event(self, event: sansio.Event):
151170
try:
152171
repository_id = event.data["repository"]["id"]

tests/test_models.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,31 @@ def test_create_from_event(self, create_event, override_app_settings):
160160
repositories
161161
)
162162

163+
@pytest.mark.asyncio
164+
async def test_acreate_from_gh_data(self):
165+
installation_data = {
166+
"id": seq.next(),
167+
"app_id": seq.next(),
168+
}
169+
170+
installation = await Installation.objects.acreate_from_gh_data(
171+
installation_data
172+
)
173+
174+
assert installation.installation_id == installation_data["id"]
175+
assert installation.data == installation_data
176+
177+
def test_create_from_gh_data(self):
178+
installation_data = {
179+
"id": seq.next(),
180+
"app_id": seq.next(),
181+
}
182+
183+
installation = Installation.objects.create_from_gh_data(installation_data)
184+
185+
assert installation.installation_id == installation_data["id"]
186+
assert installation.data == installation_data
187+
163188
@pytest.mark.asyncio
164189
async def test_aget_from_event(self, ainstallation, create_event):
165190
installation = await ainstallation
@@ -213,6 +238,60 @@ def test_from_event_invalid_action(self, create_event):
213238

214239

215240
class TestRepositoryManager:
241+
@pytest.mark.asyncio
242+
async def test_acreate_from_gh_data_list(self, ainstallation):
243+
installation = await ainstallation
244+
data = [
245+
{"id": seq.next(), "node_id": "node1", "full_name": "owner/repo1"},
246+
{"id": seq.next(), "node_id": "node2", "full_name": "owner/repo2"},
247+
]
248+
249+
repositories = await Repository.objects.acreate_from_gh_data(data, installation)
250+
251+
assert len(repositories) == len(data)
252+
for i, repo in enumerate(repositories):
253+
assert repo.repository_id == data[i]["id"]
254+
assert repo.repository_node_id == data[i]["node_id"]
255+
assert repo.full_name == data[i]["full_name"]
256+
assert repo.installation_id == installation.id
257+
258+
def test_create_from_gh_data_list(self, installation):
259+
data = [
260+
{"id": seq.next(), "node_id": "node1", "full_name": "owner/repo1"},
261+
{"id": seq.next(), "node_id": "node2", "full_name": "owner/repo2"},
262+
]
263+
264+
repositories = Repository.objects.create_from_gh_data(data, installation)
265+
266+
assert len(repositories) == len(data)
267+
for i, repo in enumerate(repositories):
268+
assert repo.repository_id == data[i]["id"]
269+
assert repo.repository_node_id == data[i]["node_id"]
270+
assert repo.full_name == data[i]["full_name"]
271+
assert repo.installation_id == installation.id
272+
273+
@pytest.mark.asyncio
274+
async def test_acreate_from_gh_data_single(self, ainstallation):
275+
installation = await ainstallation
276+
data = {"id": seq.next(), "node_id": "node1", "full_name": "owner/repo1"}
277+
278+
repository = await Repository.objects.acreate_from_gh_data(data, installation)
279+
280+
assert repository.repository_id == data["id"]
281+
assert repository.repository_node_id == data["node_id"]
282+
assert repository.full_name == data["full_name"]
283+
assert repository.installation_id == installation.id
284+
285+
def test_create_from_gh_data_single(self, installation):
286+
data = {"id": seq.next(), "node_id": "node1", "full_name": "owner/repo1"}
287+
288+
repository = Repository.objects.create_from_gh_data(data, installation)
289+
290+
assert repository.repository_id == data["id"]
291+
assert repository.repository_node_id == data["node_id"]
292+
assert repository.full_name == data["full_name"]
293+
assert repository.installation_id == installation.id
294+
216295
@pytest.mark.asyncio
217296
async def test_aget_from_event(self, arepository, create_event):
218297
repository = await arepository

0 commit comments

Comments
 (0)