diff --git a/apiserver/dora/service/deployments/analytics.py b/apiserver/dora/service/deployments/analytics.py index 6d7ea8401..f4ef19f00 100644 --- a/apiserver/dora/service/deployments/analytics.py +++ b/apiserver/dora/service/deployments/analytics.py @@ -191,6 +191,14 @@ def _get_deployment_frequency_metrics( self, successful_deployments: List[Deployment], interval: Interval ) -> DeploymentFrequencyMetrics: + successful_deployments = list( + filter( + lambda x: x.conducted_at >= interval.from_time + and x.conducted_at <= interval.to_time, + successful_deployments, + ) + ) + team_daily_deployments = generate_expanded_buckets( successful_deployments, interval, "conducted_at", "daily" ) @@ -230,6 +238,14 @@ def _get_weekly_deployment_frequency_trends( self, successful_deployments: List[Deployment], interval: Interval ) -> Dict[datetime, int]: + successful_deployments = list( + filter( + lambda x: x.conducted_at >= interval.from_time + and x.conducted_at <= interval.to_time, + successful_deployments, + ) + ) + team_weekly_deployments = generate_expanded_buckets( successful_deployments, interval, "conducted_at", "weekly" ) diff --git a/apiserver/tests/factories/models/code.py b/apiserver/tests/factories/models/code.py index 74da50796..8ed232982 100644 --- a/apiserver/tests/factories/models/code.py +++ b/apiserver/tests/factories/models/code.py @@ -2,6 +2,7 @@ from uuid import uuid4 from dora.service.deployments.models.models import ( Deployment, + DeploymentFrequencyMetrics, DeploymentStatus, DeploymentType, ) @@ -174,3 +175,18 @@ def get_deployment( html_url=html_url or "", meta=meta or {}, ) + + +def get_deployment_frequency_metrics( + total_deployments=0, + daily_deployment_frequency=0, + avg_weekly_deployment_frequency=0, + avg_monthly_deployment_frequency=0, +) -> DeploymentFrequencyMetrics: + + return DeploymentFrequencyMetrics( + total_deployments=total_deployments or 0, + daily_deployment_frequency=daily_deployment_frequency or 0, + avg_weekly_deployment_frequency=avg_weekly_deployment_frequency or 0, + avg_monthly_deployment_frequency=avg_monthly_deployment_frequency or 0, + ) diff --git a/apiserver/tests/service/deployments/test_deployment_frequency.py b/apiserver/tests/service/deployments/test_deployment_frequency.py new file mode 100644 index 000000000..c84df8680 --- /dev/null +++ b/apiserver/tests/service/deployments/test_deployment_frequency.py @@ -0,0 +1,181 @@ +from datetime import datetime, timedelta + +import pytz +from dora.service.deployments.analytics import DeploymentAnalyticsService +from dora.utils.time import Interval +from tests.factories.models.code import get_deployment, get_deployment_frequency_metrics + +first_week_2024 = datetime(2024, 1, 1, 0, 0, 0, tzinfo=pytz.UTC) +second_week_2024 = datetime(2024, 1, 8, 0, 0, 0, tzinfo=pytz.UTC) +third_week_2024 = datetime(2024, 1, 15, 0, 0, 0, tzinfo=pytz.UTC) +fourth_week_2024 = datetime(2024, 1, 22, 0, 0, 0, tzinfo=pytz.UTC) + + +def test_deployment_frequency_for_no_deployments(): + + from_time = first_week_2024 + timedelta(days=1) + to_time = third_week_2024 + timedelta(days=2) + + deployment_analytics_service = DeploymentAnalyticsService(None, None) + + assert ( + deployment_analytics_service._get_deployment_frequency_metrics( + [], Interval(from_time, to_time) + ) + == get_deployment_frequency_metrics() + ) + + +def test_deployment_frequency_for_deployments_across_days(): + + from_time = first_week_2024 + timedelta(days=1) + to_time = first_week_2024 + timedelta(days=4) + + deployment_1 = get_deployment(conducted_at=from_time + timedelta(hours=12)) + deployment_2 = get_deployment(conducted_at=from_time + timedelta(days=1)) + deployment_3 = get_deployment(conducted_at=from_time + timedelta(days=2)) + + deployment_outside_interval = get_deployment( + conducted_at=to_time + timedelta(days=20) + ) + + deployment_analytics_service = DeploymentAnalyticsService(None, None) + + assert deployment_analytics_service._get_deployment_frequency_metrics( + [deployment_1, deployment_2, deployment_3, deployment_outside_interval], + Interval(from_time, to_time), + ) == get_deployment_frequency_metrics(3, 0, 3, 3) + + +def test_deployment_frequency_for_deployments_across_weeks(): + + from_time = first_week_2024 + timedelta(days=1) + to_time = fourth_week_2024 + timedelta(days=1) + + # Week 1 + + deployment_1 = get_deployment(conducted_at=from_time + timedelta(hours=12)) + deployment_2 = get_deployment(conducted_at=from_time + timedelta(hours=24)) + + # Week 3 + deployment_3 = get_deployment(conducted_at=fourth_week_2024 - timedelta(days=4)) + deployment_4 = get_deployment(conducted_at=fourth_week_2024 - timedelta(days=2)) + deployment_5 = get_deployment(conducted_at=fourth_week_2024 - timedelta(hours=6)) + deployment_6 = get_deployment(conducted_at=fourth_week_2024 - timedelta(minutes=30)) + + deployment_analytics_service = DeploymentAnalyticsService(None, None) + + assert deployment_analytics_service._get_deployment_frequency_metrics( + [ + deployment_1, + deployment_2, + deployment_3, + deployment_4, + deployment_5, + deployment_6, + ], + Interval(from_time, to_time), + ) == get_deployment_frequency_metrics(6, 0, 1, 6) + + +def test_deployment_frequency_for_deployments_across_months(): + + from_time = first_week_2024 + timedelta(days=1) + to_time = datetime(2024, 3, 31, 0, 0, 0, tzinfo=pytz.UTC) + + second_month_2024 = datetime(2024, 2, 1, 0, 0, 0, tzinfo=pytz.UTC) + + print((to_time - from_time).days) + + # Month 1 + + deployment_1 = get_deployment(conducted_at=from_time + timedelta(hours=12)) + deployment_2 = get_deployment(conducted_at=from_time + timedelta(hours=24)) + deployment_3 = get_deployment(conducted_at=fourth_week_2024 - timedelta(days=4)) + deployment_4 = get_deployment(conducted_at=fourth_week_2024 - timedelta(days=2)) + deployment_5 = get_deployment(conducted_at=fourth_week_2024 - timedelta(hours=6)) + deployment_6 = get_deployment(conducted_at=fourth_week_2024 - timedelta(minutes=30)) + + # Month 2 + + deployment_7 = get_deployment(conducted_at=second_month_2024 + timedelta(days=3)) + deployment_8 = get_deployment(conducted_at=second_month_2024 + timedelta(days=2)) + deployment_9 = get_deployment( + conducted_at=second_month_2024 + timedelta(minutes=30) + ) + + # Month 3 + + deployment_10 = get_deployment(conducted_at=to_time - timedelta(days=3)) + deployment_11 = get_deployment(conducted_at=to_time - timedelta(days=2)) + deployment_12 = get_deployment(conducted_at=to_time - timedelta(days=1)) + deployment_13 = get_deployment(conducted_at=to_time - timedelta(days=1)) + + deployment_analytics_service = DeploymentAnalyticsService(None, None) + + assert deployment_analytics_service._get_deployment_frequency_metrics( + [ + deployment_1, + deployment_2, + deployment_3, + deployment_4, + deployment_5, + deployment_6, + deployment_7, + deployment_8, + deployment_9, + deployment_10, + deployment_11, + deployment_12, + deployment_13, + ], + Interval(from_time, to_time), + ) == get_deployment_frequency_metrics(13, 0, 1, 4) + + +def test_weekly_deployment_frequency_trends_for_no_deployments(): + + from_time = first_week_2024 + timedelta(days=1) + to_time = third_week_2024 + timedelta(days=2) + + deployment_analytics_service = DeploymentAnalyticsService(None, None) + + assert deployment_analytics_service._get_weekly_deployment_frequency_trends( + [], Interval(from_time, to_time) + ) == {first_week_2024: 0, second_week_2024: 0, third_week_2024: 0} + + +def test_weekly_deployment_frequency_trends_for_deployments(): + + from_time = first_week_2024 + timedelta(days=1) + to_time = fourth_week_2024 + timedelta(days=1) + + # Week 1 + + deployment_1 = get_deployment(conducted_at=from_time + timedelta(hours=12)) + deployment_2 = get_deployment(conducted_at=from_time + timedelta(hours=24)) + + # Week 3 + deployment_3 = get_deployment(conducted_at=fourth_week_2024 - timedelta(days=4)) + deployment_4 = get_deployment(conducted_at=fourth_week_2024 - timedelta(days=2)) + deployment_5 = get_deployment(conducted_at=fourth_week_2024 - timedelta(hours=6)) + deployment_6 = get_deployment(conducted_at=fourth_week_2024 - timedelta(minutes=30)) + + deployment_analytics_service = DeploymentAnalyticsService(None, None) + + assert deployment_analytics_service._get_weekly_deployment_frequency_trends( + [ + deployment_1, + deployment_2, + deployment_3, + deployment_4, + deployment_5, + deployment_6, + ], + Interval(from_time, to_time), + ) == { + first_week_2024: 2, + second_week_2024: 0, + third_week_2024: 4, + fourth_week_2024: 0, + }