[#7882] ticket:783 Option to use a tmp dir for git ops on merge request view
diff --git a/Allura/development.ini b/Allura/development.ini
index baf479d..d5a12f4 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -301,6 +301,10 @@
scm.merge.git.disabled = false
scm.merge.hg.disabled = false
+; Merge request viewing will fetch git info into existing git repositories. On
+; deployments where writes in existing git repos are unwanted, clone to tmp dir
+; can be used.
+;scm.merge_list.git.use_tmp_dir = true
; 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
diff --git a/ForgeGit/forgegit/model/git_repo.py b/ForgeGit/forgegit/model/git_repo.py
index aeb5734..bb3b8d8 100644
--- a/ForgeGit/forgegit/model/git_repo.py
+++ b/ForgeGit/forgegit/model/git_repo.py
@@ -21,6 +21,7 @@
import logging
import tempfile
from datetime import datetime
+from contextlib import contextmanager
import tg
import git
@@ -631,6 +632,14 @@
'total': total,
}
+ @contextmanager
+ def _shared_clone(self, from_path):
+ tmp_path = tempfile.mkdtemp()
+ self._git.git.clone('--bare', '--shared', from_path, tmp_path)
+ tmp_repo = GitImplementation(Object(full_fs_path=tmp_path))
+ yield tmp_repo
+ shutil.rmtree(tmp_path, ignore_errors=True)
+
def merge_base(self, mr):
g = self._git.git
g.fetch(mr.app.repo.full_fs_path, mr.target_branch)
@@ -642,11 +651,20 @@
Must be called within mr.push_downstream_context()
"""
- base = self.merge_base(mr)
- return list(c.app.repo.log(
- mr.downstream.commit_id,
- exclude=base,
- id_only=False))
+ use_tmp_dir = tg.config.get('scm.merge_list.git.use_tmp_dir', False)
+ use_tmp_dir = asbool(use_tmp_dir)
+ if not use_tmp_dir:
+ base = self.merge_base(mr)
+ return list(c.app.repo.log(
+ mr.downstream.commit_id,
+ exclude=base,
+ id_only=False))
+ with self._shared_clone(self._repo.full_fs_path) as tmp_repo:
+ base = tmp_repo.merge_base(mr)
+ return list(tmp_repo.log(
+ [mr.downstream.commit_id],
+ exclude=[base],
+ id_only=False))
class _OpenedGitBlob(object):
diff --git a/ForgeGit/forgegit/tests/model/test_repository.py b/ForgeGit/forgegit/tests/model/test_repository.py
index e516f35..936fbee 100644
--- a/ForgeGit/forgegit/tests/model/test_repository.py
+++ b/ForgeGit/forgegit/tests/model/test_repository.py
@@ -143,6 +143,14 @@
ThreadLocalORMSession.flush_all()
ThreadLocalORMSession.close_all()
+ @property
+ def merge_request(self):
+ cid = '5c47243c8e424136fd5cdd18cd94d34c66d1955c'
+ return M.MergeRequest(
+ downstream={'commit_id': cid},
+ source_branch='zz',
+ target_branch='master')
+
def test_init(self):
repo = GM.Repository(
name='testgit.git',
@@ -686,25 +694,11 @@
assert_equals(diffs, expected)
def test_merge_base(self):
- mr = M.MergeRequest(
- downstream={
- 'commit_id': '5c47243c8e424136fd5cdd18cd94d34c66d1955c',
- },
- source_branch='zz',
- target_branch='master',
- )
- res = self.repo._impl.merge_base(mr)
+ res = self.repo._impl.merge_base(self.merge_request)
assert_equal(res, '1e146e67985dcd71c74de79613719bef7bddca4a')
def test_merge_request_commits(self):
- mr = M.MergeRequest(
- downstream={
- 'commit_id': '5c47243c8e424136fd5cdd18cd94d34c66d1955c',
- },
- source_branch='zz',
- target_branch='master',
- )
- res = self.repo.merge_request_commits(mr)
+ res = self.repo.merge_request_commits(self.merge_request)
expected = [
{'authored': {
'date': datetime.datetime(2013, 3, 28, 18, 54, 16),
@@ -722,6 +716,18 @@
'size': None}]
assert_equals(res, expected)
+ def test_merge_request_commits_tmp_dir(self):
+ """
+ repo.merge_request_commits should return the same result with and
+ without scm.merge_list.git.use_tmp_dir option enabled
+ """
+ mr = self.merge_request
+ res_without_tmp = self.repo.merge_request_commits(mr)
+ opt = {'scm.merge_list.git.use_tmp_dir': True}
+ with h.push_config(tg.config, **opt):
+ res_with_tmp = self.repo.merge_request_commits(mr)
+ assert_equals(res_without_tmp, res_with_tmp)
+
class TestGitImplementation(unittest.TestCase):