Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add library report over all releases. #1310

Merged
merged 3 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 48 additions & 13 deletions libraries/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from django.utils.safestring import mark_safe
from django.shortcuts import redirect

from libraries.forms import CreateReportForm
from libraries.forms import CreateReportForm, CreateReportFullForm
from versions.tasks import import_all_library_versions
from .models import (
Category,
Expand Down Expand Up @@ -139,40 +139,75 @@ def get_urls(self):
name="library_stat_detail",
),
path(
"report-form/",
self.admin_site.admin_view(self.report_form_view),
name="library_report_form",
"release-report-form/",
self.admin_site.admin_view(self.release_report_form),
name="release_report_form",
),
path(
"report/",
self.admin_site.admin_view(self.report_view),
name="library_report",
"release-report/",
self.admin_site.admin_view(self.release_report_view),
name="release_report",
),
path(
"report-full-form/",
self.admin_site.admin_view(self.report_form_full_view),
name="library_report_full_form",
),
path(
"report-full/",
self.admin_site.admin_view(self.report_full_view),
name="library_report_full",
),
]
return my_urls + urls

def report_form_view(self, request):
def release_report_form(self, request):
form = CreateReportForm()
context = {}
if request.GET.get("version", None):
if request.GET.get("submit", None):
form = CreateReportForm(request.GET)
if form.is_valid():
context.update(form.get_stats())
return redirect(
reverse("admin:library_report") + f"?{request.GET.urlencode()}"
reverse("admin:release_report") + f"?{request.GET.urlencode()}"
)
if not context:
context["form"] = form
return TemplateResponse(request, "admin/library_report_form.html", context)

def report_view(self, request):
def release_report_view(self, request):
form = CreateReportForm(request.GET)
context = {"form": form}
if form.is_valid():
context.update(form.get_stats())
else:
return redirect("admin:library_report_form")
return TemplateResponse(request, "admin/library_report_detail.html", context)
return redirect("admin:release_report_form")
return TemplateResponse(request, "admin/release_report_detail.html", context)

def report_form_full_view(self, request):
form = CreateReportFullForm()
context = {}
if request.GET.get("submit", None):
form = CreateReportFullForm(request.GET)
if form.is_valid():
context.update(form.get_stats())
return redirect(
reverse("admin:library_report_full") + f"?{request.GET.urlencode()}"
)
if not context:
context["form"] = form
return TemplateResponse(request, "admin/library_report_form.html", context)

def report_full_view(self, request):
form = CreateReportFullForm(request.GET)
context = {"form": form}
if form.is_valid():
context.update(form.get_stats())
else:
return redirect("admin:library_report_full_form")
return TemplateResponse(
request, "admin/library_report_full_detail.html", context
)

def view_stats(self, instance):
url = reverse("admin:library_stat_detail", kwargs={"pk": instance.pk})
Expand Down
129 changes: 102 additions & 27 deletions libraries/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,14 @@ class VersionSelectionForm(Form):
)


class CreateReportForm(Form):
class CreateReportFullForm(Form):
"""Form for creating a report over all releases."""

library_queryset = Library.objects.all().order_by("name")
version = ModelChoiceField(
queryset=Version.objects.active()
.exclude(name__in=["develop", "master", "head"])
.order_by("-name")
)
library_1 = ModelChoiceField(
queryset=library_queryset,
required=False,
help_text=(
"If none are selected, the top 5 for this release will be auto-selected."
),
help_text="If none are selected, the top 5 will be auto-selected.",
)
library_2 = ModelChoiceField(
queryset=library_queryset,
Expand Down Expand Up @@ -65,28 +60,14 @@ class CreateReportForm(Form):
required=False,
)

def _get_top_contributors_for_version(self):
return (
CommitAuthor.objects.filter(
commit__library_version__version=self.cleaned_data["version"]
)
.annotate(commit_count=Count("commit"))
.values("name", "avatar_url", "commit_count")
.order_by("-commit_count")[:10]
)

def _get_top_libraries_for_version(self):
def _get_top_libraries(self):
return (
Library.objects.filter(
library_version=LibraryVersion.objects.filter(
library=OuterRef("id"), version=self.cleaned_data["version"]
)[:1],
)
Library.objects.all()
.annotate(commit_count=Count("library_version__commit"))
.order_by("-commit_count")[:5]
)

def _get_library_order(self, top_libraries_release):
def _get_library_order(self, top_libraries):
library_order = [
x.id
for x in [
Expand All @@ -102,7 +83,7 @@ def _get_library_order(self, top_libraries_release):
if x is not None
]
if not library_order:
library_order = [x.id for x in top_libraries_release]
library_order = [x.id for x in top_libraries]
return library_order

def _get_library_full_counts(self, libraries, library_order):
Expand All @@ -115,6 +96,99 @@ def _get_library_full_counts(self, libraries, library_order):
key=lambda x: library_order.index(x["id"]),
)

