~launchpad-pqm/launchpad/devel

« back to all changes in this revision

Viewing changes to lib/lp/soyuz/doc/distroseriesqueue-notify.txt

Merged db-devel into replication.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
= Queue Notify =
2
 
 
3
 
PackageUpload has a notify() method to send emails.
4
 
We need to be logged into the security model in order to get any further.
5
 
 
6
 
  >>> login('foo.bar@canonical.com')
 
1
Queue Notify
 
2
============
 
3
 
 
4
PackageUpload has a notify() method to send emails. We need to be logged
 
5
into the security model in order to get any further.
 
6
 
 
7
    >>> login('foo.bar@canonical.com')
7
8
 
8
9
Get a packageupload object for netapplet, which has a relatively intact
9
 
set of supporting sample data.  It has rows in distribution, distroseries, 
10
 
sourcepackagerelease, person and a librarian entry for the changes file 
11
 
which are all needed for successful operation of notify().
12
 
 
13
 
  >>> from lp.soyuz.interfaces.queue import IPackageUploadSet
14
 
  >>> netapplet_upload = getUtility(IPackageUploadSet)[3]
15
 
  >>> print netapplet_upload.displayname
16
 
  netapplet
17
 
 
18
 
Set up some library files for the netapplet source package.  These are not
19
 
already present in the sample data.
20
 
 
21
 
  >>> from canonical.launchpad.interfaces.librarian import ILibraryFileAliasSet
22
 
  >>> from lp.archiveuploader.tests import datadir
23
 
  >>> import os
24
 
  >>> netapplet_spr = netapplet_upload.sources[0].sourcepackagerelease
25
 
  >>> librarian = getUtility(ILibraryFileAliasSet)
26
 
  >>> files = ['netapplet_1.0-1.dsc', 'netapplet_1.0.orig.tar.gz',
27
 
  ...     'netapplet_1.0-1.diff.gz']
28
 
  >>> for file in files:
29
 
  ...     filepath = datadir('suite/netapplet_1.0-1/%s' % file)
30
 
  ...     fileobj = open(filepath, 'rb')
31
 
  ...     filesize = os.stat(filepath).st_size
32
 
  ...     lfa = librarian.create(file, filesize, fileobj, 'dummytype')
33
 
  ...     sprf = netapplet_spr.addFile(lfa)
34
 
  ...     fileobj.close()
35
 
 
36
 
The notify() method generates one email here on this unsigned package.  It
37
 
requires an announcement list email address, a "changes_file_object" that is
38
 
just an open file object for the original changes file, and a special
39
 
logger object that will extract tracebacks for the purposes of this doctest.
40
 
 
41
 
  >>> changes_file_path = datadir(
42
 
  ...     'suite/netapplet_1.0-1/netapplet_1.0-1_source.changes')
43
 
  >>> changes_file = open(changes_file_path,'r')
44
 
  >>> from lp.services.log.logger import FakeLogger
45
 
  >>> netapplet_upload.notify(
46
 
  ...     changes_file_object=changes_file, logger=FakeLogger())
47
 
  DEBUG Building recipients list.
48
 
  DEBUG Changes file is unsigned, adding changer as recipient
49
 
  ...
50
 
  DEBUG Sent a mail:
51
 
  ...
52
 
  DEBUG     Recipients: Daniel Silverstone <daniel.silverstone@canonical.com>
53
 
  ...
54
 
  DEBUG above if files already exist in other distroseries.
55
 
  ...
56
 
  DEBUG signer of the above package.
 
10
set of supporting sample data.  It has rows in distribution,
 
11
distroseries, sourcepackagerelease, person and a librarian entry for the
 
12
changes file which are all needed for successful operation of notify().
 
13
 
 
14
    >>> from lp.soyuz.interfaces.queue import IPackageUploadSet
 
15
    >>> netapplet_upload = getUtility(IPackageUploadSet)[3]
 
16
    >>> print netapplet_upload.displayname
 
17
    netapplet
 
18
 
 
19
Set up some library files for the netapplet source package.  These are
 
20
not already present in the sample data.
 
21
 
 
22
    >>> from canonical.launchpad.interfaces.librarian import (
 
23
    ...     ILibraryFileAliasSet)
 
