[#6530] Refactor error handling into context manager

- Also allows exc to propagate up so task will end in error state

Signed-off-by: Tim Van Steenburgh <tvansteenburgh@gmail.com>
diff --git a/ForgeImporters/forgeimporters/base.py b/ForgeImporters/forgeimporters/base.py
index 54f006b..e0e9d6f 100644
--- a/ForgeImporters/forgeimporters/base.py
+++ b/ForgeImporters/forgeimporters/base.py
@@ -66,20 +66,31 @@
     mount_label = fev.UnicodeString()
 
 
+class ImportErrorHandler(object):
+    def __init__(self, importer, project_name):
+        self.importer = importer
+        self.project_name = project_name
+
+    def __enter__(self):
+        pass
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        if exc_type:
+            g.post_event('import_tool_task_failed',
+                error=str(exc_val),
+                traceback=traceback.format_exc(),
+                importer_source=self.importer.source,
+                importer_tool_label=self.importer.tool_label,
+                project_name=self.project_name,
+                )
+
+
 @task(notifications_disabled=True)
 def import_tool(importer_name, project_name=None, mount_point=None, mount_label=None, **kw):
-    try:
-        importer = ToolImporter.by_name(importer_name)
+    importer = ToolImporter.by_name(importer_name)
+    with ImportErrorHandler(importer, project_name):
         importer.import_tool(c.project, c.user, project_name=project_name,
                 mount_point=mount_point, mount_label=mount_label, **kw)
-    except Exception as e:
-        g.post_event('import_tool_task_failed',
-                error=str(e),
-                traceback=traceback.format_exc(),
-                importer_source=importer.source,
-                importer_tool_label=importer.tool_label,
-                project_name=project_name,
-                )
 
 
 class ProjectExtractor(object):
diff --git a/ForgeImporters/forgeimporters/google/code.py b/ForgeImporters/forgeimporters/google/code.py
index 5adaaa0..359632f 100644
--- a/ForgeImporters/forgeimporters/google/code.py
+++ b/ForgeImporters/forgeimporters/google/code.py
@@ -16,7 +16,6 @@
 #       under the License.
 
 import urllib2
-import traceback
 
 import formencode as fe
 from formencode import validators as fev
@@ -38,7 +37,10 @@
 from allura.lib import validators as v
 from allura.lib.decorators import require_post, task
 
-from forgeimporters.base import ToolImporter
+from forgeimporters.base import (
+        ToolImporter,
+        ImportErrorHandler,
+        )
 from forgeimporters.google import GoogleCodeProjectExtractor
 
 REPO_APPS = {}
@@ -84,17 +86,9 @@
 
 @task(notifications_disabled=True)
 def import_tool(**kw):
-    try:
-        importer = GoogleRepoImporter()
+    importer = GoogleRepoImporter()
+    with ImportErrorHandler(importer, kw.get('project_name')):
         importer.import_tool(c.project, c.user, **kw)
-    except Exception as e:
-        g.post_event('import_tool_task_failed',
-                error=str(e),
-                traceback=traceback.format_exc(),
-                importer_source=importer.source,
-                importer_tool_label=importer.tool_label,
-                project_name=kw.get('project_name'),
-                )
 
 
 class GoogleRepoImportForm(fe.schema.Schema):
diff --git a/ForgeImporters/forgeimporters/google/tracker.py b/ForgeImporters/forgeimporters/google/tracker.py
index e5c8dc3..1535531 100644
--- a/ForgeImporters/forgeimporters/google/tracker.py
+++ b/ForgeImporters/forgeimporters/google/tracker.py
@@ -17,7 +17,6 @@
 
 from collections import defaultdict
 from datetime import datetime
-import traceback
 
 from formencode import validators as fev
 
@@ -49,22 +48,15 @@
 from forgeimporters.base import (
         ToolImporter,
         ToolImportForm,
+        ImportErrorHandler,
         )
 
 
 @task(notifications_disabled=True)
 def import_tool(**kw):
-    try:
-        importer = GoogleCodeTrackerImporter()
+    importer = GoogleCodeTrackerImporter()
+    with ImportErrorHandler(importer, kw.get('project_name')):
         importer.import_tool(c.project, c.user, **kw)
-    except Exception as e:
-        g.post_event('import_tool_task_failed',
-                error=str(e),
-                traceback=traceback.format_exc(),
-                importer_source=importer.source,
-                importer_tool_label=importer.tool_label,
-                project_name=kw.get('project_name'),
-                )
 
 
 class GoogleCodeTrackerImportForm(ToolImportForm):
diff --git a/ForgeImporters/forgeimporters/tests/test_base.py b/ForgeImporters/forgeimporters/tests/test_base.py
index f6d443f..7de0625 100644
--- a/ForgeImporters/forgeimporters/tests/test_base.py
+++ b/ForgeImporters/forgeimporters/tests/test_base.py
@@ -20,7 +20,7 @@
 from formencode import Invalid
 import mock
 from tg import expose
-from nose.tools import assert_equal
+from nose.tools import assert_equal, assert_raises
 
 from alluratest.controller import TestController
 
@@ -66,7 +66,8 @@
     importer.import_tool.side_effect = RuntimeError('my error')
     ToolImporter.by_name.return_value = importer
 
-    base.import_tool('importer_name', project_name='project_name')
+    assert_raises(RuntimeError, base.import_tool, 'importer_name',
+            project_name='project_name')
     g.post_event.assert_called_once_with(
             'import_tool_task_failed',
             error=str(importer.import_tool.side_effect),
diff --git a/ForgeImporters/forgeimporters/trac/tickets.py b/ForgeImporters/forgeimporters/trac/tickets.py
index 7876b44..3063d71 100644
--- a/ForgeImporters/forgeimporters/trac/tickets.py
+++ b/ForgeImporters/forgeimporters/trac/tickets.py
@@ -20,7 +20,6 @@
         timedelta,
         )
 import json
-import traceback
 
 from formencode import validators as fev
 
@@ -53,6 +52,7 @@
 from forgeimporters.base import (
         ToolImporter,
         ToolImportForm,
+        ImportErrorHandler,
         )
 from forgetracker.tracker_main import ForgeTrackerApp
 from forgetracker.scripts.import_tracker import import_tracker
@@ -60,17 +60,9 @@
 
 @task(notifications_disabled=True)
 def import_tool(**kw):
-    try:
-        importer = TracTicketImporter()
+    importer = TracTicketImporter()
+    with ImportErrorHandler(importer, kw.get('trac_url')):
         importer.import_tool(c.project, c.user, **kw)
-    except Exception as e:
-        g.post_event('import_tool_task_failed',
-                error=str(e),
-                traceback=traceback.format_exc(),
-                importer_source=importer.source,
-                importer_tool_label=importer.tool_label,
-                project_name=kw.get('trac_url'),
-                )
 
 
 class TracTicketImportForm(ToolImportForm):