def _get_top_contributors_overall(self):
return (
CommitAuthor.objects.all()
.annotate(commit_count=Count("commit"))
.values("name", "avatar_url", "commit_count", "github_profile_url")
.order_by("-commit_count")[:10]
)

def _get_top_contributors_for_library(self, library_order):
top_contributors_library = []
for library_id in library_order:
top_contributors_library.append(
CommitAuthor.objects.filter(
commit__library_version__library_id=library_id
)
.annotate(commit_count=Count("commit"))
.values(
"name",
"avatar_url",
"github_profile_url",
"commit_count",
"commit__library_version__library_id",
)
.order_by("-commit_count")[:10]
)
return top_contributors_library

def get_stats(self):
commit_count = Commit.objects.count()

top_libraries = self._get_top_libraries()
library_order = self._get_library_order(top_libraries)
libraries = Library.objects.filter(id__in=library_order)
library_data = [
{
"library": x[0],
"full_count": x[1],
"top_contributors": x[2],
}
for x in zip(
sorted(list(libraries), key=lambda x: library_order.index(x.id)),
self._get_library_full_counts(libraries, library_order),
self._get_top_contributors_for_library(library_order),
)
]
top_contributors = self._get_top_contributors_overall()
return {
"commit_count": commit_count,
"top_contributors": top_contributors,
"library_data": library_data,
"top_libraries": top_libraries,
"library_count": Library.objects.all().count(),
}


class CreateReportForm(CreateReportFullForm):
"""Form for creating a report for a specific release."""

version = ModelChoiceField(
queryset=Version.objects.active()
.exclude(name__in=["develop", "master", "head"])
.order_by("-name")
)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields[
"library_1"
].help_text = (
"If none are selected, the top 5 for this release will be auto-selected."
)

def _get_top_contributors_for_version(self):
return (
CommitAuthor.objects.filter(
commit__library_version__version=self.cleaned_data["version"]
)
.annotate(commit_count=Count("commit"))
.values("name", "avatar_url", "commit_count", "github_profile_url")
.order_by("-commit_count")[:10]
)

def _get_top_libraries_for_version(self):
return (
Library.objects.filter(
library_version=LibraryVersion.objects.filter(
library=OuterRef("id"), version=self.cleaned_data["version"]
)[:1],
)
.annotate(commit_count=Count("library_version__commit"))
.order_by("-commit_count")[:5]
)

def _get_library_version_counts(self, libraries, library_order):
return sorted(
list(
Expand Down Expand Up @@ -173,6 +247,7 @@ def _get_top_contributors_for_library_version(self, library_order):
.values(
"name",
"avatar_url",
"github_profile_url",
"commit_count",
"commit__library_version__library_id",
)
Expand Down
3 changes: 2 additions & 1 deletion templates/admin/library_change_list.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
{% block object-tools-items %}
{{ block.super }}
<li><a href="{% url 'admin:update_libraries' %}" class="addlink">{% trans "Update Library Data" %}</a></li>
<li><a href="{% url 'admin:library_report_form' %}" class="addlink">{% trans "Get Release Report" %}</a></li>
<li><a href="{% url 'admin:release_report_form' %}" class="addlink">{% trans "Get Release Report" %}</a></li>
<li><a href="{% url 'admin:library_report_full_form' %}" class="addlink">{% trans "Get Library Report" %}</a></li>
{% endblock %}
</ul>
{% endblock %}
54 changes: 54 additions & 0 deletions templates/admin/library_report_base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{% load static humanize avatar_tags %}
<!DOCTYPE html>
<html>
<head>
<title>
{% block title %}Boost{% endblock %}
</title>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="{% block description %}{% endblock %}" />
<meta name="keywords" content="{% block keywords %}{% endblock %}" />
<meta name="author"
content="{% block author %}Boost C++ Libraries{% endblock %}" />
<link rel="shortcut icon"
href="{% static 'img/Boost_Symbol_Transparent.svg' %}"
type="image/x-icon" />
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,100..900;1,100..900&display=swap"
rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+Mono&display=swap"
rel="stylesheet">
<link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@24,400,0,0" />
<link rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.css" />
<!-- TODO bring this local if we like it -->
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
<script src="{% static 'js/boost-gecko/main.062e4862.js' %}" defer></script>
{% block extra_head %}
<link href="{% static 'css/styles.css' %}" rel="stylesheet" />
{% endblock %}
{% block css %}
<style>
@page {
margin: 0;
size: 300mm 180mm;
}

.pdf-page {
padding: 5mm;
height: 180mm;
width: 300mm;
page-break-after: always;
}
</style>
{% endblock css %}
</head>
<body>
{% block content %}
{% endblock content %}
</body>
</html>
4 changes: 2 additions & 2 deletions templates/admin/library_report_form.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
{% block content %}
{{ block.super }}
<div class='container mx-auto'>
<h1>Generate Report for Release</h1>
<h1>Generate Report</h1>
<div>
<form action="">
{{ form.as_p }}
<input class="default" type="submit" />
<input name="submit" value="Submit" class="default" type="submit" />
</form>
</div>
</div>
Expand Down
Loading