Skip to content

Commit

Permalink
Fixed django#1119 -- Used GitHub API for commits stats.
Browse files Browse the repository at this point in the history
  • Loading branch information
felixxm committed Oct 27, 2021
1 parent 471587a commit 8bf11a0
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 2,672 deletions.
Binary file modified dashboard/fixtures/dashboard_example_data.json.gz
Binary file not shown.
12 changes: 6 additions & 6 deletions dashboard/fixtures/dashboard_production_metrics.json
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@
}
},
{
"model": "dashboard.rssfeedmetric",
"model": "dashboard.githubsearchcountmetric",
"pk": 1,
"fields": {
"name": "Commits today",
Expand All @@ -284,12 +284,12 @@
"period": "daily",
"unit": "commit",
"unit_plural": "commits",
"feed_url": "https://code.djangoproject.com/timeline?changeset=on&max=0&daysback=0&format=rss",
"link_url": "https://code.djangoproject.com/timeline?changeset=on&max=0&daysback=0"
"api_url": "https://api.github.com/search/commits",
"link_url": "https://github.com/django/django/commits"
}
},
{
"model": "dashboard.rssfeedmetric",
"model": "dashboard.githubsearchcountmetric",
"pk": 2,
"fields": {
"name": "Commits in the last week",
Expand All @@ -301,8 +301,8 @@
"period": "weekly",
"unit": "commit",
"unit_plural": "commits",
"feed_url": "https://code.djangoproject.com/timeline?changeset=on&max=0&daysback=7&format=rss",
"link_url": "https://code.djangoproject.com/timeline?changeset=on&max=0&daysback=7"
"api_url": "https://api.github.com/search/commits",
"link_url": "https://github.com/django/django/commits"
}
},
{
Expand Down
16 changes: 8 additions & 8 deletions dashboard/fixtures/dashboard_test_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -180,33 +180,33 @@
"category": 1,
"show_on_dashboard": true,
"name": "Commits today",
"feed_url": "https://code.djangoproject.com/timeline?changeset=on&max=0&daysback=0&format=rss",
"link_url": "https://code.djangoproject.com/timeline?changeset=on&max=0&daysback=0",
"api_url": "https://api.github.com/search/commits",
"link_url": "https://github.com/django/django/commits",
"period": "daily",
"show_sparkline": true,
"unit_plural": "commits",
"position": 1,
"position": 2,
"slug": "commits-today",
"unit": "commit"
},
"model": "dashboard.rssfeedmetric",
"model": "dashboard.githubsearchcountmetric",
"pk": 1
},
{
"fields": {
"category": 1,
"show_on_dashboard": true,
"name": "Commits in the last week",
"feed_url": "https://code.djangoproject.com/timeline?changeset=on&max=0&daysback=7&format=rss",
"link_url": "https://code.djangoproject.com/timeline?changeset=on&max=0&daysback=7",
"api_url": "https://api.github.com/search/commits",
"link_url": "https://github.com/django/django/commits",
"period": "weekly",
"show_sparkline": true,
"unit_plural": "commits",
"position": 1,
"position": 4,
"slug": "commits-week",
"unit": "commit"
},
"model": "dashboard.rssfeedmetric",
"model": "dashboard.githubsearchcountmetric",
"pk": 2
},
{
Expand Down
2,626 changes: 0 additions & 2,626 deletions dashboard/fixtures/rss_feed_metric.xml

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Generated by Django 2.2.24 on 2021-10-27 01:33
import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('dashboard', '0001_initial'),
]

operations = [
migrations.CreateModel(
name='GitHubSearchCountMetric',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=300)),
('slug', models.SlugField()),
('position', models.PositiveSmallIntegerField(default=1)),
('show_on_dashboard', models.BooleanField(default=True)),
('show_sparkline', models.BooleanField(default=True)),
('period', models.CharField(choices=[('instant', 'Instant'), ('daily', 'Daily'), ('weekly', 'Weekly')], default='instant', max_length=15)),
('unit', models.CharField(max_length=100)),
('unit_plural', models.CharField(max_length=100)),
('api_url', models.URLField(max_length=1000)),
('link_url', models.URLField(max_length=1000)),
('category', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='dashboard.Category')),
],
options={
'abstract': False,
},
),
migrations.DeleteModel(
name='RSSFeedMetric',
),
]
30 changes: 18 additions & 12 deletions dashboard/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import datetime
import xmlrpc.client

