You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@allura.apache.org by he...@apache.org on 2015/04/01 23:10:31 UTC
[14/45] allura git commit: [#7830] ticket:729 One-click merge for git
[#7830] ticket:729 One-click merge for git
Project: http://git-wip-us.apache.org/repos/asf/allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/allura/commit/121ebed7
Tree: http://git-wip-us.apache.org/repos/asf/allura/tree/121ebed7
Diff: http://git-wip-us.apache.org/repos/asf/allura/diff/121ebed7
Branch: refs/heads/hss/7072
Commit: 121ebed71e8395f3a436bbecc88d180f0e3b7108
Parents: 9c06caf
Author: Igor Bondarenko <je...@gmail.com>
Authored: Wed Feb 18 17:00:27 2015 +0000
Committer: Dave Brondsema <db...@slashdotmedia.com>
Committed: Fri Mar 20 20:40:29 2015 +0000
----------------------------------------------------------------------
Allura/allura/controllers/repository.py | 13 ++++++++
Allura/allura/model/repository.py | 24 +++++++++++++++
Allura/allura/templates/repo/merge_request.html | 26 ++++++++++++++++
ForgeGit/forgegit/model/git_repo.py | 32 ++++++++++++++++++++
4 files changed, 95 insertions(+)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/allura/blob/121ebed7/Allura/allura/controllers/repository.py
----------------------------------------------------------------------
diff --git a/Allura/allura/controllers/repository.py b/Allura/allura/controllers/repository.py
index a3c1541..78bff44 100644
--- a/Allura/allura/controllers/repository.py
+++ b/Allura/allura/controllers/repository.py
@@ -441,6 +441,19 @@ class MergeRequestController(object):
self.req.status = status
redirect('.')
+ @expose()
+ @require_post()
+ def merge(self):
+ require_access(c.app, 'write')
+ if self.req.status != 'open' or not self.req.can_merge():
+ raise exc.HTTPNotFound
+ ok = self.req.merge()
+ if ok:
+ flash('Merged successfully', 'ok')
+ else:
+ flash('Merge failed. Please, merge manually', 'error')
+ redirect(self.req.url())
+
class RefsController(object):
http://git-wip-us.apache.org/repos/asf/allura/blob/121ebed7/Allura/allura/model/repository.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/repository.py b/Allura/allura/model/repository.py
index 0030aa5..5e4a171 100644
--- a/Allura/allura/model/repository.py
+++ b/Allura/allura/model/repository.py
@@ -805,6 +805,30 @@ class MergeRequest(VersionedArtifact, ActivityObject):
self.request_number, self.project.name, self.app.repo.name))
return result
+ def can_merge(self):
+ if not self.app.forkable:
+ return False
+ try:
+ result = self.app.repo.can_merge(self)
+ except:
+ log.exception(
+ "Can't determine if merge request %s can be merged",
+ self.url())
+ return False
+ return result
+
+ def merge(self):
+ if not self.app.forkable:
+ return False
+ try:
+ self.app.repo.merge(self)
+ except:
+ log.exception("Can't merge merge request %s", self.url())
+ return False
+ self.status = 'merged'
+ session(self).flush(self)
+ return True
+
# Basic commit information
# One of these for each commit in the physical repo on disk. The _id is the
http://git-wip-us.apache.org/repos/asf/allura/blob/121ebed7/Allura/allura/templates/repo/merge_request.html
----------------------------------------------------------------------
diff --git a/Allura/allura/templates/repo/merge_request.html b/Allura/allura/templates/repo/merge_request.html
index 3c79654..060b5b9 100644
--- a/Allura/allura/templates/repo/merge_request.html
+++ b/Allura/allura/templates/repo/merge_request.html
@@ -44,6 +44,25 @@ Merge Request #{{req.request_number}}: {{req.summary}} ({{req.status}})
<div>{{g.markdown.convert(req.description)}}</div>
+ {% if req.status == 'open' and c.app.forkable and h.has_access(c.app, 'write')() %}
+ {% set can_merge = req.can_merge() %}
+ <div class="grid-19">
+ <form action="merge" method="POST">
+ {{ lib.csrf_token() }}
+ <input type="submit" value="Merge"{% if not can_merge %}disabled="disabled"{% endif %}>
+ {% if can_merge %}
+ <div class="merge-ok">
+ Merge request has no conflicts. You can merge automatically.
+ </div>
+ {% else %}
+ <div class="merge-conflicts">
+ Merge request has conflicts. Follow manual instructions below to merge.
+ </div>
+ {% endif %}
+ </form>
+ </div>
+ {% endif %}
+
{{ c.log_widget.display(value=req.commits, app=downstream_app) }}
<div class="grid-19"><a href="#discussion_holder">Discuss</a></div>
@@ -87,3 +106,10 @@ Merge Request #{{req.request_number}}: {{req.summary}} ({{req.status}})
count=count)}}
</div>
{% endblock %}
+
+{% block extra_css %}
+<style type="text/css">
+ .merge-ok { color: green; }
+ .merge-conflicts { color: red; }
+</style>
+{% endblock %}
http://git-wip-us.apache.org/repos/asf/allura/blob/121ebed7/ForgeGit/forgegit/model/git_repo.py
----------------------------------------------------------------------
diff --git a/ForgeGit/forgegit/model/git_repo.py b/ForgeGit/forgegit/model/git_repo.py
index 7fda67a..831da5b 100644
--- a/ForgeGit/forgegit/model/git_repo.py
+++ b/ForgeGit/forgegit/model/git_repo.py
@@ -19,6 +19,7 @@ import os
import shutil
import string
import logging
+import tempfile
from datetime import datetime
import tg
@@ -95,6 +96,37 @@ class Repository(M.Repository):
merge_request.downstream.commit_id,
)
+ def can_merge(self, mr):
+ """
+ Given merge request `mr` determine if it can be merged w/o conflicts.
+ """
+ g = self._impl._git.git
+ # http://stackoverflow.com/a/6283843
+ # fetch source branch
+ g.fetch(mr.downstream_repo_url, mr.source_branch)
+ # find merge base
+ merge_base = g.merge_base(mr.downstream.commit_id, mr.target_branch)
+ # print out merge result, but don't actually touch anything
+ merge_tree = g.merge_tree(
+ merge_base, mr.target_branch, mr.downstream.commit_id)
+ return '+<<<<<<<' not in merge_tree
+
+ def merge(self, mr):
+ g = self._impl._git.git
+ # can't merge in bare repo, so need to clone
+ tmp_path = tempfile.mkdtemp()
+ tmp_repo = git.Repo.clone_from(
+ self.clone_url('rw'),
+ to_path=tmp_path,
+ bare=False)
+ tmp_repo = GitImplementation(Object(full_fs_path=tmp_path))._git
+ tmp_repo.git.fetch('origin', mr.target_branch)
+ tmp_repo.git.checkout(mr.target_branch)
+ tmp_repo.git.fetch(mr.downstream_repo_url, mr.source_branch)
+ tmp_repo.git.merge(mr.downstream.commit_id)
+ tmp_repo.git.push('origin', mr.target_branch)
+ shutil.rmtree(tmp_path, ignore_errors=True)
+
def rev_to_commit_id(self, rev):
return self._impl.rev_parse(rev).hexsha