Merge lp:~ricardokirkner/locolander/add-author into lp:locolander

Proposed by Ricardo Kirkner
Status: Merged
Approved by: Ricardo Kirkner
Approved revision: 24
Merged at revision: 19
Proposed branch: lp:~ricardokirkner/locolander/add-author
Merge into: lp:locolander
Prerequisite: lp:~ricardokirkner/locolander/celery-stack
Diff against target: 291 lines (+159/-26)
7 files modified
locolander/locolanderweb/admin.py (+8/-0)
locolander/locolanderweb/migrations/0004_auto__add_field_mergerequest_author.py (+87/-0)
locolander/locolanderweb/models.py (+1/-0)
locolander/locolanderweb/tests/test_base.py (+5/-2)
locolander/locolanderweb/tests/test_models.py (+5/-1)
locolander/repos/launchpad.py (+11/-0)
locolander/repos/tests/test_launchpad.py (+42/-23)
To merge this branch: bzr merge lp:~ricardokirkner/locolander/add-author
Reviewer Review Type Date Requested Status
Natalia Bidart Approve
Review via email: mp+174570@code.launchpad.net

Commit message

added author to MergeRequest model

To post a comment you must log in.
20. By Ricardo Kirkner

expose locolanderweb models in admin

Revision history for this message
Natalia Bidart (nataliabidart) wrote :

Changes for the new author field looks good, but there seem to be a mixup in the diff since the next branch has 0 diff lines, and this one includes all the celery tasks things.

review: Needs Fixing
21. By Ricardo Kirkner

merged trunk

22. By Ricardo Kirkner

regenerated migration

Revision history for this message
Natalia Bidart (nataliabidart) wrote :

Code looks good! One detail: in a branch of mine you made me remove the datetime(created.year, created.month, created.day) to avoid loosing the precision from mp.date_created, any reason for you to revert that?

Leaving my approve vote, if you think the mp.date_created is a merge error, please revert before landing.

review: Approve
Revision history for this message
Ricardo Kirkner (ricardokirkner) wrote :

> Code looks good! One detail: in a branch of mine you made me remove the
> datetime(created.year, created.month, created.day) to avoid loosing the
> precision from mp.date_created, any reason for you to revert that?
>
> Leaving my approve vote, if you think the mp.date_created is a merge error,
> please revert before landing.

It is an artifact from my pre-merged branch. Fixed, thanks!

23. By Ricardo Kirkner

merged trunk

24. By Ricardo Kirkner

