Added a simple page to show release information parsed from a release's changelog file.
- Legacy-Id: 4958
This commit is contained in:
parent
7f42117210
commit
bfe0756351
66
changelog.py
Normal file
66
changelog.py
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
import re
|
||||||
|
from tzparse import tzparse
|
||||||
|
from datetime import datetime as Datetime
|
||||||
|
|
||||||
|
def parse_date(dstr):
|
||||||
|
formats = [
|
||||||
|
"%d %b %Y %H:%M:%S %Z", # standard logfile format
|
||||||
|
"%d %b %Y %H:%M:%S",
|
||||||
|
"%d %b %Y %H:%M %Z",
|
||||||
|
"%d %b %Y %H:%M",
|
||||||
|
"%d %b %Y %Z",
|
||||||
|
"%Y-%m-%d %H:%M:%S %Z",
|
||||||
|
"%Y-%m-%d %H:%M:%S",
|
||||||
|
"%Y-%m-%d_%H:%M:%S %Z",
|
||||||
|
"%Y-%m-%d_%H:%M:%S",
|
||||||
|
"%Y-%m-%dT%H:%M:%S%Z",
|
||||||
|
"%Y-%m-%dT%H:%M:%S",
|
||||||
|
"%Y-%m-%d %H:%M %Z",
|
||||||
|
"%Y-%m-%d %H:%M",
|
||||||
|
"%Y-%m-%d",
|
||||||
|
]
|
||||||
|
for format in formats:
|
||||||
|
try:
|
||||||
|
t = tzparse(dstr, format)
|
||||||
|
return t
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
raise Exception("Couldn't parse the date string '%s'" % dstr)
|
||||||
|
|
||||||
|
class ChangeLogEntry:
|
||||||
|
package = ""
|
||||||
|
version = ""
|
||||||
|
logentry = ""
|
||||||
|
author = ""
|
||||||
|
email = ""
|
||||||
|
date = ""
|
||||||
|
time = ""
|
||||||
|
|
||||||
|
def parse(logfile):
|
||||||
|
ver_line = "^(\w+) \((\S+)\) (\S+;)? (?:urgency=(\S+))?$"
|
||||||
|
sig_line = "^ -- ([^<]+) <([^>]+)> (.*?) *$"
|
||||||
|
|
||||||
|
entries = []
|
||||||
|
if type(logfile) == type(''):
|
||||||
|
logfile = open(logfile)
|
||||||
|
entry = None
|
||||||
|
for line in logfile:
|
||||||
|
if re.match(ver_line, line):
|
||||||
|
package, version, distribution, urgency = re.match(ver_line, line).groups()
|
||||||
|
entry = ChangeLogEntry()
|
||||||
|
entry.package = package
|
||||||
|
entry.version = version
|
||||||
|
entry.logentry = ""
|
||||||
|
elif re.match(sig_line, line):
|
||||||
|
author, email, date = re.match(sig_line, line).groups()
|
||||||
|
entry.author = author
|
||||||
|
entry.email = email
|
||||||
|
entry.date = date
|
||||||
|
entry.time = parse_date(date)
|
||||||
|
entry.logentry = entry.logentry.rstrip()
|
||||||
|
entries += [ entry ]
|
||||||
|
elif entry:
|
||||||
|
entry.logentry += line
|
||||||
|
else:
|
||||||
|
print "Unexpected line: '%s'" % line
|
||||||
|
return entries
|
0
ietf/release/__init__.py
Normal file
0
ietf/release/__init__.py
Normal file
1
ietf/release/models.py
Normal file
1
ietf/release/models.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
# This app has no models
|
16
ietf/release/tests.py
Normal file
16
ietf/release/tests.py
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
"""
|
||||||
|
This file demonstrates writing tests using the unittest module. These will pass
|
||||||
|
when you run "manage.py test".
|
||||||
|
|
||||||
|
Replace this with more appropriate tests for your application.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
|
||||||
|
class SimpleTest(TestCase):
|
||||||
|
def test_basic_addition(self):
|
||||||
|
"""
|
||||||
|
Tests that 1 + 1 always equals 2.
|
||||||
|
"""
|
||||||
|
self.assertEqual(1 + 1, 2)
|
22
ietf/release/views.py
Normal file
22
ietf/release/views.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.template import RequestContext
|
||||||
|
from django.shortcuts import render_to_response
|
||||||
|
|
||||||
|
import changelog
|
||||||
|
|
||||||
|
def release(request, version=None):
|
||||||
|
entries = {}
|
||||||
|
log_entries = changelog.parse("changelog")
|
||||||
|
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:
|
||||||
|
version = log_entries[0].version
|
||||||
|
return render_to_response('release/release.html', { 'entry': entries[version], }, context_instance=RequestContext(request))
|
||||||
|
|
23
ietf/templates/release/release.html
Normal file
23
ietf/templates/release/release.html
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{% extends "registration/base.html" %}
|
||||||
|
|
||||||
|
{% block title %}Release information{% endblock %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div id="release">
|
||||||
|
<h2>Release {{ entry.version }}, released {{ entry.date }}</h2>
|
||||||
|
<p style="font-size: 90%">
|
||||||
|
{% if entry.prev %}← <a href="/release/{{entry.prev.version}}/">previous release</a>{% else %}<span style="color: grey">← previous release</span>{% endif %}
|
||||||
|
|
|
||||||
|
{% if entry.next %}<a href="/release/{{entry.next.version}}/">next release</a> →{% else %}<span style="color: grey">next release →</span>{% endif %}
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
<b>Release Notes:</b>
|
||||||
|
<tt>
|
||||||
|
<pre>
|
||||||
|
{{entry.logentry}}
|
||||||
|
</pre>
|
||||||
|
</tt>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
36
ietf/urls.py
36
ietf/urls.py
|
@ -43,33 +43,31 @@ if settings.USE_DB_REDESIGN_PROXY_CLASSES:
|
||||||
del sitemaps['drafts'] # not needed, overlaps sitemaps['idtracker']
|
del sitemaps['drafts'] # not needed, overlaps sitemaps['idtracker']
|
||||||
|
|
||||||
urlpatterns = patterns('',
|
urlpatterns = patterns('',
|
||||||
(r'^feed/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
|
(r'^$', 'ietf.idrfc.views.main'),
|
||||||
{ 'feed_dict': feeds}),
|
(r'^accounts/', include('ietf.ietfauth.urls')),
|
||||||
(r'^sitemap.xml$', 'django.contrib.sitemaps.views.index',
|
(r'^admin/', include(admin.site.urls)),
|
||||||
{ 'sitemaps': sitemaps}),
|
(r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
||||||
(r'^sitemap-(?P<section>.+).xml$', 'django.contrib.sitemaps.views.sitemap',
|
|
||||||
{'sitemaps': sitemaps}),
|
|
||||||
(r'^ann/', include('ietf.announcements.urls')),
|
(r'^ann/', include('ietf.announcements.urls')),
|
||||||
(r'^idtracker/', include('ietf.idtracker.urls')),
|
(r'^community/', include('ietf.community.urls')),
|
||||||
|
(r'^cookies/', include('ietf.cookies.urls')),
|
||||||
|
(r'^doc/', include('ietf.idrfc.urls')),
|
||||||
(r'^drafts/', include('ietf.idindex.urls')),
|
(r'^drafts/', include('ietf.idindex.urls')),
|
||||||
|
(r'^feed/(?P<url>.*)/$', 'django.contrib.syndication.views.feed', { 'feed_dict': feeds}),
|
||||||
|
(r'^idtracker/', include('ietf.idtracker.urls')),
|
||||||
(r'^iesg/', include('ietf.iesg.urls')),
|
(r'^iesg/', include('ietf.iesg.urls')),
|
||||||
|
(r'^ipr/', include('ietf.ipr.urls')),
|
||||||
(r'^liaison/', include('ietf.liaisons.urls')),
|
(r'^liaison/', include('ietf.liaisons.urls')),
|
||||||
(r'^list/', include('ietf.mailinglists.urls')),
|
(r'^list/', include('ietf.mailinglists.urls')),
|
||||||
(r'^(?P<path>public)/', include('ietf.redirects.urls')),
|
|
||||||
(r'^ipr/', include('ietf.ipr.urls')),
|
|
||||||
(r'^meeting/', include('ietf.meeting.urls')),
|
(r'^meeting/', include('ietf.meeting.urls')),
|
||||||
(r'^accounts/', include('ietf.ietfauth.urls')),
|
|
||||||
(r'^doc/', include('ietf.idrfc.urls')),
|
|
||||||
(r'^wg/', include('ietf.wginfo.urls')),
|
|
||||||
(r'^cookies/', include('ietf.cookies.urls')),
|
|
||||||
(r'^person/', include('ietf.person.urls')),
|
(r'^person/', include('ietf.person.urls')),
|
||||||
(r'^submit/', include('ietf.submit.urls')),
|
(r'^release/$', 'ietf.release.views.release'),
|
||||||
|
(r'^release/(?P<version>.+)/$', 'ietf.release.views.release'),
|
||||||
|
(r'^sitemap-(?P<section>.+).xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps}),
|
||||||
|
(r'^sitemap.xml$', 'django.contrib.sitemaps.views.index', { 'sitemaps': sitemaps}),
|
||||||
(r'^streams/', include('ietf.ietfworkflows.urls')),
|
(r'^streams/', include('ietf.ietfworkflows.urls')),
|
||||||
(r'^community/', include('ietf.community.urls')),
|
(r'^submit/', include('ietf.submit.urls')),
|
||||||
|
(r'^(?P<path>public)/', include('ietf.redirects.urls')),
|
||||||
(r'^$', 'ietf.idrfc.views.main'),
|
(r'^wg/', include('ietf.wginfo.urls')),
|
||||||
(r'^admin/doc/', include('django.contrib.admindocs.urls')),
|
|
||||||
('^admin/', include(admin.site.urls)),
|
|
||||||
|
|
||||||
# Google webmaster tools verification url
|
# Google webmaster tools verification url
|
||||||
(r'^googlea30ad1dacffb5e5b.html', 'django.views.generic.simple.direct_to_template', { 'template': 'googlea30ad1dacffb5e5b.html' }),
|
(r'^googlea30ad1dacffb5e5b.html', 'django.views.generic.simple.direct_to_template', { 'template': 'googlea30ad1dacffb5e5b.html' }),
|
||||||
|
|
Loading…
Reference in a new issue