Skip to content

Commit 301aaea

Browse files
authored
Decouple release reports from releases (boostorg#1737)
1 parent 0b146ce commit 301aaea

File tree

11 files changed

+308
-147
lines changed

11 files changed

+308
-147
lines changed

docs/commands.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,7 @@ For this to work `SLACK_BOT_API` must be set in the `.env` file.
334334

335335
| Options | Format | Description |
336336
|----------------|--------|----------------------------------------------------------------------------------------------------------------------|
337-
| `--start_date` | date | If passed, retrieves data from the start date supplied, d-m-y, default 20-11-1998 (the start of the data in mailman) |
337+
| `--start_date` | date | If passed, retrieves data from the start date supplied, d-m-y, default 1998-11-20 (the start of the data in mailman) |
338338
| `--end_date` | date | If passed, If passed, retrieves data until the start date supplied, d-m-y, default today |
339339

340340
## `link_contributors_to_users`

libraries/forms.py

Lines changed: 84 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
get_new_subscribers_stats,
1717
)
1818
from slack.models import Channel, SlackActivityBucket, SlackUser
19-
from versions.models import Version
19+
from versions.models import Version, ReportConfiguration
2020
from .models import (
2121
Commit,
2222
CommitAuthor,
@@ -232,8 +232,8 @@ class CreateReportForm(CreateReportFullForm):
232232

233233
html_template_name = "admin/release_report_detail.html"
234234

235-
version = ModelChoiceField(
236-
queryset=Version.objects.minor_versions().order_by("-version_array")
235+
report_configuration = ModelChoiceField(
236+
queryset=ReportConfiguration.objects.order_by("-version")
237237
)
238238

239239
def __init__(self, *args, **kwargs):
@@ -255,14 +255,12 @@ def cache_key(self):
255255
self.cleaned_data["library_8"],
256256
]
257257
lib_string = ",".join(str(x.id) if x else "" for x in chosen_libraries)
258-
version = self.cleaned_data["version"]
259-
return f"release-report-{lib_string}-{version.name}"
258+
report_configuration = self.cleaned_data["report_configuration"]
259+
return f"release-report-{lib_string}-{report_configuration.version}"
260260

261-
def _get_top_contributors_for_version(self):
261+
def _get_top_contributors_for_version(self, version):
262262
return (
263-
CommitAuthor.objects.filter(
264-
commit__library_version__version=self.cleaned_data["version"]
265-
)
263+
CommitAuthor.objects.filter(commit__library_version__version=version)
266264
.annotate(
267265
commit_count=Count(
268266
"commit",
@@ -277,30 +275,32 @@ def _get_top_contributors_for_version(self):
277275
def _get_library_queryset_by_version(
278276
self, version: Version, annotate_commit_count=False
279277
):
280-
qs = self.library_queryset.filter(
281-
library_version=LibraryVersion.objects.filter(
282-
library=OuterRef("id"), version=version
283-
)[:1],
284-
)
278+
qs = self.library_queryset.none()
279+
if version:
280+
qs = self.library_queryset.filter(
281+
library_version=LibraryVersion.objects.filter(
282+
library=OuterRef("id"), version=version
283+
)[:1],
284+
)
285285
if annotate_commit_count:
286286
qs = qs.annotate(commit_count=Count("library_version__commit"))
287287
return qs
288288

289-
def _get_top_libraries_for_version(self):
289+
def _get_top_libraries_for_version(self, version):
290290
library_qs = self._get_library_queryset_by_version(
291-
self.cleaned_data["version"], annotate_commit_count=True
291+
version, annotate_commit_count=True
292292
)
293293
return library_qs.order_by("-commit_count")
294294

295-
def _get_libraries_by_name(self):
295+
def _get_libraries_by_name(self, version):
296296
library_qs = self._get_library_queryset_by_version(
297-
self.cleaned_data["version"], annotate_commit_count=True
297+
version, annotate_commit_count=True
298298
)
299299
return library_qs.order_by("name")
300300

301-
def _get_libraries_by_quality(self):
301+
def _get_libraries_by_quality(self, version):
302302
# returns "great", "good", and "standard" libraries in that order
303-
library_qs = self._get_library_queryset_by_version(self.cleaned_data["version"])
303+
library_qs = self._get_library_queryset_by_version(version)
304304
return list(
305305
chain(
306306
library_qs.filter(graphic__isnull=False),
@@ -309,17 +309,16 @@ def _get_libraries_by_quality(self):
309309
)
310310
)
311311

312-
def _get_library_version_counts(self, libraries, library_order):
312+
def _get_library_version_counts(self, library_order, version):
313313
library_qs = self._get_library_queryset_by_version(
314-
self.cleaned_data["version"], annotate_commit_count=True
314+
version, annotate_commit_count=True
315315
)
316316
return sorted(
317317
list(library_qs.values("commit_count", "id")),
318318
key=lambda x: library_order.index(x["id"]),
319319
)
320320

321-
def _global_new_contributors(self, library_version):
322-
version = self.cleaned_data["version"]
321+
def _global_new_contributors(self, version):
323322
version_lt = list(
324323
Version.objects.minor_versions()
325324
.filter(version_array__lt=version.cleaned_version_parts_int)
@@ -343,8 +342,7 @@ def _global_new_contributors(self, library_version):
343342

344343
return set(version_author_ids) - set(prior_version_author_ids)
345344

346-
def _count_new_contributors(self, libraries, library_order):
347-
version = self.cleaned_data["version"]
345+
def _count_new_contributors(self, libraries, library_order, version):
348346
version_lt = list(
349347
Version.objects.minor_versions()
350348
.filter(version_array__lt=version.cleaned_version_parts_int)
@@ -382,12 +380,12 @@ def _count_new_contributors(self, libraries, library_order):
382380
key=lambda x: library_order.index(x["id"]),
383381
)
384382

385-
def _count_issues(self, libraries, library_order, version):
383+
def _count_issues(self, libraries, library_order, version, prior_version):
386384
data = {
387385
x["library_id"]: x
388-
for x in Issue.objects.count_opened_closed_during_release(version).filter(
389-
library_id__in=[x.id for x in libraries]
390-
)
386+
for x in Issue.objects.count_opened_closed_during_release(
387+
version, prior_version
388+
).filter(library_id__in=[x.id for x in libraries])
391389
}
392390
ret = []
393391
for lib_id in library_order:
@@ -397,14 +395,14 @@ def _count_issues(self, libraries, library_order, version):
397395
ret.append({"opened": 0, "closed": 0, "library_id": lib_id})
398396
return ret
399397

400-
def _count_commit_contributors_totals(self, version):
398+
def _count_commit_contributors_totals(self, version, prior_version):
401399
"""Get a count of contributors for this release, and a count of
402400
new contributors.
403401
404402
"""
405403
version_lt = list(
406404
Version.objects.minor_versions()
407-
.filter(version_array__lt=version.cleaned_version_parts_int)
405+
.filter(version_array__lte=prior_version.cleaned_version_parts_int)
408406
.values_list("id", flat=True)
409407
)
410408
version_lte = version_lt + [version.id]
@@ -439,24 +437,24 @@ def _count_commit_contributors_totals(self, version):
439437
this_release_count = qs["this_release_count"]
440438
return this_release_count, new_count
441439

442-
def _get_top_contributors_for_library_version(self, library_order):
440+
def _get_top_contributors_for_library_version(self, library_order, version):
443441
top_contributors_release = []
444442
for library_id in library_order:
445443
top_contributors_release.append(
446444
CommitAuthor.objects.filter(
447445
commit__library_version=LibraryVersion.objects.get(
448-
version=self.cleaned_data["version"], library_id=library_id
446+
version=version, library_id=library_id
449447
)
450448
)
451449
.annotate(commit_count=Count("commit"))
452450
.order_by("-commit_count")[:10]
453451
)
454452
return top_contributors_release
455453

456-
def _count_mailinglist_contributors(self, version):
454+
def _count_mailinglist_contributors(self, version, prior_version):
457455
version_lt = list(
458456
Version.objects.minor_versions()
459-
.filter(version_array__lt=version.cleaned_version_parts_int)
457+
.filter(version_array__lte=prior_version.cleaned_version_parts_int)
460458
.values_list("id", flat=True)
461459
)
462460
version_lte = version_lt + [version.id]
@@ -620,7 +618,9 @@ def _get_slack_stats_for_channels(
620618
):
621619
"""Get slack stats for specific channels, or all channels."""
622620
start = prior_version.release_date
623-
end = version.release_date - timedelta(days=1)
621+
end = date.today()
622+
if version.release_date:
623+
end = version.release_date - timedelta(days=1)
624624
# count of all messages in the date range
625625
q = Q(day__range=[start, end])
626626
if channels:
@@ -671,7 +671,15 @@ def _get_dependency_data(self, library_order, version):
671671
return diffs
672672

673673
def get_stats(self):
674-
version = self.cleaned_data["version"]
674+
report_configuration = self.cleaned_data["report_configuration"]
675+
version = Version.objects.filter(name=report_configuration.version).first()
676+
677+
prior_version = None
678+
if not version:
679+
# if the version is not set then the user has chosen a report configuration
680+
# that's not matching a live version, so we use the most recent version
681+
version = Version.objects.filter(name="master").first()
682+
prior_version = Version.objects.most_recent()
675683

676684
downloads = {
677685
k: list(v)
@@ -680,12 +688,14 @@ def get_stats(self):
680688
key=attrgetter("operating_system"),
681689
)
682690
}
683-
prior_version = (
684-
Version.objects.minor_versions()
685-
.filter(version_array__lt=version.cleaned_version_parts_int)
686-
.order_by("-version_array")
687-
.first()
688-
)
691+
692+
if not prior_version:
693+
prior_version = (
694+
Version.objects.minor_versions()
695+
.filter(version_array__lt=version.cleaned_version_parts_int)
696+
.order_by("-version_array")
697+
.first()
698+
)
689699

690700
commit_count = Commit.objects.filter(
691701
library_version__version__name__lte=version.name,
@@ -696,8 +706,8 @@ def get_stats(self):
696706
library_version__library__in=self.library_queryset,
697707
).count()
698708

699-
top_libraries_for_version = self._get_top_libraries_for_version()
700-
top_libraries_by_name = self._get_libraries_by_name()
709+
top_libraries_for_version = self._get_top_libraries_for_version(version)
710+
top_libraries_by_name = self._get_libraries_by_name(version)
701711
library_order = self._get_library_order(top_libraries_by_name)
702712
libraries = Library.objects.filter(id__in=library_order).order_by(
703713
Case(
@@ -719,18 +729,18 @@ def get_stats(self):
719729
for item in zip(
720730
libraries,
721731
self._get_library_full_counts(libraries, library_order),
722-
self._get_library_version_counts(libraries, library_order),
723-
self._get_top_contributors_for_library_version(library_order),
724-
self._count_new_contributors(libraries, library_order),
725-
self._count_issues(libraries, library_order, version),
732+
self._get_library_version_counts(library_order, version),
733+
self._get_top_contributors_for_library_version(library_order, version),
734+
self._count_new_contributors(libraries, library_order, version),
735+
self._count_issues(libraries, library_order, version, prior_version),
726736
self._get_library_versions(library_order, version),
727737
self._get_dependency_data(library_order, version),
728738
)
729739
]
730740
library_data = [
731741
x for x in library_data if x["version_count"]["commit_count"] > 0
732742
]
733-
top_contributors = self._get_top_contributors_for_version()
743+
top_contributors = self._get_top_contributors_for_version(version)
734744
# total messages sent during this release (version)
735745
total_mailinglist_count = EmailData.objects.filter(version=version).aggregate(
736746
total=Sum("count")
@@ -743,11 +753,11 @@ def get_stats(self):
743753
(
744754
mailinglist_contributor_release_count,
745755
mailinglist_contributor_new_count,
746-
) = self._count_mailinglist_contributors(version)
756+
) = self._count_mailinglist_contributors(version, prior_version)
747757
(
748758
commit_contributors_release_count,
749759
commit_contributors_new_count,
750-
) = self._count_commit_contributors_totals(version)
760+
) = self._count_commit_contributors_totals(version, prior_version)
751761
library_count = LibraryVersion.objects.filter(
752762
version=version,
753763
library__in=self.library_queryset,
@@ -775,22 +785,35 @@ def get_stats(self):
775785
slack_channels = batched(
776786
Channel.objects.filter(name__istartswith="boost").order_by("name"), 10
777787
)
778-
committee_members = version.financial_committee_members.all()
788+
committee_members = report_configuration.financial_committee_members.all()
779789
mailinglist_post_stats = get_mailing_list_post_stats(
780-
prior_version.release_date, version.release_date
790+
prior_version.release_date, version.release_date or date.today()
781791
)
782792
new_subscribers_stats = get_new_subscribers_stats(
783-
prior_version.release_date, version.release_date
793+
prior_version.release_date, version.release_date or date.today()
784794
)
785795
library_index_library_data = []
786-
for library in self._get_libraries_by_quality():
796+
for library in self._get_libraries_by_quality(version):
787797
library_index_library_data.append(
788798
(
789799
library,
790800
library in [lib["library"] for lib in library_data],
791801
)
792802
)
793-
wordcloud_base64, wordcloud_top_words = generate_wordcloud(version)
803+
wordcloud_base64, wordcloud_top_words = generate_wordcloud(
804+
version, prior_version
805+
)
806+
807+
opened_issues_count = (
808+
Issue.objects.filter(library__in=self.library_queryset)
809+
.opened_during_release(version, prior_version)
810+
.count()
811+
)
812+
closed_issues_count = (
813+
Issue.objects.filter(library__in=self.library_queryset)
814+
.closed_during_release(version, prior_version)
815+
.count()
816+
)
794817

795818
return {
796819
"committee_members": committee_members,
@@ -799,17 +822,10 @@ def get_stats(self):
799822
"wordcloud_base64": wordcloud_base64,
800823
"wordcloud_frequencies": wordcloud_top_words,
801824
"version": version,
825+
"report_configuration": report_configuration,
802826
"prior_version": prior_version,
803-
"opened_issues_count": Issue.objects.filter(
804-
library__in=self.library_queryset
805-
)
806-
.opened_during_release(version)
807-
.count(),
808-
"closed_issues_count": Issue.objects.filter(
809-
library__in=self.library_queryset
810-
)
811-
.closed_during_release(version)
812-
.count(),
827+
"opened_issues_count": opened_issues_count,
828+
"closed_issues_count": closed_issues_count,
813829
"mailinglist_counts": mailinglist_counts,
814830
"mailinglist_total": total_mailinglist_count or 0,
815831
"mailinglist_contributor_release_count": mailinglist_contributor_release_count, # noqa: E501

0 commit comments

Comments
 (0)