Merge lp:~allenap/launchpad/localpackagediffs-show-changed-by-bug-798865 into lp:launchpad

Proposed by Gavin Panella
Status: Merged
Approved by: Gavin Panella
Approved revision: no longer in the source branch.
Merged at revision: 13508
Proposed branch: lp:~allenap/launchpad/localpackagediffs-show-changed-by-bug-798865
Merge into: lp:launchpad
Diff against target: 445 lines (+193/-113)
5 files modified
lib/canonical/launchpad/icing/style-3-0.css (+3/-0)
lib/lp/registry/browser/tests/test_distroseries.py (+159/-96)
lib/lp/registry/model/distroseriesdifference.py (+4/-2)
lib/lp/registry/templates/distroseries-localdifferences.pt (+25/-9)
lib/lp/soyuz/model/sourcepackagerelease.py (+2/-6)
To merge this branch: bzr merge lp:~allenap/launchpad/localpackagediffs-show-changed-by-bug-798865
Reviewer Review Type Date Requested Status
Henning Eggers (community) Approve
Review via email: mp+69072@code.launchpad.net

Commit message

[r=henninge][bug=798865] Show the package changer in DistroSeries:+localpackagediffs and co. as well as the uploader.

Description of the change

This changes the "Last changed by" column to "Last changed" because it shows a date too (it already did that before this branch). It also shows the in that column the person who made the package change instead of the person who uploaded it. In many cases these people are different. It does, however, show the uploader in smaller text.

Screenshot:
  http://people.canonical.com/~gavin/ui/localpackagediffs-show-changed-by-bug-798865/last-changed.png

It also merges the tests in TestDistroSeriesLocalDifferences and TestDistroSeriesLocalDifferencesZopeless and calls the resulting class TestDistroSeriesLocalDifferences.

To post a comment you must log in.
Revision history for this message
Henning Eggers (henninge) wrote :

