+
+
+
diff --git a/lib/release_helper/tt/index.tt b/lib/release_helper/tt/index.tt
new file mode 100644
index 0000000..dff5142
--- /dev/null
+++ b/lib/release_helper/tt/index.tt
@@ -0,0 +1,111 @@
+
+
+
+
+
[% project %] release
+
+[% INCLUDE 'css.tt' %]
+
+
+
+
+
+
+
+
+
+
+
+
Select a release to view backlog
+
+
+
+
+
+
+
+[% FOREACH milestone IN milestones %]
+
+
+[% i_closed = 0; i_open = 0; m_due = 'never'; %]
+[% FOREACH repo IN data.$milestone.pairs %]
+[%- things = repo.value.things;
+ IF things.size == 0;
+ NEXT;
+ END;
+ i_closed = i_closed + repo.value.closed;
+ i_open = i_open + repo.value.open;
+ IF repo.value.defined('due');
+ m_due = repo.value.due;
+ END; %]
+
+ [% repo.key %] |
+
+
+[% FOREACH this IN things.sort('title').reverse() %]
+ -
+
+ [% this.title %]
+[% IF this.comment_count > 0 %]
+ [% this.comment_count %]
+[% END %]
+
+ Created by
+ [% this.user %]
+
+ [% this.created %]
+
+[% IF this.defined('assignee') %]
+ , Assigned to
+ [% this.assignee %]
+[% END %]
+ , Updated [% this.updated %]
+
+
+[% END %]
+
+ |
+
+[% END -%]
+
+
+[% IF i_open + i_closed > 0 -%]
+
+[% END -%]
+
+
+[% END -%]
+
+
Page generated [% now %]
+
+
+
+
+
+
+
+
diff --git a/lib/release_helper/tt/js_reldate.tt b/lib/release_helper/tt/js_reldate.tt
new file mode 100644
index 0000000..dd23484
--- /dev/null
+++ b/lib/release_helper/tt/js_reldate.tt
@@ -0,0 +1,5 @@
+ $(function() {
+ $('.reldate').each(function(index) {
+ $(this).text(moment.tz($(this).text(), "YYYY-MM-DDTHH:mm:ss", "UTC").fromNow());
+ });
+ });
diff --git a/lib/release_helper/tt/quattor_releasenotes.tt b/lib/release_helper/tt/quattor_releasenotes.tt
new file mode 100644
index 0000000..fb1e910
--- /dev/null
+++ b/lib/release_helper/tt/quattor_releasenotes.tt
@@ -0,0 +1,36 @@
+---
+layout: article
+title: [% project %] [% milestone %] released
+category: news
+author: James Adams
+---
+
+Packages are available from our [yum repository](http://yum.quattor.org/[% milestone %]/),
+both the RPMs and the repository metadata are signed with
+[my GPG key](http://yum.quattor.org/GPG/RPM-GPG-KEY-quattor-jrha).
+
+As always, many thanks to everyone who contributed!
+We merged [% count_pulls %] pull requests and resolved [% count_issues %] issues.
+
+The next release should be [% next_milestone %],
+take a look at the [backlog](http://www.quattor.org/release/) to see what we're working on.
+
+[% IF backwards.defined() -%]
+Backwards Incompatible Changes
+------------------------------
+[% FOREACH repo IN backwards.pairs %]
+### [% repo.key %]
+[% FOREACH pr IN repo.value -%]
+* [[% pr.title.replace('^([^:]+): ', '**$1:** ') %]](https://github.com/quattor/[% repo.key %]/pull/[% pr.number %])
+[% END -%]
+[% END %]
+[%- END -%]
+
+Changelog
+---------
+[% FOREACH repo IN pulls.pairs %]
+### [% repo.key %]
+[% FOREACH pr IN repo.value -%]
+* [[% pr.title.replace('^([^:]+): ', '**$1:** ') %]](https://github.com/quattor/[% repo.key %]/pull/[% pr.number %])
+[% END -%]
+[% END %]
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..e3165d0
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,34 @@
+#!/usr/bin/env python
+
+import glob
+from setuptools import setup
+
+
+SETUP = {
+ 'name': 'release-helper',
+ 'version': '0.1.0',
+ 'author': 'James Adams',
+ 'author_email': 'james.adams@stfc.ac.uk',
+ 'license': 'APL',
+ 'packages' : ['release_helper'],
+ 'package_dir': {'': 'lib'},
+ 'scripts': glob.glob('bin/*.py') + glob.glob('bin/*.sh'),
+ 'install_requires': [
+ 'PyGithub',
+ 'Template-Python', # python TT port
+ # For tests
+ #'mock',
+ #'prospector',
+ ],
+ 'test_suite': 'test',
+ 'data_files': [
+ # Look for better location
+ ('release_helper/data', glob.glob('data/*html') + glob.glob('data/*example') + glob.glob('data/*/js')),
+ ('release_helper/tt', glob.glob('lib/release_helper/tt/*.tt')),
+ ('release_helper/javascript', glob.glob('lib/release_helper/javascript/*.js')),
+ ],
+ 'zip_safe': False, # shipped TT files
+}
+
+if __name__ == '__main__':
+ setup(**SETUP)
diff --git a/test/__init__.py b/test/__init__.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/test/__init__.py
@@ -0,0 +1 @@
+
diff --git a/test/config.py b/test/config.py
new file mode 100644
index 0000000..e4f2c34
--- /dev/null
+++ b/test/config.py
@@ -0,0 +1,69 @@
+import datetime
+import os
+import unittest
+import release_helper.config as cfg
+
+
+# mock.patch really isn't made for this
+class Repo(object):
+ def __init__(self, name):
+ self.name = name
+
+class GHU(object):
+ def __init__(self, org, ghargs):
+ self.org = org
+ self.ghargs = ghargs
+
+ def get_repos(self):
+ if self.ghargs.get('base_url', None) is None:
+ ts = ['repoxyz', 'repoabc']
+ else:
+ ts = ['repopublic', 'reposecret']
+ return map(Repo, ts)
+
+GHCALLED = []
+class GH(object):
+ def __init__(self, **kwargs):
+ GHCALLED.append(kwargs)
+
+ def get_user(self, user):
+ return GHU(user, GHCALLED[-1])
+
+ def get_organization(self, org):
+ return GHU(org, GHCALLED[-1])
+
+
+# monkey patch Github
+cfg.Github = GH
+
+class UtilsTest(unittest.TestCase):
+
+ def setUp(self):
+ global GHCALLED
+ GHCALLED = []
+
+ def test_make_config(self):
+
+ fn = os.path.join(os.path.dirname(__file__), 'data', 'test1.cfg')
+
+ config = cfg.make_config([fn])
+
+ self.assertEqual(GHCALLED, [{'login_or_token': 'example1', 'password': '1234567890'},
+ {'password': 'abcdef123456', 'login_or_token': 'localuser', 'base_url': 'https://enterprise.example.com/some/subtree/v3/'}])
+ self.assertEqual(sorted(config.keys()), ['labels', 'project', 'releases', 'repos'])
+
+ self.assertEqual(config['labels'], {'bug': 'ef2929', 'question': '123456'})
+ self.assertEqual(config['project'], 'mytest')
+ self.assertEqual(config['releases'], {
+ "14.10" : {
+ "start" : datetime.datetime(2014, 9, 1, 0, 0),
+ "rcs" : datetime.datetime(2014, 10, 27, 0, 0),
+ "target" : datetime.datetime(2014, 11, 1, 0, 0),
+ },
+ "15.2" : {
+ "start" : datetime.datetime(2014, 11, 14, 0, 0),
+ "rcs" : datetime.datetime(2015, 3, 7, 0, 0),
+ "target" : datetime.datetime(2015, 3, 20, 0, 0),
+ },
+ })
+ self.assertEqual([r.name for r in config['repos']], ['repoabc', 'repopublic'])
diff --git a/test/data/index.html b/test/data/index.html
new file mode 100644
index 0000000..2dcd7c6
--- /dev/null
+++ b/test/data/index.html
@@ -0,0 +1,462 @@
+
+
+
+
+
myproject release
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Select a release to view backlog
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CAF |
+
+
+ |
+
+
+
+ CCM |
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ CAF |
+
+
+ |
+
+
+
+ CCM |
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ CAF |
+
+
+
+ -
+
+ CAF::Download
+
+
+ Created by
+ stdweird
+
+ 2014-10-26T16:07:41
+
+
+ , Updated 2016-05-05T15:07:03
+
+
+
+
+ |
+
+
+
+ CCM |
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+ CAF |
+
+
+ |
+
+
+
+ CCM |
+
+
+ |
+
+
+
+
+
+
+
+
+
Page generated 1970-01-02 03:04:05
+
+
+
+
+
+
+
+
diff --git a/test/data/quattor-pulls.json b/test/data/quattor-pulls.json
new file mode 100644
index 0000000..f542e2b
--- /dev/null
+++ b/test/data/quattor-pulls.json
@@ -0,0 +1,267 @@
+{
+ "16.6": {
+ "CCM": {
+ "things": [
+ {
+ "updated": "2016-07-08T13:01:15",
+ "labels": [],
+ "number": 111,
+ "user": "stdweird",
+ "icon": "git-pull-request",
+ "title": "ProfileCache: Lock use reporter instance for reporting",
+ "url": "https://github.com/quattor/CCM/pull/111",
+ "created": "2016-07-07T12:43:29",
+ "comment_count": 0,
+ "state": "closed",
+ "closed": "2016-07-08T13:01:15",
+ "type": "pull-request"
+ },
+ {
+ "updated": "2016-05-17T16:33:26",
+ "labels": [],
+ "number": 101,
+ "user": "stdweird",
+ "icon": "git-pull-request",
+ "title": "CCM: fetchProfile should close all CAF::File* instances ",
+ "url": "https://github.com/quattor/CCM/pull/101",
+ "created": "2016-05-16T08:56:38",
+ "comment_count": 4,
+ "state": "closed",
+ "closed": "2016-05-17T16:33:26",
+ "type": "pull-request"
+ },
+ {
+ "updated": "2016-05-09T10:06:41",
+ "labels": [],
+ "number": 99,
+ "user": "stdweird",
+ "icon": "git-pull-request",
+ "title": "bump build-tools to 1.49",
+ "url": "https://github.com/quattor/CCM/pull/99",
+ "created": "2016-05-09T09:40:08",
+ "comment_count": 1,
+ "state": "closed",
+ "closed": "2016-05-09T10:06:41",
+ "type": "pull-request"
+ }
+ ],
+ "open": 0,
+ "due": "2016-06-30T07:00:00",
+ "closed": 11
+ },
+ "CAF": {
+ "things": [
+ {
+ "updated": "2016-07-07T10:02:43",
+ "labels": [],
+ "number": 174,
+ "user": "jouvin",
+ "icon": "git-pull-request",
+ "title": "Add PyCharm and Eclipse files to gitignore",
+ "url": "https://github.com/quattor/CAF/pull/174",
+ "created": "2016-07-07T09:49:05",
+ "comment_count": 0,
+ "state": "closed",
+ "closed": "2016-07-07T10:02:43",
+ "type": "pull-request"
+ },
+ {
+ "updated": "2016-07-08T13:26:38",
+ "labels": [
+ "discuss at workshop",
+ "backwards incompatible"
+ ],
+ "number": 173,
+ "user": "stdweird",
+ "icon": "git-pull-request",
+ "title": "Lock: handle existing old-style locks",
+ "url": "https://github.com/quattor/CAF/pull/173",
+ "created": "2016-07-06T15:54:55",
+ "comment_count": 16,
+ "state": "closed",
+ "closed": "2016-07-08T12:57:56",
+ "type": "pull-request",
+ "backwards_incompatible": true,
+ "to_discuss": true
+ },
+ {
+ "updated": "2016-07-08T12:57:56",
+ "labels": [],
+ "number": 172,
+ "user": "stdweird",
+ "icon": "issue-closed",
+ "title": "Lock not compatible with old lock",
+ "url": "https://github.com/quattor/CAF/issues/172",
+ "created": "2016-07-06T13:41:53",
+ "comment_count": 0,
+ "state": "closed",
+ "closed": "2016-07-08T12:57:56",
+ "type": "issue"
+ }
+ ],
+ "open": 0,
+ "due": "2016-06-30T07:00:00",
+ "closed": 25
+ }
+ },
+ "Legacy": {
+ "CCM": {
+ "things": [],
+ "open": 0,
+ "due": null,
+ "closed": 0
+ },
+ "CAF": {
+ "things": [
+ {
+ "updated": "2016-07-06T09:33:14",
+ "labels": [
+ "bug",
+ "discuss at workshop"
+ ],
+ "number": 148,
+ "user": "ttyS4",
+ "icon": "issue-opened",
+ "title": "CAF::FileWriter updates files in-place",
+ "url": "https://github.com/quattor/CAF/issues/148",
+ "created": "2016-04-11T13:03:16",
+ "comment_count": 11,
+ "state": "open",
+ "type": "issue",
+ "to_discuss": true
+ }
+ ],
+ "open": 0,
+ "due": null,
+ "closed": 0
+ }
+ },
+ "16.10": {
+ "CCM": {
+ "things": [
+ {
+ "updated": "2016-06-05T09:55:39",
+ "labels": [],
+ "number": 107,
+ "user": "stdweird",
+ "icon": "issue-opened",
+ "title": "remove CCM::Property class",
+ "url": "https://github.com/quattor/CCM/issues/107",
+ "created": "2016-06-05T09:52:08",
+ "comment_count": 1,
+ "state": "open",
+ "type": "issue"
+ }
+ ],
+ "open": 1,
+ "due": "2016-10-31T07:00:00",
+ "closed": 0
+ },
+ "CAF": {
+ "things": [
+ {
+ "updated": "2016-05-05T15:07:03",
+ "labels": [],
+ "number": 62,
+ "user": "stdweird",
+ "icon": "issue-opened",
+ "title": "CAF::Download",
+ "url": "https://github.com/quattor/CAF/issues/62",
+ "created": "2014-10-26T16:07:41",
+ "comment_count": 0,
+ "state": "open",
+ "type": "issue"
+ }
+ ],
+ "open": 1,
+ "due": "2016-10-31T07:00:00",
+ "closed": 0
+ }
+ },
+ "Backlog": {
+ "CCM": {
+ "things": [
+ {
+ "updated": "2016-07-08T15:25:10",
+ "labels": [],
+ "number": 112,
+ "user": "msmark",
+ "icon": "issue-opened",
+ "title": "ccm-fetch to support downloading test profiles",
+ "url": "https://github.com/quattor/CCM/issues/112",
+ "created": "2016-07-08T15:19:36",
+ "comment_count": 2,
+ "state": "open",
+ "type": "issue"
+ }
+ ],
+ "open": 0,
+ "due": null,
+ "closed": 0
+ },
+ "CAF": {
+ "things": [
+ {
+ "updated": "2016-06-03T12:16:39",
+ "labels": [
+ "bug"
+ ],
+ "number": 167,
+ "user": "ned21",
+ "icon": "issue-opened",
+ "title": "CAF::Process, $? and NoAction",
+ "url": "https://github.com/quattor/CAF/issues/167",
+ "created": "2016-06-02T20:41:26",
+ "comment_count": 1,
+ "state": "open",
+ "type": "issue"
+ }
+ ],
+ "open": 0,
+ "due": null,
+ "closed": 0
+ }
+ },
+ "16.8": {
+ "CCM": {
+ "things": [
+ {
+ "updated": "2016-06-08T11:48:26",
+ "labels": [],
+ "number": 109,
+ "user": "stdweird",
+ "icon": "issue-opened",
+ "title": "ugly exception during initial installation",
+ "url": "https://github.com/quattor/CCM/issues/109",
+ "created": "2016-06-08T11:48:26",
+ "comment_count": 0,
+ "state": "open",
+ "type": "issue"
+ }
+ ],
+ "open": 7,
+ "due": "2016-08-30T07:00:00",
+ "closed": 0
+ },
+ "CAF": {
+ "things": [
+ {
+ "updated": "2016-06-04T13:13:01",
+ "labels": [],
+ "number": 169,
+ "user": "stdweird",
+ "icon": "issue-opened",
+ "title": "CAF::FileWriter support mtime",
+ "url": "https://github.com/quattor/CAF/issues/169",
+ "created": "2016-06-04T13:13:01",
+ "comment_count": 0,
+ "state": "open",
+ "type": "issue"
+ }
+ ],
+ "open": 7,
+ "due": "2016-08-30T07:00:00",
+ "closed": 0
+ }
+ }
+}
diff --git a/test/data/release_notes.md b/test/data/release_notes.md
new file mode 100644
index 0000000..a7bb7b5
--- /dev/null
+++ b/test/data/release_notes.md
@@ -0,0 +1,35 @@
+---
+layout: article
+title: myproject 16.6 released
+category: news
+author: James Adams
+---
+
+Packages are available from our [yum repository](http://yum.quattor.org/16.6/),
+both the RPMs and the repository metadata are signed with
+[my GPG key](http://yum.quattor.org/GPG/RPM-GPG-KEY-quattor-jrha).
+
+As always, many thanks to everyone who contributed!
+We merged 5 pull requests and resolved 1 issues.
+
+The next release should be 16.8,
+take a look at the [backlog](http://www.quattor.org/release/) to see what we're working on.
+
+Backwards Incompatible Changes
+------------------------------
+
+### CAF
+* [**Lock:** handle existing old-style locks](https://github.com/quattor/CAF/pull/173)
+
+Changelog
+---------
+
+### CAF
+* [Add PyCharm and Eclipse files to gitignore](https://github.com/quattor/CAF/pull/174)
+* [**Lock:** handle existing old-style locks](https://github.com/quattor/CAF/pull/173)
+
+### CCM
+* [**CCM:** fetchProfile should close all CAF::File* instances ](https://github.com/quattor/CCM/pull/101)
+* [**ProfileCache:** Lock use reporter instance for reporting](https://github.com/quattor/CCM/pull/111)
+* [bump build-tools to 1.49](https://github.com/quattor/CCM/pull/99)
+
diff --git a/test/data/test1.cfg b/test/data/test1.cfg
new file mode 100644
index 0000000..511d1a6
--- /dev/null
+++ b/test/data/test1.cfg
@@ -0,0 +1,24 @@
+[main]
+github=github,enterprise
+project=mytest
+
+[releases]
+14.10=2014-09-01,2014-10-27,2014-11-01
+15.2=2014-11-14,2015-03-07,2015-03-20
+
+[labels]
+bug=ef2929
+question=123456
+
+[github]
+username=example1
+token=1234567890
+organisation=pubteam
+white=abc
+
+[enterprise]
+api=https://enterprise.example.com/some/subtree/v3/
+username=localuser
+token=abcdef123456
+organisation=myteam
+black=secret
diff --git a/test/data/to_discuss.html b/test/data/to_discuss.html
new file mode 100644
index 0000000..056b392
--- /dev/null
+++ b/test/data/to_discuss.html
@@ -0,0 +1,97 @@
+
+
+
+
+
myproject to discuss
+
+
+
+
+
+
+
+
+
+
+
+
To be discussed at the next workshop
+
+
+
+
+
+ CAF |
+
+
+ |
+
+
+
+
+
+
+
+
+
diff --git a/test/lint.py b/test/lint.py
new file mode 100644
index 0000000..8ca4856
--- /dev/null
+++ b/test/lint.py
@@ -0,0 +1,75 @@
+from prospector.run import Prospector
+from prospector.config import ProspectorConfig
+import os
+import pprint
+import re
+import sys
+import unittest
+
+class UtilsTest(unittest.TestCase):
+ # List of regexps patterns applied to code or message of a prospector.message.Message
+ # Blacklist: if match, skip message, do not check whitelist
+ # Whitelist: if match, fail test
+ PROSPECTOR_BLACKLIST = [
+ ]
+ PROSPECTOR_WHITELIST = [
+ 'undefined',
+ 'no-value-for-parameter',
+ 'dangerous-default-value',
+ 'redefined-builtin',
+ 'bare-except',
+ 'E713', # not 'c' in d: -> 'c' not in d:
+ 'arguments-differ',
+ 'unused-argument',
+ 'unused-variable',
+ 'reimported',
+ 'F811', # redefinition of unused name
+ 'unused-import',
+ 'syntax-error',
+ ]
+
+ # Prospector commandline options (positional path is added automatically)
+ PROSPECTOR_OPTIONS = [
+ '--strictness', 'medium',
+ '--max-line-length', '120',
+ '--absolute-paths',
+ ]
+
+ def test_prospector(self):
+
+ if os.environ.get('NO_PROSPECTOR', '0') in ('1', 'y', 'yes'):
+ self.assertTrue(True, msg='Skipping prospector test')
+ return
+
+ sys.argv = ['release-helper-prospector']
+
+ # extra options needed
+ sys.argv.extend(self.PROSPECTOR_OPTIONS)
+ # add/set repository path as basepath
+ sys.argv.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
+
+ config = ProspectorConfig()
+ prospector = Prospector(config)
+
+ prospector.execute()
+
+ blacklist = map(re.compile, self.PROSPECTOR_BLACKLIST)
+ whitelist = map(re.compile, self.PROSPECTOR_WHITELIST)
+
+ failures = []
+ for msg in prospector.get_messages():
+ # example msg.as_dict():
+ # {'source': 'pylint', 'message': 'Missing function docstring', 'code': 'missing-docstring',
+ # 'location': {'function': 'TestHeaders.test_check_header.lgpl', 'path': u'headers.py',
+ # 'line': 122, 'character': 8, 'module': 'headers'}}
+
+ if any([bool(reg.search(msg.code) or reg.search(msg.message)) for reg in blacklist]):
+ continue
+
+ if any([bool(reg.search(msg.code) or reg.search(msg.message)) for reg in whitelist]):
+ failures.append(msg.as_dict())
+
+ self.assertFalse(failures, "prospector failures: %s" % pprint.pformat(failures))
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/test/render.py b/test/render.py
new file mode 100644
index 0000000..c7d6868
--- /dev/null
+++ b/test/render.py
@@ -0,0 +1,77 @@
+import datetime
+import os
+import unittest
+import release_helper.render
+from release_helper.render import render, index_discuss, release_notes
+from mock import patch
+
+ORIG_INCLUDE = release_helper.render.INCLUDEPATH
+
+class UtilsTest(unittest.TestCase):
+ def test_render(self):
+ """
+ Test simple rendering example
+ """
+
+ # Monkey patch the inlcude path for testing
+ release_helper.render.INCLUDEPATH = os.path.join(os.path.dirname(__file__), 'tt')
+
+ txt = render('hello', {'world': 'trivial test'})
+
+ # restore it
+ release_helper.render.INCLUDEPATH = ORIG_INCLUDE
+
+ self.assertEqual(txt, "Hello trivial test.\n", msg="Trivial test result: %s" % txt)
+
+
+ @patch('release_helper.render.datetime')
+ def test_index(self, mocked_datetime):
+ """
+ Test rendering index using TT
+ """
+ mocked_datetime.utcnow.return_value=datetime.datetime(1970, 1, 2, 3, 4, 5, 6)
+
+ self.maxDiff = None
+ self.longMessage = True
+
+ fn = os.path.join(os.path.dirname(__file__), 'data', 'index.html')
+ res_i = open(fn).read()
+
+ fn = os.path.join(os.path.dirname(__file__), 'data', 'to_discuss.html')
+ res_d = open(fn).read()
+
+ json_filename = os.path.join(os.path.dirname(__file__), 'data', 'quattor-pulls.json')
+
+ index, discuss = index_discuss('myproject', json_filename)
+
+ # Uncomment to update the rendered test/data/index.html once considered ok
+ # Do not forget to comment it again
+ #open('/tmp/testrenderindex.html', 'w').write(index)
+ #open('/tmp/testrenderdiscuss.html', 'w').write(discuss)
+
+ self.assertMultiLineEqual(index, res_i)
+ self.assertMultiLineEqual(discuss, res_d)
+
+
+ @patch('release_helper.render.datetime')
+ def test_releasenotes(self, mocked_datetime):
+ """
+ Test rendering index using TT
+ """
+ mocked_datetime.utcnow.return_value=datetime.datetime(1970, 1, 2, 3, 4, 5, 6)
+
+ self.maxDiff = None
+ self.longMessage = True
+
+ fn = os.path.join(os.path.dirname(__file__), 'data', 'release_notes.md')
+ res = open(fn).read()
+
+ json_filename = os.path.join(os.path.dirname(__file__), 'data', 'quattor-pulls.json')
+
+ md = release_notes('myproject', json_filename, '16.6', 'quattor_releasenotes')
+
+ # Uncomment to update the rendered test/data/index.html once considered ok
+ # Do not forget to comment it again
+ #open('/tmp/testrelease_notes.md', 'w').write(md)
+
+ self.assertMultiLineEqual(md, res)
diff --git a/test/tt/hello.tt b/test/tt/hello.tt
new file mode 100644
index 0000000..db894b1
--- /dev/null
+++ b/test/tt/hello.tt
@@ -0,0 +1 @@
+Hello [% world %].