import feedparser
import requests
from django.conf import settings
from django.contrib.contenttypes.fields import (
Expand Down Expand Up @@ -127,17 +126,6 @@ def link(self):
return "%squery?%s&desc=1&order=changetime" % (settings.TRAC_URL, self.query)


class RSSFeedMetric(Metric):
feed_url = models.URLField(max_length=1000)
link_url = models.URLField(max_length=1000)

def fetch(self):
return len(feedparser.parse(requests.get(self.feed_url).text).entries)

def link(self):
return self.link_url


class GithubItemCountMetric(Metric):
"""Example: https://api.github.com/repos/django/django/pulls?state=open"""
api_url = models.URLField(max_length=1000)
Expand Down Expand Up @@ -165,6 +153,24 @@ def link(self):
return self.link_url


class GitHubSearchCountMetric(Metric):
api_url = models.URLField(max_length=1000)
link_url = models.URLField(max_length=1000)

def fetch(self):
"""Request the specified GitHub API and return a total count."""
today = datetime.date.today()
if self.period == METRIC_PERIOD_WEEKLY:
committer_date = '>%s' % (today - datetime.timedelta(weeks=1)).isoformat()
else:
committer_date = today.isoformat()
r = requests.get(
self.api_url + '?per_page=1&q=repo:django/django+committer-date:%s' % committer_date
)
data = r.json()
return data['total_count']


class JenkinsFailuresMetric(Metric):
"""
Track failures of a job/build. Uses the Python flavor of the Jenkins REST
Expand Down
54 changes: 34 additions & 20 deletions dashboard/tests.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import codecs
import datetime
import json
import os
from unittest import mock

import requests_mock
Expand All @@ -10,7 +9,8 @@
from django_hosts.resolvers import reverse

from .models import (
GithubItemCountMetric, Metric, RSSFeedMetric, TracTicketMetric,
METRIC_PERIOD_DAILY, METRIC_PERIOD_WEEKLY, GithubItemCountMetric,
GitHubSearchCountMetric, Metric, TracTicketMetric,
)
from .views import index, metric_detail, metric_json

Expand Down Expand Up @@ -77,23 +77,6 @@ def test_fetch(self, mock_server_proxy):
self.assertTrue(mock_server_proxy.client.query.assert_called_with)


class RSSFeedMetricTestCase(TestCase, MetricMixin):
fixtures = ['dashboard_test_data']
feed_url = 'https://code.djangoproject.com/timeline?changeset=on&max=0&daysback=7&format=rss'
fixtures_path = os.path.join(os.path.dirname(__file__), 'fixtures', 'rss_feed_metric.xml')

def setUp(self):
super().setUp()
self.instance = RSSFeedMetric.objects.last()

@requests_mock.mock()
def test_fetch(self, mocker):
with codecs.open(self.fixtures_path, 'r', 'utf-8') as fixtures:
feed_items = fixtures.read()
mocker.get(self.feed_url, text=feed_items)
self.assertEqual(self.instance.fetch(), 177)


class GithubItemCountMetricTestCase(TestCase, MetricMixin):
fixtures = ['dashboard_test_data']
api_url1 = 'https://api.github.com/repos/django/django/pulls?state=closed&per_page=100&page=1'
Expand All @@ -112,6 +95,37 @@ def test_fetch(self, mocker):
self.assertEqual(self.instance.fetch(), 142)


class GitHubSearchCountMetricTestCase(TestCase, MetricMixin):
fixtures = ['dashboard_test_data']
api_url = (
'https://api.github.com/search/commits?'
'per_page=1&q=repo:django/django+committer-date:%s'
)

def setUp(self):
super().setUp()
self.instance = GitHubSearchCountMetric.objects.last()

@requests_mock.mock()
def test_fetch(self, mocker):
today = datetime.date.today()
week_start = today - datetime.timedelta(weeks=1)
# Faking a daily JSON output with 4 items.
mocker.get(
self.api_url % today.isoformat(),
text=json.dumps({'total_count': 4, 'items': []}),
)
metric = GitHubSearchCountMetric.objects.filter(period=METRIC_PERIOD_DAILY).last()
self.assertEqual(metric.fetch(), 4)
# Faking a weekly JSON output with 23 items.
mocker.get(
self.api_url % '>' + week_start.isoformat(),
text=json.dumps({'total_count': 23, 'items': []}),
)
metric = GitHubSearchCountMetric.objects.filter(period=METRIC_PERIOD_WEEKLY).last()
self.assertEqual(metric.fetch(), 23)


class UpdateMetricCommandTestCase(TestCase):
github_url = 'https://api.github.com/repos/django/django/pulls?state=closed&per_page=100&page=1'

Expand Down

0 comments on commit 8bf11a0

Please sign in to comment.