Merge lp:~cjwatson/launchpad/publishinghistory-show-copier into lp:launchpad

Proposed by Colin Watson on 2012-08-04
Status: Merged
Approved by: William Grant on 2012-08-09
Approved revision: no longer in the source branch.
Merged at revision: 15783
Proposed branch: lp:~cjwatson/launchpad/publishinghistory-show-copier
Merge into: lp:launchpad
Diff against target: 194 lines (+90/-5)
5 files modified
lib/lp/registry/browser/distributionsourcepackage.py (+10/-0)
lib/lp/registry/browser/tests/test_distributionsourcepackage.py (+68/-2)
lib/lp/soyuz/interfaces/publishing.py (+3/-0)
lib/lp/soyuz/stories/ppa/xx-copy-packages.txt (+2/-1)
lib/lp/soyuz/templates/packagepublishing-details.pt (+7/-2)
To merge this branch: bzr merge lp:~cjwatson/launchpad/publishinghistory-show-copier
Reviewer Review Type Date Requested Status
William Grant code Approve on 2012-08-09
Steve Kowalik (community) code 2012-08-04 Approve on 2012-08-08
Review via email: mp+118223@code.launchpad.net

Commit Message

Show the person who copied a source package, if available, in the publishing history.

Description of the Change

== Summary ==

There's no way to see who copied a package in the +publishinghistory UI; you have to wheel out the API and look at SPPH.creator. This is more cumbersome than it should be.

== Proposed fix ==

Add "by [creator]" to the template if we know who that is.

== LOC Rationale ==

+5. I have 3911 lines of credit.

== Tests ==

bin/test -vvct soyuz/stories/ppa/xx-copy-packages.txt

== Demo and Q/A ==

Find a package that's been copied using a PCJ - the auto-syncer is a good source of these on old DB snapshots such as qastaging, so try https://qastaging.launchpad.net/ubuntu/+source/man-db/+publishinghistory - and look for the new text.

To post a comment you must log in.
Steve Kowalik (stevenk) :
review: Approve (code)
William Grant (wgrant) wrote :

As discussed on IRC, this requires preloading of the people to avoid timeouts.

review: Needs Fixing (code)
Colin Watson (cjwatson) wrote :

The IRC discussion in question was:

  http://irclogs.ubuntu.com/2012/08/04/%23ubuntu-release.html

Colin Watson (cjwatson) wrote :

I think I've addressed almost all of the comments William made on IRC. The exception is bug 851047, where I've left a comment on the bug explaining why that's hard to fix at the moment.

William Grant (wgrant) :
review: Approve (code)
William Grant (wgrant) wrote :

I'm a bit wary about that high per-SPPH query count, but otherwise good. What sort of queries are they? I know there's a few for DistroSeries, but can't think what the other 9 would be.

Colin Watson (cjwatson) wrote :

