~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/bugs/doc/initial-bug-contacts.txt

  • Committer: Jelmer Vernooij
  • Date: 2011-09-21 14:28:02 UTC
  • mfrom: (14006 devel)
  • mto: This revision was merged to the branch mainline in revision 14010.
  • Revision ID: jelmer@canonical.com-20110921142802-7ggkc204igsy532w
MergeĀ lp:launchpad

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
= Bug Subscriptions =
 
1
Bug Subscriptions
 
2
=================
2
3
 
3
 
Package bug subscriptions allow zero, one, or more people or teams that get
4
 
explicitly Cc'd to all public bugs filed on a package.
 
4
Package bug subscriptions allow zero, one, or more people or teams that
 
5
get explicitly Cc'd to all public bugs filed on a package.
5
6
 
6
7
The package bug subscriptions are obtained from looking at the
7
8
StructuralSubscription table.
20
21
    []
21
22
 
22
23
Adding a package subscription is done with the
23
 
IDistributionSourcePackage.addBugSubscription method. You have to
24
 
be logged in to call this method:
 
24
IDistributionSourcePackage.addBugSubscription method. You have to be
 
25
logged in to call this method:
25
26
 
26
27
    >>> from lp.registry.interfaces.person import IPersonSet
27
28
    >>> personset = getUtility(IPersonSet)
39
40
 
40
41
    >>> debian_firefox.addBugSubscription(sample_person, sample_person)
41
42
    <...StructuralSubscription object at ...>
 
43
 
42
44
    >>> [pbc.subscriber.name for pbc in debian_firefox.bug_subscriptions]
43
45
    [u'name12']
44
46
 
54
56
    >>> debian_firefox.addBugSubscription(ubuntu_team, ubuntu_team)
55
57
    <...StructuralSubscription object at ...>
56
58
 
57
 
    >>> sorted([sub.subscriber.name for sub in debian_firefox.bug_subscriptions])
 
59
    >>> sorted([
 
60
    ...     sub.subscriber.name for sub in debian_firefox.bug_subscriptions])
58
61
    [u'name12', u'ubuntu-team']
59
62
 
60
63
To remove a subscription, use
61
64
IStructuralSubscriptionTarget.removeBugSubscription:
62
65
 
63
66
    >>> debian_firefox.removeBugSubscription(sample_person, sample_person)
64
 
    >>> sorted([sub.subscriber.id for sub in debian_firefox.bug_subscriptions])
 
67
    >>> sorted([
 
68
    ...     sub.subscriber.id for sub in debian_firefox.bug_subscriptions])
65
69
    [17]
66
70
 
67
 
Trying to remove a subscription that doesn't exist on a source package raises a
68
 
DeleteSubscriptionError.
 
71
Trying to remove a subscription that doesn't exist on a source package
 
72
raises a DeleteSubscriptionError.
69
73
 
70
74
    >>> foobar = personset.getByName("name16")
71
75
    >>> debian_firefox.removeBugSubscription(foobar, foobar)
74
78
    DeleteSubscriptionError: ...
75
79
 
76
80
 
77
 
== Package Subscriptions and Bug Tasks ==
 
81
Package Subscriptions and Bug Tasks
 
82
-----------------------------------
78
83
 
79
84
Often a bug gets reported on package foo, when it should have been
80
85
reported on bar. When a user, likely a bug triager or developer, changes
81
 
the source package, the subscribers for the new package get
82
 
subscribed. The subscribers of the previous package also remain
83
 
subscribed.
 
86
the source package, the subscribers for the new package get subscribed.
 
87
The subscribers of the previous package also remain subscribed.
84
88
 
85
 
To demonstrate, let's change the source package for bug #1 in
86
 
mozilla-firefox in Ubuntu to be pmount in Ubuntu, and see how the
87
 
subscribers list changes.
 
89
To demonstrate, let's change the source package for bug #1 in mozilla-
 
90
firefox in Ubuntu to be pmount in Ubuntu, and see how the subscribers
 
91
list changes.
88
92
 
89
93
    >>> from lp.bugs.interfaces.bugtask import IBugTaskSet
90
94
 
103
107
    ...     subscribers = chain(
104
108
    ...         bug.getDirectSubscribers(),
105
109
    ...         bug.getIndirectSubscribers())
106
 
    ...     return sorted(subscriber.displayname for subscriber in subscribers)
 
110
    ...     return sorted(
 
111
    ...         subscriber.displayname for subscriber in subscribers)
107
112
 
