Merge lp:~joetalbott/uci-engine/owner_split into lp:uci-engine
- owner_split
- Merge into trunk
Status: | Rejected |
---|---|
Rejected by: | Joe Talbott |
Proposed branch: | lp:~joetalbott/uci-engine/owner_split |
Merge into: | lp:uci-engine |
Diff against target: |
780 lines (+364/-37) 14 files modified
cli/ci_cli/tests/test_cli.py (+79/-17) cli/ci_cli/tests/test_ticket.py (+15/-9) cli/ci_cli/ticket.py (+10/-4) cli/ubuntu-ci (+26/-2) docs/api/initial-request.rst (+1/-1) docs/usage.rst (+4/-2) ticket_system/ticket/api.py (+1/-0) ticket_system/ticket/migrations/0008_auto__add_field_ticket_creator__chg_field_ticket_owner.py (+111/-0) ticket_system/ticket/migrations/0009_add_creator.py (+103/-0) ticket_system/ticket/models.py (+2/-1) ticket_system/ticket/tests/test_full_read_api.py (+1/-0) ticket_system/ticket/tests/test_models.py (+4/-1) ticket_system/ticket/tests/test_read_api.py (+5/-0) ticket_system/ticket/tests/test_write_api.py (+2/-0) |
To merge this branch: | bzr merge lp:~joetalbott/uci-engine/owner_split |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot (community) | continuous-integration | Approve | |
Ursula Junque (community) | Needs Information | ||
Paul Larson | Needs Information | ||
Review via email: mp+230378@code.launchpad.net |
Commit message
ticket-system - Split owner role into owner and creator.
* -c/--creator is now a required parameter to ubuntu-ci and -o/--owner is optional.
if no owner is specified the creator value is used for owner as well.
Description of the change
ticket-system - Split owner role into owner and creator.
* -c/--creator is now a required parameter to ubuntu-ci and -o/--owner is optional.
if no owner is specified the creator value is used for owner as well.
- 742. By Joe Talbott
-
Fix typo
PS Jenkins bot (ps-jenkins) wrote : | # |
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:742
http://
Executed test runs:
Click here to trigger a rebuild:
http://
Could you please update the docs to reflect this as well?
- 743. By Joe Talbott
-
ticket-system - Update docs to reflect new owner/creator split.
- 744. By Joe Talbott
-
cli - Update tests to match new owner/creator split.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:744
http://
Executed test runs:
Click here to trigger a rebuild:
http://
- 745. By Joe Talbott
-
merge with trunk
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:745
http://
Executed test runs:
Click here to trigger a rebuild:
http://
- 746. By Joe Talbott
-
cli - Fix owner/creator logic when updating tickets.
* for new tickets we'll have args.creator
* for existing tickets we'll have args.owner
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:746
http://
Executed test runs:
Click here to trigger a rebuild:
http://
Paul Larson (pwlars) wrote : | # |
Can you also add a line in the docs to say why we even have this? I'm not sure I understand the use case for a different creator and owner. Also, why would we not preserve backwards compatibility with just specifying -o? We could probably change this to say if either one is specified (but not the other) then they are assumed to be the same, right?
Ursula Junque (ursinha) wrote : | # |
I think owner is more important than creator, because the owner is the person/team you want to notify whenever the ticket has changed or requires input (like citrain spreadsheet "Lander"). This way I'd invert the logic and allow the creator to be optional, while the owner (or "lander") is required.
I agree with Paul that the way it's now it's not clear why to split these, is there a use case where you see creator being more important than owner?
- 747. By Joe Talbott
-
cli - when creating a ticket accept an owner or creator or both
At least one is required when creating a ticket.
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:747
http://
Executed test runs:
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:747
http://
Executed test runs:
Click here to trigger a rebuild:
http://
Joe Talbott (joetalbott) wrote : | # |
Paul and Ursula,
I've updated the MP to allow either of owner or creator to be provided individually or together. If only one is provided it's used for the other. If neither is provided a parser error is raised. I think keeping track of the ticket submitter (creator) is important and am on the fence as to whether only supplying the owner should set the creator.
Celso Providelo (cprov) wrote : | # |
Joe,
On the other hand, once we have authentication, the creator can be obtained implicitly from self.request.
I would consider a minimum-impact path, by populating "creator" with the already provided "owner" in Ticket.save(), so zero changes in the CLI (after all we don't want user foo creating tickets as bar). That would carry us safely to the point where we have authenticated requests implemented to extend tastypie views accordingly.
Ursula Junque (ursinha) wrote : | # |
> Joe,
>
> On the other hand, once we have authentication, the creator can be obtained
> implicitly from self.request.
> reference}.
>
> I would consider a minimum-impact path, by populating "creator" with the
> already provided "owner" in Ticket.save(), so zero changes in the CLI (after
> all we don't want user foo creating tickets as bar). That would carry us
> safely to the point where we have authenticated requests implemented to extend
> tastypie views accordingly.
Just to keep in mind: the reason to have an owner is to annotate the relevant people to be notified about ticket changes, and it's possible that more than one person needs to be notified. We still haven't defined how to notify, if using an IRC bot (then we would need this to be populated with one or more IRC nicks), or else, so assuming the owner is the same as the creator (LP username or email) might need to be changed in a near future.
Joe Talbott (joetalbott) wrote : | # |
I'm going to reject this MP and submit a new one based on our conversation today.
Unmerged revisions
- 747. By Joe Talbott
-
cli - when creating a ticket accept an owner or creator or both
At least one is required when creating a ticket.
- 746. By Joe Talbott
-
cli - Fix owner/creator logic when updating tickets.
* for new tickets we'll have args.creator
* for existing tickets we'll have args.owner - 745. By Joe Talbott
-
merge with trunk
- 744. By Joe Talbott
-
cli - Update tests to match new owner/creator split.
- 743. By Joe Talbott
-
ticket-system - Update docs to reflect new owner/creator split.
- 742. By Joe Talbott
-
Fix typo
- 741. By Joe Talbott
-
ticket-system - Split owner role into owner/creator roles.
Preview Diff
1 | === modified file 'cli/ci_cli/tests/test_cli.py' |
2 | --- cli/ci_cli/tests/test_cli.py 2014-08-12 23:55:22 +0000 |
3 | +++ cli/ci_cli/tests/test_cli.py 2014-08-21 13:48:34 +0000 |
4 | @@ -54,6 +54,7 @@ |
5 | "title": "My cool feature", |
6 | "id": '5', |
7 | "description": "my new feature", |
8 | + "creator": "user@example.com", |
9 | "owner": "user@example.com", |
10 | "created": "Wed, 12 Mar 2014 02:18:28 +0000", |
11 | "updated": "Wed, 12 Mar 2014 02:30:22 +0000", |
12 | @@ -128,7 +129,7 @@ |
13 | 'create_ticket', |
14 | '-t', 'New feature', |
15 | '-b', '4321', |
16 | - '-o', 'someone@example.com', |
17 | + '-c', 'someone@example.com', |
18 | '-d', 'This is a cool new feature', |
19 | '-s', changes_1, |
20 | '-s', changes_2, |
21 | @@ -150,7 +151,7 @@ |
22 | changes_2 = get_test_file_path( |
23 | 'foobar-unsupported_0.1-1ubuntu1_source.changes') |
24 | |
25 | - args = ['create_ticket', '-t', '"New feature"', '-b', '4321', '-o', |
26 | + args = ['create_ticket', '-t', '"New feature"', '-b', '4321', '-c', |
27 | 'someone@example.com', '-d', '"This is a cool new feature"', |
28 | '-s', changes_1, '-s', changes_2] |
29 | |
30 | @@ -274,6 +275,65 @@ |
31 | 'create_ticket', |
32 | '-t', 'New feature', |
33 | '-d', 'New feature description', |
34 | + '-c', 'someone@example.com', |
35 | + '-s', foobar_changes, |
36 | + ] |
37 | + with LogCapture() as lc: |
38 | + logger = logging.getLogger() |
39 | + self.cli.main(args, log=logger) |
40 | + ticket_url = urlparse.urljoin( |
41 | + utils.CI_URL, '/ticket.html?ticket_id=1') |
42 | + # The first output line contains a local absolute host path, so |
43 | + # it is ignored. |
44 | + self.assertEquals( |
45 | + ['Parsing foobar_0.1-1_source.changes...', |
46 | + 'Validating .changes...', |
47 | + 'foobar_0.1-1 parsed and validated.', |
48 | + 'Created source package upload: http://mocked/api/v1/ticket/1/', |
49 | + 'Created subticket: http://mocked/api/v1/ticket/1/', |
50 | + 'Uploading foobar_0.1-1.dsc ...', |
51 | + 'Uploading foobar_0.1.orig.tar.gz ...', |
52 | + 'Uploading foobar_0.1-1.debian.tar.gz ...', |
53 | + 'Uploading foobar_0.1-1_source.changes ...', |
54 | + 'Done! Access {} for more information.'.format(ticket_url), |
55 | + 'Created artifact: http://mocked/api/v1/ticket/1/', |
56 | + 'Created artifact: http://mocked/api/v1/ticket/1/', |
57 | + 'Created artifact: http://mocked/api/v1/ticket/1/', |
58 | + 'Created artifact: http://mocked/api/v1/ticket/1/'], |
59 | + list([r.msg for r in lc.records])) |
60 | + |
61 | + @mock.patch('ci_cli.utils.post', |
62 | + return_value='http://mocked/api/v1/ticket/1/') |
63 | + @mock.patch('ci_cli.utils.get') |
64 | + @mock.patch('ci_cli.utils.patch') |
65 | + @mock.patch('ci_cli.ticket._open_file') |
66 | + @mock.patch('requests.put') |
67 | + @mock.patch('requests.post') |
68 | + def test_create_ticket_with_owner(self, mocked_post, mocked_put, mocked_of, |
69 | + mocked_upa, mocked_ug, mocked_upo): |
70 | + # CLI 'create_ticket' action allows users to upload new sources |
71 | + # via gatekeeper (without swift credentials). |
72 | + mocked_post.side_effect = [ |
73 | + FakeResponse(201, '/ticket/1/sandbox/UUID'), |
74 | + FakeResponse(201, '/ticket.html?ticket_id=1'), |
75 | + ] |
76 | + mocked_put.side_effect = [ |
77 | + FakeResponse(200, 'A_TEMP_URL'), |
78 | + FakeResponse(201, '/a_sandbox_object_url/'), |
79 | + FakeResponse(200, 'A_TEMP_URL'), |
80 | + FakeResponse(201, '/a_sandbox_object_url/'), |
81 | + FakeResponse(200, 'A_TEMP_URL'), |
82 | + FakeResponse(201, '/a_sandbox_object_url/'), |
83 | + FakeResponse(200, 'A_TEMP_URL'), |
84 | + FakeResponse(201, '/a_sandbox_object_url/'), |
85 | + ] |
86 | + mocked_of.return_value = 'a_content' |
87 | + foobar_changes = get_test_file_path('foobar_0.1-1_source.changes') |
88 | + args = [ |
89 | + '-v2', |
90 | + 'create_ticket', |
91 | + '-t', 'New feature', |
92 | + '-d', 'New feature description', |
93 | '-o', 'someone@example.com', |
94 | '-s', foobar_changes, |
95 | ] |
96 | @@ -334,7 +394,7 @@ |
97 | 'create_ticket', |
98 | '-t', 'New feature', |
99 | '-d', 'New feature description', |
100 | - '-o', 'someone@example.com', |
101 | + '-c', 'someone@example.com', |
102 | '-s', foobar_changes, |
103 | ] |
104 | mocked_patch.side_effect = [ |
105 | @@ -397,31 +457,33 @@ |
106 | with capture_stderr(self.assertRaises, SystemExit, self.cli.main, |
107 | args) as cm: |
108 | self.assertNotEqual(cm, None) |
109 | - self.assertTrue(expected_msg in cm) |
110 | + self.assertTrue(expected_msg in cm, "cm: {}, expected_msg: {}".format( |
111 | + cm, expected_msg)) |
112 | |
113 | def test_cli_arguments_are_required(self): |
114 | """Verify cli arguments are required.""" |
115 | args = ['create_ticket'] |
116 | self._test_parser_missing_arguments( |
117 | args, "create_ticket: error: argument -t/--title is required") |
118 | - |
119 | args.extend(['-t', '"New feature"']) |
120 | + |
121 | self._test_parser_missing_arguments( |
122 | args, |
123 | "create_ticket: error: argument -d/--description is required") |
124 | - |
125 | args.extend(['-d', '"This is a cool new feature"']) |
126 | - self._test_parser_missing_arguments( |
127 | - args, "create_ticket: error: argument -o/--owner is required") |
128 | - |
129 | - args.extend(['-o', 'someone@example.com']) |
130 | |
131 | self._test_parser_missing_arguments( |
132 | args, "create_ticket: error: argument -s/--sources is required") |
133 | + args.extend(['-s', 'foobar.changesss']) |
134 | + |
135 | + self._test_parser_missing_arguments( |
136 | + args, "error: at least one of the arguments " |
137 | + "-o/--owner or -c/--creator is required") |
138 | + |
139 | + args.extend(['-c', 'someone@example.com']) |
140 | |
141 | # All arguments were provided. It should fail because file is not |
142 | # found. |
143 | - args.extend(['-s', 'foobar.changesss']) |
144 | with LogCapture() as lc: |
145 | logger = logging.getLogger() |
146 | self.cli.main(args, log=logger) |
147 | @@ -432,7 +494,7 @@ |
148 | """Verify cli fails in case file isn't prefixed .changes.""" |
149 | wrong_changes = get_test_file_path('foobar_0.1-1.dsc') |
150 | args = ['create_ticket', '-t', '"New feature"', '-d', |
151 | - '"This is a cool new feature"', '-o', 'someone@example.com', |
152 | + '"This is a cool new feature"', '-c', 'someone@example.com', |
153 | '-s', wrong_changes] |
154 | with LogCapture() as lc: |
155 | logger = logging.getLogger() |
156 | @@ -453,7 +515,7 @@ |
157 | """Verify cli behavior when .changes file is a .dsc.""" |
158 | wrong_changes = get_test_file_path('foobar_0.1-1_dsc.changes') |
159 | args = ['create_ticket', '-t', '"New feature"', '-d', |
160 | - '"This is a cool new feature"', '-o', 'someone@example.com', |
161 | + '"This is a cool new feature"', '-c', 'someone@example.com', |
162 | '-s', wrong_changes] |
163 | with LogCapture() as lc: |
164 | logger = logging.getLogger() |
165 | @@ -470,7 +532,7 @@ |
166 | """Verify cli behavior when provided .changes file isn't a .changes.""" |
167 | wrong_changes = get_test_file_path('foobar_0.1-1_random.changes') |
168 | args = ['create_ticket', '-t', '"New feature"', '-d', |
169 | - '"This is a cool new feature"', '-o', 'someone@example.com', |
170 | + '"This is a cool new feature"', '-c', 'someone@example.com', |
171 | '-s', wrong_changes] |
172 | with LogCapture() as lc: |
173 | logger = logging.getLogger() |
174 | @@ -488,7 +550,7 @@ |
175 | unsigned_changes = get_test_file_path( |
176 | 'foobar_0.1-1_unsigned.changes') |
177 | args = ['create_ticket', '-t', '"New feature"', '-d', |
178 | - '"This is a cool new feature"', '-o', 'someone@example.com', |
179 | + '"This is a cool new feature"', '-c', 'someone@example.com', |
180 | '-s', unsigned_changes] |
181 | with LogCapture() as lc: |
182 | logger = logging.getLogger() |
183 | @@ -507,7 +569,7 @@ |
184 | changes_filename = 'foobar_0.1-1_unreleased.changes' |
185 | wrong_changes = get_test_file_path(changes_filename) |
186 | args = ['create_ticket', '-t', '"New feature"', '-d', |
187 | - '"This is a cool new feature"', '-o', 'someone@example.com', |
188 | + '"This is a cool new feature"', '-c', 'someone@example.com', |
189 | '-s', wrong_changes] |
190 | with LogCapture() as lc: |
191 | logger = logging.getLogger() |
192 | @@ -527,7 +589,7 @@ |
193 | changes_filename = 'foobar-unsupported_0.1-1ubuntu1_source.changes' |
194 | wrong_changes = get_test_file_path(changes_filename) |
195 | args = ['create_ticket', '-t', '"New feature"', '-d', |
196 | - '"This is a cool new feature"', '-o', 'someone@example.com', |
197 | + '"This is a cool new feature"', '-c', 'someone@example.com', |
198 | '-s', wrong_changes] |
199 | with LogCapture() as lc: |
200 | logger = logging.getLogger() |
201 | |
202 | === modified file 'cli/ci_cli/tests/test_ticket.py' |
203 | --- cli/ci_cli/tests/test_ticket.py 2014-08-13 13:13:21 +0000 |
204 | +++ cli/ci_cli/tests/test_ticket.py 2014-08-21 13:48:34 +0000 |
205 | @@ -208,7 +208,8 @@ |
206 | @mock.patch('ci_cli.utils.post', |
207 | return_value='http://www.example.com/api/v1/sourcepackage/4/') |
208 | def test_create_sourcepackage(self, mock_post): |
209 | - new_subticket = SubTicket(owner='foobar@example.com', ticket_id=4) |
210 | + new_subticket = SubTicket(creator='foobar@example.com', |
211 | + owner='foobar@example.com', ticket_id=4) |
212 | with mock.patch('sys.stdout'): |
213 | new_subticket._parse_changes(self.changes) |
214 | sourcepackage_uri = new_subticket._create_sourcepackage() |
215 | @@ -220,7 +221,8 @@ |
216 | @mock.patch('ci_cli.utils.post', |
217 | return_value='http://www.example.com/api/v1/spu/38/') |
218 | def test_create_spu(self, mock_post, mock_sp_uri): |
219 | - new_subticket = SubTicket(owner='foobar@example.com', ticket_id=3) |
220 | + new_subticket = SubTicket(creator='foobar@example.com', |
221 | + owner='foobar@example.com', ticket_id=3) |
222 | with mock.patch('sys.stdout'): |
223 | new_subticket._parse_changes(self.changes) |
224 | new_subticket._create_spu() |
225 | @@ -232,7 +234,8 @@ |
226 | return_value='http://www.example.com/api/v1/spu/39/') |
227 | def test_create_spu_sourcepackage_not_found(self, mock_spu_post, mock_post, |
228 | mock_sp_uri): |
229 | - new_subticket = SubTicket(owner='foobar@example.com', ticket_id=3) |
230 | + new_subticket = SubTicket(creator='foobar@example.com', |
231 | + owner='foobar@example.com', ticket_id=3) |
232 | with mock.patch('sys.stdout'): |
233 | new_subticket._parse_changes(self.changes) |
234 | new_subticket._create_spu() |
235 | @@ -242,7 +245,8 @@ |
236 | return_value='http://www.example.com/api/v1/subticketartifact/38/', |
237 | ) |
238 | def test_create_artifact(self, mock_post): |
239 | - new_subticket = SubTicket(owner='foobar@example.com', ticket_id=2) |
240 | + new_subticket = SubTicket(creator='foobar@example.com', |
241 | + owner='foobar@example.com', ticket_id=2) |
242 | file = 'foobar_source.changes' |
243 | location = 'http://www.example.com/path/to/foobar_source.changes' |
244 | new_subticket._create_artifact(file, location) |
245 | @@ -251,7 +255,8 @@ |
246 | @mock.patch('ci_cli.utils.post', |
247 | return_value='http://www.example.com/api/v1/subticket/1/') |
248 | def test_create_subticket(self, mock_post): |
249 | - new_subticket = SubTicket(owner='foobar@example.com', ticket_id=1) |
250 | + new_subticket = SubTicket(creator='foobar@example.com', |
251 | + owner='foobar@example.com', ticket_id=1) |
252 | new_subticket._create_subticket() |
253 | |
254 | |
255 | @@ -261,7 +266,7 @@ |
256 | return_value='http://www.example.com/api/v1/ticket/38/') |
257 | def test_create_ticket(self, mock_post): |
258 | changes = get_test_file_path('foobar_0.1-1_source.changes') |
259 | - args = ['create_ticket', '-t', 'New feature', '-b', '1234', '-o', |
260 | + args = ['create_ticket', '-t', 'New feature', '-b', '1234', '-c', |
261 | 'someone@example.com', '-d', 'This is a cool new feature', |
262 | '-s', changes] |
263 | |
264 | @@ -280,7 +285,7 @@ |
265 | 'create_ticket', |
266 | '-t', 'New feature', |
267 | '-b', '1234', |
268 | - '-o', 'someone@example.com', |
269 | + '-c', 'someone@example.com', |
270 | '-d', 'This is a cool new feature', |
271 | '-s', changes, |
272 | ] |
273 | @@ -307,7 +312,7 @@ |
274 | 'create_ticket', |
275 | '-t', 'New feature', |
276 | '-b', '1234', |
277 | - '-o', 'someone@example.com', |
278 | + '-c', 'someone@example.com', |
279 | '-d', 'This is a cool new feature', |
280 | '-s', changes, |
281 | '-w' |
282 | @@ -342,6 +347,7 @@ |
283 | '{}/api/v1/ticket/'.format(utils.CI_URL), |
284 | data={ |
285 | 'owner': 'someone@example.com', |
286 | + 'creator': 'someone@example.com', |
287 | 'series': 'trusty', |
288 | 'bug_id': '1234', |
289 | 'description': 'This is a cool new feature', |
290 | @@ -367,7 +373,7 @@ |
291 | 'create_ticket', |
292 | '-t', 'New feature', |
293 | '-b', '4321', |
294 | - '-o', 'someone@example.com', |
295 | + '-c', 'someone@example.com', |
296 | '-d', 'This is a cool new feature', |
297 | '-s', changes_1, |
298 | '-s', changes_2, |
299 | |
300 | === modified file 'cli/ci_cli/ticket.py' |
301 | --- cli/ci_cli/ticket.py 2014-08-18 19:01:55 +0000 |
302 | +++ cli/ci_cli/ticket.py 2014-08-21 13:48:34 +0000 |
303 | @@ -138,8 +138,9 @@ |
304 | |
305 | class SubTicket(): |
306 | |
307 | - def __init__(self, owner, ticket_id=None): |
308 | - self.owner = owner |
309 | + def __init__(self, creator, ticket_id=None, owner=None): |
310 | + self.creator = creator |
311 | + self.owner = owner if owner is not None else creator |
312 | self.ticket_id = ticket_id |
313 | self.sourcepackage = '' |
314 | self.files = '' |
315 | @@ -241,7 +242,8 @@ |
316 | def _create_ticket(self, args): |
317 | data = { |
318 | "title": args.title, |
319 | - "owner": args.owner, |
320 | + "owner": args.owner if args.owner else args.creator, |
321 | + "creator": args.creator if args.creator else args.owner, |
322 | "description": args.description, |
323 | "series": self.suite.split("-")[0], |
324 | "bug_id": args.bug, |
325 | @@ -280,9 +282,13 @@ |
326 | to the same suite. |
327 | """ |
328 | suites = set() |
329 | + if hasattr(args, 'creator'): |
330 | + creator = args.creator |
331 | + else: |
332 | + creator = args.owner |
333 | # First, process all sources and validate the series. |
334 | for source in args.sources: |
335 | - subticket = SubTicket(owner=args.owner) |
336 | + subticket = SubTicket(owner=args.owner, creator=creator) |
337 | subticket._parse_changes(source) |
338 | suites.add(subticket.suite) |
339 | self.subtickets[subticket.sourcepackage] = subticket |
340 | |
341 | === modified file 'cli/ubuntu-ci' |
342 | --- cli/ubuntu-ci 2014-08-14 18:57:54 +0000 |
343 | +++ cli/ubuntu-ci 2014-08-21 13:48:34 +0000 |
344 | @@ -53,8 +53,10 @@ |
345 | help='Ticket description') |
346 | ticket_parser.add_argument('-b', '--bug', |
347 | help='Related bug number') |
348 | - ticket_parser.add_argument('-o', '--owner', required=True, |
349 | + ticket_parser.add_argument('-o', '--owner', |
350 | help='Email address of the ticket owner') |
351 | + ticket_parser.add_argument('-c', '--creator', |
352 | + help='Email address of the ticket creator') |
353 | ticket_parser.add_argument('-s', '--sources', action='append', |
354 | help='Path to source.changes files. ' |
355 | 'Source package files (e.g. source.dsc, ' |
356 | @@ -110,7 +112,29 @@ |
357 | help='Desired file name (and path) for the ' |
358 | 'downloaded image', required=True) |
359 | image_parser.set_defaults(func=image.get_image) |
360 | - return parser.parse_args(args) |
361 | + args = parser.parse_args(args) |
362 | + |
363 | + if not _has_valid_owner_creator(args): |
364 | + parser.error("at least one of the arguments -o/--owner or " |
365 | + "-c/--creator is required") |
366 | + |
367 | + return args |
368 | + |
369 | + |
370 | +def _has_valid_owner_creator(args): |
371 | + if hasattr(args, 'func'): |
372 | + # only certain subcommands need to require an owner/creator |
373 | + if args.func.func_name not in ['new_ticket']: |
374 | + return True |
375 | + |
376 | + if not (hasattr(args, 'owner') or hasattr(args, 'creator')): |
377 | + return False |
378 | + |
379 | + if (hasattr(args, 'owner') and args.owner is None) and ( |
380 | + hasattr(args, 'creator') and args.creator is None): |
381 | + return False |
382 | + |
383 | + return True |
384 | |
385 | |
386 | def set_log_level(logger, loglevel): |
387 | |
388 | === modified file 'docs/api/initial-request.rst' |
389 | --- docs/api/initial-request.rst 2014-08-05 18:14:05 +0000 |
390 | +++ docs/api/initial-request.rst 2014-08-21 13:48:34 +0000 |
391 | @@ -10,7 +10,7 @@ |
392 | |
393 | :: |
394 | |
395 | - python ubuntu-ci create_ticket -t "Ticket name" -d "Ticket description" -b 123 -o user@example.com -s /full/path/to/_source.changes -s /full/path/to/_source.changes |
396 | + python ubuntu-ci create_ticket -t "Ticket name" -d "Ticket description" -b 123 -c user@example.com -s /full/path/to/_source.changes -s /full/path/to/_source.changes |
397 | |
398 | CLI -> Ticket System |
399 | -------------------- |
400 | |
401 | === modified file 'docs/usage.rst' |
402 | --- docs/usage.rst 2014-08-05 18:14:05 +0000 |
403 | +++ docs/usage.rst 2014-08-21 13:48:34 +0000 |
404 | @@ -53,7 +53,7 @@ |
405 | |
406 | .. code-block:: none |
407 | |
408 | - ubuntu-ci [-S|--url] create_ticket -t "Ticket name" -d "Ticket description" -b 123 -o user@example.com -s /full/path/to/_source.changes -s /full/path/to/_source.changes |
409 | + ubuntu-ci [-S|--url] create_ticket -t "Ticket name" -d "Ticket description" -b 123 -c user@example.com -s /full/path/to/_source.changes -s /full/path/to/_source.changes |
410 | |
411 | This returns a ticket ID which can later be used to monitor and check for |
412 | results. Once the ticket is created, the Ubuntu CI Engine does the rest. The |
413 | @@ -86,8 +86,10 @@ |
414 | -d DESCRIPTION, --description DESCRIPTION |
415 | Ticket description |
416 | -b BUG, --bug BUG Related bug number |
417 | + -c CREATOR, --creator CREATOR |
418 | + Email address of the ticket creator |
419 | -o OWNER, --owner OWNER |
420 | - Email address of the ticket owner |
421 | + Email address of the ticket owner (default: CREATOR) |
422 | -s SOURCES, --sources SOURCES |
423 | Path to source.changes files. Source package files |
424 | (e.g. source.dsc, source.orig.tar.gz, etc.) are |
425 | |
426 | === modified file 'ticket_system/ticket/api.py' |
427 | --- ticket_system/ticket/api.py 2014-08-07 20:45:58 +0000 |
428 | +++ ticket_system/ticket/api.py 2014-08-21 13:48:34 +0000 |
429 | @@ -403,6 +403,7 @@ |
430 | return ip |
431 | url = 'http://{}:8080/api/v1/ticket/'.format(ip) |
432 | ticket_content = {"owner": "create@example.com", |
433 | + "creator": "creator@example.com", |
434 | "title": "Created ticket", |
435 | "description": "This ticket is for creation test", |
436 | "bug_id": "111111", |
437 | |
438 | === added file 'ticket_system/ticket/migrations/0008_auto__add_field_ticket_creator__chg_field_ticket_owner.py' |
439 | --- ticket_system/ticket/migrations/0008_auto__add_field_ticket_creator__chg_field_ticket_owner.py 1970-01-01 00:00:00 +0000 |
440 | +++ ticket_system/ticket/migrations/0008_auto__add_field_ticket_creator__chg_field_ticket_owner.py 2014-08-21 13:48:34 +0000 |
441 | @@ -0,0 +1,111 @@ |
442 | +# -*- coding: utf-8 -*- |
443 | +import datetime |
444 | +from south.db import db |
445 | +from south.v2 import SchemaMigration |
446 | +from django.db import models |
447 | + |
448 | + |
449 | +class Migration(SchemaMigration): |
450 | + |
451 | + def forwards(self, orm): |
452 | + # Adding field 'Ticket.creator' |
453 | + db.add_column('ticket', 'creator', |
454 | + self.gf('django.db.models.fields.EmailField')(default='unknown', max_length=4096), |
455 | + keep_default=False) |
456 | + |
457 | + |
458 | + # Changing field 'Ticket.owner' |
459 | + db.alter_column('ticket', 'owner', self.gf('django.db.models.fields.EmailField')(max_length=4096)) |
460 | + |
461 | + def backwards(self, orm): |
462 | + # Deleting field 'Ticket.creator' |
463 | + db.delete_column('ticket', 'creator') |
464 | + |
465 | + |
466 | + # Changing field 'Ticket.owner' |
467 | + db.alter_column('ticket', 'owner', self.gf('django.db.models.fields.EmailField')(max_length=254)) |
468 | + |
469 | + models = { |
470 | + u'project.sourcepackage': { |
471 | + 'Meta': {'object_name': 'SourcePackage', 'db_table': "'sourcepackage'"}, |
472 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
473 | + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '4096'}) |
474 | + }, |
475 | + u'ticket.mergeproposal': { |
476 | + 'Meta': {'object_name': 'MergeProposal', 'db_table': "'mergeproposal'"}, |
477 | + 'approved_revno': ('django.db.models.fields.IntegerField', [], {}), |
478 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
479 | + 'lp_url': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
480 | + 'project': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
481 | + 'sourcepackage': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['project.SourcePackage']"}), |
482 | + 'target_branch': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
483 | + 'version': ('django.db.models.fields.CharField', [], {'max_length': '4096'}) |
484 | + }, |
485 | + u'ticket.review': { |
486 | + 'Meta': {'object_name': 'Review'}, |
487 | + 'completed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
488 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
489 | + 'review_type': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
490 | + 'ticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.Ticket']"}), |
491 | + 'workflow_step': ('django.db.models.fields.IntegerField', [], {}) |
492 | + }, |
493 | + u'ticket.sourcepackageupload': { |
494 | + 'Meta': {'object_name': 'SourcePackageUpload', 'db_table': "'sourcepackageupload'"}, |
495 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
496 | + 'sourcepackage': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['project.SourcePackage']"}), |
497 | + 'version': ('django.db.models.fields.CharField', [], {'max_length': '4096'}) |
498 | + }, |
499 | + u'ticket.subticket': { |
500 | + 'Meta': {'object_name': 'SubTicket', 'db_table': "'subticket'"}, |
501 | + 'assignee': ('django.db.models.fields.EmailField', [], {'max_length': '254'}), |
502 | + 'current_workflow_step': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}), |
503 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
504 | + 'merge_proposal': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['ticket.MergeProposal']", 'null': 'True', 'blank': 'True'}), |
505 | + 'source_package_upload': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['ticket.SourcePackageUpload']", 'null': 'True', 'blank': 'True'}), |
506 | + 'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}), |
507 | + 'ticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.Ticket']"}) |
508 | + }, |
509 | + u'ticket.subticketartifact': { |
510 | + 'Meta': {'object_name': 'SubTicketArtifact', 'db_table': "'subticket_artifact'"}, |
511 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
512 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
513 | + 'reference': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
514 | + 'subticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.SubTicket']", 'null': 'True'}), |
515 | + 'type': ('django.db.models.fields.CharField', [], {'max_length': '4096'}) |
516 | + }, |
517 | + u'ticket.ticket': { |
518 | + 'Meta': {'object_name': 'Ticket', 'db_table': "'ticket'"}, |
519 | + 'base_image': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4096'}), |
520 | + 'bug_id': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), |
521 | + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
522 | + 'creator': ('django.db.models.fields.EmailField', [], {'max_length': '4096'}), |
523 | + 'current_workflow_step': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}), |
524 | + 'description': ('django.db.models.fields.TextField', [], {}), |
525 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
526 | + 'lander_unit': ('django.db.models.fields.IntegerField', [], {'default': '0'}), |
527 | + 'master_ppa': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4096'}), |
528 | + 'owner': ('django.db.models.fields.EmailField', [], {'max_length': '4096'}), |
529 | + 'private': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
530 | + 'series': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4096'}), |
531 | + 'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}), |
532 | + 'title': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
533 | + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), |
534 | + 'uuid': ('django.db.models.fields.CharField', [], {'default': "'1b1a4510-1db3-11e4-9bc5-4437e68484d8'", 'unique': 'True', 'max_length': '36'}), |
535 | + 'workflow': ('django.db.models.fields.related.ForeignKey', [], {'default': "'default'", 'to': u"orm['ticket.Workflow']"}) |
536 | + }, |
537 | + u'ticket.ticketartifact': { |
538 | + 'Meta': {'object_name': 'TicketArtifact', 'db_table': "'ticket_artifact'"}, |
539 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
540 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
541 | + 'reference': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
542 | + 'ticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.Ticket']", 'null': 'True'}), |
543 | + 'type': ('django.db.models.fields.CharField', [], {'max_length': '4096'}) |
544 | + }, |
545 | + u'ticket.workflow': { |
546 | + 'Meta': {'object_name': 'Workflow'}, |
547 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096', 'primary_key': 'True'}), |
548 | + 'steps': ('django.db.models.fields.CharField', [], {'max_length': '4096'}) |
549 | + } |
550 | + } |
551 | + |
552 | + complete_apps = ['ticket'] |
553 | \ No newline at end of file |
554 | |
555 | === added file 'ticket_system/ticket/migrations/0009_add_creator.py' |
556 | --- ticket_system/ticket/migrations/0009_add_creator.py 1970-01-01 00:00:00 +0000 |
557 | +++ ticket_system/ticket/migrations/0009_add_creator.py 2014-08-21 13:48:34 +0000 |
558 | @@ -0,0 +1,103 @@ |
559 | +# -*- coding: utf-8 -*- |
560 | +import datetime |
561 | +from south.db import db |
562 | +from south.v2 import DataMigration |
563 | +from django.db import models |
564 | + |
565 | +class Migration(DataMigration): |
566 | + |
567 | + def forwards(self, orm): |
568 | + # Note: Remember to use orm['appname.ModelName'] rather than "from appname.models..." |
569 | + |
570 | + for ticket in orm.Ticket.objects.all(): |
571 | + ticket.creator = ticket.owner |
572 | + ticket.save() |
573 | + |
574 | + def backwards(self, orm): |
575 | + raise RuntimeError("This migration cannot be reversed") |
576 | + |
577 | + models = { |
578 | + u'project.sourcepackage': { |
579 | + 'Meta': {'object_name': 'SourcePackage', 'db_table': "'sourcepackage'"}, |
580 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
581 | + 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '4096'}) |
582 | + }, |
583 | + u'ticket.mergeproposal': { |
584 | + 'Meta': {'object_name': 'MergeProposal', 'db_table': "'mergeproposal'"}, |
585 | + 'approved_revno': ('django.db.models.fields.IntegerField', [], {}), |
586 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
587 | + 'lp_url': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
588 | + 'project': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
589 | + 'sourcepackage': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['project.SourcePackage']"}), |
590 | + 'target_branch': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
591 | + 'version': ('django.db.models.fields.CharField', [], {'max_length': '4096'}) |
592 | + }, |
593 | + u'ticket.review': { |
594 | + 'Meta': {'object_name': 'Review'}, |
595 | + 'completed': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
596 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
597 | + 'review_type': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
598 | + 'ticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.Ticket']"}), |
599 | + 'workflow_step': ('django.db.models.fields.IntegerField', [], {}) |
600 | + }, |
601 | + u'ticket.sourcepackageupload': { |
602 | + 'Meta': {'object_name': 'SourcePackageUpload', 'db_table': "'sourcepackageupload'"}, |
603 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
604 | + 'sourcepackage': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['project.SourcePackage']"}), |
605 | + 'version': ('django.db.models.fields.CharField', [], {'max_length': '4096'}) |
606 | + }, |
607 | + u'ticket.subticket': { |
608 | + 'Meta': {'object_name': 'SubTicket', 'db_table': "'subticket'"}, |
609 | + 'assignee': ('django.db.models.fields.EmailField', [], {'max_length': '254'}), |
610 | + 'current_workflow_step': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}), |
611 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
612 | + 'merge_proposal': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['ticket.MergeProposal']", 'null': 'True', 'blank': 'True'}), |
613 | + 'source_package_upload': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': u"orm['ticket.SourcePackageUpload']", 'null': 'True', 'blank': 'True'}), |
614 | + 'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}), |
615 | + 'ticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.Ticket']"}) |
616 | + }, |
617 | + u'ticket.subticketartifact': { |
618 | + 'Meta': {'object_name': 'SubTicketArtifact', 'db_table': "'subticket_artifact'"}, |
619 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
620 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
621 | + 'reference': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
622 | + 'subticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.SubTicket']", 'null': 'True'}), |
623 | + 'type': ('django.db.models.fields.CharField', [], {'max_length': '4096'}) |
624 | + }, |
625 | + u'ticket.ticket': { |
626 | + 'Meta': {'object_name': 'Ticket', 'db_table': "'ticket'"}, |
627 | + 'base_image': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4096'}), |
628 | + 'bug_id': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}), |
629 | + 'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}), |
630 | + 'creator': ('django.db.models.fields.EmailField', [], {'max_length': '4096'}), |
631 | + 'current_workflow_step': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}), |
632 | + 'description': ('django.db.models.fields.TextField', [], {}), |
633 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
634 | + 'lander_unit': ('django.db.models.fields.IntegerField', [], {'default': '0'}), |
635 | + 'master_ppa': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4096'}), |
636 | + 'owner': ('django.db.models.fields.EmailField', [], {'max_length': '4096'}), |
637 | + 'private': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), |
638 | + 'series': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4096'}), |
639 | + 'status': ('django.db.models.fields.IntegerField', [], {'default': '0', 'max_length': '4096'}), |
640 | + 'title': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
641 | + 'updated': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}), |
642 | + 'uuid': ('django.db.models.fields.CharField', [], {'default': "'458c437a-1db3-11e4-ad48-4437e68484d8'", 'unique': 'True', 'max_length': '36'}), |
643 | + 'workflow': ('django.db.models.fields.related.ForeignKey', [], {'default': "'default'", 'to': u"orm['ticket.Workflow']"}) |
644 | + }, |
645 | + u'ticket.ticketartifact': { |
646 | + 'Meta': {'object_name': 'TicketArtifact', 'db_table': "'ticket_artifact'"}, |
647 | + u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), |
648 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
649 | + 'reference': ('django.db.models.fields.CharField', [], {'max_length': '4096'}), |
650 | + 'ticket': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['ticket.Ticket']", 'null': 'True'}), |
651 | + 'type': ('django.db.models.fields.CharField', [], {'max_length': '4096'}) |
652 | + }, |
653 | + u'ticket.workflow': { |
654 | + 'Meta': {'object_name': 'Workflow'}, |
655 | + 'name': ('django.db.models.fields.CharField', [], {'max_length': '4096', 'primary_key': 'True'}), |
656 | + 'steps': ('django.db.models.fields.CharField', [], {'max_length': '4096'}) |
657 | + } |
658 | + } |
659 | + |
660 | + complete_apps = ['ticket'] |
661 | + symmetrical = True |
662 | |
663 | === modified file 'ticket_system/ticket/models.py' |
664 | --- ticket_system/ticket/models.py 2014-08-18 19:23:55 +0000 |
665 | +++ ticket_system/ticket/models.py 2014-08-21 13:48:34 +0000 |
666 | @@ -108,7 +108,8 @@ |
667 | max_length=36, editable=False, unique=True, default=get_ticket_uuid, |
668 | help_text=('UUIDv1 ticket identification represented as ' |
669 | 'string (aka \'hyphenated\').')) |
670 | - owner = models.EmailField(max_length=254) |
671 | + owner = models.EmailField(max_length=4096) |
672 | + creator = models.EmailField(max_length=4096) |
673 | title = models.CharField(max_length=4096) |
674 | description = models.TextField() |
675 | bug_id = models.IntegerField(null=True, blank=True) |
676 | |
677 | === modified file 'ticket_system/ticket/tests/test_full_read_api.py' |
678 | --- ticket_system/ticket/tests/test_full_read_api.py 2014-08-05 00:42:26 +0000 |
679 | +++ ticket_system/ticket/tests/test_full_read_api.py 2014-08-21 13:48:34 +0000 |
680 | @@ -93,6 +93,7 @@ |
681 | u'created': unicode(self.ticket.created.strftime( |
682 | settings.TEST_DATETIME_FORMAT)), |
683 | u'owner': unicode(self.ticket.owner), |
684 | + u'creator': unicode(self.ticket.creator), |
685 | u'base_image': unicode(self.ticket.base_image), |
686 | u'id': self.ticket.pk, |
687 | u'lander_unit': 0, |
688 | |
689 | === modified file 'ticket_system/ticket/tests/test_models.py' |
690 | --- ticket_system/ticket/tests/test_models.py 2014-08-05 20:20:26 +0000 |
691 | +++ ticket_system/ticket/tests/test_models.py 2014-08-21 13:48:34 +0000 |
692 | @@ -70,12 +70,14 @@ |
693 | def create_ticket(title="This is my ticket", |
694 | description="this is my ticket description", |
695 | bug_id='12345', owner='test@example.com', |
696 | + creator='test@example.com', |
697 | current_workflow_step=TicketWorkflowStep.PKG_BUILDING, |
698 | status=TicketWorkflowStepStatus.INPROGRESS, |
699 | base_image='17', series='saucy', |
700 | master_ppa='ci-engine/ppa'): |
701 | ticket = Ticket() |
702 | ticket.owner = owner |
703 | + ticket.creator = creator |
704 | ticket.title = title |
705 | ticket.description = description |
706 | ticket.bug_id = bug_id |
707 | @@ -149,7 +151,8 @@ |
708 | self.addCleanup(_m.stop) |
709 | # Creating tickets, independently of its status, creates its |
710 | # container. |
711 | - self.ticket = create_ticket(owner='test@example.com') |
712 | + self.ticket = create_ticket(owner='test@example.com', |
713 | + creator='test@example.com') |
714 | self.create_container.assert_called_once() |
715 | |
716 | def test_creating_an_artifact_subticket(self): |
717 | |
718 | === modified file 'ticket_system/ticket/tests/test_read_api.py' |
719 | --- ticket_system/ticket/tests/test_read_api.py 2014-08-05 00:42:26 +0000 |
720 | +++ ticket_system/ticket/tests/test_read_api.py 2014-08-21 13:48:34 +0000 |
721 | @@ -105,6 +105,7 @@ |
722 | u'title': unicode(self.ticket.title), |
723 | u'bug_id': self.ticket.bug_id, |
724 | u'owner': unicode(self.ticket.owner), |
725 | + u'creator': unicode(self.ticket.creator), |
726 | u'base_image': unicode(self.ticket.base_image), |
727 | u'id': self.ticket.pk, |
728 | u'lander_unit': 0, |
729 | @@ -142,6 +143,7 @@ |
730 | u'title': unicode(self.ticket.title), |
731 | u'bug_id': self.ticket.bug_id, |
732 | u'owner': unicode(self.ticket.owner), |
733 | + u'creator': unicode(self.ticket.creator), |
734 | u'base_image': unicode(self.ticket.base_image), |
735 | u'id': self.ticket.pk, |
736 | u'lander_unit': 0, |
737 | @@ -194,6 +196,7 @@ |
738 | u'lander_unit': 0, |
739 | u'master_ppa': unicode(self.ticket.master_ppa), |
740 | u'owner': unicode(self.ticket.owner), |
741 | + u'creator': unicode(self.ticket.creator), |
742 | u'status': unicode(get_enum_title(self.ticket.status, |
743 | TicketWorkflowStepStatus)), |
744 | u'title': unicode(self.ticket.title), |
745 | @@ -220,6 +223,7 @@ |
746 | u'title': unicode(self.ticket.title), |
747 | u'bug_id': self.ticket.bug_id, |
748 | u'owner': unicode(self.ticket.owner), |
749 | + u'creator': unicode(self.ticket.creator), |
750 | u'base_image': unicode(self.ticket.base_image), |
751 | u'id': self.ticket.pk, |
752 | u'lander_unit': 0, |
753 | @@ -445,6 +449,7 @@ |
754 | u'title': unicode(self.ticket_6.title), |
755 | u'bug_id': self.ticket_6.bug_id, |
756 | u'owner': unicode(self.ticket_6.owner), |
757 | + u'creator': unicode(self.ticket_6.creator), |
758 | u'base_image': unicode(self.ticket_6.base_image), |
759 | u'id': self.ticket_6.pk, |
760 | u'lander_unit': self.ticket_6.lander_unit, |
761 | |
762 | === modified file 'ticket_system/ticket/tests/test_write_api.py' |
763 | --- ticket_system/ticket/tests/test_write_api.py 2014-08-05 00:42:26 +0000 |
764 | +++ ticket_system/ticket/tests/test_write_api.py 2014-08-21 13:48:34 +0000 |
765 | @@ -61,6 +61,7 @@ |
766 | self.detail_url = self.resource + '{0}/'.format(self.ticket.pk) |
767 | self.post_ticket_data = { |
768 | 'owner': 'owner@example.com', |
769 | + 'creator': 'creator@example.com', |
770 | 'title': 'My first ticket!', |
771 | 'description': 'This if my first ticket. See what it can do', |
772 | 'bug_id': '12345', |
773 | @@ -84,6 +85,7 @@ |
774 | a_uuid = str(uuid.uuid1()) |
775 | params = { |
776 | 'owner': 'owner@example.com', |
777 | + 'creator': 'creator@example.com', |
778 | 'title': 'UUID FTW!', |
779 | 'description': 'This ticket has UUID', |
780 | 'bug_id': '12345', |
FAILED: Continuous integration, rev:741 s-jenkins. ubuntu- ci:8080/ job/uci- engine- ci/1268/
http://
Executed test runs:
Click here to trigger a rebuild: s-jenkins. ubuntu- ci:8080/ job/uci- engine- ci/1268/ rebuild
http://