Thank you for this improvement.
As discussed on IRC, please make the tests in the two implementations of test_diff_row_shows_spr_creator work in the same way.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/canonical/launchpad/icing/style-3-0.css'
2--- lib/canonical/launchpad/icing/style-3-0.css 2011-07-04 13:24:48 +0000
3+++ lib/canonical/launchpad/icing/style-3-0.css 2011-07-25 11:57:37 +0000
4@@ -306,6 +306,9 @@
5 min-width: 1em;
6 outline: 1px #666;
7 }
8+.nowrap {
9+ white-space: nowrap;
10+ }
11
12 /* =========================
13 Universal presentation
14
15=== modified file 'lib/lp/registry/browser/tests/test_distroseries.py'
16--- lib/lp/registry/browser/tests/test_distroseries.py 2011-07-21 09:27:45 +0000
17+++ lib/lp/registry/browser/tests/test_distroseries.py 2011-07-25 11:57:37 +0000
18@@ -91,6 +91,7 @@
19 login,
20 login_celebrity,
21 login_person,
22+ normalize_whitespace,
23 person_logged_in,
24 StormStatementRecorder,
25 TestCaseWithFactory,
26@@ -857,93 +858,6 @@
27 return (derived_series, parent_series)
28
29
30-class TestDistroSeriesLocalDifferences(
31- DistroSeriesDifferenceMixin, TestCaseWithFactory):
32- """Test the distroseries +localpackagediffs page."""
33-
34- layer = DatabaseFunctionalLayer
35-
36- def setUp(self):
37- super(TestDistroSeriesLocalDifferences,
38- self).setUp('foo.bar@canonical.com')
39- set_derived_series_ui_feature_flag(self)
40- self.simple_user = self.factory.makePerson()
41-
42- def test_filter_form_if_differences(self):
43- # Test that the page includes the filter form if differences
44- # are present
45- login_person(self.simple_user)
46- derived_series, parent_series = self._createChildAndParent()
47- self.factory.makeDistroSeriesDifference(
48- derived_series=derived_series)
49-
50- view = create_initialized_view(
51- derived_series, '+localpackagediffs', principal=self.simple_user)
52-
53- self.assertIsNot(
54- None,
55- find_tag_by_id(view(), 'distroseries-localdiff-search-filter'),
56- "Form filter should be shown when there are differences.")
57-
58- def test_filter_noform_if_nodifferences(self):
59- # Test that the page doesn't includes the filter form if no
60- # differences are present
61- login_person(self.simple_user)
62- derived_series, parent_series = self._createChildAndParent()
63-
64- view = create_initialized_view(
65- derived_series, '+localpackagediffs', principal=self.simple_user)
66-
67- self.assertIs(
68- None,
69- find_tag_by_id(view(), 'distroseries-localdiff-search-filter'),
70- "Form filter should not be shown when there are no differences.")
71-
72- def test_parent_packagesets_localpackagediffs(self):
73- # +localpackagediffs displays the packagesets.
74- ds_diff = self.factory.makeDistroSeriesDifference()
75- with celebrity_logged_in('admin'):
76- ps = self.factory.makePackageset(
77- packages=[ds_diff.source_package_name],
78- distroseries=ds_diff.derived_series)
79-
80- with person_logged_in(self.simple_user):
81- view = create_initialized_view(
82- ds_diff.derived_series,
83- '+localpackagediffs',
84- principal=self.simple_user)
85- html_content = view()
86-
87- packageset_text = re.compile('\s*' + ps.name)
88- self._test_packagesets(
89- html_content, packageset_text, 'packagesets',
90- 'Packagesets')
91-
92- def test_parent_packagesets_localpackagediffs_sorts(self):
93- # Multiple packagesets are sorted in a comma separated list.
94- ds_diff = self.factory.makeDistroSeriesDifference()
95- unsorted_names = [u"zzz", u"aaa"]
96- with celebrity_logged_in('admin'):
97- for name in unsorted_names:
98- self.factory.makePackageset(
99- name=name,
100- packages=[ds_diff.source_package_name],
101- distroseries=ds_diff.derived_series)
102-
103- with person_logged_in(self.simple_user):
104- view = create_initialized_view(
105- ds_diff.derived_series,
106- '+localpackagediffs',
107- principal=self.simple_user)
108- html_content = view()
109-
110- packageset_text = re.compile(
111- '\s*' + ', '.join(sorted(unsorted_names)))
112- self._test_packagesets(
113- html_content, packageset_text, 'packagesets',
114- 'Packagesets')
115-
116-
117 class TestDistroSeriesLocalDiffPerformance(TestCaseWithFactory,
118 DistroSeriesDifferenceMixin):
119 """Test the distroseries +localpackagediffs page's performance."""
120@@ -1076,8 +990,8 @@
121 self._assertQueryCount(derived_series)
122
123
124-class TestDistroSeriesLocalDifferencesZopeless(TestCaseWithFactory,
125- DistroSeriesDifferenceMixin):
126+class TestDistroSeriesLocalDifferences(TestCaseWithFactory,
127+ DistroSeriesDifferenceMixin):
128 """Test the distroseries +localpackagediffs view."""
129
130 layer = LaunchpadFunctionalLayer
131@@ -1107,6 +1021,88 @@
132 principal=get_current_principal(),
133 current_request=True)
134
135+ def test_filter_form_if_differences(self):
136+ # Test that the page includes the filter form if differences
137+ # are present
138+ simple_user = self.factory.makePerson()
139+ login_person(simple_user)
140+ derived_series, parent_series = self._createChildAndParent()
141+ self.factory.makeDistroSeriesDifference(
142+ derived_series=derived_series)
143+
144+ set_derived_series_ui_feature_flag(self)
145+ view = create_initialized_view(
146+ derived_series, '+localpackagediffs', principal=simple_user)
147+
148+ self.assertIsNot(
149+ None,
150+ find_tag_by_id(view(), 'distroseries-localdiff-search-filter'),
151+ "Form filter should be shown when there are differences.")
152+
153+ def test_filter_noform_if_nodifferences(self):
154+ # Test that the page doesn't includes the filter form if no
155+ # differences are present
156+ simple_user = self.factory.makePerson()
157+ login_person(simple_user)
158+ derived_series, parent_series = self._createChildAndParent()
159+
160+ set_derived_series_ui_feature_flag(self)
161+ view = create_initialized_view(
162+ derived_series, '+localpackagediffs', principal=simple_user)
163+
164+ self.assertIs(
165+ None,
166+ find_tag_by_id(view(), 'distroseries-localdiff-search-filter'),
167+ "Form filter should not be shown when there are no differences.")
168+
169+ def test_parent_packagesets_localpackagediffs(self):
170+ # +localpackagediffs displays the packagesets.
171+ ds_diff = self.factory.makeDistroSeriesDifference()
172+ with celebrity_logged_in('admin'):
173+ ps = self.factory.makePackageset(
174+ packages=[ds_diff.source_package_name],
175+ distroseries=ds_diff.derived_series)
176+
177+ set_derived_series_ui_feature_flag(self)
178+ simple_user = self.factory.makePerson()
179+ with person_logged_in(simple_user):
180+ view = create_initialized_view(
181+ ds_diff.derived_series,
182+ '+localpackagediffs',
183+ principal=simple_user)
184+ html_content = view()
185+
186+ packageset_text = re.compile('\s*' + ps.name)
187+ self._test_packagesets(
188+ html_content, packageset_text, 'packagesets',
189+ 'Packagesets')
190+
191+ def test_parent_packagesets_localpackagediffs_sorts(self):
192+ # Multiple packagesets are sorted in a comma separated list.
193+ ds_diff = self.factory.makeDistroSeriesDifference()
194+ unsorted_names = [u"zzz", u"aaa"]
195+ with celebrity_logged_in('admin'):
196+ for name in unsorted_names:
197+ self.factory.makePackageset(
198+ name=name,
199+ packages=[ds_diff.source_package_name],
200+ distroseries=ds_diff.derived_series)
201+
202+ set_derived_series_ui_feature_flag(self)
203+ simple_user = self.factory.makePerson()
204+ with person_logged_in(simple_user):
205+ view = create_initialized_view(
206+ ds_diff.derived_series,
207+ '+localpackagediffs',
208+ principal=simple_user)
209+ html_content = view()
210+
211+ packageset_text = re.compile(
212+ '\s*' + ', '.join(sorted(unsorted_names)))
213+ self._test_packagesets(
214+ html_content, packageset_text, 'packagesets',
215+ 'Packagesets')
216+
217 def test_view_redirects_without_feature_flag(self):
218 # If the feature flag soyuz.derived_series_ui.enabled is not set the
219 # view simply redirects to the derived series.
220@@ -1349,6 +1345,38 @@
221 self.assertEqual(versions['derived'], derived_span[0].string.strip())
222 self.assertEqual(versions['parent'], parent_span[0].string.strip())
223
224+ def test_diff_row_last_changed(self):
225+ # The SPR creator (i.e. who make the package change, rather than the
226+ # uploader) is shown on each difference row.
227+ set_derived_series_ui_feature_flag(self)
228+ dsd = self.makePackageUpgrade()
229+ view = self.makeView(dsd.derived_series)
230+ root = html.fromstring(view())
231+ [creator_cell] = root.cssselect(
232+ "table.listing tbody td.last-changed")
233+ self.assertEqual(
234+ "a moment ago by %s" % (
235+ dsd.source_package_release.creator.displayname,),
236+ normalize_whitespace(creator_cell.text_content()))
237+
238+ def test_diff_row_last_changed_also_shows_uploader_if_different(self):
239+ # When the SPR creator and uploader are different both are named on
240+ # each difference row.
241+ set_derived_series_ui_feature_flag(self)
242+ dsd = self.makePackageUpgrade()
243+ uploader = self.factory.makePerson()
244+ removeSecurityProxy(dsd.source_package_release).dscsigningkey = (
245+ self.factory.makeGPGKey(uploader))
246+ view = self.makeView(dsd.derived_series)
247+ root = html.fromstring(view())
248+ [creator_cell] = root.cssselect(
249+ "table.listing tbody td.last-changed")
250+ self.assertEqual(
251+ "a moment ago by %s (uploaded by %s)" % (
252+ dsd.source_package_release.creator.displayname,
253+ dsd.source_package_release.dscsigningkey.owner.displayname),
254+ normalize_whitespace(creator_cell.text_content()))
255+
256 def test_getUpgrades_shows_updates_in_parent(self):
257 # The view's getUpgrades methods lists packages that can be
258 # trivially upgraded: changed in the parent, not changed in the
259@@ -1477,12 +1505,6 @@
260 recorder2,
261 HasQueryCount(Equals(recorder1.count)))
262
263-
264-class TestDistroSeriesLocalDifferencesFunctional(TestCaseWithFactory,
265- DistroSeriesDifferenceMixin):
266-
267- layer = LaunchpadFunctionalLayer
268-
269 def makeDSDJob(self, dsd):
270 """Create a `DistroSeriesDifferenceJob` to update `dsd`."""
271 job_source = getUtility(IDistroSeriesDifferenceJobSource)
272@@ -2213,7 +2235,7 @@
273 DistroSeriesDifferenceMixin):
274 """Test the distroseries +missingpackages page."""
275
276- layer = DatabaseFunctionalLayer
277+ layer = LaunchpadFunctionalLayer
278
279 def setUp(self):
280 super(DistroSeriesMissingPackagesPageTestCase,
281@@ -2244,6 +2266,47 @@
282 html_content, packageset_text, 'parent-packagesets',
283 'Parent packagesets')
284
285+ def test_diff_row_last_changed(self):
286+ # The parent SPR creator (i.e. who make the package change, rather
287+ # than the uploader) is shown on each difference row.
288+ missing_type = DistroSeriesDifferenceType.MISSING_FROM_DERIVED_SERIES
289+ dsd = self.factory.makeDistroSeriesDifference(
290+ difference_type=missing_type)
291+ with person_logged_in(self.simple_user):
292+ view = create_initialized_view(
293+ dsd.derived_series, '+missingpackages',
294+ principal=self.simple_user)
295+ root = html.fromstring(view())
296+ [creator_cell] = root.cssselect(
297+ "table.listing tbody td.last-changed")
298+ self.assertEqual(
299+ "a moment ago by %s" % (
300+ dsd.parent_source_package_release.creator.displayname,),
301+ normalize_whitespace(creator_cell.text_content()))
302+
303+ def test_diff_row_last_changed_also_shows_uploader_if_different(self):
304+ # When the SPR creator and uploader are different both are named on
305+ # each difference row.
306+ missing_type = DistroSeriesDifferenceType.MISSING_FROM_DERIVED_SERIES
307+ dsd = self.factory.makeDistroSeriesDifference(
308+ difference_type=missing_type)
309+ uploader = self.factory.makePerson()
310+ naked_spr = removeSecurityProxy(dsd.parent_source_package_release)
311+ naked_spr.dscsigningkey = self.factory.makeGPGKey(uploader)
312+ with person_logged_in(self.simple_user):
313+ view = create_initialized_view(
314+ dsd.derived_series, '+missingpackages',
315+ principal=self.simple_user)
316+ root = html.fromstring(view())
317+ [creator_cell] = root.cssselect(
318+ "table.listing tbody td.last-changed")
319+ parent_spr = dsd.parent_source_package_release
320+ self.assertEqual(
321+ "a moment ago by %s (uploaded by %s)" % (
322+ parent_spr.creator.displayname,
323+ parent_spr.dscsigningkey.owner.displayname),
324+ normalize_whitespace(creator_cell.text_content()))
325+
326
327 class DistroSerieUniquePackageDiffsTestCase(TestCaseWithFactory,
328 DistroSeriesDifferenceMixin):
329
330=== modified file 'lib/lp/registry/model/distroseriesdifference.py'
331--- lib/lp/registry/model/distroseriesdifference.py 2011-07-08 09:06:24 +0000
332+++ lib/lp/registry/model/distroseriesdifference.py 2011-07-25 11:57:37 +0000
333@@ -481,11 +481,13 @@
334 gpgkeys = bulk.load_related(GPGKey, sprs, ("dscsigningkeyID",))
335
336 # Load DistroSeriesDifferenceComment owners,
337- # SourcePackageRecipeBuild requesters and GPGKey owners.
338+ # SourcePackageRecipeBuild requesters and GPGKey owners, and
339+ # SourcePackageRelease creators.
340 person_ids = set().union(
341 (dsdc.message.ownerID for dsdc in latest_comments),
342 (sprb.requester_id for sprb in sprbs),
343- (gpgkey.ownerID for gpgkey in gpgkeys))
344+ (gpgkey.ownerID for gpgkey in gpgkeys),
345+ (spr.creatorID for spr in sprs))
346 uploaders = getUtility(IPersonSet).getPrecachedPersonsFromIDs(
347 person_ids, need_validity=True)
348 list(uploaders)
349
350=== modified file 'lib/lp/registry/templates/distroseries-localdifferences.pt'
351--- lib/lp/registry/templates/distroseries-localdifferences.pt 2011-07-20 16:59:53 +0000
352+++ lib/lp/registry/templates/distroseries-localdifferences.pt 2011-07-25 11:57:37 +0000
353@@ -69,7 +69,7 @@
354 class="package-sets">
355 Package-sets
356 </th>
357- <th>Last uploaded</th>
358+ <th>Last changed</th>
359 <th>Latest comment</th>
360 </tr>
361 </thead>
362@@ -145,26 +145,42 @@
363 <tal:replace replace="difference/@@/packagesets_names" />
364 </td>
365
366- <td>
367+ <td class="last-changed">
368 <tal:parent condition="not: view/show_derived_version">
369 <tal:published condition="parent_source_pub">
370 <span tal:attributes="title parent_source_pub/datepublished/fmt:datetime"
371 tal:content="parent_source_pub/datepublished/fmt:approximatedate">2005-09-16</span>
372- <tal:signer condition="parent_source_pub/sourcepackagerelease/uploader">
373- by <a tal:replace="structure parent_source_pub/sourcepackagerelease/uploader/fmt:link">Steph Smith</a>
374- </tal:signer>
375+ <tal:creator define="spr parent_source_pub/sourcepackagerelease">
376+ <span class="nowrap">by <a tal:replace="structure spr/creator/fmt:link" /></span>
377+ </tal:creator>
378+ <tal:uploader
379+ define="spr parent_source_pub/sourcepackagerelease"
380+ condition="python: spr.uploader not in (None, spr.creator)">
381+ <br />
382+ <span class="discreet nowrap">
383+ (uploaded by <a tal:replace="structure spr/uploader/fmt:link" />)
384+ </span>
385+ </tal:uploader>
386 </tal:published>
387 <tal:not-published condition="not:parent_source_pub">
388 <span tal:content="difference/parent_source_version" />
389 </tal:not-published>
390 </tal:parent>
391 <tal:derived condition="view/show_derived_version">
392- <tal:published condition="parent_source_pub">
393+ <tal:published condition="source_pub">
394 <span tal:attributes="title source_pub/datepublished/fmt:datetime"
395 tal:content="source_pub/datepublished/fmt:approximatedate">2005-09-16</span>
396- <tal:signer condition="source_pub/sourcepackagerelease/uploader">
397- by <a tal:replace="structure source_pub/sourcepackagerelease/uploader/fmt:link">Steph Smith</a>
398- </tal:signer>
399+ <tal:creator define="spr source_pub/sourcepackagerelease">
400+ <span class="nowrap">by <a tal:replace="structure spr/creator/fmt:link" /></span>
401+ </tal:creator>
402+ <tal:uploader
403+ define="spr source_pub/sourcepackagerelease"
404+ condition="python: spr.uploader not in (None, spr.creator)">
405+ <br />
406+ <span class="discreet nowrap">
407+ (uploaded by <a tal:replace="structure spr/uploader/fmt:link" />)
408+ </span>
409+ </tal:uploader>
410 </tal:published>
411 <tal:not-published condition="not:source_pub">
412 <span tal:content="difference/source_version" />
413
414=== modified file 'lib/lp/soyuz/model/sourcepackagerelease.py'
415--- lib/lp/soyuz/model/sourcepackagerelease.py 2011-06-16 11:31:24 +0000
416+++ lib/lp/soyuz/model/sourcepackagerelease.py 2011-07-25 11:57:37 +0000
417@@ -47,7 +47,6 @@
418 LibraryFileContent,
419 )
420 from canonical.launchpad.helpers import shortlist
421-from lp.app.errors import NotFoundError
422 from lp.app.interfaces.launchpad import ILaunchpadCelebrities
423 from lp.archiveuploader.utils import determine_source_file_type
424 from lp.buildmaster.enums import BuildStatus
425@@ -61,10 +60,7 @@
426 PackageDiffStatus,
427 PackagePublishingStatus,
428 )
429-from lp.soyuz.interfaces.archive import (
430- IArchiveSet,
431- MAIN_ARCHIVE_PURPOSES,
432- )
433+from lp.soyuz.interfaces.archive import MAIN_ARCHIVE_PURPOSES
434 from lp.soyuz.interfaces.binarypackagebuild import IBinaryPackageBuildSet
435 from lp.soyuz.interfaces.packagediff import PackageDiffAlreadyRequested
436 from lp.soyuz.interfaces.sourcepackagerelease import ISourcePackageRelease
437@@ -574,7 +570,7 @@
438
439 queue = getUtility(ITranslationImportQueue)
440
441- only_templates=self.sourcepackage.has_sharing_translation_templates
442+ only_templates = self.sourcepackage.has_sharing_translation_templates
443 queue.addOrUpdateEntriesFromTarball(
444 tarball, by_maintainer, importer,
445 sourcepackagename=self.sourcepackagename,