You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by br...@apache.org on 2014/01/22 20:36:51 UTC

[1/3] git commit: [#6393] Cleanup

Updated Branches:
  refs/heads/master 5d46b785d -> a2bc2dd64


[#6393] Cleanup

* Removed download button test
* Changed show_download_button macro default to False
* Added docs for extending Allura with macros

Signed-off-by: Tim Van Steenburgh <tv...@gmail.com>


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

Branch: refs/heads/master
Commit: 586eb2c1931754e69eab10c0b8a07d76b864dd12
Parents: bc594e1
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Thu Jan 16 13:11:51 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Wed Jan 22 19:35:54 2014 +0000

----------------------------------------------------------------------
 Allura/allura/lib/app_globals.py               |  2 +
 Allura/allura/lib/macro.py                     |  6 +--
 Allura/allura/templates/neighborhood_help.html |  2 +-
 Allura/allura/tests/test_globals.py            |  8 ----
 Allura/docs/extending.rst                      | 41 +++++++++++++++++++++
 5 files changed, 47 insertions(+), 12 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/586eb2c1/Allura/allura/lib/app_globals.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/app_globals.py b/Allura/allura/lib/app_globals.py
index f53776d..d4f1b06 100644
--- a/Allura/allura/lib/app_globals.py
+++ b/Allura/allura/lib/app_globals.py
@@ -254,6 +254,8 @@ class Globals(object):
             stats=_cache_eps('allura.stats'),
             site_stats=_cache_eps('allura.site_stats'),
             admin=_cache_eps('allura.admin'),
+            # macro eps are used solely for ensuring that external macros are
+            # imported (after load, the ep itself is not used)
             macros=_cache_eps('allura.macros'),
         )
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/586eb2c1/Allura/allura/lib/macro.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/macro.py b/Allura/allura/lib/macro.py
index 957fcb8..efb1433 100644
--- a/Allura/allura/lib/macro.py
+++ b/Allura/allura/lib/macro.py
@@ -164,7 +164,7 @@ def project_blog_posts(max_number=5, sort='timestamp', summary=False, mount_poin
 def get_projects_for_macro(
         category=None, display_mode='grid', sort='last_updated',
         show_total=False, limit=100, labels='', award='', private=False,
-        columns=1, show_proj_icon=True, show_download_button=True, show_awards_banner=True,
+        columns=1, show_proj_icon=True, show_download_button=False, show_awards_banner=True,
         grid_view_tools='',
         initial_q={}):
     from allura.lib.widgets.project_list import ProjectList
@@ -267,7 +267,7 @@ def get_projects_for_macro(
 @macro('neighborhood-wiki')
 def projects(category=None, display_mode='grid', sort='last_updated',
              show_total=False, limit=100, labels='', award='', private=False,
-             columns=1, show_proj_icon=True, show_download_button=True, show_awards_banner=True,
+             columns=1, show_proj_icon=True, show_download_button=False, show_awards_banner=True,
              grid_view_tools=''):
     initial_q = dict(neighborhood_id=c.project.neighborhood_id)
     return get_projects_for_macro(
@@ -281,7 +281,7 @@ def projects(category=None, display_mode='grid', sort='last_updated',
 @macro('userproject-wiki')
 def my_projects(category=None, display_mode='grid', sort='last_updated',
                 show_total=False, limit=100, labels='', award='', private=False,
-                columns=1, show_proj_icon=True, show_download_button=True, show_awards_banner=True,
+                columns=1, show_proj_icon=True, show_download_button=False, show_awards_banner=True,
                 grid_view_tools=''):
 
     myproj_user = c.project.user_project_of

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/586eb2c1/Allura/allura/templates/neighborhood_help.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/neighborhood_help.html b/Allura/allura/templates/neighborhood_help.html
index ed57b53..5c5d27a 100644
--- a/Allura/allura/templates/neighborhood_help.html
+++ b/Allura/allura/templates/neighborhood_help.html
@@ -45,7 +45,7 @@
     <li><code>display_mode</code> = grid/list.  Default is 'grid'</li>
     <li><code>show_proj_icon</code> = yes/no.  Default 'yes'</li>
     <li><code>grid_view_tools</code> = git,hg,svn,tickets,wiki... Limit the tools shown in project list. Multivalue option (example grid_view_tools=git,wiki).  Default ''</li>
-    <li><code>show_download_button</code> = yes/no.  Default 'yes'</li>
+    <li><code>show_download_button</code> = yes/no.  Default 'no'</li>
 	<li><code>show_awards_banner</code> = yes/no.  Default 'yes'</li>
     <li><code>sort</code> = last_updated/alpha/random/last_registered.  Default 'last_updated'</li>
     <li><code>show_total</code> = yes/no.  Adds a sentence with a total count of how many projects are listed. Default 'no'</li>

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/586eb2c1/Allura/allura/tests/test_globals.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_globals.py b/Allura/allura/tests/test_globals.py
index 1910e89..c8553a1 100644
--- a/Allura/allura/tests/test_globals.py
+++ b/Allura/allura/tests/test_globals.py
@@ -499,14 +499,6 @@ def test_projects_macro():
         r = g.markdown_wiki.convert('[[projects display_mode=list columns=3]]')
         assert two_column_style not in r
 
-        # test project download button
-        r = g.markdown_wiki.convert(
-            '[[projects display_mode=list show_download_button=True]]')
-        assert 'download-button' in r
-        r = g.markdown_wiki.convert(
-            '[[projects display_mode=list show_download_button=False]]')
-        assert 'download-button' not in r
-
 
 @td.with_wiki
 def test_limit_tools_macro():

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/586eb2c1/Allura/docs/extending.rst
----------------------------------------------------------------------
diff --git a/Allura/docs/extending.rst b/Allura/docs/extending.rst
index 7fb46da..c39d572 100644
--- a/Allura/docs/extending.rst
+++ b/Allura/docs/extending.rst
@@ -64,3 +64,44 @@ The events that allura publishes are:
 * repo_cloned
 * repo_refreshed
 * repo_clone_task_failed
+
+
+Markdown Macros
+===============
+
+Most text inputs in Allura accept Markdown text which is parsed and turned into
+HTML before being rendered. The Markdown text may contain "macros" - custom
+commands which extend the Markdown language. Here's an example of a macro
+that comes with Allura::
+
+    [[project_admins]]
+
+Include this macro in a wiki page or other Markdown content, and when rendered
+it will be replaced by an actual list of the project's admin users.
+
+Extending Allura with your own macros is simple, requiring two basic steps:
+
+1. Decide on a name for your macro, then create a function with that name, and
+   decorate it with the `macro()` decorator from Allura. The function can
+   accept keyword arguments, and must return text or HTML. For example::
+
+    from allura.lib.macro import macro
+
+    @macro()
+    def hello(name='World'):
+        return "<p>Hello {}!</p>".format(name)
+
+2. Add an entry point for your macro to the `setup.py` for your package::
+
+    [allura.macros]
+    hello_macro = mypkg.mymodule:hello
+
+Note that the key name (`hello_macro` in this case) doesn't matter - the macro
+is named after the function name. Our example macro could be used in a couple
+ways::
+
+    [[hello]]
+    [[hello name=Universe]]
+
+For more help with macros, consult the source code for the macros that ship
+with Allura. You can find them in the `allura.lib.macro` package.


[3/3] git commit: [#6393] Remove download button from default wiki text

Posted by br...@apache.org.
[#6393] Remove download button from default wiki text

Signed-off-by: Tim Van Steenburgh <tv...@gmail.com>


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

Branch: refs/heads/master
Commit: a2bc2dd6444f1271a59ace9bf956c57b1c5072b7
Parents: 586eb2c
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Tue Jan 21 21:43:58 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Wed Jan 22 19:36:00 2014 +0000

----------------------------------------------------------------------
 ForgeWiki/forgewiki/wiki_main.py | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/a2bc2dd6/ForgeWiki/forgewiki/wiki_main.py
----------------------------------------------------------------------
diff --git a/ForgeWiki/forgewiki/wiki_main.py b/ForgeWiki/forgewiki/wiki_main.py
index 2709733..01a6008 100644
--- a/ForgeWiki/forgewiki/wiki_main.py
+++ b/ForgeWiki/forgewiki/wiki_main.py
@@ -146,6 +146,16 @@ class ForgeWikiApp(Application):
             if globals is not None:
                 session(globals).flush(globals)
 
+    def default_root_page_text(self):
+        return """Welcome to your wiki!
+
+This is the default page, edit it as you see fit. To add a new page simply reference it within brackets, e.g.: [SamplePage].
+
+The wiki uses [Markdown](%s) syntax.
+
+[[members limit=20]]
+""" % (self.url + 'markdown_syntax/')
+
     @Property
     def show_discussion():
         def fget(self):
@@ -272,16 +282,7 @@ class ForgeWikiApp(Application):
             with h.push_config(c, app=self):
                 p = WM.Page.upsert(new_root)
                 p.viewable_by = ['all']
-                url = c.app.url + 'markdown_syntax' + '/'
-                p.text = """Welcome to your wiki!
-
-This is the default page, edit it as you see fit. To add a new page simply reference it within brackets, e.g.: [SamplePage].
-
-The wiki uses [Markdown](%s) syntax.
-
-[[members limit=20]]
-[[download_button]]
-""" % url
+                p.text = self.default_root_page_text()
                 p.commit()
 
     def uninstall(self, project):


[2/3] git commit: [#6393] Load macros from external packages

Posted by br...@apache.org.
[#6393] Load macros from external packages

* Moved download_button macro out of allura
* Fixed/cleaned up tests that rely on pylons globals

Signed-off-by: Tim Van Steenburgh <tv...@gmail.com>


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

Branch: refs/heads/master
Commit: bc594e1625698bdb83577749d17fba336fe594a8
Parents: 5d46b78
Author: Tim Van Steenburgh <tv...@gmail.com>
Authored: Tue Jan 14 18:06:46 2014 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Wed Jan 22 19:35:54 2014 +0000

----------------------------------------------------------------------
 Allura/allura/lib/app_globals.py                |  1 +
 Allura/allura/lib/macro.py                      | 20 ------------
 Allura/allura/lib/widgets/macros.py             | 11 -------
 .../templates/widgets/download_button.html      | 19 ------------
 Allura/allura/tests/model/test_openid.py        |  9 ++----
 Allura/allura/tests/test_app.py                 |  7 ++---
 Allura/allura/tests/test_globals.py             | 32 +++++++++-----------
 Allura/allura/tests/test_utils.py               |  1 -
 AlluraTest/alluratest/controller.py             |  5 +--
 9 files changed, 24 insertions(+), 81 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/bc594e16/Allura/allura/lib/app_globals.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/app_globals.py b/Allura/allura/lib/app_globals.py
index ecc7b35..f53776d 100644
--- a/Allura/allura/lib/app_globals.py
+++ b/Allura/allura/lib/app_globals.py
@@ -254,6 +254,7 @@ class Globals(object):
             stats=_cache_eps('allura.stats'),
             site_stats=_cache_eps('allura.site_stats'),
             admin=_cache_eps('allura.admin'),
+            macros=_cache_eps('allura.macros'),
         )
 
         # Zarkov logger

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/bc594e16/Allura/allura/lib/macro.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/macro.py b/Allura/allura/lib/macro.py
index d22b431..957fcb8 100644
--- a/Allura/allura/lib/macro.py
+++ b/Allura/allura/lib/macro.py
@@ -318,26 +318,6 @@ def gittip_button(username):
     response = button.display(username=username)
     return response
 
-# FIXME: this is SourceForge specific - need to provide a way for macros
-# to come from other packages
-
-
-@macro()
-def download_button():
-    from allura.lib.widgets.macros import DownloadButton
-    button = DownloadButton(project=c.project)
-    try:
-        res_mgr = g.resource_manager
-    except TypeError:
-        # e.g. "TypeError: No object (name: widget_context) has been registered for this thread"
-        # this is an ugly way to check to see if we're outside of a web request
-        # and avoid errors
-        return '[[download_button]]'
-    else:
-        res_mgr.register(button)
-        response = button.display(project=c.project)
-        return response
-
 
 @macro()
 def include(ref=None, **kw):

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/bc594e16/Allura/allura/lib/widgets/macros.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/widgets/macros.py b/Allura/allura/lib/widgets/macros.py
index 18268cb..77c329a 100644
--- a/Allura/allura/lib/widgets/macros.py
+++ b/Allura/allura/lib/widgets/macros.py
@@ -33,17 +33,6 @@ class GittipButton(ew.Widget):
     project = None
 
 
-class DownloadButton(ew.Widget):
-    template = 'jinja:allura:templates/widgets/download_button.html'
-    params = ['project']
-    project = None
-
-    def resources(self):
-        yield ew.jinja2_ew.JSScript('''
-            $(function(){$(".download-button-%s").load("%s");
-        });''' % (self.project._id, self.project.best_download_url()))
-
-
 class NeighborhoodFeeds(ew.Widget):
     template = 'jinja:allura:templates/macro/neighborhood_feeds.html'
     params = ['feeds']

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/bc594e16/Allura/allura/templates/widgets/download_button.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/widgets/download_button.html b/Allura/allura/templates/widgets/download_button.html
deleted file mode 100644
index 44e3b36..0000000
--- a/Allura/allura/templates/widgets/download_button.html
+++ /dev/null
@@ -1,19 +0,0 @@
-{#-
-       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.
--#}
-<p><span class="download-button-{{project._id}}" style="margin-bottom: 1em; display: block;"></span></p>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/bc594e16/Allura/allura/tests/model/test_openid.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/model/test_openid.py b/Allura/allura/tests/model/test_openid.py
index 056f030..30dcdb4 100644
--- a/Allura/allura/tests/model/test_openid.py
+++ b/Allura/allura/tests/model/test_openid.py
@@ -23,22 +23,17 @@ Model tests for openid_model
 import time
 
 import mock
-from pylons import tmpl_context as c, app_globals as g
-from pylons import request
-from webob import Request
 from openid.association import Association
 
 from ming.orm.ormsession import ThreadLocalORMSession
 
-from allura.lib.app_globals import Globals
+from alluratest.controller import setup_unit_test
 from allura import model as M
 from allura.lib import helpers as h
 
 
 def setUp():
-    g._push_object(Globals())
-    c._push_object(mock.Mock())
-    request._push_object(Request.blank('/'))
+    setup_unit_test()
     ThreadLocalORMSession.close_all()
     M.EmailAddress.query.remove({})
     M.OpenIdNonce.query.remove({})

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/bc594e16/Allura/allura/tests/test_app.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_app.py b/Allura/allura/tests/test_app.py
index f5f5ac4..a31f112 100644
--- a/Allura/allura/tests/test_app.py
+++ b/Allura/allura/tests/test_app.py
@@ -15,17 +15,16 @@
 #       specific language governing permissions and limitations
 #       under the License.
 
-from pylons import tmpl_context as c, app_globals as g
+from pylons import tmpl_context as c
 import mock
 from ming.base import Object
 
+from alluratest.controller import setup_unit_test
 from allura import app
-from allura.lib.app_globals import Globals
 
 
 def setUp():
-    g._push_object(Globals())
-    c._push_object(mock.Mock())
+    setup_unit_test()
     c.user._id = None
     c.project = mock.Mock()
     c.project.name = 'Test Project'

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/bc594e16/Allura/allura/tests/test_globals.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_globals.py b/Allura/allura/tests/test_globals.py
index e537c2d..1910e89 100644
--- a/Allura/allura/tests/test_globals.py
+++ b/Allura/allura/tests/test_globals.py
@@ -26,13 +26,16 @@ import hashlib
 from mock import patch
 
 from bson import ObjectId
-
 from nose.tools import with_setup, assert_equal, assert_in
 from pylons import tmpl_context as c, app_globals as g
 import tg
 
 from ming.orm import ThreadLocalORMSession
-from alluratest.controller import setup_basic_test, setup_global_objects
+from alluratest.controller import (
+        setup_basic_test,
+        setup_global_objects,
+        setup_unit_test,
+        )
 
 from allura import model as M
 from allura.lib import helpers as h
@@ -46,9 +49,14 @@ from forgeblog import model as BM
 def setUp():
     """Method called by nose once before running the package.  Some functions need it run again to reset data"""
     setup_basic_test()
+    setup_unit_test()
     setup_with_tools()
 
 
+def tearDown():
+    setUp()
+
+
 @td.with_wiki
 def setup_with_tools():
     setup_global_objects()
@@ -66,7 +74,7 @@ def test_app_globals():
         assert g.url('/foo') == 'http://localhost/foo', g.url('/foo')
 
 
-@with_setup(teardown=setUp)  # reset everything we changed
+@with_setup(setUp)
 def test_macro_projects():
     file_name = 'neo-icon-set-454545-256x350.png'
     file_path = os.path.join(
@@ -153,16 +161,6 @@ def test_macro_projects():
         assert '<img alt="Test Project Logo"' not in r
 
 
-def test_macro_download_button():
-    p_nbhd = M.Neighborhood.query.get(name='Projects')
-    p_test = M.Project.query.get(shortname='test', neighborhood_id=p_nbhd._id)
-    with h.push_config(c, project=p_test):
-        r = g.markdown_wiki.convert('[[download_button]]')
-    assert_equal(
-        r, '<div class="markdown_content"><p><span class="download-button-%s" style="margin-bottom: 1em; display: block;"></span></p>\n</div>' %
-        p_test._id)
-
-
 def test_macro_gittip_button():
     p_nbhd = M.Neighborhood.query.get(name='Projects')
     p_test = M.Project.query.get(shortname='test', neighborhood_id=p_nbhd._id)
@@ -204,7 +202,7 @@ def test_macro_neighborhood_feeds():
         assert 'test content' in r
 
 
-@with_setup(setUp, setUp)  # start clean and reset everything we change
+@with_setup(setUp)
 def test_macro_members():
     p_nbhd = M.Neighborhood.query.get(name='Projects')
     p_test = M.Project.query.get(shortname='test', neighborhood_id=p_nbhd._id)
@@ -220,7 +218,7 @@ def test_macro_members():
                  '</div>')
 
 
-@with_setup(teardown=setUp)  # reset everything we changed
+@with_setup(setUp)
 def test_macro_members_escaping():
     user = M.User.by_username('test-admin')
     user.display_name = u'Test Admin <script>'
@@ -231,7 +229,7 @@ def test_macro_members_escaping():
                  u'</ul>\n</div>')
 
 
-@with_setup(teardown=setUp)  # reset everything we changed
+@with_setup(setUp)
 def test_macro_project_admins():
     user = M.User.by_username('test-admin')
     user.display_name = u'Test Ã…dmin <script>'
@@ -241,7 +239,7 @@ def test_macro_project_admins():
         r, u'<div class="markdown_content"><h6>Project Admins:</h6>\n<ul class="md-users-list">\n<li><a href="/u/test-admin/">Test \xc5dmin &lt;script&gt;</a></li>\n</ul>\n</div>')
 
 
-@with_setup(teardown=setUp)  # reset everything we changed
+@with_setup(setUp)
 def test_macro_project_admins_one_br():
     p_nbhd = M.Neighborhood.query.get(name='Projects')
     p_test = M.Project.query.get(shortname='test', neighborhood_id=p_nbhd._id)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/bc594e16/Allura/allura/tests/test_utils.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/test_utils.py b/Allura/allura/tests/test_utils.py
index 232763a..92f1e28 100644
--- a/Allura/allura/tests/test_utils.py
+++ b/Allura/allura/tests/test_utils.py
@@ -96,7 +96,6 @@ class TestAntispam(unittest.TestCase):
 
     def setUp(self):
         setup_unit_test()
-        pylons.request._push_object(Request.blank('/'))
         pylons.request.remote_addr = '127.0.0.1'
         self.a = utils.AntiSpam()
 

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/bc594e16/AlluraTest/alluratest/controller.py
----------------------------------------------------------------------
diff --git a/AlluraTest/alluratest/controller.py b/AlluraTest/alluratest/controller.py
index 8386d0b..dcd7c53 100644
--- a/AlluraTest/alluratest/controller.py
+++ b/AlluraTest/alluratest/controller.py
@@ -26,9 +26,9 @@ from paste.deploy import loadapp
 from paste.deploy.converters import asbool
 from paste.script.appinstall import SetupCommand
 from pylons import tmpl_context as c, app_globals as g
-from pylons import url, response, session
+from pylons import url, request, response, session
 import tg
-from webob import Response
+from webob import Response, Request
 import ew
 from ming.orm import ThreadLocalORMSession
 import ming.orm
@@ -101,6 +101,7 @@ def setup_unit_test():
     REGISTRY.register(g, Globals())
     REGISTRY.register(c, mock.Mock())
     REGISTRY.register(url, lambda: None)
+    REGISTRY.register(request, Request.blank('/'))
     REGISTRY.register(response, Response())
     REGISTRY.register(session, beaker.session.SessionObject({}))
     REGISTRY.register(allura.credentials, allura.lib.security.Credentials())