← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~wgrant/turnip/api-diff-merge into lp:turnip

 

William Grant has proposed merging lp:~wgrant/turnip/api-diff-merge into lp:turnip.

Commit message:
Add an API to preview a merge diff. 

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)

For more details, see:
https://code.launchpad.net/~wgrant/turnip/api-diff-merge/+merge/256599

Add an API to get a merge diff. No prereq support yet, but that'll look something like /compare-merge/{base}/{prereq}/{head}.
-- 
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~wgrant/turnip/api-diff-merge into lp:turnip.
=== modified file 'turnip/api/store.py'
--- turnip/api/store.py	2015-04-16 16:51:43 +0000
+++ turnip/api/store.py	2015-04-16 22:18:24 +0000
@@ -130,6 +130,23 @@
     return get_diff(repo_path, common_ancestor, sha1_source, context_lines)
 
 
+def get_merge_diff(repo_path, sha1_base, sha1_head, context_lines=3):
+    """Get diff of common ancestor and source diff.
+
+    :param sha1_base: target sha1 for merge.
+    :param sha1_head: source sha1 for merge.
+    :param context_lines: num unchanged lines that define a hunk boundary.
+    """
+    repo = open_repo(repo_path)
+    merged_index = repo.merge_commits(sha1_base, sha1_head)
+    diff = merged_index.diff_to_tree(
+        repo[sha1_base].tree, context_lines=context_lines).patch
+    shas = [sha1_base, sha1_head]
+    commits = [get_commit(repo_path, sha, repo) for sha in shas]
+    diff = {'commits': commits, 'patch': diff}
+    return diff
+
+
 def get_diff(repo_path, sha1_from, sha1_to, context_lines=3):
     """Get patch and associated commits of two sha1s.
 

=== modified file 'turnip/api/tests/test_api.py'
--- turnip/api/tests/test_api.py	2015-04-16 19:15:23 +0000
+++ turnip/api/tests/test_api.py	2015-04-16 22:18:24 +0000
@@ -238,6 +238,22 @@
         self.assertIn('+baz', resp.json_body['patch'])
         self.assertNotIn('+corge', resp.json_body['patch'])
 
+    def test_repo_diff_merge(self):
+        """Ensure expected changes exist in diff patch."""
+        repo = RepoFactory(self.repo_store)
+        c1 = repo.add_commit('foo\nbar\nbaz\n', 'blah.txt')
+        c2_right = repo.add_commit('quux\nbar\nbaz\n', 'blah.txt', parents=[c1])
+        c3_right = repo.add_commit('quux\nbar\nbaz\n', 'blah.txt', parents=[c2_right])
+        c2_left = repo.add_commit('foo\nbar\nbar\n', 'blah.txt', parents=[c1])
+        c3_left = repo.add_commit('foo\nbar\nbar\n', 'blah.txt', parents=[c2_left])
+
+        resp = self.app.get('/repo/{}/compare-merge/{}/{}'.format(
+            self.repo_path, c3_right, c3_left))
+        self.assertIn(' quux', resp.json_body['patch'])
+        self.assertIn('-baz', resp.json_body['patch'])
+        self.assertIn('+bar', resp.json_body['patch'])
+        self.assertNotIn('foo', resp.json_body['patch'])
+
     def test_repo_get_commit(self):
         factory = RepoFactory(self.repo_store)
         message = 'Computers make me angry.'

=== modified file 'turnip/api/views.py'
--- turnip/api/views.py	2015-04-16 16:51:43 +0000
+++ turnip/api/views.py	2015-04-16 22:18:24 +0000
@@ -144,6 +144,30 @@
         return patch
 
 
+@resource(path='/repo/{name}/compare-merge/{base}/{head}')
+class DiffMergeAPI(BaseAPI):
+    """Provides an HTTP API for merge previews.
+
+    {head} will be merged into {base} and the diff from {base} returned.
+    """
+    def __init__(self, request):
+        super(DiffMergeAPI, self).__init__()
+        self.request = request
+
+    @repo_path
+    def get(self, repo_path):
+        """Returns diff of two commits."""
+        context_lines = int(self.request.params.get('context_lines', 3))
+        try:
+            patch = store.get_merge_diff(
+                repo_path, self.request.matchdict['base'],
+                self.request.matchdict['head'], context_lines)
+        except (ValueError, GitError):
+            # invalid pygit2 sha1's return ValueError: 1: Ambiguous lookup
+            return exc.HTTPNotFound()
+        return patch
+
+
 @resource(collection_path='/repo/{name}/commits',
           path='/repo/{name}/commits/{sha1}')
 class CommitAPI(BaseAPI):


Follow ups