Merge lp:~ursinha/uci-engine/ts-add-mp-support into lp:uci-engine

Proposed by Ursula Junque
Status: Merged
Approved by: Ursula Junque
Approved revision: 494
Merged at revision: 508
Proposed branch: lp:~ursinha/uci-engine/ts-add-mp-support
Merge into: lp:uci-engine
Diff against target: 329 lines (+234/-15)
3 files modified
ticket_system/ticket/migrations/0002_uce0.py (+110/-0)
ticket_system/ticket/models.py (+42/-2)
ticket_system/ticket/tests/test_models.py (+82/-13)
To merge this branch: bzr merge lp:~ursinha/uci-engine/ts-add-mp-support
Reviewer Review Type Date Requested Status
Andy Doan (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Chris Johnston (community) Needs Information
Review via email: mp+220275@code.launchpad.net

Commit message

This branch adds Merge Proposals to the Ticket System.

Description of the change

This branch adds Merge Proposals to the Ticket System.

To post a comment you must log in.
Revision history for this message
Chris Johnston (cjohnston) :
Revision history for this message
Ursula Junque (ursinha) :
Revision history for this message
Chris Johnston (cjohnston) :
review: Needs Fixing
Revision history for this message
Chris Johnston (cjohnston) :
review: Needs Information
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

FAILED: Continuous integration, rev:492
No commit message was specified in the merge proposal. Click on the following link and set the commit message (if you want a jenkins rebuild you need to trigger it yourself):
https://code.launchpad.net/~ursinha/uci-engine/ts-add-mp-support/+merge/220275/+edit-commit-message

http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/694/
Executed test runs:

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/694/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Ursula Junque (ursinha) :
Revision history for this message
Ursula Junque (ursinha) :
Revision history for this message
Andy Doan (doanac) wrote :

two largely bike-shedding comments. feel free to ignore.

Revision history for this message
Chris Johnston (cjohnston) :
Revision history for this message
Ursula Junque (ursinha) :
493. By Ursula Junque

Removing max_length from IntegerField

494. By Ursula Junque

merging trunk for the last time

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :

PASSED: Continuous integration, rev:494
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/696/
Executed test runs:

Click here to trigger a rebuild:
http://s-jenkins.ubuntu-ci:8080/job/uci-engine-ci/696/rebuild

review: Approve (continuous-integration)
Revision history for this message
Andy Doan (doanac) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'ticket_system/ticket/migrations/0002_uce0.py'
2--- ticket_system/ticket/migrations/0002_uce0.py 1970-01-01 00:00:00 +0000
3+++ ticket_system/ticket/migrations/0002_uce0.py 2014-05-26 08:30:26 +0000
4@@ -0,0 +1,110 @@
5+# -*- coding: utf-8 -*-
6+import datetime
7+from south.db import db
8+from south.v2 import SchemaMigration
9+from django.db import models
10+
11+
12+class Migration(SchemaMigration):
13+
14+ def forwards(self, orm):
15+ # Adding model 'MergeProposal'
16+ db.create_table('mergeproposal', (
17+ (u'id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
18+ ('project', self.gf('django.db.models.fields.CharField')(max_length=4096)),
19+ ('lp_url', self.gf('django.db.models.fields.CharField')(max_length=4096)),
20+ ('target_branch', self.gf('django.db.models.fields.CharField')(max_length=4096)),
21+ ('approved_revno', self.gf('django.db.models.fields.IntegerField')()),
22+ ('sourcepackage', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['project.SourcePackage'])),
23+ ('version', self.gf('django.db.models.fields.CharField')(max_length=4096)),
24+ ))
25+ db.send_create_signal(u'ticket', ['MergeProposal'])
26+
27+ # Adding field 'SubTicket.merge_proposal'
28+ db.add_column('subticket', 'merge_proposal',
29+ self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['ticket.MergeProposal'], null=True, blank=True),
30+ keep_default=False)
31+
32+
33+ # Changing field 'SubTicket.source_package_upload'
34+ db.alter_column('subticket', 'source_package_upload_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['ticket.SourcePackageUpload'], null=True))
35+
36+ def backwards(self, orm):
37+ # Deleting model 'MergeProposal'
38+ db.delete_table('mergeproposal')
39+
40+ # Deleting field 'SubTicket.merge_proposal'
41+ db.delete_column('subticket', 'merge_proposal_id')
42+
43+
44+ # Changing field 'SubTicket.source_package_upload'
45+ db.alter_column('subticket', 'source_package_upload_id', self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['ticket.SourcePackageUpload']))
46+
47+ models = {
48+ u'project.sourcepackage': {
49+ 'Meta': {'object_name': 'SourcePackage', 'db_table': "'sourcepackage'"},
50+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
51+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '4096'})
52+ },
53+ u'ticket.mergeproposal': {
54+ 'Meta': {'object_name': 'MergeProposal', 'db_table': "'mergeproposal'"},
55+ 'approved_revno': ('django.db.models.fields.IntegerField', [], {}),
56+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
57+ 'lp_url': ('django.db.models.fields.CharField', [], {'max_length': '4096'}),
58+ 'project': ('django.db.models.fields.CharField', [], {'max_length': '4096'}),
59+ 'sourcepackage': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['project.SourcePackage']"}),
60+ 'target_branch': ('django.db.models.fields.CharField', [], {'max_length': '4096'}),
61+ 'version': ('django.db.models.fields.CharField', [], {'max_length': '4096'})
62+ },
63+ u'ticket.sourcepackageupload': {
64+ 'Meta': {'object_name': 'SourcePackageUpload', 'db_table': "'sourcepackageupload'"},
65+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
66+ 'sourcepackage': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['project.SourcePackage']"}),
67+ 'version': ('django.db.models.fields.CharField', [], {'max_length': '4096'})
68+ },
69+ u'ticket.subticket': {
70+ 'Meta': {'object_name': 'SubTicket', 'db_table': "'subticket'"},
71+ 'assignee': ('django.db.models.fields.EmailField', [], {'max_length': '254'}),
72+ 'current_workflow_step': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}),
73+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
74+ 'merge_proposal': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['ticket.MergeProposal']", 'null': 'True', 'blank': 'True'}),
75+ 'source_package_upload': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['ticket.SourcePackageUpload']", 'null': 'True', 'blank': 'True'}),
76+ 'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}),
77+ 'ticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.Ticket']"})
78+ },
79+ u'ticket.subticketartifact': {
80+ 'Meta': {'object_name': 'SubTicketArtifact', 'db_table': "'subticket_artifact'"},
81+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
82+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096'}),
83+ 'reference': ('django.db.models.fields.CharField', [], {'max_length': '4096'}),
84+ 'subticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.SubTicket']", 'null': 'True'}),
85+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '4096'})
86+ },
87+ u'ticket.ticket': {
88+ 'Meta': {'object_name': 'Ticket', 'db_table': "'ticket'"},
89+ 'added_binaries': ('django.db.models.fields.CharField', [], {'max_length': '4096', 'null': 'True', 'blank': 'True'}),
90+ 'base_image': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4096'}),
91+ 'bug_id': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
92+ 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
93+ 'current_workflow_step': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}),
94+ 'description': ('django.db.models.fields.TextField', [], {}),
95+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
96+ 'master_ppa': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4096'}),
97+ 'owner': ('django.db.models.fields.EmailField', [], {'max_length': '254'}),
98+ 'removed_binaries': ('django.db.models.fields.CharField', [], {'max_length': '4096', 'null': 'True', 'blank': 'True'}),
99+ 'series': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4096'}),
100+ 'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}),
101+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '4096'}),
102+ 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
103+ },
104+ u'ticket.ticketartifact': {
105+ 'Meta': {'object_name': 'TicketArtifact', 'db_table': "'ticket_artifact'"},
106+ u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
107+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096'}),
108+ 'reference': ('django.db.models.fields.CharField', [], {'max_length': '4096'}),
109+ 'ticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.Ticket']", 'null': 'True'}),
110+ 'type': ('django.db.models.fields.CharField', [], {'max_length': '4096'})
111+ }
112+ }
113+
114+ complete_apps = ['ticket']
115\ No newline at end of file
116
117=== modified file 'ticket_system/ticket/models.py'
118--- ticket_system/ticket/models.py 2014-05-22 14:48:56 +0000
119+++ ticket_system/ticket/models.py 2014-05-26 08:30:26 +0000
120@@ -123,6 +123,28 @@
121 return "{} {}".format(self.sourcepackage, self.version)
122
123
124+class MergeProposal(models.Model):
125+ class Meta:
126+ db_table = 'mergeproposal'
127+
128+ project = models.CharField(max_length=4096)
129+ lp_url = models.CharField(max_length=4096)
130+ target_branch = models.CharField(max_length=4096)
131+ approved_revno = models.IntegerField()
132+ # All branches submitted to ci-airline will result on a package, so
133+ # will have a debian packaging dir with the latest version.
134+ sourcepackage = models.ForeignKey(SourcePackage)
135+ version = models.CharField(max_length=4096)
136+
137+ def __unicode__(self):
138+ return "{} {}".format(self.project, self.lp_url, self.sourcepackage,
139+ self.version)
140+
141+ @property
142+ def proposed_branch(self):
143+ return "lp:{}".format(self.lp_url.split("/+merge")[0])
144+
145+
146 class SubTicket(models.Model):
147 class Meta:
148 db_table = 'subticket'
149@@ -135,10 +157,28 @@
150 default=000)
151 ticket = models.ForeignKey(Ticket)
152 assignee = models.EmailField(max_length=254)
153- source_package_upload = models.ForeignKey(SourcePackageUpload)
154+ source_package_upload = models.ForeignKey(SourcePackageUpload, null=True,
155+ blank=True, default=None)
156+ merge_proposal = models.ForeignKey(MergeProposal, null=True, blank=True,
157+ default=None)
158+
159+ def save(self, *args, **kwargs):
160+ if self.source_package_upload and self.merge_proposal:
161+ raise IntegrityError("Subtickets only accept a source package "
162+ "upload or a merge proposal at a time, you "
163+ "provided both.")
164+ elif not self.source_package_upload and not self.merge_proposal:
165+ raise IntegrityError("A subticket requires at least one source "
166+ "package upload or one merge proposal, you "
167+ "provided neither.")
168+ super(SubTicket, self).save(*args, **kwargs)
169
170 def __unicode__(self):
171- return "{} {}".format(self.ticket, self.source_package_upload)
172+ if self.source_package_upload:
173+ target = self.source_package_upload
174+ else:
175+ target = self.merge_proposal
176+ return "{} {}".format(self.ticket, target)
177
178
179 class ArtifactBase(models.Model):
180
181=== modified file 'ticket_system/ticket/tests/test_models.py'
182--- ticket_system/ticket/tests/test_models.py 2014-05-16 19:16:57 +0000
183+++ ticket_system/ticket/tests/test_models.py 2014-05-26 08:30:26 +0000
184@@ -19,9 +19,10 @@
185 from django.test import TestCase
186 from project.models import SourcePackage
187 from ticket.models import (TicketArtifact, SubTicketArtifact, SubTicket,
188- SourcePackageUpload, SubTicketWorkflowStep,
189- SubTicketWorkflowStepStatus, Ticket,
190- TicketWorkflowStep, TicketWorkflowStepStatus)
191+ SourcePackageUpload, MergeProposal,
192+ SubTicketWorkflowStep, SubTicketWorkflowStepStatus,
193+ Ticket, TicketWorkflowStep,
194+ TicketWorkflowStepStatus)
195
196
197 def create_sourcepackage(name='my-package'):
198@@ -39,6 +40,21 @@
199 return spu
200
201
202+def create_merge_proposal(project='my-project', sourcepackage='my-package',
203+ lp_url='~foobar/my-project/my-branch/+merge/123456',
204+ target_branch='lp:~foobar/my-project/trunk',
205+ approved_revno=100, version='1.1'):
206+ merge_proposal = MergeProposal()
207+ merge_proposal.project = project
208+ merge_proposal.sourcepackage = sourcepackage
209+ merge_proposal.lp_url = lp_url
210+ merge_proposal.version = version
211+ merge_proposal.target_branch = target_branch
212+ merge_proposal.approved_revno = approved_revno
213+ merge_proposal.save()
214+ return merge_proposal
215+
216+
217 def create_ticket(title="This is my ticket",
218 description="this is my ticket description",
219 bug_id='12345', owner='test@example.com',
220@@ -65,13 +81,15 @@
221 def create_subticket(current_workflow_step=SubTicketWorkflowStep.PKG_BUILDING,
222 ticket=None, status=(
223 SubTicketWorkflowStepStatus.PKG_BUILDING_INPROGRESS),
224- assignee='test@example.com', source_package_upload=None):
225+ assignee='test@example.com', source_package_upload=None,
226+ merge_proposal=None):
227 subticket = SubTicket()
228 subticket.current_workflow_step = current_workflow_step
229 subticket.status = status
230 subticket.ticket = ticket
231 subticket.assignee = assignee
232 subticket.source_package_upload = source_package_upload
233+ subticket.merge_proposal = merge_proposal
234 subticket.save()
235 return subticket
236
237@@ -100,13 +118,15 @@
238 self.sourcepackage = create_sourcepackage()
239 self.spu = create_sourcepackageupload(
240 sourcepackage=self.sourcepackage)
241+ self.mp = create_merge_proposal(sourcepackage=self.sourcepackage)
242 self.ticket = create_ticket(owner='test@example.com')
243- self.subticket = create_subticket(ticket=self.ticket,
244- assignee='test@example.com',
245- source_package_upload=self.spu)
246
247 def test_creating_an_artifact_subticket(self):
248- self.artifact_1 = create_subticketartifact(subticket=self.subticket)
249+ subticket = create_subticket(ticket=self.ticket,
250+ assignee='test@example.com',
251+ source_package_upload=self.spu)
252+
253+ self.artifact_1 = create_subticketartifact(subticket=subticket)
254 artifact_in_database = SubTicketArtifact.objects.exclude(
255 subticket=None)
256 self.assertEquals(len(artifact_in_database), 1)
257@@ -135,11 +155,46 @@
258 self.assertEquals(only_ticket_in_database.added_binaries, "foo,bar")
259 self.assertEquals(only_ticket_in_database.removed_binaries, "baz")
260
261- def test_creating_a_subticket(self):
262- subticket_in_database = SubTicket.objects.all()
263- self.assertEquals(len(subticket_in_database), 1)
264- only_subticket_in_database = subticket_in_database[0]
265- self.assertEquals(only_subticket_in_database, self.subticket)
266+ def test_creating_a_subticket_with_spu(self):
267+ subticket = create_subticket(ticket=self.ticket,
268+ assignee='test@example.com',
269+ source_package_upload=self.spu)
270+ subticket_in_database = SubTicket.objects.all()
271+ self.assertEquals(len(subticket_in_database), 1)
272+ only_subticket_in_database = subticket_in_database[0]
273+ self.assertEquals(only_subticket_in_database, subticket)
274+
275+ self.assertEquals(only_subticket_in_database.assignee,
276+ "test@example.com")
277+
278+ def test_creating_a_subticket_with_spu_and_mp(self):
279+ with self.assertRaises(IntegrityError) as cm:
280+ create_subticket(ticket=self.ticket, assignee='test@example.com',
281+ source_package_upload=self.spu,
282+ merge_proposal=self.mp)
283+ self.assertEquals(cm.exception.args[0], "Subtickets only accept a "
284+ "source package upload or a merge proposal at a "
285+ "time, you provided both.")
286+ subticket_in_database = SubTicket.objects.all()
287+ self.assertEquals(len(subticket_in_database), 0)
288+
289+ def test_creating_a_subticket_with_no_spu_or_mp(self):
290+ with self.assertRaises(IntegrityError) as cm:
291+ create_subticket(ticket=self.ticket, assignee='test@example.com')
292+ self.assertEquals(cm.exception.args[0], "A subticket requires at "
293+ "least one source package upload or one merge "
294+ "proposal, you provided neither.")
295+ subticket_in_database = SubTicket.objects.all()
296+ self.assertEquals(len(subticket_in_database), 0)
297+
298+ def test_creating_a_subticket_with_mp(self):
299+ subticket = create_subticket(ticket=self.ticket,
300+ assignee='test@example.com',
301+ merge_proposal=self.mp)
302+ subticket_in_database = SubTicket.objects.all()
303+ self.assertEquals(len(subticket_in_database), 1)
304+ only_subticket_in_database = subticket_in_database[0]
305+ self.assertEquals(only_subticket_in_database, subticket)
306
307 self.assertEquals(only_subticket_in_database.assignee,
308 "test@example.com")
309@@ -153,6 +208,20 @@
310 self.assertEquals(only_spu_in_database.sourcepackage.name,
311 "my-package")
312
313+ def test_creating_a_mergeproposal(self):
314+ mp_in_database = MergeProposal.objects.all()
315+ self.assertEquals(len(mp_in_database), 1)
316+ only_mp_in_database = mp_in_database[0]
317+ self.assertEquals(only_mp_in_database, self.mp)
318+
319+ self.assertEquals(only_mp_in_database.project, "my-project")
320+ self.assertEquals(only_mp_in_database.lp_url,
321+ "~foobar/my-project/my-branch/+merge/123456")
322+ self.assertEquals(only_mp_in_database.target_branch,
323+ "lp:~foobar/my-project/trunk")
324+ self.assertEquals(only_mp_in_database.proposed_branch,
325+ "lp:~foobar/my-project/my-branch")
326+
327 def test_added_binary_list_invalid(self):
328 added_binaries = "foo bar"
329 self.assertRaises(IntegrityError, create_ticket,

Subscribers

People subscribed via source and target branches