You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by jo...@apache.org on 2013/08/17 00:21:37 UTC
[01/16] git commit: [#6506] Added TracWikiImporter to
requirements-sf.txt
Updated Branches:
refs/heads/cj/6464 7474e6e55 -> d1ac784ee (forced update)
[#6506] Added TracWikiImporter to requirements-sf.txt
Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/2b0a101f
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/2b0a101f
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/2b0a101f
Branch: refs/heads/cj/6464
Commit: 2b0a101f0a7a581fbde2fbc03441bcbcb3e616b1
Parents: 3e67aa6
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Fri Aug 16 14:46:34 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri Aug 16 14:46:34 2013 +0000
----------------------------------------------------------------------
requirements-sf.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/2b0a101f/requirements-sf.txt
----------------------------------------------------------------------
diff --git a/requirements-sf.txt b/requirements-sf.txt
index 6d006ec..cc66c69 100644
--- a/requirements-sf.txt
+++ b/requirements-sf.txt
@@ -20,7 +20,7 @@ wsgipreload==1.2
pyzmq==2.1.7
html2text==3.200.3dev-20121112
PyMollom==0.1
-TracWikiImporter=0.1.0
+TracWikiImporter==0.1.0
# use version built from https://github.com/johnsca/GitPython/commits/tv/6000
# for unmerged fixes for [#5411], [#6000], and [#6078]
[03/16] git commit: [#6464] Added tests for GC tracker attachments
and comments
Posted by jo...@apache.org.
[#6464] Added tests for GC tracker attachments and comments
Signed-off-by: Cory Johns <cj...@slashdotmedia.com>
Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/ea2fc78b
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/ea2fc78b
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/ea2fc78b
Branch: refs/heads/cj/6464
Commit: ea2fc78b88b4c52fa184daff35d367a07d33971a
Parents: 79d9493
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Fri Aug 9 16:25:01 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Fri Aug 16 22:20:59 2013 +0000
----------------------------------------------------------------------
.../forgeimporters/google/__init__.py | 10 +++-
.../tests/data/google/test-issue.html | 38 +++++++++++++
.../tests/google/test_extractor.py | 60 ++++++++++++++++++++
.../forgeimporters/tests/google/test_tracker.py | 4 +-
4 files changed, 107 insertions(+), 5 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ea2fc78b/ForgeImporters/forgeimporters/google/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/__init__.py b/ForgeImporters/forgeimporters/google/__init__.py
index d06a500..88a1449 100644
--- a/ForgeImporters/forgeimporters/google/__init__.py
+++ b/ForgeImporters/forgeimporters/google/__init__.py
@@ -192,8 +192,12 @@ class GoogleCodeProjectExtractor(ProjectExtractor):
return self.page.find(id='hc0').find('span', 'date').get('title')
def get_issue_mod_date(self):
- last_update = Comment(self.page.findAll('div', 'issuecomment')[-1])
- return last_update.created_date
+ comments = self.page.findAll('div', 'issuecomment')
+ if comments:
+ last_update = Comment(comments[-1])
+ return last_update.created_date
+ else:
+ return self.get_issue_created_date()
def get_issue_creator(self):
a = self.page.find(id='hc0').find('a', 'userlink')
@@ -237,7 +241,7 @@ class Comment(object):
def __init__(self, tag):
self.author = UserLink(tag.find('span', 'author').find('a', 'userlink'))
self.created_date = tag.find('span', 'date').get('title')
- self.body = _as_text(tag.find('pre'))
+ self.body = _as_text(tag.find('pre')).strip()
self._get_updates(tag)
self._get_attachments(tag)
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ea2fc78b/ForgeImporters/forgeimporters/tests/data/google/test-issue.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/data/google/test-issue.html b/ForgeImporters/forgeimporters/tests/data/google/test-issue.html
index 04667ac..dbef54e 100644
--- a/ForgeImporters/forgeimporters/tests/data/google/test-issue.html
+++ b/ForgeImporters/forgeimporters/tests/data/google/test-issue.html
@@ -282,6 +282,44 @@ That's all
</pre>
+<div class="attachments">
+<table cellspacing="3" cellpadding="2" border="0">
+<tr><td width="20">
+<a href="//allura-google-importer.googlecode.com/issues/attachment?aid=70000000&name=at1.txt&token=3REU1M3JUUMt0rJUg7ldcELt6LA%3A1376059941255">
+<img width="15" height="15" src="http://www.gstatic.com/codesite/ph/images/paperclip.gif" border="0" />
+</a>
+</td>
+<td style="min-width:16em" valign="top">
+<b>at1.txt</b>
+<br />
+ 13 bytes
+
+
+ <a href="../../allura-google-importer/issues/attachmentText?id=7&aid=70000000&name=at1.txt&token=3REU1M3JUUMt0rJUg7ldcELt6LA%3A1376059941255" target="_blank">View</a>
+
+ <a href="//allura-google-importer.googlecode.com/issues/attachment?aid=70000000&name=at1.txt&token=3REU1M3JUUMt0rJUg7ldcELt6LA%3A1376059941255">Download</a>
+</td>
+</tr>
+</table>
+<table cellspacing="3" cellpadding="2" border="0">
+<tr><td width="20">
+<a href="//allura-google-importer.googlecode.com/issues/attachment?aid=70000001&name=at2.txt&token=C9Hn4s1-g38hlSggRGo65VZM1ys%3A1376059941255">
+<img width="15" height="15" src="http://www.gstatic.com/codesite/ph/images/paperclip.gif" border="0" />
+</a>
+</td>
+<td style="min-width:16em" valign="top">
+<b>at2.txt</b>
+<br />
+ 13 bytes
+
+
+ <a href="../../allura-google-importer/issues/attachmentText?id=7&aid=70000001&name=at2.txt&token=C9Hn4s1-g38hlSggRGo65VZM1ys%3A1376059941255" target="_blank">View</a>
+
+ <a href="//allura-google-importer.googlecode.com/issues/attachment?aid=70000001&name=at2.txt&token=C9Hn4s1-g38hlSggRGo65VZM1ys%3A1376059941255">Download</a>
+</td>
+</tr>
+</table>
+</div>
</div>
<div class="cursor_off vt issuecomment" id="hc1">
<div style="float:right; margin-right:.3em; text-align:right">
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ea2fc78b/ForgeImporters/forgeimporters/tests/google/test_extractor.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/test_extractor.py b/ForgeImporters/forgeimporters/tests/google/test_extractor.py
index 14333aa..bac1750 100644
--- a/ForgeImporters/forgeimporters/tests/google/test_extractor.py
+++ b/ForgeImporters/forgeimporters/tests/google/test_extractor.py
@@ -140,6 +140,7 @@ class TestGoogleCodeProjectExtractor(TestCase):
self.assertEqual(gpe.get_issue_status(), '')
self.assertEqual(gpe.get_issue_attachments(), [])
self.assertEqual(list(gpe.iter_comments()), [])
+ self.assertEqual(gpe.get_issue_mod_date(), 'Thu Aug 8 14:56:23 2013')
def test_get_issue_basic_fields(self):
test_issue = open(pkg_resources.resource_filename('forgeimporters', 'tests/data/google/test-issue.html')).read()
@@ -189,3 +190,62 @@ class TestGoogleCodeProjectExtractor(TestCase):
'OpSys-Windows',
'OpSys-OSX',
])
+
+ def test_get_issue_attachments(self):
+ test_issue = open(pkg_resources.resource_filename('forgeimporters', 'tests/data/google/test-issue.html')).read()
+ gpe = self._make_extractor(test_issue)
+ attachments = gpe.get_issue_attachments()
+ self.assertEqual(len(attachments), 2)
+ self.assertEqual(attachments[0].filename, 'at1.txt')
+ self.assertEqual(attachments[0].url, 'http://allura-google-importer.googlecode.com/issues/attachment?aid=70000000&name=at1.txt&token=3REU1M3JUUMt0rJUg7ldcELt6LA%3A1376059941255')
+ self.assertIsNone(attachments[0].type)
+ self.assertEqual(attachments[1].filename, 'at2.txt')
+ self.assertEqual(attachments[1].url, 'http://allura-google-importer.googlecode.com/issues/attachment?aid=70000001&name=at2.txt&token=C9Hn4s1-g38hlSggRGo65VZM1ys%3A1376059941255')
+ self.assertIsNone(attachments[1].type)
+
+ def test_iter_comments(self):
+ test_issue = open(pkg_resources.resource_filename('forgeimporters', 'tests/data/google/test-issue.html')).read()
+ gpe = self._make_extractor(test_issue)
+ comments = list(gpe.iter_comments())
+ self.assertEqual(len(comments), 4)
+ expected = [
+ {
+ 'author.name': 'john...@gmail.com',
+ 'author.link': 'http://code.google.com/u/101557263855536553789/',
+ 'created_date': 'Thu Aug 8 15:35:15 2013',
+ 'body': 'Test *comment* is a comment',
+ 'updates': {'Status:': 'Started', 'Labels:': '-OpSys-Linux OpSys-Windows'},
+ 'attachments': ['at2.txt'],
+ },
+ {
+ 'author.name': 'john...@gmail.com',
+ 'author.link': 'http://code.google.com/u/101557263855536553789/',
+ 'created_date': 'Thu Aug 8 15:35:34 2013',
+ 'body': 'Another comment',
+ 'updates': {},
+ 'attachments': [],
+ },
+ {
+ 'author.name': 'john...@gmail.com',
+ 'author.link': 'http://code.google.com/u/101557263855536553789/',
+ 'created_date': 'Thu Aug 8 15:36:39 2013',
+ 'body': 'Last comment',
+ 'updates': {},
+ 'attachments': ['at4.txt', 'at1.txt'],
+ },
+ {
+ 'author.name': 'john...@gmail.com',
+ 'author.link': 'http://code.google.com/u/101557263855536553789/',
+ 'created_date': 'Thu Aug 8 15:36:57 2013',
+ 'body': 'Oh, I forgot one',
+ 'updates': {'Labels:': 'OpSys-OSX'},
+ 'attachments': [],
+ },
+ ]
+ for actual, expected in zip(comments, expected):
+ self.assertEqual(actual.author.name, expected['author.name'])
+ self.assertEqual(actual.author.link, expected['author.link'])
+ self.assertEqual(actual.created_date, expected['created_date'])
+ self.assertEqual(actual.body, expected['body'])
+ self.assertEqual(actual.updates, expected['updates'])
+ self.assertEqual([a.filename for a in actual.attachments], expected['attachments'])
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ea2fc78b/ForgeImporters/forgeimporters/tests/google/test_tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/test_tracker.py b/ForgeImporters/forgeimporters/tests/google/test_tracker.py
index 62493bd..a1f0a28 100644
--- a/ForgeImporters/forgeimporters/tests/google/test_tracker.py
+++ b/ForgeImporters/forgeimporters/tests/google/test_tracker.py
@@ -116,7 +116,7 @@ class TestTrackerImporter(TestCase):
return u
issue = mock.Mock(
get_issue_summary=lambda:'summary',
- get_issue_description=lambda:'description',
+ get_issue_description=lambda:'my *description* fool',
get_issue_status=lambda:'status',
get_issue_created_date=lambda:'created_date',
get_issue_mod_date=lambda:'mod_date',
@@ -128,7 +128,7 @@ class TestTrackerImporter(TestCase):
dt.strptime.side_effect = lambda s,f: s
importer.process_fields(ticket, issue)
self.assertEqual(ticket.summary, 'summary')
- self.assertEqual(ticket.description, '*Originally created by:* [cname](clink)\n*Originally owned by:* [oname](olink)\n\ndescription')
+ self.assertEqual(ticket.description, '*Originally created by:* [cname](clink)\n*Originally owned by:* [oname](olink)\n\nmy \*description\* fool')
self.assertEqual(ticket.status, 'status')
self.assertEqual(ticket.created_date, 'created_date')
self.assertEqual(ticket.mod_date, 'mod_date')
[11/16] git commit: [#6464] Fixed issues from rebase
Posted by jo...@apache.org.
[#6464] Fixed issues from rebase
Signed-off-by: Cory Johns <cj...@slashdotmedia.com>
Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/3c9bc576
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/3c9bc576
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/3c9bc576
Branch: refs/heads/cj/6464
Commit: 3c9bc576cfee85d43b73ef8d6b9892d010ec72f0
Parents: 38c8c8e
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Fri Aug 16 02:06:33 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Fri Aug 16 22:21:00 2013 +0000
----------------------------------------------------------------------
Allura/allura/lib/helpers.py | 3 +++
Allura/allura/tests/test_helpers.py | 9 +++++----
ForgeImporters/forgeimporters/google/__init__.py | 4 ++--
.../tests/google/functional/test_tracker.py | 14 ++++++++------
4 files changed, 18 insertions(+), 12 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3c9bc576/Allura/allura/lib/helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index 01586c2..39bf250 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -956,6 +956,9 @@ def plain2markdown(text, preserve_multiple_spaces=False, has_html_entities=False
if preserve_multiple_spaces:
text = text.replace('\t', ' ' * 4)
text = re_preserve_spaces.sub(' ', text)
+ else:
+ text = re_leading_spaces.sub('', text)
+ try:
# try to use html2text for most of the escaping
import html2text
html2text.BODY_WIDTH = 0
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3c9bc576/Allura/allura/tests/test_helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_helpers.py b/Allura/allura/tests/test_helpers.py
index 03a530c..4a0b80d 100644
--- a/Allura/allura/tests/test_helpers.py
+++ b/Allura/allura/tests/test_helpers.py
@@ -292,17 +292,18 @@ M & Ms - doesn't get escaped
http://blah.com/?x=y&a=b - not escaped either
'''
- assert_equals(h.plain2markdown(text), expected)
+ dd.assert_equal(h.plain2markdown(text), expected)
- assert_equals(h.plain2markdown('a foo bar\n\n code here?', preserve_multiple_spaces=True),
+ dd.assert_equal(h.plain2markdown('a foo bar\n\n code here?', preserve_multiple_spaces=True),
'a foo bar\n\n code here?')
- assert_equals(h.plain2markdown('\ttab before (stuff)', preserve_multiple_spaces=True),
+ dd.assert_equal(h.plain2markdown('\ttab before (stuff)', preserve_multiple_spaces=True),
' tab before \(stuff\)')
- assert_equals(h.plain2markdown('\ttab before (stuff)', preserve_multiple_spaces=False),
+ dd.assert_equal(h.plain2markdown('\ttab before (stuff)', preserve_multiple_spaces=False),
'tab before \(stuff\)')
+
@td.without_module('html2text')
def test_plain2markdown():
"""Test plain2markdown using fallback regexp to escape markdown.
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3c9bc576/ForgeImporters/forgeimporters/google/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/__init__.py b/ForgeImporters/forgeimporters/google/__init__.py
index f60bc58..7234dc8 100644
--- a/ForgeImporters/forgeimporters/google/__init__.py
+++ b/ForgeImporters/forgeimporters/google/__init__.py
@@ -156,7 +156,7 @@ class GoogleCodeProjectExtractor(ProjectExtractor):
@classmethod
def _get_issue_ids_page(cls, project_name, start):
url = cls.PAGE_MAP['issues_csv'].format(project_name=project_name, start=start)
- with closing(urllib2.urlopen(url)) as fp:
+ with closing(cls.urlopen(url)) as fp:
lines = fp.readlines()[1:] # skip CSV header
if not lines[-1].startswith('"'):
lines.pop() # skip "next page here" info footer
@@ -285,6 +285,6 @@ class Attachment(object):
@property
def file(self):
- fp_ish = urllib2.urlopen(self.url)
+ fp_ish = GoogleCodeProjectExtractor(None).urlopen(self.url)
fp = StringIO(fp_ish.read())
return fp
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3c9bc576/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py b/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
index 7d67255..62c4453 100644
--- a/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
+++ b/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
@@ -29,15 +29,17 @@ from IPython.testing.decorators import module_not_available, skipif
from alluratest.controller import setup_basic_test
from allura.tests.decorators import without_module
from allura import model as M
+from allura.lib import helpers as h
from forgetracker import model as TM
-from .... import google
-from ....google import tracker
+from forgeimporters import base
+from forgeimporters import google
+from forgeimporters.google import tracker
class TestGCTrackerImporter(TestCase):
def _make_extractor(self, html):
- with mock.patch.object(google, 'urllib2') as urllib2:
- urllib2.urlopen.return_value = ''
+ with mock.patch.object(base.h, 'urlopen') as urlopen:
+ urlopen.return_value = ''
extractor = google.GoogleCodeProjectExtractor('my-project', 'project_info')
extractor.page = BeautifulSoup(html)
extractor.url = "http://test/issue/?id=1"
@@ -45,9 +47,9 @@ class TestGCTrackerImporter(TestCase):
def _make_ticket(self, issue):
self.assertIsNone(self.project.app_instance('test-issue'))
- with mock.patch.object(google, 'urllib2') as urllib2,\
+ with mock.patch.object(base.h, 'urlopen') as urlopen,\
mock.patch.object(google.tracker, 'GoogleCodeProjectExtractor') as GPE:
- urllib2.urlopen = lambda url: mock.Mock(read=lambda: url)
+ urlopen.side_effect = lambda req, **kw: mock.Mock(read=req.get_full_url)
GPE.iter_issues.return_value = [issue]
gti = google.tracker.GoogleCodeTrackerImporter()
gti.import_tool(self.project, self.user, 'test-issue-project', mount_point='test-issue')
[09/16] git commit: [#6464] Fixed attribute error on missing / empty
GC issue fields and added tests
Posted by jo...@apache.org.
[#6464] Fixed attribute error on missing / empty GC issue fields and added tests
Signed-off-by: Cory Johns <cj...@slashdotmedia.com>
Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/79d94937
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/79d94937
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/79d94937
Branch: refs/heads/cj/6464
Commit: 79d94937c03eb7d68f847272f83f99054b716f31
Parents: 9222343
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Fri Aug 9 14:35:59 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Fri Aug 16 22:20:59 2013 +0000
----------------------------------------------------------------------
.../forgeimporters/google/__init__.py | 14 +-
.../tests/data/google/empty-issue.html | 306 ++++++++++++
.../tests/data/google/test-issue.html | 488 +++++++++++++++++++
.../tests/google/test_extractor.py | 58 +++
4 files changed, 863 insertions(+), 3 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/79d94937/ForgeImporters/forgeimporters/google/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/__init__.py b/ForgeImporters/forgeimporters/google/__init__.py
index eaa0765..d06a500 100644
--- a/ForgeImporters/forgeimporters/google/__init__.py
+++ b/ForgeImporters/forgeimporters/google/__init__.py
@@ -186,7 +186,7 @@ class GoogleCodeProjectExtractor(ProjectExtractor):
return self.page.find(id='issueheader').findAll('td', limit=2)[1].span.string.strip()
def get_issue_description(self):
- return _as_text(self.page.find(id='hc0').pre)
+ return _as_text(self.page.find(id='hc0').pre).strip()
def get_issue_created_date(self):
return self.page.find(id='hc0').find('span', 'date').get('title')
@@ -200,10 +200,18 @@ class GoogleCodeProjectExtractor(ProjectExtractor):
return UserLink(a)
def get_issue_status(self):
- return self.page.find(id='issuemeta').find('th', text=re.compile('Status:')).findNext().span.string.strip()
+ tag = self.page.find(id='issuemeta').find('th', text=re.compile('Status:')).findNext().span
+ if tag:
+ return tag.string.strip()
+ else:
+ return ''
def get_issue_owner(self):
- return UserLink(self.page.find(id='issuemeta').find('th', text=re.compile('Owner:')).findNext().a)
+ tag = self.page.find(id='issuemeta').find('th', text=re.compile('Owner:')).findNext().a
+ if tag:
+ return UserLink(tag)
+ else:
+ return None
def get_issue_labels(self):
label_nodes = self.page.find(id='issuemeta').findAll('a', 'label')
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/79d94937/ForgeImporters/forgeimporters/tests/data/google/empty-issue.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/data/google/empty-issue.html b/ForgeImporters/forgeimporters/tests/data/google/empty-issue.html
new file mode 100644
index 0000000..a8fb1d5
--- /dev/null
+++ b/ForgeImporters/forgeimporters/tests/data/google/empty-issue.html
@@ -0,0 +1,306 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+<meta name="ROBOTS" content="NOARCHIVE" />
+<link rel="icon" type="image/vnd.microsoft.icon" href="http://www.gstatic.com/codesite/ph/images/phosting.ico" />
+<script type="text/javascript">
+
+
+
+
+ var codesite_token = null;
+
+
+ var CS_env = {"assetHostPath":"http://www.gstatic.com/codesite/ph","projectHomeUrl":"/p/allura-google-importer","relativeBaseUrl":"","domainName":null,"projectName":"allura-google-importer","loggedInUserEmail":null,"profileUrl":null,"token":null,"assetVersionPath":"http://www.gstatic.com/codesite/ph/3783617020303179221"};
+ var _gaq = _gaq || [];
+ _gaq.push(
+ ['siteTracker._setAccount', 'UA-18071-1'],
+ ['siteTracker._trackPageview']);
+
+ (function() {
+ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+ ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+ (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ga);
+ })();
+
+ </script>
+<title>Issue 5 -
+ allura-google-importer -
+
+ Empty Issue -
+ Import Google Code projects to an Allura forge - Google Project Hosting
+ </title>
+<link type="text/css" rel="stylesheet" href="http://www.gstatic.com/codesite/ph/3783617020303179221/css/core.css" />
+<link type="text/css" rel="stylesheet" href="http://www.gstatic.com/codesite/ph/3783617020303179221/css/ph_detail.css" />
+<!--[if IE]>
+ <link type="text/css" rel="stylesheet" href="http://www.gstatic.com/codesite/ph/3783617020303179221/css/d_ie.css" >
+<![endif]-->
+<style type="text/css">
+ .menuIcon.off { background: no-repeat url(http://www.gstatic.com/codesite/ph/images/dropdown_sprite.gif) 0 -42px }
+ .menuIcon.on { background: no-repeat url(http://www.gstatic.com/codesite/ph/images/dropdown_sprite.gif) 0 -28px }
+ .menuIcon.down { background: no-repeat url(http://www.gstatic.com/codesite/ph/images/dropdown_sprite.gif) 0 0; }
+
+
+ .attachments { width:33%; border-top:2px solid #999; padding-top: 3px; margin-left: .7em;}
+ .attachments table { margin-bottom: 0.75em; }
+ .attachments table tr td { padding: 0; margin: 0; font-size: 95%; }
+ .preview { border: 2px solid #c3d9ff; padding: 1px; }
+ .preview:hover { border: 2px solid blue; }
+ .label { white-space: nowrap; }
+ .derived { font-style:italic }
+ .cursor_on .author {
+ background: url(http://www.gstatic.com/codesite/ph/images/show-arrow.gif) no-repeat 2px;
+ }
+ .hiddenform {
+ display: none;
+ }
+
+
+ </style>
+</head>
+<body class="t3">
+<script type="text/javascript">
+ window.___gcfg = {lang: 'en'};
+ (function()
+ {var po = document.createElement("script");
+ po.type = "text/javascript"; po.async = true;po.src = "https://apis.google.com/js/plusone.js";
+ var s = document.getElementsByTagName("script")[0];
+ s.parentNode.insertBefore(po, s);
+ })();
+</script>
+<div class="headbg">
+<div id="gaia">
+<span>
+<a href="#" id="projects-dropdown" onclick="return false;"><u>My favorites</u> <small>▼</small></a>
+ | <a href="https://www.google.com/accounts/ServiceLogin?service=code&ltmpl=phosting&continue=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D5&followup=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D5" onclick="_CS_click('/gb/ph/signin');"><u>Sign in</u></a>
+</span>
+</div>
+<div class="gbh" style="left: 0pt;"></div>
+<div class="gbh" style="right: 0pt;"></div>
+<div style="height: 1px"></div>
+<!--[if lte IE 7]>
+<div style="text-align:center;">
+Your version of Internet Explorer is not supported. Try a browser that
+contributes to open source, such as <a href="http://www.firefox.com">Firefox</a>,
+<a href="http://www.google.com/chrome">Google Chrome</a>, or
+<a href="http://code.google.com/chrome/chromeframe/">Google Chrome Frame</a>.
+</div>
+<![endif]-->
+<table style="padding:0px; margin: 0px 0px 10px 0px; width:100%" cellpadding="0" cellspacing="0" itemscope="itemscope" itemtype="http://schema.org/CreativeWork">
+<tr style="height: 58px;">
+<td id="plogo">
+<link itemprop="url" href="/p/allura-google-importer" />
+<a href="/p/allura-google-importer/">
+<img src="/p/allura-google-importer/logo?cct=1374769571" alt="Logo" itemprop="image" />
+</a>
+</td>
+<td style="padding-left: 0.5em">
+<div id="pname">
+<a href="/p/allura-google-importer/"><span itemprop="name">allura-google-importer</span></a>
+</div>
+<div id="psum">
+<a id="project_summary_link" href="/p/allura-google-importer/"><span itemprop="description">Import Google Code projects to an Allura forge</span></a>
+</div>
+</td>
+<td style="white-space:nowrap;text-align:right; vertical-align:bottom;">
+<form action="/hosting/search">
+<input size="30" name="q" value="" type="text" />
+<input type="submit" name="projectsearch" value="Search projects" />
+</form>
+</td></tr>
+</table>
+</div>
+<div id="mt" class="gtb">
+<a href="/p/allura-google-importer/" class="tab ">Project Home</a>
+<a href="/p/allura-google-importer/wiki/TestPage?tm=6" class="tab ">Wiki</a>
+<a href="/p/allura-google-importer/issues/list" class="tab active">Issues</a>
+<a href="/p/allura-google-importer/source/checkout" class="tab ">Source</a>
+<div class="gtbc"></div>
+</div>
+<table cellspacing="0" cellpadding="0" width="100%" align="center" border="0" class="st">
+<tr>
+<td class="subt">
+<div class="issueDetail">
+<div class="isf">
+<span class="inIssueEntry">
+<a class="buttonify" href="entry" onclick="return _newIssuePrompt();">New issue</a>
+</span>
+
+ <span class="inIssueList">
+<span>Search</span>
+</span><form action="list" method="GET" style="display:inline">
+<select id="can" name="can">
+<option disabled="disabled">Search within:</option>
+<option value="1"> All issues</option>
+<option value="2" selected="selected"> Open issues</option>
+<option value="6"> New issues</option>
+<option value="7"> Issues to verify</option>
+</select>
+<span>for</span>
+<span id="qq"><input type="text" size="38" id="searchq" name="q" value="" autocomplete="off" onkeydown="_blurOnEsc(event)" /></span>
+<span id="search_colspec"><input type="hidden" name="colspec" value="ID Type Status Priority Milestone Owner Summary" /></span>
+<input type="hidden" name="cells" value="tiles" />
+<input type="submit" value="Search" />
+</form>
+
+ <span class="inIssueAdvSearch">
+<a href="advsearch">Advanced search</a>
+</span>
+ <span class="inIssueSearchTips">
+<a href="searchtips">Search tips</a>
+</span>
+ <span class="inIssueSubscriptions">
+<a href="/p/allura-google-importer/issues/subscriptions">Subscriptions</a>
+</span>
+</div>
+</div>
+</td>
+<td align="right" valign="top" class="bevel-right"></td>
+</tr>
+</table>
+<script type="text/javascript">
+ var cancelBubble = false;
+ function _go(url) { document.location = url; }
+</script>
+<div id="maincol">
+<div id="color_control" class="">
+<div id="issueheader">
+<table cellpadding="0" cellspacing="0" width="100%"><tbody>
+<tr>
+<td class="vt h3" nowrap="nowrap" style="padding:0 5px">
+
+
+ Issue <a href="detail?id=5">5</a>:
+ </td>
+<td width="90%" class="vt">
+<span class="h3">Empty Issue</span>
+</td>
+<td>
+<div class="pagination">
+<a href="../../allura-google-importer/issues/detail?id=4" title="Prev">‹ Prev</a>
+ 5 of 5
+
+ </div>
+</td>
+</tr>
+<tr>
+<td></td>
+<td nowrap="nowrap">
+
+
+ 1 person starred this issue and may be notified of changes.
+
+
+
+ </td>
+<td align="center" nowrap="nowrap">
+<a href="http://code.google.com/p/allura-google-importer/issues/list?cursor=allura-google-importer%3A5">Back to list</a>
+</td>
+</tr>
+</tbody></table>
+</div>
+<table width="100%" cellpadding="0" cellspacing="0" border="0" class="issuepage" id="meta-container">
+<tbody class="collapse">
+<tr>
+<td id="issuemeta">
+<div id="meta-float">
+<table cellspacing="0" cellpadding="0">
+<tr><th align="left">Status: </th>
+<td width="100%">
+
+
+ ----
+
+
+ </td>
+</tr>
+<tr><th align="left">Owner: </th><td>
+
+
+ ----
+
+
+ </td>
+</tr>
+<tr><td colspan="2">
+</td></tr>
+</table>
+<div class="rel_issues">
+</div>
+<br /><br />
+<div style="white-space:nowrap"><a href="https://www.google.com/accounts/ServiceLogin?service=code&ltmpl=phosting&continue=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D5&followup=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D5">Sign in</a> to add a comment</div>
+</div>
+ </td>
+<td class="vt issuedescription" width="100%" id="cursorarea">
+<div class="cursor_off vt issuedescription" id="hc0">
+<div class="author">
+<span class="role_label">Project Member</span>
+ Reported by
+
+
+ <a class="userlink" href="/u/101557263855536553789/">john...@gmail.com</a>,
+ <span class="date" title="Thu Aug 8 14:56:23 2013">Today (15 minutes ago)</span>
+</div>
+<pre>
+Empty
+</pre>
+</div>
+</td>
+</tr>
+<tr>
+<td></td>
+<td class="vt issuecomment">
+<span class="indicator">►</span> <a href="https://www.google.com/accounts/ServiceLogin?service=code&ltmpl=phosting&continue=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D5&followup=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D5">Sign in</a> to add a comment
+ </td>
+</tr>
+</tbody>
+</table>
+<br />
+<script type="text/javascript" src="http://www.gstatic.com/codesite/ph/3783617020303179221/js/dit_scripts.js"></script>
+</div>
+<form name="delcom" action="delComment.do?q=&can=2&groupby=&sort=&colspec=ID+Type+Status+Priority+Milestone+Owner+Summary" method="POST">
+<input type="hidden" name="sequence_num" value="" />
+<input type="hidden" name="mode" value="" />
+<input type="hidden" name="id" value="5" />
+<input type="hidden" name="token" value="" />
+</form>
+<div id="helparea"></div>
+<script type="text/javascript">
+ _onload();
+ function delComment(sequence_num, delete_mode) {
+ var f = document.forms["delcom"];
+ f.sequence_num.value = sequence_num;
+ f.mode.value = delete_mode;
+
+ f.submit();
+ return false;
+ }
+
+ _floatMetadata();
+</script>
+<script type="text/javascript" src="http://www.gstatic.com/codesite/ph/3783617020303179221/js/kibbles.js"></script>
+<script type="text/javascript">
+ _setupKibblesOnDetailPage(
+ 'http://code.google.com/p/allura-google-importer/issues/list?cursor\x3dallura-google-importer%3A5',
+ '/p/allura-google-importer/issues/entry',
+ '../../allura-google-importer/issues/detail?id\x3d4',
+ '',
+ '', 'allura-google-importer', 5,
+ false, false, codesite_token);
+</script>
+<script type="text/javascript" src="http://www.gstatic.com/codesite/ph/3783617020303179221/js/ph_core.js"></script>
+</div>
+<div id="footer" dir="ltr">
+<div class="text">
+<a href="/projecthosting/terms.html">Terms</a> -
+ <a href="http://www.google.com/privacy.html">Privacy</a> -
+ <a href="/p/support/">Project Hosting Help</a>
+</div>
+</div>
+<div class="hostedBy" style="margin-top: -20px;">
+<span style="vertical-align: top;">Powered by <a href="http://code.google.com/projecthosting/">Google Project Hosting</a></span>
+</div>
+</body>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/79d94937/ForgeImporters/forgeimporters/tests/data/google/test-issue.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/data/google/test-issue.html b/ForgeImporters/forgeimporters/tests/data/google/test-issue.html
new file mode 100644
index 0000000..04667ac
--- /dev/null
+++ b/ForgeImporters/forgeimporters/tests/data/google/test-issue.html
@@ -0,0 +1,488 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
+<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
+<meta name="ROBOTS" content="NOARCHIVE" />
+<link rel="icon" type="image/vnd.microsoft.icon" href="http://www.gstatic.com/codesite/ph/images/phosting.ico" />
+<script type="text/javascript">
+
+
+
+
+ var codesite_token = null;
+
+
+ var CS_env = {"loggedInUserEmail":null,"relativeBaseUrl":"","projectHomeUrl":"/p/allura-google-importer","assetVersionPath":"http://www.gstatic.com/codesite/ph/3783617020303179221","assetHostPath":"http://www.gstatic.com/codesite/ph","domainName":null,"projectName":"allura-google-importer","token":null,"profileUrl":null};
+ var _gaq = _gaq || [];
+ _gaq.push(
+ ['siteTracker._setAccount', 'UA-18071-1'],
+ ['siteTracker._trackPageview']);
+
+ (function() {
+ var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
+ ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
+ (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ga);
+ })();
+
+ </script>
+<title>Issue 6 -
+ allura-google-importer -
+
+ Test Issue -
+ Import Google Code projects to an Allura forge - Google Project Hosting
+ </title>
+<link type="text/css" rel="stylesheet" href="http://www.gstatic.com/codesite/ph/3783617020303179221/css/core.css" />
+<link type="text/css" rel="stylesheet" href="http://www.gstatic.com/codesite/ph/3783617020303179221/css/ph_detail.css" />
+<!--[if IE]>
+ <link type="text/css" rel="stylesheet" href="http://www.gstatic.com/codesite/ph/3783617020303179221/css/d_ie.css" >
+<![endif]-->
+<style type="text/css">
+ .menuIcon.off { background: no-repeat url(http://www.gstatic.com/codesite/ph/images/dropdown_sprite.gif) 0 -42px }
+ .menuIcon.on { background: no-repeat url(http://www.gstatic.com/codesite/ph/images/dropdown_sprite.gif) 0 -28px }
+ .menuIcon.down { background: no-repeat url(http://www.gstatic.com/codesite/ph/images/dropdown_sprite.gif) 0 0; }
+
+
+ .attachments { width:33%; border-top:2px solid #999; padding-top: 3px; margin-left: .7em;}
+ .attachments table { margin-bottom: 0.75em; }
+ .attachments table tr td { padding: 0; margin: 0; font-size: 95%; }
+ .preview { border: 2px solid #c3d9ff; padding: 1px; }
+ .preview:hover { border: 2px solid blue; }
+ .label { white-space: nowrap; }
+ .derived { font-style:italic }
+ .cursor_on .author {
+ background: url(http://www.gstatic.com/codesite/ph/images/show-arrow.gif) no-repeat 2px;
+ }
+ .hiddenform {
+ display: none;
+ }
+
+
+ </style>
+</head>
+<body class="t3">
+<script type="text/javascript">
+ window.___gcfg = {lang: 'en'};
+ (function()
+ {var po = document.createElement("script");
+ po.type = "text/javascript"; po.async = true;po.src = "https://apis.google.com/js/plusone.js";
+ var s = document.getElementsByTagName("script")[0];
+ s.parentNode.insertBefore(po, s);
+ })();
+</script>
+<div class="headbg">
+<div id="gaia">
+<span>
+<a href="#" id="projects-dropdown" onclick="return false;"><u>My favorites</u> <small>▼</small></a>
+ | <a href="https://www.google.com/accounts/ServiceLogin?service=code&ltmpl=phosting&continue=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D6&followup=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D6" onclick="_CS_click('/gb/ph/signin');"><u>Sign in</u></a>
+</span>
+</div>
+<div class="gbh" style="left: 0pt;"></div>
+<div class="gbh" style="right: 0pt;"></div>
+<div style="height: 1px"></div>
+<!--[if lte IE 7]>
+<div style="text-align:center;">
+Your version of Internet Explorer is not supported. Try a browser that
+contributes to open source, such as <a href="http://www.firefox.com">Firefox</a>,
+<a href="http://www.google.com/chrome">Google Chrome</a>, or
+<a href="http://code.google.com/chrome/chromeframe/">Google Chrome Frame</a>.
+</div>
+<![endif]-->
+<table style="padding:0px; margin: 0px 0px 10px 0px; width:100%" cellpadding="0" cellspacing="0" itemscope="itemscope" itemtype="http://schema.org/CreativeWork">
+<tr style="height: 58px;">
+<td id="plogo">
+<link itemprop="url" href="/p/allura-google-importer" />
+<a href="/p/allura-google-importer/">
+<img src="/p/allura-google-importer/logo?cct=1374769571" alt="Logo" itemprop="image" />
+</a>
+</td>
+<td style="padding-left: 0.5em">
+<div id="pname">
+<a href="/p/allura-google-importer/"><span itemprop="name">allura-google-importer</span></a>
+</div>
+<div id="psum">
+<a id="project_summary_link" href="/p/allura-google-importer/"><span itemprop="description">Import Google Code projects to an Allura forge</span></a>
+</div>
+</td>
+<td style="white-space:nowrap;text-align:right; vertical-align:bottom;">
+<form action="/hosting/search">
+<input size="30" name="q" value="" type="text" />
+<input type="submit" name="projectsearch" value="Search projects" />
+</form>
+</td></tr>
+</table>
+</div>
+<div id="mt" class="gtb">
+<a href="/p/allura-google-importer/" class="tab ">Project Home</a>
+<a href="/p/allura-google-importer/wiki/TestPage?tm=6" class="tab ">Wiki</a>
+<a href="/p/allura-google-importer/issues/list" class="tab active">Issues</a>
+<a href="/p/allura-google-importer/source/checkout" class="tab ">Source</a>
+<div class="gtbc"></div>
+</div>
+<table cellspacing="0" cellpadding="0" width="100%" align="center" border="0" class="st">
+<tr>
+<td class="subt">
+<div class="issueDetail">
+<div class="isf">
+<span class="inIssueEntry">
+<a class="buttonify" href="entry" onclick="return _newIssuePrompt();">New issue</a>
+</span>
+
+ <span class="inIssueList">
+<span>Search</span>
+</span><form action="list" method="GET" style="display:inline">
+<select id="can" name="can">
+<option disabled="disabled">Search within:</option>
+<option value="1"> All issues</option>
+<option value="2" selected="selected"> Open issues</option>
+<option value="6"> New issues</option>
+<option value="7"> Issues to verify</option>
+</select>
+<span>for</span>
+<span id="qq"><input type="text" size="38" id="searchq" name="q" value="" autocomplete="off" onkeydown="_blurOnEsc(event)" /></span>
+<span id="search_colspec"><input type="hidden" name="colspec" value="ID Type Status Priority Milestone Owner Summary" /></span>
+<input type="hidden" name="cells" value="tiles" />
+<input type="submit" value="Search" />
+</form>
+
+ <span class="inIssueAdvSearch">
+<a href="advsearch">Advanced search</a>
+</span>
+ <span class="inIssueSearchTips">
+<a href="searchtips">Search tips</a>
+</span>
+ <span class="inIssueSubscriptions">
+<a href="/p/allura-google-importer/issues/subscriptions">Subscriptions</a>
+</span>
+</div>
+</div>
+</td>
+<td align="right" valign="top" class="bevel-right"></td>
+</tr>
+</table>
+<script type="text/javascript">
+ var cancelBubble = false;
+ function _go(url) { document.location = url; }
+</script>
+<div id="maincol">
+<div id="color_control" class="">
+<div id="issueheader">
+<table cellpadding="0" cellspacing="0" width="100%"><tbody>
+<tr>
+<td class="vt h3" nowrap="nowrap" style="padding:0 5px">
+
+
+ Issue <a href="detail?id=6">6</a>:
+ </td>
+<td width="90%" class="vt">
+<span class="h3">Test Issue</span>
+</td>
+<td>
+<div class="pagination">
+<a href="../../allura-google-importer/issues/detail?id=5" title="Prev">‹ Prev</a>
+ 6 of 6
+
+ </div>
+</td>
+</tr>
+<tr>
+<td></td>
+<td nowrap="nowrap">
+
+
+ 1 person starred this issue and may be notified of changes.
+
+
+
+ </td>
+<td align="center" nowrap="nowrap">
+<a href="http://code.google.com/p/allura-google-importer/issues/list?cursor=allura-google-importer%3A6">Back to list</a>
+</td>
+</tr>
+</tbody></table>
+</div>
+<table width="100%" cellpadding="0" cellspacing="0" border="0" class="issuepage" id="meta-container">
+<tbody class="collapse">
+<tr>
+<td id="issuemeta">
+<div id="meta-float">
+<table cellspacing="0" cellpadding="0">
+<tr><th align="left">Status: </th>
+<td width="100%">
+<span title="Work on this issue has begun">Started</span>
+</td>
+</tr>
+<tr><th align="left">Owner: </th><td>
+<a class="userlink" href="/u/101557263855536553789/">john...@gmail.com</a>
+</td>
+</tr>
+<tr><td colspan="2">
+<div style="padding-top:2px">
+<a href="list?q=label:Type-Defect" title="Report of a software defect" class="label"><b>Type-</b>Defect</a>
+</div>
+<div style="padding-top:2px">
+<a href="list?q=label:Priority-Medium" title="Normal priority" class="label"><b>Priority-</b>Medium</a>
+</div>
+<div style="padding-top:2px">
+<a href="list?q=label:Milestone-Release1.0" title="All essential functionality working" class="label"><b>Milestone-</b>Release1.0</a>
+</div>
+<div style="padding-top:2px">
+<a href="list?q=label:OpSys-All" title="Affects all operating systems" class="label"><b>OpSys-</b>All</a>
+</div>
+<div style="padding-top:2px">
+<a href="list?q=label:Component-Logic" title="Issue relates to application logic" class="label"><b>Component-</b>Logic</a>
+</div>
+<div style="padding-top:2px">
+<a href="list?q=label:Performance" title="Performance issue" class="label">Performance</a>
+</div>
+<div style="padding-top:2px">
+<a href="list?q=label:Security" title="Security risk to users" class="label">Security</a>
+</div>
+<div style="padding-top:2px">
+<a href="list?q=label:OpSys-Windows" title="Affects Windows users" class="label"><b>OpSys-</b>Windows</a>
+</div>
+<div style="padding-top:2px">
+<a href="list?q=label:OpSys-OSX" title="Affects Mac OS X users" class="label"><b>OpSys-</b>OSX</a>
+</div>
+</td></tr>
+</table>
+<div class="rel_issues">
+</div>
+<br /><br />
+<div style="white-space:nowrap"><a href="https://www.google.com/accounts/ServiceLogin?service=code&ltmpl=phosting&continue=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D6&followup=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D6">Sign in</a> to add a comment</div>
+</div>
+ </td>
+<td class="vt issuedescription" width="100%" id="cursorarea">
+<div class="cursor_off vt issuedescription" id="hc0">
+<div class="author">
+<span class="role_label">Project Member</span>
+ Reported by
+
+
+ <a class="userlink" href="/u/101557263855536553789/">john...@gmail.com</a>,
+ <span class="date" title="Thu Aug 8 15:33:52 2013">Today (3 minutes ago)</span>
+</div>
+<pre>
+Test *Issue* for testing
+
+ 1. Test List
+ 2. Item
+
+**Testing**
+
+ * Test list 2
+ * Item
+
+# Test Section
+
+ p = source.test_issue.post()
+ p.count = p.count *5 #* 6
+
+That's all
+
+
+</pre>
+</div>
+<div class="cursor_off vt issuecomment" id="hc1">
+<div style="float:right; margin-right:.3em; text-align:right">
+<span class="date" title="Thu Aug 8 15:35:15 2013">
+ Today (2 minutes ago)
+ </span>
+</div>
+<span class="author">
+<span class="role_label">Project Member</span>
+<a name="c1" href="/p/allura-google-importer/issues/detail?id=6#c1">#1</a>
+<a class="userlink" href="/u/101557263855536553789/">john...@gmail.com</a></span>
+<pre>
+Test *comment* is a comment
+</pre>
+<div class="attachments">
+<table cellspacing="3" cellpadding="2" border="0">
+<tr><td width="20">
+<a href="//allura-google-importer.googlecode.com/issues/attachment?aid=60001000&name=at2.txt&token=JOSo4duwaN2FCKZrwYOQ-nx9r7U%3A1376001446667">
+<img width="15" height="15" src="http://www.gstatic.com/codesite/ph/images/paperclip.gif" border="0" />
+</a>
+</td>
+<td style="min-width:16em" valign="top">
+<b>at2.txt</b>
+<br />
+ 13 bytes
+
+
+ <a href="../../allura-google-importer/issues/attachmentText?id=6&aid=60001000&name=at2.txt&token=JOSo4duwaN2FCKZrwYOQ-nx9r7U%3A1376001446667" target="_blank">View</a>
+
+ <a href="//allura-google-importer.googlecode.com/issues/attachment?aid=60001000&name=at2.txt&token=JOSo4duwaN2FCKZrwYOQ-nx9r7U%3A1376001446667">Download</a>
+</td>
+</tr>
+</table>
+</div>
+<div class="updates">
+<div class="round4"></div>
+<div class="round2"></div>
+<div class="round1"></div>
+<div class="box-inner">
+<b>Status:</b>
+ Started
+
+ <br />
+<b>Labels:</b>
+ -OpSys-Linux OpSys-Windows
+
+ <br />
+</div>
+<div class="round1"></div>
+<div class="round2"></div>
+<div class="round4"></div>
+</div>
+</div>
+<div class="cursor_off vt issuecomment" id="hc2">
+<div style="float:right; margin-right:.3em; text-align:right">
+<span class="date" title="Thu Aug 8 15:35:34 2013">
+ Today (1 minute ago)
+ </span>
+</div>
+<span class="author">
+<span class="role_label">Project Member</span>
+<a name="c2" href="/p/allura-google-importer/issues/detail?id=6#c2">#2</a>
+<a class="userlink" href="/u/101557263855536553789/">john...@gmail.com</a></span>
+<pre>
+Another comment
+</pre>
+</div>
+<div class="cursor_off vt issuecomment" id="hc3">
+<div style="float:right; margin-right:.3em; text-align:right">
+<span class="date" title="Thu Aug 8 15:36:39 2013">
+ Today (moments ago)
+ </span>
+</div>
+<span class="author">
+<span class="role_label">Project Member</span>
+<a name="c3" href="/p/allura-google-importer/issues/detail?id=6#c3">#3</a>
+<a class="userlink" href="/u/101557263855536553789/">john...@gmail.com</a></span>
+<pre>
+Last comment
+</pre>
+<div class="attachments">
+<table cellspacing="3" cellpadding="2" border="0">
+<tr><td width="20">
+<a href="//allura-google-importer.googlecode.com/issues/attachment?aid=60003000&name=at4.txt&token=6Ny2zYHmV6b82dqxyoiH6HUYoC4%3A1376001446667">
+<img width="15" height="15" src="http://www.gstatic.com/codesite/ph/images/paperclip.gif" border="0" />
+</a>
+</td>
+<td style="min-width:16em" valign="top">
+<b>at4.txt</b>
+<br />
+ 13 bytes
+
+
+ <a href="../../allura-google-importer/issues/attachmentText?id=6&aid=60003000&name=at4.txt&token=6Ny2zYHmV6b82dqxyoiH6HUYoC4%3A1376001446667" target="_blank">View</a>
+
+ <a href="//allura-google-importer.googlecode.com/issues/attachment?aid=60003000&name=at4.txt&token=6Ny2zYHmV6b82dqxyoiH6HUYoC4%3A1376001446667">Download</a>
+</td>
+</tr>
+</table>
+<table cellspacing="3" cellpadding="2" border="0">
+<tr><td width="20">
+<a href="//allura-google-importer.googlecode.com/issues/attachment?aid=60003001&name=at1.txt&token=NS8aMvWsKzTAPuY2kniJG5aLzPg%3A1376001446667">
+<img width="15" height="15" src="http://www.gstatic.com/codesite/ph/images/paperclip.gif" border="0" />
+</a>
+</td>
+<td style="min-width:16em" valign="top">
+<b>at1.txt</b>
+<br />
+ 13 bytes
+
+
+ <a href="../../allura-google-importer/issues/attachmentText?id=6&aid=60003001&name=at1.txt&token=NS8aMvWsKzTAPuY2kniJG5aLzPg%3A1376001446667" target="_blank">View</a>
+
+ <a href="//allura-google-importer.googlecode.com/issues/attachment?aid=60003001&name=at1.txt&token=NS8aMvWsKzTAPuY2kniJG5aLzPg%3A1376001446667">Download</a>
+</td>
+</tr>
+</table>
+</div>
+</div>
+<div class="cursor_off vt issuecomment" id="hc4">
+<div style="float:right; margin-right:.3em; text-align:right">
+<span class="date" title="Thu Aug 8 15:36:57 2013">
+ Today (moments ago)
+ </span>
+</div>
+<span class="author">
+<span class="role_label">Project Member</span>
+<a name="c4" href="/p/allura-google-importer/issues/detail?id=6#c4">#4</a>
+<a class="userlink" href="/u/101557263855536553789/">john...@gmail.com</a></span>
+<pre>
+Oh, I forgot one
+</pre>
+<div class="updates">
+<div class="round4"></div>
+<div class="round2"></div>
+<div class="round1"></div>
+<div class="box-inner">
+<b>Labels:</b>
+ OpSys-OSX
+
+ <br />
+</div>
+<div class="round1"></div>
+<div class="round2"></div>
+<div class="round4"></div>
+</div>
+</div>
+</td>
+</tr>
+<tr>
+<td></td>
+<td class="vt issuecomment">
+<span class="indicator">►</span> <a href="https://www.google.com/accounts/ServiceLogin?service=code&ltmpl=phosting&continue=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D6&followup=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D6">Sign in</a> to add a comment
+ </td>
+</tr>
+</tbody>
+</table>
+<br />
+<script type="text/javascript" src="http://www.gstatic.com/codesite/ph/3783617020303179221/js/dit_scripts.js"></script>
+</div>
+<form name="delcom" action="delComment.do?q=&can=2&groupby=&sort=&colspec=ID+Type+Status+Priority+Milestone+Owner+Summary" method="POST">
+<input type="hidden" name="sequence_num" value="" />
+<input type="hidden" name="mode" value="" />
+<input type="hidden" name="id" value="6" />
+<input type="hidden" name="token" value="" />
+</form>
+<div id="helparea"></div>
+<script type="text/javascript">
+ _onload();
+ function delComment(sequence_num, delete_mode) {
+ var f = document.forms["delcom"];
+ f.sequence_num.value = sequence_num;
+ f.mode.value = delete_mode;
+
+ f.submit();
+ return false;
+ }
+
+ _floatMetadata();
+</script>
+<script type="text/javascript" src="http://www.gstatic.com/codesite/ph/3783617020303179221/js/kibbles.js"></script>
+<script type="text/javascript">
+ _setupKibblesOnDetailPage(
+ 'http://code.google.com/p/allura-google-importer/issues/list?cursor\x3dallura-google-importer%3A6',
+ '/p/allura-google-importer/issues/entry',
+ '../../allura-google-importer/issues/detail?id\x3d5',
+ '',
+ '', 'allura-google-importer', 6,
+ false, false, codesite_token);
+</script>
+<script type="text/javascript" src="http://www.gstatic.com/codesite/ph/3783617020303179221/js/ph_core.js"></script>
+</div>
+<div id="footer" dir="ltr">
+<div class="text">
+<a href="/projecthosting/terms.html">Terms</a> -
+ <a href="http://www.google.com/privacy.html">Privacy</a> -
+ <a href="/p/support/">Project Hosting Help</a>
+</div>
+</div>
+<div class="hostedBy" style="margin-top: -20px;">
+<span style="vertical-align: top;">Powered by <a href="http://code.google.com/projecthosting/">Google Project Hosting</a></span>
+</div>
+</body>
+</html>
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/79d94937/ForgeImporters/forgeimporters/tests/google/test_extractor.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/test_extractor.py b/ForgeImporters/forgeimporters/tests/google/test_extractor.py
index 89aac5a..14333aa 100644
--- a/ForgeImporters/forgeimporters/tests/google/test_extractor.py
+++ b/ForgeImporters/forgeimporters/tests/google/test_extractor.py
@@ -16,6 +16,7 @@
# under the License.
from unittest import TestCase
+import pkg_resources
import mock
@@ -131,3 +132,60 @@ class TestGoogleCodeProjectExtractor(TestCase):
with self.assertRaises(Exception) as cm:
extractor.get_repo_type()
self.assertEqual(str(cm.exception), "Unknown repo type: cvs")
+
+ def test_empty_issue(self):
+ empty_issue = open(pkg_resources.resource_filename('forgeimporters', 'tests/data/google/empty-issue.html')).read()
+ gpe = self._make_extractor(empty_issue)
+ self.assertIsNone(gpe.get_issue_owner())
+ self.assertEqual(gpe.get_issue_status(), '')
+ self.assertEqual(gpe.get_issue_attachments(), [])
+ self.assertEqual(list(gpe.iter_comments()), [])
+
+ def test_get_issue_basic_fields(self):
+ test_issue = open(pkg_resources.resource_filename('forgeimporters', 'tests/data/google/test-issue.html')).read()
+ gpe = self._make_extractor(test_issue)
+ self.assertEqual(gpe.get_issue_creator().name, 'john...@gmail.com')
+ self.assertEqual(gpe.get_issue_creator().link, 'http://code.google.com/u/101557263855536553789/')
+ self.assertEqual(gpe.get_issue_owner().name, 'john...@gmail.com')
+ self.assertEqual(gpe.get_issue_owner().link, 'http://code.google.com/u/101557263855536553789/')
+ self.assertEqual(gpe.get_issue_status(), 'Started')
+ self.assertEqual(gpe.get_issue_summary(), 'Test Issue')
+ self.assertEqual(gpe.get_issue_description(),
+ 'Test *Issue* for testing\n'
+ '\n'
+ ' 1. Test List\n'
+ ' 2. Item\n'
+ '\n'
+ '**Testing**\n'
+ '\n'
+ ' * Test list 2\n'
+ ' * Item\n'
+ '\n'
+ '# Test Section\n'
+ '\n'
+ ' p = source.test_issue.post()\n'
+ ' p.count = p.count *5 #* 6\n'
+ '\n'
+ 'That\'s all'
+ )
+ self.assertEqual(gpe.get_issue_created_date(), 'Thu Aug 8 15:33:52 2013')
+
+ def test_get_issue_mod_date(self):
+ test_issue = open(pkg_resources.resource_filename('forgeimporters', 'tests/data/google/test-issue.html')).read()
+ gpe = self._make_extractor(test_issue)
+ self.assertEqual(gpe.get_issue_mod_date(), 'Thu Aug 8 15:36:57 2013')
+
+ def test_get_issue_labels(self):
+ test_issue = open(pkg_resources.resource_filename('forgeimporters', 'tests/data/google/test-issue.html')).read()
+ gpe = self._make_extractor(test_issue)
+ self.assertEqual(gpe.get_issue_labels(), [
+ 'Type-Defect',
+ 'Priority-Medium',
+ 'Milestone-Release1.0',
+ 'OpSys-All',
+ 'Component-Logic',
+ 'Performance',
+ 'Security',
+ 'OpSys-Windows',
+ 'OpSys-OSX',
+ ])
[10/16] git commit: [#6464] Fixed issue with custom fields not
persisting and added tests
Posted by jo...@apache.org.
[#6464] Fixed issue with custom fields not persisting and added tests
Signed-off-by: Cory Johns <cj...@slashdotmedia.com>
Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/36cf1a28
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/36cf1a28
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/36cf1a28
Branch: refs/heads/cj/6464
Commit: 36cf1a281b1e0d88e384a18922e0edbb5a27d7b0
Parents: ea2fc78
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Mon Aug 12 22:25:23 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Fri Aug 16 22:21:00 2013 +0000
----------------------------------------------------------------------
Allura/allura/lib/helpers.py | 4 +-
.../forgeimporters/google/__init__.py | 19 ++
ForgeImporters/forgeimporters/google/tracker.py | 65 ++---
.../tests/google/functional/__init__.py | 17 ++
.../tests/google/functional/test_tracker.py | 260 +++++++++++++++++++
.../forgeimporters/tests/google/test_tracker.py | 25 +-
6 files changed, 341 insertions(+), 49 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/36cf1a28/Allura/allura/lib/helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index 99a5d30..01586c2 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -98,7 +98,7 @@ re_preserve_spaces = re.compile(r'''
''', re.VERBOSE)
re_angle_bracket_open = re.compile('<')
re_angle_bracket_close = re.compile('>')
-md_chars_matcher_all = re.compile(r"([`\*_{}\[\]\(\)#!\\.+-])")
+md_chars_matcher_all = re.compile(r"([`\*_{}\[\]\(\)#!\\\.+-])")
def make_safe_path_portion(ustr, relaxed=True):
"""Return an ascii representation of ``ustr`` that conforms to mount point
@@ -962,7 +962,7 @@ def plain2markdown(text, preserve_multiple_spaces=False, has_html_entities=False
text = html2text.escape_md_section(text, snob=True)
except ImportError:
# fall back to just escaping any MD-special chars
- text = md_chars_matcher.sub(r"\\\\1", text)
+ text = md_chars_matcher_all.sub(r"\\\1", text)
# prevent < and > from becoming tags
text = re_angle_bracket_open.sub('<', text)
text = re_angle_bracket_close.sub('>', text)
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/36cf1a28/ForgeImporters/forgeimporters/google/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/__init__.py b/ForgeImporters/forgeimporters/google/__init__.py
index 88a1449..660853f 100644
--- a/ForgeImporters/forgeimporters/google/__init__.py
+++ b/ForgeImporters/forgeimporters/google/__init__.py
@@ -28,6 +28,7 @@ import logging
from BeautifulSoup import BeautifulSoup
+from allura.lib import helpers as h
from allura import model as M
from forgeimporters.base import ProjectExtractor
@@ -261,6 +262,24 @@ class Comment(object):
else:
self.attachments = []
+ @property
+ def annotated_text(self):
+ text = (
+ u'*Originally posted by:* [{author.name}]({author.link})\n'
+ u'\n'
+ u'{body}\n'
+ u'\n'
+ u'{updates}'
+ ).format(
+ author=self.author,
+ body=h.plain2markdown(self.body, True),
+ updates='\n'.join(
+ '**%s** %s' % (k,v)
+ for k,v in self.updates.items()
+ ),
+ )
+ return text
+
class Attachment(object):
def __init__(self, tag):
self.filename = _as_text(tag).strip().split()[0]
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/36cf1a28/ForgeImporters/forgeimporters/google/tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tracker.py b/ForgeImporters/forgeimporters/google/tracker.py
index bd3a57f..fefd695 100644
--- a/ForgeImporters/forgeimporters/google/tracker.py
+++ b/ForgeImporters/forgeimporters/google/tracker.py
@@ -19,6 +19,7 @@ from collections import defaultdict
from datetime import datetime
from pylons import tmpl_context as c
+from pylons import app_globals as g
from ming.orm import session, ThreadLocalORMSession
from allura import model as M
@@ -44,22 +45,27 @@ class GoogleCodeTrackerImporter(ToolImporter):
def import_tool(self, project, user, project_name, mount_point=None,
mount_label=None, **kw):
- c.app = project.install_app('tickets', mount_point, mount_label)
+ app = project.install_app('tickets', mount_point, mount_label)
+ app.globals.open_status_names = 'New Accepted Started'
+ app.globals.closed_status_names = 'Fixed Verified Invalid Duplicate WontFix Done'
ThreadLocalORMSession.flush_all()
- c.app.globals.open_status_names = 'New Accepted Started'
- c.app.globals.closed_status_names = 'Fixed Verified Invalid Duplicate WontFix Done'
self.custom_fields = {}
try:
M.session.artifact_orm_session._get().skip_mod_date = True
- for issue in GoogleCodeProjectExtractor.iter_issues(project_name):
- ticket = TM.Ticket.new()
- self.process_fields(ticket, issue)
- self.process_labels(ticket, issue)
- self.process_comments(ticket, issue)
- session(ticket).flush(ticket)
- session(ticket).expunge(ticket)
- self.postprocess_custom_fields()
- ThreadLocalORMSession.flush_all()
+ with h.push_config(c, user=M.User.anonymous(), app=app):
+ for issue in GoogleCodeProjectExtractor.iter_issues(project_name):
+ ticket = TM.Ticket.new()
+ self.process_fields(ticket, issue)
+ self.process_labels(ticket, issue)
+ self.process_comments(ticket, issue)
+ session(ticket).flush(ticket)
+ session(ticket).expunge(ticket)
+ # app.globals gets expunged every time Ticket.new() is called :-(
+ app.globals = TM.Globals.query.get(app_config_id=app.config._id)
+ app.globals.custom_fields = self.postprocess_custom_fields()
+ ThreadLocalORMSession.flush_all()
+ g.post_event('project_updated')
+ return app
finally:
M.session.artifact_orm_session._get().skip_mod_date = False
@@ -78,13 +84,18 @@ class GoogleCodeTrackerImporter(ToolImporter):
ticket.status = issue.get_issue_status()
ticket.created_date = datetime.strptime(issue.get_issue_created_date(), '%c')
ticket.mod_date = datetime.strptime(issue.get_issue_mod_date(), '%c')
+ owner = issue.get_issue_owner()
+ if owner:
+ owner_line = '*Originally owned by:* [{owner.name}]({owner.link})\n'.format(owner=owner)
+ else:
+ owner_line = ''
ticket.description = (
u'*Originally created by:* [{creator.name}]({creator.link})\n'
- '*Originally owned by:* [{owner.name}]({owner.link})\n'
- '\n'
- '{body}').format(
+ u'{owner}'
+ u'\n'
+ u'{body}').format(
creator=issue.get_issue_creator(),
- owner=issue.get_issue_owner(),
+ owner=owner_line,
body=h.plain2markdown(issue.get_issue_description(), True),
)
ticket.add_multiple_attachments(issue.get_issue_attachments())
@@ -106,25 +117,14 @@ class GoogleCodeTrackerImporter(ToolImporter):
def process_comments(self, ticket, issue):
for comment in issue.iter_comments():
p = ticket.discussion_thread.add_post(
- text = (
- u'*Originally posted by:* [{author.name}]({author.link})\n'
- '\n'
- '{body}\n'
- '\n'
- '{updates}').format(
- author=comment.author,
- body=h.plain2markdown(comment.body, True),
- updates='\n'.join(
- '**%s** %s' % (k,v)
- for k,v in comment.updates.items()
- ),
- )
+ text = comment.annotated_text,
+ ignore_security = True,
+ timestamp = datetime.strptime(comment.created_date, '%c'),
)
- p.created_date = p.timestamp = datetime.strptime(comment.created_date, '%c')
p.add_multiple_attachments(comment.attachments)
def postprocess_custom_fields(self):
- c.app.globals.custom_fields = []
+ custom_fields = []
for name, field in self.custom_fields.iteritems():
if field['name'] == '_milestone':
field['milestones'] = [{
@@ -137,4 +137,5 @@ class GoogleCodeTrackerImporter(ToolImporter):
field['options'] = ' '.join(field['options'])
else:
field['options'] = ''
- c.app.globals.custom_fields.append(field)
+ custom_fields.append(field)
+ return custom_fields
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/36cf1a28/ForgeImporters/forgeimporters/tests/google/functional/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/functional/__init__.py b/ForgeImporters/forgeimporters/tests/google/functional/__init__.py
new file mode 100644
index 0000000..77505f1
--- /dev/null
+++ b/ForgeImporters/forgeimporters/tests/google/functional/__init__.py
@@ -0,0 +1,17 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/36cf1a28/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py b/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
new file mode 100644
index 0000000..206ac7c
--- /dev/null
+++ b/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
@@ -0,0 +1,260 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+from unittest import TestCase
+import pkg_resources
+from functools import wraps
+from datetime import datetime
+
+from BeautifulSoup import BeautifulSoup
+import mock
+from ming.orm import ThreadLocalORMSession
+from pylons import tmpl_context as c
+from IPython.testing.decorators import module_not_available, skipif
+
+from alluratest.controller import setup_basic_test
+from allura import model as M
+from forgetracker import model as TM
+from .... import google
+from ....google import tracker
+
+
+def without_html2text(func):
+ @wraps(func)
+ def wrapped(*args, **kw):
+ try:
+ import html2text
+ except ImportError:
+ return func(*args, **kw)
+ else:
+ with mock.patch.object(html2text, 'escape_md_section') as ems:
+ ems.side_effect = ImportError
+ return func(*args, **kw)
+ return wrapped
+
+class TestGCTrackerImporter(TestCase):
+ def _make_extractor(self, html):
+ with mock.patch.object(google, 'urllib2') as urllib2:
+ urllib2.urlopen.return_value = ''
+ extractor = google.GoogleCodeProjectExtractor('my-project', 'project_info')
+ extractor.page = BeautifulSoup(html)
+ extractor.url = "http://test/issue/?id=1"
+ return extractor
+
+ def _make_ticket(self, issue):
+ self.assertIsNone(self.project.app_instance('test-issue'))
+ with mock.patch.object(google, 'urllib2') as urllib2,\
+ mock.patch.object(google.tracker, 'GoogleCodeProjectExtractor') as GPE:
+ urllib2.urlopen = lambda url: mock.Mock(read=lambda: url)
+ GPE.iter_issues.return_value = [issue]
+ gti = google.tracker.GoogleCodeTrackerImporter()
+ gti.import_tool(self.project, self.user, 'test-issue-project', mount_point='test-issue')
+ c.app = self.project.app_instance('test-issue')
+ query = TM.Ticket.query.find({'app_config_id': c.app.config._id})
+ self.assertEqual(query.count(), 1)
+ ticket = query.all()[0]
+ return ticket
+
+ def setUp(self, *a, **kw):
+ super(TestGCTrackerImporter, self).setUp(*a, **kw)
+ setup_basic_test()
+ self.empty_issue = self._make_extractor(open(pkg_resources.resource_filename('forgeimporters', 'tests/data/google/empty-issue.html')).read())
+ self.test_issue = self._make_extractor(open(pkg_resources.resource_filename('forgeimporters', 'tests/data/google/test-issue.html')).read())
+ c.project = self.project = M.Project.query.get(shortname='test')
+ c.user = self.user = M.User.query.get(username='test-admin')
+
+ def test_empty_issue(self):
+ ticket = self._make_ticket(self.empty_issue)
+ self.assertEqual(ticket.summary, 'Empty Issue')
+ self.assertEqual(ticket.description, '*Originally created by:* [john...@gmail.com](http://code.google.com/u/101557263855536553789/)\n\nEmpty')
+ self.assertEqual(ticket.status, '')
+ self.assertEqual(ticket.milestone, '')
+ self.assertEqual(ticket.custom_fields, {})
+
+ @without_html2text
+ def test_issue_basic_fields(self):
+ anon = M.User.anonymous()
+ ticket = self._make_ticket(self.test_issue)
+ self.assertEqual(ticket.reported_by, anon)
+ self.assertIsNone(ticket.assigned_to_id)
+ self.assertEqual(ticket.summary, 'Test Issue')
+ self.assertEqual(ticket.description,
+ '*Originally created by:* [john...@gmail.com](http://code.google.com/u/101557263855536553789/)\n'
+ '*Originally owned by:* [john...@gmail.com](http://code.google.com/u/101557263855536553789/)\n'
+ '\n'
+ 'Test \\*Issue\\* for testing\n'
+ '\n'
+ ' 1\\. Test List\n'
+ ' 2\\. Item\n'
+ '\n'
+ '\\*\\*Testing\\*\\*\n'
+ '\n'
+ ' \\* Test list 2\n'
+ ' \\* Item\n'
+ '\n'
+ '\\# Test Section\n'
+ '\n'
+ ' p = source\\.test\\_issue\\.post\\(\\)\n'
+ ' p\\.count = p\\.count \\*5 \\#\\* 6\n'
+ '\n'
+ 'That\'s all'
+ )
+ self.assertEqual(ticket.status, 'Started')
+ self.assertEqual(ticket.created_date, datetime(2013, 8, 8, 15, 33, 52))
+ self.assertEqual(ticket.mod_date, datetime(2013, 8, 8, 15, 36, 57))
+ self.assertEqual(ticket.custom_fields, {
+ '_priority': 'Medium',
+ '_opsys': 'All, OSX, Windows',
+ '_component': 'Logic',
+ '_type': 'Defect',
+ '_milestone': 'Release1.0'
+ })
+ self.assertEqual(ticket.labels, ['Performance', 'Security'])
+
+ @skipif(module_not_available('html2text'))
+ def test_html2text_escaping(self):
+ ticket = self._make_ticket(self.test_issue)
+ self.assertEqual(ticket.description,
+ '*Originally created by:* [john...@gmail.com](http://code.google.com/u/101557263855536553789/)\n'
+ '*Originally owned by:* [john...@gmail.com](http://code.google.com/u/101557263855536553789/)\n'
+ '\n'
+ 'Test \\*Issue\\* for testing\n'
+ '\n'
+ ' 1. Test List\n'
+ ' 2. Item\n'
+ '\n'
+ '\\*\\*Testing\\*\\*\n'
+ '\n'
+ ' \\* Test list 2\n'
+ ' \\* Item\n'
+ '\n'
+ '\\# Test Section\n'
+ '\n'
+ ' p = source.test\\_issue.post\\(\\)\n'
+ ' p.count = p.count \\*5 \\#\\* 6\n'
+ '\n'
+ 'That\'s all'
+ )
+
+ def _assert_attachments(self, actual, *expected):
+ self.assertEqual(actual.count(), len(expected))
+ atts = set((a.filename, a.content_type, a.rfile().read()) for a in actual)
+ self.assertEqual(atts, set(expected))
+
+ def test_attachements(self):
+ ticket = self._make_ticket(self.test_issue)
+ self._assert_attachments(ticket.attachments,
+ ('at1.txt', 'text/plain', 'http://allura-google-importer.googlecode.com/issues/attachment?aid=70000000&name=at1.txt&token=3REU1M3JUUMt0rJUg7ldcELt6LA%3A1376059941255'),
+ ('at2.txt', 'text/plain', 'http://allura-google-importer.googlecode.com/issues/attachment?aid=70000001&name=at2.txt&token=C9Hn4s1-g38hlSggRGo65VZM1ys%3A1376059941255'),
+ )
+
+ @without_html2text
+ def test_comments(self):
+ anon = M.User.anonymous()
+ ticket = self._make_ticket(self.test_issue)
+ actual_comments = ticket.discussion_thread.find_posts()
+ expected_comments = [
+ {
+ 'timestamp': datetime(2013, 8, 8, 15, 35, 15),
+ 'text': (
+ '*Originally posted by:* [john...@gmail.com](http://code.google.com/u/101557263855536553789/)\n'
+ '\n'
+ 'Test \\*comment\\* is a comment\n'
+ '\n'
+ '**Labels:** -OpSys-Linux OpSys-Windows\n'
+ '**Status:** Started'
+ ),
+ 'attachments': [
+ ('at2.txt', 'text/plain', 'http://allura-google-importer.googlecode.com/issues/attachment?aid=60001000&name=at2.txt&token=JOSo4duwaN2FCKZrwYOQ-nx9r7U%3A1376001446667'),
+ ],
+ },
+ {
+ 'timestamp': datetime(2013, 8, 8, 15, 35, 34),
+ 'text': (
+ '*Originally posted by:* [john...@gmail.com](http://code.google.com/u/101557263855536553789/)\n'
+ '\n'
+ 'Another comment\n\n'
+ ),
+ },
+ {
+ 'timestamp': datetime(2013, 8, 8, 15, 36, 39),
+ 'text': (
+ '*Originally posted by:* [john...@gmail.com](http://code.google.com/u/101557263855536553789/)\n'
+ '\n'
+ 'Last comment\n\n'
+ ),
+ 'attachments': [
+ ('at4.txt', 'text/plain', 'http://allura-google-importer.googlecode.com/issues/attachment?aid=60003000&name=at4.txt&token=6Ny2zYHmV6b82dqxyoiH6HUYoC4%3A1376001446667'),
+ ('at1.txt', 'text/plain', 'http://allura-google-importer.googlecode.com/issues/attachment?aid=60003001&name=at1.txt&token=NS8aMvWsKzTAPuY2kniJG5aLzPg%3A1376001446667'),
+ ],
+ },
+ {
+ 'timestamp': datetime(2013, 8, 8, 15, 36, 57),
+ 'text': (
+ '*Originally posted by:* [john...@gmail.com](http://code.google.com/u/101557263855536553789/)\n'
+ '\n'
+ 'Oh, I forgot one\n'
+ '\n'
+ '**Labels:** OpSys-OSX'
+ ),
+ },
+ ]
+ self.assertEqual(len(actual_comments), len(expected_comments))
+ for actual, expected in zip(actual_comments, expected_comments):
+ self.assertEqual(actual.author(), anon)
+ self.assertEqual(actual.timestamp, expected['timestamp'])
+ self.assertEqual(actual.text, expected['text'])
+ if 'attachments' in expected:
+ self._assert_attachments(actual.attachments, *expected['attachments'])
+
+ def test_globals(self):
+ globals = self._make_ticket(self.test_issue).globals
+ self.assertItemsEqual(globals.custom_fields, [
+ {
+ 'label': 'Milestone',
+ 'name': '_milestone',
+ 'type': 'milestone',
+ 'options': '',
+ 'milestones': [
+ {'name': 'Release1.0', 'due_date': None, 'complete': False},
+ ],
+ },
+ {
+ 'label': 'Type',
+ 'name': '_type',
+ 'type': 'select',
+ 'options': 'Defect',
+ },
+ {
+ 'label': 'Priority',
+ 'name': '_priority',
+ 'type': 'select',
+ 'options': 'Medium',
+ },
+ {
+ 'label': 'OpSys',
+ 'name': '_opsys',
+ 'type': 'string',
+ 'options': '',
+ },
+ {
+ 'label': 'Component',
+ 'name': '_component',
+ 'type': 'string',
+ 'options': '',
+ },
+ ])
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/36cf1a28/ForgeImporters/forgeimporters/tests/google/test_tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/test_tracker.py b/ForgeImporters/forgeimporters/tests/google/test_tracker.py
index a1f0a28..3efd97d 100644
--- a/ForgeImporters/forgeimporters/tests/google/test_tracker.py
+++ b/ForgeImporters/forgeimporters/tests/google/test_tracker.py
@@ -27,9 +27,10 @@ class TestTrackerImporter(TestCase):
@mock.patch.object(tracker, 'c')
@mock.patch.object(tracker, 'ThreadLocalORMSession')
@mock.patch.object(tracker, 'session')
+ @mock.patch.object(tracker, 'M')
@mock.patch.object(tracker, 'TM')
@mock.patch.object(tracker, 'GoogleCodeProjectExtractor')
- def test_import_tool(self, gpe, TM, session, tlos, c):
+ def test_import_tool(self, gpe, TM, M, session, tlos, c):
importer = tracker.GoogleCodeTrackerImporter()
importer.process_fields = mock.Mock()
importer.process_labels = mock.Mock()
@@ -158,12 +159,14 @@ class TestTrackerImporter(TestCase):
mock.Mock(
author=_author(1),
body='text1',
+ annotated_text='annotated1',
attachments='attachments1',
created_date='Mon Jul 15 00:00:00 2013',
),
mock.Mock(
author=_author(2),
body='text2',
+ annotated_text='annotated2',
attachments='attachments2',
created_date='Mon Jul 16 00:00:00 2013',
),
@@ -177,24 +180,16 @@ class TestTrackerImporter(TestCase):
importer = tracker.GoogleCodeTrackerImporter()
importer.process_comments(ticket, issue)
self.assertEqual(ticket.discussion_thread.add_post.call_args_list[0], mock.call(
- text='*Originally posted by:* [author1](author1_link)\n'
- '\n'
- 'text1\n'
- '\n'
- '**Foo:** Bar\n'
- '**Baz:** Qux'
+ text='annotated1',
+ timestamp=datetime(2013, 7, 15),
+ ignore_security=True,
))
- self.assertEqual(posts[0].created_date, datetime(2013, 7, 15))
- self.assertEqual(posts[0].timestamp, datetime(2013, 7, 15))
posts[0].add_multiple_attachments.assert_called_once_with('attachments1')
self.assertEqual(ticket.discussion_thread.add_post.call_args_list[1], mock.call(
- text='*Originally posted by:* [author2](author2_link)\n'
- '\n'
- 'text2\n'
- '\n'
+ text='annotated2',
+ timestamp=datetime(2013, 7, 16),
+ ignore_security=True,
))
- self.assertEqual(posts[1].created_date, datetime(2013, 7, 16))
- self.assertEqual(posts[1].timestamp, datetime(2013, 7, 16))
posts[1].add_multiple_attachments.assert_called_once_with('attachments2')
@mock.patch.object(tracker, 'c')
[13/16] git commit: [#6464] Fixed handling of attachment links in GC
Tracker importer
Posted by jo...@apache.org.
[#6464] Fixed handling of attachment links in GC Tracker importer
Signed-off-by: Cory Johns <cj...@slashdotmedia.com>
Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/d1ac784e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/d1ac784e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/d1ac784e
Branch: refs/heads/cj/6464
Commit: d1ac784eeb2665a3d016b5cef592b887e6af6774
Parents: 8facbc5
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Fri Aug 16 22:04:00 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Fri Aug 16 22:21:00 2013 +0000
----------------------------------------------------------------------
ForgeImporters/forgeimporters/google/__init__.py | 16 ++++++++--------
.../forgeimporters/tests/google/test_extractor.py | 6 +++---
2 files changed, 11 insertions(+), 11 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/d1ac784e/ForgeImporters/forgeimporters/google/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/__init__.py b/ForgeImporters/forgeimporters/google/__init__.py
index 22be7c2..fbf3eb0 100644
--- a/ForgeImporters/forgeimporters/google/__init__.py
+++ b/ForgeImporters/forgeimporters/google/__init__.py
@@ -17,7 +17,7 @@
import re
import urllib
-from urlparse import urlparse, urljoin
+from urlparse import urlparse, urljoin, parse_qs
from collections import defaultdict
from contextlib import closing
try:
@@ -123,7 +123,7 @@ class GoogleCodeProjectExtractor(ProjectExtractor):
def get_icon(self, project):
page = self.get_page('project_info')
- icon_url = urljoin(self.url, page.find(itemprop='image').attrMap['src'])
+ icon_url = urljoin(self.url, page.find(itemprop='image').get('src'))
if icon_url == self.DEFAULT_ICON:
return
icon_name = urllib.unquote(urlparse(icon_url).path).split('/')[-1]
@@ -222,7 +222,7 @@ class GoogleCodeProjectExtractor(ProjectExtractor):
def get_issue_attachments(self):
attachments = self.page.find(id='hc0').find('div', 'attachments')
if attachments:
- return map(Attachment, attachments.findAll('tr'))
+ return [Attachment(a.parent) for a in attachments.findAll('a', text='Download')]
else:
return []
@@ -233,8 +233,8 @@ class GoogleCodeProjectExtractor(ProjectExtractor):
class UserLink(object):
def __init__(self, tag):
self.name = tag.string.strip()
- if 'href' in tag.attrMap:
- self.url = urljoin(GoogleCodeProjectExtractor.BASE_URL, tag.attrMap['href'])
+ if tag.get('href'):
+ self.url = urljoin(GoogleCodeProjectExtractor.BASE_URL, tag.get('href'))
else:
self.url = None
@@ -264,7 +264,7 @@ class Comment(object):
def _get_attachments(self, tag):
attachments = tag.find('div', 'attachments')
if attachments:
- self.attachments = map(Attachment, attachments.findAll('tr'))
+ self.attachments = [Attachment(a.parent) for a in attachments.findAll('a', text='Download')]
else:
self.attachments = []
@@ -288,8 +288,8 @@ class Comment(object):
class Attachment(object):
def __init__(self, tag):
- self.filename = _as_text(tag).strip().split()[0]
- self.url = urljoin(GoogleCodeProjectExtractor.BASE_URL, tag.a.get('href'))
+ self.url = urljoin(GoogleCodeProjectExtractor.BASE_URL, tag.get('href'))
+ self.filename = parse_qs(urlparse(self.url).query)['name'][0]
self.type = None
@property
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/d1ac784e/ForgeImporters/forgeimporters/tests/google/test_extractor.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/test_extractor.py b/ForgeImporters/forgeimporters/tests/google/test_extractor.py
index 4157c98..e208e8d 100644
--- a/ForgeImporters/forgeimporters/tests/google/test_extractor.py
+++ b/ForgeImporters/forgeimporters/tests/google/test_extractor.py
@@ -76,7 +76,7 @@ class TestGoogleCodeProjectExtractor(TestCase):
def test_get_icon(self, M, StringIO):
self.urlopen.return_value.info.return_value = {'content-type': 'image/png'}
extractor = google.GoogleCodeProjectExtractor('my-project', 'project_info')
- extractor.page.find.return_value.attrMap = {'src': 'http://example.com/foo/bar/my-logo.png'}
+ extractor.page.find.return_value.get.return_value = 'http://example.com/foo/bar/my-logo.png'
self.urlopen.reset_mock()
extractor.get_icon(self.project)
@@ -260,13 +260,13 @@ class TestUserLink(TestCase):
def test_plain(self):
tag = mock.Mock()
tag.string.strip.return_value = 'name'
- tag.attrMap = {}
+ tag.get.return_value = None
link = google.UserLink(tag)
self.assertEqual(str(link), 'name')
def test_linked(self):
tag = mock.Mock()
tag.string.strip.return_value = 'name'
- tag.attrMap = {'href': '/p/project'}
+ tag.get.return_value = '/p/project'
link = google.UserLink(tag)
self.assertEqual(str(link), '[name](http://code.google.com/p/project)')
[02/16] git commit: [#6480] add Apache License header to
Allura/allura/tests/test_decorators.py
Posted by jo...@apache.org.
[#6480] add Apache License header to Allura/allura/tests/test_decorators.py
Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/1c62317d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/1c62317d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/1c62317d
Branch: refs/heads/cj/6464
Commit: 1c62317dbbb01bfd413b83aa7e6906f9a1505249
Parents: 2b0a101
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Fri Aug 16 15:17:14 2013 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri Aug 16 15:17:14 2013 +0000
----------------------------------------------------------------------
Allura/allura/tests/test_decorators.py | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/1c62317d/Allura/allura/tests/test_decorators.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_decorators.py b/Allura/allura/tests/test_decorators.py
index 41ba631..d4b70a5 100644
--- a/Allura/allura/tests/test_decorators.py
+++ b/Allura/allura/tests/test_decorators.py
@@ -1,3 +1,20 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
from unittest import TestCase
from mock import patch
[14/16] git commit: [#6464] Refactored plain2markdown tests
Posted by jo...@apache.org.
[#6464] Refactored plain2markdown tests
Signed-off-by: Cory Johns <cj...@slashdotmedia.com>
Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/38c8c8ea
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/38c8c8ea
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/38c8c8ea
Branch: refs/heads/cj/6464
Commit: 38c8c8eafa93419e84d0a64fb6495d4472f5f5a1
Parents: 123cb15
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Wed Aug 14 18:47:04 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Fri Aug 16 22:21:00 2013 +0000
----------------------------------------------------------------------
Allura/allura/tests/decorators.py | 11 +++
Allura/allura/tests/test_helpers.py | 85 ++++++++++++++++++++
ForgeBlog/forgeblog/tests/test_commands.py | 42 ----------
.../forgeimporters/google/__init__.py | 2 +-
ForgeImporters/forgeimporters/google/tracker.py | 2 +-
.../tests/google/functional/test_tracker.py | 18 +----
6 files changed, 101 insertions(+), 59 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/38c8c8ea/Allura/allura/tests/decorators.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/decorators.py b/Allura/allura/tests/decorators.py
index 745b008..8c9e4c9 100644
--- a/Allura/allura/tests/decorators.py
+++ b/Allura/allura/tests/decorators.py
@@ -15,6 +15,7 @@
# specific language governing permissions and limitations
# under the License.
+import sys
from functools import wraps
import contextlib
@@ -104,3 +105,13 @@ class raises(object):
return False
else:
raise AssertionError('Did not raise %s' % self.ExcType)
+
+
+def without_module(*module_names):
+ def _without_module(func):
+ @wraps(func)
+ def wrapped(*a, **kw):
+ with patch.dict(sys.modules, {m: None for m in module_names}):
+ return func(*a, **kw)
+ return wrapped
+ return _without_module
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/38c8c8ea/Allura/allura/tests/test_helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_helpers.py b/Allura/allura/tests/test_helpers.py
index 4ec91df..03a530c 100644
--- a/Allura/allura/tests/test_helpers.py
+++ b/Allura/allura/tests/test_helpers.py
@@ -23,6 +23,8 @@ from mock import Mock, patch
from pylons import tmpl_context as c
from nose.tools import eq_, assert_equals
+from IPython.testing.decorators import skipif, module_not_available
+from datadiff import tools as dd
from allura import model as M
from allura.lib import helpers as h
@@ -263,6 +265,89 @@ def test_notifications_disabled():
assert_equals(project.notifications_disabled, False)
+@skipif(module_not_available('html2text'))
+def test_plain2markdown_with_html2text():
+ """Test plain2markdown using html2text to escape markdown, if available."""
+ text = '''paragraph
+
+ 4 spaces before this
+
+ *blah*
+
+here's a <tag> that should be <b>preserved</b>
+Literal > Ò ¼ & & ሿ
+M & Ms - doesn't get escaped
+http://blah.com/?x=y&a=b - not escaped either
+'''
+
+ expected = '''paragraph
+
+4 spaces before this
+
+\*blah\*
+
+here's a <tag> that should be <b>preserved</b>
+Literal &gt; &Ograve; &frac14; &amp; &\#38; &\#x123F;
+M & Ms - doesn't get escaped
+http://blah.com/?x=y&a=b - not escaped either
+'''
+
+ assert_equals(h.plain2markdown(text), expected)
+
+ assert_equals(h.plain2markdown('a foo bar\n\n code here?', preserve_multiple_spaces=True),
+ 'a foo bar\n\n code here?')
+
+ assert_equals(h.plain2markdown('\ttab before (stuff)', preserve_multiple_spaces=True),
+ ' tab before \(stuff\)')
+
+ assert_equals(h.plain2markdown('\ttab before (stuff)', preserve_multiple_spaces=False),
+ 'tab before \(stuff\)')
+
+@td.without_module('html2text')
+def test_plain2markdown():
+ """Test plain2markdown using fallback regexp to escape markdown.
+
+ Potentially MD-special characters are aggresively escaped, as without
+ knowledge of the MD parsing rules it's better to be excessive but safe.
+ """
+ text = '''paragraph
+
+ 4 spaces before this
+
+ *blah*
+
+here's a <tag> that should be <b>preserved</b>
+Literal > Ò ¼ & & ሿ
+M & Ms - amp doesn't get escaped
+http://blah.com/?x=y&a=b - not escaped either
+back\\-slash escaped
+'''
+
+ expected = '''paragraph
+
+4 spaces before this
+
+\*blah\*
+
+here's a <tag> that should be <b>preserved</b>
+Literal &gt; &Ograve; &frac14; &amp; &\#38; &\#x123F;
+M & Ms \- amp doesn't get escaped
+http://blah\.com/?x=y&a=b \- not escaped either
+back\\\\\-slash escaped
+'''
+
+ dd.assert_equal(h.plain2markdown(text), expected)
+
+ dd.assert_equal(h.plain2markdown('a foo bar\n\n code here?', preserve_multiple_spaces=True),
+ 'a foo bar\n\n code here?')
+
+ dd.assert_equal(h.plain2markdown('\ttab before (stuff)', preserve_multiple_spaces=True),
+ ' tab before \(stuff\)')
+
+ dd.assert_equal(h.plain2markdown('\ttab before (stuff)', preserve_multiple_spaces=False),
+ 'tab before \(stuff\)')
+
+
class TestUrlOpen(TestCase):
@patch('allura.lib.helpers.urllib2')
def test_no_error(self, urllib2):
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/38c8c8ea/ForgeBlog/forgeblog/tests/test_commands.py
----------------------------------------------------------------------
diff --git a/ForgeBlog/forgeblog/tests/test_commands.py b/ForgeBlog/forgeblog/tests/test_commands.py
index 472efda..0b2804a 100644
--- a/ForgeBlog/forgeblog/tests/test_commands.py
+++ b/ForgeBlog/forgeblog/tests/test_commands.py
@@ -168,45 +168,3 @@ def test_plaintext_preprocessor_wrapped():
'<p>#foo bar <a class="" href="../baz">baz</a> foo bar </p>\n'
'<p>#foo bar <a class="" href="../baz"> baz </a></p></div>'
)
-
-@skipif(module_not_available('html2text'))
-def test_plain2markdown():
- text = '''paragraph
-
- 4 spaces before this
-
- *blah*
-
-here's a <tag> that should be <b>preserved</b>
-Literal > Ò ¼ & & ሿ
-M & Ms - doesn't get escaped
-http://blah.com/?x=y&a=b - not escaped either
-'''
-
- expected = '''paragraph
-
-4 spaces before this
-
-\*blah\*
-
-here's a <tag> that should be <b>preserved</b>
-Literal &gt; &Ograve; &frac14; &amp; &\#38; &\#x123F;
-M & Ms - doesn't get escaped
-http://blah.com/?x=y&a=b - not escaped either
-'''
- # note: the \# isn't necessary it could be just # but that's the way
- # html2text escapes all #s currently. The extra escaping of \# ends up
- # being ok though when rendered
-
- from forgeblog.command import rssfeeds
-
- assert_equal(rssfeeds.plain2markdown(text), expected)
-
- assert_equal(rssfeeds.plain2markdown('a foo bar\n\n code here?', preserve_multiple_spaces=True),
- 'a foo bar\n\n code here?')
-
- assert_equal(rssfeeds.plain2markdown('\ttab before (stuff)', preserve_multiple_spaces=True),
- ' tab before \(stuff\)')
-
- assert_equal(rssfeeds.plain2markdown('\ttab before (stuff)', preserve_multiple_spaces=False),
- 'tab before \(stuff\)')
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/38c8c8ea/ForgeImporters/forgeimporters/google/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/__init__.py b/ForgeImporters/forgeimporters/google/__init__.py
index 90319cd..f60bc58 100644
--- a/ForgeImporters/forgeimporters/google/__init__.py
+++ b/ForgeImporters/forgeimporters/google/__init__.py
@@ -269,7 +269,7 @@ class Comment(object):
u'{updates}'
).format(
author=self.author,
- body=h.plain2markdown(self.body, True),
+ body=h.plain2markdown(self.body, preserve_multiple_spaces=True),
updates='\n'.join(
'**%s** %s' % (k,v)
for k,v in self.updates.items()
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/38c8c8ea/ForgeImporters/forgeimporters/google/tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tracker.py b/ForgeImporters/forgeimporters/google/tracker.py
index fefd695..3257c5a 100644
--- a/ForgeImporters/forgeimporters/google/tracker.py
+++ b/ForgeImporters/forgeimporters/google/tracker.py
@@ -96,7 +96,7 @@ class GoogleCodeTrackerImporter(ToolImporter):
u'{body}').format(
creator=issue.get_issue_creator(),
owner=owner_line,
- body=h.plain2markdown(issue.get_issue_description(), True),
+ body=h.plain2markdown(issue.get_issue_description(), preserve_multiple_spaces=True),
)
ticket.add_multiple_attachments(issue.get_issue_attachments())
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/38c8c8ea/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py b/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
index 206ac7c..7d67255 100644
--- a/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
+++ b/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
@@ -27,25 +27,13 @@ from pylons import tmpl_context as c
from IPython.testing.decorators import module_not_available, skipif
from alluratest.controller import setup_basic_test
+from allura.tests.decorators import without_module
from allura import model as M
from forgetracker import model as TM
from .... import google
from ....google import tracker
-def without_html2text(func):
- @wraps(func)
- def wrapped(*args, **kw):
- try:
- import html2text
- except ImportError:
- return func(*args, **kw)
- else:
- with mock.patch.object(html2text, 'escape_md_section') as ems:
- ems.side_effect = ImportError
- return func(*args, **kw)
- return wrapped
-
class TestGCTrackerImporter(TestCase):
def _make_extractor(self, html):
with mock.patch.object(google, 'urllib2') as urllib2:
@@ -85,7 +73,7 @@ class TestGCTrackerImporter(TestCase):
self.assertEqual(ticket.milestone, '')
self.assertEqual(ticket.custom_fields, {})
- @without_html2text
+ @without_module('html2text')
def test_issue_basic_fields(self):
anon = M.User.anonymous()
ticket = self._make_ticket(self.test_issue)
@@ -162,7 +150,7 @@ class TestGCTrackerImporter(TestCase):
('at2.txt', 'text/plain', 'http://allura-google-importer.googlecode.com/issues/attachment?aid=70000001&name=at2.txt&token=C9Hn4s1-g38hlSggRGo65VZM1ys%3A1376059941255'),
)
- @without_html2text
+ @without_module('html2text')
def test_comments(self):
anon = M.User.anonymous()
ticket = self._make_ticket(self.test_issue)
[04/16] git commit: [#6464] Refactored plain2markdown to Allura
helpers
Posted by jo...@apache.org.
[#6464] Refactored plain2markdown to Allura helpers
Signed-off-by: Cory Johns <cj...@slashdotmedia.com>
Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/67852feb
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/67852feb
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/67852feb
Branch: refs/heads/cj/6464
Commit: 67852feb0b9fe82ab6eeaf1783fbeb5d0810a5ee
Parents: 547cad2
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Thu Aug 8 18:49:51 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Fri Aug 16 22:20:59 2013 +0000
----------------------------------------------------------------------
Allura/allura/lib/helpers.py | 41 ++++++++++++++++++++++++++++
ForgeBlog/forgeblog/command/rssfeeds.py | 36 +-----------------------
2 files changed, 42 insertions(+), 35 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/67852feb/Allura/allura/lib/helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index 0511dc7..99a5d30 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -80,6 +80,26 @@ re_clean_vardec_key = re.compile(r'''\A
)+
\Z''', re.VERBOSE)
+# markdown escaping regexps
+re_amp = re.compile(r'''
+ [&] # amp
+ (?= # look ahead for:
+ ([a-zA-Z0-9]+;) # named HTML entity
+ |
+ (\#[0-9]+;) # decimal entity
+ |
+ (\#x[0-9A-F]+;) # hex entity
+ )
+ ''', re.VERBOSE)
+re_leading_spaces = re.compile(r'^[\t ]+', re.MULTILINE)
+re_preserve_spaces = re.compile(r'''
+ [ ] # space
+ (?=[ ]) # lookahead for a space
+ ''', re.VERBOSE)
+re_angle_bracket_open = re.compile('<')
+re_angle_bracket_close = re.compile('>')
+md_chars_matcher_all = re.compile(r"([`\*_{}\[\]\(\)#!\\.+-])")
+
def make_safe_path_portion(ustr, relaxed=True):
"""Return an ascii representation of ``ustr`` that conforms to mount point
naming :attr:`rules <re_tool_mount_point_fragment>`.
@@ -926,3 +946,24 @@ def urlopen(url, retries=3, codes=(408,)):
else:
log.exception('Failed after %s retries: %s', retries, e)
raise
+
+
+def plain2markdown(text, preserve_multiple_spaces=False, has_html_entities=False):
+ if not has_html_entities:
+ # prevent &foo; and { from becoming HTML entities
+ text = re_amp.sub('&', text)
+ # avoid accidental 4-space indentations creating code blocks
+ if preserve_multiple_spaces:
+ text = text.replace('\t', ' ' * 4)
+ text = re_preserve_spaces.sub(' ', text)
+ # try to use html2text for most of the escaping
+ import html2text
+ html2text.BODY_WIDTH = 0
+ text = html2text.escape_md_section(text, snob=True)
+ except ImportError:
+ # fall back to just escaping any MD-special chars
+ text = md_chars_matcher.sub(r"\\\\1", text)
+ # prevent < and > from becoming tags
+ text = re_angle_bracket_open.sub('<', text)
+ text = re_angle_bracket_close.sub('>', text)
+ return text
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/67852feb/ForgeBlog/forgeblog/command/rssfeeds.py
----------------------------------------------------------------------
diff --git a/ForgeBlog/forgeblog/command/rssfeeds.py b/ForgeBlog/forgeblog/command/rssfeeds.py
index 305bc5a..f4b5c75 100644
--- a/ForgeBlog/forgeblog/command/rssfeeds.py
+++ b/ForgeBlog/forgeblog/command/rssfeeds.py
@@ -34,6 +34,7 @@ from forgeblog import version
from forgeblog.main import ForgeBlogApp
from allura.lib import exceptions
from allura.lib.helpers import exceptionless
+from allura.lib.helpers import plain2markdown
## Everything in this file depends on html2text,
## so import attempt is placed in global scope.
@@ -45,41 +46,6 @@ except ImportError:
html2text.BODY_WIDTH = 0
-re_amp = re.compile(r'''
- [&] # amp
- (?= # look ahead for:
- ([a-zA-Z0-9]+;) # named HTML entity
- |
- (\#[0-9]+;) # decimal entity
- |
- (\#x[0-9A-F]+;) # hex entity
- )
- ''', re.VERBOSE)
-re_leading_spaces = re.compile(r'^[\t ]+', re.MULTILINE)
-re_preserve_spaces = re.compile(r'''
- [ ] # space
- (?=[ ]) # lookahead for a space
- ''', re.VERBOSE)
-re_angle_bracket_open = re.compile('<')
-re_angle_bracket_close = re.compile('>')
-def plain2markdown(text, preserve_multiple_spaces=False, has_html_entities=False):
- if not has_html_entities:
- # prevent &foo; and { from becoming HTML entities
- text = re_amp.sub('&', text)
- # avoid accidental 4-space indentations creating code blocks
- if preserve_multiple_spaces:
- text = text.replace('\t', ' ' * 4)
- text = re_preserve_spaces.sub(' ', text)
- else:
- text = re_leading_spaces.sub('', text)
- # use html2text for most of the escaping
- text = html2text.escape_md_section(text, snob=True)
- # prevent < and > from becoming tags
- text = re_angle_bracket_open.sub('<', text)
- text = re_angle_bracket_close.sub('>', text)
- return text
-
-
class RssFeedsCommand(base.BlogCommand):
summary = 'Rss feed client'
parser = base.BlogCommand.standard_parser(verbose=True)
[15/16] git commit: [#6464] Fixed issues from rebase
Posted by jo...@apache.org.
[#6464] Fixed issues from rebase
Signed-off-by: Cory Johns <cj...@slashdotmedia.com>
Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/123cb154
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/123cb154
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/123cb154
Branch: refs/heads/cj/6464
Commit: 123cb15447f9159f8bf3db38d13785e8f031049d
Parents: 3eab85b
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Wed Aug 14 16:26:53 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Fri Aug 16 22:21:00 2013 +0000
----------------------------------------------------------------------
ForgeImporters/forgeimporters/google/__init__.py | 7 ++-----
ForgeImporters/forgeimporters/google/tests/test_code.py | 4 +++-
.../forgeimporters/tests/google/test_extractor.py | 12 +++++++++---
.../forgeimporters/tests/google/test_tracker.py | 4 +++-
4 files changed, 17 insertions(+), 10 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/123cb154/ForgeImporters/forgeimporters/google/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/__init__.py b/ForgeImporters/forgeimporters/google/__init__.py
index 660853f..90319cd 100644
--- a/ForgeImporters/forgeimporters/google/__init__.py
+++ b/ForgeImporters/forgeimporters/google/__init__.py
@@ -79,7 +79,6 @@ class GoogleCodeProjectExtractor(ProjectExtractor):
DEFAULT_ICON = 'http://www.gstatic.com/codesite/ph/images/defaultlogo.png'
def __init__(self, project_name, page_name=None, **kw):
- self.url = self.PAGE_MAP[page_name].format(
self.project_name = project_name
self._page_cache = {}
self.url = None
@@ -105,7 +104,7 @@ class GoogleCodeProjectExtractor(ProjectExtractor):
if self.url in self._page_cache:
self.page = self._page_cache[self.url]
else:
- self.page = self._page_cache[page_name_or_url] = \
+ self.page = self._page_cache[self.url] = \
BeautifulSoup(self.urlopen(self.url))
return self.page
@@ -116,9 +115,7 @@ class GoogleCodeProjectExtractor(ProjectExtractor):
"""
return self.PAGE_MAP[page_name].format(
- project_name = urllib.quote(self.project_name),
- **kw,
- )
+ project_name = urllib.quote(self.project_name), **kw)
def get_short_description(self, project):
page = self.get_page('project_info')
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/123cb154/ForgeImporters/forgeimporters/google/tests/test_code.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tests/test_code.py b/ForgeImporters/forgeimporters/google/tests/test_code.py
index 13ec0c3..950246a 100644
--- a/ForgeImporters/forgeimporters/google/tests/test_code.py
+++ b/ForgeImporters/forgeimporters/google/tests/test_code.py
@@ -56,9 +56,10 @@ class TestGoogleRepoImporter(TestCase):
project.get_tool_data.side_effect = lambda *args: gc_proj_name
return project
+ @patch('forgeimporters.google.code.g')
@patch('forgeimporters.google.code.GoogleCodeProjectExtractor')
@patch('forgeimporters.google.code.get_repo_url')
- def test_import_tool_happy_path(self, get_repo_url, gcpe):
+ def test_import_tool_happy_path(self, get_repo_url, gcpe, g):
gcpe.return_value.get_repo_type.return_value = 'git'
get_repo_url.return_value = 'http://remote/clone/url/'
p = self._make_project(gc_proj_name='myproject')
@@ -70,6 +71,7 @@ class TestGoogleRepoImporter(TestCase):
mount_label='Code',
init_from_url='http://remote/clone/url/',
)
+ g.post_event.assert_called_once_with('project_updated')
class TestGoogleRepoImportController(TestController, TestCase):
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/123cb154/ForgeImporters/forgeimporters/tests/google/test_extractor.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/test_extractor.py b/ForgeImporters/forgeimporters/tests/google/test_extractor.py
index bac1750..7a485d6 100644
--- a/ForgeImporters/forgeimporters/tests/google/test_extractor.py
+++ b/ForgeImporters/forgeimporters/tests/google/test_extractor.py
@@ -45,14 +45,20 @@ class TestGoogleCodeProjectExtractor(TestCase):
self.assertEqual(extractor.page, self.soup.return_value)
def test_get_page(self):
- extractor = google.GoogleCodeProjectExtractor(self.project, 'my-project', 'project_info')
+ extractor = google.GoogleCodeProjectExtractor('my-project', 'project_info')
+ self.assertEqual(1, self.urlopen.call_count)
+ page = extractor.get_page('project_info')
self.assertEqual(1, self.urlopen.call_count)
+ self.assertEqual(page, extractor._page_cache['http://code.google.com/p/my-project/'])
page = extractor.get_page('project_info')
self.assertEqual(1, self.urlopen.call_count)
- self.assertEqual(page, extractor._page_cache['project_info'])
+ self.assertEqual(page, extractor._page_cache['http://code.google.com/p/my-project/'])
+ page = extractor.get_page('source_browse')
+ self.assertEqual(2, self.urlopen.call_count)
+ self.assertEqual(page, extractor._page_cache['http://code.google.com/p/my-project/source/browse/'])
def test_get_page_url(self):
- extractor = google.GoogleCodeProjectExtractor(self.project, 'my-project')
+ extractor = google.GoogleCodeProjectExtractor('my-project')
self.assertEqual(extractor.get_page_url('project_info'),
'http://code.google.com/p/my-project/')
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/123cb154/ForgeImporters/forgeimporters/tests/google/test_tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/test_tracker.py b/ForgeImporters/forgeimporters/tests/google/test_tracker.py
index 70ea3ad..15b8f33 100644
--- a/ForgeImporters/forgeimporters/tests/google/test_tracker.py
+++ b/ForgeImporters/forgeimporters/tests/google/test_tracker.py
@@ -24,13 +24,14 @@ from ...google import tracker
class TestTrackerImporter(TestCase):
+ @mock.patch.object(tracker, 'g')
@mock.patch.object(tracker, 'c')
@mock.patch.object(tracker, 'ThreadLocalORMSession')
@mock.patch.object(tracker, 'session')
@mock.patch.object(tracker, 'M')
@mock.patch.object(tracker, 'TM')
@mock.patch.object(tracker, 'GoogleCodeProjectExtractor')
- def test_import_tool(self, gpe, TM, M, session, tlos, c):
+ def test_import_tool(self, gpe, TM, M, session, tlos, c, g):
importer = tracker.GoogleCodeTrackerImporter()
importer.process_fields = mock.Mock()
importer.process_labels = mock.Mock()
@@ -70,6 +71,7 @@ class TestTrackerImporter(TestCase):
mock.call(tickets[0]),
mock.call(tickets[1]),
])
+ g.post_event.assert_called_once_with('project_updated')
def test_custom_fields(self):
importer = tracker.GoogleCodeTrackerImporter()
[06/16] git commit: [#6464] Changed tool_label on GC code importer
Posted by jo...@apache.org.
[#6464] Changed tool_label on GC code importer
Signed-off-by: Cory Johns <cj...@slashdotmedia.com>
Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/547cad28
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/547cad28
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/547cad28
Branch: refs/heads/cj/6464
Commit: 547cad28efff4ee0d63c00c63e76facd93132d2d
Parents: ef8ecc8
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Wed Aug 7 01:14:26 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Fri Aug 16 22:20:59 2013 +0000
----------------------------------------------------------------------
ForgeImporters/forgeimporters/google/code.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/547cad28/ForgeImporters/forgeimporters/google/code.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/code.py b/ForgeImporters/forgeimporters/google/code.py
index 2f8d19f..11dd7a6 100644
--- a/ForgeImporters/forgeimporters/google/code.py
+++ b/ForgeImporters/forgeimporters/google/code.py
@@ -105,7 +105,7 @@ class GoogleRepoImporter(ToolImporter):
""" Import a Google Code repo into a new SVN, Git, or Hg Allura tool.
"""
- extractor = GoogleCodeProjectExtractor(project, project_name, 'source_browse')
+ extractor = GoogleCodeProjectExtractor(project_name, 'source_browse')
repo_type = extractor.get_repo_type()
repo_url = get_repo_url(project_name, repo_type)
app = project.install_app(
[08/16] git commit: [#6464] Use plain2markdown to escape ticket
description and comments in GC Issues importer
Posted by jo...@apache.org.
[#6464] Use plain2markdown to escape ticket description and comments in GC Issues importer
Signed-off-by: Cory Johns <cj...@slashdotmedia.com>
Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/9e4d5073
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/9e4d5073
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/9e4d5073
Branch: refs/heads/cj/6464
Commit: 9e4d50737ec8be750bda481d6a10b5bf415b62ab
Parents: 67852fe
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Thu Aug 8 20:44:54 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Fri Aug 16 22:20:59 2013 +0000
----------------------------------------------------------------------
ForgeImporters/forgeimporters/google/tracker.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/9e4d5073/ForgeImporters/forgeimporters/google/tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tracker.py b/ForgeImporters/forgeimporters/google/tracker.py
index 297f65a..a997429 100644
--- a/ForgeImporters/forgeimporters/google/tracker.py
+++ b/ForgeImporters/forgeimporters/google/tracker.py
@@ -80,7 +80,7 @@ class GoogleCodeTrackerImporter(ToolImporter):
'{body}').format(
creator=issue.get_issue_creator(),
owner=issue.get_issue_owner(),
- body=issue.get_issue_description(),
+ body=h.plain2markdown(issue.get_issue_description(), True),
)
ticket.add_multiple_attachments(issue.get_issue_attachments())
@@ -108,7 +108,7 @@ class GoogleCodeTrackerImporter(ToolImporter):
'\n'
'{updates}').format(
author=comment.author,
- body=comment.body,
+ body=h.plain2markdown(comment.body, True),
updates='\n'.join(
'**%s** %s' % (k,v)
for k,v in comment.updates.items()
[05/16] git commit: [#6464] Google Code Tracker Importer via web
scraping
Posted by jo...@apache.org.
[#6464] Google Code Tracker Importer via web scraping
Signed-off-by: Cory Johns <cj...@slashdotmedia.com>
Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/ef8ecc85
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/ef8ecc85
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/ef8ecc85
Branch: refs/heads/cj/6464
Commit: ef8ecc85986996049d91603989747d3f6f14c0c7
Parents: 1c62317
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Tue Aug 6 23:47:14 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Fri Aug 16 22:20:59 2013 +0000
----------------------------------------------------------------------
Allura/allura/controllers/site_admin.py | 15 +-
.../allura/templates/site_admin_task_view.html | 8 +
.../forgeimporters/google/__init__.py | 176 ++++++++++++++---
ForgeImporters/forgeimporters/google/tasks.py | 8 +-
ForgeImporters/forgeimporters/google/tracker.py | 191 ++++---------------
.../tests/google/test_extractor.py | 19 +-
.../forgeimporters/tests/google/test_tasks.py | 8 +-
.../forgeimporters/tests/google/test_tracker.py | 98 +++++-----
8 files changed, 277 insertions(+), 246 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ef8ecc85/Allura/allura/controllers/site_admin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/site_admin.py b/Allura/allura/controllers/site_admin.py
index 4f8f835..50b0e38 100644
--- a/Allura/allura/controllers/site_admin.py
+++ b/Allura/allura/controllers/site_admin.py
@@ -30,6 +30,7 @@ import tg
from pylons import tmpl_context as c, app_globals as g
from pylons import request
from formencode import validators, Invalid
+from webob.exc import HTTPNotFound
from allura.lib import helpers as h
from allura.lib import validators as v
@@ -321,7 +322,19 @@ class TaskManagerController(object):
config_dict['user'] = user
with h.push_config(c, **config_dict):
task = task.post(*args, **kw)
- redirect('view/%s' % task._id)
+ redirect('../view/%s' % task._id)
+
+ @expose()
+ @require_post()
+ def resubmit(self, task_id):
+ try:
+ task = M.monq_model.MonQTask.query.get(_id=bson.ObjectId(task_id))
+ except bson.errors.InvalidId as e:
+ task = None
+ if task is None:
+ raise HTTPNotFound()
+ task.state = 'ready'
+ redirect('../view/%s' % task._id)
@expose('json:')
def task_doc(self, task_name):
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ef8ecc85/Allura/allura/templates/site_admin_task_view.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/site_admin_task_view.html b/Allura/allura/templates/site_admin_task_view.html
index c107382..e363b8d 100644
--- a/Allura/allura/templates/site_admin_task_view.html
+++ b/Allura/allura/templates/site_admin_task_view.html
@@ -66,6 +66,9 @@
#task_details td.second-column {
border: 0;
}
+ #resubmit-task-form {
+ float: right;
+ }
</style>
{% endblock %}
@@ -73,6 +76,11 @@
{% if not task %}
Task not found
{% else %}
+ {% if task.state in ['error', 'complete'] %}
+ <form id="resubmit-task-form" action="../resubmit/{{task._id}}" method="POST">
+ <input type="submit" value="Re-Submit Task" />
+ </form>
+ {% endif %}
<h2>Task Details</h2>
<table id="task_details">
<tr>
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ef8ecc85/ForgeImporters/forgeimporters/google/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/__init__.py b/ForgeImporters/forgeimporters/google/__init__.py
index a12389b..eaa0765 100644
--- a/ForgeImporters/forgeimporters/google/__init__.py
+++ b/ForgeImporters/forgeimporters/google/__init__.py
@@ -19,6 +19,7 @@ import re
import urllib
from urlparse import urlparse, urljoin
from collections import defaultdict
+from contextlib import closing
try:
from cStringIO import StringIO
except ImportError:
@@ -33,13 +34,32 @@ from forgeimporters.base import ProjectExtractor
log = logging.getLogger(__name__)
+def _as_text(node, chunks=None):
+ """
+ Similar to node.text, but preserves whitespace around tags,
+ and converts <br/>s to \n.
+ """
+ if chunks is None:
+ chunks = []
+ for n in node:
+ if isinstance(n, basestring):
+ chunks.append(n)
+ elif n.name == 'br':
+ chunks.append('\n')
+ else:
+ _as_text(n, chunks)
+ return ''.join(chunks)
+
+
class GoogleCodeProjectExtractor(ProjectExtractor):
BASE_URL = 'http://code.google.com'
RE_REPO_TYPE = re.compile(r'(svn|hg|git)')
PAGE_MAP = {
- 'project_info': BASE_URL + '/p/%s/',
- 'source_browse': BASE_URL + '/p/%s/source/browse/',
+ 'project_info': BASE_URL + '/p/{project_name}/',
+ 'source_browse': BASE_URL + '/p/{project_name}/source/browse/',
+ 'issues_csv': BASE_URL + '/p/{project_name}/issues/csv?can=1&colspec=ID&start={start}',
+ 'issue': BASE_URL + '/p/{project_name}/issues/detail?id={issue_id}',
}
LICENSE_MAP = defaultdict(lambda:'Other/Proprietary License', {
@@ -57,16 +77,16 @@ class GoogleCodeProjectExtractor(ProjectExtractor):
DEFAULT_ICON = 'http://www.gstatic.com/codesite/ph/images/defaultlogo.png'
- def __init__(self, allura_project, gc_project_name, page=None):
- self.project = allura_project
- self.gc_project_name = gc_project_name
+ def __init__(self, project_name, page_name=None, **kw):
+ self.url = self.PAGE_MAP[page_name].format(
+ self.project_name = project_name
self._page_cache = {}
self.url = None
self.page = None
- if page:
- self.get_page(page)
+ if page_name:
+ self.get_page(page_name, **kw)
- def get_page(self, page_name_or_url):
+ def get_page(self, page_name_or_url, **kw):
"""Return a Beautiful soup object for the given page name or url.
If a page name is provided, the associated url is looked up in
@@ -77,27 +97,33 @@ class GoogleCodeProjectExtractor(ProjectExtractor):
request.
"""
- if page_name_or_url in self._page_cache:
- return self._page_cache[page_name_or_url]
- self.url = (self.get_page_url(page_name_or_url) if page_name_or_url in
- self.PAGE_MAP else page_name_or_url)
- self.page = self._page_cache[page_name_or_url] = \
- BeautifulSoup(self.urlopen(self.url))
+ if page_name_or_url in self.PAGE_MAP:
+ self.url = self.get_page_url(page_name_or_url, **kw)
+ else:
+ self.url = page_name_or_url
+ if self.url in self._page_cache:
+ self.page = self._page_cache[self.url]
+ else:
+ self.page = self._page_cache[page_name_or_url] = \
+ BeautifulSoup(self.urlopen(self.url))
return self.page
- def get_page_url(self, page_name):
+ def get_page_url(self, page_name, **kw):
"""Return the url associated with ``page_name``.
Raises KeyError if ``page_name`` is not in :attr:`PAGE_MAP`.
"""
- return self.PAGE_MAP[page_name] % urllib.quote(self.gc_project_name)
+ return self.PAGE_MAP[page_name].format(
+ project_name = urllib.quote(self.project_name),
+ **kw,
+ )
- def get_short_description(self):
+ def get_short_description(self, project):
page = self.get_page('project_info')
- self.project.short_description = page.find(itemprop='description').string.strip()
+ project.short_description = page.find(itemprop='description').string.strip()
- def get_icon(self):
+ def get_icon(self, project):
page = self.get_page('project_info')
icon_url = urljoin(self.url, page.find(itemprop='image').attrMap['src'])
if icon_url == self.DEFAULT_ICON:
@@ -109,13 +135,13 @@ class GoogleCodeProjectExtractor(ProjectExtractor):
icon_name, fp,
fp_ish.info()['content-type'].split(';')[0], # strip off charset=x extra param,
square=True, thumbnail_size=(48,48),
- thumbnail_meta={'project_id': self.project._id, 'category': 'icon'})
+ thumbnail_meta={'project_id': project._id, 'category': 'icon'})
- def get_license(self):
+ def get_license(self, project):
page = self.get_page('project_info')
license = page.find(text='Code license').findNext().find('a').string.strip()
trove = M.TroveCategory.query.get(fullname=self.LICENSE_MAP[license])
- self.project.trove_license.append(trove._id)
+ project.trove_license.append(trove._id)
def get_repo_type(self):
page = self.get_page('source_browse')
@@ -128,3 +154,109 @@ class GoogleCodeProjectExtractor(ProjectExtractor):
return re_match.group(0)
else:
raise Exception("Unknown repo type: {0}".format(repo_type.text))
+
+ @classmethod
+ def _get_issue_ids_page(cls, project_name, start):
+ url = cls.PAGE_MAP['issues_csv'].format(project_name=project_name, start=start)
+ with closing(urllib2.urlopen(url)) as fp:
+ lines = fp.readlines()[1:] # skip CSV header
+ if not lines[-1].startswith('"'):
+ lines.pop() # skip "next page here" info footer
+ issue_ids = [line.strip('",\n') for line in lines]
+ return issue_ids
+
+ @classmethod
+ def iter_issues(cls, project_name):
+ """
+ Iterate over all issues for a project,
+ using paging to keep the responses reasonable.
+ """
+ start = 0
+ limit = 100
+
+ while True:
+ issue_ids = cls._get_issue_ids_page(project_name, start)
+ if len(issue_ids) <= 0:
+ return
+ for issue_id in issue_ids:
+ yield cls(project_name, 'issue', issue_id=issue_id)
+ start += limit
+
+ def get_issue_summary(self):
+ return self.page.find(id='issueheader').findAll('td', limit=2)[1].span.string.strip()
+
+ def get_issue_description(self):
+ return _as_text(self.page.find(id='hc0').pre)
+
+ def get_issue_created_date(self):
+ return self.page.find(id='hc0').find('span', 'date').get('title')
+
+ def get_issue_mod_date(self):
+ last_update = Comment(self.page.findAll('div', 'issuecomment')[-1])
+ return last_update.created_date
+
+ def get_issue_creator(self):
+ a = self.page.find(id='hc0').find('a', 'userlink')
+ return UserLink(a)
+
+ def get_issue_status(self):
+ return self.page.find(id='issuemeta').find('th', text=re.compile('Status:')).findNext().span.string.strip()
+
+ def get_issue_owner(self):
+ return UserLink(self.page.find(id='issuemeta').find('th', text=re.compile('Owner:')).findNext().a)
+
+ def get_issue_labels(self):
+ label_nodes = self.page.find(id='issuemeta').findAll('a', 'label')
+ return [_as_text(l) for l in label_nodes]
+
+ def get_issue_attachments(self):
+ attachments = self.page.find(id='hc0').find('div', 'attachments')
+ if attachments:
+ return map(Attachment, attachments.findAll('tr'))
+ else:
+ return []
+
+ def iter_comments(self):
+ for comment in self.page.findAll('div', 'issuecomment'):
+ yield Comment(comment)
+
+class UserLink(object):
+ def __init__(self, tag):
+ self.name = tag.string.strip()
+ self.link = urljoin(GoogleCodeProjectExtractor.BASE_URL, tag.get('href'))
+
+class Comment(object):
+ def __init__(self, tag):
+ self.author = UserLink(tag.find('span', 'author').find('a', 'userlink'))
+ self.created_date = tag.find('span', 'date').get('title')
+ self.body = _as_text(tag.find('pre'))
+ self._get_updates(tag)
+ self._get_attachments(tag)
+
+ def _get_updates(self, tag):
+ _updates = tag.find('div', 'updates')
+ if _updates:
+ _strings = _updates.findAll(text=True)
+ updates = (s.strip() for s in _strings if s.strip())
+ self.updates = {field: updates.next() for field in updates}
+ else:
+ self.updates = {}
+
+ def _get_attachments(self, tag):
+ attachments = tag.find('div', 'attachments')
+ if attachments:
+ self.attachments = map(Attachment, attachments.findAll('tr'))
+ else:
+ self.attachments = []
+
+class Attachment(object):
+ def __init__(self, tag):
+ self.filename = _as_text(tag).strip().split()[0]
+ self.url = urljoin(GoogleCodeProjectExtractor.BASE_URL, tag.a.get('href'))
+ self.type = None
+
+ @property
+ def file(self):
+ fp_ish = urllib2.urlopen(self.url)
+ fp = StringIO(fp_ish.read())
+ return fp
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ef8ecc85/ForgeImporters/forgeimporters/google/tasks.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tasks.py b/ForgeImporters/forgeimporters/google/tasks.py
index 968d9a9..69e7556 100644
--- a/ForgeImporters/forgeimporters/google/tasks.py
+++ b/ForgeImporters/forgeimporters/google/tasks.py
@@ -27,9 +27,9 @@ from . import GoogleCodeProjectExtractor
@task
def import_project_info(project_name):
- extractor = GoogleCodeProjectExtractor(c.project, project_name, 'project_info')
- extractor.get_short_description()
- extractor.get_icon()
- extractor.get_license()
+ extractor = GoogleCodeProjectExtractor(project_name, 'project_info')
+ extractor.get_short_description(c.project)
+ extractor.get_icon(c.project)
+ extractor.get_license(c.project)
ThreadLocalORMSession.flush_all()
g.post_event('project_updated')
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ef8ecc85/ForgeImporters/forgeimporters/google/tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tracker.py b/ForgeImporters/forgeimporters/google/tracker.py
index 95f53e4..297f65a 100644
--- a/ForgeImporters/forgeimporters/google/tracker.py
+++ b/ForgeImporters/forgeimporters/google/tracker.py
@@ -19,15 +19,14 @@ from collections import defaultdict
from datetime import datetime
from pylons import tmpl_context as c
-#import gdata
-gdata = None
-from ming.orm import session
+from ming.orm import session, ThreadLocalORMSession
from allura.lib import helpers as h
from forgetracker.tracker_main import ForgeTrackerApp
from forgetracker import model as TM
from ..base import ToolImporter
+from . import GoogleCodeProjectExtractor
class GoogleCodeTrackerImporter(ToolImporter):
@@ -42,23 +41,22 @@ class GoogleCodeTrackerImporter(ToolImporter):
type='select',
)
- def import_tool(self, project, user, project_name=None, mount_point=None,
+ def import_tool(self, project, user, project_name, mount_point=None,
mount_label=None, **kw):
- c.app = project.install_app('tracker', mount_point, mount_label)
- c.app.globals.open_status_names = ['New', 'Accepted', 'Started']
- c.app.globals.closed_status_names = ['Fixed', 'Verified', 'Invalid', 'Duplicate', 'WontFix', 'Done']
+ c.app = project.install_app('tickets', mount_point, mount_label)
+ ThreadLocalORMSession.flush_all()
+ c.app.globals.open_status_names = 'New Accepted Started'
+ c.app.globals.closed_status_names = 'Fixed Verified Invalid Duplicate WontFix Done'
self.custom_fields = {}
- extractor = GDataAPIExtractor(project_name)
- for issue in extractor.iter_issues():
+ for issue in GoogleCodeProjectExtractor.iter_issues(project_name):
ticket = TM.Ticket.new()
self.process_fields(ticket, issue)
self.process_labels(ticket, issue)
- self.process_comments(ticket, extractor.iter_comments(issue))
+ self.process_comments(ticket, issue)
session(ticket).flush(ticket)
session(ticket).expunge(ticket)
self.postprocess_custom_fields()
- session(c.app).flush(c.app)
- session(c.app.globals).flush(c.app.globals)
+ ThreadLocalORMSession.flush_all()
def custom_field(self, name):
if name not in self.custom_fields:
@@ -71,16 +69,25 @@ class GoogleCodeTrackerImporter(ToolImporter):
return self.custom_fields[name]
def process_fields(self, ticket, issue):
- ticket.summary = issue.summary
- ticket.description = issue.description
- ticket.status = issue.status
- ticket.created_date = datetime.strptime(issue.created_date, '')
- ticket.mod_date = datetime.strptime(issue.mod_date, '')
+ ticket.summary = issue.get_issue_summary()
+ ticket.status = issue.get_issue_status()
+ ticket.created_date = datetime.strptime(issue.get_issue_created_date(), '%c')
+ ticket.mod_date = datetime.strptime(issue.get_issue_mod_date(), '%c')
+ ticket.description = (
+ u'*Originally created by:* [{creator.name}]({creator.link})\n'
+ '*Originally owned by:* [{owner.name}]({owner.link})\n'
+ '\n'
+ '{body}').format(
+ creator=issue.get_issue_creator(),
+ owner=issue.get_issue_owner(),
+ body=issue.get_issue_description(),
+ )
+ ticket.add_multiple_attachments(issue.get_issue_attachments())
def process_labels(self, ticket, issue):
labels = set()
custom_fields = defaultdict(set)
- for label in issue.labels:
+ for label in issue.get_issue_labels():
if u'-' in label:
name, value = label.split(u'-', 1)
cf = self.custom_field(name)
@@ -91,23 +98,24 @@ class GoogleCodeTrackerImporter(ToolImporter):
ticket.labels = list(labels)
ticket.custom_fields = {n: u', '.join(sorted(v)) for n,v in custom_fields.iteritems()}
- def process_comments(self, ticket, comments):
- for comment in comments:
- p = ticket.thread.add_post(
+ def process_comments(self, ticket, issue):
+ for comment in issue.iter_comments():
+ p = ticket.discussion_thread.add_post(
text = (
- u'Originally posted by: [{author.name}]({author.link})\n'
+ u'*Originally posted by:* [{author.name}]({author.link})\n'
'\n'
'{body}\n'
'\n'
'{updates}').format(
author=comment.author,
- body=comment.text,
+ body=comment.body,
updates='\n'.join(
- '*%s*: %s' % (k,v)
+ '**%s** %s' % (k,v)
for k,v in comment.updates.items()
),
)
)
+ p.created_date = p.timestamp = datetime.strptime(comment.created_date, '%c')
p.add_multiple_attachments(comment.attachments)
def postprocess_custom_fields(self):
@@ -125,138 +133,3 @@ class GoogleCodeTrackerImporter(ToolImporter):
else:
field['options'] = ''
c.app.globals.custom_fields.append(field)
-
-
-class GDataAPIExtractor(object):
- def __init__(self, project_name):
- self.project_name = project_name
-
- def iter_issues(self, limit=50):
- """
- Iterate over all issues for a project,
- using paging to keep the responses reasonable.
- """
- start = 1
-
- client = gdata.projecthosting.client.ProjectHostingClient()
- while True:
- query = gdata.projecthosting.client.Query(start_index=start, max_results=limit)
- issues = client.get_issues(self.project_name, query=query).entry
- if len(issues) <= 0:
- return
- for issue in issues:
- yield GDataAPIIssue(issue)
- start += limit
-
- def iter_comments(self, issue, limit=50):
- """
- Iterate over all comments for a given issue,
- using paging to keep the responses reasonable.
- """
- start = 1
-
- client = gdata.projecthosting.client.ProjectHostingClient()
- while True:
- query = gdata.projecthosting.client.Query(start_index=start, max_results=limit)
- comments = client.get_comments(self.project_name, query=query).entry
- if len(comments) <= 0:
- return
- for comment in comments:
- yield GDataAPIComment(comment)
- start += limit
-
-
-class GDataAPIUser(object):
- def __init__(self, user):
- self.user = user
-
- @property
- def name(self):
- return h.really_unicode(self.user.name.text)
-
- @property
- def link(self):
- return u'http://code.google.com/u/%s' % self.name
-
-
-class GDataAPIIssue(object):
- def __init__(self, issue):
- self.issue = issue
-
- @property
- def summary(self):
- return h.really_unicode(self.issue.title.text)
-
- @property
- def description(self):
- return h.really_unicode(self.issue.content.text)
-
- @property
- def created_date(self):
- return self.to_date(self.issue.published.text)
-
- @property
- def mod_date(self):
- return self.to_date(self.issue.updated.text)
-
- @property
- def creator(self):
- return h.really_unicode(self.issue.author[0].name.text)
-
- @property
- def status(self):
- if getattr(self.issue, 'status', None) is not None:
- return h.really_unicode(self.issue.status.text)
- return u''
-
- @property
- def owner(self):
- if getattr(self.issue, 'owner', None) is not None:
- return h.really_unicode(self.issue.owner.username.text)
- return u''
-
- @property
- def labels(self):
- return [h.really_unicode(l.text) for l in self.issue.labels]
-
-
-class GDataAPIComment(object):
- def __init__(self, comment):
- self.comment = comment
-
- @property
- def author(self):
- return GDataAPIUser(self.comment.author[0])
-
- @property
- def created_date(self):
- return h.really_unicode(self.comment.published.text)
-
- @property
- def body(self):
- return h.really_unicode(self.comment.content.text)
-
- @property
- def updates(self):
- return {}
-
- @property
- def attachments(self):
- return []
-
-
-class GDataAPIAttachment(object):
- def __init__(self, attachment):
- self.attachment = attachment
-
- @property
- def filename(self):
- pass
-
- @property
- def type(self):
- pass
-
- @property
- def file(self):
- pass
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ef8ecc85/ForgeImporters/forgeimporters/tests/google/test_extractor.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/test_extractor.py b/ForgeImporters/forgeimporters/tests/google/test_extractor.py
index 9b6db45..89aac5a 100644
--- a/ForgeImporters/forgeimporters/tests/google/test_extractor.py
+++ b/ForgeImporters/forgeimporters/tests/google/test_extractor.py
@@ -37,10 +37,9 @@ class TestGoogleCodeProjectExtractor(TestCase):
self._p_soup.stop()
def test_init(self):
- extractor = google.GoogleCodeProjectExtractor(self.project, 'my-project', 'project_info')
+ extractor = google.GoogleCodeProjectExtractor('my-project', 'project_info')
self.urlopen.assert_called_once_with('http://code.google.com/p/my-project/')
- self.assertEqual(extractor.project, self.project)
self.soup.assert_called_once_with(self.urlopen.return_value)
self.assertEqual(extractor.page, self.soup.return_value)
@@ -57,10 +56,10 @@ class TestGoogleCodeProjectExtractor(TestCase):
'http://code.google.com/p/my-project/')
def test_get_short_description(self):
- extractor = google.GoogleCodeProjectExtractor(self.project, 'my-project', 'project_info')
+ extractor = google.GoogleCodeProjectExtractor('my-project', 'project_info')
extractor.page.find.return_value.string = 'My Super Project'
- extractor.get_short_description()
+ extractor.get_short_description(self.project)
extractor.page.find.assert_called_once_with(itemprop='description')
self.assertEqual(self.project.short_description, 'My Super Project')
@@ -69,11 +68,11 @@ class TestGoogleCodeProjectExtractor(TestCase):
@mock.patch.object(google, 'M')
def test_get_icon(self, M, StringIO):
self.urlopen.return_value.info.return_value = {'content-type': 'image/png'}
- extractor = google.GoogleCodeProjectExtractor(self.project, 'my-project', 'project_info')
+ extractor = google.GoogleCodeProjectExtractor('my-project', 'project_info')
extractor.page.find.return_value.attrMap = {'src': 'http://example.com/foo/bar/my-logo.png'}
self.urlopen.reset_mock()
- extractor.get_icon()
+ extractor.get_icon(self.project)
extractor.page.find.assert_called_once_with(itemprop='image')
self.urlopen.assert_called_once_with('http://example.com/foo/bar/my-logo.png')
@@ -87,11 +86,11 @@ class TestGoogleCodeProjectExtractor(TestCase):
@mock.patch.object(google, 'M')
def test_get_license(self, M):
self.project.trove_license = []
- extractor = google.GoogleCodeProjectExtractor(self.project, 'my-project', 'project_info')
+ extractor = google.GoogleCodeProjectExtractor('my-project', 'project_info')
extractor.page.find.return_value.findNext.return_value.find.return_value.string = ' New BSD License '
trove = M.TroveCategory.query.get.return_value
- extractor.get_license()
+ extractor.get_license(self.project)
extractor.page.find.assert_called_once_with(text='Code license')
extractor.page.find.return_value.findNext.assert_called_once_with()
@@ -101,13 +100,13 @@ class TestGoogleCodeProjectExtractor(TestCase):
M.TroveCategory.query.get.reset_mock()
extractor.page.find.return_value.findNext.return_value.find.return_value.string = 'non-existant license'
- extractor.get_license()
+ extractor.get_license(self.project)
M.TroveCategory.query.get.assert_called_once_with(fullname='Other/Proprietary License')
def _make_extractor(self, html):
from BeautifulSoup import BeautifulSoup
with mock.patch.object(base.ProjectExtractor, 'urlopen'):
- extractor = google.GoogleCodeProjectExtractor(self.project, 'my-project')
+ extractor = google.GoogleCodeProjectExtractor('my-project')
extractor.page = BeautifulSoup(html)
extractor.get_page = lambda pagename: extractor.page
extractor.url="http://test/source/browse"
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ef8ecc85/ForgeImporters/forgeimporters/tests/google/test_tasks.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/test_tasks.py b/ForgeImporters/forgeimporters/tests/google/test_tasks.py
index dc7d936..01bab68 100644
--- a/ForgeImporters/forgeimporters/tests/google/test_tasks.py
+++ b/ForgeImporters/forgeimporters/tests/google/test_tasks.py
@@ -26,8 +26,8 @@ from ...google import tasks
def test_import_project_info(c, session, gpe):
c.project = mock.Mock(name='project')
tasks.import_project_info('my-project')
- gpe.assert_called_once_with(c.project, 'my-project', 'project_info')
- gpe.return_value.get_short_description.assert_called_once_with()
- gpe.return_value.get_icon.assert_called_once_with()
- gpe.return_value.get_license.assert_called_once_with()
+ gpe.assert_called_once_with('my-project', 'project_info')
+ gpe.return_value.get_short_description.assert_called_once_with(c.project)
+ gpe.return_value.get_icon.assert_called_once_with(c.project)
+ gpe.return_value.get_license.assert_called_once_with(c.project)
session.flush_all.assert_called_once_with()
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/ef8ecc85/ForgeImporters/forgeimporters/tests/google/test_tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/test_tracker.py b/ForgeImporters/forgeimporters/tests/google/test_tracker.py
index e49f279..62493bd 100644
--- a/ForgeImporters/forgeimporters/tests/google/test_tracker.py
+++ b/ForgeImporters/forgeimporters/tests/google/test_tracker.py
@@ -15,6 +15,7 @@
# specific language governing permissions and limitations
# under the License.
+from datetime import datetime
from operator import itemgetter
from unittest import TestCase
import mock
@@ -24,10 +25,11 @@ from ...google import tracker
class TestTrackerImporter(TestCase):
@mock.patch.object(tracker, 'c')
+ @mock.patch.object(tracker, 'ThreadLocalORMSession')
@mock.patch.object(tracker, 'session')
@mock.patch.object(tracker, 'TM')
- @mock.patch.object(tracker, 'GDataAPIExtractor')
- def test_import_tool(self, gdata, TM, session, c):
+ @mock.patch.object(tracker, 'GoogleCodeProjectExtractor')
+ def test_import_tool(self, gpe, TM, session, tlos, c):
importer = tracker.GoogleCodeTrackerImporter()
importer.process_fields = mock.Mock()
importer.process_labels = mock.Mock()
@@ -35,16 +37,14 @@ class TestTrackerImporter(TestCase):
importer.postprocess_custom_fields = mock.Mock()
project, user = mock.Mock(), mock.Mock()
app = project.install_app.return_value
- extractor = gdata.return_value
- issues = extractor.iter_issues.return_value = [mock.Mock(), mock.Mock()]
+ issues = gpe.iter_issues.return_value = [mock.Mock(), mock.Mock()]
tickets = TM.Ticket.new.side_effect = [mock.Mock(), mock.Mock()]
- comments = extractor.iter_comments.side_effect = [mock.Mock(), mock.Mock()]
importer.import_tool(project, user, project_name='project_name',
mount_point='mount_point', mount_label='mount_label')
- project.install_app.assert_called_once_with('tracker', 'mount_point', 'mount_label')
- gdata.assert_called_once_with('project_name')
+ project.install_app.assert_called_once_with('tickets', 'mount_point', 'mount_label')
+ gpe.iter_issues.assert_called_once_with('project_name')
self.assertEqual(importer.process_fields.call_args_list, [
mock.call(tickets[0], issues[0]),
mock.call(tickets[1], issues[1]),
@@ -54,26 +54,16 @@ class TestTrackerImporter(TestCase):
mock.call(tickets[1], issues[1]),
])
self.assertEqual(importer.process_comments.call_args_list, [
- mock.call(tickets[0], comments[0]),
- mock.call(tickets[1], comments[1]),
+ mock.call(tickets[0], issues[0]),
+ mock.call(tickets[1], issues[1]),
])
- self.assertEqual(extractor.iter_comments.call_args_list, [
- mock.call(issues[0]),
- mock.call(issues[1]),
- ])
- self.assertEqual(session.call_args_list, [
- mock.call(tickets[0]),
- mock.call(tickets[0]),
- mock.call(tickets[1]),
- mock.call(tickets[1]),
- mock.call(app),
- mock.call(app.globals),
+ self.assertEqual(tlos.flush_all.call_args_list, [
+ mock.call(),
+ mock.call(),
])
self.assertEqual(session.return_value.flush.call_args_list, [
mock.call(tickets[0]),
mock.call(tickets[1]),
- mock.call(app),
- mock.call(app.globals),
])
self.assertEqual(session.return_value.expunge.call_args_list, [
mock.call(tickets[0]),
@@ -119,30 +109,37 @@ class TestTrackerImporter(TestCase):
def test_process_fields(self):
ticket = mock.Mock()
+ def _user(l):
+ u = mock.Mock()
+ u.name = '%sname' % l
+ u.link = '%slink' % l
+ return u
issue = mock.Mock(
- summary='summary',
- description='description',
- status='status',
- created_date='created_date',
- mod_date='mod_date',
+ get_issue_summary=lambda:'summary',
+ get_issue_description=lambda:'description',
+ get_issue_status=lambda:'status',
+ get_issue_created_date=lambda:'created_date',
+ get_issue_mod_date=lambda:'mod_date',
+ get_issue_creator=lambda:_user('c'),
+ get_issue_owner=lambda:_user('o'),
)
importer = tracker.GoogleCodeTrackerImporter()
with mock.patch.object(tracker, 'datetime') as dt:
dt.strptime.side_effect = lambda s,f: s
importer.process_fields(ticket, issue)
self.assertEqual(ticket.summary, 'summary')
- self.assertEqual(ticket.description, 'description')
+ self.assertEqual(ticket.description, '*Originally created by:* [cname](clink)\n*Originally owned by:* [oname](olink)\n\ndescription')
self.assertEqual(ticket.status, 'status')
self.assertEqual(ticket.created_date, 'created_date')
self.assertEqual(ticket.mod_date, 'mod_date')
self.assertEqual(dt.strptime.call_args_list, [
- mock.call('created_date', ''),
- mock.call('mod_date', ''),
+ mock.call('created_date', '%c'),
+ mock.call('mod_date', '%c'),
])
def test_process_labels(self):
ticket = mock.Mock(custom_fields={}, labels=[])
- issue = mock.Mock(labels=['Foo-Bar', 'Baz', 'Foo-Qux'])
+ issue = mock.Mock(get_issue_labels=lambda:['Foo-Bar', 'Baz', 'Foo-Qux'])
importer = tracker.GoogleCodeTrackerImporter()
importer.custom_field = mock.Mock(side_effect=lambda n: {'name': '_%s' % n.lower(), 'options': set()})
importer.process_labels(ticket, issue)
@@ -156,40 +153,49 @@ class TestTrackerImporter(TestCase):
a.link = 'author%s_link' % n
return a
ticket = mock.Mock()
- comments = [
+ issue = mock.Mock()
+ comments = issue.iter_comments.return_value = [
mock.Mock(
author=_author(1),
- text='text1',
+ body='text1',
attachments='attachments1',
+ created_date='Mon Jul 15 00:00:00 2013',
),
mock.Mock(
author=_author(2),
- text='text2',
+ body='text2',
attachments='attachments2',
+ created_date='Mon Jul 16 00:00:00 2013',
),
]
- comments[0].updates.items.return_value = [('Foo', 'Bar'), ('Baz', 'Qux')]
+ comments[0].updates.items.return_value = [('Foo:', 'Bar'), ('Baz:', 'Qux')]
comments[1].updates.items.return_value = []
+ posts = ticket.discussion_thread.add_post.side_effect = [
+ mock.Mock(),
+ mock.Mock(),
+ ]
importer = tracker.GoogleCodeTrackerImporter()
- importer.process_comments(ticket, comments)
- self.assertEqual(ticket.thread.add_post.call_args_list[0], mock.call(
- text='Originally posted by: [author1](author1_link)\n'
+ importer.process_comments(ticket, issue)
+ self.assertEqual(ticket.discussion_thread.add_post.call_args_list[0], mock.call(
+ text='*Originally posted by:* [author1](author1_link)\n'
'\n'
'text1\n'
'\n'
- '*Foo*: Bar\n'
- '*Baz*: Qux'
+ '**Foo:** Bar\n'
+ '**Baz:** Qux'
))
- self.assertEqual(ticket.thread.add_post.call_args_list[1], mock.call(
- text='Originally posted by: [author2](author2_link)\n'
+ self.assertEqual(posts[0].created_date, datetime(2013, 7, 15))
+ self.assertEqual(posts[0].timestamp, datetime(2013, 7, 15))
+ posts[0].add_multiple_attachments.assert_called_once_with('attachments1')
+ self.assertEqual(ticket.discussion_thread.add_post.call_args_list[1], mock.call(
+ text='*Originally posted by:* [author2](author2_link)\n'
'\n'
'text2\n'
'\n'
))
- self.assertEqual(ticket.thread.add_post.return_value.add_multiple_attachments.call_args_list, [
- mock.call('attachments1'),
- mock.call('attachments2'),
- ])
+ self.assertEqual(posts[1].created_date, datetime(2013, 7, 16))
+ self.assertEqual(posts[1].timestamp, datetime(2013, 7, 16))
+ posts[1].add_multiple_attachments.assert_called_once_with('attachments2')
@mock.patch.object(tracker, 'c')
def test_postprocess_custom_fields(self, c):
[07/16] git commit: [#6464] Added skip_mod_date to GC tracker importer
Posted by jo...@apache.org.
[#6464] Added skip_mod_date to GC tracker importer
Signed-off-by: Cory Johns <cj...@slashdotmedia.com>
Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/92223433
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/92223433
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/92223433
Branch: refs/heads/cj/6464
Commit: 9222343379c48fac96a52bb886dee762f2c54870
Parents: 9e4d507
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Thu Aug 8 21:10:24 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Fri Aug 16 22:20:59 2013 +0000
----------------------------------------------------------------------
ForgeImporters/forgeimporters/google/tracker.py | 23 ++++++++++++--------
1 file changed, 14 insertions(+), 9 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/92223433/ForgeImporters/forgeimporters/google/tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tracker.py b/ForgeImporters/forgeimporters/google/tracker.py
index a997429..bd3a57f 100644
--- a/ForgeImporters/forgeimporters/google/tracker.py
+++ b/ForgeImporters/forgeimporters/google/tracker.py
@@ -21,6 +21,7 @@ from datetime import datetime
from pylons import tmpl_context as c
from ming.orm import session, ThreadLocalORMSession
+from allura import model as M
from allura.lib import helpers as h
from forgetracker.tracker_main import ForgeTrackerApp
@@ -48,15 +49,19 @@ class GoogleCodeTrackerImporter(ToolImporter):
c.app.globals.open_status_names = 'New Accepted Started'
c.app.globals.closed_status_names = 'Fixed Verified Invalid Duplicate WontFix Done'
self.custom_fields = {}
- for issue in GoogleCodeProjectExtractor.iter_issues(project_name):
- ticket = TM.Ticket.new()
- self.process_fields(ticket, issue)
- self.process_labels(ticket, issue)
- self.process_comments(ticket, issue)
- session(ticket).flush(ticket)
- session(ticket).expunge(ticket)
- self.postprocess_custom_fields()
- ThreadLocalORMSession.flush_all()
+ try:
+ M.session.artifact_orm_session._get().skip_mod_date = True
+ for issue in GoogleCodeProjectExtractor.iter_issues(project_name):
+ ticket = TM.Ticket.new()
+ self.process_fields(ticket, issue)
+ self.process_labels(ticket, issue)
+ self.process_comments(ticket, issue)
+ session(ticket).flush(ticket)
+ session(ticket).expunge(ticket)
+ self.postprocess_custom_fields()
+ ThreadLocalORMSession.flush_all()
+ finally:
+ M.session.artifact_orm_session._get().skip_mod_date = False
def custom_field(self, name):
if name not in self.custom_fields:
[12/16] git commit: [#6464] Fixed test failing due to refactor
Posted by jo...@apache.org.
[#6464] Fixed test failing due to refactor
Signed-off-by: Cory Johns <cj...@slashdotmedia.com>
Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/3eab85b7
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/3eab85b7
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/3eab85b7
Branch: refs/heads/cj/6464
Commit: 3eab85b71cc64ebe1686f7bfdd462327399b2c39
Parents: 36cf1a2
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Tue Aug 13 14:07:38 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Fri Aug 16 22:21:00 2013 +0000
----------------------------------------------------------------------
ForgeImporters/forgeimporters/tests/google/test_tracker.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/3eab85b7/ForgeImporters/forgeimporters/tests/google/test_tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/test_tracker.py b/ForgeImporters/forgeimporters/tests/google/test_tracker.py
index 3efd97d..70ea3ad 100644
--- a/ForgeImporters/forgeimporters/tests/google/test_tracker.py
+++ b/ForgeImporters/forgeimporters/tests/google/test_tracker.py
@@ -212,8 +212,8 @@ class TestTrackerImporter(TestCase):
'options': set(['foo', 'bar']),
},
}
- importer.postprocess_custom_fields()
- self.assertEqual(sorted(c.app.globals.custom_fields, key=itemgetter('name')), [
+ custom_fields = importer.postprocess_custom_fields()
+ self.assertItemsEqual(custom_fields, [
{
'name': '_foo',
'type': 'string',
[16/16] git commit: [#6464] Handle non-linked Google users in tracker
import
Posted by jo...@apache.org.
[#6464] Handle non-linked Google users in tracker import
Signed-off-by: Cory Johns <cj...@slashdotmedia.com>
Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/8facbc5e
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/8facbc5e
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/8facbc5e
Branch: refs/heads/cj/6464
Commit: 8facbc5e2ada555bca0a92b0b322fcb05c6fb23d
Parents: 3c9bc57
Author: Cory Johns <cj...@slashdotmedia.com>
Authored: Fri Aug 16 20:02:17 2013 +0000
Committer: Cory Johns <cj...@slashdotmedia.com>
Committed: Fri Aug 16 22:21:00 2013 +0000
----------------------------------------------------------------------
.../forgeimporters/google/__init__.py | 19 +++++++++----
ForgeImporters/forgeimporters/google/tracker.py | 4 +--
.../tests/data/google/empty-issue.html | 2 +-
.../tests/google/functional/test_tracker.py | 2 +-
.../tests/google/test_extractor.py | 29 +++++++++++++++-----
.../forgeimporters/tests/google/test_tracker.py | 11 ++------
6 files changed, 43 insertions(+), 24 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8facbc5e/ForgeImporters/forgeimporters/google/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/__init__.py b/ForgeImporters/forgeimporters/google/__init__.py
index 7234dc8..22be7c2 100644
--- a/ForgeImporters/forgeimporters/google/__init__.py
+++ b/ForgeImporters/forgeimporters/google/__init__.py
@@ -198,7 +198,7 @@ class GoogleCodeProjectExtractor(ProjectExtractor):
return self.get_issue_created_date()
def get_issue_creator(self):
- a = self.page.find(id='hc0').find('a', 'userlink')
+ a = self.page.find(id='hc0').find(True, 'userlink')
return UserLink(a)
def get_issue_status(self):
@@ -209,7 +209,7 @@ class GoogleCodeProjectExtractor(ProjectExtractor):
return ''
def get_issue_owner(self):
- tag = self.page.find(id='issuemeta').find('th', text=re.compile('Owner:')).findNext().a
+ tag = self.page.find(id='issuemeta').find('th', text=re.compile('Owner:')).findNext().find(True, 'userlink')
if tag:
return UserLink(tag)
else:
@@ -233,11 +233,20 @@ class GoogleCodeProjectExtractor(ProjectExtractor):
class UserLink(object):
def __init__(self, tag):
self.name = tag.string.strip()
- self.link = urljoin(GoogleCodeProjectExtractor.BASE_URL, tag.get('href'))
+ if 'href' in tag.attrMap:
+ self.url = urljoin(GoogleCodeProjectExtractor.BASE_URL, tag.attrMap['href'])
+ else:
+ self.url = None
+
+ def __str__(self):
+ if self.url:
+ return '[{name}]({url})'.format(name = self.name, url = self.url)
+ else:
+ return self.name
class Comment(object):
def __init__(self, tag):
- self.author = UserLink(tag.find('span', 'author').find('a', 'userlink'))
+ self.author = UserLink(tag.find('span', 'author').find(True, 'userlink'))
self.created_date = tag.find('span', 'date').get('title')
self.body = _as_text(tag.find('pre')).strip()
self._get_updates(tag)
@@ -262,7 +271,7 @@ class Comment(object):
@property
def annotated_text(self):
text = (
- u'*Originally posted by:* [{author.name}]({author.link})\n'
+ u'*Originally posted by:* {author}\n'
u'\n'
u'{body}\n'
u'\n'
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8facbc5e/ForgeImporters/forgeimporters/google/tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/tracker.py b/ForgeImporters/forgeimporters/google/tracker.py
index 3257c5a..3d9843c 100644
--- a/ForgeImporters/forgeimporters/google/tracker.py
+++ b/ForgeImporters/forgeimporters/google/tracker.py
@@ -86,11 +86,11 @@ class GoogleCodeTrackerImporter(ToolImporter):
ticket.mod_date = datetime.strptime(issue.get_issue_mod_date(), '%c')
owner = issue.get_issue_owner()
if owner:
- owner_line = '*Originally owned by:* [{owner.name}]({owner.link})\n'.format(owner=owner)
+ owner_line = '*Originally owned by:* {owner}\n'.format(owner=owner)
else:
owner_line = ''
ticket.description = (
- u'*Originally created by:* [{creator.name}]({creator.link})\n'
+ u'*Originally created by:* {creator}\n'
u'{owner}'
u'\n'
u'{body}').format(
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8facbc5e/ForgeImporters/forgeimporters/tests/data/google/empty-issue.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/data/google/empty-issue.html b/ForgeImporters/forgeimporters/tests/data/google/empty-issue.html
index a8fb1d5..b2eef20 100644
--- a/ForgeImporters/forgeimporters/tests/data/google/empty-issue.html
+++ b/ForgeImporters/forgeimporters/tests/data/google/empty-issue.html
@@ -240,7 +240,7 @@ contributes to open source, such as <a href="http://www.firefox.com">Firefox</a>
Reported by
- <a class="userlink" href="/u/101557263855536553789/">john...@gmail.com</a>,
+ <span class="userlink">john...@gmail.com</span>,
<span class="date" title="Thu Aug 8 14:56:23 2013">Today (15 minutes ago)</span>
</div>
<pre>
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8facbc5e/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py b/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
index 62c4453..80a8747 100644
--- a/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
+++ b/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
@@ -70,7 +70,7 @@ class TestGCTrackerImporter(TestCase):
def test_empty_issue(self):
ticket = self._make_ticket(self.empty_issue)
self.assertEqual(ticket.summary, 'Empty Issue')
- self.assertEqual(ticket.description, '*Originally created by:* [john...@gmail.com](http://code.google.com/u/101557263855536553789/)\n\nEmpty')
+ self.assertEqual(ticket.description, '*Originally created by:* john...@gmail.com\n\nEmpty')
self.assertEqual(ticket.status, '')
self.assertEqual(ticket.milestone, '')
self.assertEqual(ticket.custom_fields, {})
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8facbc5e/ForgeImporters/forgeimporters/tests/google/test_extractor.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/test_extractor.py b/ForgeImporters/forgeimporters/tests/google/test_extractor.py
index 7a485d6..4157c98 100644
--- a/ForgeImporters/forgeimporters/tests/google/test_extractor.py
+++ b/ForgeImporters/forgeimporters/tests/google/test_extractor.py
@@ -152,9 +152,9 @@ class TestGoogleCodeProjectExtractor(TestCase):
test_issue = open(pkg_resources.resource_filename('forgeimporters', 'tests/data/google/test-issue.html')).read()
gpe = self._make_extractor(test_issue)
self.assertEqual(gpe.get_issue_creator().name, 'john...@gmail.com')
- self.assertEqual(gpe.get_issue_creator().link, 'http://code.google.com/u/101557263855536553789/')
+ self.assertEqual(gpe.get_issue_creator().url, 'http://code.google.com/u/101557263855536553789/')
self.assertEqual(gpe.get_issue_owner().name, 'john...@gmail.com')
- self.assertEqual(gpe.get_issue_owner().link, 'http://code.google.com/u/101557263855536553789/')
+ self.assertEqual(gpe.get_issue_owner().url, 'http://code.google.com/u/101557263855536553789/')
self.assertEqual(gpe.get_issue_status(), 'Started')
self.assertEqual(gpe.get_issue_summary(), 'Test Issue')
self.assertEqual(gpe.get_issue_description(),
@@ -217,7 +217,7 @@ class TestGoogleCodeProjectExtractor(TestCase):
expected = [
{
'author.name': 'john...@gmail.com',
- 'author.link': 'http://code.google.com/u/101557263855536553789/',
+ 'author.url': 'http://code.google.com/u/101557263855536553789/',
'created_date': 'Thu Aug 8 15:35:15 2013',
'body': 'Test *comment* is a comment',
'updates': {'Status:': 'Started', 'Labels:': '-OpSys-Linux OpSys-Windows'},
@@ -225,7 +225,7 @@ class TestGoogleCodeProjectExtractor(TestCase):
},
{
'author.name': 'john...@gmail.com',
- 'author.link': 'http://code.google.com/u/101557263855536553789/',
+ 'author.url': 'http://code.google.com/u/101557263855536553789/',
'created_date': 'Thu Aug 8 15:35:34 2013',
'body': 'Another comment',
'updates': {},
@@ -233,7 +233,7 @@ class TestGoogleCodeProjectExtractor(TestCase):
},
{
'author.name': 'john...@gmail.com',
- 'author.link': 'http://code.google.com/u/101557263855536553789/',
+ 'author.url': 'http://code.google.com/u/101557263855536553789/',
'created_date': 'Thu Aug 8 15:36:39 2013',
'body': 'Last comment',
'updates': {},
@@ -241,7 +241,7 @@ class TestGoogleCodeProjectExtractor(TestCase):
},
{
'author.name': 'john...@gmail.com',
- 'author.link': 'http://code.google.com/u/101557263855536553789/',
+ 'author.url': 'http://code.google.com/u/101557263855536553789/',
'created_date': 'Thu Aug 8 15:36:57 2013',
'body': 'Oh, I forgot one',
'updates': {'Labels:': 'OpSys-OSX'},
@@ -250,8 +250,23 @@ class TestGoogleCodeProjectExtractor(TestCase):
]
for actual, expected in zip(comments, expected):
self.assertEqual(actual.author.name, expected['author.name'])
- self.assertEqual(actual.author.link, expected['author.link'])
+ self.assertEqual(actual.author.url, expected['author.url'])
self.assertEqual(actual.created_date, expected['created_date'])
self.assertEqual(actual.body, expected['body'])
self.assertEqual(actual.updates, expected['updates'])
self.assertEqual([a.filename for a in actual.attachments], expected['attachments'])
+
+class TestUserLink(TestCase):
+ def test_plain(self):
+ tag = mock.Mock()
+ tag.string.strip.return_value = 'name'
+ tag.attrMap = {}
+ link = google.UserLink(tag)
+ self.assertEqual(str(link), 'name')
+
+ def test_linked(self):
+ tag = mock.Mock()
+ tag.string.strip.return_value = 'name'
+ tag.attrMap = {'href': '/p/project'}
+ link = google.UserLink(tag)
+ self.assertEqual(str(link), '[name](http://code.google.com/p/project)')
http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/8facbc5e/ForgeImporters/forgeimporters/tests/google/test_tracker.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/google/test_tracker.py b/ForgeImporters/forgeimporters/tests/google/test_tracker.py
index 15b8f33..01d9f8e 100644
--- a/ForgeImporters/forgeimporters/tests/google/test_tracker.py
+++ b/ForgeImporters/forgeimporters/tests/google/test_tracker.py
@@ -112,26 +112,21 @@ class TestTrackerImporter(TestCase):
def test_process_fields(self):
ticket = mock.Mock()
- def _user(l):
- u = mock.Mock()
- u.name = '%sname' % l
- u.link = '%slink' % l
- return u
issue = mock.Mock(
get_issue_summary=lambda:'summary',
get_issue_description=lambda:'my *description* fool',
get_issue_status=lambda:'status',
get_issue_created_date=lambda:'created_date',
get_issue_mod_date=lambda:'mod_date',
- get_issue_creator=lambda:_user('c'),
- get_issue_owner=lambda:_user('o'),
+ get_issue_creator=lambda:'creator',
+ get_issue_owner=lambda:'owner',
)
importer = tracker.GoogleCodeTrackerImporter()
with mock.patch.object(tracker, 'datetime') as dt:
dt.strptime.side_effect = lambda s,f: s
importer.process_fields(ticket, issue)
self.assertEqual(ticket.summary, 'summary')
- self.assertEqual(ticket.description, '*Originally created by:* [cname](clink)\n*Originally owned by:* [oname](olink)\n\nmy \*description\* fool')
+ self.assertEqual(ticket.description, '*Originally created by:* creator\n*Originally owned by:* owner\n\nmy \*description\* fool')
self.assertEqual(ticket.status, 'status')
self.assertEqual(ticket.created_date, 'created_date')
self.assertEqual(ticket.mod_date, 'mod_date')