You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by je...@apache.org on 2015/04/21 16:25:31 UTC

[01/25] allura git commit: [#7864] remove annoying ew.render logging, by configuring logging before initializing EW

Repository: allura
Updated Branches:
  refs/heads/ib/7856 e6c653620 -> c27af24da (forced update)


[#7864] remove annoying ew.render logging, by configuring logging before initializing EW


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/fa548be3
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/fa548be3
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/fa548be3

Branch: refs/heads/ib/7856
Commit: fa548be3fae8c90b7d7ef889b11604fac169cd58
Parents: 225dc73
Author: Dave Brondsema <da...@brondsema.net>
Authored: Tue Apr 7 15:36:38 2015 -0400
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Wed Apr 15 11:04:02 2015 +0000

----------------------------------------------------------------------
 AlluraTest/alluratest/controller.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/fa548be3/AlluraTest/alluratest/controller.py
----------------------------------------------------------------------
diff --git a/AlluraTest/alluratest/controller.py b/AlluraTest/alluratest/controller.py
index 0f13c5d..4a8f983 100644
--- a/AlluraTest/alluratest/controller.py
+++ b/AlluraTest/alluratest/controller.py
@@ -88,10 +88,10 @@ def setup_basic_test(config=None, app_name=DFL_APP_NAME):
         conf_dir = tg.config.here
     except AttributeError:
         conf_dir = os.getcwd()
-    ew.TemplateEngine.initialize({})
     test_file = os.path.join(conf_dir, get_config_file(config))
     cmd = SetupCommand('setup-app')
     cmd.run([test_file])
+    ew.TemplateEngine.initialize({})
 
     # run all tasks, e.g. indexing from bootstrap operations
     while M.MonQTask.run_ready('setup'):


[25/25] allura git commit: [#7856] ticket:757 Fix email regex

Posted by je...@apache.org.
[#7856] ticket:757 Fix email regex


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/c27af24d
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/c27af24d
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/c27af24d

Branch: refs/heads/ib/7856
Commit: c27af24dafa4582b83af44314dc0ce8d736e4b57
Parents: 8ea45a5
Author: Igor Bondarenko <je...@gmail.com>
Authored: Tue Apr 21 09:25:13 2015 +0000
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Tue Apr 21 09:25:13 2015 +0000

----------------------------------------------------------------------
 Allura/allura/model/auth.py            | 2 +-
 Allura/allura/tests/model/test_auth.py | 6 +++++-
 2 files changed, 6 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/c27af24d/Allura/allura/model/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index 8b06c73..bc16649 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -109,7 +109,7 @@ class AlluraUserProperty(ForeignIdProperty):
 
 
 class EmailAddress(MappedClass):
-    re_format = re.compile('^.* <(.*)>$')
+    re_format = re.compile('^.*\s+<(.*)>\s*$')
 
     class __mongometa__:
         name = 'email_address'

http://git-wip-us.apache.org/repos/asf/allura/blob/c27af24d/Allura/allura/tests/model/test_auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/model/test_auth.py b/Allura/allura/tests/model/test_auth.py
index 4281bb1..5d1841b 100644
--- a/Allura/allura/tests/model/test_auth.py
+++ b/Allura/allura/tests/model/test_auth.py
@@ -106,7 +106,11 @@ def test_email_address_canonical():
     assert_equal(M.EmailAddress.canonical('  nobody@example.com\t'),
                  'nobody@example.com')
     assert_equal(M.EmailAddress.canonical('I Am@Nobody <no...@example.com> '),
-                 'I Am@Nobody <no...@example.com>')
+                 'nobody@example.com')
+    assert_equal(M.EmailAddress.canonical(' No@body <no...@example.com> '),
+                 'no@body@example.com')
+    assert_equal(M.EmailAddress.canonical('no@body@example.com'),
+                 'no@body@example.com')
     assert_equal(M.EmailAddress.canonical('invalid'), None)
 
 @with_setup(setUp)


[09/25] allura git commit: [#6017] ticket:751 Clear Ming's cache for attachments to generate a changelog

Posted by je...@apache.org.
[#6017] ticket:751 Clear Ming's cache for attachments to generate a changelog


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/677fd677
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/677fd677
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/677fd677

Branch: refs/heads/ib/7856
Commit: 677fd677338c3a2c62c4674273f68ca2cc1186ad
Parents: 130ccec
Author: Igor Bondarenko <je...@gmail.com>
Authored: Wed Apr 8 10:10:02 2015 +0000
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Apr 16 10:43:47 2015 +0000

----------------------------------------------------------------------
 ForgeTracker/forgetracker/tracker_main.py | 6 ++++++
 1 file changed, 6 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/677fd677/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index 2b4e807..7558eab 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -38,6 +38,7 @@ from bson.errors import InvalidId
 from webhelpers import feedgenerator as FG
 
 from ming import schema
+from ming.odm import session
 from ming.orm.ormsession import ThreadLocalORMSession
 from ming.utils import LazyProperty
 
@@ -1434,6 +1435,11 @@ class TicketController(BaseController, FeedController):
             attachment = post_data['attachment']
             changes['attachments'] = attachments_info(self.ticket.attachments)
             self.ticket.add_multiple_attachments(attachment)
+            # flush new attachments to db
+            session(self.ticket.attachment_class()).flush()
+            # self.ticket.attachments is ming's LazyProperty, we need to reset
+            # it's cache to fetch updated attachments here:
+            self.ticket.__dict__.pop('attachments')
             changes['attachments'] = attachments_info(self.ticket.attachments)
         for cf in c.app.globals.custom_fields or []:
             if 'custom_fields.' + cf.name in post_data:


[20/25] allura git commit: [#7870] Make test.ini inherit from development.ini, update tests. And:

Posted by je...@apache.org.
[#7870] Make test.ini inherit from development.ini, update tests.  And:

* specify only the settings needed in test.ini
* remove tool_test section from development.ini (part of test.ini)
* remove unnecessary entry points


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/2cdb4f85
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/2cdb4f85
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/2cdb4f85

Branch: refs/heads/ib/7856
Commit: 2cdb4f85c131bce7ac3c3f85a4f630d1f823e5bf
Parents: c566681
Author: Dave Brondsema <da...@brondsema.net>
Authored: Thu Apr 9 18:34:47 2015 -0400
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Mon Apr 20 12:51:30 2015 -0400

----------------------------------------------------------------------
 Allura/allura/tests/functional/test_auth.py     |   4 +-
 .../tests/functional/test_neighborhood.py       |   2 +-
 .../tests/functional/test_user_profile.py       |   4 +-
 Allura/allura/tests/test_globals.py             |   2 +-
 Allura/allura/tests/unit/test_app.py            |   4 +-
 .../tests/unit/test_ldap_auth_provider.py       |  10 +-
 Allura/allura/websetup/bootstrap.py             |   1 -
 Allura/development.ini                          |  87 ++++-----
 Allura/setup.py                                 |  12 +-
 Allura/test.ini                                 | 185 ++++++-------------
 .../forgegit/tests/model/test_repository.py     |   6 +-
 .../forgesvn/tests/model/test_repository.py     |   8 +-
 .../forgetracker/tests/functional/test_root.py  |   2 +-
 .../tests/unit/test_root_controller.py          |   9 +-
 14 files changed, 128 insertions(+), 208 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/2cdb4f85/Allura/allura/tests/functional/test_auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_auth.py b/Allura/allura/tests/functional/test_auth.py
index f288b0b..0f9a8ee 100644
--- a/Allura/allura/tests/functional/test_auth.py
+++ b/Allura/allura/tests/functional/test_auth.py
@@ -771,8 +771,8 @@ class TestAuth(TestController):
         r = self.app.get('/auth/logout')
         r = self.app.post('/auth/do_login', params=dict(
             username='test-user', password='foo',
-            return_to='https://localhost/foo'))
-        assert_equal(r.location, 'https://localhost/foo')
+            return_to='http://localhost:8080/foo'))
+        assert_equal(r.location, 'http://localhost:8080/foo')
 
         r = self.app.get('/auth/logout')
         r = self.app.post('/auth/do_login', params=dict(

http://git-wip-us.apache.org/repos/asf/allura/blob/2cdb4f85/Allura/allura/tests/functional/test_neighborhood.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_neighborhood.py b/Allura/allura/tests/functional/test_neighborhood.py
index 332a60b..afe4dc6 100644
--- a/Allura/allura/tests/functional/test_neighborhood.py
+++ b/Allura/allura/tests/functional/test_neighborhood.py
@@ -281,7 +281,7 @@ class TestNeighborhood(TestController):
                           extra_environ=dict(username='root'))
         r = self.app.get('/adobe/adobe-1/admin/overview',
                          extra_environ=dict(username='root'))
-        assert "_add_tracking('nbhd', 'U-123456');" in r
+        assert "_add_tracking('nbhd', 'U-123456');" in r, r
         assert "_add_tracking('proj', 'U-654321');" in r
         # analytics not allowed
         neighborhood = M.Neighborhood.query.get(name='Adobe')

http://git-wip-us.apache.org/repos/asf/allura/blob/2cdb4f85/Allura/allura/tests/functional/test_user_profile.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_user_profile.py b/Allura/allura/tests/functional/test_user_profile.py
index a3ea741..c539baf 100644
--- a/Allura/allura/tests/functional/test_user_profile.py
+++ b/Allura/allura/tests/functional/test_user_profile.py
@@ -80,7 +80,7 @@ class TestUserProfile(TestController):
 
         sendsimplemail.post.assert_called_once_with(
             cc=User.by_username('test-admin').get_pref('email_address'),
-            text=u'test message\n\n---\n\nThis message was sent to you via the Allura web mail form.  You may reply to this message directly, or send a message to Test Admin at http://localhost/u/test-admin/profile/send_message\n',
+            text=u'test message\n\n---\n\nThis message was sent to you via the Allura web mail form.  You may reply to this message directly, or send a message to Test Admin at http://localhost:8080/u/test-admin/profile/send_message\n',
             toaddr=User.by_username('test-user').get_pref('email_address'),
             fromaddr=User.by_username('test-admin').get_pref('email_address'),
             reply_to=User.by_username('test-admin').get_pref('email_address'),
@@ -93,7 +93,7 @@ class TestUserProfile(TestController):
 
         sendsimplemail.post.assert_called_once_with(
             cc=None,
-            text=u'test message\n\n---\n\nThis message was sent to you via the Allura web mail form.  You may reply to this message directly, or send a message to Test Admin at http://localhost/u/test-admin/profile/send_message\n',
+            text=u'test message\n\n---\n\nThis message was sent to you via the Allura web mail form.  You may reply to this message directly, or send a message to Test Admin at http://localhost:8080/u/test-admin/profile/send_message\n',
             toaddr=User.by_username('test-user').get_pref('email_address'),
             fromaddr=User.by_username('test-admin').get_pref('email_address'),
             reply_to=User.by_username('test-admin').get_pref('email_address'),

http://git-wip-us.apache.org/repos/asf/allura/blob/2cdb4f85/Allura/allura/tests/test_globals.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_globals.py b/Allura/allura/tests/test_globals.py
index 6920f6d..ca04652 100644
--- a/Allura/allura/tests/test_globals.py
+++ b/Allura/allura/tests/test_globals.py
@@ -430,7 +430,7 @@ Some text in a regular paragraph
     for i in range(10):
         print i
 ''')
-    assert 'http://localhost/' in g.forge_markdown(email=True).convert('[Home]')
+    assert_in('http://localhost:8080/', g.forge_markdown(email=True).convert('[Home]'))
     assert 'class="codehilite"' in g.markdown.convert('''
 ~~~~
 def foo(): pass

http://git-wip-us.apache.org/repos/asf/allura/blob/2cdb4f85/Allura/allura/tests/unit/test_app.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/unit/test_app.py b/Allura/allura/tests/unit/test_app.py
index 95c56c5..eca1ae7 100644
--- a/Allura/allura/tests/unit/test_app.py
+++ b/Allura/allura/tests/unit/test_app.py
@@ -17,6 +17,8 @@
 
 from unittest import TestCase
 
+from nose.tools import assert_equal
+
 from allura.app import Application
 from allura import model
 from allura.tests.unit import WithDatabase
@@ -100,7 +102,7 @@ class TestAppDefaults(WithDatabase):
 
     def test_email_address(self):
         self.app.url = '/p/project/mount-point/'
-        assert self.app.email_address == 'mount-point@project.p.in.localhost'
+        assert_equal(self.app.email_address, 'mount-point@project.p.in.localhost')
 
 
 def install_app():

http://git-wip-us.apache.org/repos/asf/allura/blob/2cdb4f85/Allura/allura/tests/unit/test_ldap_auth_provider.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/unit/test_ldap_auth_provider.py b/Allura/allura/tests/unit/test_ldap_auth_provider.py
index 1dc4bf3..7d7f5b5 100644
--- a/Allura/allura/tests/unit/test_ldap_auth_provider.py
+++ b/Allura/allura/tests/unit/test_ldap_auth_provider.py
@@ -53,7 +53,7 @@ class TestLdapAuthenticationProvider(object):
         self.provider._encode_password = Mock(return_value='new-pass-hash')
         ldap.dn.escape_dn_chars = lambda x: x
 
-        dn = 'uid=%s,ou=users,dc=sf,dc=net' % user.username
+        dn = 'uid=%s,ou=people,dc=localdomain' % user.username
         self.provider.set_password(user, 'old-pass', 'new-pass')
         ldap.initialize.assert_called_once_with('ldaps://localhost/')
         connection = ldap.initialize.return_value
@@ -74,7 +74,7 @@ class TestLdapAuthenticationProvider(object):
 
         self.provider._login()
 
-        dn = 'uid=%s,ou=users,dc=sf,dc=net' % params['username']
+        dn = 'uid=%s,ou=people,dc=localdomain' % params['username']
         ldap.initialize.assert_called_once_with('ldaps://localhost/')
         connection = ldap.initialize.return_value
         connection.bind_s.called_once_with(dn, 'test-password')
@@ -90,7 +90,7 @@ class TestLdapAuthenticationProvider(object):
         self.provider.request.method = 'POST'
         self.provider.request.body = '&'.join(['%s=%s' % (k,v) for k,v in params.iteritems()])
         ldap.dn.escape_dn_chars = lambda x: x
-        dn = 'uid=%s,ou=users,dc=sf,dc=net' % params['username']
+        dn = 'uid=%s,ou=people,dc=localdomain' % params['username']
         conn = ldap.initialize.return_value
         conn.search_s.return_value = [(dn, {'cn': [u'åℒƒ'.encode('utf-8')]})]
 
@@ -117,11 +117,11 @@ class TestLdapAuthenticationProvider(object):
         ThreadLocalORMSession.flush_all()
         assert_not_equal(M.User.query.get(username=user_doc['username']), None)
 
-        dn = 'uid=%s,ou=users,dc=sf,dc=net' % user_doc['username']
+        dn = 'uid=%s,ou=people,dc=localdomain' % user_doc['username']
         ldap.initialize.assert_called_once_with('ldaps://localhost/')
         connection = ldap.initialize.return_value
         connection.bind_s.called_once_with(
-            'cn=site,ou=admin,dc=sf,dc=net',
+            'cn=admin,dc=localdomain',
             'admin-password')
         connection.add_s.assert_called_once_with(dn, modlist.addModlist.return_value)
         connection.unbind_s.assert_called_once()

http://git-wip-us.apache.org/repos/asf/allura/blob/2cdb4f85/Allura/allura/websetup/bootstrap.py
----------------------------------------------------------------------
diff --git a/Allura/allura/websetup/bootstrap.py b/Allura/allura/websetup/bootstrap.py
index bb89995..ed76c15 100644
--- a/Allura/allura/websetup/bootstrap.py
+++ b/Allura/allura/websetup/bootstrap.py
@@ -90,7 +90,6 @@ def bootstrap(command, conf, vars):
     # Clean up all old stuff
     ThreadLocalORMSession.close_all()
     c.user = c.project = c.app = None
-    database = conf.get('db_prefix', '') + 'project:test'
     wipe_database()
     try:
         g.solr.delete(q='*:*')

http://git-wip-us.apache.org/repos/asf/allura/blob/2cdb4f85/Allura/development.ini
----------------------------------------------------------------------
diff --git a/Allura/development.ini b/Allura/development.ini
index 4a4f18c..b7e0b95 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -28,17 +28,22 @@
 ; More settings should be changed for good performance in a production site (no autoreload, no debugging, etc)
 ;
 ; You may copy this file to make a new configuration file (e.g. production.ini)
-; Just use the new file name instead of development.ini for any paster commands you run.
+; Or inherit from this file by starting your .ini file like this:
+;    [app:main]
+;    use = config:development.ini#main
+; Then just use the new file name instead of development.ini for any paster commands you run.
 
 
-; TODO:
-; remove test config
-; clarify debug settings
-
 [DEFAULT]
+; this section is for a few settings that are shared with error handling middleware
+
+; WARNING: *THE LINE BELOW MUST BE CHANGED ON A PRODUCTION ENVIRONMENT*
+; Debug mode will enable the interactive debugging tool, allowing ANYONE to
+; execute malicious code after an exception is raised.
 debug = true
-; Uncomment and replace with the address which should receive any error reports
+; If you want to receive an email for every unhandled HTTP 500 error, set your email address here:
 ;email_to = you@yourdomain.com
+error_email_from = paste@localhost
 
 ; SMTP settings for outgoing mail
 smtp_tls = false
@@ -49,22 +54,21 @@ smtp_timeout = 10
 smtp_server = localhost
 smtp_port = 8826
 ; Reply-To and From address often used in email notifications:
-forgemail.return_path = noreply@sf.net
+forgemail.return_path = noreply@localhost
 
-error_email_from = paste@localhost
-; Used to uniquify references to static resources, can be a timestamp or any unique value
-; This should be updated each time you deploy (or make significant changes, like new tools, new css)
-build_key=1276635823
 
+;
+; Settings for `paster serve` command
+;
 [server:main]
 use = egg:Paste#http
 host = 0.0.0.0
 port = 8080
 
-[filter-app:profile]
-use=egg:keas.profile#profiler
-next=main
 
+;
+; The main allura settings
+;
 [app:main]
 use = egg:Allura
 full_stack = true
@@ -74,7 +78,13 @@ site_name = Allura
 ; Change these to your website's domain
 domain = localhost
 base_url = http://localhost:8080
+forgemail.url = http://localhost:8080
 
+; Used to uniquify references to static resources, can be a timestamp or any unique value
+; This should be updated each time you deploy (or make significant changes, like new tools, new css)
+build_key=1276635823
+
+; Used by Turbogears / Pylons in some cases.  Not particularly relevant for Allura.
 cache_dir = %(here)s/data
 
 ; Cache Neighborhood objects for N seconds (speeds up requests).
@@ -125,11 +135,12 @@ auth.max_password_len = 30
 
 ; if using LDAP, also run `pip install python-ldap` in your Allura environment
 
-auth.ldap.server = ldap://localhost
+auth.ldap.server = ldaps://localhost/
 auth.ldap.suffix = ou=people,dc=localdomain
 auth.ldap.admin_dn = cn=admin,dc=localdomain
 auth.ldap.admin_password = secret
 auth.ldap.schroot_name = scm
+auth.ldap.use_schroot = false
 auth.ldap.password.algorithm = 6
 auth.ldap.password.rounds = 6000
 auth.ldap.password.salt_len = 16
@@ -187,7 +198,7 @@ webhook.retry = 60 120 240
 ; Option format: webhook.<hook type>.limit,
 ; all '-' in hook type must be changed to '_'
 ; e.g. for repo-push webhook:
-webhook.repo_push.limit = 10
+webhook.repo_push.limit = 30
 ; Limit max number of hooks that can be created for given project/app
 ; Option name format: same as above.
 ; Value format: json dict, where keys are app names (as appears in
@@ -380,9 +391,7 @@ forgemail.host = 0.0.0.0
 forgemail.port = 8825
 ; domain suffix for your mail, change this.  You also need to route *.*.*.forgemail.domain to the above host/port via
 ; your mail and DNS configuration
-forgemail.domain = .in.sf.net
-; probably unused?
-forgemail.url = http://localhost:8080
+forgemail.domain = .in.localhost
 
 ; Specify the number of projects allowed to be created by a user
 ; depending on the age of their user account.
@@ -395,11 +404,6 @@ forgemail.url = http://localhost:8080
 ; set this to "false" if you are deploying to production and want performance improvements
 auto_reload_templates = true
 
-; WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*
-; Debug mode will enable the interactive debugging tool, allowing ANYONE to
-; execute malicious code after an exception is raised.
-;set debug = false
-
 ; How frequently users can send messages
 user_message.time_interval = 3600
 user_message.max_messages = 20
@@ -457,43 +461,30 @@ short_url.url_pattern = {base_url}/{nbhd}/{project}/{mount_point}/{short_name}
 userstats.count_lines_of_code = true
 
 
-; Setup for tool testing
-[app:tool_test]
-use = egg:Allura
-override_root=basetest_project_root ; TurboGears will use controllers/basetest_project_root.py as root controller
-full_stack = true
-
-cache_dir = %(here)s/data
-beaker.session.key = allura
-beaker.session.type = cookie
-beaker.session.validate_key = 714bfe3612c42390726f
-
-; Ming setup
-ming.main.uri = mongo://127.0.0.1:27017/allura:test
-
-; Forgemail server
-forgemail.host = 0.0.0.0
-forgemail.port = 8825
-forgemail.domain = .in.sf.net
-forgemail.return_path = noreply@sourceforge.net
-forgemail.url = http://localhost:8080
+;
+; Optional settings for profiling with https://pypi.python.org/pypi/keas.profile
+;
+[filter-app:profile]
+use=egg:keas.profile#profiler
+next=main
 
-auth.method = local
-registration.method = local
 
+;
 ; setup for the taskd background daemon request controller
+;
 [app:task]
 use = main
 override_root = task ; TurboGears will use controllers/task.py as root controller
 
 
 
-
+;
 ; Logging configuration
+;
 ; Add additional loggers, handlers, formatters here
 ; Uses python's logging config file format
 ; http://docs.python.org/lib/logging-config-fileformat.html
-
+;
 [loggers]
 keys = root, allura, sqlalchemy, paste, pylons, taskdstatus, timermiddleware, tmw_details
 

http://git-wip-us.apache.org/repos/asf/allura/blob/2cdb4f85/Allura/setup.py
----------------------------------------------------------------------
diff --git a/Allura/setup.py b/Allura/setup.py
index e44c0c2..f2213b3 100644
--- a/Allura/setup.py
+++ b/Allura/setup.py
@@ -90,16 +90,10 @@ setup(
         ('templates/**.html', 'genshi', None),
         ('public/**', 'ignore', None)]},
 
+    # These entry points define what tools and plugins are available for Allura.
+    # Other packages (the Forge* directories) or 3rd-party can add more too.
+    # development.ini is used for many cases to specify which to actually use.
     entry_points="""
-    [paste.app_factory]
-    main = allura.config.middleware:make_app
-    task = allura.config.middleware:make_task_app
-    tool_test = allura.config.middleware:make_tool_test_app
-
-    [paste.app_install]
-    main = pylons.util:PylonsInstaller
-    tool_test = pylons.util:PylonsInstaller
-
     [allura]
     profile = allura.ext.user_profile:UserProfileApp
     admin = allura.ext.admin:AdminApp

http://git-wip-us.apache.org/repos/asf/allura/blob/2cdb4f85/Allura/test.ini
----------------------------------------------------------------------
diff --git a/Allura/test.ini b/Allura/test.ini
index ecf1639..4381cb6 100644
--- a/Allura/test.ini
+++ b/Allura/test.ini
@@ -1,168 +1,97 @@
-#       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.
-#
-# allura - TurboGears 2 testing environment configuration
-#
-# The %(here)s variable will be replaced with the parent directory of this file
-#
-[DEFAULT]
-debug = false
-# make sure, since this extends development.ini
-set debug = false
-# Uncomment and replace with the address which should receive any error reports
-# email_to = you@yourdomain.com
-smtp_server = localhost
-error_email_from = paste@localhost
-
-[server:main]
-use = egg:Paste#http
-host = 0.0.0.0
-port = 5000
+;       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.
+;
+; Allura - testing configuration
+;
+;
+
+;
+; This inherits all the settings from development.ini
+; and then overrides only settings needed for tests to work.
+;
 
 [app:main]
-use = config:development.ini#tool_test
-db_prefix = test_
+use = config:development.ini#main
+override_root=basetest_project_root ; TurboGears will use controllers/basetest_project_root.py as root controller
 disable_template_overrides = True
 
-site_name = Allura
-base_url = http://localhost
-domain = localhost
-
-mediawikiimporter.db_config_prefix = hostedapps.db.
-mediawikiimporter.attachments_dir_prefix = /nfs/mediawiki-attachments/
-mediawikiimporter.db_name_template = p_%s_mediawiki
-hostedapps.db.host = localhost
-hostedapps.db.port = 3306
-hostedapps.db.user = user
-hostedapps.db.password = password
-
-# Use test MongoDB DB server
-# ming.main.master = mongo://127.0.0.1:27018/allura
+; Use in-memory MongoDB
 ming.main.uri = mim:///allura
 ming.project.uri = mim:///project-data
 ming.task.uri = mim:///task
-
-trovecategories.enableediting = true
-
-# ActivityStream
 activitystream.master = mim://
-activitystream.database = activitystream
-activitystream.activity_collection = activities
-activitystream.node_collection = nodes
-activitystream.timeline_collection = timelines
-activitystream.recording.enabled = true
-activitystream.enabled = true
-
-solr.mock = true
-amqp.mock = true
-smtp.mock = true
 
-# Forgemail server
-forgemail.host = 0.0.0.0
-forgemail.port = 8825
-forgemail.domain = .in.localhost
-forgemail.url = http://localhost:8080
-forgemail.return_path = noreply@localhost
+solr.server =
+smtp.mock = true
 
 load_test_data = true
 cache_test_data = false
 site_admin_project = test
 
-# useful primarily for test suites, where we want to see the error right away
+; useful primarily for test suites, where we want to see the error right away
 monq.raise_errors = true
 
-# Set the locations of some static resources
-#  script_name is the path that is handled by the application
-#  url_base is the prefix that references to the static resources should have
+; Required so that g.production_mode is True, and Google Analytics is included (weird.)
+; may also be useful for other reasons during tests (e.g. not intercepting error handling)
+debug = false
+
+; if enabled during tests, TimerMiddleware will end up wrapping requests way too many times instead of just once
+; not necessary anyway
+stats.sample_rate = 0
+
+; specify these without any build_key being included
 ew.script_name = /nf/_ew_/
 ew.url_base = /nf/_ew_/
 static.script_name = /nf/_static_/
 static.url_base = /nf/_static_/
 
+; tests check for these values in output
 scm.host.ro.git = git://git.localhost$path
 scm.host.rw.git = ssh://$username@localhost:8022/scm-repo$path
-scm.host.https.git = https://$username@localhost:8022/scm-repo$path
-scm.host.https_anon.git = https://localhost:8022/scm-repo$path
-scm.host.ro.hg = http://hg.localhost$path
-scm.host.rw.hg = ssh://$username@localhost:8022/scm-repo$path
-scm.host.https.hg = https://$username@localhost:8022/scm-repo$path
-scm.host.https_anon.hg = https://localhost:8022/scm-repo$path
 scm.host.ro.svn = http://svn.localhost$path/
 scm.host.rw.svn = svn+ssh://$username@localhost:8022/scm-repo$path/
 scm.host.https.svn = https://$username@localhost:8022/scm-repo$path/
-scm.host.https_anon.svn = https://localhost:8022/scm-repo$path/
-
-scm.clone.git = git clone $source_url $dest_path
-scm.clone.hg = hg clone $source_url $dest_path
-scm.clone.https_anon.svn = svn checkout $source_url $dest_path
-scm.clone.ro.svn = svn checkout $source_url $dest_path
-scm.clone.svn = svn checkout --username=$username $source_url $dest_path
+scm.host.ro.hg = http://hg.localhost$path
+scm.host.rw.hg = ssh://$username@localhost:8022/scm-repo$path
 
 scm.repos.root = /tmp
 scm.repos.tarball.enable = true
 scm.repos.tarball.root = /tmp/tarball
 scm.repos.tarball.url_prefix = file://
 
-bulk_export_path = /tmp/bulk_export/{nbhd}/{project}
-bulk_export_filename = {project}.zip
-bulk_export_download_instructions = Sample instructions for {project}
-
 support_tool_choices = wiki tickets discussion
 
-#stats.sample_rate = 0
+; markdown text longer than max length will not be converted to html
+; tests expect max length of 40000
+markdown_render_max_length = 40000
 
-short_url.url_pattern = {base_url}/{nbhd}/{project}/{mount_point}/{short_name}
+; TODO: make this and tests match development.ini
+bulk_export_filename = {project}.zip
+
+; TODO: update tests and let this be true
+solr.use_new_types = false
+
+; TODO: update tests and remove this setting override
+auth.require_email_addr = false
 
-# markdown text longer than max length will not be converted to html
-# tests expect max length of 40000
-markdown_render_max_length = 40000
 
-user_message.time_interval = 3600
-user_message.max_messages = 200
-
-auth.min_password_len = 6
-auth.max_password_len = 30
-
-# LDAP auth provider
-auth.ldap.server = ldaps://localhost/
-auth.ldap.suffix = ou=users,dc=sf,dc=net
-auth.ldap.admin_dn = cn=site,ou=admin,dc=sf,dc=net
-auth.ldap.admin_password = admin-password
-auth.ldap.use_schroot = False
-auth.ldap.password.algorithm = 6
-auth.ldap.password.rounds = 6000
-auth.ldap.password.salt_len = 16
-user_prefs_storage.ldap.fields.display_name = cn
-
-auth.allow_user_to_disable_account = true
-auth.allow_edit_prefs = true
-
-[app:main_with_amqp]
-use = main
-# Use test RabbitMQ vhost
-amqp.mock = false
-amqp.hostname = localhost
-amqp.port = 5672
-amqp.userid = testuser
-amqp.password = testpw
-amqp.vhost = vhost_testing
-
-
-# Add additional test specific configuration options as necessary.
+;
+; Logging goes to a test.log file in current directory
+;
 [loggers]
 keys = root, allura
 

http://git-wip-us.apache.org/repos/asf/allura/blob/2cdb4f85/ForgeGit/forgegit/tests/model/test_repository.py
----------------------------------------------------------------------
diff --git a/ForgeGit/forgegit/tests/model/test_repository.py b/ForgeGit/forgegit/tests/model/test_repository.py
index 3ffb2a2..dbc12b0 100644
--- a/ForgeGit/forgegit/tests/model/test_repository.py
+++ b/ForgeGit/forgegit/tests/model/test_repository.py
@@ -82,6 +82,7 @@ class TestNewGit(unittest.TestCase):
             '1e146e67985dcd71c74de79613719bef7bddca4a/')
         all_cis = list(self.repo.log(self.rev._id, id_only=True))
         assert len(all_cis) == 4
+        c.lcid_cache = {}
         self.rev.tree.ls()
         # print self.rev.tree.readme()
         assert_equal(self.rev.tree.readme(), (
@@ -204,7 +205,7 @@ class TestGitRepo(unittest.TestCase, RepoImplTestBase):
         with open(os.path.join(g.tmpdir, 'testgit.git/hooks/post-receive')) as f:
             c = f.read()
         self.assertIn(
-            'curl -s http://localhost/auth/refresh_repo/p/test/src-git/\n', c)
+            'curl -s http://localhost:8080/auth/refresh_repo/p/test/src-git/\n', c)
         self.assertIn('exec $DIR/post-receive-user\n', c)
         shutil.rmtree(dirname)
 
@@ -238,7 +239,7 @@ class TestGitRepo(unittest.TestCase, RepoImplTestBase):
             with open(os.path.join(g.tmpdir, 'testgit.git/hooks/post-receive')) as f:
                 c = f.read()
             self.assertIn(
-                'curl -s http://localhost/auth/refresh_repo/p/test/src-git/\n', c)
+                'curl -s http://localhost:8080/auth/refresh_repo/p/test/src-git/\n', c)
             self.assertIn('exec $DIR/post-receive-user\n', c)
             shutil.rmtree(dirname)
 
@@ -403,6 +404,7 @@ class TestGitRepo(unittest.TestCase, RepoImplTestBase):
         self.assertEqual(cids[-1], '9a7df788cf800241e3bb5a849c8870f2f8259d98')
 
     def test_ls(self):
+        c.lcid_cache = {}  # else it'll be a mock
         lcd_map = self.repo.commit('HEAD').tree.ls()
         self.assertEqual(lcd_map, [{
             'href': u'README',

http://git-wip-us.apache.org/repos/asf/allura/blob/2cdb4f85/ForgeSVN/forgesvn/tests/model/test_repository.py
----------------------------------------------------------------------
diff --git a/ForgeSVN/forgesvn/tests/model/test_repository.py b/ForgeSVN/forgesvn/tests/model/test_repository.py
index 92ccaf5..6276df8 100644
--- a/ForgeSVN/forgesvn/tests/model/test_repository.py
+++ b/ForgeSVN/forgesvn/tests/model/test_repository.py
@@ -169,7 +169,7 @@ class TestSVNRepo(unittest.TestCase, RepoImplTestBase):
         with open(os.path.join(g.tmpdir, 'testsvn/hooks/post-commit')) as f:
             hook_data = f.read()
         self.assertIn(
-            'curl -s http://localhost/auth/refresh_repo/p/test/src/\n',
+            'curl -s http://localhost:8080/auth/refresh_repo/p/test/src/\n',
             hook_data)
         self.assertIn('exec $DIR/post-commit-user "$@"\n', hook_data)
 
@@ -221,7 +221,7 @@ class TestSVNRepo(unittest.TestCase, RepoImplTestBase):
         with open(os.path.join(g.tmpdir, 'testsvn/hooks/post-commit')) as f:
             c = f.read()
         self.assertIn(
-            'curl -s http://localhost/auth/refresh_repo/p/test/src/\n', c)
+            'curl -s http://localhost:8080/auth/refresh_repo/p/test/src/\n', c)
         self.assertIn('exec $DIR/post-commit-user "$@"\n', c)
 
         repo.refresh(notify=False)
@@ -696,7 +696,7 @@ class TestSVNRev(unittest.TestCase):
         n = M.Notification.query.find(
             dict(subject='[test:src] [r1] - rick446: Create readme')).first()
         assert n
-        assert_equal(n.text, 'Create readme http://localhost/p/test/src/1/')
+        assert_equal(n.text, 'Create readme http://localhost:8080/p/test/src/1/')
 
 
 class _Test(unittest.TestCase):
@@ -890,7 +890,7 @@ class TestRepo(_TestWithRepo):
         notifications = M.Notification.query.find().all()
         for n in notifications:
             if '100 new commits' in n.subject:
-                assert "master,branch:  by %s http://localhost/ci/foo99" % committer_name in n.text
+                assert "master,branch:  by %s http://localhost:8080/ci/foo99" % committer_name in n.text
                 break
         else:
             assert False, 'Did not find notification'

http://git-wip-us.apache.org/repos/asf/allura/blob/2cdb4f85/ForgeTracker/forgetracker/tests/functional/test_root.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tests/functional/test_root.py b/ForgeTracker/forgetracker/tests/functional/test_root.py
index e8195d5..7f67b3a 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_root.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_root.py
@@ -2351,7 +2351,7 @@ class TestFunctionalController(TrackerTestController):
             return_path, rcpts, body = _client.sendmail.call_args[0]
             body = body.split('\n')
             assert 'Subject: [test:bugs] #1 test <h2> ticket' in body
-            assert '<p><strong> <a class="alink" href="http://localhost/p/test/bugs/1">[bugs:#1]</a> test &lt;h2&gt; ticket</strong></p>' in body
+            assert_in('<p><strong> <a class="alink" href="http://localhost:8080/p/test/bugs/1">[bugs:#1]</a> test &lt;h2&gt; ticket</strong></p>', body)
 
     @patch('forgetracker.search.query_filter_choices')
     def test_multiselect(self, query_filter_choices):

http://git-wip-us.apache.org/repos/asf/allura/blob/2cdb4f85/ForgeTracker/forgetracker/tests/unit/test_root_controller.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tests/unit/test_root_controller.py b/ForgeTracker/forgetracker/tests/unit/test_root_controller.py
index facc28c..ae2f7a1 100644
--- a/ForgeTracker/forgetracker/tests/unit/test_root_controller.py
+++ b/ForgeTracker/forgetracker/tests/unit/test_root_controller.py
@@ -15,16 +15,19 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
+import unittest
+
 from mock import Mock, patch
 from ming.orm.ormsession import session
+from pylons import tmpl_context as c
+from nose.tools import assert_equal
 
 from allura.lib import helpers as h
 from allura.model import User
-from pylons import tmpl_context as c
+
 from forgetracker.tests.unit import TrackerTestWithModel
 from forgetracker.model import Ticket
 from forgetracker import tracker_main
-import unittest
 
 
 class WithUserAndBugsApp(TrackerTestWithModel):
@@ -46,7 +49,7 @@ class TestWhenSearchingWithCustomFields(WithUserAndBugsApp):
         expected = [dict(sortable_name='_iteration_number_s',
                          name='_iteration_number',
                          label='Iteration Number')]
-        assert self.response['sortable_custom_fields'] == expected
+        assert_equal(self.response['sortable_custom_fields'], expected)
 
     def test_that_tickets_are_listed(self):
         assert self.response['tickets'][0].summary == 'colors are wrong'


[02/25] allura git commit: [#7864] handle multiple pages of Google Code comments

Posted by je...@apache.org.
[#7864] handle multiple pages of Google Code comments

The new test .html files are based off of the existing test-issue.html and are very similar.

Some tests were moved around to accomodate different test setup for those using iter_comments and
affected by the changes.


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/225dc73c
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/225dc73c
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/225dc73c

Branch: refs/heads/ib/7856
Commit: 225dc73c51dce1de27de0514cf58f222d3f1a351
Parents: 747cad0
Author: Dave Brondsema <da...@brondsema.net>
Authored: Tue Apr 7 10:22:46 2015 -0400
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Wed Apr 15 11:04:02 2015 +0000

----------------------------------------------------------------------
 .../forgeimporters/google/__init__.py           |  30 +-
 .../data/google/test-issue-first-page.html      | 548 +++++++++++++++++++
 .../tests/data/google/test-issue-prev-page.html | 431 +++++++++++++++
 .../tests/data/google/test-issue.html           |   7 +
 .../tests/google/functional/test_tracker.py     |   7 +-
 .../tests/google/test_extractor.py              | 207 ++++---
 6 files changed, 1148 insertions(+), 82 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/225dc73c/ForgeImporters/forgeimporters/google/__init__.py
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/google/__init__.py b/ForgeImporters/forgeimporters/google/__init__.py
index b848151..302544e 100644
--- a/ForgeImporters/forgeimporters/google/__init__.py
+++ b/ForgeImporters/forgeimporters/google/__init__.py
@@ -304,9 +304,9 @@ class GoogleCodeProjectExtractor(ProjectExtractor):
         return self.page.find(id='hc0').find('span', 'date').get('title')
 
     def get_issue_mod_date(self):
-        comments = self.page.findAll('div', 'issuecomment')
+        comments = list(self.iter_comments())
         if comments:
-            last_update = Comment(comments[-1], self.project_name)
+            last_update = comments[-1]
             return last_update.created_date
         else:
             return self.get_issue_created_date()
@@ -346,8 +346,30 @@ class GoogleCodeProjectExtractor(ProjectExtractor):
         return 0
 
     def iter_comments(self):
-        for comment in self.page.findAll('div', 'issuecomment'):
-            yield Comment(comment, self.project_name)
+        # first, get all pages if there are multiple pages of comments
+        looking_for_comment_pages = True
+        comment_page_urls = [self.url]
+        while looking_for_comment_pages:
+            first_comment = self.page.find('div', 'vt issuecomment')
+            looking_for_comment_pages = False
+            if first_comment and 'cursor_off' not in first_comment['class']:
+                # this is not a real comment, just forward/back links
+                for link in first_comment.findAll('a'):
+                    if link.text.startswith('Older'):
+                        prev_comments_page = urljoin(self.url, link['href'])
+                        comment_page_urls.insert(0, prev_comments_page)
+                        looking_for_comment_pages = True
+                        self.get_page(prev_comments_page)  # prep for next iteration of loop
+
+        # then go through those to get the actual comments
+        for comment_page_url in comment_page_urls:
+            self.get_page(comment_page_url)
+            # regular comments have cursor_off class
+            for comment in self.page.findAll('div', 'cursor_off vt issuecomment'):
+                yield Comment(comment, self.project_name)
+
+
+
 
 
 class UserLink(object):

http://git-wip-us.apache.org/repos/asf/allura/blob/225dc73c/ForgeImporters/forgeimporters/tests/data/google/test-issue-first-page.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/data/google/test-issue-first-page.html b/ForgeImporters/forgeimporters/tests/data/google/test-issue-first-page.html
new file mode 100644
index 0000000..4fc25eb
--- /dev/null
+++ b/ForgeImporters/forgeimporters/tests/data/google/test-issue-first-page.html
@@ -0,0 +1,548 @@
+<!DOCTYPE html>
+<!--
+
+An issue with a link to another page of comments (google paginates after 500 comments, we simulate with less)
+test-issue-prev-page.html is the test file for that other page of comments
+
+-->
+<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>&#9660;</small></a>
+ | <a href="https://www.google.com/accounts/ServiceLogin?service=code&amp;ltmpl=phosting&amp;continue=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D6&amp;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&nbsp;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> &nbsp;
+
+ <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">&nbsp;All issues</option>
+<option value="2" selected="selected">&nbsp;Open issues</option>
+<option value="6">&nbsp;New issues</option>
+<option value="7">&nbsp;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>
+ &nbsp;
+ <span class="inIssueAdvSearch">
+<a href="advsearch">Advanced search</a>
+</span> &nbsp;
+ <span class="inIssueSearchTips">
+<a href="searchtips">Search tips</a>
+</span> &nbsp;
+ <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 &quot;Issue&quot;</span>
+</td>
+<td>
+<div class="pagination">
+<a href="../../allura-google-importer/issues/detail?id=5" title="Prev">&lsaquo; 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:&nbsp;</th>
+<td width="100%">
+<span title="Work on this issue has begun">Started</span>
+</td>
+</tr>
+<tr><th align="left">Owner:&nbsp;</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&amp;ltmpl=phosting&amp;continue=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D6&amp;followup=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D6">Sign in</a> to add a comment</div>
+</div>&nbsp;
+ </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
+    if p.count &gt; 5:
+        print "Not &lt; 5 &amp; != 5"
+
+References: <a href="/p/allura-google-importer/issues/detail?id=1">issue 1</a>, <a href="/p/allura-google-importer/source/detail?r=2">r2</a>
+
+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&amp;name=at1.txt&amp;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
+
+
+ &nbsp; <a href="../../allura-google-importer/issues/attachmentText?id=7&amp;aid=70000000&amp;name=at1.txt&amp;token=3REU1M3JUUMt0rJUg7ldcELt6LA%3A1376059941255" target="_blank">View</a>
+
+ &nbsp; <a href="//allura-google-importer.googlecode.com/issues/attachment?aid=70000000&amp;name=at1.txt&amp;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&amp;name=&amp;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></b>
+<br />
+ 0 bytes
+
+
+ &nbsp; <a href="//allura-google-importer.googlecode.com/issues/attachment?aid=70000001&amp;name=&amp;token=C9Hn4s1-g38hlSggRGo65VZM1ys%3A1376059941255">Download</a>
+</td>
+</tr>
+</table>
+</div>
+</div>
+
+ <div class="vt issuecomment" width="100%" style="background:#e5ecf9; padding:2px .7em; margin:0; border:0">
+Showing comments 3 - 6
+of 6
+ &nbsp; <a href="detail?id=1769&amp;cnum=500&amp;cstart=2">Older <b>&rsaquo;</b></a>
+ </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&amp;name=&amp;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
+
+
+ &nbsp; <a href="../../allura-google-importer/issues/attachmentText?id=6&amp;aid=60001000&amp;name=at2.txt&amp;token=JOSo4duwaN2FCKZrwYOQ-nx9r7U%3A1376001446667" target="_blank">View</a>
+
+ &nbsp; <a href="//allura-google-importer.googlecode.com/issues/attachment?aid=60001000&amp;name=at2.txt&amp;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 with references: <a href="/p/allura-google-importer/issues/detail?id=2">issue 2</a>, <a href="/p/allura-google-importer/source/detail?r=1">r1</a>
+</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&amp;name=at4.txt&amp;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
+
+
+ &nbsp; <a href="../../allura-google-importer/issues/attachmentText?id=6&amp;aid=60003000&amp;name=at4.txt&amp;token=6Ny2zYHmV6b82dqxyoiH6HUYoC4%3A1376001446667" target="_blank">View</a>
+
+ &nbsp; <a href="//allura-google-importer.googlecode.com/issues/attachment?aid=60003000&amp;name=at4.txt&amp;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&amp;name=at1.txt&amp;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
+
+
+ &nbsp; <a href="../../allura-google-importer/issues/attachmentText?id=6&amp;aid=60003001&amp;name=at1.txt&amp;token=NS8aMvWsKzTAPuY2kniJG5aLzPg%3A1376001446667" target="_blank">View</a>
+
+ &nbsp; <a href="//allura-google-importer.googlecode.com/issues/attachment?aid=60003001&amp;name=at1.txt&amp;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 (with an inter-project reference to <a href="/p/other-project/issues/detail?id=1">issue other-project:1</a>)
+</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>
+
+<div class="vt issuecomment" width="100%" style="background:#e5ecf9; padding:2px .7em; margin:0">
+Showing comments 3 - 6
+of 6
+ &nbsp; <a href="detail?id=1769&amp;cnum=500&amp;cstart=2">Older <b>&rsaquo;</b></a>
+</div>
+
+</td>
+</tr>
+<tr>
+<td></td>
+<td class="vt issuecomment">
+<span class="indicator">&#9658;</span> <a href="https://www.google.com/accounts/ServiceLogin?service=code&amp;ltmpl=phosting&amp;continue=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D6&amp;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=&amp;can=2&amp;groupby=&amp;sort=&amp;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/allura/blob/225dc73c/ForgeImporters/forgeimporters/tests/data/google/test-issue-prev-page.html
----------------------------------------------------------------------
diff --git a/ForgeImporters/forgeimporters/tests/data/google/test-issue-prev-page.html b/ForgeImporters/forgeimporters/tests/data/google/test-issue-prev-page.html
new file mode 100644
index 0000000..62a3b23
--- /dev/null
+++ b/ForgeImporters/forgeimporters/tests/data/google/test-issue-prev-page.html
@@ -0,0 +1,431 @@
+<!DOCTYPE html>
+<!--
+
+This is the second page of previous comments, that goes with test-issue-first-page.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>&#9660;</small></a>
+ | <a href="https://www.google.com/accounts/ServiceLogin?service=code&amp;ltmpl=phosting&amp;continue=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D6&amp;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&nbsp;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> &nbsp;
+
+ <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">&nbsp;All issues</option>
+<option value="2" selected="selected">&nbsp;Open issues</option>
+<option value="6">&nbsp;New issues</option>
+<option value="7">&nbsp;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>
+ &nbsp;
+ <span class="inIssueAdvSearch">
+<a href="advsearch">Advanced search</a>
+</span> &nbsp;
+ <span class="inIssueSearchTips">
+<a href="searchtips">Search tips</a>
+</span> &nbsp;
+ <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 &quot;Issue&quot;</span>
+</td>
+<td>
+<div class="pagination">
+<a href="../../allura-google-importer/issues/detail?id=5" title="Prev">&lsaquo; 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:&nbsp;</th>
+<td width="100%">
+<span title="Work on this issue has begun">Started</span>
+</td>
+</tr>
+<tr><th align="left">Owner:&nbsp;</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&amp;ltmpl=phosting&amp;continue=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D6&amp;followup=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D6">Sign in</a> to add a comment</div>
+</div>&nbsp;
+ </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
+    if p.count &gt; 5:
+        print "Not &lt; 5 &amp; != 5"
+
+References: <a href="/p/allura-google-importer/issues/detail?id=1">issue 1</a>, <a href="/p/allura-google-importer/source/detail?r=2">r2</a>
+
+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&amp;name=at1.txt&amp;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
+
+
+ &nbsp; <a href="../../allura-google-importer/issues/attachmentText?id=7&amp;aid=70000000&amp;name=at1.txt&amp;token=3REU1M3JUUMt0rJUg7ldcELt6LA%3A1376059941255" target="_blank">View</a>
+
+ &nbsp; <a href="//allura-google-importer.googlecode.com/issues/attachment?aid=70000000&amp;name=at1.txt&amp;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&amp;name=&amp;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></b>
+<br />
+ 0 bytes
+
+
+ &nbsp; <a href="//allura-google-importer.googlecode.com/issues/attachment?aid=70000001&amp;name=&amp;token=C9Hn4s1-g38hlSggRGo65VZM1ys%3A1376059941255">Download</a>
+</td>
+</tr>
+</table>
+</div>
+</div>
+
+ <div class="vt issuecomment" width="100%" style="background:#e5ecf9; padding:2px .7em; margin:0; border:0">
+ <a href="detail?id=1769&amp;cnum=500&amp;cstart=502">Newer <b>&rsaquo;</b></a>
+ &nbsp;
+Showing comments 1 - 2
+of 6
+ </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:34:01 2013">
+ Today (3 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>
+Simple comment
+</pre>
+</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:34:09 2013">
+ Today (3 minutes 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>
+Boring comment
+</pre>
+</div>
+
+<div class="vt issuecomment" width="100%" style="background:#e5ecf9; padding:2px .7em; margin:0">
+ <a href="detail?id=1769&amp;cnum=500&amp;cstart=502">Newer <b>&rsaquo;</b></a>
+ &nbsp;
+Showing comments 1 - 2
+of 6
+</div>
+
+</td>
+</tr>
+<tr>
+<td></td>
+<td class="vt issuecomment">
+<span class="indicator">&#9658;</span> <a href="https://www.google.com/accounts/ServiceLogin?service=code&amp;ltmpl=phosting&amp;continue=http%3A%2F%2Fcode.google.com%2Fp%2Fallura-google-importer%2Fissues%2Fdetail%3Fid%3D6&amp;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=&amp;can=2&amp;groupby=&amp;sort=&amp;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/allura/blob/225dc73c/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 c6bce0a..59507a9 100644
--- a/ForgeImporters/forgeimporters/tests/data/google/test-issue.html
+++ b/ForgeImporters/forgeimporters/tests/data/google/test-issue.html
@@ -1,4 +1,9 @@
 <!DOCTYPE html>
+<!--
+
+Just a regular single-page issue
+
+-->
 <html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
@@ -323,6 +328,7 @@ That's all
 </table>
 </div>
 </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">
@@ -469,6 +475,7 @@ Oh, I forgot one (with an inter-project reference to <a href="/p/other-project/i
 <div class="round4"></div>
 </div>
 </div>
+
 </td>
 </tr>
 <tr>

http://git-wip-us.apache.org/repos/asf/allura/blob/225dc73c/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 96d789d..938d1c7 100644
--- a/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
+++ b/ForgeImporters/forgeimporters/tests/google/functional/test_tracker.py
@@ -31,6 +31,7 @@ from allura import model as M
 from forgetracker import model as TM
 from forgeimporters import base
 from forgeimporters import google
+import forgeimporters.google.tracker
 
 
 class TestGCTrackerImporter(TestCase):
@@ -42,6 +43,10 @@ class TestGCTrackerImporter(TestCase):
                 'allura-google-importer', 'project_info')
         extractor.page = BeautifulSoup(html)
         extractor.url = "http://test/issue/?id=1"
+        # iter_comments will make more get_page() calls but we don't want the real thing to run an mess up the .page
+        # and .url attributes, make it a no-op which works with these tests (since its just the same page being
+        # fetched really)
+        extractor.get_page = lambda *a, **kw: ''
         return extractor
 
     def _make_ticket(self, issue, issue_id=1):
@@ -197,7 +202,7 @@ class TestGCTrackerImporter(TestCase):
                    for a in actual)
         self.assertEqual(atts, set(expected))
 
-    def test_attachements(self):
+    def test_attachments(self):
         ticket = self._make_ticket(self.test_issue)
         self._assert_attachments(ticket.attachments,
                                  ('at1.txt', 'text/plain',

http://git-wip-us.apache.org/repos/asf/allura/blob/225dc73c/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 60ca0e2..fe74f9c 100644
--- a/ForgeImporters/forgeimporters/tests/google/test_extractor.py
+++ b/ForgeImporters/forgeimporters/tests/google/test_extractor.py
@@ -33,7 +33,6 @@ class TestGoogleCodeProjectExtractor(TestCase):
 
     def setUp(self):
         self._p_urlopen = mock.patch.object(base.ProjectExtractor, 'urlopen')
-        # self._p_soup = mock.patch.object(google, 'BeautifulSoup')
         self._p_soup = mock.patch.object(base, 'BeautifulSoup')
         self.urlopen = self._p_urlopen.start()
         self.soup = self._p_soup.start()
@@ -145,8 +144,7 @@ class TestGoogleCodeProjectExtractor(TestCase):
 
     def _make_extractor(self, html):
         with mock.patch.object(base.ProjectExtractor, 'urlopen'):
-            extractor = google.GoogleCodeProjectExtractor(
-                'allura-google-importer')
+            extractor = google.GoogleCodeProjectExtractor('allura-google-importer')
         extractor.page = BeautifulSoup(html)
         extractor.get_page = lambda pagename: extractor.page
         extractor.url = "http://test/source/browse"
@@ -184,9 +182,9 @@ class TestGoogleCodeProjectExtractor(TestCase):
 
     @without_module('html2text')
     def test_get_issue_basic_fields(self):
-        test_issue = open(pkg_resources.resource_filename(
-            'forgeimporters', 'tests/data/google/test-issue.html')).read()
+        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().url,
                          'http://code.google.com/u/101557263855536553789/')
@@ -224,8 +222,7 @@ class TestGoogleCodeProjectExtractor(TestCase):
 
     @skipif(module_not_available('html2text'))
     def test_get_issue_basic_fields_html2text(self):
-        test_issue = open(pkg_resources.resource_filename(
-            'forgeimporters', 'tests/data/google/test-issue.html')).read()
+        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().url,
@@ -280,12 +277,6 @@ class TestGoogleCodeProjectExtractor(TestCase):
         gpe = self._make_extractor(html % u'My Summary')
         self.assertEqual(gpe.get_issue_summary(), u'My Summary')
 
-    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()
@@ -316,18 +307,116 @@ class TestGoogleCodeProjectExtractor(TestCase):
             attachments[0].url, 'http://allura-google-importer.googlecode.com/issues/attachment?aid=70000000&name=at1.txt&token=3REU1M3JUUMt0rJUg7ldcELt6LA%3A1376059941255')
         self.assertEqual(attachments[0].type, 'text/plain')
 
+    def test_get_issue_ids(self):
+        extractor = google.GoogleCodeProjectExtractor(None)
+        extractor.get_page = mock.Mock(side_effect=((1, 2, 3), (2, 3, 4), ()))
+        self.assertItemsEqual(extractor.get_issue_ids(start=10), (1, 2, 3, 4))
+        self.assertEqual(extractor.get_page.call_count, 3)
+        extractor.get_page.assert_has_calls([
+            mock.call('issues_csv', parser=google.csv_parser, start=10),
+            mock.call('issues_csv', parser=google.csv_parser, start=110),
+            mock.call('issues_csv', parser=google.csv_parser, start=210),
+        ])
+
+    @mock.patch.object(google.GoogleCodeProjectExtractor, 'get_page')
+    @mock.patch.object(google.GoogleCodeProjectExtractor, 'get_issue_ids')
+    def test_iter_issue_ids(self, get_issue_ids, get_page):
+        get_issue_ids.side_effect = [set([1, 2]), set([2, 3, 4])]
+        issue_ids = [i for i,
+                     e in list(google.GoogleCodeProjectExtractor.iter_issues('foo'))]
+        self.assertEqual(issue_ids, [1, 2, 3, 4])
+        get_issue_ids.assert_has_calls([
+            mock.call(start=0),
+            mock.call(start=-8),
+        ])
+
+    @mock.patch.object(google.GoogleCodeProjectExtractor, '__init__')
+    @mock.patch.object(google.GoogleCodeProjectExtractor, 'get_issue_ids')
+    def test_iter_issue_ids_raises(self, get_issue_ids, __init__):
+        get_issue_ids.side_effect = [set([1, 2, 3, 4, 5])]
+        __init__.side_effect = [
+            None,
+            None,
+            # should skip but keep going
+            HTTPError('fourohfour', 404, 'fourohfour', {}, mock.Mock()),
+            None,
+            # should be re-raised
+            HTTPError('fubar', 500, 'fubar', {}, mock.Mock()),
+            None,
+        ]
+        issue_ids = []
+        try:
+            for issue_id, extractor in google.GoogleCodeProjectExtractor.iter_issues('foo'):
+                issue_ids.append(issue_id)
+        except HTTPError as e:
+            self.assertEqual(e.code, 500)
+        else:
+            assert False, 'Missing expected raised exception'
+        self.assertEqual(issue_ids, [1, 3])
+
+    @mock.patch.object(google.requests, 'head')
+    def test_check_readable(self, head):
+        head.return_value.status_code = 200
+        assert google.GoogleCodeProjectExtractor('my-project').check_readable()
+        head.return_value.status_code = 404
+        assert not google.GoogleCodeProjectExtractor('my-project').check_readable()
+
+
+class TestWithSetupForComments(TestCase):
+    # The main test suite did too much patching for how we want these tests to work
+    # These tests use iter_comments and 2 HTML pages of comments.
+
+    def _create_extractor(self):
+        test_issue = open(pkg_resources.resource_filename('forgeimporters', 'tests/data/google/test-issue-first-page.html')).read()
+        test_issue_older = open(pkg_resources.resource_filename('forgeimporters', 'tests/data/google/test-issue-prev-page.html')).read()
+
+        class LocalTestExtractor(google.GoogleCodeProjectExtractor):
+            def urlopen(self, url, **kw):
+                return self.urlopen_results.pop(0)
+
+            def setup_urlopen_results(self, results):
+                self.urlopen_results = results
+
+        gpe = LocalTestExtractor('allura-google-importer')
+        gpe.setup_urlopen_results([test_issue, test_issue_older])
+
+        return gpe
+
+    def test_get_issue_mod_date(self):
+        gpe = self._create_extractor()
+        gpe.get_page('detail?id=6')
+        self.assertEqual(gpe.get_issue_mod_date(), 'Thu Aug  8 15:36:57 2013')
+
     @without_module('html2text')
     @mock.patch.object(base, 'StringIO')
     def test_iter_comments(self, StringIO):
-        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)
+        gpe = self._create_extractor()
+        gpe.get_page('detail?id=6')
+
+        with mock.patch.object(base.ProjectExtractor, 'urlopen'):  # for attachments, which end up using a different Extractor urlopen
+            comments = list(gpe.iter_comments())
+
+        self.assertEqual(len(comments), 6)
         expected = [
             {
                 'author.name': 'john...@gmail.com',
                 'author.url': 'http://code.google.com/u/101557263855536553789/',
+                'created_date': 'Thu Aug  8 15:34:01 2013',
+                'body': 'Simple comment',
+                'updates': {},
+                'attachments': [],
+            },
+            {
+                'author.name': 'john...@gmail.com',
+                'author.url': 'http://code.google.com/u/101557263855536553789/',
+                'created_date': 'Thu Aug  8 15:34:09 2013',
+                'body': 'Boring comment',
+                'updates': {},
+                'attachments': [],
+            },
+            {
+                'author.name': 'john...@gmail.com',
+                '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'},
@@ -370,15 +459,33 @@ class TestGoogleCodeProjectExtractor(TestCase):
     @skipif(module_not_available('html2text'))
     @mock.patch.object(base, 'StringIO')
     def test_iter_comments_html2text(self, StringIO):
-        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)
+        gpe = self._create_extractor()
+        gpe.get_page('detail?id=6')
+
+        with mock.patch.object(base.ProjectExtractor, 'urlopen'):  # for attachments, which end up using a different Extractor urlopen
+            comments = list(gpe.iter_comments())
+
+        self.assertEqual(len(comments), 6)
         expected = [
             {
                 'author.name': 'john...@gmail.com',
                 'author.url': 'http://code.google.com/u/101557263855536553789/',
+                'created_date': 'Thu Aug  8 15:34:01 2013',
+                'body': 'Simple comment',
+                'updates': {},
+                'attachments': [],
+            },
+            {
+                'author.name': 'john...@gmail.com',
+                'author.url': 'http://code.google.com/u/101557263855536553789/',
+                'created_date': 'Thu Aug  8 15:34:09 2013',
+                'body': 'Boring comment',
+                'updates': {},
+                'attachments': [],
+            },
+            {
+                'author.name': 'john...@gmail.com',
+                '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'},
@@ -418,60 +525,6 @@ class TestGoogleCodeProjectExtractor(TestCase):
             self.assertEqual(
                 [a.filename for a in actual.attachments], expected['attachments'])
 
-    def test_get_issue_ids(self):
-        extractor = google.GoogleCodeProjectExtractor(None)
-        extractor.get_page = mock.Mock(side_effect=((1, 2, 3), (2, 3, 4), ()))
-        self.assertItemsEqual(extractor.get_issue_ids(start=10), (1, 2, 3, 4))
-        self.assertEqual(extractor.get_page.call_count, 3)
-        extractor.get_page.assert_has_calls([
-            mock.call('issues_csv', parser=google.csv_parser, start=10),
-            mock.call('issues_csv', parser=google.csv_parser, start=110),
-            mock.call('issues_csv', parser=google.csv_parser, start=210),
-        ])
-
-    @mock.patch.object(google.GoogleCodeProjectExtractor, 'get_page')
-    @mock.patch.object(google.GoogleCodeProjectExtractor, 'get_issue_ids')
-    def test_iter_issue_ids(self, get_issue_ids, get_page):
-        get_issue_ids.side_effect = [set([1, 2]), set([2, 3, 4])]
-        issue_ids = [i for i,
-                     e in list(google.GoogleCodeProjectExtractor.iter_issues('foo'))]
-        self.assertEqual(issue_ids, [1, 2, 3, 4])
-        get_issue_ids.assert_has_calls([
-            mock.call(start=0),
-            mock.call(start=-8),
-        ])
-
-    @mock.patch.object(google.GoogleCodeProjectExtractor, '__init__')
-    @mock.patch.object(google.GoogleCodeProjectExtractor, 'get_issue_ids')
-    def test_iter_issue_ids_raises(self, get_issue_ids, __init__):
-        get_issue_ids.side_effect = [set([1, 2, 3, 4, 5])]
-        __init__.side_effect = [
-            None,
-            None,
-            # should skip but keep going
-            HTTPError('fourohfour', 404, 'fourohfour', {}, mock.Mock()),
-            None,
-            # should be re-raised
-            HTTPError('fubar', 500, 'fubar', {}, mock.Mock()),
-            None,
-        ]
-        issue_ids = []
-        try:
-            for issue_id, extractor in google.GoogleCodeProjectExtractor.iter_issues('foo'):
-                issue_ids.append(issue_id)
-        except HTTPError as e:
-            self.assertEqual(e.code, 500)
-        else:
-            assert False, 'Missing expected raised exception'
-        self.assertEqual(issue_ids, [1, 3])
-
-    @mock.patch.object(google.requests, 'head')
-    def test_check_readable(self, head):
-        head.return_value.status_code = 200
-        assert google.GoogleCodeProjectExtractor('my-project').check_readable()
-        head.return_value.status_code = 404
-        assert not google.GoogleCodeProjectExtractor('my-project').check_readable()
-
 
 class TestUserLink(TestCase):
 


[10/25] allura git commit: [#6017] ticket:751 Add attachment information to ticket changelog entries

Posted by je...@apache.org.
[#6017] ticket:751 Add attachment information to ticket changelog entries


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/130ccecc
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/130ccecc
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/130ccecc

Branch: refs/heads/ib/7856
Commit: 130cceccd0c4ce69e0b37cb1977df5bb2b33c20b
Parents: a3f7d44
Author: Aleksey 'LXj' Alekseyev <go...@gmail.com>
Authored: Tue Apr 7 17:22:16 2015 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Apr 16 10:43:47 2015 +0000

----------------------------------------------------------------------
 ForgeTracker/forgetracker/tracker_main.py | 10 ++++++++++
 1 file changed, 10 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/130ccecc/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index 4f20d88..2b4e807 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -1389,6 +1389,14 @@ class TicketController(BaseController, FeedController):
 
     @require_post()
     def _update_ticket(self, post_data):
+        def attachments_info(attachments):
+            text = ''
+            for attach in attachments:
+                text = "%s %s (%s; %s) " % (
+                    text, attach.filename,
+                    h.do_filesizeformat(attach.length), attach.content_type)
+            return text
+
         require_access(self.ticket, 'update')
         changes = changelog()
         comment = post_data.pop('comment', None)
@@ -1424,7 +1432,9 @@ class TicketController(BaseController, FeedController):
 
         if 'attachment' in post_data:
             attachment = post_data['attachment']
+            changes['attachments'] = attachments_info(self.ticket.attachments)
             self.ticket.add_multiple_attachments(attachment)
+            changes['attachments'] = attachments_info(self.ticket.attachments)
         for cf in c.app.globals.custom_fields or []:
             if 'custom_fields.' + cf.name in post_data:
                 value = post_data['custom_fields.' + cf.name]


[17/25] allura git commit: Remove warnings like the following, for setuptools < 14.3.1, >=8.0

Posted by je...@apache.org.
Remove warnings like the following, for setuptools < 14.3.1, >=8.0

PEP440Warning: 'ForgeBlog (0.0dev-r0)' is being parsed as a legacy, non PEP 440,
version. You may find odd behavior and sort order. In particular it will be
sorted as less than 0.0. It is recommend to migrate to PEP 440 compatible versions.


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/3ff1adec
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/3ff1adec
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/3ff1adec

Branch: refs/heads/ib/7856
Commit: 3ff1adec484e9201e19216416038908f84b53062
Parents: 3d7b62b
Author: Dave Brondsema <da...@brondsema.net>
Authored: Thu Apr 16 17:47:16 2015 -0400
Committer: Dave Brondsema <da...@brondsema.net>
Committed: Thu Apr 16 17:47:16 2015 -0400

----------------------------------------------------------------------
 Allura/setup.cfg          | 3 +--
 ForgeActivity/setup.cfg   | 3 +--
 ForgeBlog/setup.cfg       | 3 +--
 ForgeChat/setup.cfg       | 3 +--
 ForgeDiscussion/setup.cfg | 3 +--
 ForgeGit/setup.cfg        | 3 +--
 ForgeLink/setup.cfg       | 3 +--
 ForgeSVN/setup.cfg        | 3 +--
 ForgeTracker/setup.cfg    | 3 +--
 ForgeWiki/setup.cfg       | 3 +--
 requirements.txt          | 2 +-
 11 files changed, 11 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/3ff1adec/Allura/setup.cfg
----------------------------------------------------------------------
diff --git a/Allura/setup.cfg b/Allura/setup.cfg
index dffd7e7..a835b71 100644
--- a/Allura/setup.cfg
+++ b/Allura/setup.cfg
@@ -16,8 +16,7 @@
 #       under the License.
 
 [egg_info]
-tag_build = dev
-tag_svn_revision = true
+tag_build = dev0
 
 [easy_install]
 find_links = http://www.pylonshq.com/download/

http://git-wip-us.apache.org/repos/asf/allura/blob/3ff1adec/ForgeActivity/setup.cfg
----------------------------------------------------------------------
diff --git a/ForgeActivity/setup.cfg b/ForgeActivity/setup.cfg
index 01bb954..2637327 100644
--- a/ForgeActivity/setup.cfg
+++ b/ForgeActivity/setup.cfg
@@ -1,3 +1,2 @@
 [egg_info]
-tag_build = dev
-tag_svn_revision = true
+tag_build = dev0

http://git-wip-us.apache.org/repos/asf/allura/blob/3ff1adec/ForgeBlog/setup.cfg
----------------------------------------------------------------------
diff --git a/ForgeBlog/setup.cfg b/ForgeBlog/setup.cfg
index 01bb954..2637327 100644
--- a/ForgeBlog/setup.cfg
+++ b/ForgeBlog/setup.cfg
@@ -1,3 +1,2 @@
 [egg_info]
-tag_build = dev
-tag_svn_revision = true
+tag_build = dev0

http://git-wip-us.apache.org/repos/asf/allura/blob/3ff1adec/ForgeChat/setup.cfg
----------------------------------------------------------------------
diff --git a/ForgeChat/setup.cfg b/ForgeChat/setup.cfg
index 01bb954..2637327 100644
--- a/ForgeChat/setup.cfg
+++ b/ForgeChat/setup.cfg
@@ -1,3 +1,2 @@
 [egg_info]
-tag_build = dev
-tag_svn_revision = true
+tag_build = dev0

http://git-wip-us.apache.org/repos/asf/allura/blob/3ff1adec/ForgeDiscussion/setup.cfg
----------------------------------------------------------------------
diff --git a/ForgeDiscussion/setup.cfg b/ForgeDiscussion/setup.cfg
index 01bb954..2637327 100644
--- a/ForgeDiscussion/setup.cfg
+++ b/ForgeDiscussion/setup.cfg
@@ -1,3 +1,2 @@
 [egg_info]
-tag_build = dev
-tag_svn_revision = true
+tag_build = dev0

http://git-wip-us.apache.org/repos/asf/allura/blob/3ff1adec/ForgeGit/setup.cfg
----------------------------------------------------------------------
diff --git a/ForgeGit/setup.cfg b/ForgeGit/setup.cfg
index 01bb954..2637327 100644
--- a/ForgeGit/setup.cfg
+++ b/ForgeGit/setup.cfg
@@ -1,3 +1,2 @@
 [egg_info]
-tag_build = dev
-tag_svn_revision = true
+tag_build = dev0

http://git-wip-us.apache.org/repos/asf/allura/blob/3ff1adec/ForgeLink/setup.cfg
----------------------------------------------------------------------
diff --git a/ForgeLink/setup.cfg b/ForgeLink/setup.cfg
index 01bb954..2637327 100644
--- a/ForgeLink/setup.cfg
+++ b/ForgeLink/setup.cfg
@@ -1,3 +1,2 @@
 [egg_info]
-tag_build = dev
-tag_svn_revision = true
+tag_build = dev0

http://git-wip-us.apache.org/repos/asf/allura/blob/3ff1adec/ForgeSVN/setup.cfg
----------------------------------------------------------------------
diff --git a/ForgeSVN/setup.cfg b/ForgeSVN/setup.cfg
index 01bb954..2637327 100644
--- a/ForgeSVN/setup.cfg
+++ b/ForgeSVN/setup.cfg
@@ -1,3 +1,2 @@
 [egg_info]
-tag_build = dev
-tag_svn_revision = true
+tag_build = dev0

http://git-wip-us.apache.org/repos/asf/allura/blob/3ff1adec/ForgeTracker/setup.cfg
----------------------------------------------------------------------
diff --git a/ForgeTracker/setup.cfg b/ForgeTracker/setup.cfg
index 01bb954..2637327 100644
--- a/ForgeTracker/setup.cfg
+++ b/ForgeTracker/setup.cfg
@@ -1,3 +1,2 @@
 [egg_info]
-tag_build = dev
-tag_svn_revision = true
+tag_build = dev0

http://git-wip-us.apache.org/repos/asf/allura/blob/3ff1adec/ForgeWiki/setup.cfg
----------------------------------------------------------------------
diff --git a/ForgeWiki/setup.cfg b/ForgeWiki/setup.cfg
index 01bb954..2637327 100644
--- a/ForgeWiki/setup.cfg
+++ b/ForgeWiki/setup.cfg
@@ -1,3 +1,2 @@
 [egg_info]
-tag_build = dev
-tag_svn_revision = true
+tag_build = dev0

http://git-wip-us.apache.org/repos/asf/allura/blob/3ff1adec/requirements.txt
----------------------------------------------------------------------
diff --git a/requirements.txt b/requirements.txt
index 21b0ca5..fffb91d 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,4 +1,3 @@
-pytz==2012j
 ActivityStream==0.2.0
 BeautifulSoup==3.2.0
 Beaker==1.6.4
@@ -36,6 +35,7 @@ pysolr==2.1.0-beta
 python-dateutil==1.5
 python-magic==0.4.3
 python-oembed==0.2.1
+pytz==2014.10
 requests==2.0.0
 oauthlib==0.4.2
 requests-oauthlib==0.4.0


[11/25] allura git commit: [#6017] ticket:756 Show attachments list as a diff, so it's easy to see what was added or removed

Posted by je...@apache.org.
[#6017] ticket:756 Show attachments list as a diff, so it's easy to see what was added or removed


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/9546f5ae
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/9546f5ae
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/9546f5ae

Branch: refs/heads/ib/7856
Commit: 9546f5ae425c02cd21266a047a2b34ebb50bbf5e
Parents: da94700
Author: Igor Bondarenko <je...@gmail.com>
Authored: Thu Apr 16 11:04:23 2015 +0000
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Apr 16 11:04:23 2015 +0000

----------------------------------------------------------------------
 ForgeTracker/forgetracker/data/ticket_changed_tmpl |  4 ++--
 ForgeTracker/forgetracker/tracker_main.py          | 11 ++++++-----
 2 files changed, 8 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/9546f5ae/ForgeTracker/forgetracker/data/ticket_changed_tmpl
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/data/ticket_changed_tmpl b/ForgeTracker/forgetracker/data/ticket_changed_tmpl
index 899b353..c04d92d 100644
--- a/ForgeTracker/forgetracker/data/ticket_changed_tmpl
+++ b/ForgeTracker/forgetracker/data/ticket_changed_tmpl
@@ -20,8 +20,8 @@
 {% python from allura.model import User %}\
 {% for key, values in changelist %}\
 {% choose %}\
-{% when key == 'description' %}\
-- Description has changed:
+{% when key in ['description', 'attachments'] %}\
+- ${key.capitalize()} has changed:
 
 Diff:
 

http://git-wip-us.apache.org/repos/asf/allura/blob/9546f5ae/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index 7558eab..f8a5680 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -1391,12 +1391,13 @@ class TicketController(BaseController, FeedController):
     @require_post()
     def _update_ticket(self, post_data):
         def attachments_info(attachments):
-            text = ''
+            text = []
             for attach in attachments:
-                text = "%s %s (%s; %s) " % (
-                    text, attach.filename,
-                    h.do_filesizeformat(attach.length), attach.content_type)
-            return text
+                text.append("{} ({}; {})".format(
+                    attach.filename,
+                    h.do_filesizeformat(attach.length),
+                    attach.content_type))
+            return "\n".join(text)
 
         require_access(self.ticket, 'update')
         changes = changelog()


[13/25] allura git commit: [#6017] ticket:756 Test attachments changelog better

Posted by je...@apache.org.
[#6017] ticket:756 Test attachments changelog better


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/ad7c5f9c
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/ad7c5f9c
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/ad7c5f9c

Branch: refs/heads/ib/7856
Commit: ad7c5f9cc4ea231dc896a7fbb14be6956125cd4a
Parents: b5a084f
Author: Igor Bondarenko <je...@gmail.com>
Authored: Thu Apr 16 15:10:13 2015 +0000
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Apr 16 15:10:13 2015 +0000

----------------------------------------------------------------------
 ForgeTracker/forgetracker/tests/functional/test_root.py | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/ad7c5f9c/ForgeTracker/forgetracker/tests/functional/test_root.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tests/functional/test_root.py b/ForgeTracker/forgetracker/tests/functional/test_root.py
index 666fbc1..21a3564 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_root.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_root.py
@@ -790,6 +790,10 @@ class TestFunctionalController(TrackerTestController):
         }, upload_files=[upload]).follow()
         assert_true(file_name in ticket_editor)
         assert '<span>py</span>' not in ticket_editor
+        ticket_page = self.app.get('/bugs/1/')
+        diff = ticket_page.html.findAll('div', attrs={'class': 'codehilite'})
+        added = diff[-1].findAll('span', attrs={'class': 'gi'})[-1]
+        assert_in('+test_root.py', added.getText())
 
     def test_delete_attachment(self):
         file_name = 'test_root.py'
@@ -806,8 +810,11 @@ class TestFunctionalController(TrackerTestController):
         self.app.post(str(file_link['href']), {
             'delete': 'True'
         })
-        deleted_form = self.app.get('/bugs/1/')
-        assert file_link not in deleted_form
+        ticket_page = self.app.get('/bugs/1/')
+        assert file_link not in ticket_page
+        diff = ticket_page.html.findAll('div', attrs={'class': 'codehilite'})
+        removed = diff[-1].findAll('span', attrs={'class': 'gd'})[-1]
+        assert_in('-test_root.py', removed.getText())
 
     def test_delete_attachment_from_comments(self):
         ticket_view = self.new_ticket(summary='test ticket').follow()


[19/25] allura git commit: [#7870] Add missing config examples, move some configs up from app:tool_test, standardize format for example vs default configs

Posted by je...@apache.org.
[#7870] Add missing config examples, move some configs up from app:tool_test, standardize format for example vs default configs


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/c5666811
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/c5666811
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/c5666811

Branch: refs/heads/ib/7856
Commit: c566681169a1f4c95c9b1a6314290d52e82a844a
Parents: 251f413
Author: Dave Brondsema <da...@brondsema.net>
Authored: Thu Apr 9 18:23:55 2015 -0400
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Mon Apr 20 12:51:30 2015 -0400

----------------------------------------------------------------------
 Allura/development.ini | 258 ++++++++++++++++++++++++++++++--------------
 1 file changed, 178 insertions(+), 80 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/c5666811/Allura/development.ini
----------------------------------------------------------------------
diff --git a/Allura/development.ini b/Allura/development.ini
index b7ccde6..4a4f18c 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -14,28 +14,42 @@
 ;       KIND, either express or implied.  See the License for the
 ;       specific language governing permissions and limitations
 ;       under the License.
+
+
+;
+; Allura configuration
 ;
-; allura - Pylons development environment configuration
+; Default config values are shown in this file.
+; Commented-out configurations are examples that you can use if you want.
 ;
-; The %(here)s variable will be replaced with the parent directory of this file
+; Logging configuration is at the end of the file (starting at [loggers])
 ;
-; This file is for deployment specific config options -- other configuration
-; that is always required for the app is done in the config directory,
-; and generally should not be modified by end users.
+; There are many settings you should change for your site (name, domain, secret keys, etc)
+; More settings should be changed for good performance in a production site (no autoreload, no debugging, etc)
+;
+; You may copy this file to make a new configuration file (e.g. production.ini)
+; Just use the new file name instead of development.ini for any paster commands you run.
+
+
+; TODO:
+; remove test config
+; clarify debug settings
 
 [DEFAULT]
 debug = true
 ; Uncomment and replace with the address which should receive any error reports
 ;email_to = you@yourdomain.com
 
-; Smtp settings
-;smtp_tls = False
-;smtp_ssl = True
+; SMTP settings for outgoing mail
+smtp_tls = false
+smtp_ssl = false
 ;smtp_user = some_user
 ;smtp_password = some_password
-;smtp_timeout = 10
+smtp_timeout = 10
 smtp_server = localhost
 smtp_port = 8826
+; Reply-To and From address often used in email notifications:
+forgemail.return_path = noreply@sf.net
 
 error_email_from = paste@localhost
 ; Used to uniquify references to static resources, can be a timestamp or any unique value
@@ -54,17 +68,25 @@ next=main
 [app:main]
 use = egg:Allura
 full_stack = true
-site_name = Allura
 
+; Change this to your website's name
+site_name = Allura
+; Change these to your website's domain
 domain = localhost
 base_url = http://localhost:8080
 
-;lang = ru
 cache_dir = %(here)s/data
 
 ; Cache Neighborhood objects for N seconds (speeds up requests).
 ; Set to 0 to disable (the default).
-; neighborhood.cache.duration = 0
+;neighborhood.cache.duration = 0
+
+; Template cache settings
+; See http://jinja.pocoo.org/docs/api/#jinja2.Environment
+jinja_cache_size = -1
+;jinja_bytecode_cache_type = filesystem
+;jinja_bytecode_cache_type = memcached
+;memcached_host =
 
 ; Docs at http://beaker.readthedocs.org/en/latest/configuration.html#session-options
 ; and http://beaker.readthedocs.org/en/latest/modules/session.html#beaker.session.CookieSession
@@ -77,26 +99,29 @@ beaker.session.secure = false
 beaker.session.validate_key = 714bfe3612c42390726f
 
 ; Google Analytics account for tracking
-; ga.account = UA-XXXXX-X
+;ga.account = UA-XXXXX-X
 
+; Project registration system.  Only local is available, unless you write a custom one for custom integratino.
 registration.method = local
-; theme = sftheme
 theme = allura
-show_export_control = false
 
-; auth.method = ldap
+; For LDAP see https://forge-allura.apache.org/docs/getting_started/installation.html#using-ldap
+;auth.method = ldap
 auth.method = local
 auth.remember_for = 365  ; in days, for the "remember me" checkbox on login
-; auth.login_url = /auth/
-; auth.logout_url = /auth/logout
-; auth.login_fragment_url = /auth/login_fragment
+
+; Customize login/logout URLs only if you have some custom authentication set up.
+auth.login_url = /auth/
+auth.logout_url = /auth/logout
+auth.login_fragment_url = /auth/login_fragment/
+auth.post_logout_url = /
 
 auth.min_password_len = 6
 auth.max_password_len = 30
 
 ; password expiration options (disabled if neither is set)
-; auth.pwdexpire.days = 1
-; auth.pwdexpire.before = 1401949912  ; unix timestamp
+;auth.pwdexpire.days = 1
+;auth.pwdexpire.before = 1401949912  ; unix timestamp
 
 ; if using LDAP, also run `pip install python-ldap` in your Allura environment
 
@@ -124,6 +149,8 @@ auth.allow_user_messages_config = true
 auth.allow_birth_date = true
 auth.allow_non_primary_email_password_reset = true
 auth.require_email_addr = true
+; List of social network options to use on user account settings
+socialnetworks = Facebook, Linkedin, Twitter, Google+
 
 ; In seconds
 auth.recovery_hash_expiry_period = 600
@@ -137,6 +164,13 @@ user_prefs_storage.ldap.fields.display_name = cn
 ; Limit the number of emails a user can claim.
 user_prefs.maximum_claimed_emails = 20
 
+; Control the order of sections on the user profile page
+;user_profile_sections.order = activity, personal-data, skills
+
+; Site admins will be the same as the admins of this project:
+site_admin_project = allura
+site_admin_project_nbhd = Projects
+
 ; Spam filtering service: mollom or akismet
 ;spam.method = akismet
 ; for akismet:
@@ -145,41 +179,39 @@ user_prefs.maximum_claimed_emails = 20
 ;spam.public_key =
 ;spam.private_key =
 
-; webhook.timeout = 30  # seconds, default = 30
-
+; Webhook timeout in seconds
+webhook.timeout = 30
 ; List of pauses between retries, if hook fails (in seconds)
-; webhook.retry = 60 120 240
-
+webhook.retry = 60 120 240
 ; Limit rate of webhook firing (in seconds, default = 30)
 ; Option format: webhook.<hook type>.limit,
 ; all '-' in hook type must be changed to '_'
 ; e.g. for repo-push webhook:
-; webhook.repo_push.limit = 10
-
+webhook.repo_push.limit = 10
 ; Limit max number of hooks that can be created for given project/app
 ; Option name format: same as above.
 ; Value format: json dict, where keys are app names (as appears in
 ; `WebhookSender.triggered_by`) and values are actual limits (default=3), e.g.:
-; webhook.repo_push.max_hooks = {"git": 3, "hg": 3, "svn": 3}
+webhook.repo_push.max_hooks = {"git": 3, "hg": 3, "svn": 3}
 
 ; Additional fields for admin project/user search
 ; Note: whitespace after comma is important!
-; search.project.additional_search_fields = private, url, title
-; search.user.additional_search_fields = email_addresses
+;search.project.additional_search_fields = private, url, title
+;search.user.additional_search_fields = email_addresses
 
 ; Additional fields to show in the result of admin project/user search
 ; Note: whitespace after comma is important!
-; search.project.additional_display_fields = private, url, title
-; search.user.additional_display_fields = email_addresses
+;search.project.additional_display_fields = private, url, title
+;search.user.additional_display_fields = email_addresses
 
 ; To make all pages use ssl:   (also set beaker.session.secure above)
-; force_ssl.pattern = .
+;force_ssl.pattern = .
 ; To use ssl if and only if a user is logged in:
-; force_ssl.logged_in = true
+;force_ssl.logged_in = true
 ; If you set force_ssl.logged_in, you probably want some URLs to be ssl when logged out:
-; force_ssl.pattern = ^/auth|^/[a-z0-9-]+/import_project/  ; import_project uses a login overlay
+;force_ssl.pattern = ^/auth|^/[a-z0-9-]+/import_project/  ; import_project uses a login overlay
 ; And to permit some URLs to be accessed over http anyway:
-; no_redirect.pattern = ^/nf/\d+/_(ew|static)_/|^/rest/|^/nf/tool_icon_css|^/auth/refresh_repo
+;no_redirect.pattern = ^/nf/\d+/_(ew|static)_/|^/rest/|^/nf/tool_icon_css|^/auth/refresh_repo
 
 
 ; Set the locations of some static resources.  ("ew" stands for EasyWidgets library)
@@ -210,12 +242,12 @@ scm.host.ro.svn = file:///srv/svn$path/
 scm.host.rw.svn = file:///srv/svn$path/
 
 ; SCM settings for chroot + ldap configuration.  See Allura/docs/getting_started/scm_host.rst
-; scm.host.ro.git = git://git.localhost$path
-; scm.host.rw.git = ssh://$username@localhost:8022/scm-repo$path
-; scm.host.ro.hg = http://hg.localhost$path
-; scm.host.rw.hg = ssh://$username@localhost:8022/scm-repo$path
-; scm.host.ro.svn = http://svn.localhost$path/
-; scm.host.rw.svn = svn+ssh://localhost:8022/scm-repo$path/
+;scm.host.ro.git = git://git.localhost$path
+;scm.host.rw.git = ssh://$username@localhost:8022/scm-repo$path
+;scm.host.ro.hg = http://hg.localhost$path
+;scm.host.rw.hg = ssh://$username@localhost:8022/scm-repo$path
+;scm.host.ro.svn = http://svn.localhost$path/
+;scm.host.rw.svn = svn+ssh://localhost:8022/scm-repo$path/
 
 ; SCM settings for https (sorry no docs for setting these up)
 ; these settings are currently required by the template, no matter what
@@ -240,24 +272,46 @@ scm.repos.tarball.zip_binary = /usr/bin/zip
 
 ; SCM imports (currently just SVN) will retry if it fails
 ; You can control the number of tries and delay between tries here:
-;scm.import.retry_count = 50
-;scm.import.retry_sleep_secs = 5
+scm.import.retry_count = 50
+scm.import.retry_sleep_secs = 5
 
 ; One-click merge is enabled by default, but can be turned off on for each type of repo
-;scm.merge.git.disabled = true
-;scm.merge.hg.disabled = true
+scm.merge.git.disabled = false
+scm.merge.hg.disabled = false
 
+
+; bulk_export_enabled = true
+; If you keep bulk_export_enabled, you should set up your server to securely share bulk_export_path with users somehow
 bulk_export_path = /tmp/bulk_export/{nbhd}/{project}
 bulk_export_filename = {project}-backup-{date:%Y-%m-%d-%H%M%S}.zip
+; You will need to specify site-specific instructions here for accessing the exported files.
 bulk_export_download_instructions = Sample instructions for {project}
 
 importer_upload_path = /tmp/importer_upload/{nbhd}/{project}
 
+; To disable any plugin, tool, importer, etc from being available, you can use the disable_entry_points config option.
+; Specify the keys and values as they are declared in the tool's "setup.py" file.
+; Examples:
+;disable_entry_points.importers = google-code-tracker, google-code-repo
+;disable_entry_points.allura.project_importers = google-code
+
+; Importers specifically, can be left enabled but not linked to.  You have to know the URL to use it.  Example:
+;hidden_importers = trac-tickets
+
 ; GitHub importer keys.  For github ticket import, it is best to set
 ; up an app at https://github.com/settings/applications  Use the root URL
 ; of your Allura instance for both URLs, and enter client values here:
-; github_importer.client_id =
-; github_importer.client_secret =
+;github_importer.client_id =
+;github_importer.client_secret =
+
+; If your site has docs about specific importers, you can add them here and
+; they'll appear on the import forms
+;doc.url.importers.Google Code = http://...
+
+; List of oauth API keys permitted to use special forum import API
+; (should be converted to newer importer system)
+;oauth.can_import_forum = api-key-1234, fa832r0fdsafd, f23f80sdf32fd
+
 
 ; space-separated list of tool names that are valid options
 ; for project admins to set for their 'support_page' field
@@ -265,7 +319,13 @@ importer_upload_path = /tmp/importer_upload/{nbhd}/{project}
 ; is disabled by default
 ;support_tool_choices = wiki tickets discussion
 
+; Control how /categories URL can be accessed to edit trove categories (used in project categories and user skills)
+; Default: everyone
 trovecategories.enableediting = true
+; Nobody:
+;trovecategories.enableediting = false
+; Site admins only:
+;trovecategories.enableediting = admin
 
 ; ActivityStream
 activitystream.master = mongodb://127.0.0.1:27017
@@ -285,12 +345,14 @@ ming.project.uri = mongodb://127.0.0.1:27017/project-data
 ming.project.auto_ensure_indexes = False
 ming.task.uri = mongodb://127.0.0.1:27017/task
 ming.task.auto_ensure_indexes = False
-ming.zarkov.uri = mongodb://127.0.0.1:27017/zarkov
-ming.zarkov.auto_ensure_indexes = False
+;ming.zarkov.uri = mongodb://127.0.0.1:27017/zarkov
+;ming.zarkov.auto_ensure_indexes = False
 
 ; Zarkov host setting, requires the zarkov and gevent libraries.
 ;zarkov.host = tcp://127.0.0.1:9000
 
+; A float from 0-1 representing a % of requests to measure timing on.
+; Sampled requests will have timing logged to stats.log (can change file in [handler_timermiddleware] logging section)
 stats.sample_rate = 1
 
 ; Taskd setup
@@ -298,6 +360,10 @@ monq.poll_interval=2
 
 ; SOLR setup
 solr.server = http://localhost:8983/solr
+; Alternate server to use just for querying
+;solr.query_server =
+; Shorter timeout for search queries (longer timeout for saving to solr)
+solr.short_timeout = 10
 ; commit on every add/delete?
 solr.commit = false
 ; commit add operations within N ms
@@ -308,12 +374,15 @@ solr.commitWithin = 10000
 ; convert existing label and custom field data to more appropriate solr types.
 solr.use_new_types = true
 
-; Forgemail server
+; Incoming email settings.  Used when you run: paster smtp_server development.ini
+; address to listen to
 forgemail.host = 0.0.0.0
 forgemail.port = 8825
+; domain suffix for your mail, change this.  You also need to route *.*.*.forgemail.domain to the above host/port via
+; your mail and DNS configuration
 forgemail.domain = .in.sf.net
+; probably unused?
 forgemail.url = http://localhost:8080
-forgemail.return_path = noreply@sf.net
 
 ; Specify the number of projects allowed to be created by a user
 ; depending on the age of their user account.
@@ -321,11 +390,7 @@ forgemail.return_path = noreply@sf.net
 ; (including the default user-project, so you probably want to add 1)
 ; This example allows for 1 project if the account is less than an hour old
 ; and 5 projects if the account is less than a day old.  No limits after that
-; project.rate_limits = {"3600": 2, "86400": 6}
-
-; Special Command settings
-; no need to sleep in devel
-ensure_index.sleep = 0
+;project.rate_limits = {"3600": 2, "86400": 6}
 
 ; set this to "false" if you are deploying to production and want performance improvements
 auto_reload_templates = true
@@ -335,17 +400,64 @@ auto_reload_templates = true
 ; execute malicious code after an exception is raised.
 ;set debug = false
 
+; How frequently users can send messages
+user_message.time_interval = 3600
+user_message.max_messages = 20
+; Default number of times to show a sitewide notification
+site_notification.impressions = 0
+
+; When rendering discussion post Markdown to html, if the render takes longer
+; than `markdown_cache_threshold` (in seconds), the resulting html will be
+; cached and served from cache on subsequent requests. Set to 0 to cache all
+; posts. Remove entirely to cache nothing.
+markdown_cache_threshold = .1
+; markdown text longer than max length will not be converted to html
+markdown_render_max_length = 999999999
+; Don't add rel=nofollow to these domains when generating links from Markdown content
+;nofollow_exempt_domains =
+
+; Export control choices on the project admin overview page.
+show_export_control = false
+
+; By default project admins can soft-delete their projects.
+allow_project_delete = true
+allow_project_undelete = true
+
+; Advanced settings for controlling "Last Commit Doc" algorithm used when visiting any repo browse page
+lcd_thread_chunk_size = 10
+lcd_timeout = 60
+
+
+;
+; Settings for the Blog tool
+;
 ; Enable or disable external RSS feed importing in ForgeBlog tool.
-; Default is "false". This feature requires GPL library "html2text". Install it
-; with following command:
-; pip install -e git://github.com/brondsem/html2text.git#egg=html2text
+; Default is "false". This feature requires GPL library "html2text". Install it with following command:
+;   pip install -e git://github.com/brondsem/html2text.git#egg=html2text
+; You will also need to run `paster pull-rss-feeds development.ini` in a cron job to fetch them.
 forgeblog.exfeed = false
 
+;
+; Settings for the Chat tool
+;
+forgechat.host = irc.freenode.net
+forgechat.port = 6667
+ircbot.nick = allurabot
+
+;
+; Settings for ShortUrl tool
+;
+; Override this if you set up an additional shortening mechanism (e.g. custom short domain)
 short_url.url_pattern = {base_url}/{nbhd}/{project}/{mount_point}/{short_name}
 
-user_message.time_interval = 3600
-user_message.max_messages = 20
 
+;
+; Settings for UserStats tool
+;
+userstats.count_lines_of_code = true
+
+
+; Setup for tool testing
 [app:tool_test]
 use = egg:Allura
 override_root=basetest_project_root ; TurboGears will use controllers/basetest_project_root.py as root controller
@@ -359,12 +471,6 @@ beaker.session.validate_key = 714bfe3612c42390726f
 ; Ming setup
 ming.main.uri = mongo://127.0.0.1:27017/allura:test
 
-sqlalchemy.url = sqlite:///%(here)s/devdata.db
-;echo shouldn't be used together with the logging module.
-sqlalchemy.echo = false
-sqlalchemy.echo_pool = false
-sqlalchemy.pool_recycle = 3600
-
 ; Forgemail server
 forgemail.host = 0.0.0.0
 forgemail.port = 8825
@@ -375,22 +481,14 @@ forgemail.url = http://localhost:8080
 auth.method = local
 registration.method = local
 
-; When rendering discussion post Markdown to html, if the render takes longer
-; than `markdown_cache_threshold` (in seconds), the resulting html will be
-; cached and served from cache on subsequent requests. Set to 0 to cache all
-; posts. Remove entirely to cache nothing.
-markdown_cache_threshold = .1
-; markdown text longer than max length will not be converted to html
-markdown_render_max_length = 999999999
-
-; If your site has docs about specific importers, you can add them here and
-; they'll appear on the import forms
-;doc.url.importers.Google Code = http://...
-
+; setup for the taskd background daemon request controller
 [app:task]
 use = main
 override_root = task ; TurboGears will use controllers/task.py as root controller
 
+
+
+
 ; Logging configuration
 ; Add additional loggers, handlers, formatters here
 ; Uses python's logging config file format


[03/25] allura git commit: [#7864] update pyflakes to avoid invalid warnings from @property.setter dupe fn name; fix new pyflakes warnings

Posted by je...@apache.org.
[#7864] update pyflakes to avoid invalid warnings from @property.setter dupe fn name; fix new pyflakes warnings


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/567b1d41
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/567b1d41
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/567b1d41

Branch: refs/heads/ib/7856
Commit: 567b1d41befe2571e0f7cdd02f061282b1427ffd
Parents: c72837d
Author: Dave Brondsema <da...@brondsema.net>
Authored: Wed Apr 8 16:04:12 2015 -0400
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Wed Apr 15 11:04:03 2015 +0000

----------------------------------------------------------------------
 Allura/allura/command/show_models.py        | 4 ++--
 Allura/allura/controllers/repository.py     | 8 ++++----
 Allura/allura/controllers/site_admin.py     | 6 +++---
 Allura/allura/lib/helpers.py                | 4 ++--
 Allura/allura/model/project.py              | 2 +-
 Allura/allura/tests/test_commands.py        | 7 +++----
 Allura/allura/tests/unit/test_repo.py       | 6 +++---
 ForgeSVN/forgesvn/model/svn.py              | 3 +--
 ForgeTracker/forgetracker/import_support.py | 4 ++--
 ForgeTracker/forgetracker/tracker_main.py   | 6 +++---
 requirements.txt                            | 2 +-
 11 files changed, 25 insertions(+), 27 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/567b1d41/Allura/allura/command/show_models.py
----------------------------------------------------------------------
diff --git a/Allura/allura/command/show_models.py b/Allura/allura/command/show_models.py
index 36aa29e..d941e9e 100644
--- a/Allura/allura/command/show_models.py
+++ b/Allura/allura/command/show_models.py
@@ -359,8 +359,8 @@ def dump_cls(depth, cls):
 
 def dfs(root, graph, depth=0):
     yield depth, root
-    for c in graph[root][1]:
-        for r in dfs(c, graph, depth + 1):
+    for node in graph[root][1]:
+        for r in dfs(node, graph, depth + 1):
             yield r
 
 

http://git-wip-us.apache.org/repos/asf/allura/blob/567b1d41/Allura/allura/controllers/repository.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/repository.py b/Allura/allura/controllers/repository.py
index 34210ce..b36449c 100644
--- a/Allura/allura/controllers/repository.py
+++ b/Allura/allura/controllers/repository.py
@@ -254,8 +254,8 @@ class RepoRootController(BaseController, FeedController):
         columns = []
 
         def find_column(columns):
-            for i, c in enumerate(columns):
-                if c is None:
+            for i, col in enumerate(columns):
+                if col is None:
                     return i
             columns.append(None)
             return len(columns) - 1
@@ -757,8 +757,8 @@ def topo_sort(children, parents, dates, head_ids):
         visited.add(next)
         yield next
         for p in parents[next]:
-            for c in children[p]:
-                if c not in visited:
+            for child in children[p]:
+                if child not in visited:
                     break
             else:
                 to_visit.append(p)

http://git-wip-us.apache.org/repos/asf/allura/blob/567b1d41/Allura/allura/controllers/site_admin.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/site_admin.py b/Allura/allura/controllers/site_admin.py
index a85680b..ee47274 100644
--- a/Allura/allura/controllers/site_admin.py
+++ b/Allura/allura/controllers/site_admin.py
@@ -275,18 +275,18 @@ class SiteAdminController(object):
                     _id = obj['id'].split('#')[1]
                     obj['object'] = mongo_objects.get(_id)
                 # Some objects can be deleted, but still have index in solr, should skip those
-                objects = [obj for obj in objects if obj.get('object')]
+                objects = [o for o in objects if o.get('object')]
 
         def convert_fields(obj):
             # throw the type away (e.g. '_s' from 'url_s')
             result = {}
-            for k,v in obj.iteritems():
+            for k,val in obj.iteritems():
                 name = k.rsplit('_', 1)
                 if len(name) == 2:
                     name = name[0]
                 else:
                     name = k
-                result[name] = v
+                result[name] = val
             return result
 
         return {

http://git-wip-us.apache.org/repos/asf/allura/blob/567b1d41/Allura/allura/lib/helpers.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/helpers.py b/Allura/allura/lib/helpers.py
index 3cd14fb..36932a3 100644
--- a/Allura/allura/lib/helpers.py
+++ b/Allura/allura/lib/helpers.py
@@ -583,8 +583,8 @@ def twophase_transaction(*engines):
     txns = []
     to_rollback = []
     try:
-        for c in connections:
-            txn = c.begin_twophase()
+        for conn in connections:
+            txn = conn.begin_twophase()
             txns.append(txn)
             to_rollback.append(txn)
         yield

http://git-wip-us.apache.org/repos/asf/allura/blob/567b1d41/Allura/allura/model/project.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/project.py b/Allura/allura/model/project.py
index b66ecec..db460a1 100644
--- a/Allura/allura/model/project.py
+++ b/Allura/allura/model/project.py
@@ -551,7 +551,7 @@ class Project(SearchIndexable, MappedClass, ActivityNode, ActivityObject):
             try:
                 App = ac.load()
             # If so, we don't want it listed
-            except KeyError as e:
+            except KeyError:
                 log.exception('AppConfig %s references invalid tool %s',
                               ac._id, ac.tool_name)
                 continue

http://git-wip-us.apache.org/repos/asf/allura/blob/567b1d41/Allura/allura/tests/test_commands.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_commands.py b/Allura/allura/tests/test_commands.py
index 1c298c5..f6800b7 100644
--- a/Allura/allura/tests/test_commands.py
+++ b/Allura/allura/tests/test_commands.py
@@ -193,11 +193,10 @@ class TestEnsureIndexCommand(object):
         cmd._update_indexes(collection, indexes)
 
         collection_call_order = {}
-        for i, call in enumerate(collection.mock_calls):
-            method_name = call[0]
+        for i, call_ in enumerate(collection.mock_calls):
+            method_name = call_[0]
             collection_call_order[method_name] = i
-        assert collection_call_order['ensure_index'] < collection_call_order[
-            'drop_index'], collection.mock_calls
+        assert collection_call_order['ensure_index'] < collection_call_order['drop_index'], collection.mock_calls
 
     def test_update_indexes_unique_changes(self):
         collection = Mock(name='collection')

http://git-wip-us.apache.org/repos/asf/allura/blob/567b1d41/Allura/allura/tests/unit/test_repo.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/unit/test_repo.py b/Allura/allura/tests/unit/test_repo.py
index 7411db5..9008571 100644
--- a/Allura/allura/tests/unit/test_repo.py
+++ b/Allura/allura/tests/unit/test_repo.py
@@ -42,9 +42,9 @@ class TestCommitRunBuilder(unittest.TestCase):
             M.repository.CommitDoc.make(dict(
                 _id=str(i)))
             for i in range(10)]
-        for p, c in zip(commits, commits[1:]):
-            p.child_ids = [c._id]
-            c.parent_ids = [p._id]
+        for p, com in zip(commits, commits[1:]):
+            p.child_ids = [com._id]
+            com.parent_ids = [p._id]
         for ci in commits:
             ci.m.save()
         self.commits = commits

http://git-wip-us.apache.org/repos/asf/allura/blob/567b1d41/ForgeSVN/forgesvn/model/svn.py
----------------------------------------------------------------------
diff --git a/ForgeSVN/forgesvn/model/svn.py b/ForgeSVN/forgesvn/model/svn.py
index 4594a2f..cd410e3 100644
--- a/ForgeSVN/forgesvn/model/svn.py
+++ b/ForgeSVN/forgesvn/model/svn.py
@@ -360,8 +360,7 @@ class SVNImplementation(M.RepositoryImplementation):
             if not oid.startswith(prefix):
                 break
             seen_oids.add(oid)
-        return [
-            oid for oid in oids if oid not in seen_oids]
+        return [o for o in oids if o not in seen_oids]
 
     def refresh_commit_info(self, oid, seen_object_ids, lazy=True):
         from allura.model.repository import CommitDoc

http://git-wip-us.apache.org/repos/asf/allura/blob/567b1d41/ForgeTracker/forgetracker/import_support.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/import_support.py b/ForgeTracker/forgetracker/import_support.py
index c1865e9..affe94b 100644
--- a/ForgeTracker/forgetracker/import_support.py
+++ b/ForgeTracker/forgetracker/import_support.py
@@ -282,8 +282,8 @@ class ImportSupport(object):
         for a in artifacts:
             users.add(a['submitter'])
             users.add(a['assigned_to'])
-            for c in a['comments']:
-                users.add(c['submitter'])
+            for com in a['comments']:
+                users.add(com['submitter'])
         return users
 
     def find_unknown_users(self, users):

http://git-wip-us.apache.org/repos/asf/allura/blob/567b1d41/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index b846f42..4f20d88 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -57,7 +57,7 @@ from allura.lib.widgets import form_fields as ffw
 from allura.lib.widgets.subscriptions import SubscribeForm
 from allura.lib.plugin import ImportIdConverter
 from allura.controllers import AppDiscussionController, AppDiscussionRestController
-from allura.controllers import attachments as ac
+from allura.controllers import attachments as att
 from allura.controllers import BaseController
 from allura.controllers.feed import FeedArgs, FeedController
 
@@ -1531,12 +1531,12 @@ class TicketController(BaseController, FeedController):
         }
 
 
-class AttachmentController(ac.AttachmentController):
+class AttachmentController(att.AttachmentController):
     AttachmentClass = TM.TicketAttachment
     edit_perm = 'update'
 
 
-class AttachmentsController(ac.AttachmentsController):
+class AttachmentsController(att.AttachmentsController):
     AttachmentControllerClass = AttachmentController
 
 NONALNUM_RE = re.compile(r'\W+')

http://git-wip-us.apache.org/repos/asf/allura/blob/567b1d41/requirements.txt
----------------------------------------------------------------------
diff --git a/requirements.txt b/requirements.txt
index 6de0f60..5664528 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -74,7 +74,7 @@ datadiff==1.1.5
 ipython==1.2.1
 mock==1.0.1
 nose==1.3.4
-pyflakes==0.5.0
+pyflakes==0.8.1
 WebTest==1.4.0
 testfixtures==3.0.0
 q==2.3


[23/25] allura git commit: [#7870] restore paster entry points that are actually needed

Posted by je...@apache.org.
[#7870] restore paster entry points that are actually needed


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/fb7f2cf1
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/fb7f2cf1
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/fb7f2cf1

Branch: refs/heads/ib/7856
Commit: fb7f2cf1377be7b49c3648bf47303c4f2322acf2
Parents: 1877bb3
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Mon Apr 20 17:11:20 2015 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Mon Apr 20 17:11:20 2015 +0000

----------------------------------------------------------------------
 Allura/setup.py | 5 +++++
 1 file changed, 5 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/fb7f2cf1/Allura/setup.py
----------------------------------------------------------------------
diff --git a/Allura/setup.py b/Allura/setup.py
index f2213b3..05cbf0b 100644
--- a/Allura/setup.py
+++ b/Allura/setup.py
@@ -94,6 +94,11 @@ setup(
     # Other packages (the Forge* directories) or 3rd-party can add more too.
     # development.ini is used for many cases to specify which to actually use.
     entry_points="""
+    [paste.app_factory]
+    main = allura.config.middleware:make_app
+    [paste.app_install]
+    main = pylons.util:PylonsInstaller
+
     [allura]
     profile = allura.ext.user_profile:UserProfileApp
     admin = allura.ext.admin:AdminApp


[06/25] allura git commit: [#7855] Updated a test to work with Pygments version 1.6 and higher

Posted by je...@apache.org.
[#7855] Updated a test to work with Pygments version 1.6 and higher


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/d731920a
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/d731920a
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/d731920a

Branch: refs/heads/ib/7856
Commit: d731920ab24ea35c21cf0f57ef4ed040612720e9
Parents: 89981f0
Author: Heith Seewald <hs...@slashdotmedia.com>
Authored: Tue Apr 14 19:16:25 2015 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Wed Apr 15 16:36:13 2015 +0000

----------------------------------------------------------------------
 Allura/allura/tests/test_utils.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/d731920a/Allura/allura/tests/test_utils.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_utils.py b/Allura/allura/tests/test_utils.py
index 06579c5..7903ba3 100644
--- a/Allura/allura/tests/test_utils.py
+++ b/Allura/allura/tests/test_utils.py
@@ -25,7 +25,7 @@ from os import path
 
 from webob import Request
 from mock import Mock, patch
-from nose.tools import assert_equal, assert_raises
+from nose.tools import assert_equal, assert_raises, assert_in
 from pygments import highlight
 from pygments.lexers import get_lexer_for_filename
 from tg import config
@@ -201,7 +201,7 @@ class TestLineAnchorCodeHtmlFormatter(unittest.TestCase):
         hl_code = highlight(code, lexer, formatter)
         assert '<div class="codehilite">' in hl_code
         assert '<div id="l1" class="code_block">' in hl_code
-        assert '<span class="lineno">1</span>' in hl_code
+        assert_in('<span class="lineno">1 </span>', hl_code)
 
 
 class TestIsTextFile(unittest.TestCase):


[07/25] allura git commit: [#7855] update packages

Posted by je...@apache.org.
[#7855] update packages


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/a3f7d44a
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/a3f7d44a
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/a3f7d44a

Branch: refs/heads/ib/7856
Commit: a3f7d44ab3ca05686c10a655ea8d8f6d2f392421
Parents: d731920
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Wed Apr 15 17:45:30 2015 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Wed Apr 15 17:45:30 2015 +0000

----------------------------------------------------------------------
 requirements.txt | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/a3f7d44a/requirements.txt
----------------------------------------------------------------------
diff --git a/requirements.txt b/requirements.txt
index 5664528..21b0ca5 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -8,7 +8,7 @@ colander==0.9.3
 Creoleparser==0.7.3
 decorator==3.3.2
 # dep of pypeline, sphinx
-docutils==0.9
+docutils==0.12
 EasyWidgets==0.2dev-20130716
 faulthandler==2.1
 feedparser==5.1.3
@@ -29,9 +29,9 @@ PasteDeploy==1.5.0
 PasteScript==1.7.4.2
 Pillow==2.0.0
 poster==0.8.1
-Pygments==1.6
+Pygments==2.0.2
 pymongo==2.4.2
-Pypeline==0.1dev
+Pypeline==0.2
 pysolr==2.1.0-beta
 python-dateutil==1.5
 python-magic==0.4.3
@@ -53,7 +53,7 @@ WebOb==1.0.8
 wsgiref==0.1.2
 
 # tg2 deps (not used directly)
-Babel==0.9.6
+Babel==1.3
 Mako==0.3.2
 MarkupSafe==0.15
 Pylons==1.0


[08/25] allura git commit: [#6017] ticket:751 Fixed test

Posted by je...@apache.org.
[#6017] ticket:751 Fixed test


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/da94700a
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/da94700a
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/da94700a

Branch: refs/heads/ib/7856
Commit: da94700afcfd4b69cf38adf8835bc16ac599a12b
Parents: 677fd67
Author: Aleksey 'LXj' Alekseyev <go...@gmail.com>
Authored: Wed Apr 8 14:51:39 2015 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Apr 16 10:43:47 2015 +0000

----------------------------------------------------------------------
 ForgeTracker/forgetracker/tests/functional/test_root.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/da94700a/ForgeTracker/forgetracker/tests/functional/test_root.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tests/functional/test_root.py b/ForgeTracker/forgetracker/tests/functional/test_root.py
index 0e92b1f..666fbc1 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_root.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_root.py
@@ -807,7 +807,7 @@ class TestFunctionalController(TrackerTestController):
             'delete': 'True'
         })
         deleted_form = self.app.get('/bugs/1/')
-        assert file_name not in deleted_form
+        assert file_link not in deleted_form
 
     def test_delete_attachment_from_comments(self):
         ticket_view = self.new_ticket(summary='test ticket').follow()


[05/25] allura git commit: [#7864] add new test data files to rat-excludes.txt

Posted by je...@apache.org.
[#7864] add new test data files to rat-excludes.txt


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/89981f0a
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/89981f0a
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/89981f0a

Branch: refs/heads/ib/7856
Commit: 89981f0ae4fef4f1d3821359a195068bd9a5cd41
Parents: 567b1d4
Author: Dave Brondsema <db...@slashdotmedia.com>
Authored: Wed Apr 15 14:22:18 2015 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Wed Apr 15 14:22:18 2015 +0000

----------------------------------------------------------------------
 rat-excludes.txt | 2 ++
 1 file changed, 2 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/89981f0a/rat-excludes.txt
----------------------------------------------------------------------
diff --git a/rat-excludes.txt b/rat-excludes.txt
index 2d62d50..6be4d29 100644
--- a/rat-excludes.txt
+++ b/rat-excludes.txt
@@ -39,6 +39,8 @@ ForgeGit/forgegit/data/post-receive_tmpl
 ForgeSVN/forgesvn/tests/data/
 ForgeImporters/forgeimporters/tests/data/google/empty-issue.html
 ForgeImporters/forgeimporters/tests/data/google/test-issue.html
+ForgeImporters/forgeimporters/tests/data/google/test-issue-first-page.html
+ForgeImporters/forgeimporters/tests/data/google/test-issue-prev-page.html
 ForgeImporters/forgeimporters/trac/tests/data/test-list.csv
 ForgeImporters/forgeimporters/trac/tests/data/test-list.html
 ForgeTracker/forgetracker/widgets/resources/js/jquery.multiselect.min.js


[18/25] allura git commit: [#7870] Standardize .ini comments with ;

Posted by je...@apache.org.
[#7870] Standardize .ini comments with ;

'#' sort of works, but you actually end up with config keys like '# my comment'


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/251f413d
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/251f413d
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/251f413d

Branch: refs/heads/ib/7856
Commit: 251f413d4c8242aca04d2218d2cf25004f3cdc76
Parents: 3ff1ade
Author: Dave Brondsema <da...@brondsema.net>
Authored: Thu Apr 9 17:03:57 2015 -0400
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Mon Apr 20 12:51:29 2015 -0400

----------------------------------------------------------------------
 Allura/development.ini | 310 ++++++++++++++++++++++----------------------
 1 file changed, 155 insertions(+), 155 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/251f413d/Allura/development.ini
----------------------------------------------------------------------
diff --git a/Allura/development.ini b/Allura/development.ini
index b6c3154..b7ccde6 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -1,34 +1,34 @@
-#       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.
-#
-# allura - Pylons development environment configuration
-#
-# The %(here)s variable will be replaced with the parent directory of this file
-#
-# This file is for deployment specific config options -- other configuration
-# that is always required for the app is done in the config directory,
-# and generally should not be modified by end users.
+;       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.
+;
+; allura - Pylons development environment configuration
+;
+; The %(here)s variable will be replaced with the parent directory of this file
+;
+; This file is for deployment specific config options -- other configuration
+; that is always required for the app is done in the config directory,
+; and generally should not be modified by end users.
 
 [DEFAULT]
 debug = true
-# Uncomment and replace with the address which should receive any error reports
-#email_to = you@yourdomain.com
+; Uncomment and replace with the address which should receive any error reports
+;email_to = you@yourdomain.com
 
-# Smtp settings
+; Smtp settings
 ;smtp_tls = False
 ;smtp_ssl = True
 ;smtp_user = some_user
@@ -59,12 +59,12 @@ site_name = Allura
 domain = localhost
 base_url = http://localhost:8080
 
-#lang = ru
+;lang = ru
 cache_dir = %(here)s/data
 
-# Cache Neighborhood objects for N seconds (speeds up requests).
-# Set to 0 to disable (the default).
-# neighborhood.cache.duration = 0
+; Cache Neighborhood objects for N seconds (speeds up requests).
+; Set to 0 to disable (the default).
+; neighborhood.cache.duration = 0
 
 ; Docs at http://beaker.readthedocs.org/en/latest/configuration.html#session-options
 ; and http://beaker.readthedocs.org/en/latest/modules/session.html#beaker.session.CookieSession
@@ -76,29 +76,29 @@ beaker.session.secure = false
 ; CHANGE THIS VALUE FOR YOUR SITE
 beaker.session.validate_key = 714bfe3612c42390726f
 
-# Google Analytics account for tracking
-# ga.account = UA-XXXXX-X
+; Google Analytics account for tracking
+; ga.account = UA-XXXXX-X
 
 registration.method = local
-# theme = sftheme
+; theme = sftheme
 theme = allura
 show_export_control = false
 
-# auth.method = ldap
+; auth.method = ldap
 auth.method = local
 auth.remember_for = 365  ; in days, for the "remember me" checkbox on login
-# auth.login_url = /auth/
-# auth.logout_url = /auth/logout
-# auth.login_fragment_url = /auth/login_fragment
+; auth.login_url = /auth/
+; auth.logout_url = /auth/logout
+; auth.login_fragment_url = /auth/login_fragment
 
 auth.min_password_len = 6
 auth.max_password_len = 30
 
-# password expiration options (disabled if neither is set)
-# auth.pwdexpire.days = 1
-# auth.pwdexpire.before = 1401949912  ; unix timestamp
+; password expiration options (disabled if neither is set)
+; auth.pwdexpire.days = 1
+; auth.pwdexpire.before = 1401949912  ; unix timestamp
 
-# if using LDAP, also run `pip install python-ldap` in your Allura environment
+; if using LDAP, also run `pip install python-ldap` in your Allura environment
 
 auth.ldap.server = ldap://localhost
 auth.ldap.suffix = ou=people,dc=localdomain
@@ -108,11 +108,11 @@ auth.ldap.schroot_name = scm
 auth.ldap.password.algorithm = 6
 auth.ldap.password.rounds = 6000
 auth.ldap.password.salt_len = 16
-# "autoregister" allows users to log in to Allura with an existing LDAP account
-# If using ldap, with autoregister, you should also set "allow_user_registration"
-# to false below.
-# Set "autoregister" to false to require user to register in Allura to create
-# the LDAP record and Allura record for the user.
+; "autoregister" allows users to log in to Allura with an existing LDAP account
+; If using ldap, with autoregister, you should also set "allow_user_registration"
+; to false below.
+; Set "autoregister" to false to require user to register in Allura to create
+; the LDAP record and Allura record for the user.
 auth.ldap.autoregister = true
 
 auth.allow_user_registration = true
@@ -125,16 +125,16 @@ auth.allow_birth_date = true
 auth.allow_non_primary_email_password_reset = true
 auth.require_email_addr = true
 
-# In seconds
+; In seconds
 auth.recovery_hash_expiry_period = 600
 
 user_prefs_storage.method = local
-# user_prefs_storage.method = ldap
-# If using ldap, you can specify which fields to use for a preference.
-# Any fields not specified here will be stored locally in mongo
+; user_prefs_storage.method = ldap
+; If using ldap, you can specify which fields to use for a preference.
+; Any fields not specified here will be stored locally in mongo
 user_prefs_storage.ldap.fields.display_name = cn
 
-# Limit the number of emails a user can claim.
+; Limit the number of emails a user can claim.
 user_prefs.maximum_claimed_emails = 20
 
 ; Spam filtering service: mollom or akismet
@@ -145,32 +145,32 @@ user_prefs.maximum_claimed_emails = 20
 ;spam.public_key =
 ;spam.private_key =
 
-# webhook.timeout = 30  # seconds, default = 30
+; webhook.timeout = 30  # seconds, default = 30
 
-# List of pauses between retries, if hook fails (in seconds)
-# webhook.retry = 60 120 240
+; List of pauses between retries, if hook fails (in seconds)
+; webhook.retry = 60 120 240
 
-# Limit rate of webhook firing (in seconds, default = 30)
-# Option format: webhook.<hook type>.limit,
-# all '-' in hook type must be changed to '_'
-# e.g. for repo-push webhook:
-# webhook.repo_push.limit = 10
+; Limit rate of webhook firing (in seconds, default = 30)
+; Option format: webhook.<hook type>.limit,
+; all '-' in hook type must be changed to '_'
+; e.g. for repo-push webhook:
+; webhook.repo_push.limit = 10
 
-# Limit max number of hooks that can be created for given project/app
-# Option name format: same as above.
-# Value format: json dict, where keys are app names (as appears in
-# `WebhookSender.triggered_by`) and values are actual limits (default=3), e.g.:
-# webhook.repo_push.max_hooks = {"git": 3, "hg": 3, "svn": 3}
+; Limit max number of hooks that can be created for given project/app
+; Option name format: same as above.
+; Value format: json dict, where keys are app names (as appears in
+; `WebhookSender.triggered_by`) and values are actual limits (default=3), e.g.:
+; webhook.repo_push.max_hooks = {"git": 3, "hg": 3, "svn": 3}
 
-# Additional fields for admin project/user search
-# Note: whitespace after comma is important!
-# search.project.additional_search_fields = private, url, title
-# search.user.additional_search_fields = email_addresses
+; Additional fields for admin project/user search
+; Note: whitespace after comma is important!
+; search.project.additional_search_fields = private, url, title
+; search.user.additional_search_fields = email_addresses
 
-# Additional fields to show in the result of admin project/user search
-# Note: whitespace after comma is important!
-# search.project.additional_display_fields = private, url, title
-# search.user.additional_display_fields = email_addresses
+; Additional fields to show in the result of admin project/user search
+; Note: whitespace after comma is important!
+; search.project.additional_display_fields = private, url, title
+; search.user.additional_display_fields = email_addresses
 
 ; To make all pages use ssl:   (also set beaker.session.secure above)
 ; force_ssl.pattern = .
@@ -182,10 +182,10 @@ user_prefs.maximum_claimed_emails = 20
 ; no_redirect.pattern = ^/nf/\d+/_(ew|static)_/|^/rest/|^/nf/tool_icon_css|^/auth/refresh_repo
 
 
-# Set the locations of some static resources.  ("ew" stands for EasyWidgets library)
-#  script_name is the path that is handled by the application
-#  url_base is the prefix that references to the static resources should have
-# If you use a CDN, put your CDN prefix in the url_base values
+; Set the locations of some static resources.  ("ew" stands for EasyWidgets library)
+;  script_name is the path that is handled by the application
+;  url_base is the prefix that references to the static resources should have
+; If you use a CDN, put your CDN prefix in the url_base values
 ew.script_name = /nf/%(build_key)s/_ew_/
 ew.url_base = /nf/%(build_key)s/_ew_/
 static.script_name = /nf/%(build_key)s/_static_/
@@ -199,26 +199,26 @@ ew.extra_headers = [ ('Access-Control-Allow-Origin', '*') ]
 ; If your environment (e.g. behind a server-side proxy) needs to look at an http header to get the actual remote addr
 ;ip_address_header = X-Forwarded-For
 
-# SCM settings for local development
+; SCM settings for local development
 scm.host.ro.git = /srv/git$path
 scm.host.rw.git = /srv/git$path
-# remote access varies by configuration.  If you are using a vagrant VM, this should work:
-#scm.host.rw.git = ssh://vagrant@localhost:2222/srv/git$path
+; remote access varies by configuration.  If you are using a vagrant VM, this should work:
+;scm.host.rw.git = ssh://vagrant@localhost:2222/srv/git$path
 scm.host.ro.hg = /srv/hg$path
 scm.host.rw.hg = /srv/hg$path
 scm.host.ro.svn = file:///srv/svn$path/
 scm.host.rw.svn = file:///srv/svn$path/
 
-# SCM settings for chroot + ldap configuration.  See Allura/docs/getting_started/scm_host.rst
-# scm.host.ro.git = git://git.localhost$path
-# scm.host.rw.git = ssh://$username@localhost:8022/scm-repo$path
-# scm.host.ro.hg = http://hg.localhost$path
-# scm.host.rw.hg = ssh://$username@localhost:8022/scm-repo$path
-# scm.host.ro.svn = http://svn.localhost$path/
-# scm.host.rw.svn = svn+ssh://localhost:8022/scm-repo$path/
+; SCM settings for chroot + ldap configuration.  See Allura/docs/getting_started/scm_host.rst
+; scm.host.ro.git = git://git.localhost$path
+; scm.host.rw.git = ssh://$username@localhost:8022/scm-repo$path
+; scm.host.ro.hg = http://hg.localhost$path
+; scm.host.rw.hg = ssh://$username@localhost:8022/scm-repo$path
+; scm.host.ro.svn = http://svn.localhost$path/
+; scm.host.rw.svn = svn+ssh://localhost:8022/scm-repo$path/
 
-# SCM settings for https (sorry no docs for setting these up)
-# these settings are currently required by the template, no matter what
+; SCM settings for https (sorry no docs for setting these up)
+; these settings are currently required by the template, no matter what
 scm.host.https.git = https://$username@localhost:8022/scm-repo$path
 scm.host.https_anon.git = https://localhost:8022/scm-repo$path
 scm.host.https.hg = https://$username@localhost:8022/scm-repo$path
@@ -253,21 +253,21 @@ bulk_export_download_instructions = Sample instructions for {project}
 
 importer_upload_path = /tmp/importer_upload/{nbhd}/{project}
 
-# GitHub importer keys.  For github ticket import, it is best to set
-# up an app at https://github.com/settings/applications  Use the root URL
-# of your Allura instance for both URLs, and enter client values here:
-# github_importer.client_id =
-# github_importer.client_secret =
+; GitHub importer keys.  For github ticket import, it is best to set
+; up an app at https://github.com/settings/applications  Use the root URL
+; of your Allura instance for both URLs, and enter client values here:
+; github_importer.client_id =
+; github_importer.client_secret =
 
-# space-separated list of tool names that are valid options
-# for project admins to set for their 'support_page' field
-# this field is not used by default in Allura, so this option
-# is disabled by default
-#support_tool_choices = wiki tickets discussion
+; space-separated list of tool names that are valid options
+; for project admins to set for their 'support_page' field
+; this field is not used by default in Allura, so this option
+; is disabled by default
+;support_tool_choices = wiki tickets discussion
 
 trovecategories.enableediting = true
 
-# ActivityStream
+; ActivityStream
 activitystream.master = mongodb://127.0.0.1:27017
 activitystream.database = activitystream
 activitystream.activity_collection = activities
@@ -276,9 +276,9 @@ activitystream.timeline_collection = timelines
 activitystream.enabled = true
 activitystream.recording.enabled = true
 
-# Ming setup
-# These don't necessarily have to be separate databases, they could
-# be all in the same database if desired
+; Ming setup
+; These don't necessarily have to be separate databases, they could
+; be all in the same database if desired
 ming.main.uri = mongodb://127.0.0.1:27017/allura
 ming.main.auto_ensure_indexes = False
 ming.project.uri = mongodb://127.0.0.1:27017/project-data
@@ -288,57 +288,57 @@ ming.task.auto_ensure_indexes = False
 ming.zarkov.uri = mongodb://127.0.0.1:27017/zarkov
 ming.zarkov.auto_ensure_indexes = False
 
-# Zarkov host setting, requires the zarkov and gevent libraries.
-#zarkov.host = tcp://127.0.0.1:9000
+; Zarkov host setting, requires the zarkov and gevent libraries.
+;zarkov.host = tcp://127.0.0.1:9000
 
 stats.sample_rate = 1
 
 ; Taskd setup
 monq.poll_interval=2
 
-# SOLR setup
+; SOLR setup
 solr.server = http://localhost:8983/solr
-# commit on every add/delete?
+; commit on every add/delete?
 solr.commit = false
-# commit add operations within N ms
+; commit add operations within N ms
 solr.commitWithin = 10000
-# Use improved data types for labels and custom fields?
-# New Allura deployments should leave this set to true. Existing deployments
-# should set to false until existing data has been reindexed. Reindexing will
-# convert existing label and custom field data to more appropriate solr types.
+; Use improved data types for labels and custom fields?
+; New Allura deployments should leave this set to true. Existing deployments
+; should set to false until existing data has been reindexed. Reindexing will
+; convert existing label and custom field data to more appropriate solr types.
 solr.use_new_types = true
 
-# Forgemail server
+; Forgemail server
 forgemail.host = 0.0.0.0
 forgemail.port = 8825
 forgemail.domain = .in.sf.net
 forgemail.url = http://localhost:8080
 forgemail.return_path = noreply@sf.net
 
-# Specify the number of projects allowed to be created by a user
-# depending on the age of their user account.
-# Keys are number of seconds, values are max number of projects allowed
-# (including the default user-project, so you probably want to add 1)
-# This example allows for 1 project if the account is less than an hour old
-# and 5 projects if the account is less than a day old.  No limits after that
-# project.rate_limits = {"3600": 2, "86400": 6}
+; Specify the number of projects allowed to be created by a user
+; depending on the age of their user account.
+; Keys are number of seconds, values are max number of projects allowed
+; (including the default user-project, so you probably want to add 1)
+; This example allows for 1 project if the account is less than an hour old
+; and 5 projects if the account is less than a day old.  No limits after that
+; project.rate_limits = {"3600": 2, "86400": 6}
 
-# Special Command settings
-# no need to sleep in devel
+; Special Command settings
+; no need to sleep in devel
 ensure_index.sleep = 0
 
-# set this to "false" if you are deploying to production and want performance improvements
+; set this to "false" if you are deploying to production and want performance improvements
 auto_reload_templates = true
 
-# WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*
-# Debug mode will enable the interactive debugging tool, allowing ANYONE to
-# execute malicious code after an exception is raised.
-#set debug = false
+; WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*
+; Debug mode will enable the interactive debugging tool, allowing ANYONE to
+; execute malicious code after an exception is raised.
+;set debug = false
 
-# Enable or disable external RSS feed importing in ForgeBlog tool.
-# Default is "false". This feature requires GPL library "html2text". Install it
-# with following command:
-# pip install -e git://github.com/brondsem/html2text.git#egg=html2text
+; Enable or disable external RSS feed importing in ForgeBlog tool.
+; Default is "false". This feature requires GPL library "html2text". Install it
+; with following command:
+; pip install -e git://github.com/brondsem/html2text.git#egg=html2text
 forgeblog.exfeed = false
 
 short_url.url_pattern = {base_url}/{nbhd}/{project}/{mount_point}/{short_name}
@@ -356,16 +356,16 @@ beaker.session.key = allura
 beaker.session.type = cookie
 beaker.session.validate_key = 714bfe3612c42390726f
 
-# Ming setup
+; Ming setup
 ming.main.uri = mongo://127.0.0.1:27017/allura:test
 
 sqlalchemy.url = sqlite:///%(here)s/devdata.db
-#echo shouldn't be used together with the logging module.
+;echo shouldn't be used together with the logging module.
 sqlalchemy.echo = false
 sqlalchemy.echo_pool = false
 sqlalchemy.pool_recycle = 3600
 
-# Forgemail server
+; Forgemail server
 forgemail.host = 0.0.0.0
 forgemail.port = 8825
 forgemail.domain = .in.sf.net
@@ -375,26 +375,26 @@ forgemail.url = http://localhost:8080
 auth.method = local
 registration.method = local
 
-# When rendering discussion post Markdown to html, if the render takes longer
-# than `markdown_cache_threshold` (in seconds), the resulting html will be
-# cached and served from cache on subsequent requests. Set to 0 to cache all
-# posts. Remove entirely to cache nothing.
+; When rendering discussion post Markdown to html, if the render takes longer
+; than `markdown_cache_threshold` (in seconds), the resulting html will be
+; cached and served from cache on subsequent requests. Set to 0 to cache all
+; posts. Remove entirely to cache nothing.
 markdown_cache_threshold = .1
-# markdown text longer than max length will not be converted to html
+; markdown text longer than max length will not be converted to html
 markdown_render_max_length = 999999999
 
-# If your site has docs about specific importers, you can add them here and
-# they'll appear on the import forms
-#doc.url.importers.Google Code = http://...
+; If your site has docs about specific importers, you can add them here and
+; they'll appear on the import forms
+;doc.url.importers.Google Code = http://...
 
 [app:task]
 use = main
 override_root = task ; TurboGears will use controllers/task.py as root controller
 
-# Logging configuration
-# Add additional loggers, handlers, formatters here
-# Uses python's logging config file format
-# http://docs.python.org/lib/logging-config-fileformat.html
+; Logging configuration
+; Add additional loggers, handlers, formatters here
+; Uses python's logging config file format
+; http://docs.python.org/lib/logging-config-fileformat.html
 
 [loggers]
 keys = root, allura, sqlalchemy, paste, pylons, taskdstatus, timermiddleware, tmw_details
@@ -405,7 +405,7 @@ keys = console, stats, taskdstatus, timermiddleware
 [formatters]
 keys = generic, stats, timermiddleware
 
-# If you create additional loggers, add them as a key to [loggers]
+; If you create additional loggers, add them as a key to [loggers]
 [logger_root]
 level = INFO
 handlers = console, stats
@@ -419,9 +419,9 @@ qualname = allura
 level = INFO
 handlers =
 qualname = sqlalchemy.engine
-# "level = INFO" logs SQL queries.
-# "level = DEBUG" logs SQL queries and results.
-# "level = WARN" logs neither.  (Recommended for production systems.)
+; "level = INFO" logs SQL queries.
+; "level = DEBUG" logs SQL queries and results.
+; "level = WARN" logs neither.  (Recommended for production systems.)
 
 [logger_paste]
 level = INFO
@@ -434,7 +434,7 @@ qualname = pylons
 handlers =
 
 [logger_tmw_details]
-# DEBUG will include every instrumented call in our logging
+; DEBUG will include every instrumented call in our logging
 level = INFO
 qualname = timermiddleware
 handlers =
@@ -450,7 +450,7 @@ handlers = timermiddleware
 qualname = stats
 propagate = 0
 
-# If you create additional handlers, add them as a key to [handlers]
+; If you create additional handlers, add them as a key to [handlers]
 [handler_console]
 class = StreamHandler
 args = (sys.stderr,)
@@ -471,13 +471,13 @@ formatter = generic
 
 [handler_timermiddleware]
 class = handlers.WatchedFileHandler
-# if you run 'paster serve' in allura/Allura/ then that's where this file will be
-# you may want to hard-code a specific directory here.
+; if you run 'paster serve' in allura/Allura/ then that's where this file will be
+; you may want to hard-code a specific directory here.
 args = ('stats.log', 'a')
 level = NOTSET
 formatter = timermiddleware
 
-# If you create additional formatters, add them as a key to [formatters]
+; If you create additional formatters, add them as a key to [formatters]
 [formatter_generic]
 format = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
 datefmt = %H:%M:%S


[22/25] allura git commit: [#7870] Added a note indicating a possible test falure on OSX

Posted by je...@apache.org.
[#7870]  Added a note indicating a possible test falure on OSX


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/1877bb3b
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/1877bb3b
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/1877bb3b

Branch: refs/heads/ib/7856
Commit: 1877bb3b31e84107561af1dc9df4108f88347cc3
Parents: 95af4cb
Author: Heith Seewald <hs...@slashdotmedia.com>
Authored: Mon Apr 20 12:51:00 2015 -0400
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Mon Apr 20 12:51:30 2015 -0400

----------------------------------------------------------------------
 Allura/allura/tests/unit/test_ldap_auth_provider.py | 1 +
 1 file changed, 1 insertion(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/1877bb3b/Allura/allura/tests/unit/test_ldap_auth_provider.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/unit/test_ldap_auth_provider.py b/Allura/allura/tests/unit/test_ldap_auth_provider.py
index 7d7f5b5..abce671 100644
--- a/Allura/allura/tests/unit/test_ldap_auth_provider.py
+++ b/Allura/allura/tests/unit/test_ldap_auth_provider.py
@@ -41,6 +41,7 @@ class TestLdapAuthenticationProvider(object):
     def test_password_encoder(self):
         # Verify salt
         ep = self.provider._encode_password
+        # Note: OSX uses a crypt library with a known issue relating the hashing algorithms.
         assert_not_equal(ep('test_pass'), ep('test_pass'))
         assert_equal(ep('test_pass', '0000'), ep('test_pass', '0000'))
         # Test password format


[24/25] allura git commit: [#7856] ticket:753 Handle emails in unexpected formats

Posted by je...@apache.org.
[#7856] ticket:753 Handle emails in unexpected formats


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/8ea45a55
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/8ea45a55
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/8ea45a55

Branch: refs/heads/ib/7856
Commit: 8ea45a552b6c7cfe81ce277c1a4afe9d2bebed66
Parents: fb7f2cf
Author: Aleksey 'LXj' Alekseyev <go...@gmail.com>
Authored: Thu Apr 9 20:39:23 2015 +0300
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Tue Apr 21 09:15:34 2015 +0000

----------------------------------------------------------------------
 Allura/allura/model/auth.py            | 7 +++++--
 Allura/allura/tests/model/test_auth.py | 2 ++
 2 files changed, 7 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/8ea45a55/Allura/allura/model/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index 98dc4ec..8b06c73 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -169,8 +169,11 @@ class EmailAddress(MappedClass):
         if mo:
             addr = mo.group(1)
         if '@' in addr:
-            user, domain = addr.strip().split('@')
-            return '%s@%s' % (user, domain.lower())
+            try:
+                user, domain = addr.strip().split('@')
+                return '%s@%s' % (user, domain.lower())
+            except ValueError:
+                return addr.strip()
         else:
             return None
 

http://git-wip-us.apache.org/repos/asf/allura/blob/8ea45a55/Allura/allura/tests/model/test_auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/model/test_auth.py b/Allura/allura/tests/model/test_auth.py
index eb7416c..4281bb1 100644
--- a/Allura/allura/tests/model/test_auth.py
+++ b/Allura/allura/tests/model/test_auth.py
@@ -105,6 +105,8 @@ def test_email_address_canonical():
                  'nobody@example.com')
     assert_equal(M.EmailAddress.canonical('  nobody@example.com\t'),
                  'nobody@example.com')
+    assert_equal(M.EmailAddress.canonical('I Am@Nobody <no...@example.com> '),
+                 'I Am@Nobody <no...@example.com>')
     assert_equal(M.EmailAddress.canonical('invalid'), None)
 
 @with_setup(setUp)


[14/25] allura git commit: [#7852] Added tests to confirm 'mod_time' field does not get updated on page view.

Posted by je...@apache.org.
[#7852] Added tests to confirm 'mod_time' field does not get updated on page view.


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/fc066e31
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/fc066e31
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/fc066e31

Branch: refs/heads/ib/7856
Commit: fc066e31bb244c1445b19def36a2d70fa0fdd1c3
Parents: b5b01d0
Author: Heith Seewald <hs...@slashdotmedia.com>
Authored: Tue Apr 14 13:31:12 2015 -0400
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Thu Apr 16 13:04:18 2015 -0400

----------------------------------------------------------------------
 .../forgetracker/templates/tracker/ticket.html  |  2 +-
 .../forgetracker/tests/functional/test_root.py  | 21 ++++++++++++++++++++
 2 files changed, 22 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/fc066e31/ForgeTracker/forgetracker/templates/tracker/ticket.html
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/templates/tracker/ticket.html b/ForgeTracker/forgetracker/templates/tracker/ticket.html
index 27331c8..5f9f534 100644
--- a/ForgeTracker/forgetracker/templates/tracker/ticket.html
+++ b/ForgeTracker/forgetracker/templates/tracker/ticket.html
@@ -123,7 +123,7 @@
     <div style="clear:both"></div>
     <div class="grid-4">
       <label class="simple">Updated:</label>
-      {{abbr_date(ticket.mod_date)}}
+      <span id="updated_id">{{abbr_date(ticket.mod_date)}}</span>
     </div>
     <div class="grid-4">
       <label class="simple">Created:</label>

http://git-wip-us.apache.org/repos/asf/allura/blob/fc066e31/ForgeTracker/forgetracker/tests/functional/test_root.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tests/functional/test_root.py b/ForgeTracker/forgetracker/tests/functional/test_root.py
index 21a3564..d096010 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_root.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_root.py
@@ -16,6 +16,7 @@
 #       KIND, either express or implied.  See the License for the
 #       specific language governing permissions and limitations
 #       under the License.
+from datetime import datetime
 
 import urllib
 import os
@@ -720,6 +721,26 @@ class TestFunctionalController(TrackerTestController):
         r = self.app.get('/bugs/markdown_syntax')
         assert_true('Markdown Syntax' in r)
 
+    @patch.dict('allura.lib.app_globals.config', markdown_cache_threshold='0')
+    @patch('allura.lib.app_globals.ForgeMarkdown.cached_convert')
+    def test_cached_convert(self, mock_cached_convert):
+        from allura.model.session import artifact_orm_session
+        # Create ticket
+        params = dict(ticket_num=1,
+                      app_config_id=c.app.config._id,
+                      summary=u'test md cache',
+                      mod_date=datetime(2010, 1, 1, 1, 1, 1))
+        ticket = tm.Ticket(**params)
+        session = artifact_orm_session._get()
+        setattr(session, 'skip_mod_date', True)
+
+        # This visit will cause cache to be stored on the artifact.
+        # We want to make sure the 'last_updated' field isn't updated by the cache creation
+        r = self.app.get('/bugs/1').follow()
+        last_updated = r.html.find("span", {"id": "updated_id"}).text
+        assert_equal(last_updated, '2010-01-01')
+        assert_equal(mock_cached_convert.call_count, 1)
+
     def test_ticket_diffs(self):
         self.new_ticket(summary='difftest', description='1\n2\n3\n')
         self.app.post('/bugs/1/update_ticket', {


[16/25] allura git commit: [#7852] Removed cached_convert mock from test_cached_convert.

Posted by je...@apache.org.
[#7852] Removed cached_convert mock from test_cached_convert.


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/3d7b62b2
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/3d7b62b2
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/3d7b62b2

Branch: refs/heads/ib/7856
Commit: 3d7b62b2e3f510ee1e935817251a78c71aecfc86
Parents: fc066e3
Author: Heith Seewald <hs...@slashdotmedia.com>
Authored: Thu Apr 16 13:03:47 2015 -0400
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Thu Apr 16 17:30:12 2015 +0000

----------------------------------------------------------------------
 Allura/allura/lib/app_globals.py                       |  2 +-
 .../forgetracker/tests/functional/test_root.py         | 13 +++++++++----
 2 files changed, 10 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/3d7b62b2/Allura/allura/lib/app_globals.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/app_globals.py b/Allura/allura/lib/app_globals.py
index 31f3c79..e9879de 100644
--- a/Allura/allura/lib/app_globals.py
+++ b/Allura/allura/lib/app_globals.py
@@ -133,7 +133,7 @@ class ForgeMarkdown(markdown.Markdown):
 
             # Prevent cache creation from updating the mod_date timestamp.
             _session = artifact_orm_session._get()
-            setattr(_session, 'skip_mod_date', True)
+            _session.skip_mod_date = True
         return html
 
 

http://git-wip-us.apache.org/repos/asf/allura/blob/3d7b62b2/ForgeTracker/forgetracker/tests/functional/test_root.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tests/functional/test_root.py b/ForgeTracker/forgetracker/tests/functional/test_root.py
index d096010..e8195d5 100644
--- a/ForgeTracker/forgetracker/tests/functional/test_root.py
+++ b/ForgeTracker/forgetracker/tests/functional/test_root.py
@@ -722,24 +722,29 @@ class TestFunctionalController(TrackerTestController):
         assert_true('Markdown Syntax' in r)
 
     @patch.dict('allura.lib.app_globals.config', markdown_cache_threshold='0')
-    @patch('allura.lib.app_globals.ForgeMarkdown.cached_convert')
-    def test_cached_convert(self, mock_cached_convert):
+    def test_cached_convert(self):
         from allura.model.session import artifact_orm_session
         # Create ticket
         params = dict(ticket_num=1,
                       app_config_id=c.app.config._id,
                       summary=u'test md cache',
+                      description=u'# Test markdown cached_convert',
                       mod_date=datetime(2010, 1, 1, 1, 1, 1))
         ticket = tm.Ticket(**params)
+
+        # Enable skip_mod_date to prevent mod_date from being set automatically when the ticket is saved.
         session = artifact_orm_session._get()
-        setattr(session, 'skip_mod_date', True)
+        session.skip_mod_date = True
 
         # This visit will cause cache to be stored on the artifact.
         # We want to make sure the 'last_updated' field isn't updated by the cache creation
         r = self.app.get('/bugs/1').follow()
         last_updated = r.html.find("span", {"id": "updated_id"}).text
         assert_equal(last_updated, '2010-01-01')
-        assert_equal(mock_cached_convert.call_count, 1)
+
+        # Make sure the cache has been saved.
+        t = tm.Ticket.query.find({'_id': ticket._id}).first()
+        assert_in('<h1 id="test-markdown-cached_convert">Test markdown cached_convert</h1>', t.description_cache.html)
 
     def test_ticket_diffs(self):
         self.new_ticket(summary='difftest', description='1\n2\n3\n')


[12/25] allura git commit: [#6017] ticket:756 Send notification when attachment is deleted

Posted by je...@apache.org.
[#6017] ticket:756 Send notification when attachment is deleted


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/b5a084fd
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/b5a084fd
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/b5a084fd

Branch: refs/heads/ib/7856
Commit: b5a084fd7832afe989e5722340c44477f088285a
Parents: 9546f5a
Author: Igor Bondarenko <je...@gmail.com>
Authored: Thu Apr 16 14:51:43 2015 +0000
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Thu Apr 16 14:51:43 2015 +0000

----------------------------------------------------------------------
 Allura/allura/controllers/attachments.py  | 19 ++++----
 ForgeTracker/forgetracker/tracker_main.py | 60 ++++++++++++++++++++------
 2 files changed, 57 insertions(+), 22 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/b5a084fd/Allura/allura/controllers/attachments.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/attachments.py b/Allura/allura/controllers/attachments.py
index 4ab3b92..a648873 100644
--- a/Allura/allura/controllers/attachments.py
+++ b/Allura/allura/controllers/attachments.py
@@ -73,17 +73,20 @@ class AttachmentController(BaseController):
             raise exc.HTTPNotFound
         return attachment
 
+    def handle_post(self, delete, **kw):
+        require_access(self.artifact, self.edit_perm)
+        if delete:
+            self.attachment.delete()
+            try:
+                if self.thumbnail:
+                    self.thumbnail.delete()
+            except exc.HTTPNotFound:
+                pass
+
     @expose()
     def index(self, delete=False, **kw):
         if request.method == 'POST':
-            require_access(self.artifact, self.edit_perm)
-            if delete:
-                self.attachment.delete()
-                try:
-                    if self.thumbnail:
-                        self.thumbnail.delete()
-                except exc.HTTPNotFound:
-                    pass
+            self.handle_post(delete, **kw)
             redirect(request.referer)
         embed = False
         if self.attachment.content_type and self.attachment.content_type.startswith('image/'):

http://git-wip-us.apache.org/repos/asf/allura/blob/b5a084fd/ForgeTracker/forgetracker/tracker_main.py
----------------------------------------------------------------------
diff --git a/ForgeTracker/forgetracker/tracker_main.py b/ForgeTracker/forgetracker/tracker_main.py
index f8a5680..9fc39d8 100644
--- a/ForgeTracker/forgetracker/tracker_main.py
+++ b/ForgeTracker/forgetracker/tracker_main.py
@@ -148,6 +148,33 @@ def get_change_text(name, new_value, old_value):
         comment=None)
 
 
+def attachments_info(attachments):
+    text = []
+    for attach in attachments:
+        text.append("{} ({}; {})".format(
+            attach.filename,
+            h.do_filesizeformat(attach.length),
+            attach.content_type))
+    return "\n".join(text)
+
+
+def render_changes(changes, comment=None):
+    """
+    Render ticket changes given instanse of :class changelog:
+
+    Returns tuple (post_text, notification_text)
+    """
+    template = pkg_resources.resource_filename(
+        'forgetracker', 'data/ticket_changed_tmpl')
+    render = partial(
+        h.render_genshi_plaintext,
+        template,
+        changelist=changes.get_changed())
+    post_text = render(comment=None)
+    notification_text = render(comment=comment) if comment else None
+    return post_text, notification_text
+
+
 def _my_trackers(user, current_tracker_app_config):
     '''Collect all 'Tickets' instances in all user's projects
     for which user has admin permissions.
@@ -1390,15 +1417,6 @@ class TicketController(BaseController, FeedController):
 
     @require_post()
     def _update_ticket(self, post_data):
-        def attachments_info(attachments):
-            text = []
-            for attach in attachments:
-                text.append("{} ({}; {})".format(
-                    attach.filename,
-                    h.do_filesizeformat(attach.length),
-                    attach.content_type))
-            return "\n".join(text)
-
         require_access(self.ticket, 'update')
         changes = changelog()
         comment = post_data.pop('comment', None)
@@ -1469,11 +1487,7 @@ class TicketController(BaseController, FeedController):
                 self.ticket.custom_fields[cf.name] = value
                 changes[cf.label] = cf_val(cf)
 
-        tpl = pkg_resources.resource_filename(
-            'forgetracker', 'data/ticket_changed_tmpl')
-        render = partial(h.render_genshi_plaintext, tpl, changelist=changes.get_changed())
-        post_text = render(comment=None)
-        notification_text = render(comment=comment) if comment else None
+        post_text, notification_text = render_changes(changes, comment)
         thread = self.ticket.discussion_thread
         thread.add_post(text=post_text, is_meta=True,
                         notification_text=notification_text)
@@ -1552,6 +1566,24 @@ class AttachmentController(att.AttachmentController):
     AttachmentClass = TM.TicketAttachment
     edit_perm = 'update'
 
+    def handle_post(self, delete, **kw):
+        old_attachments = attachments_info(self.artifact.attachments)
+        super(AttachmentController, self).handle_post(delete, **kw)
+        if delete:
+            session(self.artifact.attachment_class()).flush()
+            # self.artifact.attachments is ming's LazyProperty, we need to reset
+            # it's cache to fetch updated attachments here:
+            self.artifact.__dict__.pop('attachments')
+            new_attachments = attachments_info(self.artifact.attachments)
+            changes = changelog()
+            changes['attachments'] = old_attachments
+            changes['attachments'] = new_attachments
+            post_text, notification = render_changes(changes)
+            self.artifact.discussion_thread.add_post(
+                text=post_text,
+                is_meta=True,
+                notification_text=notification)
+
 
 class AttachmentsController(att.AttachmentsController):
     AttachmentControllerClass = AttachmentController


[15/25] allura git commit: [#7852] Fixed an issue where 'mod_time' was getting updated on the first view.

Posted by je...@apache.org.
[#7852] Fixed an issue where 'mod_time' was getting updated on the first view.


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/b5b01d01
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/b5b01d01
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/b5b01d01

Branch: refs/heads/ib/7856
Commit: b5b01d01f8d9d3cc25e0e0681480e5fc3b2b1a07
Parents: ad7c5f9
Author: Heith Seewald <hs...@slashdotmedia.com>
Authored: Tue Apr 14 13:29:20 2015 -0400
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Thu Apr 16 13:04:18 2015 -0400

----------------------------------------------------------------------
 Allura/allura/lib/app_globals.py | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/b5b01d01/Allura/allura/lib/app_globals.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/app_globals.py b/Allura/allura/lib/app_globals.py
index 30bfbf3..31f3c79 100644
--- a/Allura/allura/lib/app_globals.py
+++ b/Allura/allura/lib/app_globals.py
@@ -63,6 +63,7 @@ from allura.lib.widgets import analytics
 from allura.lib.security import Credentials
 from allura.lib.solr import MockSOLR, make_solr_from_config
 from allura.lib.zarkov_helpers import ZarkovClient
+from allura.model.session import artifact_orm_session
 
 log = logging.getLogger(__name__)
 
@@ -104,11 +105,13 @@ class ForgeMarkdown(markdown.Markdown):
             return self.convert(source_text)
 
         md5 = None
+        # If a cached version exists and it is valid, return it.
         if cache.md5 is not None:
             md5 = hashlib.md5(source_text.encode('utf-8')).hexdigest()
             if cache.md5 == md5 and getattr(cache, 'fix7528', False):
                 return h.html.literal(cache.html)
 
+        # Convert the markdown and time the result.
         start = time.time()
         html = self.convert(source_text)
         render_time = time.time() - start
@@ -121,11 +124,16 @@ class ForgeMarkdown(markdown.Markdown):
             log.warn('Skipping Markdown caching - The value for config param '
                      '"markdown_cache_threshold" must be a float.')
 
-        if threshold != None and render_time > threshold:
+        if threshold is not None and render_time > threshold:
+            # Save the cache
             if md5 is None:
                 md5 = hashlib.md5(source_text.encode('utf-8')).hexdigest()
             cache.md5, cache.html, cache.render_time = md5, html, render_time
             cache.fix7528 = True  # flag to indicate good caches created after [#7528] was fixed
+
+            # Prevent cache creation from updating the mod_date timestamp.
+            _session = artifact_orm_session._get()
+            setattr(_session, 'skip_mod_date', True)
         return html
 
 


[04/25] allura git commit: [#7864] remove Property with nested get/setters, since sys.settrace causes pydev/PyCharm debugger not to work

Posted by je...@apache.org.
[#7864] remove Property with nested get/setters, since sys.settrace causes pydev/PyCharm debugger not to work


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/c72837df
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/c72837df
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/c72837df

Branch: refs/heads/ib/7856
Commit: c72837df2062465c9f75bcde6bb747df38acf243
Parents: fa548be
Author: Dave Brondsema <da...@brondsema.net>
Authored: Tue Apr 7 15:37:53 2015 -0400
Committer: Igor Bondarenko <je...@gmail.com>
Committed: Wed Apr 15 11:04:03 2015 +0000

----------------------------------------------------------------------
 Allura/allura/lib/decorators.py  | 18 ---------
 ForgeBlog/forgeblog/main.py      | 40 +++++++++---------
 ForgeWiki/forgewiki/wiki_main.py | 76 +++++++++++++++++------------------
 3 files changed, 58 insertions(+), 76 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/c72837df/Allura/allura/lib/decorators.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/decorators.py b/Allura/allura/lib/decorators.py
index d472758..cb5cfc5 100644
--- a/Allura/allura/lib/decorators.py
+++ b/Allura/allura/lib/decorators.py
@@ -188,24 +188,6 @@ class log_action(object):  # pragma no cover
         return extra
 
 
-def Property(function):
-    '''Decorator to easily assign descriptors based on sub-function names
-    See <http://code.activestate.com/recipes/410698-property-decorator-for-python-24/>
-    '''
-    keys = 'fget', 'fset', 'fdel'
-    func_locals = {'doc': function.__doc__}
-
-    def probeFunc(frame, event, arg):
-        if event == 'return':
-            locals = frame.f_locals
-            func_locals.update(dict((k, locals.get(k)) for k in keys))
-            sys.settrace(None)
-        return probeFunc
-    sys.settrace(probeFunc)
-    function()
-    return property(**func_locals)
-
-
 def getattr_(obj, name, default_thunk):
     "Similar to .setdefault in dictionaries."
     try:

http://git-wip-us.apache.org/repos/asf/allura/blob/c72837df/ForgeBlog/forgeblog/main.py
----------------------------------------------------------------------
diff --git a/ForgeBlog/forgeblog/main.py b/ForgeBlog/forgeblog/main.py
index 93cd01b..160b94e 100644
--- a/ForgeBlog/forgeblog/main.py
+++ b/ForgeBlog/forgeblog/main.py
@@ -39,7 +39,7 @@ from allura.app import Application, SitemapEntry
 from allura.app import DefaultAdminController
 from allura.lib import helpers as h
 from allura.lib.search import search_app
-from allura.lib.decorators import require_post, Property
+from allura.lib.decorators import require_post
 from allura.lib.security import has_access, require_access
 from allura.lib import widgets as w
 from allura.lib.widgets.subscriptions import SubscribeForm
@@ -106,25 +106,25 @@ class ForgeBlogApp(Application):
         self.admin = BlogAdminController(self)
         self.api_root = RootRestController()
 
-    @Property
-    def external_feeds_list():
-        def fget(self):
-            globals = BM.Globals.query.get(app_config_id=self.config._id)
-            if globals is not None:
-                external_feeds = globals.external_feeds
-            else:
-                external_feeds = self.default_external_feeds
-            return external_feeds
-
-        def fset(self, new_external_feeds):
-            globals = BM.Globals.query.get(app_config_id=self.config._id)
-            if globals is not None:
-                globals.external_feeds = new_external_feeds
-            elif len(new_external_feeds) > 0:
-                globals = BM.Globals(
-                    app_config_id=self.config._id, external_feeds=new_external_feeds)
-            if globals is not None:
-                session(globals).flush()
+    @property
+    def external_feeds_list(self):
+        globals = BM.Globals.query.get(app_config_id=self.config._id)
+        if globals is not None:
+            external_feeds = globals.external_feeds
+        else:
+            external_feeds = self.default_external_feeds
+        return external_feeds
+
+    @external_feeds_list.setter
+    def external_feeds_list(self, new_external_feeds):
+        globals = BM.Globals.query.get(app_config_id=self.config._id)
+        if globals is not None:
+            globals.external_feeds = new_external_feeds
+        elif len(new_external_feeds) > 0:
+            globals = BM.Globals(
+                app_config_id=self.config._id, external_feeds=new_external_feeds)
+        if globals is not None:
+            session(globals).flush()
 
     def main_menu(self):
         return [SitemapEntry(self.config.options.mount_label, '.')]

http://git-wip-us.apache.org/repos/asf/allura/blob/c72837df/ForgeWiki/forgewiki/wiki_main.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/wiki_main.py b/ForgeWiki/forgewiki/wiki_main.py
index ecbddef..a5b3d3e 100644
--- a/ForgeWiki/forgewiki/wiki_main.py
+++ b/ForgeWiki/forgewiki/wiki_main.py
@@ -35,7 +35,7 @@ from allura import model as M
 from allura.lib import helpers as h
 from allura.app import Application, SitemapEntry, DefaultAdminController
 from allura.lib.search import search_app
-from allura.lib.decorators import require_post, Property
+from allura.lib.decorators import require_post
 from allura.lib.security import require_access, has_access
 from allura.controllers import AppDiscussionController, BaseController, AppDiscussionRestController
 from allura.controllers import DispatchIndex
@@ -129,25 +129,25 @@ class ForgeWikiApp(Application):
             log.exception('Error getting artifact %s', topic)
         self.handle_artifact_message(page, message)
 
-    @Property
-    def root_page_name():
-        def fget(self):
-            globals = WM.Globals.query.get(app_config_id=self.config._id)
-            if globals is not None:
-                page_name = globals.root
-            else:
-                page_name = self.default_root_page_name
-            return page_name
-
-        def fset(self, new_root_page_name):
-            globals = WM.Globals.query.get(app_config_id=self.config._id)
-            if globals is not None:
-                globals.root = new_root_page_name
-            elif new_root_page_name != self.default_root_page_name:
-                globals = WM.Globals(
-                    app_config_id=self.config._id, root=new_root_page_name)
-            if globals is not None:
-                session(globals).flush(globals)
+    @property
+    def root_page_name(self):
+        globals = WM.Globals.query.get(app_config_id=self.config._id)
+        if globals is not None:
+            page_name = globals.root
+        else:
+            page_name = self.default_root_page_name
+        return page_name
+
+    @root_page_name.setter
+    def root_page_name(self, new_root_page_name):
+        globals = WM.Globals.query.get(app_config_id=self.config._id)
+        if globals is not None:
+            globals.root = new_root_page_name
+        elif new_root_page_name != self.default_root_page_name:
+            globals = WM.Globals(
+                app_config_id=self.config._id, root=new_root_page_name)
+        if globals is not None:
+            session(globals).flush(globals)
 
     def default_root_page_text(self):
         return """Welcome to your wiki!
@@ -159,29 +159,29 @@ The wiki uses [Markdown](%s) syntax.
 [[members limit=20]]
 """ % (self.url + 'markdown_syntax/')
 
-    @Property
-    def show_discussion():
-        def fget(self):
-            return self.config.options.get('show_discussion', True)
+    @property
+    def show_discussion(self):
+        return self.config.options.get('show_discussion', True)
 
-        def fset(self, show):
-            self.config.options['show_discussion'] = bool(show)
+    @show_discussion.setter
+    def show_discussion(self, show):
+        self.config.options['show_discussion'] = bool(show)
 
-    @Property
-    def show_left_bar():
-        def fget(self):
-            return self.config.options.get('show_left_bar', True)
+    @property
+    def show_left_bar(self):
+        return self.config.options.get('show_left_bar', True)
 
-        def fset(self, show):
-            self.config.options['show_left_bar'] = bool(show)
+    @show_left_bar.setter
+    def show_left_bar(self, show):
+        self.config.options['show_left_bar'] = bool(show)
 
-    @Property
-    def show_right_bar():
-        def fget(self):
-            return self.config.options.get('show_right_bar', True)
+    @property
+    def show_right_bar(self):
+        return self.config.options.get('show_right_bar', True)
 
-        def fset(self, show):
-            self.config.options['show_right_bar'] = bool(show)
+    @show_right_bar.setter
+    def show_right_bar(self, show):
+        self.config.options['show_right_bar'] = bool(show)
 
     def main_menu(self):
         '''Apps should provide their entries to be added to the main nav


[21/25] allura git commit: [#7870] further comments in development.ini

Posted by je...@apache.org.
[#7870] further comments in development.ini


Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/95af4cb7
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/95af4cb7
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/95af4cb7

Branch: refs/heads/ib/7856
Commit: 95af4cb76ceb03a832ab91f515331bf88daba5d1
Parents: 2cdb4f8
Author: Dave Brondsema <da...@brondsema.net>
Authored: Mon Apr 20 12:11:46 2015 -0400
Committer: Heith Seewald <hs...@slashdotmedia.com>
Committed: Mon Apr 20 12:51:30 2015 -0400

----------------------------------------------------------------------
 Allura/development.ini | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/allura/blob/95af4cb7/Allura/development.ini
----------------------------------------------------------------------
diff --git a/Allura/development.ini b/Allura/development.ini
index b7e0b95..5d68aed 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -77,7 +77,9 @@ full_stack = true
 site_name = Allura
 ; Change these to your website's domain
 domain = localhost
+; Change this to your website's full URL
 base_url = http://localhost:8080
+; This should be the same as base_url
 forgemail.url = http://localhost:8080
 
 ; Used to uniquify references to static resources, can be a timestamp or any unique value
@@ -111,7 +113,7 @@ beaker.session.validate_key = 714bfe3612c42390726f
 ; Google Analytics account for tracking
 ;ga.account = UA-XXXXX-X
 
-; Project registration system.  Only local is available, unless you write a custom one for custom integratino.
+; Project registration system.  Only local is available, unless you write a custom one for custom integration.
 registration.method = local
 theme = allura
 
@@ -123,6 +125,7 @@ auth.remember_for = 365  ; in days, for the "remember me" checkbox on login
 ; Customize login/logout URLs only if you have some custom authentication set up.
 auth.login_url = /auth/
 auth.logout_url = /auth/logout
+; the login fragement URL shows just the form, not a whole page.  It is used within a login overlay on some pages
 auth.login_fragment_url = /auth/login_fragment/
 auth.post_logout_url = /
 
@@ -367,6 +370,7 @@ ming.task.auto_ensure_indexes = False
 stats.sample_rate = 1
 
 ; Taskd setup
+; number of seconds to sleep between checking for new tasks
 monq.poll_interval=2
 
 ; SOLR setup
@@ -404,10 +408,13 @@ forgemail.domain = .in.localhost
 ; set this to "false" if you are deploying to production and want performance improvements
 auto_reload_templates = true
 
-; How frequently users can send messages
+; How frequently users can send messages, in seconds
 user_message.time_interval = 3600
+; Max number of messages that can be sent within that time interval.
 user_message.max_messages = 20
+
 ; Default number of times to show a sitewide notification
+; See https://forge-allura.apache.org/docs/getting_started/administration.html#site-notifications
 site_notification.impressions = 0
 
 ; When rendering discussion post Markdown to html, if the render takes longer
@@ -424,6 +431,7 @@ markdown_render_max_length = 999999999
 show_export_control = false
 
 ; By default project admins can soft-delete their projects.
+; A soft-deleted project will still be in the database and visible to admins, but not to others.
 allow_project_delete = true
 allow_project_undelete = true
 
@@ -483,7 +491,7 @@ override_root = task ; TurboGears will use controllers/task.py as root controlle
 ;
 ; Add additional loggers, handlers, formatters here
 ; Uses python's logging config file format
-; http://docs.python.org/lib/logging-config-fileformat.html
+; https://docs.python.org/2/library/logging.config.html#configuration-file-format
 ;
 [loggers]
 keys = root, allura, sqlalchemy, paste, pylons, taskdstatus, timermiddleware, tmw_details