108
 
    >>> subscriber_names(bug_one_in_ubuntu_firefox.bug)
109
 
    [u'Foo Bar', u'Mark Shuttleworth', u'Sample Person', u'Steve Alexander',
110
 
     u'Ubuntu Team']
 
113
    >>> names = subscriber_names(bug_one_in_ubuntu_firefox.bug)
 
114
    >>> for name in names:
 
115
    ...     print name
 
116
    Foo Bar
 
117
    Mark Shuttleworth
 
118
    Sample Person
 
119
    Steve Alexander
 
120
    Ubuntu Team
111
121
 
112
122
Changing the package for bug_one_in_ubuntu_firefox to pmount will
113
123
implicitly subscribe the new package's subscribers to the bug. In
114
 
demonstrating this, we'll also make Sample Person a subscriber to
115
 
ubuntu pmount, to show that the subscription changes behave correctly
116
 
when a subscriber to the new package is already subscribed to the bug:
 
124
demonstrating this, we'll also make Sample Person a subscriber to ubuntu
 
125
pmount, to show that the subscription changes behave correctly when a
 
126
subscriber to the new package is already subscribed to the bug:
117
127
 
118
128
    >>> from zope.event import notify
119
129
 
126
136
    >>> daf = personset.getByName("daf")
127
137
    >>> ubuntu_pmount.addBugSubscription(daf, daf)
128
138
    <...StructuralSubscription object at ...>
 
139
 
129
140
    >>> ubuntu_pmount.addBugSubscription(sample_person, sample_person)
130
141
    <...StructuralSubscription object at ...>
131
142
 
132
143
    >>> old_state = Snapshot(
133
 
    ...     bug_one_in_ubuntu_firefox, providing=IBugTask)
 
144
    ...        bug_one_in_ubuntu_firefox, providing=IBugTask)
134
145
 
135
146
    >>> bug_one_in_ubuntu_firefox.transitionToTarget(ubuntu_pmount)
136
147
 
137
148
    >>> source_package_changed = ObjectModifiedEvent(
138
 
    ...     bug_one_in_ubuntu_firefox, old_state,
139
 
    ...     ["id", "title", "sourcepackagename"])
 
149
    ...        bug_one_in_ubuntu_firefox, old_state,
 
150
    ...        ["id", "title", "sourcepackagename"])
140
151
 
141
152
    >>> notify(source_package_changed)
142
153
    >>> transaction.commit()
149
160
 
150
161
daf is sent an email giving him complete information about the bug that
151
162
has just been retargeted, including the title, description, status,
152
 
importance, etc. The References header of the email contains the
153
 
msgid of the initial bug report (as if daf was a original recipient of
154
 
the bug notification). The email has the X-Launchpad-Message-Rationale
155
 
header to track why daf received the email. The rational is repeated
156
 
in the footer of the email with the bug title and URL.
 
163
importance, etc. The References header of the email contains the msgid
 
164
of the initial bug report (as if daf was a original recipient of the bug
 
165
notification). The email has the X-Launchpad-Message-Rationale header to
 
166
track why daf received the email. The rational is repeated in the footer
 
167
of the email with the bug title and URL.
157
168
 
158
169
    >>> import email
159
170
 
160
171
    >>> def by_to_addrs(a, b):
161
 
    ...     return cmp(a[1], b[1])
 
172
    ...        return cmp(a[1], b[1])
162
173
 
163
174
    >>> test_emails = list(stub.test_emails)
164
175
    >>> test_emails.sort(by_to_addrs)
165
176
 
166
177
    >>> len(test_emails)
167
178
    1
 
179
 
168
180
    >>> from_addr, to_addr, raw_message = test_emails.pop()
169
181
    >>> print from_addr
170
182
    bounces@canonical.com
 
183
 
171
184
    >>> print to_addr
172
185
    ['daf@canonical.com']
173
186
 
174
187
    >>> msg = email.message_from_string(raw_message)
175
188
    >>> msg['References'] == (
176
 
    ...     bug_one_in_ubuntu_firefox.bug.initial_message.rfc822msgid)
 
189
    ...        bug_one_in_ubuntu_firefox.bug.initial_message.rfc822msgid)
177
190
    True
 
191
 
178
192
    >>> msg['X-Launchpad-Message-Rationale']
179
193
    'Subscriber (pmount in Ubuntu)'
 
194
 
180
195
    >>> msg['Subject']
181
196
    '[Bug 1] [NEW] Firefox does not support SVG'
 
197
 
182
198
    >>> print msg.get_payload(decode=True)
