From f5cd9ef2aa211da222ffedf8798b78206db019b4 Mon Sep 17 00:00:00 2001 From: Alex Finder Date: Thu, 26 Jun 2025 10:08:21 +0300 Subject: [PATCH] Add filtering by all sheriffed frameworks in Alerts View --- .../api/test_performance_alertsummary_api.py | 35 ++++++++++++++++++- treeherder/webapp/api/performance_data.py | 6 +++- treeherder/webapp/api/utils.py | 11 ++++++ ui/perfherder/alerts/AlertsView.jsx | 17 +++++++-- ui/perfherder/alerts/AlertsViewControls.jsx | 12 ++++--- 5 files changed, 72 insertions(+), 9 deletions(-) diff --git a/tests/webapp/api/test_performance_alertsummary_api.py b/tests/webapp/api/test_performance_alertsummary_api.py index bb08f0daf97..7fdbc0d06e6 100644 --- a/tests/webapp/api/test_performance_alertsummary_api.py +++ b/tests/webapp/api/test_performance_alertsummary_api.py @@ -6,7 +6,11 @@ from tests.conftest import create_perf_alert from treeherder.model.models import Push -from treeherder.perf.models import PerformanceAlert, PerformanceAlertSummary +from treeherder.perf.models import ( + PerformanceAlert, + PerformanceAlertSummary, + PerformanceFramework, +) pytestmark = pytest.mark.perf @@ -153,6 +157,35 @@ def test_alert_summaries_get_multiple_alerts( assert len(set([result["id"] for result in data["results"]])) == 2 +def test_alert_summaries_sheriffed_frameworks( + client, test_perf_alert_summary, test_perf_alert_summary_2, test_perf_framework +): + # verify that we return only the sheriffed framework alerts if show_sheriffed_frameworks is True + sheriffed_framework = PerformanceFramework.objects.create(name="browsertime", enabled=True) + non_sheriffed_framework = PerformanceFramework.objects.create( + name="platform_microbench", enabled=True + ) + test_perf_alert_summary.framework = sheriffed_framework + test_perf_alert_summary.save() + test_perf_alert_summary_2.framework = non_sheriffed_framework + test_perf_alert_summary_2.save() + resp = client.get( + reverse("performance-alert-summaries-list"), {"show_sheriffed_frameworks": True} + ) + assert resp.status_code == 200 + # Should only include the sheriffed alert (browsertime) + assert len(resp.json()["results"]) == 1 + assert resp.json()["results"][0]["framework"] == sheriffed_framework.id + test_perf_alert_summary.framework = test_perf_framework + test_perf_alert_summary.save() + resp = client.get( + reverse("performance-alert-summaries-list"), {"show_sheriffed_frameworks": True} + ) + assert resp.status_code == 200 + # Should return no results, since test_talos is not a sheriffed framework + assert len(resp.json()["results"]) == 0 + + def test_alert_summaries_get_onhold( client, test_perf_alert_summary, diff --git a/treeherder/webapp/api/performance_data.py b/treeherder/webapp/api/performance_data.py index 62aec2996fd..f42b20f9301 100644 --- a/treeherder/webapp/api/performance_data.py +++ b/treeherder/webapp/api/performance_data.py @@ -47,7 +47,7 @@ TestSuiteHealthParamsSerializer, TestSuiteHealthSerializer, ) -from .utils import GroupConcat, get_profile_artifact_url +from .utils import SHERIFFED_FRAMEWORKS, GroupConcat, get_profile_artifact_url class PerformanceSignatureViewSet(viewsets.ViewSet): @@ -347,6 +347,7 @@ class PerformanceAlertSummaryFilter(django_filters.FilterSet): hide_related_and_invalid = django_filters.BooleanFilter(method="_hide_related_and_invalid") with_assignee = django_filters.CharFilter(method="_with_assignee") timerange = django_filters.NumberFilter(method="_timerange") + show_sheriffed_frameworks = django_filters.BooleanFilter(method="_show_sheriffed_frameworks") def _filter_text(self, queryset, name, value): sep = Value(" ") @@ -418,6 +419,9 @@ def _timerange(self, queryset, name, value): push__time__gt=datetime.datetime.utcfromtimestamp(int(time.time() - int(value))) ) + def _show_sheriffed_frameworks(self, queryset, name, value): + return queryset.filter(framework__name__in=SHERIFFED_FRAMEWORKS) + class Meta: model = PerformanceAlertSummary fields = [ diff --git a/treeherder/webapp/api/utils.py b/treeherder/webapp/api/utils.py index ee0b6ed3933..beca10ca2f7 100644 --- a/treeherder/webapp/api/utils.py +++ b/treeherder/webapp/api/utils.py @@ -20,6 +20,17 @@ FIVE_DAYS = 432000 +# Constant used to check for sheriffed frameworks +SHERIFFED_FRAMEWORKS = [ + "awsy", + "browsertime", + "build_metrics", + "devtools", + "js-bench", + "mozperftest", + "talos", +] + class GroupConcat(Aggregate): function = "GROUP_CONCAT" diff --git a/ui/perfherder/alerts/AlertsView.jsx b/ui/perfherder/alerts/AlertsView.jsx index 090b2057717..1d1b92a7c3a 100644 --- a/ui/perfherder/alerts/AlertsView.jsx +++ b/ui/perfherder/alerts/AlertsView.jsx @@ -150,6 +150,11 @@ class AlertsView extends React.Component { const frameworkOptions = cloneDeep(frameworks); const ignoreFrameworks = { id: -1, name: 'all frameworks' }; frameworkOptions.unshift(ignoreFrameworks); + const allSheriffedFrameworks = { + id: -2, + name: 'all sheriffed frameworks', + }; + frameworkOptions.unshift(allSheriffedFrameworks); return frameworkOptions; }; @@ -201,13 +206,21 @@ class AlertsView extends React.Component { // -1 ('all') is created for UI purposes but is not a valid API parameter const doNotFilter = -1; + // -2 ('all sheriffed') Constant created for UI purposes but is not a valid API parameter + const allSheriffedFrameworksID = -2; const listMode = !id; if (listMode && params.status === doNotFilter) { delete params.status; } - if (listMode && params.framework === doNotFilter) { - delete params.framework; + + if (listMode) { + if (params.framework === allSheriffedFrameworksID) { + params.show_sheriffed_frameworks = true; + } + if ([doNotFilter, allSheriffedFrameworksID].includes(params.framework)) { + delete params.framework; + } } return params; diff --git a/ui/perfherder/alerts/AlertsViewControls.jsx b/ui/perfherder/alerts/AlertsViewControls.jsx index ae739aca0fd..60b6e740b2c 100644 --- a/ui/perfherder/alerts/AlertsViewControls.jsx +++ b/ui/perfherder/alerts/AlertsViewControls.jsx @@ -138,14 +138,16 @@ export default class AlertsViewControls extends React.Component { let sortedFrameworks = sortData(frameworkOptions, 'name', false); const allFrameworks = 'all frameworks'; - const mozperftest = 'mozperftest'; + const allSheriffedFrameworks = 'all sheriffed frameworks'; const platformMicrobench = 'platform_microbench'; + const telemetry = 'telemetry'; sortedFrameworks = sortedFrameworks.filter( (framework) => - framework.name !== mozperftest && framework.name !== platformMicrobench && - framework.name !== allFrameworks, + framework.name !== telemetry && + framework.name !== allFrameworks && + framework.name !== allSheriffedFrameworks, ); const frameworkNames = @@ -165,8 +167,8 @@ export default class AlertsViewControls extends React.Component { selectedItem: framework.name, updateData: this.updateFramework, namespace: 'framework', - pinned: [allFrameworks], - otherPinned: [mozperftest, platformMicrobench], + pinned: [allFrameworks, allSheriffedFrameworks], + otherPinned: [platformMicrobench, telemetry], }, ];