def repo_table(scope): # repos, start, end): #this drives the list of all repos within an organization, showing the statistics for them within the selected #time range, along with navigation links. (repos, authors) = scope.standardize_repos_and_authors() interval = 'DY' # FIXME: explain repos = [x.pk for x in scope.available_repos.all()] stats = Statistic.queryset_for_range(repos=repos, authors=authors, start=scope.start, end=scope.end, interval=interval) stats = Statistic.annotate( stats.values('repo__name')).order_by('repo__name') data = _annotations_to_table(stats, 'repo', 'repo__name') # FIXME: insert in author count, which is ... complicated ... this can be optimized later # we should be able to grab every repo and annotate it with the author count in one extra query tops # but it might require manually writing it. for d in data: repo = d['repo'] author_count = Author.author_count(repo, start=scope.start, end=scope.end) d['author_count'] = author_count # some repos won't have been scanned, and this requires a second query to fill them into the table repos = Repository.objects.filter(last_scanned=None, organization=scope.org) for unscanned in repos: data.append(dict(repo=unscanned.name)) return data
def author_stats_table(scope, limit=None): """ this drives the author tables, both ranged and non-ranged, accessed off the main repo list. the interval 'LF' shows lifetime stats, but elsewhere we just do daily roundups, so this parameter should really be a boolean. The limit parameter is not yet used. """ # FIXME: this performs one query PER author and could be rewritten to be a LOT more intelligent. (repos, authors) = scope.standardize_repos_and_authors() interval = 'DY' stats = Statistic.queryset_for_range(repos=repos, authors=authors, start=scope.start, end=scope.end, interval=interval) data = None if not scope.author: stats = Statistic.annotate( stats.values('author__email')).order_by('author__email') data = _annotations_to_table(stats, 'author', 'author__email') else: stats = Statistic.annotate( stats.values('repo__name')).order_by('repo__name') data = _annotations_to_table(stats, 'repo', 'repo__name') return data
def repo_table(scope): # repos, start, end): """ this drives the list of all repos within an organization, showing the statistics for them within the selected time range, along with navigation links. """ results = [] for repo in scope.repos: stats = Statistic.queryset_for_range(repo, author=None, interval='DY', start=scope.start, end=scope.end) stat2 = Statistic.compute_interval_statistic(stats, interval='DY', repo=repo, author=None, start=scope.start, end=scope.end) stat2 = stat2.to_dict() stat2['name'] = repo.name # providing pk's for link columns in the repo chart for x in ['details1', 'details2', 'details3']: stat2[x] = repo.pk results.append(stat2) results = sorted(results, key=lambda x: x['name']) return json.dumps(results)
def compute_interval_rollup(cls, repo=None, author=None, interval=None, start_day=None, total_instances=None): """ Use the daily team stats to generate weekly or monthly rollup stats. start_day is the beginning of that period """ # FIXME: all this code should be cleaned up. # IF in weekly mode, and start_day is this week, we need to delete the current stat # IF in monthly mode, and start_day is this month, we need to delete the current stat assert repo is not None assert interval in [ 'WK', 'MN', 'LF'] (start_day, end_date) = cls.start_and_end_dates_for_interval(repo=repo, author=author, start=start_day, interval=interval) if start_day is None and interval != 'LF': print("**** GLITCH: Author has no commits? ", author) return days = cls._queryset_for_interval_rollup(repo=repo, author=author, interval=interval, start_day=start_day, end_date=end_date) if days.count() == 0: # probably just a merge commit today, be cool about it and skip this one. return stat = Statistic.compute_interval_statistic(days, repo=repo, interval=interval, author=author, start=start_day, end=end_date, for_update=True) cls.smart_bulk_update(repo=repo, start_day=start_day, author=author, interval=interval, stat=stat, total_instances=total_instances)
def compute_daily_rollup(cls, repo=None, author=None, start_day=None, total_instances=None): """ Generate rollup stats for everything the team did on a given day """ end_date = cls.get_end_day(start_day, DAY) file_change_count = FileChange.change_count(repo, author=author, start=start_day, end=end_date) if file_change_count == 0: # this looks like a merge commit, FIXME: it would be a good idea to validate that this is 100% true. # print("-- skipping potential merge commit --") return if not author: authors_count = Author.author_count(repo, start=start_day, end=end_date) else: authors_count = 1 # Aggregate values from query set for rollup data = FileChange.aggregate_stats(repo, author=author, start=start_day, end=end_date) # FIXME: if start_day is today, we need to UPDATE the current stat? - verify if the bulk_update code deals with this? # FIXME: model code method below is rather inefficient, does this matter? # Create total rollup row for the day stat = Statistic( start_date=start_day, interval=DAY, repo=repo, author=author, lines_added=data['lines_added'], lines_removed=data['lines_removed'], lines_changed=data['lines_changed'], commit_total= data['commit_total'], files_changed=data['files_changed'], author_total=authors_count, days_active=1, ) stat.compute_derived_values() cls.smart_bulk_update(repo=repo, start_day=start_day, author=author, interval=DAY, stat=stat, total_instances=total_instances)
def add_stat(author, repo): stat1 = Statistic.queryset_for_range(repo, author=author, start=scope.start, end=scope.end, interval=scope.interval) stat2 = Statistic.compute_interval_statistic(stat1, interval=scope.interval, repo=repo, author=author, start=scope.start, end=scope.end) stat2 = stat2.to_dict() stat2['author'] = author.email stat2['repo'] = repo.name if stat2['lines_changed']: # skip authors with no contribution in the time range results.append(stat2)
def compute_interval_rollup(cls, repo=None, author=None, interval=None, start_day=None, total_instances=None): """ Use the daily team stats to generate weekly or monthly rollup stats. start_day is the beginning of that period """ # IF in weekly mode, and start_day is this week, we need to delete the current stat # IF in monthly mode, and start_day is this month, we need to delete the current stat end_date = cls.get_end_day(start_day, interval) days = None if not author: days = Statistic.objects.filter( author__isnull=True, interval=DAY, repo=repo, start_date__range=(cls.aware(start_day), cls.aware(end_date))) else: days = Statistic.objects.filter( author=author, interval=DAY, repo=repo, start_date__range=(cls.aware(start_day), cls.aware(end_date))) # aggregates total stats for the interval data = days.aggregate(lines_added=Sum("lines_added"), lines_removed=Sum("lines_removed"), lines_changed=Sum("lines_changed"), commit_total=Sum("commit_total"), files_changed=Sum("files_changed"), author_total=Max("author_total")) stat = Statistic(start_date=cls.aware(start_day), interval=interval, repo=repo, author=author, lines_added=data['lines_added'], lines_removed=data['lines_removed'], lines_changed=data['lines_changed'], commit_total=data['commit_total'], files_changed=data['files_changed'], author_total=data['author_total']) cls.smart_bulk_update(repo=repo, start_day=start_day, author=author, interval=interval, stat=stat, total_instances=total_instances)
def compute_daily_rollup(cls, repo=None, author=None, start_day=None, total_instances=None): """ Generate rollup stats for everything the team did on a given day """ file_changes = None if not author: file_changes = FileChange.objects.select_related( 'commit', 'author').filter( commit__commit_date__year=start_day.year, commit__commit_date__month=start_day.month, commit__commit_date__day=start_day.day, ) else: file_changes = FileChange.objects.select_related( 'commit', 'author').filter(commit__commit_date__year=start_day.year, commit__commit_date__month=start_day.month, commit__commit_date__day=start_day.day, commit__author=author) if file_changes.count() == 0: return # FIXME: probably not the most efficient way to do this commits = file_changes.values_list('commit', flat=True).distinct().all() files = file_changes.values_list('file', flat=True).distinct().all() authors = Commit.objects.filter(pk__in=commits).values_list( 'author', flat=True).distinct().all() authors_count = len(authors) # Aggregate values from query set for rollup data = file_changes.aggregate(lines_added=Sum("lines_added"), lines_removed=Sum("lines_removed")) commits_total = len(commits) files_changed = len(files) lines_added = data['lines_added'] lines_removed = data['lines_removed'] lines_changed = lines_added + lines_removed # FIXME: if start_day is today, we need to delete the current stat # Create total rollup row for the day stat = Statistic(start_date=cls.aware(start_day), interval=DAY, repo=repo, author=author, lines_added=lines_added, lines_removed=lines_removed, lines_changed=lines_changed, commit_total=commits_total, files_changed=files_changed, author_total=authors_count) cls.smart_bulk_update(repo=repo, start_day=start_day, author=author, interval=DAY, stat=stat, total_instances=total_instances)