183
199
    You have been subscribed to a public bug:
184
200
    <BLANKLINE>
218
234
 
219
235
    >>> stub.test_emails = []
220
236
 
221
 
Let's see that nothing unexpected happens when we set the source
222
 
package to None.
 
237
Let's see that nothing unexpected happens when we set the source package
 
238
to None.
223
239
 
224
240
    >>> old_state = Snapshot(
225
 
    ...     bug_one_in_ubuntu_firefox, providing=IBugTask)
 
241
    ...        bug_one_in_ubuntu_firefox, providing=IBugTask)
226
242
 
227
243
    >>> bug_one_in_ubuntu_firefox.transitionToTarget(ubuntu)
228
244
 
229
245
    >>> source_package_changed = ObjectModifiedEvent(
230
 
    ...     bug_one_in_ubuntu_firefox, old_state, ["sourcepackagename"])
 
246
    ...        bug_one_in_ubuntu_firefox, old_state, ["sourcepackagename"])
231
247
 
232
248
    >>> notify(source_package_changed)
233
249
    >>> transaction.commit()
235
251
 
236
252
The package subscribers, Daf and Foo Bar, are implicitly unsubscribed:
237
253
 
238
 
    >>> subscriber_names(bug_one_in_ubuntu_firefox.bug)
239
 
    [u'Mark Shuttleworth', u'Sample Person', u'Steve Alexander', u'Ubuntu Team']
 
254
    >>> names = subscriber_names(bug_one_in_ubuntu_firefox.bug)
 
255
    >>> for name in names:
 
256
    ...     print name
 
257
    Mark Shuttleworth
 
258
    Sample Person
 
259
    Steve Alexander
 
260
    Ubuntu Team
240
261
 
241
 
Subscriptions are not limited to persons; teams are also allowed to subscribe.
242
 
Teams are a bit different, since they might not have a contact address. Let's
243
 
add such a team as a subscriber.
 
262
Subscriptions are not limited to persons; teams are also allowed to
 
263
subscribe. Teams are a bit different, since they might not have a
 
264
contact address. Let's add such a team as a subscriber.
244
265
 
245
266
    >>> ubuntu_gnome = personset.getByName("name18")
246
267
    >>> ubuntu_gnome.preferredemail is None
247
268
    True
 
269
 
248
270
    >>> ubuntu_pmount.addBugSubscription(ubuntu_gnome, ubuntu_gnome)
249
271
    <...StructuralSubscription object at ...>
250
272
 
251
273
    >>> old_state = Snapshot(
252
 
    ...     bug_one_in_ubuntu_firefox, providing=IBugTask)
 
274
    ...        bug_one_in_ubuntu_firefox, providing=IBugTask)
253
275
 
254
276
    >>> bug_one_in_ubuntu_firefox.transitionToTarget(ubuntu_pmount)
255
277
 
256
278
    >>> source_package_changed = ObjectModifiedEvent(
257
 
    ...     bug_one_in_ubuntu_firefox, old_state, ["sourcepackagename"])
 
279
    ...        bug_one_in_ubuntu_firefox, old_state, ["sourcepackagename"])
258
280
 
259
281
    >>> notify(source_package_changed)
260
282
    >>> transaction.commit()
270
292
bug is reassigned to a different package.
271
293
 
272
294
    >>> bug_one_in_ubuntu_firefox.bug.setPrivate(
273
 
    ...     True, getUtility(ILaunchBag).user)
 
295
    ...        True, getUtility(ILaunchBag).user)
274
296
    True
275
297
 
276
298
So, if Martin Pitt subscribes to ubuntu mozilla-firefox:
282
304
and then the bug gets reassigned to mozilla firefox:
283
305
 
284
306
    >>> old_state = Snapshot(
285
 
    ...     bug_one_in_ubuntu_firefox, providing=IBugTask)
 
307
    ...        bug_one_in_ubuntu_firefox, providing=IBugTask)
286
308
 
287
309
    >>> bug_one_in_ubuntu_firefox.transitionToTarget(ubuntu_firefox)
288
310
 
289
311
    >>> source_package_changed = ObjectModifiedEvent(
290
 
    ...     bug_one_in_ubuntu_firefox, old_state,
291
 
    ...     ["id", "title", "sourcepackagename"])
 
312
    ...        bug_one_in_ubuntu_firefox, old_state,
 
313
    ...        ["id", "title", "sourcepackagename"])
292
314
 
293
315
    >>> notify(source_package_changed)
294
316
    >>> transaction.commit()
