Skip to content

Commit bfe0756

Browse files
committed
Added a simple page to show release information parsed from a release's changelog file.
- Legacy-Id: 4958
1 parent 7f42117 commit bfe0756

7 files changed

Lines changed: 145 additions & 19 deletions

File tree

changelog.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import re
2+
from tzparse import tzparse
3+
from datetime import datetime as Datetime
4+
5+
def parse_date(dstr):
6+
formats = [
7+
"%d %b %Y %H:%M:%S %Z", # standard logfile format
8+
"%d %b %Y %H:%M:%S",
9+
"%d %b %Y %H:%M %Z",
10+
"%d %b %Y %H:%M",
11+
"%d %b %Y %Z",
12+
"%Y-%m-%d %H:%M:%S %Z",
13+
"%Y-%m-%d %H:%M:%S",
14+
"%Y-%m-%d_%H:%M:%S %Z",
15+
"%Y-%m-%d_%H:%M:%S",
16+
"%Y-%m-%dT%H:%M:%S%Z",
17+
"%Y-%m-%dT%H:%M:%S",
18+
"%Y-%m-%d %H:%M %Z",
19+
"%Y-%m-%d %H:%M",
20+
"%Y-%m-%d",
21+
]
22+
for format in formats:
23+
try:
24+
t = tzparse(dstr, format)
25+
return t
26+
except Exception:
27+
pass
28+
raise Exception("Couldn't parse the date string '%s'" % dstr)
29+
30+
class ChangeLogEntry:
31+
package = ""
32+
version = ""
33+
logentry = ""
34+
author = ""
35+
email = ""
36+
date = ""
37+
time = ""
38+
39+
def parse(logfile):
40+
ver_line = "^(\w+) \((\S+)\) (\S+;)? (?:urgency=(\S+))?$"
41+
sig_line = "^ -- ([^<]+) <([^>]+)> (.*?) *$"
42+
43+
entries = []
44+
if type(logfile) == type(''):
45+
logfile = open(logfile)
46+
entry = None
47+
for line in logfile:
48+
if re.match(ver_line, line):
49+
package, version, distribution, urgency = re.match(ver_line, line).groups()
50+
entry = ChangeLogEntry()
51+
entry.package = package
52+
entry.version = version
53+
entry.logentry = ""
54+
elif re.match(sig_line, line):
55+
author, email, date = re.match(sig_line, line).groups()
56+
entry.author = author
57+
entry.email = email
58+
entry.date = date
59+
entry.time = parse_date(date)
60+
entry.logentry = entry.logentry.rstrip()
61+
entries += [ entry ]
62+
elif entry:
63+
entry.logentry += line
64+
else:
65+
print "Unexpected line: '%s'" % line
66+
return entries

ietf/release/__init__.py

Whitespace-only changes.

ietf/release/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# This app has no models

ietf/release/tests.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
"""
2+
This file demonstrates writing tests using the unittest module. These will pass
3+
when you run "manage.py test".
4+
5+
Replace this with more appropriate tests for your application.
6+
"""
7+
8+
from django.test import TestCase
9+
10+
11+
class SimpleTest(TestCase):
12+
def test_basic_addition(self):
13+
"""
14+
Tests that 1 + 1 always equals 2.
15+
"""
16+
self.assertEqual(1 + 1, 2)

ietf/release/views.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import re
2+
import os
3+
4+
from django.template import RequestContext
5+
from django.shortcuts import render_to_response
6+
7+
import changelog
8+
9+
def release(request, version=None):
10+
entries = {}
11+
log_entries = changelog.parse("changelog")
12+
next = None
13+
for entry in log_entries:
14+
if next:
15+
next.prev = entry
16+
entry.next = next
17+
next = entry
18+
entries = dict([ (entry.version, entry) for entry in log_entries])
19+
if version == None:
20+
version = log_entries[0].version
21+
return render_to_response('release/release.html', { 'entry': entries[version], }, context_instance=RequestContext(request))
22+
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{% extends "registration/base.html" %}
2+
3+
{% block title %}Release information{% endblock %}
4+
5+
{% block content %}
6+
<div id="release">
7+
<h2>Release {{ entry.version }}, released {{ entry.date }}</h2>
8+
<p style="font-size: 90%">
9+
{% if entry.prev %}&larr;&nbsp;<a href="/release/{{entry.prev.version}}/">previous release</a>{% else %}<span style="color: grey">&larr; previous release</span>{% endif %}
10+
|
11+
{% if entry.next %}<a href="/release/{{entry.next.version}}/">next release</a>&nbsp;&rarr;{% else %}<span style="color: grey">next release &rarr;</span>{% endif %}
12+
</p>
13+
<p>
14+
<b>Release Notes:</b>
15+
<tt>
16+
<pre>
17+
{{entry.logentry}}
18+
</pre>
19+
</tt>
20+
</p>
21+
22+
</div>
23+
{% endblock %}