24
    >>> from lp.archiveuploader.tests import datadir
 
25
    >>> import os
 
26
    >>> netapplet_spr = netapplet_upload.sources[0].sourcepackagerelease
 
27
    >>> librarian = getUtility(ILibraryFileAliasSet)
 
28
    >>> files = [
 
29
    ...     'netapplet_1.0-1.dsc',
 
30
    ...     'netapplet_1.0.orig.tar.gz',
 
31
    ...     'netapplet_1.0-1.diff.gz',
 
32
    ...     ]
 
33
    >>> for file in files:
 
34
    ...     filepath = datadir('suite/netapplet_1.0-1/%s' % file)
 
35
    ...     fileobj = open(filepath, 'rb')
 
36
    ...     filesize = os.stat(filepath).st_size
 
37
    ...     lfa = librarian.create(file, filesize, fileobj, 'dummytype')
 
38
    ...     sprf = netapplet_spr.addFile(lfa)
 
39
    ...     fileobj.close()
 
40
 
 
41
The notify() method generates one email here on this unsigned package.
 
42
It requires an announcement list email address, a "changes_file_object"
 
43
that is just an open file object for the original changes file, and a
 
44
special logger object that will extract tracebacks for the purposes of
 
45
this doctest.
 
46
 
 
47
    >>> changes_file_path = datadir(
 
48
    ...     'suite/netapplet_1.0-1/netapplet_1.0-1_source.changes')
 
49
    >>> changes_file = open(changes_file_path,'r')
 
50
    >>> from lp.services.log.logger import FakeLogger
 
51
    >>> netapplet_upload.notify(
 
52
    ...     changes_file_object=changes_file, logger=FakeLogger())
 
53
    DEBUG Building recipients list.
 
54
    DEBUG Changes file is unsigned; adding changer as recipient.
 
55
    ...
 
56
    DEBUG Sent a mail:
 
57
    ...
 
58
    DEBUG   Recipients: ... Silverstone ...
 
59
    ...
 
60
    DEBUG above if files already exist in other distroseries.
 
61
    ...
 
62
    DEBUG signer of the above package.
57
63
 
58
64
Helper functions to examine emails that were sent:
59
65
 
60
 
  >>> from lp.services.mail import stub
61
 
  >>> from lp.testing.mail_helpers import pop_notifications
62
 
  >>> def by_to_addrs(a, b):
63
 
  ...     return cmp(a[1], b[1])
 
66
    >>> from lp.services.mail import stub
 
67
    >>> from lp.testing.mail_helpers import pop_notifications
64
68
 
65
69
There's only one email generated from the preceding upload:
66
70
 
67
 
  >>> [notification] = pop_notifications()
 
71
    >>> [notification] = pop_notifications()
68
72
 
69
73
The mail headers contain our To: as set on the notify() call.  The
70
 
subject contains "Accepted", the package name, its version and whether it's
71
 
source or binary.  The Bcc field also always contains the uploader's email
72
 
address.
73
 
 
74
 
  >>> notification['To']
75
 
  'Daniel Silverstone <daniel.silverstone@canonical.com>'
76
 
  >>> notification['Bcc']
77
 
  'Root <root@localhost>'
78
 
 
79
 
  >>> notification['Subject']
80
 
  '[ubuntu/breezy-autotest] netapplet 0.99.6-1 (New)'
 
74
subject contains "Accepted", the package name, its version and whether
 
75
it's source or binary.  The Bcc field also always contains the
 
76
uploader's email address.
 
77
 
 
78
    >>> notification['To']
 
79
    'Daniel Silverstone <daniel.silverstone@canonical.com>'
 
80
 
 
81
    >>> notification['Bcc']
 
82
    'Root <root@localhost>'
 
83
 
 
84
    >>> notification['Subject']
 
85
    '[ubuntu/breezy-autotest] netapplet 0.99.6-1 (New)'
81
86
 
82
87
The mail body contains a list of files that were accepted:
83
88
 
84
 
  >>> print notification.get_payload(0) # doctest: -NORMALIZE_WHITESPACE
85
 
  From nobody ...
86
 
  ...
87
 
  NEW: netapplet_1.0-1.dsc
88
 
  NEW: netapplet_1.0.orig.tar.gz
89
 
  NEW: netapplet_1.0-1.diff.gz
90
 
  <BLANKLINE>
91
 
  ...
92
 
  You may have gotten the distroseries wrong.  If so, you may get warnings
93
 
  above if files already exist in other distroseries.
94
 
  <BLANKLINE>
95
 
  -- =
96
 
  <BLANKLINE>
97
 
  You are receiving this email because you are the uploader, maintainer or
98
 
  signer of the above package.
99
 
  <BLANKLINE>
100
 
 
101
 
Now we will process a signed package.  Signed packages will potentially have
102
 
a different recipient list to unsigned ones; recipients for signed package 
103
 
uploads can be the signer, the maintainer and the changer, where these people 
104
 
are different.  Unsigned packages only send notifications to the changer.
105
 
 
106
 
  >>> from zope.security.proxy import removeSecurityProxy
107
 
  >>> from lp.registry.interfaces.gpg import IGPGKeySet
108
 
  >>> gpgkey = getUtility(IGPGKeySet).get(1)
109
 
  >>> removeSecurityProxy(netapplet_upload).signing_key = gpgkey
 
89
    >>> print notification.get_payload(0) # doctest: -NORMALIZE_WHITESPACE
 
90
    From nobody ...
 
91
    ...
 
92
    NEW: netapplet_1.0-1.dsc
 
93
    NEW: netapplet_1.0.orig.tar.gz
 
94
    NEW: netapplet_1.0-1.diff.gz
 
95
    <BLANKLINE>
 
96
    ...
 
97
    You may have gotten the distroseries wrong.  If so, you may get warnings
 
98
    above if files already exist in other distroseries.
 
99
    <BLANKLINE>
 
100
    -- =
 
101
    <BLANKLINE>
 
102
    You are receiving this email because you are the uploader, maintainer or
 
103
    signer of the above package.
 
104
    <BLANKLINE>
 
105
 
 
106
Now we will process a signed package.  Signed packages will potentially
 
107
have a different recipient list to unsigned ones; recipients for signed
 
108
package uploads can be the signer, the maintainer and the changer, where
 
109
these people are different.  Unsigned packages only send notifications
 
110
to the changer.
 
111
 
 
112
    >>> from zope.security.proxy import removeSecurityProxy
 
113
    >>> from lp.registry.interfaces.gpg import IGPGKeySet
 
114
    >>> gpgkey = getUtility(IGPGKeySet).get(1)
 
115
    >>> removeSecurityProxy(netapplet_upload).signing_key = gpgkey
110
116
 
111
117
Now request the email:
112
118
 
113
 
  >>> changes_file_path = datadir(
114
 
  ...     'suite/netapplet_1.0-1-signed/netapplet_1.0-1_source.changes')
115
 
  >>> changes_file = open(changes_file_path,'r')
116
 
  >>> netapplet_upload.setAccepted()
117
 
  >>> netapplet_upload.notify(
118
 
  ...     changes_file_object=changes_file, logger=FakeLogger())
119
 
  DEBUG Building recipients list.
120
 
  ...
121
 
  DEBUG Sent a mail:
122
 
  ...
123
 
  DEBUG     Recipients: Foo Bar <foo.bar@canonical.com>, Daniel Silverstone <daniel.silverstone@canonical.com>
124
 
  ...
125
 
  DEBUG Announcing to autotest_changes@ubuntu.com
126
 
  ...
127
 
  DEBUG Sent a mail:
128
 
  ...
129
 
 
130
 
There are two emails, the upload acknowledgement and the announcement, because
131
 
this upload is already accepted.
132
 
 
133
 
  >>> msgs = pop_notifications()
134
 
  >>> len(msgs)
135
 
  2
136
 
 
137
 
The mail 'To:' addresses contain the signer and the changer's email.  The
138
 
announcement email contains the serieses changeslist.
139
 
 
140
 
  >>> [msg['To'] for msg in msgs]
141
 
  ['Foo Bar <foo.bar@canonical.com>,\n\tDaniel Silverstone <daniel.silverstone@canonical.com>', 'autotest_changes@ubuntu.com']
142
 
 
143
 
The mail 'Bcc:' address is the uploader.  The announcement has the uploader
144
 
and the Debian derivatives address for the package uploaded.
145
 
 
146
 
  >>> [msg['Bcc'] for msg in msgs]
147
 
  ['Root <root@localhost>', 'Root <root@localhost>, netapplet_derivatives@packages.qa.debian.org']
 
119
    >>> changes_file_path = datadir(
 
120
    ...     'suite/netapplet_1.0-1-signed/netapplet_1.0-1_source.changes')
 
121
    >>> changes_file = open(changes_file_path,'r')
 
122
    >>> netapplet_upload.setAccepted()
 
123
    >>> netapplet_upload.notify(
 
124
    ...     changes_file_object=changes_file, logger=FakeLogger())
 
125
    DEBUG Building recipients list.
 
126
    ...
 
127
    DEBUG Sent a mail:
 
128
    ...
 
129
    DEBUG     Recipients: ... Bar ...
 
130
    ...
 
131
    DEBUG Announcing to autotest_changes@ubuntu.com
 
132
    ...
 
133
    DEBUG Sent a mail:
 
134
    ...
 
135
 
 
136
There are two emails, the upload acknowledgement and the announcement,
 
137
because this upload is already accepted.
 
138
 
 
139
    >>> msgs = pop_notifications()
 
140
    >>> len(msgs)
 
141
    2
 
142
 
 
143
The mail 'To:' addresses contain the signer and the changer's email.
 
144
The announcement email contains the serieses changeslist.
 
145
 
 
146
    >>> def to_lower(address):
 
147
    ...     """Return lower-case version of email address."""
 
148
    ...     return address.lower()
 
149
 
 
150
    >>> def extract_addresses(header_field):
 
151
    ...     """Extract and sort addresses from an email header field."""
 
152
    ...     return sorted(
 
153
    ...         [addr.strip() for addr in header_field.split(',')],
 
154
    ...         key=to_lower)
 
155
 
 
156
    >>> for addr in extract_addresses(msgs[0]['To']):
 
157
    ...     print addr
 
158
    Daniel Silverstone <daniel.silverstone@canonical.com>
 
159
    Foo Bar <foo.bar@canonical.com>
 
160
 
 
161
    >>> print msgs[1]['To']
 
162
    autotest_changes@ubuntu.com
 
163
 
 
164
The mail 'Bcc:' address is the uploader.  The announcement has the
 
165
uploader and the Debian derivatives address for the package uploaded.
 
166
 
 
167
    >>> for msg in msgs:
 
168
    ...     print extract_addresses(msg['Bcc'])
 
169
    ['Root <root@localhost>']
 
170
    ['netapplet_derivatives@packages.qa.debian.org', 'Root <root@localhost>']
148
171
 
149
172
The mail 'From:' addresses are the uploader and the changer.
150
173
 
151
 
  >>> [msg['From'] for msg in msgs]
152
 
  ['Root <root@localhost>', 'Daniel Silverstone <daniel.silverstone@canonical.com>']
 
174
    >>> for msg in msgs:
 
175
    ...     print msg['From']
 
176
    Root <root@localhost>
 
177
    Daniel Silverstone <daniel.silverstone@canonical.com>
153
178
 
154
 
  >>> notification['Subject']
155
 
  '[ubuntu/breezy-autotest] netapplet 0.99.6-1 (New)'
 
179
    >>> print notification['Subject']
 
180
    [ubuntu/breezy-autotest] netapplet 0.99.6-1 (New)
156
181
 
157
182
The mail body contains the same list of files again:
158
183
 
159
 
  >>> print notification.get_payload(0) # doctest: -NORMALIZE_WHITESPACE
160
 
  From nobody ...
161
 
  ...
162
 
  NEW: netapplet_1.0-1.dsc
163
 
  NEW: netapplet_1.0.orig.tar.gz
164
 
  NEW: netapplet_1.0-1.diff.gz
165
 
  <BLANKLINE>
166
 
  ...
167
 
  You may have gotten the distroseries wrong.  If so, you may get warnings
168
 
  above if files already exist in other distroseries.
169
 
  <BLANKLINE>
170
 
  -- =
171
 
  <BLANKLINE>
172
 
  You are receiving this email because you are the uploader, maintainer or
173
 
  signer of the above package.
174
 
  <BLANKLINE>
175
 
 
176
 
 
177
 
notify() will also work without passing the changes_file_object parameter
178
 
provided that everything is already committed to the database (which is not
179
 
the case when nascent upload runs).  This example demonstrates this usage:
180
 
 
181
 
  >>> from canonical.librarian.testing.server import fillLibrarianFile
182
 
  >>> changes_file = open(changes_file_path,"r")
183
 
  >>> fillLibrarianFile(1, content=changes_file.read())
184
 
  >>> changes_file.close()
185
 
  >>> netapplet_upload.setNew()
186
 
  >>> netapplet_upload.notify(logger=FakeLogger())
187
 
  DEBUG Building recipients list.
188
 
  ...
189
 
  DEBUG Sent a mail:
190
 
  ...
191
 
  DEBUG     Recipients: Foo Bar <foo.bar@canonical.com>, Daniel Silverstone <daniel.silverstone@canonical.com>
192
 
  ...
193
 
  DEBUG above if files already exist in other distroseries.
194
 
  ...
195
 
  DEBUG signer of the above package.
 
184
    >>> print notification.get_payload(0) # doctest: -NORMALIZE_WHITESPACE
 
185
    From nobody ...
 
186
    ...
 
187
    NEW: netapplet_1.0-1.dsc
 
188
    NEW: netapplet_1.0.orig.tar.gz
 
189
    NEW: netapplet_1.0-1.diff.gz
 
190
    <BLANKLINE>
 
191
    ...
 
192
    You may have gotten the distroseries wrong.  If so, you may get warnings
 
193
    above if files already exist in other distroseries.
 
194
    <BLANKLINE>
 
195
    -- =
 
196
    <BLANKLINE>
 
197
    You are receiving this email because you are the uploader, maintainer or
 
198
    signer of the above package.
 
199
    <BLANKLINE>
 
200
 
 
201
notify() will also work without passing the changes_file_object
 
202
parameter provided that everything is already committed to the database
 
203
(which is not the case when nascent upload runs).  This example
 
204
demonstrates this usage:
 
205
 
 
206
    >>> from canonical.librarian.testing.server import fillLibrarianFile
 
207
    >>> changes_file = open(changes_file_path,"r")
 
208
    >>> fillLibrarianFile(1, content=changes_file.read())
 
209
    >>> changes_file.close()
 
210
    >>> netapplet_upload.setNew()
 
211
    >>> netapplet_upload.notify(logger=FakeLogger())
 
212
    DEBUG Building recipients list.
 
213
    ...
 
214
    DEBUG Sent a mail:
 
215
    ...
 
216
    DEBUG     Recipients: ... Silverstone ...
 
217
    ...
 
218
    DEBUG above if files already exist in other distroseries.
 
219
    ...
 
220
    DEBUG signer of the above package.
196
221
 
197
222
Only one email is generated:
198
223
 
199
 
  >>> [notification] = pop_notifications()
 
224
    >>> [notification] = pop_notifications()
200
225
 
201
226
The mail headers are the same as before:
202
227
 
203
 
  >>> notification['To']
204
 
  'Foo Bar <foo.bar@canonical.com>,\n\tDaniel Silverstone <daniel.silverstone@canonical.com>'
205
 
  >>> notification['Bcc']
206
 
  'Root <root@localhost>'
207
 
 
208
 
  >>> notification['Subject']
209
 
  '[ubuntu/breezy-autotest] netapplet 0.99.6-1 (New)'
 
228
    >>> for addr in extract_addresses(notification['To']):
 
229
    ...     print addr
 
230
    Daniel Silverstone <daniel.silverstone@canonical.com>
 
231
    Foo Bar <foo.bar@canonical.com>
 
232
 
 
233
    >>> print notification['Bcc']
 
234
    Root <root@localhost>
 
235
 
 
236
    >>> print notification['Subject']
 
237
    [ubuntu/breezy-autotest] netapplet 0.99.6-1 (New)
210
238
 
211
239
The mail body contains the same list of files again:
212
240
 
213
 
  >>> print notification.get_payload(0) # doctest: -NORMALIZE_WHITESPACE
214
 
  From nobody ...
215
 
  ...
216
 
  NEW: netapplet_1.0-1.dsc
217
 
  NEW: netapplet_1.0.orig.tar.gz
218
 
  NEW: netapplet_1.0-1.diff.gz
219
 
  <BLANKLINE>
220
 
  ...
221
 
  You may have gotten the distroseries wrong.  If so, you may get warnings
222
 
  above if files already exist in other distroseries.
223
 
  <BLANKLINE>
224
 
  -- =
225
 
  <BLANKLINE>
226
 
  You are receiving this email because you are the uploader, maintainer or
227
 
  signer of the above package.
228
 
  <BLANKLINE>
229
 
 
 
241
    >>> print notification.get_payload(0) # doctest: -NORMALIZE_WHITESPACE
 
242
    From nobody ...
 
243
    ...
 
244
    NEW: netapplet_1.0-1.dsc
 
245
    NEW: netapplet_1.0.orig.tar.gz
 
246
    NEW: netapplet_1.0-1.diff.gz
 
247
    <BLANKLINE>
 
248
    ...
 
249
    You may have gotten the distroseries wrong.  If so, you may get warnings
 
250
    above if files already exist in other distroseries.
 
251
    <BLANKLINE>
 
252
    -- =
 
253
    <BLANKLINE>
 
254
    You are receiving this email because you are the uploader, maintainer or
 
255
    signer of the above package.
 
256
    <BLANKLINE>
230
257
 
231
258
notify() will also generate rejection notices if the upload failed.  The
232
 
summary_text argument is text that is appended to any auto-generated text for
233
 
the summary.  Rejections don't currently auto-generate anything.
 
259
summary_text argument is text that is appended to any auto-generated
 
260
text for the summary.  Rejections don't currently auto-generate
 
261
anything.
234
262
 
235
 
  >>> netapplet_upload.setRejected()
236
 
  >>> netapplet_upload.notify(summary_text="Testing rejection message",
237
 
  ...     logger=FakeLogger())
238
 
  DEBUG Building recipients list.
239
 
  ...
240
 
  DEBUG Sending rejection email.
241
 
  ...
242
 
  DEBUG   Subject: [ubuntu/breezy-autotest] netapplet 0.99.6-1 (Rejected)
243
 
  DEBUG   Sender: Root <root@localhost>
244
 
  DEBUG   Recipients: Foo Bar <foo.bar@canonical.com>, Daniel Silverstone <daniel.silverstone@canonical.com>
245
 
  DEBUG   Bcc: Root <root@localhost>
246
 
  DEBUG   Body:
247
 
  DEBUG Rejected:
248
 
  DEBUG Testing rejection message
249
 
  ...
250
 
  DEBUG If you don't understand why your files were rejected, or if the
251
 
  ...
252
 
  DEBUG signer of the above package.
 
263
    >>> netapplet_upload.setRejected()
 
264
    >>> netapplet_upload.notify(
 
265
    ...     summary_text="Testing rejection message", logger=FakeLogger())
 
266
    DEBUG Building recipients list.
 
267
    ...
 
268
    DEBUG Sending rejection email.
 
269
    ...
 
270
    DEBUG   Subject: [ubuntu/breezy-autotest] netapplet 0.99.6-1 (Rejected)
 
271
    DEBUG   Sender: Root <root@localhost>
 
272
    DEBUG   Recipients: ... Bar ...
 
273
    DEBUG   Bcc: Root <root@localhost>
 
274
    DEBUG   Body:
 
275
    DEBUG Rejected:
 
276
    DEBUG Testing rejection message
 
277
    ...
 
278
    DEBUG If you don't understand why your files were rejected, or if the
 
279
    ...
 
280
    DEBUG signer of the above package.
253
281
 
254
282
Only one email is generated:
255
283
 
256
 
  >>> transaction.commit()
257
 
  >>> len(stub.test_emails)
258
 
  1
 
284
    >>> transaction.commit()
 
285
    >>> len(stub.test_emails)
 
286
    1
259
287
 
260
288
Clean up, otherwise stuff is left lying around in /var/tmp.
261
289
 
262
 
  >>> from canonical.testing.layers import LibrarianLayer
263
 
  >>> LibrarianLayer.librarian_fixture.clear()
 
290
    >>> from canonical.testing.layers import LibrarianLayer
 
291
    >>> LibrarianLayer.librarian_fixture.clear()