Added charts for test coverage and release frequency.
- Legacy-Id: 13232
This commit is contained in:
parent
d6b9392f72
commit
e6c41879ac
|
@ -1,3 +1,7 @@
|
|||
# Copyright The IETF Trust 2016, All Rights Reserved
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals, print_function
|
||||
|
||||
from pyquery import PyQuery
|
||||
|
||||
from django.urls import reverse
|
||||
|
@ -32,4 +36,17 @@ class ReleasePagesTest(TestCase):
|
|||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
def test_stats(self):
|
||||
url = reverse('ietf.release.views.stats')
|
||||
|
||||
r = self.client.get(url)
|
||||
q = PyQuery(r.content)
|
||||
# grab the script element text, split off the json data
|
||||
s = q('#coverage-data').text()
|
||||
self.assertIn("type: 'line',", s)
|
||||
self.assertIn('"data": [[1426018457000, ', s)
|
||||
|
||||
s = q('#frequency-data').text()
|
||||
self.assertIn("type: 'column',", s)
|
||||
self.assertIn('"data": [[2007, 7], ', s)
|
||||
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
# Copyright The IETF Trust 2016, All Rights Reserved
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals, print_function
|
||||
|
||||
from django.views.generic import TemplateView
|
||||
|
||||
from ietf.release import views
|
||||
|
@ -7,6 +11,7 @@ urlpatterns = [
|
|||
url(r'^$', views.release),
|
||||
url(r'^(?P<version>[0-9.]+.*)/$', views.release),
|
||||
url(r'^about/?$', TemplateView.as_view(template_name='release/about.html')),
|
||||
url(r'^stats/?$', views.stats),
|
||||
url(r'^todo/?$', TemplateView.as_view(template_name='release/todo.html')),
|
||||
]
|
||||
|
||||
|
|
|
@ -1,13 +1,21 @@
|
|||
# Copyright The IETF Trust 2016, All Rights Reserved
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals, print_function
|
||||
|
||||
import os
|
||||
import re
|
||||
import json
|
||||
import datetime
|
||||
import gzip
|
||||
from tzparse import tzparse
|
||||
from calendar import timegm
|
||||
|
||||
from django.shortcuts import render
|
||||
from django.conf import settings
|
||||
from django.core.cache import cache
|
||||
from django.http import HttpResponse
|
||||
from django.utils.html import escape
|
||||
from django.utils.safestring import mark_safe
|
||||
|
||||
import changelog
|
||||
import debug # pyflakes:ignore
|
||||
|
@ -16,6 +24,8 @@ import debug # pyflakes:ignore
|
|||
import time
|
||||
time.strptime('1984', '%Y') # we do this to force lib loading, instead of it happening lazily when changelog calls tzparse later
|
||||
|
||||
import ietf
|
||||
|
||||
def trac_links(text):
|
||||
# changeset links
|
||||
text = re.sub(r'\[(\d+)\]', r'<a href="https://wiki.tools.ietf.org/tools/ietfdb/changeset/\1">[\1]</a>', text)
|
||||
|
@ -24,11 +34,34 @@ def trac_links(text):
|
|||
return text
|
||||
|
||||
|
||||
def get_coverage_data():
|
||||
key = 'ietf:release:get_coverage_data:%s' % ietf.__version__
|
||||
coverage_data = cache.get(key)
|
||||
if not coverage_data:
|
||||
coverage_data = {}
|
||||
if os.path.exists(settings.TEST_COVERAGE_MASTER_FILE):
|
||||
if settings.TEST_COVERAGE_MASTER_FILE.endswith(".gz"):
|
||||
with gzip.open(settings.TEST_COVERAGE_MASTER_FILE, "rb") as file:
|
||||
coverage_data = json.load(file)
|
||||
else:
|
||||
with open(settings.TEST_COVERAGE_MASTER_FILE) as file:
|
||||
coverage_data = json.load(file)
|
||||
cache.set(key, coverage_data, 60*60*24)
|
||||
return coverage_data
|
||||
|
||||
def get_changelog_entries():
|
||||
key = 'ietf:release:get_changelog_entries:%s' % ietf.__version__
|
||||
log_entries = cache.get(key)
|
||||
if not log_entries:
|
||||
if os.path.exists(settings.CHANGELOG_PATH):
|
||||
log_entries = changelog.parse(settings.CHANGELOG_PATH)
|
||||
cache.set(key, log_entries, 60*60*24)
|
||||
return log_entries
|
||||
|
||||
def release(request, version=None):
|
||||
entries = {}
|
||||
if os.path.exists(settings.CHANGELOG_PATH):
|
||||
log_entries = changelog.parse(settings.CHANGELOG_PATH)
|
||||
else:
|
||||
log_entries = get_changelog_entries()
|
||||
if not log_entries:
|
||||
return HttpResponse("Error: changelog file %s not found" % settings.CHANGELOG_PATH)
|
||||
next = None
|
||||
for entry in log_entries:
|
||||
|
@ -48,18 +81,12 @@ def release(request, version=None):
|
|||
code_coverage_time = datetime.datetime.fromtimestamp(os.path.getmtime(settings.TEST_CODE_COVERAGE_REPORT_FILE))
|
||||
|
||||
coverage = {}
|
||||
if os.path.exists(settings.TEST_COVERAGE_MASTER_FILE):
|
||||
if settings.TEST_COVERAGE_MASTER_FILE.endswith(".gz"):
|
||||
with gzip.open(settings.TEST_COVERAGE_MASTER_FILE, "rb") as file:
|
||||
coverage_data = json.load(file)
|
||||
else:
|
||||
with open(settings.TEST_COVERAGE_MASTER_FILE) as file:
|
||||
coverage_data = json.load(file)
|
||||
if version in coverage_data:
|
||||
coverage = coverage_data[version]
|
||||
for key in coverage:
|
||||
if "coverage" in coverage[key]:
|
||||
coverage[key]["percentage"] = coverage[key]["coverage"] * 100
|
||||
coverage_data = get_coverage_data()
|
||||
if version in coverage_data:
|
||||
coverage = coverage_data[version]
|
||||
for key in coverage:
|
||||
if "coverage" in coverage[key]:
|
||||
coverage[key]["percentage"] = coverage[key]["coverage"] * 100
|
||||
|
||||
return render(request, 'release/release.html',
|
||||
{
|
||||
|
@ -72,4 +99,51 @@ def release(request, version=None):
|
|||
} )
|
||||
|
||||
|
||||
|
||||
def stats(request):
|
||||
|
||||
coverage_chart_data = []
|
||||
frequency_chart_data = []
|
||||
|
||||
coverage_data = get_coverage_data()
|
||||
coverage_series_data = {}
|
||||
for version in coverage_data:
|
||||
if 'time' in coverage_data[version]:
|
||||
t = coverage_data[version]['time']
|
||||
secs = timegm(tzparse(t, "%Y-%m-%dT%H:%M:%SZ").timetuple()) * 1000
|
||||
for coverage_type in coverage_data[version]:
|
||||
if 'coverage' in coverage_data[version][coverage_type]:
|
||||
cov = coverage_data[version][coverage_type]['coverage']
|
||||
if not coverage_type in coverage_series_data:
|
||||
coverage_series_data[coverage_type] = []
|
||||
coverage_series_data[coverage_type].append([secs, cov])
|
||||
|
||||
for coverage_type in coverage_series_data:
|
||||
coverage_series_data[coverage_type].sort()
|
||||
# skip some early values
|
||||
coverage_series_data[coverage_type] = coverage_series_data[coverage_type][2:]
|
||||
coverage_chart_data.append({
|
||||
'data': coverage_series_data[coverage_type],
|
||||
'name': coverage_type,
|
||||
})
|
||||
|
||||
log_entries = get_changelog_entries()
|
||||
frequency = {}
|
||||
frequency_series_data = []
|
||||
for entry in log_entries:
|
||||
year = entry.time.year
|
||||
if not year in frequency:
|
||||
frequency[year] = 0
|
||||
frequency[year] += 1
|
||||
for year in frequency:
|
||||
frequency_series_data.append([year, frequency[year]])
|
||||
frequency_series_data.sort()
|
||||
frequency_chart_data.append({
|
||||
'data': frequency_series_data,
|
||||
'name': 'Releases',
|
||||
})
|
||||
|
||||
return render(request, 'release/stats.html',
|
||||
{
|
||||
'coverage_chart_data': mark_safe(json.dumps(coverage_chart_data)),
|
||||
'frequency_chart_data': mark_safe(json.dumps(frequency_chart_data)),
|
||||
})
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
<a href="https://trac.tools.ietf.org/tools/ietfdb/browser/tags/{{entry.version}}">
|
||||
Version {{ entry.version }}</a>
|
||||
<br><small>Released {{ entry.date }}</small>
|
||||
<div class="pull-right"><a href="{% url "ietf.release.views.stats" %}" class="icon-link"> <span class="small fa fa-bar-chart"> </span></a></div>
|
||||
</h1>
|
||||
|
||||
<ul class="pager">
|
||||
|
|
135
ietf/templates/release/stats.html
Normal file
135
ietf/templates/release/stats.html
Normal file
|
@ -0,0 +1,135 @@
|
|||
{# Copyright The IETF Trust 2017, All Rights Reserved #}
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% load origin %}
|
||||
|
||||
{% load ietf_filters staticfiles bootstrap3 %}
|
||||
|
||||
{% block title %}Release Statistics{% endblock %}
|
||||
|
||||
{% block pagehead %}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% origin %}
|
||||
|
||||
<h1>Release Statistics</h1>
|
||||
|
||||
<!-- ------------------------------------------------------------------------ -->
|
||||
|
||||
<div id="coverage-chart">
|
||||
</div>
|
||||
|
||||
<script id="coverage-data">
|
||||
var coverageChartConf = {
|
||||
chart: {
|
||||
type: 'line',
|
||||
},
|
||||
credits: {
|
||||
enabled: false
|
||||
},
|
||||
exporting: {
|
||||
fallbackToExportServer: false
|
||||
},
|
||||
legend: {
|
||||
align: "right",
|
||||
verticalAlign: "middle",
|
||||
layout: "vertical",
|
||||
enabled: true
|
||||
},
|
||||
plotOptions: {
|
||||
line: {
|
||||
marker: {
|
||||
enabled: false
|
||||
},
|
||||
animation: false
|
||||
}
|
||||
},
|
||||
title: {
|
||||
text: 'Test coverage'
|
||||
},
|
||||
xAxis: {
|
||||
type: 'datetime',
|
||||
title: {
|
||||
text: 'Release date'
|
||||
},
|
||||
},
|
||||
units: [
|
||||
[ 'day', [1]],
|
||||
[ 'week', [1]],
|
||||
[ 'month', [1, 3, 6]],
|
||||
[ 'year', null ]
|
||||
],
|
||||
yAxis: {
|
||||
min: 0,
|
||||
title: {
|
||||
text: 'Test coverage'
|
||||
},
|
||||
labels: {
|
||||
formatter: function() {
|
||||
return this.value*100+"%";
|
||||
}
|
||||
}
|
||||
},
|
||||
series: {{ coverage_chart_data }}
|
||||
};
|
||||
</script>
|
||||
|
||||
<div id="frequency-chart">
|
||||
</div>
|
||||
|
||||
<script id="frequency-data">
|
||||
var frequencyChartConf = {
|
||||
chart: {
|
||||
type: 'column',
|
||||
},
|
||||
credits: {
|
||||
enabled: false
|
||||
},
|
||||
exporting: {
|
||||
fallbackToExportServer: false
|
||||
},
|
||||
legend: {
|
||||
align: "right",
|
||||
verticalAlign: "middle",
|
||||
layout: "vertical",
|
||||
enabled: true
|
||||
},
|
||||
plotOptions: {
|
||||
column: {
|
||||
animation: false
|
||||
}
|
||||
},
|
||||
title: {
|
||||
text: 'Releases per year'
|
||||
},
|
||||
xAxis: {
|
||||
type: 'category',
|
||||
title: {
|
||||
text: 'Year'
|
||||
},
|
||||
},
|
||||
yAxis: {
|
||||
min: 0,
|
||||
title: {
|
||||
text: 'Number of releases'
|
||||
}
|
||||
},
|
||||
series: {{ frequency_chart_data }}
|
||||
};
|
||||
</script>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
<script src="{% static 'highcharts/highcharts.js' %}"></script>
|
||||
<script src="{% static 'highcharts/modules/exporting.js' %}"></script>
|
||||
<script src="{% static 'highcharts/modules/offline-exporting.js' %}"></script>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
Highcharts.chart('coverage-chart', window.coverageChartConf);
|
||||
Highcharts.chart('frequency-chart', window.frequencyChartConf);
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
Loading…
Reference in a new issue