ietf/urls.py

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -43,33 +43,31 @@
4343
del sitemaps['drafts'] # not needed, overlaps sitemaps['idtracker']
4444

4545
urlpatterns = patterns('',
46-
(r'^feed/(?P<url>.*)/$', 'django.contrib.syndication.views.feed',
47-
{ 'feed_dict': feeds}),
48-
(r'^sitemap.xml$', 'django.contrib.sitemaps.views.index',
49-
{ 'sitemaps': sitemaps}),
50-
(r'^sitemap-(?P<section>.+).xml$', 'django.contrib.sitemaps.views.sitemap',
51-
{'sitemaps': sitemaps}),
46+
(r'^$', 'ietf.idrfc.views.main'),
47+
(r'^accounts/', include('ietf.ietfauth.urls')),
48+
(r'^admin/', include(admin.site.urls)),
49+
(r'^admin/doc/', include('django.contrib.admindocs.urls')),
5250
(r'^ann/', include('ietf.announcements.urls')),
53-
(r'^idtracker/', include('ietf.idtracker.urls')),
51+
(r'^community/', include('ietf.community.urls')),
52+
(r'^cookies/', include('ietf.cookies.urls')),
53+
(r'^doc/', include('ietf.idrfc.urls')),
5454
(r'^drafts/', include('ietf.idindex.urls')),
55+
(r'^feed/(?P<url>.*)/$', 'django.contrib.syndication.views.feed', { 'feed_dict': feeds}),
56+
(r'^idtracker/', include('ietf.idtracker.urls')),
5557
(r'^iesg/', include('ietf.iesg.urls')),
58+
(r'^ipr/', include('ietf.ipr.urls')),
5659
(r'^liaison/', include('ietf.liaisons.urls')),
5760
(r'^list/', include('ietf.mailinglists.urls')),
58-
(r'^(?P<path>public)/', include('ietf.redirects.urls')),
59-
(r'^ipr/', include('ietf.ipr.urls')),
6061
(r'^meeting/', include('ietf.meeting.urls')),
61-
(r'^accounts/', include('ietf.ietfauth.urls')),
62-
(r'^doc/', include('ietf.idrfc.urls')),
63-
(r'^wg/', include('ietf.wginfo.urls')),
64-
(r'^cookies/', include('ietf.cookies.urls')),
6562
(r'^person/', include('ietf.person.urls')),
66-
(r'^submit/', include('ietf.submit.urls')),
63+
(r'^release/$', 'ietf.release.views.release'),
64+
(r'^release/(?P<version>.+)/$', 'ietf.release.views.release'),
65+
(r'^sitemap-(?P<section>.+).xml$', 'django.contrib.sitemaps.views.sitemap', {'sitemaps': sitemaps}),
66+
(r'^sitemap.xml$', 'django.contrib.sitemaps.views.index', { 'sitemaps': sitemaps}),
6767
(r'^streams/', include('ietf.ietfworkflows.urls')),
68-
(r'^community/', include('ietf.community.urls')),
69-
70-
(r'^$', 'ietf.idrfc.views.main'),
71-
(r'^admin/doc/', include('django.contrib.admindocs.urls')),
72-
('^admin/', include(admin.site.urls)),
68+
(r'^submit/', include('ietf.submit.urls')),
69+
(r'^(?P<path>public)/', include('ietf.redirects.urls')),
70+
(r'^wg/', include('ietf.wginfo.urls')),
7371

7472
# Google webmaster tools verification url
7573
(r'^googlea30ad1dacffb5e5b.html', 'django.views.generic.simple.direct_to_template', { 'template': 'googlea30ad1dacffb5e5b.html' }),

0 commit comments

Comments
 (0)