reverted unwanted changes

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'locolander/locolanderweb/admin.py'
2--- locolander/locolanderweb/admin.py 1970-01-01 00:00:00 +0000
3+++ locolander/locolanderweb/admin.py 2013-07-20 18:17:23 +0000
4@@ -0,0 +1,8 @@
5+from django.contrib import admin
6+
7+from locolanderweb.models import MergeRequest, Project, RunLog
8+
9+
10+admin.site.register(Project)
11+admin.site.register(MergeRequest)
12+admin.site.register(RunLog)
13
14=== added file 'locolander/locolanderweb/migrations/0004_auto__add_field_mergerequest_author.py'
15--- locolander/locolanderweb/migrations/0004_auto__add_field_mergerequest_author.py 1970-01-01 00:00:00 +0000
16+++ locolander/locolanderweb/migrations/0004_auto__add_field_mergerequest_author.py 2013-07-20 18:17:23 +0000
17@@ -0,0 +1,87 @@
18+# -*- coding: utf-8 -*-
19+from south.db import db
20+from south.v2 import SchemaMigration
21+
22+
23+class Migration(SchemaMigration):
24+
25+ def forwards(self, orm):
26+ # Adding field 'MergeRequest.author'
27+ db.add_column(u'locolanderweb_mergerequest', 'author',
28+ self.gf('django.db.models.fields.TextField')(default=''),
29+ keep_default=False)
30+
31+
32+ def backwards(self, orm):
33+ # Deleting field 'MergeRequest.author'
34+ db.delete_column(u'locolanderweb_mergerequest', 'author')
35+
36+
37+ models = {
38+ u'auth.group': {
39+ 'Meta': {'object_name': 'Group'},
40+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
41+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
42+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
43+ },
44+ u'auth.permission': {
45+ 'Meta': {'ordering': "(u'content_type__app_label', u'content_type__model', u'codename')", 'unique_together': "((u'content_type', u'codename'),)", 'object_name': 'Permission'},
46+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
47+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
48+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
49+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
50+ },
51+ u'auth.user': {
52+ 'Meta': {'object_name': 'User'},
53+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
54+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
55+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
56+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
57+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
58+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
59+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
60+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
61+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
62+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
63+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
64+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': u"orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
65+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
66+ },
67+ u'contenttypes.contenttype': {
68+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
69+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
70+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
71+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
72+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
73+ },
74+ u'locolanderweb.mergerequest': {
75+ 'Meta': {'object_name': 'MergeRequest'},
76+ 'author': ('django.db.models.fields.TextField', [], {'default': "''"}),
77+ 'commit_message': ('django.db.models.fields.TextField', [], {}),
78+ 'date_completed': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
79+ 'date_created': ('django.db.models.fields.DateTimeField', [], {}),
80+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
81+ 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['locolanderweb.Project']"}),
82+ 'reviewers': ('django.db.models.fields.TextField', [], {}),
83+ 'source': ('django.db.models.fields.TextField', [], {}),
84+ 'status': ('django.db.models.fields.CharField', [], {'default': "'pending'", 'max_length': '128'}),
85+ 'target': ('django.db.models.fields.TextField', [], {})
86+ },
87+ u'locolanderweb.project': {
88+ 'Meta': {'object_name': 'Project'},
89+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
90+ 'name': ('django.db.models.fields.TextField', [], {}),
91+ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['auth.User']"}),
92+ 'url': ('django.db.models.fields.CharField', [], {'max_length': '256'})
93+ },
94+ u'locolanderweb.runlog': {
95+ 'Meta': {'object_name': 'RunLog'},
96+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
97+ 'merge_request': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['locolanderweb.MergeRequest']"}),
98+ 'raw': ('django.db.models.fields.TextField', [], {}),
99+ 'return_code': ('django.db.models.fields.IntegerField', [], {}),
100+ 'timestamp': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.utcnow'})
101+ }
102+ }
103+
104+ complete_apps = ['locolanderweb']
105
106=== modified file 'locolander/locolanderweb/models.py'
107--- locolander/locolanderweb/models.py 2013-07-06 23:19:29 +0000
108+++ locolander/locolanderweb/models.py 2013-07-20 18:17:23 +0000
109@@ -55,6 +55,7 @@
110 source = models.TextField()
111 target = models.TextField()
112 commit_message = models.TextField()
113+ author = models.TextField(default='')
114 reviewers = models.TextField()
115 date_created = models.DateTimeField()
116 date_completed = models.DateTimeField(null=True, blank=True)
117
118=== modified file 'locolander/locolanderweb/tests/test_base.py'
119--- locolander/locolanderweb/tests/test_base.py 2013-07-06 23:19:29 +0000
120+++ locolander/locolanderweb/tests/test_base.py 2013-07-20 18:17:23 +0000
121@@ -46,7 +46,8 @@
122 def make_merge_request(
123 self, project=None, status=STATUS_PENDING,
124 source=None, target=None, commit_message=None,
125- reviewers=None, date_created=None, date_completed=None):
126+ author=None, reviewers=None, date_created=None,
127+ date_completed=None):
128 if project is None:
129 project = self.make_project()
130 if source is None:
131@@ -55,13 +56,15 @@
132 target = 'http://foo.target'
133 if commit_message is None:
134 commit_message = 'Foo bar commit message.'
135+ if author is None:
136+ author = 'Some Person <some@domain>'
137 if reviewers is None:
138 reviewers = ['mengano', 'fulano']
139 if date_created is None:
140 date_created = datetime.utcnow()
141 return MergeRequest.objects.create(
142 project=project, status=status, source=source, target=target,
143- commit_message=commit_message, reviewers=reviewers,
144+ commit_message=commit_message, author=author, reviewers=reviewers,
145 date_created=date_created, date_completed=date_completed)
146
147 def make_run_log(self, merge_request=None, return_code=0, raw=None):
148
149=== modified file 'locolander/locolanderweb/tests/test_models.py'
150--- locolander/locolanderweb/tests/test_models.py 2013-07-13 16:00:06 +0000
151+++ locolander/locolanderweb/tests/test_models.py 2013-07-20 18:17:23 +0000
152@@ -120,7 +120,8 @@
153 self.obj = MergeRequest.objects.create(
154 project=self.project,
155 source='source', target='target', commit_message='commit',
156- reviewers='fulano, mengano', date_created=self.created)
157+ author='Some Person <some@domain>', reviewers='fulano, mengano',
158+ date_created=self.created)
159
160 def test_status_default(self):
161 self.assertEqual(self.obj.status, STATUS_PENDING)
162@@ -139,6 +140,9 @@
163 def test_commit_message(self):
164 self.assertEqual(self.obj.commit_message, 'commit')
165
166+ def test_author(self):
167+ self.assertEqual(self.obj.author, 'Some Person <some@domain>')
168+
169 def test_reviewers(self):
170 self.assertEqual(self.obj.reviewers, 'fulano, mengano')
171
172
173=== modified file 'locolander/repos/launchpad.py'
174--- locolander/repos/launchpad.py 2013-07-13 16:00:06 +0000
175+++ locolander/repos/launchpad.py 2013-07-20 18:17:23 +0000
176@@ -5,6 +5,8 @@
177 import os
178 import re
179
180+import bzrlib.plugin
181+from bzrlib.branch import Branch
182 from launchpadlib.launchpad import Launchpad
183
184 from repos import errors
185@@ -29,6 +31,14 @@
186 self.launchpad = Launchpad.login_anonymously(
187 'locolander', 'production', CACHE_DIR)
188 self.lp_projects = self.launchpad.projects
189+ # load bzr plugins so that lp: namespace is recognized
190+ bzrlib.plugin.load_plugins()
191+
192+ def get_author(self, branch_url):
193+ branch = Branch.open(branch_url)
194+ tip = branch.repository.get_revision(
195+ branch.get_rev_id(branch.revno()))
196+ return tip.committer
197
198 def approved_requests_for_project_url(self, project_url):
199 """Return approved merge proposals."""
200@@ -56,5 +66,6 @@
201 'target': mp.target_branch.bzr_identity,
202 'reviewers': mp.reviewer.name, # csv
203 'commit_message': mp.commit_message,
204+ 'author': self.get_author(mp.source_branch.bzr_identity),
205 })
206 return approved
207
208=== modified file 'locolander/repos/tests/test_launchpad.py'
209--- locolander/repos/tests/test_launchpad.py 2013-07-06 22:26:19 +0000
210+++ locolander/repos/tests/test_launchpad.py 2013-07-20 18:17:23 +0000
211@@ -3,11 +3,16 @@
212 from datetime import datetime
213 from unittest import TestCase
214
215+import bzrlib.branch
216 from mock import Mock, patch
217
218 from repos import errors, launchpad
219
220
221+# fake bzrlib Branch object
222+FakeBranch = Mock(spec=bzrlib.branch.Branch)
223+
224+
225 class FakeMP(object):
226 """Fake launchpadlib Merge Proposal object."""
227
228@@ -71,26 +76,40 @@
229 with self.assertRaises(errors.RepositoryDoesNotExist):
230 self.lp.approved_requests_for_project_url('lp:not-found')
231
232- def test_valid_project_without_approved_mp(self):
233- mps = self.lp.approved_requests_for_project_url('lp:test-project')
234- self.assertEqual(len(mps), 1)
235- mp = mps[0]
236- self.assertIsInstance(mp, dict)
237-
238- expected_keys = ['date_created', 'source', 'target', 'reviewers',
239- 'commit_message']
240- for key in expected_keys:
241- self.assertIn(key, mp)
242- self.assertEqual(mp['commit_message'], 'approved mp')
243-
244- def test_valid_project_return_approved_mp(self):
245- mps = self.lp.approved_requests_for_project_url('lp:test-project')
246- self.assertEqual(len(mps), 1)
247- mp = mps[0]
248- self.assertIsInstance(mp, dict)
249-
250- expected_keys = ['date_created', 'source', 'target', 'reviewers',
251- 'commit_message']
252- for key in expected_keys:
253- self.assertIn(key, mp)
254- self.assertEqual(mp['commit_message'], 'approved mp')
255+ @patch('repos.launchpad.Branch.open')
256+ def test_valid_project_without_approved_mp(self, mock_open):
257+ mps = self.lp.approved_requests_for_project_url('lp:test-project')
258+ self.assertEqual(len(mps), 1)
259+ mp = mps[0]
260+ self.assertIsInstance(mp, dict)
261+
262+ expected_keys = ['date_created', 'source', 'target', 'reviewers',
263+ 'commit_message', 'author']
264+ for key in expected_keys:
265+ self.assertIn(key, mp)
266+ self.assertEqual(mp['commit_message'], 'approved mp')
267+
268+ @patch('repos.launchpad.Branch.open')
269+ def test_valid_project_return_approved_mp(self, mock_open):
270+ mps = self.lp.approved_requests_for_project_url('lp:test-project')
271+ self.assertEqual(len(mps), 1)
272+ mp = mps[0]
273+ self.assertIsInstance(mp, dict)
274+
275+ expected_keys = ['date_created', 'source', 'target', 'reviewers',
276+ 'commit_message', 'author']
277+ for key in expected_keys:
278+ self.assertIn(key, mp)
279+ self.assertEqual(mp['commit_message'], 'approved mp')
280+
281+ @patch('repos.launchpad.Branch.open')
282+ def test_get_author(self, mock_open):
283+ mock_revision = Mock()
284+ mock_revision.committer = 'The Author <some@email.com>'
285+ mock_repository = Mock()
286+ mock_repository.get_revision.return_value = mock_revision
287+ mock_open.return_value.repository = mock_repository
288+
289+ author = self.lp.get_author('lp:test-project')
290+
291+ self.assertEqual(author, 'The Author <some@email.com>')

Subscribers

People subscribed via source and target branches

to all changes: