summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Pursehouse <david.pursehouse@sonymobile.com>2013-01-31 13:59:09 +0900
committerPeter Theckanath <peter.xa.theckanath@sonymobile.com>2014-06-19 14:28:58 +0900
commit77e0d7a1d5d10771cdf26b71065b99147b7ad7d5 (patch)
tree9f726418ac182e7bcdb6b1cf7c0fcbefdf7c6884
parent0225ce0abca5de0bee669b64b40d52e3d7cbf927 (diff)
downloadpygerrit-77e0d7a1d5d10771cdf26b71065b99147b7ad7d5.tar.gz
Add message formatter class0.2.7
Add a new helper class that can be used to format the messages that are sent to Gerrit via the review command. Change-Id: Ib8684d60788c8f19054bca6cfc707b25079395d3
-rw-r--r--pygerrit/__init__.py85
-rwxr-xr-xunittests.py112
2 files changed, 197 insertions, 0 deletions
diff --git a/pygerrit/__init__.py b/pygerrit/__init__.py
index 7424b74..d9ce98d 100644
--- a/pygerrit/__init__.py
+++ b/pygerrit/__init__.py
@@ -48,3 +48,88 @@ def escape_string(string):
result = result.replace('\\', '\\\\')
result = result.replace('"', '\\"')
return '"' + result + '"'
+
+
+class GerritReviewMessageFormatter(object):
+
+ """ Helper class to format review messages that are sent to Gerrit. """
+
+ def __init__(self, header=None, footer=None):
+ """ Constructor.
+
+ If `header` is specified, it will be prepended as the first
+ paragraph of the output message. If `footer` is specified it
+ will be appended as the last paragraph of the output message.
+
+ """
+
+ self.paragraphs = []
+ if header:
+ self.header = header.strip()
+ else:
+ self.header = ""
+ if footer:
+ self.footer = footer.strip()
+ else:
+ self.footer = ""
+
+ def append(self, data):
+ """ Append the given `data` to the output.
+
+ If `data` is a list, it is formatted as a bullet list with each
+ entry in the list being a separate bullet. Otherwise if it is a
+ string, the string is added as a paragraph.
+
+ Raises ValueError if `data` is not a list or a string.
+
+ """
+ if not data:
+ return
+
+ if isinstance(data, list):
+ # First we need to clean up the data.
+ #
+ # Gerrit creates new bullet items when it gets newline characters
+ # within a bullet list paragraph, so unless we remove the newlines
+ # from the texts the resulting bullet list will contain multiple
+ # bullets and look crappy.
+ #
+ # We add the '*' character on the beginning of each bullet text in
+ # the next step, so we strip off any existing leading '*' that the
+ # caller has added, and then strip off any leading or trailing
+ # whitespace.
+ _items = [x.replace("\n", " ").strip().lstrip('*').strip()
+ for x in data]
+
+ # Create the bullet list only with the items that still have any
+ # text in them after cleaning up.
+ _paragraph = "\n".join(["* %s" % x for x in _items if x])
+ if _paragraph:
+ self.paragraphs.append(_paragraph)
+ elif isinstance(data, str):
+ _paragraph = data.strip()
+ if _paragraph:
+ self.paragraphs.append(_paragraph)
+ else:
+ raise ValueError('Data must be a list or a string')
+
+ def is_empty(self):
+ """ Return True if no paragraphs have been added. """
+ return not self.paragraphs
+
+ def format(self):
+ """ Format the message parts to a string.
+
+ Return a string of all the message parts separated into paragraphs,
+ with header and footer paragraphs if they were specified in the
+ constructor.
+
+ """
+ message = ""
+ if self.paragraphs:
+ if self.header:
+ message += (self.header + '\n\n')
+ message += "\n\n".join(self.paragraphs)
+ if self.footer:
+ message += ('\n\n' + self.footer)
+ return message
diff --git a/unittests.py b/unittests.py
index b4b3a23..28d985f 100755
--- a/unittests.py
+++ b/unittests.py
@@ -35,6 +35,84 @@ from pygerrit.events import PatchsetCreatedEvent, \
DraftPublishedEvent, GerritEventFactory, GerritEvent, UnhandledEvent, \
ErrorEvent, MergeFailedEvent, ReviewerAddedEvent, TopicChangedEvent
from pygerrit.client import GerritClient
+from pygerrit import GerritReviewMessageFormatter
+
+EXPECTED_TEST_CASE_FIELDS = ['header', 'footer', 'paragraphs', 'result']
+
+
+TEST_CASES = [
+ {'header': None,
+ 'footer': None,
+ 'paragraphs': [],
+ 'result': ""},
+ {'header': "Header",
+ 'footer': "Footer",
+ 'paragraphs': [],
+ 'result': ""},
+ {'header': None,
+ 'footer': None,
+ 'paragraphs': ["Test"],
+ 'result': "Test"},
+ {'header': None,
+ 'footer': None,
+ 'paragraphs': ["Test", "Test"],
+ 'result': "Test\n\nTest"},
+ {'header': "Header",
+ 'footer': None,
+ 'paragraphs': ["Test"],
+ 'result': "Header\n\nTest"},
+ {'header': "Header",
+ 'footer': None,
+ 'paragraphs': ["Test", "Test"],
+ 'result': "Header\n\nTest\n\nTest"},
+ {'header': "Header",
+ 'footer': "Footer",
+ 'paragraphs': ["Test", "Test"],
+ 'result': "Header\n\nTest\n\nTest\n\nFooter"},
+ {'header': "Header",
+ 'footer': "Footer",
+ 'paragraphs': [["One"]],
+ 'result': "Header\n\n* One\n\nFooter"},
+ {'header': "Header",
+ 'footer': "Footer",
+ 'paragraphs': [["One", "Two"]],
+ 'result': "Header\n\n* One\n* Two\n\nFooter"},
+ {'header': "Header",
+ 'footer': "Footer",
+ 'paragraphs': ["Test", ["One"], "Test"],
+ 'result': "Header\n\nTest\n\n* One\n\nTest\n\nFooter"},
+ {'header': "Header",
+ 'footer': "Footer",
+ 'paragraphs': ["Test", ["One", "Two"], "Test"],
+ 'result': "Header\n\nTest\n\n* One\n* Two\n\nTest\n\nFooter"},
+ {'header': "Header",
+ 'footer': "Footer",
+ 'paragraphs': ["Test", "Test", ["One"]],
+ 'result': "Header\n\nTest\n\nTest\n\n* One\n\nFooter"},
+ {'header': None,
+ 'footer': None,
+ 'paragraphs': [["* One", "* Two"]],
+ 'result': "* One\n* Two"},
+ {'header': None,
+ 'footer': None,
+ 'paragraphs': [["* One ", " * Two "]],
+ 'result': "* One\n* Two"},
+ {'header': None,
+ 'footer': None,
+ 'paragraphs': [["*", "*"]],
+ 'result': ""},
+ {'header': None,
+ 'footer': None,
+ 'paragraphs': [["", ""]],
+ 'result': ""},
+ {'header': None,
+ 'footer': None,
+ 'paragraphs': [[" ", " "]],
+ 'result': ""},
+ {'header': None,
+ 'footer': None,
+ 'paragraphs': [["* One", " ", "* Two"]],
+ 'result': "* One\n* Two"}]
@GerritEventFactory.register("user-defined-event")
@@ -315,5 +393,39 @@ class TestGerritEvents(unittest.TestCase):
return
self.fail("Did not raise exception when duplicate event registered")
+
+class TestGerritReviewMessageFormatter(unittest.TestCase):
+
+ """ Test that the GerritReviewMessageFormatter class behaves properly. """
+
+ def _check_test_case_fields(self, test_case, i):
+ for field in EXPECTED_TEST_CASE_FIELDS:
+ self.assertTrue(field in test_case,
+ "field '%s' not present in test case #%d" %
+ (field, i))
+ self.assertTrue(isinstance(test_case['paragraphs'], list),
+ "'paragraphs' field is not a list in test case #%d" % i)
+
+ def test_is_empty(self):
+ """ Test if message is empty for missing header and footer. """
+ f = GerritReviewMessageFormatter(header=None, footer=None)
+ self.assertTrue(f.is_empty())
+ f.append(['test'])
+ self.assertFalse(f.is_empty())
+
+ def test_message_formatting(self):
+ """ Test message formatter for different test cases. """
+ for i in range(len(TEST_CASES)):
+ test_case = TEST_CASES[i]
+ self._check_test_case_fields(test_case, i)
+ f = GerritReviewMessageFormatter(header=test_case['header'],
+ footer=test_case['footer'])
+ for paragraph in test_case['paragraphs']:
+ f.append(paragraph)
+ m = f.format()
+ self.assertEqual(m, test_case['result'],
+ "Formatted message does not match expected "
+ "result in test case #%d:\n[%s]" % (i, m))
+
if __name__ == '__main__':
unittest.main()