I agree the high count is unpleasant, but I checked that it was the same
before this branch (or else I'd be worried), so it probably just
reflects +publishinghistory being dreadful already. Remember that those
10 queries are for two SPPHs.

Both SPPHs involve queries for Component and Section, and as you say
DistroSeries. Then there's Archive and Distribution in the case of the
copied SPPH, and an extra Person query for the archive owner there as
well. My count seems to be off by one somewhere but that's most of it.

I had a brief go at improving this, but I think it needs rather more
care than I have time for right now and should get independent review.
Given that bug 739066 exists, and this branch isn't a regression in
terms of query count as far as I can see, I think it would be best to
address the high per-SPPH count separately.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/lp/registry/browser/distributionsourcepackage.py'
2--- lib/lp/registry/browser/distributionsourcepackage.py 2012-08-07 02:31:56 +0000
3+++ lib/lp/registry/browser/distributionsourcepackage.py 2012-08-09 00:49:24 +0000
4@@ -598,6 +598,16 @@
5
6 page_title = 'Publishing history'
7
8+ def initialize(self):
9+ """Preload relevant `IPerson` objects."""
10+ ids = set()
11+ for spph in self.context.publishing_history:
12+ ids.update((spph.removed_byID, spph.creatorID, spph.sponsorID))
13+ ids.discard(None)
14+ if ids:
15+ list(getUtility(IPersonSet).getPrecachedPersonsFromIDs(
16+ ids, need_validity=True))
17+
18 @property
19 def label(self):
20 return 'Publishing history of %s' % self.context.title
21
22=== modified file 'lib/lp/registry/browser/tests/test_distributionsourcepackage.py'
23--- lib/lp/registry/browser/tests/test_distributionsourcepackage.py 2012-08-07 00:01:04 +0000
24+++ lib/lp/registry/browser/tests/test_distributionsourcepackage.py 2012-08-09 00:49:24 +0000
25@@ -1,10 +1,13 @@
26-# Copyright 2010 Canonical Ltd. This software is licensed under the
27+# Copyright 2010-2012 Canonical Ltd. This software is licensed under the
28 # GNU Affero General Public License version 3 (see the file LICENSE).
29
30 """Test distributionsourcepackage views."""
31
32 __metaclass__ = type
33
34+import re
35+
36+import soupmatchers
37 from zope.component import getUtility
38
39 from lp.app.enums import ServiceUsage
40@@ -12,6 +15,7 @@
41 from lp.soyuz.interfaces.archive import ArchivePurpose
42 from lp.testing import (
43 celebrity_logged_in,
44+ person_logged_in,
45 test_tales,
46 TestCaseWithFactory,
47 )
48@@ -20,7 +24,10 @@
49 LaunchpadFunctionalLayer,
50 )
51 from lp.testing.matchers import BrowsesWithQueryLimit
52-from lp.testing.views import create_view
53+from lp.testing.views import (
54+ create_initialized_view,
55+ create_view,
56+ )
57
58
59 class TestDistributionSourcePackageFormatterAPI(TestCaseWithFactory):
60@@ -57,6 +64,65 @@
61 self.assertThat(dsp, changelog_browses_under_limit)
62
63
64+class TestDistributionSourcePackagePublishingHistoryView(TestCaseWithFactory):
65+
66+ layer = LaunchpadFunctionalLayer
67+
68+ def test_publishinghistory_query_count(self):
69+ archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
70+ spph = self.factory.makeSourcePackagePublishingHistory(
71+ archive=archive)
72+ spn = spph.sourcepackagerelease.sourcepackagename
73+ dsp = archive.distribution.getSourcePackage(spn)
74+ publishinghistory_browses_under_limit = BrowsesWithQueryLimit(
75+ 27, self.factory.makePerson(), "+publishinghistory")
76+ self.assertThat(dsp, publishinghistory_browses_under_limit)
77+ with person_logged_in(archive.owner):
78+ copy_source_archive = self.factory.makeArchive()
79+ copy_spph = self.factory.makeSourcePackagePublishingHistory(
80+ archive=copy_source_archive, sourcepackagename=spn)
81+ copy_spph.copyTo(
82+ spph.distroseries, spph.pocket, archive,
83+ creator=self.factory.makePerson(),
84+ sponsor=self.factory.makePerson())
85+ delete_spph = self.factory.makeSourcePackagePublishingHistory(
86+ archive=archive, sourcepackagename=spn)
87+ delete_spph.requestDeletion(self.factory.makePerson())
88+ # This is a lot of extra queries per publication, and should be
89+ # ratcheted down over time; but it at least ensures that we don't
90+ # make matters any worse.
91+ publishinghistory_browses_under_limit.query_limit += 10
92+ self.assertThat(dsp, publishinghistory_browses_under_limit)
93+
94+ def test_show_sponsor(self):
95+ archive = self.factory.makeArchive(purpose=ArchivePurpose.PRIMARY)
96+ ppa = self.factory.makeArchive()
97+ spph = self.factory.makeSourcePackagePublishingHistory(archive=ppa)
98+ creator = self.factory.makePerson()
99+ sponsor = self.factory.makePerson()
100+ copied_spph = spph.copyTo(
101+ spph.distroseries, spph.pocket, archive, creator=creator,
102+ sponsor=sponsor)
103+ html = create_initialized_view(copied_spph, "+record-details").render()
104+ record_matches = soupmatchers.HTMLContains(
105+ soupmatchers.Tag(
106+ "copy summary", "li", text=re.compile("sponsored by")),
107+ soupmatchers.Tag(
108+ "copy creator", "a", text=creator.displayname,
109+ attrs={
110+ "href": "/~%s" % creator.name,
111+ "class": "sprite person",
112+ }),
113+ soupmatchers.Tag(
114+ "copy sponsor", "a", text=sponsor.displayname,
115+ attrs={
116+ "href": "/~%s" % sponsor.name,
117+ "class": "sprite person",
118+ }),
119+ )
120+ self.assertThat(html, record_matches)
121+
122+
123 class TestDistributionSourceView(TestCaseWithFactory):
124
125 layer = DatabaseFunctionalLayer
126
127=== modified file 'lib/lp/soyuz/interfaces/publishing.py'
128--- lib/lp/soyuz/interfaces/publishing.py 2012-06-19 17:10:12 +0000
129+++ lib/lp/soyuz/interfaces/publishing.py 2012-08-09 00:49:24 +0000
130@@ -429,6 +429,7 @@
131 required=False, readonly=False,
132 ),
133 exported_as="date_removed")
134+ removed_byID = Attribute("DB ID for removed_by.")
135 removed_by = exported(
136 Reference(
137 IPerson,
138@@ -500,6 +501,7 @@
139 description=_('The previous release of this source package.'),
140 required=False, readonly=True)
141
142+ creatorID = Attribute("DB ID for creator.")
143 creator = exported(
144 Reference(
145 IPerson,
146@@ -508,6 +510,7 @@
147 required=False, readonly=True
148 ))
149
150+ sponsorID = Attribute("DB ID for sponsor.")
151 sponsor = exported(
152 Reference(
153 IPerson,
154
155=== modified file 'lib/lp/soyuz/stories/ppa/xx-copy-packages.txt'
156--- lib/lp/soyuz/stories/ppa/xx-copy-packages.txt 2012-08-01 11:02:13 +0000
157+++ lib/lp/soyuz/stories/ppa/xx-copy-packages.txt 2012-08-09 00:49:24 +0000
158@@ -272,7 +272,8 @@
159 >>> jblack_extra_browser.open(expander_url)
160 >>> print extract_text(jblack_extra_browser.contents)
161 Publishing details
162- Copied from ubuntu hoary in Primary Archive for Ubuntu Linux
163+ Copied from ubuntu hoary in Primary Archive for Ubuntu Linux by James
164+ Blackwell
165 Changelog
166 pmount (0.1-1) hoary; urgency=low
167 * Fix description (Malone #1)
168
169=== modified file 'lib/lp/soyuz/templates/packagepublishing-details.pt'
170--- lib/lp/soyuz/templates/packagepublishing-details.pt 2012-02-10 10:14:20 +0000
171+++ lib/lp/soyuz/templates/packagepublishing-details.pt 2012-08-09 00:49:24 +0000
172@@ -41,8 +41,7 @@
173 define="linkify_archive view/linkify_source_archive;
174 source context/sourcepackagerelease">
175 <tal:message
176- define="archive source/upload_archive;
177- series source/upload_distroseries;
178+ define="series source/upload_distroseries;
179 distro series/distribution;
180 message string:${distro/name} ${series/name} in "
181 replace="message" />
182@@ -55,6 +54,12 @@
183 message string:${archive/displayname}"
184 replace="message" />
185 </tal:define>
186+ <tal:source_creator condition="context/creator">
187+ by <a tal:replace="structure context/creator/fmt:link"/>
188+ </tal:source_creator>
189+ <tal:source_sponsor condition="context/sponsor">
190+ (sponsored by <a tal:replace="structure context/sponsor/fmt:link"/>)
191+ </tal:source_sponsor>
192 </tal:source_original_location>
193 <tal:binary_build_location condition="view/is_binary">
194 <tal:message