forked from OWASP/Nest
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathowasp_aggregate_member_contributions.py.bak
More file actions
142 lines (115 loc) · 4.52 KB
/
Copy pathowasp_aggregate_member_contributions.py.bak
File metadata and controls
142 lines (115 loc) · 4.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
"""Management command to aggregate user contribution data."""
from datetime import datetime, timedelta
from typing import Any
from django.core.management.base import BaseCommand
from django.db.models import Count
from django.db.models.functions import TruncDate
from django.utils import timezone
from apps.github.models.commit import Commit
from apps.github.models.issue import Issue
from apps.github.models.pull_request import PullRequest
from apps.github.models.user import User
class Command(BaseCommand):
"""Aggregate contribution data for users."""
help = "Aggregate contribution data (commits, PRs, issues) for users"
def add_arguments(self, parser):
"""Add command arguments."""
parser.add_argument(
"--user",
type=str,
help="Specific user login to process",
)
parser.add_argument(
"--days",
type=int,
default=365,
help="Number of days to look back (default: 365)",
)
parser.add_argument(
"--batch-size",
type=int,
default=100,
help="Batch size for processing users (default: 100)",
)
def handle(self, *args: Any, **options: Any) -> None:
"""Handle the command execution."""
user_login = options.get("user")
days = options.get("days", 365)
batch_size = options.get("batch_size", 100)
start_date = timezone.now() - timedelta(days=days)
self.stdout.write(
self.style.SUCCESS(
f"Aggregating contributions since {start_date.date()} ({days} days back)"
)
)
if user_login:
users = User.objects.filter(login=user_login)
if not users.exists():
self.stdout.write(self.style.ERROR(f"Member '{user_login}' not found"))
return
else:
users = User.objects.filter(contributions_count__gt=0)
total_users = users.count()
self.stdout.write(f"Processing {total_users} members...")
updated_users = []
for user in users.iterator(chunk_size=batch_size):
if not (contribution_data := self._aggregate_user_contributions(user, start_date)):
continue
user.contribution_data = contribution_data
updated_users.append(user)
User.bulk_save(updated_users, fields=["contribution_data"])
self.stdout.write(
self.style.SUCCESS(f"Successfully aggregated contributions for {total_users} members")
)
def _aggregate_user_contributions(self, user: User, start_date: datetime) -> dict[str, int]:
"""Aggregate contributions for a user.
Args:
user: User instance
start_date: Start datetime for aggregation
Returns:
Dictionary mapping YYYY-MM-DD to contribution counts
"""
contribution_data = {}
current_date = start_date.date()
end_date = timezone.now().date()
while current_date <= end_date:
date_str = current_date.strftime("%Y-%m-%d")
contribution_data[date_str] = 0
current_date += timedelta(days=1)
commits = (
Commit.objects.filter(
author=user,
created_at__gte=start_date,
)
.annotate(date=TruncDate("created_at"))
.values("date")
.annotate(count=Count("id"))
)
for commit in commits:
date_str = commit["date"].strftime("%Y-%m-%d")
contribution_data[date_str] = contribution_data.get(date_str, 0) + commit["count"]
prs = (
PullRequest.objects.filter(
author=user,
created_at__gte=start_date,
)
.annotate(date=TruncDate("created_at"))
.values("date")
.annotate(count=Count("id"))
)
for pr in prs:
date_str = pr["date"].strftime("%Y-%m-%d")
contribution_data[date_str] = contribution_data.get(date_str, 0) + pr["count"]
issues = (
Issue.objects.filter(
author=user,
created_at__gte=start_date,
)
.annotate(date=TruncDate("created_at"))
.values("date")
.annotate(count=Count("id"))
)
for issue in issues:
date_str = issue["date"].strftime("%Y-%m-%d")
contribution_data[date_str] = contribution_data.get(date_str, 0) + issue["count"]
return contribution_data