Merge pull request #75 from revsys/64-load-prs

64 Load the PRs data into the db, and get the closed PRs onto the library detail page
This commit is contained in:
Lacey Williams Henschel
2022-12-16 10:55:24 -08:00
committed by GitHub
6 changed files with 187 additions and 12 deletions

View File

@@ -7,7 +7,7 @@ import structlog
from fastcore.xtras import obj2dict
from ghapi.all import GhApi, paged
from .models import Category, Issue, Library
from .models import Category, Issue, Library, PullRequest
from .utils import parse_date
logger = structlog.get_logger()
@@ -381,4 +381,53 @@ class GithubUpdater:
def update_prs(self):
self.logger.info("updating_repo_prs")
# raise ValueError("testing!")
prs_data = repo_prs(self.owner, self.library.name, state="all")
for pr_dict in prs_data:
# Get the date information
closed_at = None
merged_at = None
created_at = None
modified_at = None
if pr_dict.get("closed_at"):
closed_at = parse_date(pr_dict["closed_at"])
if pr_dict.get("merged_at"):
merged_at = parse_date(pr_dict["merged_at"])
if pr_dict.get("created_at"):
created_at = parse_date(pr_dict["created_at"])
if pr_dict.get("updated_at"):
modified_at = parse_date(pr_dict["updated_at"])
try:
pull_request, created = PullRequest.objects.update_or_create(
library=self.library,
github_id=pr_dict["id"],
defaults={
"title": pr_dict["title"][:255],
"number": pr_dict["number"],
"is_open": pr_dict["state"] == "open",
"closed": closed_at,
"merged": merged_at,
"created": created_at,
"modified": modified_at,
"data": obj2dict(pr_dict),
},
)
except Exception as e:
logger.exception(
"update_prs_error_skipped_pr",
pr_github_id=pr_dict.get("id"),
exc_msg=str(e),
)
logger.info(
"pull_request_updated_successfully",
pr_id=pull_request.id,
created_pr=created,
pr_github_id=pull_request.github_id,
)

View File

@@ -101,6 +101,49 @@ def github_api_repo_issues_response(db):
]
@pytest.fixture
def github_api_repo_prs_response(db):
"""Returns the response from GhApi().pulls.list, already paged"""
return [
dict2obj(
{
"title": "Improve logging",
"number": 1,
"state": "closed",
"closed_at": "2022-04-11T12:38:24Z",
"merged_at": "2022-04-11T12:38:24Z",
"created_at": "2022-04-11T11:41:02Z",
"updated_at": "2022-04-11T12:38:25Z",
"id": 5898798798,
}
),
dict2obj(
{
"title": "Fix a test",
"number": 2,
"state": "open",
"closed_at": "2022-04-11T12:38:24Z",
"merged_at": "2022-04-11T12:38:24Z",
"created_at": "2022-04-11T11:41:02Z",
"updated_at": "2022-04-11T12:38:25Z",
"id": 7395968281,
}
),
dict2obj(
{
"title": "Add a new feature",
"number": 3,
"state": "closed",
"closed_at": "2022-04-11T12:38:24Z",
"merged_at": "2022-04-11T12:38:24Z",
"created_at": "2022-04-11T11:41:02Z",
"updated_at": "2022-04-11T12:38:25Z",
"id": 7492027464,
}
),
]
@pytest.fixture
def boost_module():
return {"module": "rational", "url": "rational"}

View File

