[#5230] Move SF-specific post-repo-clone handling our of allura core.
- Also added new 'repo_cloned_failed' event
diff --git a/Allura/allura/tasks/repo_tasks.py b/Allura/allura/tasks/repo_tasks.py
index ee7e58f..369b3f9 100644
--- a/Allura/allura/tasks/repo_tasks.py
+++ b/Allura/allura/tasks/repo_tasks.py
@@ -1,13 +1,10 @@
import shutil
import logging
-import traceback
from pylons import c
from allura.lib.decorators import task
from allura.lib.repository import RepositoryApp
-from allura.lib import helpers as h
-from allura.tasks.mail_tasks import sendmail
@task
def init(**kwargs):
@@ -19,57 +16,16 @@
c.project.shortname, c.app.config.options.mount_point))
@task
-def clone(
- cloned_from_path,
- cloned_from_name,
- cloned_from_url):
- try:
- from allura import model as M
- c.app.repo.init_as_clone(
- cloned_from_path,
- cloned_from_name,
- cloned_from_url)
- M.Notification.post_user(
- c.user, c.app.repo, 'created',
- text='Repository %s/%s created' % (
- c.project.shortname, c.app.config.options.mount_point))
- if not c.project.suppress_emails:
- sendmail(
- destinations=[str(c.user._id)],
- fromaddr=u'SourceForge.net <noreply+project-upgrade@in.sf.net>',
- reply_to=u'noreply@in.sf.net',
- subject=u'SourceForge Repo Clone Complete',
- message_id=h.gen_message_id(),
- text=u''.join([
- u'Your cloned repository %s in project %s is now ready for use.\n\n',
- u'Old repository url: %s \n\n',
- u'New repository checkout command: %s \n\n',
- u'You and any other developers should do a fresh checkout using the ',
- u'new repository location.\n'
- ]) % (c.app.config.options.mount_point, c.project.shortname, cloned_from_url, c.app.repo.clone_command('rw')))
- except:
- sendmail(
- destinations=['sfengineers@geek.net'],
- fromaddr=u'SourceForge.net <noreply+project-upgrade@in.sf.net>',
- reply_to=u'noreply@in.sf.net',
- subject=u'SourceForge Repo Clone Failure',
- message_id=h.gen_message_id(),
- text=u''.join([
- u'Forking/cloning repo %s in project %s from %s failed.\n',
- u'\n',
- u'%s',
- ]) % (c.app.config.options.mount_point, c.project.shortname, cloned_from_url, traceback.format_exc()))
- if not c.project.suppress_emails:
- sendmail(
- destinations=[str(c.user._id)],
- fromaddr=u'SourceForge.net <noreply+project-upgrade@in.sf.net>',
- reply_to=u'noreply@in.sf.net',
- subject=u'SourceForge Repo Clone Failed',
- message_id=h.gen_message_id(),
- text=u''.join([
- u'Forking/cloning repo %s in project %s from %s failed. ',
- u'The SourceForge engineering team has been notified.\n',
- ]) % (c.app.config.options.mount_point, c.project.shortname, cloned_from_url))
+def clone(cloned_from_path, cloned_from_name, cloned_from_url):
+ from allura import model as M
+ c.app.repo.init_as_clone(
+ cloned_from_path,
+ cloned_from_name,
+ cloned_from_url)
+ M.Notification.post_user(
+ c.user, c.app.repo, 'created',
+ text='Repository %s/%s created' % (
+ c.project.shortname, c.app.config.options.mount_point))
@task
def reclone(*args, **kwargs):
diff --git a/ForgeGit/forgegit/model/git_repo.py b/ForgeGit/forgegit/model/git_repo.py
index 4624600..d58b02d 100644
--- a/ForgeGit/forgegit/model/git_repo.py
+++ b/ForgeGit/forgegit/model/git_repo.py
@@ -3,6 +3,7 @@
import string
import logging
import random
+import traceback
from collections import namedtuple
from datetime import datetime
from glob import glob
@@ -107,11 +108,12 @@
self.__dict__['_git'] = repo
self._setup_special_files(source_url)
except:
+ g.post_event('repo_clone_failed', source_url, traceback.format_exc())
self._repo.status = 'ready'
session(self._repo).flush(self._repo)
raise
log.info('... %r cloned', self._repo)
- g.post_event('repo_cloned')
+ g.post_event('repo_cloned', source_url)
self._repo.refresh(notify=False)
def commit(self, rev):
diff --git a/ForgeGit/forgegit/tests/model/test_repository.py b/ForgeGit/forgegit/tests/model/test_repository.py
index deb8b63..756a36f 100644
--- a/ForgeGit/forgegit/tests/model/test_repository.py
+++ b/ForgeGit/forgegit/tests/model/test_repository.py
@@ -148,7 +148,8 @@
assert os.path.exists('/tmp/testgit.git/hooks/post-receive')
assert os.access('/tmp/testgit.git/hooks/post-receive', os.X_OK)
- def test_clone(self):
+ @mock.patch('forgegit.model.git_repo.g.post_event')
+ def test_clone(self, post_event):
repo = GM.Repository(
name='testgit.git',
fs_path='/tmp/',
@@ -162,6 +163,7 @@
shutil.rmtree(dirname)
repo.init()
repo._impl.clone_from(repo_path)
+ post_event.assert_any_call('repo_cloned', repo_path)
assert len(repo.log())
assert not os.path.exists('/tmp/testgit.git/hooks/update')
assert not os.path.exists('/tmp/testgit.git/hooks/post-receive-user')
@@ -172,6 +174,24 @@
self.assertIn('exec $DIR/post-receive-user\n', c)
shutil.rmtree(dirname)
+ @mock.patch('forgegit.model.git_repo.g.post_event')
+ @mock.patch('forgegit.model.git_repo.traceback')
+ def test_clone_from_posts_event_on_failure(self, traceback, post_event):
+ fake_source_url = 'fake_source_url'
+ fake_traceback = 'fake_traceback'
+ traceback.format_exc.return_value = fake_traceback
+ repo = GM.Repository(
+ name='testgit.git',
+ fs_path='/tmp/',
+ url_path = '/test/',
+ tool = 'git',
+ status = 'creating')
+ try:
+ repo._impl.clone_from(fake_source_url)
+ except:
+ pass
+ post_event.assert_any_call('repo_clone_failed', fake_source_url, fake_traceback)
+
def test_index(self):
i = self.repo.index()
assert i['type_s'] == 'Git Repository', i
diff --git a/ForgeHg/forgehg/model/hg.py b/ForgeHg/forgehg/model/hg.py
index 0212b4d..7e00971 100644
--- a/ForgeHg/forgehg/model/hg.py
+++ b/ForgeHg/forgehg/model/hg.py
@@ -2,6 +2,7 @@
import re
import shutil
import logging
+import traceback
from binascii import b2a_hex
from datetime import datetime
from cStringIO import StringIO
@@ -94,11 +95,12 @@
self.__dict__['_hg'] = repo
self._setup_special_files(source_url)
except:
+ g.post_event('repo_clone_failed', source_url, traceback.format_exc())
self._repo.status = 'raise'
session(self._repo).flush(self._repo)
raise
log.info('... %r cloned', self._repo)
- g.post_event('repo_cloned')
+ g.post_event('repo_cloned', source_url)
self._repo.refresh(notify=False)
def commit(self, rev):
diff --git a/ForgeHg/forgehg/tests/model/test_repository.py b/ForgeHg/forgehg/tests/model/test_repository.py
index c88a406..ddedac2 100644
--- a/ForgeHg/forgehg/tests/model/test_repository.py
+++ b/ForgeHg/forgehg/tests/model/test_repository.py
@@ -143,7 +143,8 @@
assert not os.path.exists('/tmp/testrepo.hg/.hg/undo.branch')
shutil.rmtree(dirname)
- def test_clone(self):
+ @mock.patch('forgehg.model.hg.g.post_event')
+ def test_clone(self, post_event):
repo = HM.Repository(
name='testrepo.hg',
fs_path='/tmp/',
@@ -157,6 +158,7 @@
shutil.rmtree(dirname)
repo.init()
repo._impl.clone_from(repo_path)
+ post_event.assert_any_call('repo_cloned', repo_path)
assert len(repo.log())
assert not os.path.exists('/tmp/testrepo.hg/.hg/external-changegroup')
assert not os.path.exists('/tmp/testrepo.hg/.hg/nested/nested-file')
@@ -171,6 +173,24 @@
assert not os.path.exists('/tmp/testrepo.hg/.hg/undo.branch')
shutil.rmtree(dirname)
+ @mock.patch('forgehg.model.hg.g.post_event')
+ @mock.patch('forgehg.model.hg.traceback')
+ def test_clone_from_posts_event_on_failure(self, traceback, post_event):
+ fake_source_url = 'fake_source_url'
+ fake_traceback = 'fake_traceback'
+ traceback.format_exc.return_value = fake_traceback
+ repo = HM.Repository(
+ name='testrepo.hg',
+ fs_path='/tmp/',
+ url_path = '/test/',
+ tool = 'hg',
+ status = 'creating')
+ try:
+ repo._impl.clone_from(fake_source_url)
+ except:
+ pass
+ post_event.assert_any_call('repo_clone_failed', fake_source_url, fake_traceback)
+
def test_index(self):
i = self.repo.index()
assert i['type_s'] == 'Hg Repository', i
diff --git a/ForgeSVN/forgesvn/model/svn.py b/ForgeSVN/forgesvn/model/svn.py
index e8173d8..85b4670 100644
--- a/ForgeSVN/forgesvn/model/svn.py
+++ b/ForgeSVN/forgesvn/model/svn.py
@@ -169,6 +169,7 @@
p = Popen(cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
stdout, stderr = p.communicate(input='p\n')
if p.returncode != 0:
+ g.post_event('repo_clone_failed', source_url, stderr)
self._repo.status = 'ready'
session(self._repo).flush(self._repo)
raise SVNCalledProcessError(cmd, p.returncode, stdout, stderr)
@@ -186,7 +187,7 @@
c.app.config.options['checkout_url'])):
c.app.config.options['checkout_url'] = ""
self._setup_special_files(source_url)
- g.post_event('repo_cloned')
+ g.post_event('repo_cloned', source_url)
self._repo.refresh(notify=False)
def refresh_heads(self):
diff --git a/ForgeSVN/forgesvn/tests/model/test_repository.py b/ForgeSVN/forgesvn/tests/model/test_repository.py
index 9e9270c..d317b70 100644
--- a/ForgeSVN/forgesvn/tests/model/test_repository.py
+++ b/ForgeSVN/forgesvn/tests/model/test_repository.py
@@ -144,7 +144,8 @@
self.assertIn('exec $DIR/post-commit-user "$@"\n', c)
shutil.rmtree(dirname)
- def test_clone(self):
+ @mock.patch('forgesvn.model.svn.g.post_event')
+ def test_clone(self, post_event):
repo = SM.Repository(
name='testsvn',
fs_path='/tmp/',
@@ -158,6 +159,7 @@
shutil.rmtree(dirname)
repo.init()
repo._impl.clone_from('file://' + repo_path)
+ post_event.assert_any_call('repo_cloned', 'file://' + repo_path)
assert len(repo.log())
assert os.path.exists('/tmp/testsvn/hooks/pre-revprop-change')
assert os.access('/tmp/testsvn/hooks/pre-revprop-change', os.X_OK)
@@ -172,6 +174,26 @@
self.assertIn('exec $DIR/post-commit-user "$@"\n', c)
shutil.rmtree(dirname)
+ @mock.patch('forgesvn.model.svn.g.post_event')
+ @mock.patch('forgesvn.model.svn.Popen')
+ def test_clone_from_posts_event_on_failure(self, popen, post_event):
+ fake_source_url = 'fake_source_url'
+ fake_traceback = 'fake_traceback'
+ popen_mock = mock.Mock(returncode=1)
+ popen_mock.communicate.return_value = '', fake_traceback
+ popen.return_value = popen_mock
+ repo = SM.Repository(
+ name='testsvn',
+ fs_path='/tmp/',
+ url_path = '/test/',
+ tool = 'svn',
+ status = 'creating')
+ try:
+ repo._impl.clone_from(fake_source_url)
+ except:
+ pass
+ post_event.assert_any_call('repo_clone_failed', fake_source_url, fake_traceback)
+
def test_index(self):
i = self.repo.index()
assert i['type_s'] == 'SVN Repository', i