295
317
    >>> stub.test_emails = []
296
318
 
297
 
the unallowed subscribers are removed:
 
319
the subscriptions remain unchanged:
298
320
 
299
321
    >>> subscriber_names(bug_one_in_ubuntu_firefox.bug)
300
 
    [u'Foo Bar', u'Mark Shuttleworth', u'Sample Person', u'Ubuntu Team']
301
 
 
302
 
 
303
 
== Product Bug Supervisors and Bug Tasks ==
 
322
    [u'Dafydd Harries', u'Foo Bar', u'Mark Shuttleworth',
 
323
     u'Sample Person', u'Steve Alexander', u'Ubuntu Gnome Team',
 
324
     u'Ubuntu Team']
 
325
 
 
326
 
 
327
Product Bug Supervisors and Bug Tasks
 
328
-------------------------------------
304
329
 
305
330
Like reassigning a bug task to another package, reassigning a bug task
306
331
to another product will subscribe any new product bug supervisors to the
320
345
    >>> bug_two_in_ubuntu = getUtility(IBugTaskSet).get(3)
321
346
    >>> print bug_two_in_ubuntu.bug.id
322
347
    2
 
348
 
323
349
    >>> print bug_two_in_ubuntu.product.name
324
350
    tomcat
325
351
 
326
352
    >>> sorted(
327
 
    ...     [subscription.person.displayname for subscription in
328
 
    ...      bug_two_in_ubuntu.bug.subscriptions])
 
353
    ...        [subscription.person.displayname for subscription in
 
354
    ...         bug_two_in_ubuntu.bug.subscriptions])
329
355
    [u'Steve Alexander']
330
356
 
331
357
    >>> old_state = Snapshot(bug_two_in_ubuntu, providing=IBugTask)
333
359
    >>> bug_two_in_ubuntu.transitionToTarget(mozilla_firefox)
334
360
 
335
361
    >>> product_changed = ObjectModifiedEvent(
336
 
    ...     bug_two_in_ubuntu, old_state, ["id", "title", "product"])
 
362
    ...        bug_two_in_ubuntu, old_state, ["id", "title", "product"])
337
363
 
338
364
    >>> notify(product_changed)
339
365
    >>> transaction.commit()
355
381
 
356
382
    >>> len(test_emails)
357
383
    1
 
384
 
358
385
    >>> from_addr, to_addr, raw_message = test_emails.pop()
359
386
    >>> print from_addr
360
387
    bounces@canonical.com
 
388
 
361
389
    >>> print to_addr
362
390
    ['foo.bar@canonical.com']
363
391
 
364
392
    >>> msg = email.message_from_string(raw_message)
365
393
    >>> msg['Subject']
366
394
    '[Bug 2] [NEW] Blackhole Trash folder'
 
395
 
367
396
    >>> print msg.get_payload(decode=True)
368
397
    You have been subscribed to a public bug:
369
398
    ...
376
405
    are subscribed to Mozilla Firefox.
377
406
 
378
407
 
379
 
== Teams as bug supervisors ==
 
408
Teams as bug supervisors
 
409
------------------------
380
410
 
381
 
The list of teams that a user may add to a package as a bug supervisor will
382
 
only contain those teams of which the user is an administrator.
 
411
The list of teams that a user may add to a package as a bug supervisor
 
412
will only contain those teams of which the user is an administrator.
383
413
 
384
414
    >>> from zope.component import getMultiAdapter
385
415
    >>> from canonical.launchpad.webapp.servers import LaunchpadTestRequest
396
426
 
397
427
    >>> sample_person = view.user
398
428
    >>> ["%s: %s" % (membership.team.displayname, membership.status.name)
399
 
    ...  for membership in sample_person.team_memberships]
 
429
    ...     for membership in sample_person.team_memberships]
400
430
    [u'HWDB Team: APPROVED',
401
431
     u'Landscape Developers: ADMIN',
402
432
     u'Launchpad Users: ADMIN',
403
433
     u'Warty Security Team: APPROVED']
404
434
 
405
 
But is only an administrator of Landscape Developers, so that is the only
406
 
team that will be listed when the user is changing a package bug supervisor:
 
435
But is only an administrator of Landscape Developers, so that is the
 
436
only team that will be listed when the user is changing a package bug
 
437
supervisor:
407
438
 
408
439
    >>> for team in view.user.getAdministratedTeams():
409
 
    ...     print team.displayname
 
440
    ...        print team.displayname
410
441
    Landscape Developers
411
442
    Launchpad Users
 
443