Merge lp:~cjwatson/turnip/default-branch into lp:turnip

Proposed by Colin Watson
Status: Merged
Merged at revision: 159
Proposed branch: lp:~cjwatson/turnip/default-branch
Merge into: lp:turnip
Diff against target: 123 lines (+84/-0)
3 files modified
turnip/api/store.py (+10/-0)
turnip/api/tests/test_api.py (+39/-0)
turnip/api/views.py (+35/-0)
To merge this branch: bzr merge lp:~cjwatson/turnip/default-branch
Reviewer Review Type Date Requested Status
William Grant code Approve
Review via email: mp+259493@code.launchpad.net

Commit message

Add GET and PATCH methods to RepoAPI to allow getting and setting the default branch (a.k.a. "HEAD").

Description of the change

Add GET and PATCH methods to RepoAPI to allow getting and setting the default branch (a.k.a. "HEAD").

To post a comment you must log in.
Revision history for this message
William Grant (wgrant) :
review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'turnip/api/store.py'
2--- turnip/api/store.py 2015-04-30 19:26:04 +0000
3+++ turnip/api/store.py 2015-05-19 12:55:50 +0000
4@@ -157,6 +157,16 @@
5 yield Repository(repo_path)
6
7
8+def get_default_branch(repo_path):
9+ repo = Repository(repo_path)
10+ return repo.lookup_reference('HEAD').target
11+
12+
13+def set_default_branch(repo_path, target):
14+ repo = Repository(repo_path)
15+ repo.set_head(target)
16+
17+
18 def delete_repo(repo_path):
19 """Permanently delete a git repository from repo store."""
20 shutil.rmtree(repo_path)
21
22=== modified file 'turnip/api/tests/test_api.py'
23--- turnip/api/tests/test_api.py 2015-04-30 19:26:04 +0000
24+++ turnip/api/tests/test_api.py 2015-05-19 12:55:50 +0000
25@@ -35,6 +35,11 @@
26 self.commit = {'ref': 'refs/heads/master', 'message': 'test commit.'}
27 self.tag = {'ref': 'refs/tags/tag0', 'message': 'tag message'}
28
29+ def assertReferencesEqual(self, repo, expected, observed):
30+ self.assertEqual(
31+ repo.lookup_reference(expected).peel().oid,
32+ repo.lookup_reference(observed).peel().oid)
33+
34 def get_ref(self, ref):
35 resp = self.app.get('/repo/{}/{}'.format(self.repo_path, ref))
36 return resp.json
37@@ -74,6 +79,40 @@
38 self.assertEqual(200, resp.status_code)
39 self.assertIn(new_repo_path, resp.json['repo_url'])
40
41+ def test_repo_get(self):
42+ """The GET method on a repository returns its properties."""
43+ factory = RepoFactory(self.repo_store, num_branches=2, num_commits=1)
44+ factory.build()
45+ factory.repo.set_head('refs/heads/branch-0')
46+
47+ resp = self.app.get('/repo/{}'.format(self.repo_path))
48+ self.assertEqual(200, resp.status_code)
49+ self.assertEqual({'default_branch': 'refs/heads/branch-0'}, resp.json)
50+
51+ def test_repo_get_default_branch_missing(self):
52+ """default_branch is returned even if that branch has been deleted."""
53+ factory = RepoFactory(self.repo_store, num_branches=2, num_commits=1)
54+ factory.build()
55+ factory.repo.set_head('refs/heads/branch-0')
56+ factory.repo.lookup_reference('refs/heads/branch-0').delete()
57+
58+ resp = self.app.get('/repo/{}'.format(self.repo_path))
59+ self.assertEqual(200, resp.status_code)
60+ self.assertEqual({'default_branch': 'refs/heads/branch-0'}, resp.json)
61+
62+ def test_repo_patch_default_branch(self):
63+ """A repository's default branch ("HEAD") can be changed."""
64+ factory = RepoFactory(self.repo_store, num_branches=2, num_commits=1)
65+ factory.build()
66+ factory.repo.set_head('refs/heads/branch-0')
67+ self.assertReferencesEqual(factory.repo, 'refs/heads/branch-0', 'HEAD')
68+
69+ resp = self.app.patch_json(
70+ '/repo/{}'.format(self.repo_path),
71+ {'default_branch': 'refs/heads/branch-1'})
72+ self.assertEqual(204, resp.status_code)
73+ self.assertReferencesEqual(factory.repo, 'refs/heads/branch-1', 'HEAD')
74+
75 def test_cross_repo_merge_diff(self):
76 """Merge diff can be requested across 2 repositories."""
77 factory = RepoFactory(self.repo_store)
78
79=== modified file 'turnip/api/views.py'
80--- turnip/api/views.py 2015-04-29 04:42:05 +0000
81+++ turnip/api/views.py 2015-05-19 12:55:50 +0000
82@@ -79,6 +79,41 @@
83 return exc.HTTPConflict() # 409
84
85 @validate_path
86+ def get(self, repo_store, repo_name):
87+ """Get properties of an existing git repository."""
88+ repo_path = os.path.join(repo_store, repo_name)
89+ if not os.path.exists(repo_path):
90+ self.request.errors.add(
91+ 'body', 'name', 'repository does not exist')
92+ raise exc.HTTPNotFound()
93+ return {
94+ 'default_branch': store.get_default_branch(repo_path),
95+ }
96+
97+ def _patch_default_branch(self, repo_path, value):
98+ try:
99+ store.set_default_branch(repo_path, value)
100+ except (KeyError, ValueError, GitError):
101+ raise exc.HTTPBadRequest()
102+
103+ @validate_path
104+ def patch(self, repo_store, repo_name):
105+ """Change properties of an existing git repository."""
106+ repo_path = os.path.join(repo_store, repo_name)
107+ if not os.path.exists(repo_path):
108+ self.request.errors.add(
109+ 'body', 'name', 'repository does not exist')
110+ raise exc.HTTPNotFound()
111+ data = extract_json_data(self.request)
112+ for key in data:
113+ if not hasattr(self, "_patch_%s" % key):
114+ self.request.errors.add('body', key, 'unknown property')
115+ raise exc.HTTPBadRequest()
116+ for key, value in data.items():
117+ getattr(self, "_patch_%s" % key)(repo_path, value)
118+ return exc.HTTPNoContent()
119+
120+ @validate_path
121 def delete(self, repo_store, repo_name):
122 """Delete an existing git repository."""
123 try:

Subscribers

People subscribed via source and target branches

to all changes: