Merge lp:~abentley/launchpad/build-mail3 into lp:launchpad
- build-mail3
- Merge into devel
Status: | Merged |
---|---|
Merged at revision: | 12275 |
Proposed branch: | lp:~abentley/launchpad/build-mail3 |
Merge into: | lp:launchpad |
Prerequisite: | lp:~abentley/launchpad/build-mail2 |
Diff against target: |
1653 lines (+671/-619) 7 files modified
database/schema/security.cfg (+1/-0) lib/lp/archiveuploader/tests/nascentupload-announcements.txt (+608/-592) lib/lp/archiveuploader/tests/test_uploadprocessor.py (+28/-5) lib/lp/archiveuploader/uploadprocessor.py (+6/-4) lib/lp/soyuz/model/binarypackagebuild.py (+2/-0) lib/lp/soyuz/model/queue.py (+20/-3) lib/lp/soyuz/tests/test_build_notify.py (+6/-15) |
To merge this branch: | bzr merge lp:~abentley/launchpad/build-mail3 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Brad Crittenden (community) | code | Approve | |
j.c.sackett (community) | code* | Approve | |
Review via email: mp+47679@code.launchpad.net |
Commit message
[r=bac,
Description of the change
= Summary =
Fix bugs:
Bug #681125: Async uploader sends recipe mail as if it were source package
uploads
Bug #613958: upload failure emails should include the upload log
== Proposed fix ==
Extend queue to skip notifications for recipe build-based uploads, not only
binary build-based uploads.
Move responsibility for deciding whether to notify on success to the Build
itself.
The upload log is now attached to the build before sending emails.
== Pre-implementation notes ==
Discussed with thumper
== Implementation details ==
Much doctest lint was cleaned up.
Some BinaryBuild tests were adjusted to reflect the fact that emails are never
sent for successful binary builds.
== Tests ==
bin/test -vt testSourcePacka
== Demo and Q/A ==
Create a sourcepackage recipe. Do a successful build. You should get an email
with a subject line like "Successfully built".
Do a build with the same version number as the previous one. You should get an
email like "[recipe build #8558] of ~abentley wakeonlan-lucid in maverick:
Failed to upload", but not one like "[PPA abentley-test]
wakeonlan_
= Launchpad lint =
Checking for conflicts and issues in changed files.
Linting changed files:
lib/lp/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
database/
lib/lp/
lib/lp/
lib/lp/
lib/lp/
./lib/lp/
873: E301 expected 1 blank line, found 2
^^^ due to a weirdly-positioned comment
./lib/lp/
191: want exceeds 78 characters.
192: want exceeds 78 characters.
718: want exceeds 78 characters.
720: want exceeds 78 characters.
766: want exceeds 78 characters.
768: want exceeds 78 characters.
^^^ cannot be fixed because tests specify strict whitespace handling
./database/
704: Line exceeds 78 characters.
705: Line exceeds 78 characters.
706: Line exceeds 78 characters.
732: Line exceeds 78 characters.
736: Line exceeds 78 characters.
791: Line exceeds 78 characters.
804: Line exceeds 78 characters.
805: Line exceeds 78 characters.
822: Line exceeds 78 characters.
823: Line exceeds 78 characters.
824: Line exceeds 78 characters.
825: Line exceeds 78 characters.
826: Line exceeds 78 characters.
878: Line exceeds 78 characters.
879: Line exceeds 78 characters.
880: Line exceeds 78 characters.
910: Line exceeds 78 characters.
991: Line exceeds 78 characters.
1001: Line exceeds 78 characters.
1002: Line exceeds 78 characters.
^^^ 78-char limit does not apply here AFAIK
./lib/lp/
1263: E301 expected 1 blank line, found 2
^^^ due to a weirdly-positioned comment
j.c.sackett (jcsackett) wrote : | # |
j.c.sackett (jcsackett) wrote : | # |
After talking in IRC, my performance question has been addressed.
11:57 AM jcsackett
abentley: builds is a SQLMultipleJoin; i'm wondering if when self.build gets called we may return a huge rowset in some cases.
11:57 AM abentley
jcsackett, as I said, it's always one or zero results.
11:57 AM jcsackett
abenltey, ah! i thought you meant from_build was called one or zero times.
11:57 AM abentley
jcsackett, there is a comment in the code saying it shouldn't be a multiple join.
11:59 AM jcsackett
abentley: yes, i see now.
11:59 AM
apologies for the confusion.
Brad Crittenden (bac) wrote : | # |
Code and review look fine. Thanks to you both.
Preview Diff
1 | === modified file 'database/schema/security.cfg' | |||
2 | --- database/schema/security.cfg 2010-12-02 16:15:46 +0000 | |||
3 | +++ database/schema/security.cfg 2011-01-27 17:17:51 +0000 | |||
4 | @@ -1363,6 +1363,7 @@ | |||
5 | 1363 | public.sourcepackagepublishinghistory = SELECT, INSERT, UPDATE | 1363 | public.sourcepackagepublishinghistory = SELECT, INSERT, UPDATE |
6 | 1364 | public.distributionsourcepackage = SELECT, INSERT, UPDATE | 1364 | public.distributionsourcepackage = SELECT, INSERT, UPDATE |
7 | 1365 | public.binarypackagepublishinghistory = SELECT, INSERT, UPDATE | 1365 | public.binarypackagepublishinghistory = SELECT, INSERT, UPDATE |
8 | 1366 | public.sourcepackagerecipebuild = SELECT | ||
9 | 1366 | public.sourcepackagerecipebuildjob = SELECT, INSERT, UPDATE | 1367 | public.sourcepackagerecipebuildjob = SELECT, INSERT, UPDATE |
10 | 1367 | public.component = SELECT | 1368 | public.component = SELECT |
11 | 1368 | public.section = SELECT | 1369 | public.section = SELECT |
12 | 1369 | 1370 | ||
13 | === modified file 'lib/lp/archiveuploader/tests/nascentupload-announcements.txt' | |||
14 | --- lib/lp/archiveuploader/tests/nascentupload-announcements.txt 2010-12-23 12:16:57 +0000 | |||
15 | +++ lib/lp/archiveuploader/tests/nascentupload-announcements.txt 2011-01-27 17:17:51 +0000 | |||
16 | @@ -1,4 +1,5 @@ | |||
18 | 1 | = NascentUpload Announcements = | 1 | NascentUpload Announcements |
19 | 2 | =========================== | ||
20 | 2 | 3 | ||
21 | 3 | NascentUpload announces uploads according its final status (NEW, | 4 | NascentUpload announces uploads according its final status (NEW, |
22 | 4 | AUTO-APPROVED, UNAPPROVED) and its destination pocket: | 5 | AUTO-APPROVED, UNAPPROVED) and its destination pocket: |
23 | @@ -32,272 +33,275 @@ | |||
24 | 32 | 33 | ||
25 | 33 | We need to be logged into the security model in order to get any further | 34 | We need to be logged into the security model in order to get any further |
26 | 34 | 35 | ||
30 | 35 | >>> from canonical.testing.layers import LaunchpadZopelessLayer | 36 | >>> from canonical.testing.layers import LaunchpadZopelessLayer |
31 | 36 | >>> LaunchpadZopelessLayer.switchDbUser('launchpad') | 37 | >>> LaunchpadZopelessLayer.switchDbUser('launchpad') |
32 | 37 | >>> login('foo.bar@canonical.com') | 38 | >>> login('foo.bar@canonical.com') |
33 | 38 | 39 | ||
34 | 39 | Helper functions to examine emails that were sent: | 40 | Helper functions to examine emails that were sent: |
35 | 40 | 41 | ||
45 | 41 | >>> from lp.services.mail import stub | 42 | >>> from lp.services.mail import stub |
46 | 42 | >>> from lp.testing.mail_helpers import pop_notifications | 43 | >>> from lp.testing.mail_helpers import pop_notifications |
47 | 43 | 44 | ||
48 | 44 | >>> def by_to_addrs(a, b): | 45 | >>> def by_to_addrs(a, b): |
49 | 45 | ... return cmp(a[1], b[1]) | 46 | ... return cmp(a[1], b[1]) |
50 | 46 | 47 | ||
51 | 47 | >>> def print_addrlist(field): | 48 | >>> def print_addrlist(field): |
52 | 48 | ... for entry in field.split(','): | 49 | ... for entry in field.split(','): |
53 | 49 | ... print entry.strip() | 50 | ... print entry.strip() |
54 | 50 | 51 | ||
55 | 51 | Import the test keys to use 'insecure' policy. | 52 | Import the test keys to use 'insecure' policy. |
56 | 52 | 53 | ||
59 | 53 | >>> from canonical.launchpad.ftests import import_public_test_keys | 54 | >>> from canonical.launchpad.ftests import import_public_test_keys |
60 | 54 | >>> import_public_test_keys() | 55 | >>> import_public_test_keys() |
61 | 55 | 56 | ||
62 | 56 | For the purpose of this test, hoary needs to be an open (development) | 57 | For the purpose of this test, hoary needs to be an open (development) |
63 | 57 | distroseries so that we can upload to it. Also adjust 'changeslist' | 58 | distroseries so that we can upload to it. Also adjust 'changeslist' |
64 | 58 | address and allow uploads to universe: | 59 | address and allow uploads to universe: |
65 | 59 | 60 | ||
75 | 60 | >>> from canonical.launchpad.interfaces.librarian import ILibraryFileAliasSet | 61 | >>> from canonical.launchpad.interfaces.librarian import ( |
76 | 61 | >>> from lp.registry.interfaces.distribution import IDistributionSet | 62 | ... ILibraryFileAliasSet, |
77 | 62 | >>> from lp.registry.interfaces.series import SeriesStatus | 63 | ... ) |
78 | 63 | >>> ubuntu = getUtility(IDistributionSet)['ubuntu'] | 64 | >>> from lp.registry.interfaces.distribution import IDistributionSet |
79 | 64 | >>> hoary = ubuntu['hoary'] | 65 | >>> from lp.registry.interfaces.series import SeriesStatus |
80 | 65 | >>> hoary.status = SeriesStatus.DEVELOPMENT | 66 | >>> ubuntu = getUtility(IDistributionSet)['ubuntu'] |
81 | 66 | >>> hoary.changeslist = "hoary-announce@lists.ubuntu.com" | 67 | >>> hoary = ubuntu['hoary'] |
82 | 67 | >>> fake_chroot = getUtility(ILibraryFileAliasSet)[1] | 68 | >>> hoary.status = SeriesStatus.DEVELOPMENT |
83 | 68 | >>> trash = hoary['hppa'].addOrUpdateChroot(fake_chroot) | 69 | >>> hoary.changeslist = "hoary-announce@lists.ubuntu.com" |
84 | 70 | >>> fake_chroot = getUtility(ILibraryFileAliasSet)[1] | ||
85 | 71 | >>> trash = hoary['hppa'].addOrUpdateChroot(fake_chroot) | ||
86 | 69 | 72 | ||
87 | 70 | NEW source upload to RELEASE pocket via 'sync' policy (it presents | 73 | NEW source upload to RELEASE pocket via 'sync' policy (it presents |
88 | 71 | the same behaviour than using insecure policy, apart from allowing | 74 | the same behaviour than using insecure policy, apart from allowing |
89 | 72 | unsigned changes): | 75 | unsigned changes): |
90 | 73 | 76 | ||
119 | 74 | >>> from lp.archiveuploader.nascentupload import NascentUpload | 77 | >>> from lp.archiveuploader.nascentupload import NascentUpload |
120 | 75 | >>> from lp.archiveuploader.tests import datadir, getPolicy | 78 | >>> from lp.archiveuploader.tests import datadir, getPolicy |
121 | 76 | 79 | ||
122 | 77 | >>> sync_policy = getPolicy( | 80 | >>> sync_policy = getPolicy( |
123 | 78 | ... name='sync', distro='ubuntu', distroseries='hoary') | 81 | ... name='sync', distro='ubuntu', distroseries='hoary') |
124 | 79 | 82 | ||
125 | 80 | >>> from lp.services.log.logger import DevNullLogger | 83 | >>> from lp.services.log.logger import DevNullLogger |
126 | 81 | >>> bar_src = NascentUpload.from_changesfile_path( | 84 | >>> bar_src = NascentUpload.from_changesfile_path( |
127 | 82 | ... datadir('suite/bar_1.0-1/bar_1.0-1_source.changes'), | 85 | ... datadir('suite/bar_1.0-1/bar_1.0-1_source.changes'), |
128 | 83 | ... sync_policy, DevNullLogger()) | 86 | ... sync_policy, DevNullLogger()) |
129 | 84 | >>> bar_src.process() | 87 | >>> bar_src.process() |
130 | 85 | 88 | ||
131 | 86 | >>> from lp.services.log.logger import FakeLogger | 89 | >>> from lp.services.log.logger import FakeLogger |
132 | 87 | >>> bar_src.logger = FakeLogger() | 90 | >>> bar_src.logger = FakeLogger() |
133 | 88 | >>> result = bar_src.do_accept() | 91 | >>> result = bar_src.do_accept() |
134 | 89 | DEBUG Creating queue entry | 92 | DEBUG Creating queue entry |
135 | 90 | ... | 93 | ... |
136 | 91 | DEBUG Sent a mail: | 94 | DEBUG Sent a mail: |
137 | 92 | ... | 95 | ... |
138 | 93 | DEBUG NEW: bar_1.0.orig.tar.gz | 96 | DEBUG NEW: bar_1.0.orig.tar.gz |
139 | 94 | DEBUG NEW: bar_1.0-1.diff.gz | 97 | DEBUG NEW: bar_1.0-1.diff.gz |
140 | 95 | DEBUG NEW: bar_1.0-1.dsc | 98 | DEBUG NEW: bar_1.0-1.dsc |
141 | 96 | ... | 99 | ... |
142 | 97 | DEBUG above if files already exist in other distroseries. | 100 | DEBUG above if files already exist in other distroseries. |
143 | 98 | ... | 101 | ... |
144 | 99 | DEBUG -- | 102 | DEBUG -- |
145 | 100 | DEBUG You are receiving this email because you are the uploader, maintainer or | 103 | DEBUG You are receiving this email because you are the uploader, |
146 | 101 | DEBUG signer of the above package. | 104 | maintainer or |
147 | 105 | DEBUG signer of the above package. | ||
148 | 102 | 106 | ||
149 | 103 | There is only one email generated: | 107 | There is only one email generated: |
150 | 104 | 108 | ||
161 | 105 | >>> [notification] = pop_notifications() | 109 | >>> [notification] = pop_notifications() |
162 | 106 | 110 | ||
163 | 107 | >>> notification['X-Katie'] | 111 | >>> notification['X-Katie'] |
164 | 108 | 'Launchpad actually' | 112 | 'Launchpad actually' |
165 | 109 | 113 | ||
166 | 110 | >>> notification['Subject'] | 114 | >>> notification['Subject'] |
167 | 111 | '[ubuntu/hoary] bar 1.0-1 (New)' | 115 | '[ubuntu/hoary] bar 1.0-1 (New)' |
168 | 112 | 116 | ||
169 | 113 | >>> print_addrlist(notification['To']) | 117 | >>> print_addrlist(notification['To']) |
170 | 114 | Daniel Silverstone <daniel.silverstone@canonical.com> | 118 | Daniel Silverstone <daniel.silverstone@canonical.com> |
171 | 115 | 119 | ||
172 | 116 | Let's ACCEPT bar sources in order to make the next uploads of this | 120 | Let's ACCEPT bar sources in order to make the next uploads of this |
173 | 117 | series *known* in hoary: | 121 | series *known* in hoary: |
174 | 118 | 122 | ||
177 | 119 | >>> bar_src.queue_root.setAccepted() | 123 | >>> bar_src.queue_root.setAccepted() |
178 | 120 | >>> pub_records = bar_src.queue_root.realiseUpload() | 124 | >>> pub_records = bar_src.queue_root.realiseUpload() |
179 | 121 | 125 | ||
180 | 122 | Make the uploaded orig file available to librarian lookups | 126 | Make the uploaded orig file available to librarian lookups |
181 | 123 | 127 | ||
184 | 124 | >>> import transaction | 128 | >>> import transaction |
185 | 125 | >>> transaction.commit() | 129 | >>> transaction.commit() |
186 | 126 | 130 | ||
187 | 127 | Ensure the previous transaction is *really* in the database before the next | 131 | Ensure the previous transaction is *really* in the database before the next |
188 | 128 | test: | 132 | test: |
189 | 129 | 133 | ||
192 | 130 | >>> from canonical.launchpad.ftests import syncUpdate | 134 | >>> from canonical.launchpad.ftests import syncUpdate |
193 | 131 | >>> syncUpdate(bar_src.queue_root) | 135 | >>> syncUpdate(bar_src.queue_root) |
194 | 132 | 136 | ||
195 | 133 | Uploading the same package again will result in a rejection email: | 137 | Uploading the same package again will result in a rejection email: |
196 | 134 | 138 | ||
224 | 135 | >>> bar_src = NascentUpload.from_changesfile_path( | 139 | >>> bar_src = NascentUpload.from_changesfile_path( |
225 | 136 | ... datadir('suite/bar_1.0-1/bar_1.0-1_source.changes'), | 140 | ... datadir('suite/bar_1.0-1/bar_1.0-1_source.changes'), |
226 | 137 | ... sync_policy, DevNullLogger()) | 141 | ... sync_policy, DevNullLogger()) |
227 | 138 | >>> bar_src.process() | 142 | >>> bar_src.process() |
228 | 139 | 143 | ||
229 | 140 | >>> bar_src.logger = FakeLogger() | 144 | >>> bar_src.logger = FakeLogger() |
230 | 141 | >>> result = bar_src.do_accept() | 145 | >>> result = bar_src.do_accept() |
231 | 142 | DEBUG Creating queue entry | 146 | DEBUG Creating queue entry |
232 | 143 | DEBUG bar diff from 1.0-1 to 1.0-1 requested | 147 | DEBUG bar diff from 1.0-1 to 1.0-1 requested |
233 | 144 | DEBUG Setting it to ACCEPTED | 148 | DEBUG Setting it to ACCEPTED |
234 | 145 | ... | 149 | ... |
235 | 146 | DEBUG Sending rejection email. | 150 | DEBUG Sending rejection email. |
236 | 147 | ... | 151 | ... |
237 | 148 | DEBUG Rejected: | 152 | DEBUG Rejected: |
238 | 149 | DEBUG The source bar - 1.0-1 is already accepted in ubuntu/hoary | 153 | DEBUG The source bar - 1.0-1 is already accepted in ubuntu/hoary |
239 | 150 | and you cannot upload the same version within the same | 154 | and you cannot upload the same version within the same |
240 | 151 | distribution. You have to modify the source version and | 155 | distribution. You have to modify the source version and |
241 | 152 | re-upload. | 156 | re-upload. |
242 | 153 | ... | 157 | ... |
243 | 154 | 158 | ||
244 | 155 | >>> [notification] = pop_notifications() | 159 | >>> [notification] = pop_notifications() |
245 | 156 | 160 | ||
246 | 157 | >>> notification['X-Katie'] | 161 | >>> notification['X-Katie'] |
247 | 158 | 'Launchpad actually' | 162 | 'Launchpad actually' |
248 | 159 | 163 | ||
249 | 160 | >>> print_addrlist(notification['To']) | 164 | >>> print_addrlist(notification['To']) |
250 | 161 | Daniel Silverstone <daniel.silverstone@canonical.com> | 165 | Daniel Silverstone <daniel.silverstone@canonical.com> |
251 | 162 | 166 | ||
252 | 163 | Upload notifications from primary archive do not contain the | 167 | Upload notifications from primary archive do not contain the |
253 | 164 | 'X-Launchpad-PPA' header, since it doesn't apply to this context. | 168 | 'X-Launchpad-PPA' header, since it doesn't apply to this context. |
254 | 165 | 169 | ||
257 | 166 | >>> 'X-Launchpad-PPA' in notification.keys() | 170 | >>> 'X-Launchpad-PPA' in notification.keys() |
258 | 167 | False | 171 | False |
259 | 168 | 172 | ||
260 | 169 | Notifications for source uploads will contain the 'X-Launchpad-Component' | 173 | Notifications for source uploads will contain the 'X-Launchpad-Component' |
261 | 170 | header however. | 174 | header however. |
262 | 171 | 175 | ||
265 | 172 | >>> 'X-Launchpad-Component' in notification.keys() | 176 | >>> 'X-Launchpad-Component' in notification.keys() |
266 | 173 | True | 177 | True |
267 | 174 | 178 | ||
270 | 175 | >>> notification['X-Launchpad-Component'] | 179 | >>> notification['X-Launchpad-Component'] |
271 | 176 | 'component=universe, section=devel' | 180 | 'component=universe, section=devel' |
272 | 177 | 181 | ||
273 | 178 | This is the body of the rejection email. | 182 | This is the body of the rejection email. |
274 | 179 | 183 | ||
305 | 180 | >>> body = notification.get_payload()[0] | 184 | >>> body = notification.get_payload()[0] |
306 | 181 | >>> print body.as_string() # doctest: -NORMALIZE_WHITESPACE | 185 | >>> print body.as_string() # doctest: -NORMALIZE_WHITESPACE |
307 | 182 | Content-Type: text/plain; charset="utf-8" | 186 | Content-Type: text/plain; charset="utf-8" |
308 | 183 | MIME-Version: 1.0 | 187 | MIME-Version: 1.0 |
309 | 184 | Content-Transfer-Encoding: quoted-printable | 188 | Content-Transfer-Encoding: quoted-printable |
310 | 185 | <BLANKLINE> | 189 | <BLANKLINE> |
311 | 186 | Rejected: | 190 | Rejected: |
312 | 187 | The source bar - 1.0-1 is already accepted in ubuntu/hoary and you cannot u= | 191 | The source bar - 1.0-1 is already accepted in ubuntu/hoary and you cannot u= |
313 | 188 | pload the same version within the same distribution. You have to modify the= | 192 | pload the same version within the same distribution. You have to modify the= |
314 | 189 | source version and re-upload. | 193 | source version and re-upload. |
315 | 190 | <BLANKLINE> | 194 | <BLANKLINE> |
316 | 191 | bar (1.0-1) breezy; urgency=3Dlow | 195 | bar (1.0-1) breezy; urgency=3Dlow |
317 | 192 | <BLANKLINE> | 196 | <BLANKLINE> |
318 | 193 | * Initial version | 197 | * Initial version |
319 | 194 | <BLANKLINE> | 198 | <BLANKLINE> |
320 | 195 | Date: Thu, 16 Feb 2006 15:34:09 +0000 | 199 | Date: Thu, 16 Feb 2006 15:34:09 +0000 |
321 | 196 | Changed-By: Daniel Silverstone <daniel.silverstone@canonical.com> | 200 | Changed-By: Daniel Silverstone <daniel.silverstone@canonical.com> |
322 | 197 | Maintainer: Launchpad team <launchpad@lists.canonical.com> | 201 | Maintainer: Launchpad team <launchpad@lists.canonical.com> |
323 | 198 | <BLANKLINE> | 202 | <BLANKLINE> |
324 | 199 | =3D=3D=3D | 203 | =3D=3D=3D |
325 | 200 | <BLANKLINE> | 204 | <BLANKLINE> |
326 | 201 | If you don't understand why your files were rejected, or if the | 205 | If you don't understand why your files were rejected, or if the |
327 | 202 | override file requires editing, please go to: | 206 | override file requires editing, please go to: |
328 | 203 | http://answers.launchpad.net/soyuz | 207 | http://answers.launchpad.net/soyuz |
329 | 204 | <BLANKLINE> | 208 | <BLANKLINE> |
330 | 205 | -- = | 209 | -- = |
331 | 206 | <BLANKLINE> | 210 | <BLANKLINE> |
332 | 207 | You are receiving this email because you are the uploader, maintainer or | 211 | You are receiving this email because you are the uploader, maintainer or |
333 | 208 | signer of the above package. | 212 | signer of the above package. |
334 | 209 | <BLANKLINE> | 213 | <BLANKLINE> |
335 | 210 | 214 | ||
336 | 211 | In order to facilitate automated processing of announcement emails, the | 215 | In order to facilitate automated processing of announcement emails, the |
337 | 212 | changes file is enclosed as an attachment. | 216 | changes file is enclosed as an attachment. |
338 | 213 | 217 | ||
381 | 214 | >>> attachment = notification.get_payload()[1] | 218 | >>> attachment = notification.get_payload()[1] |
382 | 215 | >>> print attachment.as_string() # doctest: -NORMALIZE_WHITESPACE | 219 | >>> print attachment.as_string() # doctest: -NORMALIZE_WHITESPACE |
383 | 216 | Content-Type: text/plain; charset="utf-8" | 220 | Content-Type: text/plain; charset="utf-8" |
384 | 217 | MIME-Version: 1.0 | 221 | MIME-Version: 1.0 |
385 | 218 | Content-Transfer-Encoding: quoted-printable | 222 | Content-Transfer-Encoding: quoted-printable |
386 | 219 | Content-Disposition: attachment; filename="changesfile" | 223 | Content-Disposition: attachment; filename="changesfile" |
387 | 220 | <BLANKLINE> | 224 | <BLANKLINE> |
388 | 221 | -----BEGIN PGP SIGNED MESSAGE----- | 225 | -----BEGIN PGP SIGNED MESSAGE----- |
389 | 222 | Hash: SHA1 | 226 | Hash: SHA1 |
390 | 223 | <BLANKLINE> | 227 | <BLANKLINE> |
391 | 224 | Format: 1.7 | 228 | Format: 1.7 |
392 | 225 | Date: Thu, 16 Feb 2006 15:34:09 +0000 | 229 | Date: Thu, 16 Feb 2006 15:34:09 +0000 |
393 | 226 | Source: bar | 230 | Source: bar |
394 | 227 | Binary: bar | 231 | Binary: bar |
395 | 228 | Architecture: source | 232 | Architecture: source |
396 | 229 | Version: 1.0-1 | 233 | Version: 1.0-1 |
397 | 230 | Distribution: breezy | 234 | Distribution: breezy |
398 | 231 | Urgency: low | 235 | Urgency: low |
399 | 232 | Maintainer: Launchpad team <launchpad@lists.canonical.com> | 236 | Maintainer: Launchpad team <launchpad@lists.canonical.com> |
400 | 233 | Changed-By: Daniel Silverstone <daniel.silverstone@canonical.com> | 237 | Changed-By: Daniel Silverstone <daniel.silverstone@canonical.com> |
401 | 234 | Description: = | 238 | Description: = |
402 | 235 | <BLANKLINE> | 239 | <BLANKLINE> |
403 | 236 | bar - Stuff for testing | 240 | bar - Stuff for testing |
404 | 237 | Changes: = | 241 | Changes: = |
405 | 238 | <BLANKLINE> | 242 | <BLANKLINE> |
406 | 239 | bar (1.0-1) breezy; urgency=3Dlow | 243 | bar (1.0-1) breezy; urgency=3Dlow |
407 | 240 | . | 244 | . |
408 | 241 | * Initial version | 245 | * Initial version |
409 | 242 | Files: = | 246 | Files: = |
410 | 243 | <BLANKLINE> | 247 | <BLANKLINE> |
411 | 244 | 5d533778b698edc1a122098a98c8490e 512 devel optional bar_1.0-1.dsc | 248 | 5d533778b698edc1a122098a98c8490e 512 devel optional bar_1.0-1.dsc |
412 | 245 | fc1464e5985b962a042d5354452f361d 164 devel optional bar_1.0.orig.tar.gz | 249 | fc1464e5985b962a042d5354452f361d 164 devel optional bar_1.0.orig.tar.gz |
413 | 246 | 1e35b810764f140af9616de8274e6e73 537 devel optional bar_1.0-1.diff.gz | 250 | 1e35b810764f140af9616de8274e6e73 537 devel optional bar_1.0-1.diff.gz |
414 | 247 | <BLANKLINE> | 251 | <BLANKLINE> |
415 | 248 | -----BEGIN PGP SIGNATURE----- | 252 | -----BEGIN PGP SIGNATURE----- |
416 | 249 | Version: GnuPG v1.4.3 (GNU/Linux) | 253 | Version: GnuPG v1.4.3 (GNU/Linux) |
417 | 250 | <BLANKLINE> | 254 | <BLANKLINE> |
418 | 251 | iD8DBQFFt7D9jn63CGxkqMURAk1BAJwIQfOMS+l9lDDwPORtuZb3hFI2OgCaArNc | 255 | iD8DBQFFt7D9jn63CGxkqMURAk1BAJwIQfOMS+l9lDDwPORtuZb3hFI2OgCaArNc |
419 | 252 | oH5uIHeKtedJa5Ekpcfi2bY=3D | 256 | oH5uIHeKtedJa5Ekpcfi2bY=3D |
420 | 253 | =3DDMqI | 257 | =3DDMqI |
421 | 254 | -----END PGP SIGNATURE----- | 258 | -----END PGP SIGNATURE----- |
422 | 255 | <BLANKLINE> | 259 | <BLANKLINE> |
423 | 256 | 260 | ||
424 | 257 | A PPA upload will contain the X-Launchpad-PPA header. | 261 | A PPA upload will contain the X-Launchpad-PPA header. |
425 | 258 | 262 | ||
454 | 259 | >>> from lp.registry.interfaces.distribution import IDistributionSet | 263 | >>> from lp.registry.interfaces.distribution import IDistributionSet |
455 | 260 | >>> from lp.registry.interfaces.person import IPersonSet | 264 | >>> from lp.registry.interfaces.person import IPersonSet |
456 | 261 | >>> from lp.soyuz.enums import ArchivePurpose | 265 | >>> from lp.soyuz.enums import ArchivePurpose |
457 | 262 | >>> from lp.soyuz.interfaces.archive import IArchiveSet | 266 | >>> from lp.soyuz.interfaces.archive import IArchiveSet |
458 | 263 | 267 | ||
459 | 264 | >>> ubuntu = getUtility(IDistributionSet)['ubuntu'] | 268 | >>> ubuntu = getUtility(IDistributionSet)['ubuntu'] |
460 | 265 | >>> name16 = getUtility(IPersonSet).getByName('name16') | 269 | >>> name16 = getUtility(IPersonSet).getByName('name16') |
461 | 266 | >>> name16_ppa = getUtility(IArchiveSet).new( | 270 | >>> name16_ppa = getUtility(IArchiveSet).new( |
462 | 267 | ... owner=name16, distribution=ubuntu, purpose=ArchivePurpose.PPA) | 271 | ... owner=name16, distribution=ubuntu, purpose=ArchivePurpose.PPA) |
463 | 268 | 272 | ||
464 | 269 | >>> ppa_policy = getPolicy( | 273 | >>> ppa_policy = getPolicy( |
465 | 270 | ... name='insecure', distro='ubuntu', distroseries=None) | 274 | ... name='insecure', distro='ubuntu', distroseries=None) |
466 | 271 | >>> ppa_policy.archive = name16_ppa | 275 | >>> ppa_policy.archive = name16_ppa |
467 | 272 | >>> ppa_policy.setDistroSeriesAndPocket('hoary') | 276 | >>> ppa_policy.setDistroSeriesAndPocket('hoary') |
468 | 273 | 277 | ||
469 | 274 | >>> ppa_bar_src = NascentUpload.from_changesfile_path( | 278 | >>> ppa_bar_src = NascentUpload.from_changesfile_path( |
470 | 275 | ... datadir('suite/bar_1.0-1/bar_1.0-1_source.changes'), | 279 | ... datadir('suite/bar_1.0-1/bar_1.0-1_source.changes'), |
471 | 276 | ... ppa_policy, DevNullLogger()) | 280 | ... ppa_policy, DevNullLogger()) |
472 | 277 | >>> ppa_bar_src.process() | 281 | >>> ppa_bar_src.process() |
473 | 278 | >>> result = ppa_bar_src.do_accept() | 282 | >>> result = ppa_bar_src.do_accept() |
474 | 279 | 283 | ||
475 | 280 | >>> [notification] = pop_notifications() | 284 | >>> [notification] = pop_notifications() |
476 | 281 | 285 | ||
477 | 282 | >>> notification['X-Katie'] | 286 | >>> notification['X-Katie'] |
478 | 283 | 'Launchpad actually' | 287 | 'Launchpad actually' |
479 | 284 | 288 | ||
480 | 285 | >>> print_addrlist(notification['To']) | 289 | >>> print_addrlist(notification['To']) |
481 | 286 | Foo Bar <foo.bar@canonical.com> | 290 | Foo Bar <foo.bar@canonical.com> |
482 | 287 | 291 | ||
483 | 288 | On PPA upload notifications the 'X-Launchpad-PPA' is present and | 292 | On PPA upload notifications the 'X-Launchpad-PPA' is present and |
484 | 289 | contains the target PPA owner account name. | 293 | contains the target PPA owner account name. |
485 | 290 | 294 | ||
488 | 291 | >>> notification['X-Launchpad-PPA'] | 295 | >>> notification['X-Launchpad-PPA'] |
489 | 292 | 'name16' | 296 | 'name16' |
490 | 293 | 297 | ||
491 | 294 | However, PPA upload notifications do not contain an attachment with the | 298 | However, PPA upload notifications do not contain an attachment with the |
492 | 295 | original changesfile. | 299 | original changesfile. |
493 | 296 | 300 | ||
498 | 297 | >>> attachment = notification.get_payload()[1] | 301 | >>> attachment = notification.get_payload()[1] |
499 | 298 | Traceback (most recent call last): | 302 | Traceback (most recent call last): |
500 | 299 | ... | 303 | ... |
501 | 300 | IndexError: list index out of range | 304 | IndexError: list index out of range |
502 | 301 | 305 | ||
503 | 302 | See further tests upon PPA upload notifications on | 306 | See further tests upon PPA upload notifications on |
504 | 303 | archiveuploader/ftests/test_ppauploadprocessor. | 307 | archiveuploader/ftests/test_ppauploadprocessor. |
505 | @@ -305,234 +309,240 @@ | |||
506 | 305 | NEW binary upload to RELEASE pocket via 'sync' policy (we need to | 309 | NEW binary upload to RELEASE pocket via 'sync' policy (we need to |
507 | 306 | override sync policy to allow binary uploads): | 310 | override sync policy to allow binary uploads): |
508 | 307 | 311 | ||
523 | 308 | >>> from lp.archiveuploader.uploadpolicy import ArchiveUploadType | 312 | >>> from lp.archiveuploader.uploadpolicy import ArchiveUploadType |
524 | 309 | >>> modified_sync_policy = getPolicy( | 313 | >>> modified_sync_policy = getPolicy( |
525 | 310 | ... name='sync', distro='ubuntu', distroseries='hoary') | 314 | ... name='sync', distro='ubuntu', distroseries='hoary') |
526 | 311 | >>> modified_sync_policy.accepted_type = ArchiveUploadType.BINARY_ONLY | 315 | >>> modified_sync_policy.accepted_type = ArchiveUploadType.BINARY_ONLY |
527 | 312 | 316 | ||
528 | 313 | >>> bar_src = NascentUpload.from_changesfile_path( | 317 | >>> bar_src = NascentUpload.from_changesfile_path( |
529 | 314 | ... datadir('suite/bar_1.0-1_binary/bar_1.0-1_i386.changes'), | 318 | ... datadir('suite/bar_1.0-1_binary/bar_1.0-1_i386.changes'), |
530 | 315 | ... modified_sync_policy, DevNullLogger()) | 319 | ... modified_sync_policy, DevNullLogger()) |
531 | 316 | >>> bar_src.process() | 320 | >>> bar_src.process() |
532 | 317 | 321 | ||
533 | 318 | >>> bar_src.logger = FakeLogger() | 322 | >>> bar_src.logger = FakeLogger() |
534 | 319 | >>> result = bar_src.do_accept() | 323 | >>> result = bar_src.do_accept() |
535 | 320 | DEBUG Creating queue entry | 324 | DEBUG Creating queue entry |
536 | 321 | DEBUG Not sending email, upload contains binaries. | 325 | DEBUG Not sending email; upload is from a build. |
537 | 322 | 326 | ||
538 | 323 | We simply ignore messages generated at this step because they are not | 327 | We simply ignore messages generated at this step because they are not |
539 | 324 | going to exist in production. We simply need this binary to be published | 328 | going to exist in production. We simply need this binary to be published |
540 | 325 | in order to test other features in post-release pockets. | 329 | in order to test other features in post-release pockets. |
541 | 326 | 330 | ||
543 | 327 | >>> ignore = pop_notifications() | 331 | >>> ignore = pop_notifications() |
544 | 328 | 332 | ||
545 | 329 | Let's accept & publish bar binary in order to make the next uploads of | 333 | Let's accept & publish bar binary in order to make the next uploads of |
546 | 330 | this series *known* in hoary: | 334 | this series *known* in hoary: |
547 | 331 | 335 | ||
550 | 332 | >>> bar_src.queue_root.setAccepted() | 336 | >>> bar_src.queue_root.setAccepted() |
551 | 333 | >>> pub_records = bar_src.queue_root.realiseUpload() | 337 | >>> pub_records = bar_src.queue_root.realiseUpload() |
552 | 334 | 338 | ||
553 | 335 | 339 | ||
554 | 336 | NEW source uploads for 'translations' section via sync policy: | 340 | NEW source uploads for 'translations' section via sync policy: |
555 | 337 | 341 | ||
571 | 338 | >>> modified_sync_policy = getPolicy( | 342 | >>> modified_sync_policy = getPolicy( |
572 | 339 | ... name='sync', distro='ubuntu', distroseries='hoary') | 343 | ... name='sync', distro='ubuntu', distroseries='hoary') |
573 | 340 | 344 | ||
574 | 341 | >>> lang_pack = NascentUpload.from_changesfile_path( | 345 | >>> lang_pack = NascentUpload.from_changesfile_path( |
575 | 342 | ... datadir('language-packs/language-pack-pt_1.0-1_source.changes'), | 346 | ... datadir('language-packs/language-pack-pt_1.0-1_source.changes'), |
576 | 343 | ... modified_sync_policy, DevNullLogger()) | 347 | ... modified_sync_policy, DevNullLogger()) |
577 | 344 | >>> lang_pack.process() | 348 | >>> lang_pack.process() |
578 | 345 | 349 | ||
579 | 346 | >>> lang_pack.logger = FakeLogger() | 350 | >>> lang_pack.logger = FakeLogger() |
580 | 347 | >>> result = lang_pack.do_accept() | 351 | >>> result = lang_pack.do_accept() |
581 | 348 | DEBUG Creating queue entry | 352 | DEBUG Creating queue entry |
582 | 349 | DEBUG Skipping acceptance and announcement, it is a language-package upload. | 353 | DEBUG Skipping acceptance and announcement, it is a language-package |
583 | 350 | 354 | upload. | |
584 | 351 | >>> lang_pack.queue_root.status.name | 355 | |
585 | 352 | 'NEW' | 356 | >>> lang_pack.queue_root.status.name |
586 | 357 | 'NEW' | ||
587 | 353 | 358 | ||
588 | 354 | No messages were generated since this upload is targeted for the | 359 | No messages were generated since this upload is targeted for the |
589 | 355 | 'translation' section: | 360 | 'translation' section: |
590 | 356 | 361 | ||
594 | 357 | >>> transaction.commit() | 362 | >>> transaction.commit() |
595 | 358 | >>> len(stub.test_emails) | 363 | >>> len(stub.test_emails) |
596 | 359 | 0 | 364 | 0 |
597 | 360 | 365 | ||
598 | 361 | Accept and publish this series: | 366 | Accept and publish this series: |
599 | 362 | 367 | ||
602 | 363 | >>> lang_pack.queue_root.setAccepted() | 368 | >>> lang_pack.queue_root.setAccepted() |
603 | 364 | >>> pub_records = lang_pack.queue_root.realiseUpload() | 369 | >>> pub_records = lang_pack.queue_root.realiseUpload() |
604 | 365 | 370 | ||
605 | 366 | 371 | ||
606 | 367 | AUTO_APPROVED source uploads for 'translations' section: | 372 | AUTO_APPROVED source uploads for 'translations' section: |
607 | 368 | 373 | ||
624 | 369 | >>> modified_sync_policy = getPolicy( | 374 | >>> modified_sync_policy = getPolicy( |
625 | 370 | ... name='sync', distro='ubuntu', distroseries='hoary') | 375 | ... name='sync', distro='ubuntu', distroseries='hoary') |
626 | 371 | 376 | ||
627 | 372 | >>> lang_pack = NascentUpload.from_changesfile_path( | 377 | >>> lang_pack = NascentUpload.from_changesfile_path( |
628 | 373 | ... datadir('language-packs/language-pack-pt_1.0-2_source.changes'), | 378 | ... datadir('language-packs/language-pack-pt_1.0-2_source.changes'), |
629 | 374 | ... modified_sync_policy, DevNullLogger()) | 379 | ... modified_sync_policy, DevNullLogger()) |
630 | 375 | >>> lang_pack.process() | 380 | >>> lang_pack.process() |
631 | 376 | 381 | ||
632 | 377 | >>> lang_pack.logger = FakeLogger() | 382 | >>> lang_pack.logger = FakeLogger() |
633 | 378 | >>> result = lang_pack.do_accept() | 383 | >>> result = lang_pack.do_accept() |
634 | 379 | DEBUG Creating queue entry | 384 | DEBUG Creating queue entry |
635 | 380 | ... | 385 | ... |
636 | 381 | DEBUG Skipping acceptance and announcement, it is a language-package upload. | 386 | DEBUG Skipping acceptance and announcement, it is a language-package |
637 | 382 | 387 | upload. | |
638 | 383 | >>> lang_pack.queue_root.status.name | 388 | |
639 | 384 | 'DONE' | 389 | >>> lang_pack.queue_root.status.name |
640 | 390 | 'DONE' | ||
641 | 385 | 391 | ||
642 | 386 | Again, no messages were generated since this upload is targeted for | 392 | Again, no messages were generated since this upload is targeted for |
643 | 387 | 'translation' section: | 393 | 'translation' section: |
644 | 388 | 394 | ||
648 | 389 | >>> transaction.commit() | 395 | >>> transaction.commit() |
649 | 390 | >>> len(stub.test_emails) | 396 | >>> len(stub.test_emails) |
650 | 391 | 0 | 397 | 0 |
651 | 392 | 398 | ||
652 | 393 | Release hoary, enable uploads to post-release pockets: | 399 | Release hoary, enable uploads to post-release pockets: |
653 | 394 | 400 | ||
655 | 395 | >>> hoary.status = SeriesStatus.CURRENT | 401 | >>> hoary.status = SeriesStatus.CURRENT |
656 | 396 | 402 | ||
657 | 397 | UNAPPROVED source uploads for 'translations' section via insecure: | 403 | UNAPPROVED source uploads for 'translations' section via insecure: |
658 | 398 | 404 | ||
676 | 399 | >>> insecure_policy = getPolicy( | 405 | >>> insecure_policy = getPolicy( |
677 | 400 | ... name='insecure', distro='ubuntu', distroseries=None) | 406 | ... name='insecure', distro='ubuntu', distroseries=None) |
678 | 401 | >>> insecure_policy.setDistroSeriesAndPocket('hoary-updates') | 407 | >>> insecure_policy.setDistroSeriesAndPocket('hoary-updates') |
679 | 402 | 408 | ||
680 | 403 | >>> lang_pack = NascentUpload.from_changesfile_path( | 409 | >>> lang_pack = NascentUpload.from_changesfile_path( |
681 | 404 | ... datadir('language-packs/language-pack-pt_1.0-3_source.changes'), | 410 | ... datadir('language-packs/language-pack-pt_1.0-3_source.changes'), |
682 | 405 | ... insecure_policy, DevNullLogger()) | 411 | ... insecure_policy, DevNullLogger()) |
683 | 406 | >>> lang_pack.process() | 412 | >>> lang_pack.process() |
684 | 407 | >>> lang_pack.logger = FakeLogger() | 413 | >>> lang_pack.logger = FakeLogger() |
685 | 408 | >>> result = lang_pack.do_accept() | 414 | >>> result = lang_pack.do_accept() |
686 | 409 | DEBUG Creating queue entry | 415 | DEBUG Creating queue entry |
687 | 410 | DEBUG language-pack-pt diff from 1.0-2 to 1.0-3 requested | 416 | DEBUG language-pack-pt diff from 1.0-2 to 1.0-3 requested |
688 | 411 | DEBUG Setting it to UNAPPROVED | 417 | DEBUG Setting it to UNAPPROVED |
689 | 412 | DEBUG Skipping acceptance and announcement, it is a language-package upload. | 418 | DEBUG Skipping acceptance and announcement, it is a language-package |
690 | 413 | 419 | upload. | |
691 | 414 | >>> lang_pack.queue_root.status.name | 420 | |
692 | 415 | 'UNAPPROVED' | 421 | >>> lang_pack.queue_root.status.name |
693 | 422 | 'UNAPPROVED' | ||
694 | 416 | 423 | ||
695 | 417 | UNAPPROVED message was also skipped for an upload targeted to | 424 | UNAPPROVED message was also skipped for an upload targeted to |
696 | 418 | 'translation' section: | 425 | 'translation' section: |
697 | 419 | 426 | ||
701 | 420 | >>> transaction.commit() | 427 | >>> transaction.commit() |
702 | 421 | >>> len(stub.test_emails) | 428 | >>> len(stub.test_emails) |
703 | 422 | 0 | 429 | 0 |
704 | 423 | 430 | ||
705 | 424 | 431 | ||
706 | 425 | An UNAPPROVED binary upload via insecure will send one email saying that | 432 | An UNAPPROVED binary upload via insecure will send one email saying that |
707 | 426 | the upload is waiting for approval: | 433 | the upload is waiting for approval: |
708 | 427 | 434 | ||
730 | 428 | >>> bar_src = NascentUpload.from_changesfile_path( | 435 | >>> bar_src = NascentUpload.from_changesfile_path( |
731 | 429 | ... datadir('suite/bar_1.0-2/bar_1.0-2_source.changes'), | 436 | ... datadir('suite/bar_1.0-2/bar_1.0-2_source.changes'), |
732 | 430 | ... insecure_policy, DevNullLogger()) | 437 | ... insecure_policy, DevNullLogger()) |
733 | 431 | >>> bar_src.process() | 438 | >>> bar_src.process() |
734 | 432 | 439 | ||
735 | 433 | >>> bar_src.logger = FakeLogger() | 440 | >>> bar_src.logger = FakeLogger() |
736 | 434 | >>> result = bar_src.do_accept() | 441 | >>> result = bar_src.do_accept() |
737 | 435 | DEBUG Creating queue entry | 442 | DEBUG Creating queue entry |
738 | 436 | ... | 443 | ... |
739 | 437 | 444 | ||
740 | 438 | >>> [notification] = pop_notifications() | 445 | >>> [notification] = pop_notifications() |
741 | 439 | 446 | ||
742 | 440 | >>> notification['X-Katie'] | 447 | >>> notification['X-Katie'] |
743 | 441 | 'Launchpad actually' | 448 | 'Launchpad actually' |
744 | 442 | 449 | ||
745 | 443 | >>> print_addrlist(notification['To']) | 450 | >>> print_addrlist(notification['To']) |
746 | 444 | Foo Bar <foo.bar@canonical.com> | 451 | Foo Bar <foo.bar@canonical.com> |
747 | 445 | Daniel Silverstone <daniel.silverstone@canonical.com> | 452 | Daniel Silverstone <daniel.silverstone@canonical.com> |
748 | 446 | 453 | ||
749 | 447 | >>> notification['Subject'] | 454 | >>> notification['Subject'] |
750 | 448 | '[ubuntu/hoary-updates] bar 1.0-2 (Waiting for approval)' | 455 | '[ubuntu/hoary-updates] bar 1.0-2 (Waiting for approval)' |
751 | 449 | 456 | ||
752 | 450 | 457 | ||
753 | 451 | UNAPPROVED upload to BACKPORTS via insecure policy will send a notification | 458 | UNAPPROVED upload to BACKPORTS via insecure policy will send a notification |
754 | 452 | saying they are waiting for approval: | 459 | saying they are waiting for approval: |
755 | 453 | 460 | ||
781 | 454 | >>> unapproved_backports_policy = getPolicy( | 461 | >>> unapproved_backports_policy = getPolicy( |
782 | 455 | ... name='insecure', distro='ubuntu', distroseries=None) | 462 | ... name='insecure', distro='ubuntu', distroseries=None) |
783 | 456 | >>> unapproved_backports_policy.setDistroSeriesAndPocket('hoary-backports') | 463 | >>> unapproved_backports_policy.setDistroSeriesAndPocket( |
784 | 457 | >>> bar_src = NascentUpload.from_changesfile_path( | 464 | ... 'hoary-backports') |
785 | 458 | ... datadir('suite/bar_1.0-3_valid/bar_1.0-3_source.changes'), | 465 | >>> bar_src = NascentUpload.from_changesfile_path( |
786 | 459 | ... unapproved_backports_policy, DevNullLogger()) | 466 | ... datadir('suite/bar_1.0-3_valid/bar_1.0-3_source.changes'), |
787 | 460 | >>> bar_src.process() | 467 | ... unapproved_backports_policy, DevNullLogger()) |
788 | 461 | >>> bar_src.logger = FakeLogger() | 468 | >>> bar_src.process() |
789 | 462 | >>> result = bar_src.do_accept() | 469 | >>> bar_src.logger = FakeLogger() |
790 | 463 | DEBUG Creating queue entry | 470 | >>> result = bar_src.do_accept() |
791 | 464 | DEBUG bar diff from 1.0-1 to 1.0-3 requested | 471 | DEBUG Creating queue entry |
792 | 465 | DEBUG Setting it to UNAPPROVED | 472 | DEBUG bar diff from 1.0-1 to 1.0-3 requested |
793 | 466 | ... | 473 | DEBUG Setting it to UNAPPROVED |
794 | 467 | 474 | ... | |
795 | 468 | >>> [notification] = pop_notifications() | 475 | |
796 | 469 | 476 | >>> [notification] = pop_notifications() | |
797 | 470 | >>> notification['X-Katie'] | 477 | |
798 | 471 | 'Launchpad actually' | 478 | >>> notification['X-Katie'] |
799 | 472 | 479 | 'Launchpad actually' | |
800 | 473 | >>> print_addrlist(notification['To']) | 480 | |
801 | 474 | Foo Bar <foo.bar@canonical.com> | 481 | >>> print_addrlist(notification['To']) |
802 | 475 | Daniel Silverstone <daniel.silverstone@canonical.com> | 482 | Foo Bar <foo.bar@canonical.com> |
803 | 476 | 483 | Daniel Silverstone <daniel.silverstone@canonical.com> | |
804 | 477 | >>> notification['Subject'] | 484 | |
805 | 478 | '[ubuntu/hoary-backports] bar 1.0-3 (Waiting for approval)' | 485 | >>> notification['Subject'] |
806 | 486 | '[ubuntu/hoary-backports] bar 1.0-3 (Waiting for approval)' | ||
807 | 479 | 487 | ||
808 | 480 | AUTO-APPROVED upload to BACKPORTS pocket via 'sync' policy: | 488 | AUTO-APPROVED upload to BACKPORTS pocket via 'sync' policy: |
809 | 481 | 489 | ||
845 | 482 | >>> modified_sync_policy = getPolicy( | 490 | >>> modified_sync_policy = getPolicy( |
846 | 483 | ... name='sync', distro='ubuntu', distroseries=None) | 491 | ... name='sync', distro='ubuntu', distroseries=None) |
847 | 484 | >>> modified_sync_policy.setDistroSeriesAndPocket('hoary-backports') | 492 | >>> modified_sync_policy.setDistroSeriesAndPocket('hoary-backports') |
848 | 485 | 493 | ||
849 | 486 | >>> bar_src = NascentUpload.from_changesfile_path( | 494 | >>> bar_src = NascentUpload.from_changesfile_path( |
850 | 487 | ... datadir('suite/bar_1.0-4/bar_1.0-4_source.changes'), | 495 | ... datadir('suite/bar_1.0-4/bar_1.0-4_source.changes'), |
851 | 488 | ... modified_sync_policy, DevNullLogger()) | 496 | ... modified_sync_policy, DevNullLogger()) |
852 | 489 | >>> bar_src.process() | 497 | >>> bar_src.process() |
853 | 490 | 498 | ||
854 | 491 | >>> bar_src.logger = FakeLogger() | 499 | >>> bar_src.logger = FakeLogger() |
855 | 492 | >>> result = bar_src.do_accept() | 500 | >>> result = bar_src.do_accept() |
856 | 493 | DEBUG Creating queue entry | 501 | DEBUG Creating queue entry |
857 | 494 | ... | 502 | ... |
858 | 495 | DEBUG Sent a mail: | 503 | DEBUG Sent a mail: |
859 | 496 | DEBUG Subject: [ubuntu/hoary-backports] bar 1.0-4 (Accepted) | 504 | DEBUG Subject: [ubuntu/hoary-backports] bar 1.0-4 (Accepted) |
860 | 497 | DEBUG Recipients: Celso Providelo <celso.providelo@canonical.com> | 505 | DEBUG Recipients: Celso Providelo <celso.providelo@canonical.com> |
861 | 498 | DEBUG Body: | 506 | DEBUG Body: |
862 | 499 | DEBUG bar (1.0-4) breezy; urgency=low | 507 | DEBUG bar (1.0-4) breezy; urgency=low |
863 | 500 | DEBUG | 508 | DEBUG |
864 | 501 | DEBUG * Changer using non-preferred email | 509 | DEBUG * Changer using non-preferred email |
865 | 502 | DEBUG | 510 | DEBUG |
866 | 503 | DEBUG Date: Tue, 25 Apr 2006 10:36:14 -0300 | 511 | DEBUG Date: Tue, 25 Apr 2006 10:36:14 -0300 |
867 | 504 | DEBUG Changed-By: Celso R. Providelo <cprov@ubuntu.com> | 512 | DEBUG Changed-By: Celso R. Providelo <cprov@ubuntu.com> |
868 | 505 | DEBUG Maintainer: Launchpad team <launchpad@lists.canonical.com> | 513 | DEBUG Maintainer: Launchpad team <launchpad@lists.canonical.com> |
869 | 506 | DEBUG http://launchpad.dev/ubuntu/hoary/+source/bar/1.0-4 | 514 | DEBUG http://launchpad.dev/ubuntu/hoary/+source/bar/1.0-4 |
870 | 507 | DEBUG | 515 | DEBUG |
871 | 508 | DEBUG == | 516 | DEBUG == |
872 | 509 | DEBUG | 517 | DEBUG |
873 | 510 | DEBUG Announcing to hoary-announce@lists.ubuntu.com | 518 | DEBUG Announcing to hoary-announce@lists.ubuntu.com |
874 | 511 | DEBUG | 519 | DEBUG |
875 | 512 | DEBUG Thank you for your contribution to Ubuntu Linux. | 520 | DEBUG Thank you for your contribution to Ubuntu Linux. |
876 | 513 | DEBUG | 521 | DEBUG |
877 | 514 | DEBUG -- | 522 | DEBUG -- |
878 | 515 | DEBUG You are receiving this email because you are the uploader, maintainer or | 523 | DEBUG You are receiving this email because you are the uploader, |
879 | 516 | DEBUG signer of the above package. | 524 | maintainer or |
880 | 525 | DEBUG signer of the above package. | ||
881 | 517 | 526 | ||
882 | 518 | There is one email generated: | 527 | There is one email generated: |
883 | 519 | 528 | ||
894 | 520 | >>> [notification] = pop_notifications() | 529 | >>> [notification] = pop_notifications() |
895 | 521 | 530 | ||
896 | 522 | >>> notification['X-Katie'] | 531 | >>> notification['X-Katie'] |
897 | 523 | 'Launchpad actually' | 532 | 'Launchpad actually' |
898 | 524 | 533 | ||
899 | 525 | >>> print_addrlist(notification['To']) | 534 | >>> print_addrlist(notification['To']) |
900 | 526 | Celso Providelo <celso.providelo@canonical.com> | 535 | Celso Providelo <celso.providelo@canonical.com> |
901 | 527 | 536 | ||
902 | 528 | >>> notification['Subject'] | 537 | >>> notification['Subject'] |
903 | 529 | '[ubuntu/hoary-backports] bar 1.0-4 (Accepted)' | 538 | '[ubuntu/hoary-backports] bar 1.0-4 (Accepted)' |
904 | 530 | 539 | ||
905 | 531 | Remove orig.tar.gz pumped from librarian to disk during the upload | 540 | Remove orig.tar.gz pumped from librarian to disk during the upload |
906 | 532 | checks: | 541 | checks: |
907 | 533 | 542 | ||
910 | 534 | >>> import os | 543 | >>> import os |
911 | 535 | >>> os.remove(os.path.join(datadir('suite/bar_1.0-4'), 'bar_1.0.orig.tar.gz')) | 544 | >>> upload_data = datadir('suite/bar_1.0-4') |
912 | 545 | >>> os.remove(os.path.join(upload_data, 'bar_1.0.orig.tar.gz')) | ||
913 | 536 | 546 | ||
914 | 537 | DEBIAN SYNC upload of a source via the 'sync' policy. | 547 | DEBIAN SYNC upload of a source via the 'sync' policy. |
915 | 538 | These uploads do not generate any announcement emails for auto-accepted | 548 | These uploads do not generate any announcement emails for auto-accepted |
916 | @@ -541,88 +551,88 @@ | |||
917 | 541 | Make hoary developmental again, as syncs only happen at that stage of a | 551 | Make hoary developmental again, as syncs only happen at that stage of a |
918 | 542 | distroseries. | 552 | distroseries. |
919 | 543 | 553 | ||
932 | 544 | >>> hoary.status = SeriesStatus.DEVELOPMENT | 554 | >>> hoary.status = SeriesStatus.DEVELOPMENT |
933 | 545 | 555 | ||
934 | 546 | >>> bar_src = NascentUpload.from_changesfile_path( | 556 | >>> bar_src = NascentUpload.from_changesfile_path( |
935 | 547 | ... datadir( | 557 | ... datadir( |
936 | 548 | ... 'suite/bar_1.0-5_debian_auto_sync/bar_1.0-5_source.changes'), | 558 | ... 'suite/bar_1.0-5_debian_auto_sync/bar_1.0-5_source.changes'), |
937 | 549 | ... sync_policy, DevNullLogger()) | 559 | ... sync_policy, DevNullLogger()) |
938 | 550 | >>> bar_src.process() | 560 | >>> bar_src.process() |
939 | 551 | 561 | ||
940 | 552 | >>> bar_src.logger = FakeLogger() | 562 | >>> bar_src.logger = FakeLogger() |
941 | 553 | >>> result = bar_src.do_accept() | 563 | >>> result = bar_src.do_accept() |
942 | 554 | DEBUG Creating queue entry | 564 | DEBUG Creating queue entry |
943 | 555 | ... | 565 | ... |
944 | 556 | 566 | ||
945 | 557 | One email generated: | 567 | One email generated: |
946 | 558 | 568 | ||
950 | 559 | >>> [notification] = pop_notifications() | 569 | >>> [notification] = pop_notifications() |
951 | 560 | >>> notification['Subject'] | 570 | >>> notification['Subject'] |
952 | 561 | '[ubuntu/hoary] bar 1.0-5 (Accepted)' | 571 | '[ubuntu/hoary] bar 1.0-5 (Accepted)' |
953 | 562 | 572 | ||
954 | 563 | 573 | ||
955 | 564 | In contrast, manual sync uploads do generate the announcement: | 574 | In contrast, manual sync uploads do generate the announcement: |
956 | 565 | 575 | ||
962 | 566 | >>> bar_src = NascentUpload.from_changesfile_path( | 576 | >>> bar_src = NascentUpload.from_changesfile_path( |
963 | 567 | ... datadir( | 577 | ... datadir( |
964 | 568 | ... 'suite/bar_1.0-6/bar_1.0-6_source.changes'), | 578 | ... 'suite/bar_1.0-6/bar_1.0-6_source.changes'), |
965 | 569 | ... sync_policy, DevNullLogger()) | 579 | ... sync_policy, DevNullLogger()) |
966 | 570 | >>> bar_src.process() | 580 | >>> bar_src.process() |
967 | 571 | 581 | ||
972 | 572 | >>> bar_src.logger = FakeLogger() | 582 | >>> bar_src.logger = FakeLogger() |
973 | 573 | >>> result = bar_src.do_accept() | 583 | >>> result = bar_src.do_accept() |
974 | 574 | DEBUG Creating queue entry | 584 | DEBUG Creating queue entry |
975 | 575 | ... | 585 | ... |
976 | 576 | 586 | ||
977 | 577 | Two emails generated: | 587 | Two emails generated: |
978 | 578 | 588 | ||
991 | 579 | >>> import operator | 589 | >>> import operator |
992 | 580 | >>> msgs = pop_notifications(sort_key=operator.itemgetter('To')) | 590 | >>> msgs = pop_notifications(sort_key=operator.itemgetter('To')) |
993 | 581 | >>> len(msgs) | 591 | >>> len(msgs) |
994 | 582 | 2 | 592 | 2 |
995 | 583 | 593 | ||
996 | 584 | >>> [message['To'] for message in msgs] | 594 | >>> [message['To'] for message in msgs] |
997 | 585 | ['Celso Providelo <celso.providelo@canonical.com>', | 595 | ['Celso Providelo <celso.providelo@canonical.com>', |
998 | 586 | 'hoary-announce@lists.ubuntu.com'] | 596 | 'hoary-announce@lists.ubuntu.com'] |
999 | 587 | 597 | ||
1000 | 588 | >>> [message['Subject'] for message in msgs] | 598 | >>> [message['Subject'] for message in msgs] |
1001 | 589 | ['[ubuntu/hoary] bar 1.0-6 (Accepted)', | 599 | ['[ubuntu/hoary] bar 1.0-6 (Accepted)', |
1002 | 590 | '[ubuntu/hoary] bar 1.0-6 (Accepted)'] | 600 | '[ubuntu/hoary] bar 1.0-6 (Accepted)'] |
1003 | 591 | 601 | ||
1004 | 592 | Reset hoary back to released and remove disk files created during processing: | 602 | Reset hoary back to released and remove disk files created during processing: |
1005 | 593 | 603 | ||
1011 | 594 | >>> hoary.status = SeriesStatus.CURRENT | 604 | >>> hoary.status = SeriesStatus.CURRENT |
1012 | 595 | >>> os.remove(os.path.join(datadir('suite/bar_1.0-5_debian_auto_sync'), | 605 | >>> os.remove(os.path.join(datadir('suite/bar_1.0-5_debian_auto_sync'), |
1013 | 596 | ... 'bar_1.0.orig.tar.gz')) | 606 | ... 'bar_1.0.orig.tar.gz')) |
1014 | 597 | >>> os.remove(os.path.join(datadir('suite/bar_1.0-6'), | 607 | >>> os.remove(os.path.join(datadir('suite/bar_1.0-6'), |
1015 | 598 | ... 'bar_1.0.orig.tar.gz')) | 608 | ... 'bar_1.0.orig.tar.gz')) |
1016 | 599 | 609 | ||
1017 | 600 | Dry run uploads should not generate any emails. Call do_accept with | 610 | Dry run uploads should not generate any emails. Call do_accept with |
1018 | 601 | notify=False: | 611 | notify=False: |
1019 | 602 | 612 | ||
1030 | 603 | >>> sync_policy = getPolicy( | 613 | >>> sync_policy = getPolicy( |
1031 | 604 | ... name='sync', distro='ubuntu', distroseries='hoary') | 614 | ... name='sync', distro='ubuntu', distroseries='hoary') |
1032 | 605 | 615 | ||
1033 | 606 | >>> bar_src = NascentUpload.from_changesfile_path( | 616 | >>> bar_src = NascentUpload.from_changesfile_path( |
1034 | 607 | ... datadir('suite/bar_1.0-1/bar_1.0-1_source.changes'), | 617 | ... datadir('suite/bar_1.0-1/bar_1.0-1_source.changes'), |
1035 | 608 | ... sync_policy, DevNullLogger()) | 618 | ... sync_policy, DevNullLogger()) |
1036 | 609 | >>> bar_src.process() | 619 | >>> bar_src.process() |
1037 | 610 | 620 | ||
1038 | 611 | >>> bar_src.logger = FakeLogger() | 621 | >>> bar_src.logger = FakeLogger() |
1039 | 612 | >>> result = bar_src.do_accept(notify=False) | 622 | >>> result = bar_src.do_accept(notify=False) |
1040 | 613 | 623 | ||
1041 | 614 | No emails generated: | 624 | No emails generated: |
1042 | 615 | 625 | ||
1046 | 616 | >>> msgs = pop_notifications() | 626 | >>> msgs = pop_notifications() |
1047 | 617 | >>> len(msgs) | 627 | >>> len(msgs) |
1048 | 618 | 0 | 628 | 0 |
1049 | 619 | 629 | ||
1050 | 620 | Rejections with notify=False will also not generate any emails. | 630 | Rejections with notify=False will also not generate any emails. |
1051 | 621 | 631 | ||
1056 | 622 | >>> result = bar_src.do_reject(notify=False) | 632 | >>> result = bar_src.do_reject(notify=False) |
1057 | 623 | >>> msgs = pop_notifications() | 633 | >>> msgs = pop_notifications() |
1058 | 624 | >>> len(msgs) | 634 | >>> len(msgs) |
1059 | 625 | 0 | 635 | 0 |
1060 | 626 | 636 | ||
1061 | 627 | The PackageUpload record created by NascentUpload will be in the NEW | 637 | The PackageUpload record created by NascentUpload will be in the NEW |
1062 | 628 | state if the package was not previously uploaded. When accepted by an | 638 | state if the package was not previously uploaded. When accepted by an |
1063 | @@ -631,199 +641,205 @@ | |||
1064 | 631 | dry_run, which when True will not send any emails. It will also log at | 641 | dry_run, which when True will not send any emails. It will also log at |
1065 | 632 | the INFO level what it /would/ have sent. | 642 | the INFO level what it /would/ have sent. |
1066 | 633 | 643 | ||
1082 | 634 | >>> random_package_upload = hoary.getQueueItems()[0] | 644 | >>> random_package_upload = hoary.getQueueItems()[0] |
1083 | 635 | >>> random_package_upload.notify(dry_run=True, logger=FakeLogger()) | 645 | >>> random_package_upload.notify(dry_run=True, logger=FakeLogger()) |
1084 | 636 | DEBUG Building recipients list. | 646 | DEBUG Building recipients list. |
1085 | 637 | ... | 647 | ... |
1086 | 638 | INFO Would have sent a mail: | 648 | INFO Would have sent a mail: |
1087 | 639 | INFO Subject: [ubuntu/hoary] bar 1.0-6 (Accepted) | 649 | INFO Subject: [ubuntu/hoary] bar 1.0-6 (Accepted) |
1088 | 640 | ... | 650 | ... |
1089 | 641 | INFO Recipients: Celso Providelo <celso.providelo@canonical.com> | 651 | INFO Recipients: Celso Providelo <celso.providelo@canonical.com> |
1090 | 642 | ... | 652 | ... |
1091 | 643 | INFO bar (1.0-6) breezy; urgency=low | 653 | INFO bar (1.0-6) breezy; urgency=low |
1092 | 644 | ... | 654 | ... |
1093 | 645 | INFO No announcement sent | 655 | INFO No announcement sent |
1094 | 646 | ... | 656 | ... |
1095 | 647 | INFO You are receiving this email because you are the uploader, maintainer or | 657 | INFO You are receiving this email because you are the uploader, maintainer |
1096 | 648 | INFO signer of the above package. | 658 | or |
1097 | 659 | INFO signer of the above package. | ||
1098 | 649 | 660 | ||
1099 | 650 | No emails generated: | 661 | No emails generated: |
1100 | 651 | 662 | ||
1104 | 652 | >>> msgs = pop_notifications() | 663 | >>> msgs = pop_notifications() |
1105 | 653 | >>> len(msgs) | 664 | >>> len(msgs) |
1106 | 654 | 0 | 665 | 0 |
1107 | 655 | 666 | ||
1108 | 656 | Uploads with UTF-8 characters in email addresses in the changes file are | 667 | Uploads with UTF-8 characters in email addresses in the changes file are |
1109 | 657 | permitted, but converted to ASCII, which is a limitation of the mailer. | 668 | permitted, but converted to ASCII, which is a limitation of the mailer. |
1110 | 658 | However, UTF-8 in the mail content is preserved. | 669 | However, UTF-8 in the mail content is preserved. |
1111 | 659 | 670 | ||
1129 | 660 | >>> hoary.status = SeriesStatus.DEVELOPMENT | 671 | >>> hoary.status = SeriesStatus.DEVELOPMENT |
1130 | 661 | >>> anything_policy = getPolicy( | 672 | >>> anything_policy = getPolicy( |
1131 | 662 | ... name='anything', distro='ubuntu', distroseries='hoary') | 673 | ... name='anything', distro='ubuntu', distroseries='hoary') |
1132 | 663 | >>> bar_upload = NascentUpload.from_changesfile_path( | 674 | >>> bar_upload = NascentUpload.from_changesfile_path( |
1133 | 664 | ... datadir( | 675 | ... datadir( |
1134 | 665 | ... 'suite/bar_1.0-10_utf8_changesfile/bar_1.0-10_source.changes'), | 676 | ... 'suite/bar_1.0-10_utf8_changesfile/' |
1135 | 666 | ... anything_policy, DevNullLogger()) | 677 | ... 'bar_1.0-10_source.changes'), |
1136 | 667 | >>> bar_upload.process() | 678 | ... anything_policy, DevNullLogger()) |
1137 | 668 | 679 | >>> bar_upload.process() | |
1138 | 669 | >>> bar_upload.logger = FakeLogger() | 680 | |
1139 | 670 | >>> result = bar_upload.do_accept() | 681 | >>> bar_upload.logger = FakeLogger() |
1140 | 671 | DEBUG Creating queue entry | 682 | >>> result = bar_upload.do_accept() |
1141 | 672 | ... | 683 | DEBUG Creating queue entry |
1142 | 673 | 684 | ... | |
1143 | 674 | >>> msgs = pop_notifications(sort_key=operator.itemgetter('To')) | 685 | |
1144 | 675 | >>> len(msgs) | 686 | >>> msgs = pop_notifications(sort_key=operator.itemgetter('To')) |
1145 | 676 | 2 | 687 | >>> len(msgs) |
1146 | 688 | 2 | ||
1147 | 677 | 689 | ||
1148 | 678 | "Cihar" should actually be "ÄŒihaÅ™" but the mailer will convert to ASCII. | 690 | "Cihar" should actually be "ÄŒihaÅ™" but the mailer will convert to ASCII. |
1149 | 679 | 691 | ||
1152 | 680 | >>> [message['From'] for message in msgs] | 692 | >>> [message['From'] for message in msgs] |
1153 | 681 | ['Root <root@localhost>', 'Non-ascii changed-by Cihar <daniel.silverstone@canonical.com>'] | 693 | ['Root <root@localhost>', 'Non-ascii changed-by Cihar |
1154 | 694 | <daniel.silverstone@canonical.com>'] | ||
1155 | 682 | 695 | ||
1156 | 683 | UTF-8 text in the changes file that is sent on the email is preserved | 696 | UTF-8 text in the changes file that is sent on the email is preserved |
1157 | 684 | in the MIME encoding. Please note also that the person that signed the | 697 | in the MIME encoding. Please note also that the person that signed the |
1158 | 685 | changes file is mentioned toward the end of the email. | 698 | changes file is mentioned toward the end of the email. |
1159 | 686 | 699 | ||
1163 | 687 | >>> announcement_email = msgs[0] | 700 | >>> announcement_email = msgs[0] |
1164 | 688 | >>> announcement_email.is_multipart() | 701 | >>> announcement_email.is_multipart() |
1165 | 689 | True | 702 | True |
1166 | 690 | 703 | ||
1199 | 691 | >>> body = announcement_email.get_payload()[0] | 704 | >>> body = announcement_email.get_payload()[0] |
1200 | 692 | >>> print body.as_string() # doctest: -NORMALIZE_WHITESPACE | 705 | >>> print body.as_string() # doctest: -NORMALIZE_WHITESPACE |
1201 | 693 | Content-Type: text/plain; charset="utf-8" | 706 | Content-Type: text/plain; charset="utf-8" |
1202 | 694 | MIME-Version: 1.0 | 707 | MIME-Version: 1.0 |
1203 | 695 | Content-Transfer-Encoding: quoted-printable | 708 | Content-Transfer-Encoding: quoted-printable |
1204 | 696 | <BLANKLINE> | 709 | <BLANKLINE> |
1205 | 697 | bar (1.0-10) breezy; urgency=3Dlow | 710 | bar (1.0-10) breezy; urgency=3Dlow |
1206 | 698 | <BLANKLINE> | 711 | <BLANKLINE> |
1207 | 699 | * Changes file that contains UTF-8 | 712 | * Changes file that contains UTF-8 |
1208 | 700 | <BLANKLINE> | 713 | <BLANKLINE> |
1209 | 701 | * Non-ascii text: =C4=8Ciha=C5=99 | 714 | * Non-ascii text: =C4=8Ciha=C5=99 |
1210 | 702 | <BLANKLINE> | 715 | <BLANKLINE> |
1211 | 703 | <BLANKLINE> | 716 | <BLANKLINE> |
1212 | 704 | Date: Thu, 30 Mar 2006 01:36:14 +0100 | 717 | Date: Thu, 30 Mar 2006 01:36:14 +0100 |
1213 | 705 | Changed-By: Non-ascii changed-by =C4=8Ciha=C5=99 <daniel.silverstone@canoni= | 718 | Changed-By: Non-ascii changed-by =C4=8Ciha=C5=99 <daniel.silverstone@canoni= |
1214 | 706 | cal.com> | 719 | cal.com> |
1215 | 707 | Maintainer: Non-ascii maintainer =C4=8Ciha=C5=99 <launchpad@lists.canonical= | 720 | Maintainer: Non-ascii maintainer =C4=8Ciha=C5=99 <launchpad@lists.canonical= |
1216 | 708 | .com> | 721 | .com> |
1217 | 709 | Signed-By: Foo Bar <foo.bar@canonical.com> | 722 | Signed-By: Foo Bar <foo.bar@canonical.com> |
1218 | 710 | http://launchpad.dev/ubuntu/hoary/+source/bar/1.0-10 | 723 | http://launchpad.dev/ubuntu/hoary/+source/bar/1.0-10 |
1219 | 711 | <BLANKLINE> | 724 | <BLANKLINE> |
1220 | 712 | =3D=3D | 725 | =3D=3D |
1221 | 713 | <BLANKLINE> | 726 | <BLANKLINE> |
1222 | 714 | Announcing to hoary-announce@lists.ubuntu.com | 727 | Announcing to hoary-announce@lists.ubuntu.com |
1223 | 715 | <BLANKLINE> | 728 | <BLANKLINE> |
1224 | 716 | Thank you for your contribution to Ubuntu Linux. | 729 | Thank you for your contribution to Ubuntu Linux. |
1225 | 717 | <BLANKLINE> | 730 | <BLANKLINE> |
1226 | 718 | -- = | 731 | -- = |
1227 | 719 | <BLANKLINE> | 732 | <BLANKLINE> |
1228 | 720 | You are receiving this email because you are the uploader, maintainer or | 733 | You are receiving this email because you are the uploader, maintainer or |
1229 | 721 | signer of the above package. | 734 | signer of the above package. |
1230 | 722 | <BLANKLINE> | 735 | <BLANKLINE> |
1231 | 723 | 736 | ||
1232 | 724 | In order to facilitate scripts that parse announcement emails, the changes | 737 | In order to facilitate scripts that parse announcement emails, the changes |
1233 | 725 | file is enclosed as an attachment. | 738 | file is enclosed as an attachment. |
1234 | 726 | 739 | ||
1236 | 727 | >>> attachment = announcement_email.get_payload()[1] | 740 | >>> attachment = announcement_email.get_payload()[1] |
1237 | 728 | 741 | ||
1238 | 729 | Here's the attachment metadata. | 742 | Here's the attachment metadata. |
1239 | 730 | 743 | ||
1242 | 731 | >>> attachment['Content-Disposition'] | 744 | >>> attachment['Content-Disposition'] |
1243 | 732 | 'attachment; filename="changesfile"' | 745 | 'attachment; filename="changesfile"' |
1244 | 733 | 746 | ||
1245 | 734 | And what follows is the content of the attachment. | 747 | And what follows is the content of the attachment. |
1246 | 735 | 748 | ||
1292 | 736 | >>> print attachment.as_string() # doctest: -NORMALIZE_WHITESPACE | 749 | >>> print attachment.as_string() # doctest: -NORMALIZE_WHITESPACE |
1293 | 737 | Content-Type: text/plain; charset="utf-8" | 750 | Content-Type: text/plain; charset="utf-8" |
1294 | 738 | MIME-Version: 1.0 | 751 | MIME-Version: 1.0 |
1295 | 739 | Content-Transfer-Encoding: quoted-printable | 752 | Content-Transfer-Encoding: quoted-printable |
1296 | 740 | Content-Disposition: attachment; filename="changesfile" | 753 | Content-Disposition: attachment; filename="changesfile" |
1297 | 741 | <BLANKLINE> | 754 | <BLANKLINE> |
1298 | 742 | -----BEGIN PGP SIGNED MESSAGE----- | 755 | -----BEGIN PGP SIGNED MESSAGE----- |
1299 | 743 | Hash: SHA1 | 756 | Hash: SHA1 |
1300 | 744 | <BLANKLINE> | 757 | <BLANKLINE> |
1301 | 745 | Format: 1.7 | 758 | Format: 1.7 |
1302 | 746 | Date: Thu, 30 Mar 2006 01:36:14 +0100 | 759 | Date: Thu, 30 Mar 2006 01:36:14 +0100 |
1303 | 747 | Source: bar | 760 | Source: bar |
1304 | 748 | Binary: bar | 761 | Binary: bar |
1305 | 749 | Architecture: source | 762 | Architecture: source |
1306 | 750 | Version: 1.0-10 | 763 | Version: 1.0-10 |
1307 | 751 | Distribution: breezy | 764 | Distribution: breezy |
1308 | 752 | Urgency: low | 765 | Urgency: low |
1309 | 753 | Maintainer: Non-ascii maintainer =C4=8Ciha=C5=99 <launchpad@lists.canonical= | 766 | Maintainer: Non-ascii maintainer =C4=8Ciha=C5=99 <launchpad@lists.canonical= |
1310 | 754 | .com> | 767 | .com> |
1311 | 755 | Changed-By: Non-ascii changed-by =C4=8Ciha=C5=99 <daniel.silverstone@canoni= | 768 | Changed-By: Non-ascii changed-by =C4=8Ciha=C5=99 <daniel.silverstone@canoni= |
1312 | 756 | cal.com> | 769 | cal.com> |
1313 | 757 | Description: = | 770 | Description: = |
1314 | 758 | <BLANKLINE> | 771 | <BLANKLINE> |
1315 | 759 | bar - Stuff for testing | 772 | bar - Stuff for testing |
1316 | 760 | Changes: = | 773 | Changes: = |
1317 | 761 | <BLANKLINE> | 774 | <BLANKLINE> |
1318 | 762 | bar (1.0-10) breezy; urgency=3Dlow | 775 | bar (1.0-10) breezy; urgency=3Dlow |
1319 | 763 | . | 776 | . |
1320 | 764 | * Changes file that contains UTF-8 | 777 | * Changes file that contains UTF-8 |
1321 | 765 | . | 778 | . |
1322 | 766 | * Non-ascii text: =C4=8Ciha=C5=99 | 779 | * Non-ascii text: =C4=8Ciha=C5=99 |
1323 | 767 | . | 780 | . |
1324 | 768 | Files: = | 781 | Files: = |
1325 | 769 | <BLANKLINE> | 782 | <BLANKLINE> |
1326 | 770 | a4932aa84fdb62819b49f3dda163fc0d 514 devel optional bar_1.0-10.dsc | 783 | a4932aa84fdb62819b49f3dda163fc0d 514 devel optional bar_1.0-10.dsc |
1327 | 771 | ac6b4efe44e31f47ec9f0d0fac6935f4 622 devel optional bar_1.0-10.diff.gz | 784 | ac6b4efe44e31f47ec9f0d0fac6935f4 622 devel optional bar_1.0-10.diff.gz |
1328 | 772 | <BLANKLINE> | 785 | <BLANKLINE> |
1329 | 773 | -----BEGIN PGP SIGNATURE----- | 786 | -----BEGIN PGP SIGNATURE----- |
1330 | 774 | Version: GnuPG v1.4.6 (GNU/Linux) | 787 | Version: GnuPG v1.4.6 (GNU/Linux) |
1331 | 775 | <BLANKLINE> | 788 | <BLANKLINE> |
1332 | 776 | iD8DBQFGjOzNjn63CGxkqMURAlDZAJ9CusNQWwbTJr7JHYV4Ka1JbWwmJACeLbs5 | 789 | iD8DBQFGjOzNjn63CGxkqMURAlDZAJ9CusNQWwbTJr7JHYV4Ka1JbWwmJACeLbs5 |
1333 | 777 | Hzkb2pxxwYzKs7uyCiFONlo=3D | 790 | Hzkb2pxxwYzKs7uyCiFONlo=3D |
1334 | 778 | =3D9dL/ | 791 | =3D9dL/ |
1335 | 779 | -----END PGP SIGNATURE----- | 792 | -----END PGP SIGNATURE----- |
1336 | 780 | <BLANKLINE> | 793 | <BLANKLINE> |
1337 | 781 | 794 | ||
1338 | 782 | The attempt to upload a package with a malformed changes file name will | 795 | The attempt to upload a package with a malformed changes file name will |
1339 | 783 | result in a rejection email. | 796 | result in a rejection email. |
1340 | 784 | 797 | ||
1341 | 785 | We first create a misnamed copy of the changes file. | 798 | We first create a misnamed copy of the changes file. |
1342 | 786 | 799 | ||
1347 | 787 | >>> import os, shutil | 800 | >>> import os, shutil |
1348 | 788 | >>> originalp = datadir('suite/bar_1.0-1/bar_1.0-1_source.changes') | 801 | >>> originalp = datadir('suite/bar_1.0-1/bar_1.0-1_source.changes') |
1349 | 789 | >>> copyp = datadir('suite/bar_1.0-1/z-z_0.4.12-2~ppa2.changes') | 802 | >>> copyp = datadir('suite/bar_1.0-1/z-z_0.4.12-2~ppa2.changes') |
1350 | 790 | >>> shutil.copyfile(originalp, copyp) | 803 | >>> shutil.copyfile(originalp, copyp) |
1351 | 791 | 804 | ||
1352 | 792 | And then try to upload using the changes file with the malformed name. | 805 | And then try to upload using the changes file with the malformed name. |
1353 | 793 | 806 | ||
1386 | 794 | >>> bar_src = NascentUpload.from_changesfile_path( | 807 | >>> bar_src = NascentUpload.from_changesfile_path( |
1387 | 795 | ... copyp, sync_policy, DevNullLogger()) | 808 | ... copyp, sync_policy, DevNullLogger()) |
1388 | 796 | >>> bar_src.process() | 809 | >>> bar_src.process() |
1389 | 797 | Traceback (most recent call last): | 810 | Traceback (most recent call last): |
1390 | 798 | ... | 811 | ... |
1391 | 799 | EarlyReturnUploadError: An error occurred that prevented further processing. | 812 | EarlyReturnUploadError: An error occurred that prevented further |
1392 | 800 | 813 | processing. | |
1393 | 801 | >>> bar_src.logger = FakeLogger() | 814 | |
1394 | 802 | >>> result = bar_src.do_accept() | 815 | >>> bar_src.logger = FakeLogger() |
1395 | 803 | DEBUG Building recipients list. | 816 | >>> result = bar_src.do_accept() |
1396 | 804 | ... | 817 | DEBUG Building recipients list. |
1397 | 805 | DEBUG Sending rejection email. | 818 | ... |
1398 | 806 | DEBUG Sent a mail: | 819 | DEBUG Sending rejection email. |
1399 | 807 | ... | 820 | DEBUG Sent a mail: |
1400 | 808 | DEBUG Rejected: | 821 | ... |
1401 | 809 | DEBUG z-z_0.4.12-2~ppa2.changes -> inappropriate changesfile name, should follow "<pkg>_<version>_<arch>.changes" format | 822 | DEBUG Rejected: |
1402 | 810 | ... | 823 | DEBUG z-z_0.4.12-2~ppa2.changes -> inappropriate changesfile name, should |
1403 | 811 | DEBUG If you don't understand why your files were rejected, or if the | 824 | follow "<pkg>_<version>_<arch>.changes" format |
1404 | 812 | DEBUG override file requires editing, please go to: | 825 | ... |
1405 | 813 | DEBUG http://answers.launchpad.net/soyuz | 826 | DEBUG If you don't understand why your files were rejected, or if the |
1406 | 814 | DEBUG | 827 | DEBUG override file requires editing, please go to: |
1407 | 815 | DEBUG -- | 828 | DEBUG http://answers.launchpad.net/soyuz |
1408 | 816 | DEBUG You are receiving this email because you are the uploader, maintainer or | 829 | DEBUG |
1409 | 817 | DEBUG signer of the above package. | 830 | DEBUG -- |
1410 | 818 | 831 | DEBUG You are receiving this email because you are the uploader, | |
1411 | 819 | >>> [notification] = pop_notifications() | 832 | maintainer or |
1412 | 820 | 833 | DEBUG signer of the above package. | |
1413 | 821 | >>> notification['X-Katie'] | 834 | |
1414 | 822 | 'Launchpad actually' | 835 | >>> [notification] = pop_notifications() |
1415 | 823 | 836 | ||
1416 | 824 | >>> print_addrlist(notification['To']) | 837 | >>> notification['X-Katie'] |
1417 | 825 | Daniel Silverstone <daniel.silverstone@canonical.com> | 838 | 'Launchpad actually' |
1418 | 839 | |||
1419 | 840 | >>> print_addrlist(notification['To']) | ||
1420 | 841 | Daniel Silverstone <daniel.silverstone@canonical.com> | ||
1421 | 826 | 842 | ||
1422 | 827 | Remove the misnamed changes file copy used for testing. | 843 | Remove the misnamed changes file copy used for testing. |
1423 | 828 | 844 | ||
1425 | 829 | >>> os.unlink(copyp) | 845 | >>> os.unlink(copyp) |
1426 | 830 | 846 | ||
1427 | === modified file 'lib/lp/archiveuploader/tests/test_uploadprocessor.py' | |||
1428 | --- lib/lp/archiveuploader/tests/test_uploadprocessor.py 2011-01-27 17:17:50 +0000 | |||
1429 | +++ lib/lp/archiveuploader/tests/test_uploadprocessor.py 2011-01-27 17:17:51 +0000 | |||
1430 | @@ -1950,10 +1950,7 @@ | |||
1431 | 1950 | # Upon full build the upload log is unset. | 1950 | # Upon full build the upload log is unset. |
1432 | 1951 | self.assertIs(None, build.upload_log) | 1951 | self.assertIs(None, build.upload_log) |
1433 | 1952 | 1952 | ||
1438 | 1953 | def testSourcePackageRecipeBuild(self): | 1953 | def doSuccessRecipeBuild(self): |
1435 | 1954 | # Properly uploaded source packages should result in the | ||
1436 | 1955 | # build status changing to FULLYBUILT. | ||
1437 | 1956 | |||
1439 | 1957 | # Upload a source package | 1954 | # Upload a source package |
1440 | 1958 | archive = self.factory.makeArchive() | 1955 | archive = self.factory.makeArchive() |
1441 | 1959 | archive.require_virtualized = False | 1956 | archive.require_virtualized = False |
1442 | @@ -1981,14 +1978,27 @@ | |||
1443 | 1981 | BuildUploadHandler(self.uploadprocessor, self.incoming_folder, | 1978 | BuildUploadHandler(self.uploadprocessor, self.incoming_folder, |
1444 | 1982 | leaf_name).process() | 1979 | leaf_name).process() |
1445 | 1983 | self.layer.txn.commit() | 1980 | self.layer.txn.commit() |
1446 | 1981 | return build | ||
1447 | 1984 | 1982 | ||
1448 | 1983 | def testSourcePackageRecipeBuild(self): | ||
1449 | 1984 | # Properly uploaded source packages should result in the | ||
1450 | 1985 | # build status changing to FULLYBUILT. | ||
1451 | 1986 | build = self.doSuccessRecipeBuild() | ||
1452 | 1985 | self.assertEquals(BuildStatus.FULLYBUILT, build.status) | 1987 | self.assertEquals(BuildStatus.FULLYBUILT, build.status) |
1453 | 1986 | self.assertEquals(None, build.builder) | 1988 | self.assertEquals(None, build.builder) |
1454 | 1987 | self.assertIsNot(None, build.duration) | 1989 | self.assertIsNot(None, build.duration) |
1455 | 1988 | # Upon full build the upload log is unset. | 1990 | # Upon full build the upload log is unset. |
1456 | 1989 | self.assertIs(None, build.upload_log) | 1991 | self.assertIs(None, build.upload_log) |
1457 | 1990 | 1992 | ||
1459 | 1991 | def testSourcePackageRecipeBuild_fail(self): | 1993 | def testSourcePackageRecipeBuild_success_mail(self): |
1460 | 1994 | # When a source package recipe build succeeds, it sends a build-style | ||
1461 | 1995 | # email, not user-upload-style one. | ||
1462 | 1996 | self.doSuccessRecipeBuild() | ||
1463 | 1997 | (mail,) = pop_notifications() | ||
1464 | 1998 | subject = mail['Subject'].replace('\n\t', ' ') | ||
1465 | 1999 | self.assertIn('Successfully built', subject) | ||
1466 | 2000 | |||
1467 | 2001 | def doFailureRecipeBuild(self): | ||
1468 | 1992 | # A source package recipe build will fail if no files are present. | 2002 | # A source package recipe build will fail if no files are present. |
1469 | 1993 | 2003 | ||
1470 | 1994 | # Upload a source package | 2004 | # Upload a source package |
1471 | @@ -2012,11 +2022,24 @@ | |||
1472 | 2012 | BuildUploadHandler(self.uploadprocessor, self.incoming_folder, | 2022 | BuildUploadHandler(self.uploadprocessor, self.incoming_folder, |
1473 | 2013 | leaf_name).process() | 2023 | leaf_name).process() |
1474 | 2014 | self.layer.txn.commit() | 2024 | self.layer.txn.commit() |
1475 | 2025 | return build | ||
1476 | 2026 | |||
1477 | 2027 | def testSourcePackageRecipeBuild_fail(self): | ||
1478 | 2028 | build = self.doFailureRecipeBuild() | ||
1479 | 2015 | self.assertEquals(BuildStatus.FAILEDTOUPLOAD, build.status) | 2029 | self.assertEquals(BuildStatus.FAILEDTOUPLOAD, build.status) |
1480 | 2016 | self.assertEquals(None, build.builder) | 2030 | self.assertEquals(None, build.builder) |
1481 | 2017 | self.assertIsNot(None, build.duration) | 2031 | self.assertIsNot(None, build.duration) |
1482 | 2018 | self.assertIsNot(None, build.upload_log) | 2032 | self.assertIsNot(None, build.upload_log) |
1483 | 2019 | 2033 | ||
1484 | 2034 | def testSourcePackageRecipeBuild_fail_mail(self): | ||
1485 | 2035 | # Failures should generate a message that includes the upload log URL. | ||
1486 | 2036 | self.doFailureRecipeBuild() | ||
1487 | 2037 | (mail,) = pop_notifications() | ||
1488 | 2038 | subject = mail['Subject'].replace('\n\t', ' ') | ||
1489 | 2039 | self.assertIn('Failed to upload', subject) | ||
1490 | 2040 | body = mail.get_payload(decode=True) | ||
1491 | 2041 | self.assertIn('Upload Log: http', body) | ||
1492 | 2042 | |||
1493 | 2020 | def testBuildWithInvalidStatus(self): | 2043 | def testBuildWithInvalidStatus(self): |
1494 | 2021 | # Builds with an invalid (non-UPLOADING) status should trigger | 2044 | # Builds with an invalid (non-UPLOADING) status should trigger |
1495 | 2022 | # a warning but be left alone. | 2045 | # a warning but be left alone. |
1496 | 2023 | 2046 | ||
1497 | === modified file 'lib/lp/archiveuploader/uploadprocessor.py' | |||
1498 | --- lib/lp/archiveuploader/uploadprocessor.py 2011-01-27 17:17:50 +0000 | |||
1499 | +++ lib/lp/archiveuploader/uploadprocessor.py 2011-01-27 17:17:51 +0000 | |||
1500 | @@ -660,13 +660,15 @@ | |||
1501 | 660 | error_utility.raising(info, request) | 660 | error_utility.raising(info, request) |
1502 | 661 | logger.error('%s (%s)' % (message, request.oopsid)) | 661 | logger.error('%s (%s)' % (message, request.oopsid)) |
1503 | 662 | result = UploadStatusEnum.FAILED | 662 | result = UploadStatusEnum.FAILED |
1507 | 663 | if not (result == UploadStatusEnum.ACCEPTED and | 663 | if (result != UploadStatusEnum.ACCEPTED or |
1508 | 664 | self.build.verifySuccessfulUpload() and | 664 | not self.build.verifySuccessfulUpload()): |
1506 | 665 | self.build.status == BuildStatus.FULLYBUILT): | ||
1509 | 666 | self.build.status = BuildStatus.FAILEDTOUPLOAD | 665 | self.build.status = BuildStatus.FAILEDTOUPLOAD |
1510 | 666 | if self.build.status != BuildStatus.FULLYBUILT: | ||
1511 | 667 | self.build.storeUploadLog(logger.getLogBuffer()) | ||
1512 | 667 | self.build.notify(extra_info="Uploading build %s failed." % | 668 | self.build.notify(extra_info="Uploading build %s failed." % |
1513 | 668 | self.upload) | 669 | self.upload) |
1515 | 669 | self.build.storeUploadLog(logger.getLogBuffer()) | 670 | else: |
1516 | 671 | self.build.notify() | ||
1517 | 670 | self.processor.ztm.commit() | 672 | self.processor.ztm.commit() |
1518 | 671 | self.moveProcessedUpload(result, logger) | 673 | self.moveProcessedUpload(result, logger) |
1519 | 672 | 674 | ||
1520 | 673 | 675 | ||
1521 | === modified file 'lib/lp/soyuz/model/binarypackagebuild.py' | |||
1522 | --- lib/lp/soyuz/model/binarypackagebuild.py 2011-01-24 20:57:37 +0000 | |||
1523 | +++ lib/lp/soyuz/model/binarypackagebuild.py 2011-01-27 17:17:51 +0000 | |||
1524 | @@ -621,6 +621,8 @@ | |||
1525 | 621 | 621 | ||
1526 | 622 | if not config.builddmaster.send_build_notification: | 622 | if not config.builddmaster.send_build_notification: |
1527 | 623 | return | 623 | return |
1528 | 624 | if self.status == BuildStatus.FULLYBUILT: | ||
1529 | 625 | return | ||
1530 | 624 | 626 | ||
1531 | 625 | recipients = set() | 627 | recipients = set() |
1532 | 626 | 628 | ||
1533 | 627 | 629 | ||
1534 | === modified file 'lib/lp/soyuz/model/queue.py' | |||
1535 | --- lib/lp/soyuz/model/queue.py 2011-01-14 14:03:28 +0000 | |||
1536 | +++ lib/lp/soyuz/model/queue.py 2011-01-27 17:17:51 +0000 | |||
1537 | @@ -72,7 +72,6 @@ | |||
1538 | 72 | ) | 72 | ) |
1539 | 73 | from lp.services.propertycache import cachedproperty | 73 | from lp.services.propertycache import cachedproperty |
1540 | 74 | from lp.soyuz.enums import ( | 74 | from lp.soyuz.enums import ( |
1541 | 75 | BinaryPackageFormat, | ||
1542 | 76 | PackageUploadCustomFormat, | 75 | PackageUploadCustomFormat, |
1543 | 77 | PackageUploadStatus, | 76 | PackageUploadStatus, |
1544 | 78 | ) | 77 | ) |
1545 | @@ -192,9 +191,23 @@ | |||
1546 | 192 | # PackageUploadSource objects which are related. | 191 | # PackageUploadSource objects which are related. |
1547 | 193 | sources = SQLMultipleJoin('PackageUploadSource', | 192 | sources = SQLMultipleJoin('PackageUploadSource', |
1548 | 194 | joinColumn='packageupload') | 193 | joinColumn='packageupload') |
1549 | 194 | # Does not include source builds. | ||
1550 | 195 | builds = SQLMultipleJoin('PackageUploadBuild', | 195 | builds = SQLMultipleJoin('PackageUploadBuild', |
1551 | 196 | joinColumn='packageupload') | 196 | joinColumn='packageupload') |
1552 | 197 | 197 | ||
1553 | 198 | def getSourceBuild(self): | ||
1554 | 199 | #avoid circular import | ||
1555 | 200 | from lp.code.model.sourcepackagerecipebuild import ( | ||
1556 | 201 | SourcePackageRecipeBuild) | ||
1557 | 202 | from lp.soyuz.model.sourcepackagerelease import SourcePackageRelease | ||
1558 | 203 | return Store.of(self).find( | ||
1559 | 204 | SourcePackageRecipeBuild, | ||
1560 | 205 | SourcePackageRecipeBuild.id == | ||
1561 | 206 | SourcePackageRelease.source_package_recipe_build_id, | ||
1562 | 207 | SourcePackageRelease.id == | ||
1563 | 208 | PackageUploadSource.sourcepackagereleaseID, | ||
1564 | 209 | PackageUploadSource.packageupload == self.id).one() | ||
1565 | 210 | |||
1566 | 198 | # Also the custom files associated with the build. | 211 | # Also the custom files associated with the build. |
1567 | 199 | customfiles = SQLMultipleJoin('PackageUploadCustom', | 212 | customfiles = SQLMultipleJoin('PackageUploadCustom', |
1568 | 200 | joinColumn='packageupload') | 213 | joinColumn='packageupload') |
1569 | @@ -488,6 +501,10 @@ | |||
1570 | 488 | """See `IPackageUpload`.""" | 501 | """See `IPackageUpload`.""" |
1571 | 489 | return self.builds | 502 | return self.builds |
1572 | 490 | 503 | ||
1573 | 504 | @cachedproperty | ||
1574 | 505 | def from_build(self): | ||
1575 | 506 | return bool(self.builds) or self.getSourceBuild() | ||
1576 | 507 | |||
1577 | 491 | def isAutoSyncUpload(self, changed_by_email): | 508 | def isAutoSyncUpload(self, changed_by_email): |
1578 | 492 | """See `IPackageUpload`.""" | 509 | """See `IPackageUpload`.""" |
1579 | 493 | katie = getUtility(ILaunchpadCelebrities).katie | 510 | katie = getUtility(ILaunchpadCelebrities).katie |
1580 | @@ -1070,10 +1087,10 @@ | |||
1581 | 1070 | 1087 | ||
1582 | 1071 | # If this is a binary or mixed upload, we don't send *any* emails | 1088 | # If this is a binary or mixed upload, we don't send *any* emails |
1583 | 1072 | # provided it's not a rejection or a security upload: | 1089 | # provided it's not a rejection or a security upload: |
1585 | 1073 | if(self.contains_build and | 1090 | if(self.from_build and |
1586 | 1074 | self.status != PackageUploadStatus.REJECTED and | 1091 | self.status != PackageUploadStatus.REJECTED and |
1587 | 1075 | self.pocket != PackagePublishingPocket.SECURITY): | 1092 | self.pocket != PackagePublishingPocket.SECURITY): |
1589 | 1076 | debug(self.logger, "Not sending email, upload contains binaries.") | 1093 | debug(self.logger, "Not sending email; upload is from a build.") |
1590 | 1077 | return | 1094 | return |
1591 | 1078 | 1095 | ||
1592 | 1079 | # XXX julian 2007-05-11: | 1096 | # XXX julian 2007-05-11: |
1593 | 1080 | 1097 | ||
1594 | === modified file 'lib/lp/soyuz/tests/test_build_notify.py' | |||
1595 | --- lib/lp/soyuz/tests/test_build_notify.py 2011-01-20 20:31:07 +0000 | |||
1596 | +++ lib/lp/soyuz/tests/test_build_notify.py 2011-01-27 17:17:51 +0000 | |||
1597 | @@ -114,7 +114,7 @@ | |||
1598 | 114 | duration = 'not finished' | 114 | duration = 'not finished' |
1599 | 115 | build_log = 'see builder page' | 115 | build_log = 'see builder page' |
1600 | 116 | elif ( | 116 | elif ( |
1602 | 117 | build.status == BuildStatus.SUPERSEDED or | 117 | build.status == BuildStatus.SUPERSEDED or |
1603 | 118 | build.status == BuildStatus.NEEDSBUILD): | 118 | build.status == BuildStatus.NEEDSBUILD): |
1604 | 119 | duration = 'not available' | 119 | duration = 'not available' |
1605 | 120 | build_log = 'not available' | 120 | build_log = 'not available' |
1606 | @@ -203,20 +203,11 @@ | |||
1607 | 203 | self._assert_mail_is_correct(build, notification, ppa=True) | 203 | self._assert_mail_is_correct(build, notification, ppa=True) |
1608 | 204 | 204 | ||
1609 | 205 | def test_notify_successfully_built(self): | 205 | def test_notify_successfully_built(self): |
1611 | 206 | # We can notify the creator when the build is sucessful. | 206 | # Successful builds don't notify anyone. |
1612 | 207 | self.create_builds(self.archive) | 207 | self.create_builds(self.archive) |
1613 | 208 | build = self.builds[BuildStatus.FULLYBUILT.value] | 208 | build = self.builds[BuildStatus.FULLYBUILT.value] |
1614 | 209 | build.notify() | 209 | build.notify() |
1625 | 210 | notification = pop_notifications()[1] | 210 | self.assertEqual([], pop_notifications()) |
1616 | 211 | self._assert_mail_is_correct(build, notification) | ||
1617 | 212 | |||
1618 | 213 | def test_notify_successfully_built_ppa(self): | ||
1619 | 214 | # We can notify the creator when the build is sucessful. | ||
1620 | 215 | self.create_builds(self.ppa) | ||
1621 | 216 | build = self.builds[BuildStatus.FULLYBUILT.value] | ||
1622 | 217 | build.notify() | ||
1623 | 218 | notification = pop_notifications()[1] | ||
1624 | 219 | self._assert_mail_is_correct(build, notification, ppa=True) | ||
1626 | 220 | 211 | ||
1627 | 221 | def test_notify_dependency_wait(self): | 212 | def test_notify_dependency_wait(self): |
1628 | 222 | # We can notify the creator when the build can't find a dependency. | 213 | # We can notify the creator when the build can't find a dependency. |
1629 | @@ -321,7 +312,7 @@ | |||
1630 | 321 | # When the 'notify_owner' config option is False, we don't send mail | 312 | # When the 'notify_owner' config option is False, we don't send mail |
1631 | 322 | # to the owner of the SPR. | 313 | # to the owner of the SPR. |
1632 | 323 | self.create_builds(self.archive) | 314 | self.create_builds(self.archive) |
1634 | 324 | build = self.builds[BuildStatus.FULLYBUILT.value] | 315 | build = self.builds[BuildStatus.FAILEDTOBUILD.value] |
1635 | 325 | notify_owner = dedent(""" | 316 | notify_owner = dedent(""" |
1636 | 326 | [builddmaster] | 317 | [builddmaster] |
1637 | 327 | send_build_notification: True | 318 | send_build_notification: True |
1638 | @@ -357,13 +348,13 @@ | |||
1639 | 357 | sponsor = self.factory.makePerson('sponsor@example.com') | 348 | sponsor = self.factory.makePerson('sponsor@example.com') |
1640 | 358 | key = self.factory.makeGPGKey(owner=sponsor) | 349 | key = self.factory.makeGPGKey(owner=sponsor) |
1641 | 359 | self.create_builds(self.archive) | 350 | self.create_builds(self.archive) |
1643 | 360 | build = self.builds[BuildStatus.FULLYBUILT.value] | 351 | build = self.builds[BuildStatus.FAILEDTOBUILD.value] |
1644 | 361 | spr = build.current_source_publication.sourcepackagerelease | 352 | spr = build.current_source_publication.sourcepackagerelease |
1645 | 362 | # Push past the security proxy | 353 | # Push past the security proxy |
1646 | 363 | removeSecurityProxy(spr).dscsigningkey = key | 354 | removeSecurityProxy(spr).dscsigningkey = key |
1647 | 364 | build.notify() | 355 | build.notify() |
1648 | 365 | notifications = pop_notifications() | 356 | notifications = pop_notifications() |
1649 | 366 | expected_emails = self.buildd_admins_email + [ | 357 | expected_emails = self.buildd_admins_email + [ |
1651 | 367 | 'sponsor@example.com', 'test@example.com'] | 358 | 'sponsor@example.com', 'test@example.com'] |
1652 | 368 | actual_emails = [n['To'] for n in notifications] | 359 | actual_emails = [n['To'] for n in notifications] |
1653 | 369 | self.assertEquals(expected_emails, actual_emails) | 360 | self.assertEquals(expected_emails, actual_emails) |
Aaron--
This looks pretty good. I have one commenting suggestion below which isn't terribly important, and one potentially important performance question at the bottom of the diff below.
> === modified file 'lib/lp/ archiveuploader /tests/ test_uploadproc essor.py' archiveuploader /tests/ test_uploadproc essor.py 2011-01-27 16:13:58 +0000 archiveuploader /tests/ test_uploadproc essor.py 2011-01-27 16:13:59 +0000 ler(self. uploadprocessor , self.incoming_ folder, .process( ) txn.commit( ) geRecipeBuild_ fail(self) : ecipeBuild( ) ls(BuildStatus. FAILEDTOUPLOAD, build.status) ls(None, build.builder) t(None, build.duration) t(None, build.upload_log) geRecipeBuild_ fail_mail( self): ecipeBuild( ) ].replace( '\n\t', ' ') 'Failed to upload', subject) payload( decode= True) 'Upload Log: http', body) validStatus( self):
> --- lib/lp/
> +++ lib/lp/
> @@ -2012,11 +2022,23 @@
> BuildUploadHand
> leaf_name)
> self.layer.
> + return build
> +
> + def testSourcePacka
> + build = self.doFailureR
> self.assertEqua
> self.assertEqua
> self.assertIsNo
> self.assertIsNo
>
> + def testSourcePacka
> + self.doFailureR
> + (mail,) = pop_notifications()
> + subject = mail['Subject'
> + self.assertIn(
> + body = mail.get_
> + self.assertIn(
> +
> def testBuildWithIn
> # Builds with an invalid (non-UPLOADING) status should trigger
> # a warning but be left alone.
A comment to the effect geRecipeBuild_ fail_mail would be good.
+ # When a recipe fails it should include the log in the mail.
in testSourcePacka
> @@ -192,9 +191,23 @@ ('PackageUpload Source' , 'packageupload' ) ('PackageUpload Build', 'packageupload' ) self): model.sourcepac kagerecipebuild import ( cipeBuild) model.sourcepac kagerelease import SourcePackageRe lease self).find( cipeBuild, cipeBuild. id == lease.source_ package_ recipe_ build_id, lease.id == urce.sourcepack agereleaseID, urce.packageupl oad == self.id).one() ('PackageUpload Custom' , 'packageupload' ) `.""" uild()
> # PackageUploadSource objects which are related.
> sources = SQLMultipleJoin
> joinColumn=
> + # Does not include source builds.
> builds = SQLMultipleJoin
> joinColumn=
>
> + def getSourceBuild(
> + #avoid circular import
> + from lp.code.
> + SourcePackageRe
> + from lp.soyuz.
> + return Store.of(
> + SourcePackageRe
> + SourcePackageRe
> + SourcePackageRe
> + SourcePackageRe
> + PackageUploadSo
> + PackageUploadSo
> +
> # Also the custom files associated with the build.
> customfiles = SQLMultipleJoin
> joinColumn=
> @@ -488,6 +501,10 @@
> """See `IPackageUpload
> return self.builds
>
> + @cachedproperty
> + def from_build(self):
> + return bool(self.builds) or self.getSourceB
> +
Is there any chance of a cold cache use of this method causing performance issues? I'm not saying it will, just asking. I have no idea how large the query fired for this could be.