Added a simple page to show release information parsed from a release's changelog file.

- Legacy-Id: 4958
This commit is contained in:
Henrik Levkowetz 2012-10-25 21:29:53 +00:00
parent 7f42117210
commit bfe0756351
7 changed files with 145 additions and 19 deletions

66
changelog.py Normal file
View 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
View file

1
ietf/release/models.py Normal file
View file

@ -0,0 +1 @@
# This app has no models

16
ietf/release/tests.py Normal file
View 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
View 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))

View 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 %}&larr;&nbsp;<a href="/release/{{entry.prev.version}}/">previous release</a>{% else %}<span style="color: grey">&larr; previous release</span>{% endif %}
|
{% if entry.next %}<a href="/release/{{entry.next.version}}/">next release</a>&nbsp;&rarr;{% else %}<span style="color: grey">next release &rarr;</span>{% endif %}
</p>
<p>
<b>Release Notes:</b>
<tt>
<pre>
{{entry.logentry}}
</pre>
</tt>
</p>
</div>
{% endblock %}

View file

@ -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' }),