@@ -7,7 +7,7 @@ from ghapi.all import GhApi
from model_bakery import baker
from libraries.github import GithubUpdater, LibraryUpdater, get_api
from libraries.models import Issue, Library
from libraries.models import Issue, Library, PullRequest
def test_get_api():
@@ -16,9 +16,6 @@ def test_get_api():
# GithubUpdater tests
@pytest.mark.skip(reason="Method not yet written")
def test_update_prs():
pass
def test_update_issues_new(tp, library, github_api_repo_issues_response):
@@ -56,7 +53,7 @@ def test_update_issues_new(tp, library, github_api_repo_issues_response):
def test_update_issues_existing(tp, library, github_api_repo_issues_response):
"""GithubUpdater.update_issues()"""
"""Test that GithubUpdater.update_issues() updates existing issues when appropriate"""
existing_issue_data = github_api_repo_issues_response[0]
old_title = "Old title"
issue = baker.make(
@@ -84,7 +81,7 @@ def test_update_issues_existing(tp, library, github_api_repo_issues_response):
def test_update_issues_long_title(tp, library, github_api_repo_issues_response):
"""GithubUpdater.update_issues()"""
"""Test that GithubUpdater.update_issues() handles long title gracefully"""
new_issues_count = len(github_api_repo_issues_response)
expected_count = Issue.objects.count() + new_issues_count
title = "sample" * 100
@@ -106,6 +103,70 @@ def test_update_issues_long_title(tp, library, github_api_repo_issues_response):
assert issue.title == expected_title
def test_update_prs_new(tp, library, github_api_repo_prs_response):
"""Test that GithubUpdater.update_prs() imports new PRs appropriately"""
new_prs_count = len(github_api_repo_prs_response)
expected_count = PullRequest.objects.count() + new_prs_count
with patch("libraries.github.repo_prs") as repo_prs_mock:
updater = GithubUpdater(library=library)
github_api_repo_prs_response[0]["title"] = "sample" * 100
repo_prs_mock.return_value = github_api_repo_prs_response
updater.update_prs()
assert PullRequest.objects.count() == expected_count
ids = [pr.id for pr in github_api_repo_prs_response]
pulls = PullRequest.objects.filter(library=library, github_id__in=ids)
assert pulls.exists()
assert pulls.count() == expected_count
# Test the values of a sample PR
gh_pull = github_api_repo_prs_response[0]
pr = pulls.get(github_id=gh_pull.id)
assert pr.title == gh_pull.title[:255]
assert pr.number == gh_pull.number
if gh_pull.state == "open":
assert pr.is_open
else:
assert not pr.is_open
assert pr.data == gh_pull
expected_closed = parse(gh_pull["closed_at"])
expected_created = parse(gh_pull["created_at"])
expected_modified = parse(gh_pull["updated_at"])
assert pr.closed == expected_closed
assert pr.created == expected_created
assert pr.modified == expected_modified
def test_update_prs_existing(tp, library, github_api_repo_prs_response):
"""Test that GithubUpdater.update_prs() updates existing PRs when appropriate"""
existing_pr_data = github_api_repo_prs_response[0]
old_title = "Old title"
pull = baker.make(
PullRequest, library=library, github_id=existing_pr_data.id, title=old_title
)
# Make sure we are expected one fewer new PRs, since we created one in advance
new_prs_count = len(github_api_repo_prs_response)
expected_count = PullRequest.objects.count() + new_prs_count - 1
with patch("libraries.github.repo_prs") as repo_prs_mock:
updater = GithubUpdater(library=library)
repo_prs_mock.return_value = github_api_repo_prs_response
updater.update_prs()
assert PullRequest.objects.count() == expected_count
ids = [pr.id for pr in github_api_repo_prs_response]
pulls = PullRequest.objects.filter(library=library, github_id__in=ids)
assert pulls.exists()
assert pulls.count() == expected_count
# Test that the existing PR updated
pull.refresh_from_db()
assert pull.title == existing_pr_data.title
# LibraryUpdater tests

View File

@@ -14,10 +14,28 @@ def test_library_detail(library, tp):
tp.response_200(response)
def test_library_detail_issues_context(tp, library):
def test_library_detail_context_get_closed_prs_count(tp, library):
"""
GET /libraries/{repo}/
Test that the custom context vars appear as expected
Test that the custom closed_prs_count var appears as expected
"""
# Create open and closed PRs for this library, and another random PR
lib2 = baker.make("libraries.Library", slug="sample")
baker.make("libraries.PullRequest", library=library, is_open=True)
baker.make("libraries.PullRequest", library=library, is_open=False)
baker.make("libraries.PullRequest", library=lib2, is_open=True)
url = tp.reverse("library-detail", library.slug)
response = tp.get(url)
tp.response_200(response)
assert "closed_prs_count" in response.context
# Verify that the count only includes the one open PR for this library
assert response.context["closed_prs_count"] == 1
def test_library_detail_context_get_open_issues_count(tp, library):
"""
GET /libraries/{repo}/
Test that the custom open_issues_count var appears as expected
"""
# Create open and closed issues for this library, and another random issue
lib2 = baker.make("libraries.Library", slug="sample")

View File

@@ -1,6 +1,6 @@
from django.views.generic import DetailView, ListView
from .models import Category, Issue, Library
from .models import Category, Issue, Library, PullRequest
class CategoryMixin:
@@ -59,8 +59,12 @@ class LibraryDetail(CategoryMixin, DetailView):
def get(self, request, *args, **kwargs):
self.object = self.get_object()
context = self.get_context_data(object=self.object)
context["closed_prs_count"] = self.get_closed_prs_count(self.object)
context["open_issues_count"] = self.get_open_issues_count(self.object)
return self.render_to_response(context)
def get_closed_prs_count(self, obj):
return PullRequest.objects.filter(library=obj, is_open=True).count()
def get_open_issues_count(self, obj):
return Issue.objects.filter(library=obj, is_open=True).count()

View File

@@ -63,7 +63,7 @@
<div class="md:flex my-4 md:my-11 py-6 md:justify-between">
<div class="py-6">
<h3 class="text-2xl mb-1">Closed Pull Requests</h3>
X per Month
{{ closed_prs_count }}
</div>
<div class="py-6">