feat: redirect to release information at github (#3746)
* chore: remove unused import * feat: redirect to release information at github.
This commit is contained in:
parent
32bf50ef1b
commit
79bcc6448e
|
@ -1,4 +1,4 @@
|
|||
# Copyright The IETF Trust 2012-2020, All Rights Reserved
|
||||
# Copyright The IETF Trust 2012-2022, All Rights Reserved
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
|
@ -12,14 +12,6 @@ from ietf.utils.test_utils import TestCase
|
|||
|
||||
class ReleasePagesTest(TestCase):
|
||||
|
||||
def test_release(self):
|
||||
url = reverse('ietf.release.views.release', kwargs={'version':'6.0.0'})
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
releases = [ e.text.strip() for e in q('#content table td a') if e.text ]
|
||||
for num in ["2.00", "3.00", "4.00", "5.0.0"]:
|
||||
self.assertIn(num, releases)
|
||||
|
||||
def test_about(self):
|
||||
url = reverse('ietf.release.views.release')+"about"
|
||||
|
@ -29,17 +21,3 @@ class ReleasePagesTest(TestCase):
|
|||
text = q('#content').text()
|
||||
for word in ["About", "2.00", "3.00", "4.00", "5.0.0"]:
|
||||
self.assertIn(word, text)
|
||||
|
||||
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,16 +1,14 @@
|
|||
# Copyright The IETF Trust 2015-2020, All Rights Reserved
|
||||
# Copyright The IETF Trust 2015-2022, All Rights Reserved
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
from django.views.generic import TemplateView
|
||||
from django.views.generic import RedirectView, TemplateView
|
||||
|
||||
from ietf.release import views
|
||||
from ietf.utils.urls import url
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', views.release),
|
||||
url(r'^(?P<version>[0-9.]+.*)/$', views.release),
|
||||
url(r'^$', RedirectView.as_view(url='https://github.com/ietf-tools/datatracker/releases', permanent=False), name='ietf.release.views.release'),
|
||||
url(r'^(?P<version>[0-9.]+.*)/$', RedirectView.as_view(url='https://github.com/ietf-tools/datatracker/releases/tag/%(version)s', permanent=False)),
|
||||
url(r'^about/?$', TemplateView.as_view(template_name='release/about.html'), name='releaseabout'),
|
||||
url(r'^stats/?$', views.stats),
|
||||
url(r'^stats/?$', RedirectView.as_view(url='https://github.com/ietf-tools/datatracker/releases', permanent=False)),
|
||||
]
|
||||
|
||||
|
|
|
@ -1,156 +0,0 @@
|
|||
# Copyright The IETF Trust 2012-2020, All Rights Reserved
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import io
|
||||
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
|
||||
|
||||
# workaround for thread import lock problem, http://bugs.python.org/issue7980
|
||||
import time
|
||||
time.strptime('1984', '%Y') # we do this to force lib loading, instead of it happening lazily when changelog calls tzparse later
|
||||
|
||||
|
||||
def trac_links(text):
|
||||
# changeset links
|
||||
text = re.sub(r'\[(\d+)\]', r'<a href="https://trac.ietf.org/trac/ietfdb/changeset/\1">[\1]</a>', text)
|
||||
# issue links
|
||||
text = re.sub(r'([^&])#(\d+)', r'\1<a href="https://trac.ietf.org/trac/ietfdb/ticket/\2">#\2</a>', text)
|
||||
return text
|
||||
|
||||
|
||||
def get_coverage_data():
|
||||
cache_key = 'release:get_coverage_data'
|
||||
coverage_data = cache.get(cache_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 io.open(settings.TEST_COVERAGE_MASTER_FILE) as file:
|
||||
coverage_data = json.load(file)
|
||||
cache.set(cache_key, coverage_data, 60*60*24)
|
||||
return coverage_data
|
||||
|
||||
def get_changelog_entries():
|
||||
cache_key = 'release:get_changelog_entries'
|
||||
log_entries = cache.get(cache_key)
|
||||
if not log_entries:
|
||||
if os.path.exists(settings.CHANGELOG_PATH):
|
||||
log_entries = changelog.parse(settings.CHANGELOG_PATH)
|
||||
cache.set(cache_key, log_entries, 60*60*24)
|
||||
return log_entries
|
||||
|
||||
entries = None
|
||||
log_entries = None
|
||||
coverage_data = None
|
||||
def release(request, version=None):
|
||||
global entries, log_entries, coverage_data
|
||||
if not entries:
|
||||
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:
|
||||
if next:
|
||||
next.prev = entry
|
||||
entry.next = next
|
||||
next = entry
|
||||
entries = dict((entry.version, entry) for entry in log_entries)
|
||||
|
||||
if version == None or version not in entries:
|
||||
version = log_entries[0].version
|
||||
if not hasattr(entries[version], 'html'):
|
||||
entries[version].html = trac_links(escape(entries[version].logentry.strip('\n')))
|
||||
|
||||
code_coverage_url = None
|
||||
code_coverage_time = None
|
||||
if os.path.exists(settings.TEST_CODE_COVERAGE_REPORT_FILE) and version == log_entries[0].version:
|
||||
code_coverage_url = settings.TEST_CODE_COVERAGE_REPORT_URL
|
||||
code_coverage_time = datetime.datetime.fromtimestamp(os.path.getmtime(settings.TEST_CODE_COVERAGE_REPORT_FILE))
|
||||
|
||||
coverage = {}
|
||||
if not coverage_data:
|
||||
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',
|
||||
{
|
||||
'releases': log_entries,
|
||||
'version': version,
|
||||
'entry': entries[version],
|
||||
'coverage': coverage,
|
||||
'code_coverage_url': code_coverage_url,
|
||||
'code_coverage_time': code_coverage_time,
|
||||
} )
|
||||
|
||||
|
||||
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 = round(coverage_data[version][coverage_type]['coverage'], 3)
|
||||
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)),
|
||||
})
|
|
@ -1,91 +0,0 @@
|
|||
{# Copyright The IETF Trust 2015, All Rights Reserved #}
|
||||
{% extends "base.html" %}
|
||||
{% load origin textfilters ietf_filters %}
|
||||
{% load cache %}
|
||||
{% block title %}Release information{% endblock %}
|
||||
{% block content %}
|
||||
{% origin %}
|
||||
<div class="row">
|
||||
<h1 class="col-11">
|
||||
<a class="text-reset text-decoration-none"
|
||||
href="https://trac.ietf.org/trac/ietfdb/browser/tags/{{ entry.version }}">
|
||||
Version {{ entry.version }}
|
||||
</a>
|
||||
<br>
|
||||
<small class="text-muted">Released {{ entry.date }}</small>
|
||||
</h1>
|
||||
<div class="col-1 text-end">
|
||||
<a href="{% url "ietf.release.views.stats" %}" class="icon-link">
|
||||
<i class="bi bi-bar-chart-line"></i>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="pagination d-flex py-2">
|
||||
<li class="me-auto page-item {% if not entry.prev %}disabled{% endif %}">
|
||||
<a class="page-link"
|
||||
href="{% if entry.prev %}/release/{{ entry.prev.version }}/{% else %}#{% endif %}">
|
||||
<i class="bi bi-arrow-left"></i> Previous release
|
||||
</a>
|
||||
</li>
|
||||
<li class="page-item {% if not entry.next %}disabled{% endif %}">
|
||||
<a class="page-link"
|
||||
href="{% if entry.next %}/release/{{ entry.next.version }}/{% else %}#{% endif %}">
|
||||
Next release <i class="bi bi-arrow-right"></i>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<p>
|
||||
{% if coverage %}
|
||||
Tested:
|
||||
<b>Code</b>: {{ coverage.code.percentage|stringformat:".2f" }}%,
|
||||
<b>Templates</b>: {{ coverage.template.percentage|stringformat:".2f" }}%,
|
||||
<b>URLs</b>: {{ coverage.url.percentage|stringformat:".2f" }}%
|
||||
{% endif %}
|
||||
{% if code_coverage_url %}
|
||||
(A
|
||||
<a href="{{ code_coverage_url }}">code test coverage report</a>
|
||||
dated {{ code_coverage_time }} is available.)
|
||||
{% endif %}
|
||||
</p>
|
||||
<h2 class="mt-3">{{ entry.version }} release notes</h2>
|
||||
{% if entry.title %}<h3 class="mt-3">{{ entry.title }}</h3>{% endif %}
|
||||
<pre>{{ entry.html|linkify|urlize_ietf_docs }}</pre>
|
||||
<div class="text-muted mt-1 ms-3">— {{ entry.author }} <{{ entry.email|linkify }}> {{ entry.date }}</div>
|
||||
{% cache 3600 ietf_release_list %}
|
||||
<div id="release-list"></div>
|
||||
<h2 class="mt-3">Release list</h2>
|
||||
<table class="table table-striped table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Version</th>
|
||||
<th>Release date</th>
|
||||
<th>Feature summary</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for item in releases %}
|
||||
{% ifchanged %}
|
||||
<tr class="table-info">
|
||||
<th></th>
|
||||
<th class="text-end">{{ item.date|slice:"7:11" }}</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
{% endifchanged %}
|
||||
<tr>
|
||||
<td class="text-end">
|
||||
<a href="/release/{{ item.version }}/">{{ item.version }}</a>
|
||||
</td>
|
||||
<td class="text-end">{{ item.date|slice:":11" }}</td>
|
||||
<td>{{ item.title|linkify|urlize_ietf_docs }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endcache %}
|
||||
{% endblock %}
|
||||
{% block footer %}
|
||||
<p class="text-center">
|
||||
<a href="https://trac.ietf.org/trac/ietfdb/wiki/ContractorInstructions">Contractor instructions</a>
|
||||
</p>
|
||||
{{ block.super }}
|
||||
{% endblock %}
|
|
@ -1,117 +0,0 @@
|
|||
{# Copyright The IETF Trust 2017, All Rights Reserved #}
|
||||
{% extends "base.html" %}
|
||||
{% load origin %}
|
||||
{% load ietf_filters static django_bootstrap5 %}
|
||||
{% 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 'ietf/js/highcharts-highcharts.js' %}"></script>
|
||||
<script src="{% static 'ietf/js/highcharts-exporting.js' %}"></script>
|
||||
<script src="{% static 'ietf/js/highcharts-offline-exporting.js' %}"></script>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
Highcharts.chart('coverage-chart', window.coverageChartConf);
|
||||
Highcharts.chart('frequency-chart', window.frequencyChartConf);
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
|
@ -5,7 +5,6 @@
|
|||
import io
|
||||
import os.path
|
||||
import shutil
|
||||
import sys
|
||||
import types
|
||||
|
||||
from pyquery import PyQuery
|
||||
|
|
Loading…
Reference in a new issue