Merge lp:~stevenk/launchpad/destroy-distribution-upstreamreport into lp:launchpad
- destroy-distribution-upstreamreport
- Merge into devel
Proposed by
Steve Kowalik
on 2012-11-02
| Status: | Merged | ||||||||
|---|---|---|---|---|---|---|---|---|---|
| Approved by: | Curtis Hovey on 2012-11-02 | ||||||||
| Approved revision: | no longer in the source branch. | ||||||||
| Merged at revision: | 16230 | ||||||||
| Proposed branch: | lp:~stevenk/launchpad/destroy-distribution-upstreamreport | ||||||||
| Merge into: | lp:launchpad | ||||||||
| Diff against target: |
1946 lines (+2/-1845) 8 files modified
lib/lp/bugs/browser/configure.zcml (+0/-6) lib/lp/bugs/browser/distribution_upstream_report.py (+0/-391) lib/lp/bugs/browser/tests/test_distribution_upstream_report.py (+0/-218) lib/lp/bugs/doc/distribution-upstream-report.txt (+0/-432) lib/lp/bugs/stories/distribution/xx-distribution-upstream-report.txt (+0/-303) lib/lp/bugs/templates/distribution-upstream-report.pt (+0/-298) lib/lp/registry/interfaces/distribution.py (+0/-23) lib/lp/registry/model/distribution.py (+2/-174) |
||||||||
| To merge this branch: | bzr merge lp:~stevenk/launchpad/destroy-distribution-upstreamreport | ||||||||
| Related bugs: |
|
| Reviewer | Review Type | Date Requested | Status |
|---|---|---|---|
| Curtis Hovey (community) | code | 2012-11-02 | Approve on 2012-11-02 |
|
Review via email:
|
|||
Commit Message
Destroy Distribution:
Description of the Change
Distribution:
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
| 1 | === modified file 'lib/lp/bugs/browser/configure.zcml' |
| 2 | --- lib/lp/bugs/browser/configure.zcml 2012-10-11 04:57:59 +0000 |
| 3 | +++ lib/lp/bugs/browser/configure.zcml 2012-11-02 01:01:22 +0000 |
| 4 | @@ -345,12 +345,6 @@ |
| 5 | template="../templates/product-cvereport.pt"/> |
| 6 | <browser:page |
| 7 | for="lp.registry.interfaces.distribution.IDistribution" |
| 8 | - name="+upstreamreport" |
| 9 | - class="lp.bugs.browser.distribution_upstream_report.DistributionUpstreamReport" |
| 10 | - permission="zope.Public" |
| 11 | - template="../templates/distribution-upstream-report.pt"/> |
| 12 | - <browser:page |
| 13 | - for="lp.registry.interfaces.distribution.IDistribution" |
| 14 | class="lp.bugs.browser.cvereport.CVEReportView" |
| 15 | permission="zope.Public" |
| 16 | name="+cve" |
| 17 | |
| 18 | === removed file 'lib/lp/bugs/browser/distribution_upstream_report.py' |
| 19 | --- lib/lp/bugs/browser/distribution_upstream_report.py 2012-05-25 19:58:27 +0000 |
| 20 | +++ lib/lp/bugs/browser/distribution_upstream_report.py 1970-01-01 00:00:00 +0000 |
| 21 | @@ -1,391 +0,0 @@ |
| 22 | -# Copyright 2009-2011 Canonical Ltd. This software is licensed under the |
| 23 | -# GNU Affero General Public License version 3 (see the file LICENSE). |
| 24 | - |
| 25 | -"""Browser views for distributions.""" |
| 26 | - |
| 27 | -__metaclass__ = type |
| 28 | - |
| 29 | -__all__ = [ |
| 30 | - 'DistributionUpstreamReport', |
| 31 | - ] |
| 32 | - |
| 33 | -from operator import attrgetter |
| 34 | - |
| 35 | -from lp.app.enums import ServiceUsage |
| 36 | -from lp.bugs.browser.bugtask import get_buglisting_search_filter_url |
| 37 | -from lp.services.propertycache import cachedproperty |
| 38 | -from lp.services.webapp.publisher import ( |
| 39 | - canonical_url, |
| 40 | - LaunchpadView, |
| 41 | - ) |
| 42 | -from lp.services.webapp.url import urlappend |
| 43 | - |
| 44 | -# TODO: fix column sorting to work for the different colspans, or |
| 45 | -# alternatively implement a sort option box. |
| 46 | -# TODO: make the totals column also link to bug listings. |
| 47 | -# TODO A fourth potential count could be a count of open distribution |
| 48 | -# bugs that are fixed upstream, which would imply closing the loop |
| 49 | -# of upstream fixes back to the distribution. |
| 50 | - |
| 51 | - |
| 52 | -class BugReportData: |
| 53 | - """Represents a row of bug count data in the report. |
| 54 | - |
| 55 | - This is a base class and is directly used only for the totals row. |
| 56 | - See the help text in the template for a verbose description of what |
| 57 | - the numbers mean. Briefly, we hold three counts: |
| 58 | - |
| 59 | - 1. open: bugs with distribution tasks with a status of one of |
| 60 | - interfaces.bugtask.UNRESOLVED_BUGTASK_STATUSES. |
| 61 | - 2. triaged: bugs with distribution tasks that are TRIAGED |
| 62 | - 3. upstream: bugs that are triaged and have an upstream task against |
| 63 | - them. |
| 64 | - 4. watched: bugs that are triaged and have an upstream task linked |
| 65 | - to a watch. |
| 66 | - |
| 67 | - This class makes the three latter counts available as percentages and |
| 68 | - deltas to their predecessor. The report gives the impression of a |
| 69 | - pipeline where bugs trickle into the next count. |
| 70 | - |
| 71 | - The *_class() methods return "good" or nothing, and are intended for |
| 72 | - use in a CSS class. They calculate their values based on the |
| 73 | - UPSTREAM_THRESHOLD and WATCH_THRESHOLD class variables. The reason |
| 74 | - we calculate them is that until we have a way of tracking whether a |
| 75 | - bug is actually /not/ upstream we can't assume 100% of distribution |
| 76 | - bugs need upstream tasks. |
| 77 | - """ |
| 78 | - TRIAGED_THRESHOLD = 75 |
| 79 | - UPSTREAM_THRESHOLD = 90 |
| 80 | - WATCH_THRESHOLD = 90 |
| 81 | - |
| 82 | - BAD_THRESHOLD = 20 |
| 83 | - |
| 84 | - def __init__(self, open_bugs=0, triaged_bugs=0, upstream_bugs=0, |
| 85 | - watched_bugs=0, bugs_with_upstream_patches=0): |
| 86 | - self.open_bugs = open_bugs |
| 87 | - self.triaged_bugs = triaged_bugs |
| 88 | - self.upstream_bugs = upstream_bugs |
| 89 | - self.watched_bugs = watched_bugs |
| 90 | - self.bugs_with_upstream_patches = bugs_with_upstream_patches |
| 91 | - |
| 92 | - @staticmethod |
| 93 | - def _as_percentage(number, total): |
| 94 | - if total: |
| 95 | - return round(100.0 * number / total, 2) |
| 96 | - else: |
| 97 | - return 0.0 |
| 98 | - |
| 99 | - @property |
| 100 | - def triaged_bugs_percentage(self): |
| 101 | - return self._as_percentage(self.triaged_bugs, self.open_bugs) |
| 102 | - |
| 103 | - @property |
| 104 | - def upstream_bugs_percentage(self): |
| 105 | - return self._as_percentage(self.upstream_bugs, self.open_bugs) |
| 106 | - |
| 107 | - @property |
| 108 | - def watched_bugs_percentage(self): |
| 109 | - return self._as_percentage(self.watched_bugs, self.upstream_bugs) |
| 110 | - |
| 111 | - @property |
| 112 | - def row_class(self): |
| 113 | - """Return the class to be used for the current table row. |
| 114 | - |
| 115 | - :returns: 'good' if watched_bugs_percentage > WATCH_THRESHOLD; |
| 116 | - 'bad' if watched_bugs_percentage < BAD_THRESHOLD; |
| 117 | - '' otherwise. |
| 118 | - """ |
| 119 | - if self.watched_bugs_percentage > self.WATCH_THRESHOLD: |
| 120 | - return "good" |
| 121 | - elif self.watched_bugs_percentage < self.BAD_THRESHOLD: |
| 122 | - return "bad" |
| 123 | - else: |
| 124 | - return '' |
| 125 | - |
| 126 | - @staticmethod |
| 127 | - def _as_value_class(percentage, threshold): |
| 128 | - if percentage > threshold: |
| 129 | - return "good" |
| 130 | - return "" |
| 131 | - |
| 132 | - @property |
| 133 | - def triaged_bugs_class(self): |
| 134 | - return self._as_value_class( |
| 135 | - self.triaged_bugs_percentage, self.TRIAGED_THRESHOLD) |
| 136 | - |
| 137 | - @property |
| 138 | - def upstream_bugs_class(self): |
| 139 | - return self._as_value_class( |
| 140 | - self.upstream_bugs_percentage, self.UPSTREAM_THRESHOLD) |
| 141 | - |
| 142 | - @property |
| 143 | - def watched_bugs_class(self): |
| 144 | - return self._as_value_class( |
| 145 | - self.watched_bugs_percentage, self.WATCH_THRESHOLD) |
| 146 | - |
| 147 | - @property |
| 148 | - def triaged_bugs_delta(self): |
| 149 | - return self.open_bugs - self.triaged_bugs |
| 150 | - |
| 151 | - @property |
| 152 | - def upstream_bugs_delta(self): |
| 153 | - return self.open_bugs - self.upstream_bugs |
| 154 | - |
| 155 | - @property |
| 156 | - def watched_bugs_delta(self): |
| 157 | - return self.upstream_bugs - self.watched_bugs |
| 158 | - |
| 159 | - |
| 160 | -class PackageBugReportData(BugReportData): |
| 161 | - """Represents a package row in the report. |
| 162 | - |
| 163 | - Apart from the counts, includes data to make it easy to link to |
| 164 | - pages which allow inputting missing information related to the |
| 165 | - package. Relevant instance variables: |
| 166 | - |
| 167 | - - dsp: an IDistributionSourcePackage |
| 168 | - - dssp: an IDistributionSeriesSourcepackage |
| 169 | - - product: an IProduct |
| 170 | - - bugtracker: convenience holder for the product's bugtracker |
| 171 | - - bug_tracking_usage: convenience enum for |
| 172 | - IProduct.bug_tracking_usage |
| 173 | - - *_url: convenience URLs |
| 174 | - """ |
| 175 | - |
| 176 | - def __init__(self, dsp, dssp, product, open_bugs, triaged_bugs, |
| 177 | - upstream_bugs, watched_bugs, bugs_with_upstream_patches): |
| 178 | - BugReportData.__init__(self, open_bugs, triaged_bugs, upstream_bugs, |
| 179 | - watched_bugs, bugs_with_upstream_patches) |
| 180 | - self.dsp = dsp |
| 181 | - self.dssp = dssp |
| 182 | - self.product = product |
| 183 | - |
| 184 | - dsp_bugs_url = canonical_url(dsp, rootsite='bugs') |
| 185 | - |
| 186 | - self.open_bugs_url = urlappend( |
| 187 | - dsp_bugs_url, get_buglisting_search_filter_url()) |
| 188 | - |
| 189 | - if product is not None: |
| 190 | - self.bug_tracking_usage = product.bug_tracking_usage |
| 191 | - self.branch = product.development_focus.branch |
| 192 | - else: |
| 193 | - self.bug_tracking_usage = ServiceUsage.UNKNOWN |
| 194 | - self.branch = None |
| 195 | - |
| 196 | - # If a product is specified, build some convenient links to |
| 197 | - # pages which allow filling out required information. The |
| 198 | - # template ensures they are only visible to people who can |
| 199 | - # actually change the product. |
| 200 | - if self.product: |
| 201 | - product_url = canonical_url(product) |
| 202 | - self.bugtracker = self.product.getExternalBugTracker() |
| 203 | - |
| 204 | - self.product_edit_url = product_url + "/+edit" |
| 205 | - self.bug_supervisor_url = product_url + "/+bugsupervisor" |
| 206 | - |
| 207 | - # Create a 'bugtracker_name' attribute for searching. |
| 208 | - if self.bugtracker is not None: |
| 209 | - self.bugtracker_name = self.bugtracker.title |
| 210 | - elif self.product.bug_tracking_usage == ServiceUsage.LAUNCHPAD: |
| 211 | - self.bugtracker_name = 'Launchpad' |
| 212 | - else: |
| 213 | - self.bugtracker_name = None |
| 214 | - |
| 215 | - if self.product.bug_supervisor is not None: |
| 216 | - self.bug_supervisor_name = ( |
| 217 | - self.product.bug_supervisor.displayname) |
| 218 | - else: |
| 219 | - self.bug_supervisor_name = None |
| 220 | - else: |
| 221 | - # Set bug_supervisor and bugtracker to None so that the |
| 222 | - # sorting code doesn't choke. |
| 223 | - self.bug_supervisor_name = None |
| 224 | - self.bugtracker_name = None |
| 225 | - |
| 226 | - # Note that the +edit-packaging page allows launchpad.AnyPerson |
| 227 | - # so no permissions check needs to be done in the template. |
| 228 | - self.packaging_url = canonical_url(self.dssp) + "/+edit-packaging" |
| 229 | - self.triaged_bugs_url = urlappend( |
| 230 | - dsp_bugs_url, get_buglisting_search_filter_url(status='TRIAGED')) |
| 231 | - |
| 232 | - # The triaged delta URL links to all bugs that are open but not |
| 233 | - # triaged for the current DistributionSourcePackage. |
| 234 | - untriaged_bug_statuses = [ |
| 235 | - 'CONFIRMED', |
| 236 | - 'INCOMPLETE_WITHOUT_RESPONSE', |
| 237 | - 'INCOMPLETE_WITH_RESPONSE', |
| 238 | - 'NEW', |
| 239 | - ] |
| 240 | - untriaged_search_filter_url = get_buglisting_search_filter_url( |
| 241 | - status=untriaged_bug_statuses) |
| 242 | - self.triaged_bugs_delta_url = urlappend( |
| 243 | - dsp_bugs_url, untriaged_search_filter_url) |
| 244 | - |
| 245 | - # The upstream URL links to all bugs that are open and have an |
| 246 | - # open upstream bug task or bug watch. |
| 247 | - upstream_search_filter_url = get_buglisting_search_filter_url( |
| 248 | - status_upstream='open_upstream') |
| 249 | - self.upstream_bugs_url = urlappend( |
| 250 | - dsp_bugs_url, upstream_search_filter_url) |
| 251 | - |
| 252 | - # The upstream delta URL links to all bugs that are open without |
| 253 | - # an upstream bug task or bug watch. |
| 254 | - non_upstream_search_filter_url = get_buglisting_search_filter_url( |
| 255 | - status_upstream='hide_upstream') |
| 256 | - self.upstream_bugs_delta_url = urlappend( |
| 257 | - dsp_bugs_url, non_upstream_search_filter_url) |
| 258 | - |
| 259 | - # The watch delta URL links to all open upstream bugs that don't |
| 260 | - # have a bugwatch. |
| 261 | - unwatched_bugs_search_filter_url = get_buglisting_search_filter_url( |
| 262 | - status_upstream='pending_bugwatch') |
| 263 | - self.watched_bugs_delta_url = urlappend( |
| 264 | - dsp_bugs_url, unwatched_bugs_search_filter_url) |
| 265 | - |
| 266 | - # The bugs with upstream patches URL links to all open upstream |
| 267 | - # bugs that don't have a bugwatch but have patches attached. |
| 268 | - bugs_with_upstream_patches_filter_url = ( |
| 269 | - get_buglisting_search_filter_url( |
| 270 | - status_upstream='pending_bugwatch', has_patches=True)) |
| 271 | - self.bugs_with_upstream_patches_url = urlappend( |
| 272 | - dsp_bugs_url, bugs_with_upstream_patches_filter_url) |
| 273 | - |
| 274 | - |
| 275 | -class DistributionUpstreamReport(LaunchpadView): |
| 276 | - """Implements the actual upstream report. |
| 277 | - |
| 278 | - Most of the work is actually done in the |
| 279 | - getPackagesAndPublicUpstreamBugCounts API, and in the *Data classes |
| 280 | - constructed from here. |
| 281 | - """ |
| 282 | - LIMIT = 100 |
| 283 | - |
| 284 | - valid_sort_keys = [ |
| 285 | - 'bugtracker_name', |
| 286 | - 'bug_supervisor_name', |
| 287 | - 'bugs_with_upstream_patches', |
| 288 | - 'dsp', |
| 289 | - 'open_bugs', |
| 290 | - 'product', |
| 291 | - 'triaged_bugs', |
| 292 | - 'triaged_bugs_class', |
| 293 | - 'triaged_bugs_delta', |
| 294 | - 'triaged_bugs_percentage', |
| 295 | - 'upstream_bugs', |
| 296 | - 'upstream_bugs_class', |
| 297 | - 'upstream_bugs_delta', |
| 298 | - 'upstream_bugs_percentage', |
| 299 | - 'watched_bugs', |
| 300 | - 'watched_bugs_class', |
| 301 | - 'watched_bugs_delta', |
| 302 | - 'watched_bugs_percentage', |
| 303 | - ] |
| 304 | - |
| 305 | - arrow_up = "/@@/arrowUp" |
| 306 | - arrow_down = "/@@/arrowDown" |
| 307 | - arrow_blank = "/@@/arrowBlank" |
| 308 | - |
| 309 | - @property |
| 310 | - def page_title(self): |
| 311 | - return 'Upstream Report for %s' % self.context.title |
| 312 | - |
| 313 | - @property |
| 314 | - def sort_order(self): |
| 315 | - """Return the sort order for the report. |
| 316 | - |
| 317 | - :returns: The sort order as a dict of (sort_key, reversed). |
| 318 | - """ |
| 319 | - sort_order = self.request.get('sort_by', '-open_bugs') |
| 320 | - |
| 321 | - sort_key = sort_order |
| 322 | - if sort_key.startswith('-'): |
| 323 | - sort_key = sort_key.replace('-', '') |
| 324 | - reversed = True |
| 325 | - else: |
| 326 | - reversed = False |
| 327 | - |
| 328 | - # Validate the sort key before proceeding. |
| 329 | - if sort_key not in self.valid_sort_keys: |
| 330 | - return ('open_bugs', True) |
| 331 | - else: |
| 332 | - return (sort_key, reversed) |
| 333 | - |
| 334 | - @cachedproperty |
| 335 | - def data(self): |
| 336 | - """Return the _data list, sorted by `sort_order`.""" |
| 337 | - sort_key, reversed = self.sort_order |
| 338 | - data = sorted( |
| 339 | - self._data, key=attrgetter(sort_key), reverse=reversed) |
| 340 | - |
| 341 | - return data |
| 342 | - |
| 343 | - @cachedproperty |
| 344 | - def sort_order_links(self): |
| 345 | - """Return a dict of sort order links based on the current sort_order. |
| 346 | - """ |
| 347 | - current_sort_key, reversed = self.sort_order |
| 348 | - sort_order_links = {} |
| 349 | - |
| 350 | - # Loop over the possible sort keys and work out what the link |
| 351 | - # should be for that column. |
| 352 | - base_url = canonical_url(self.context, view_name='+upstreamreport') |
| 353 | - for sort_key in self.valid_sort_keys: |
| 354 | - if sort_key == current_sort_key: |
| 355 | - if not reversed: |
| 356 | - sort_order = '-%s' % sort_key |
| 357 | - arrow = self.arrow_up |
| 358 | - else: |
| 359 | - sort_order = sort_key |
| 360 | - arrow = self.arrow_down |
| 361 | - else: |
| 362 | - sort_order = sort_key |
| 363 | - arrow = self.arrow_blank |
| 364 | - |
| 365 | - sort_order_links[sort_key] = { |
| 366 | - 'link': base_url + '?sort_by=%s' % sort_order, |
| 367 | - 'arrow': arrow, |
| 368 | - } |
| 369 | - |
| 370 | - return sort_order_links |
| 371 | - |
| 372 | - @cachedproperty |
| 373 | - def current_distro_series(self): |
| 374 | - """Cache the current distroseries. |
| 375 | - |
| 376 | - This avoids us having to reissue this query for each row we want |
| 377 | - to produce an IDistroSeriesSourcePackage for. |
| 378 | - """ |
| 379 | - return self.context.currentseries |
| 380 | - |
| 381 | - def initialize(self): |
| 382 | - """Assemble self._data and self.total from upstream count report.""" |
| 383 | - self._data = [] |
| 384 | - self.total = BugReportData() |
| 385 | - packages_to_exclude = self.context.upstream_report_excluded_packages |
| 386 | - counts = self.context.getPackagesAndPublicUpstreamBugCounts( |
| 387 | - limit=self.LIMIT, exclude_packages=packages_to_exclude) |
| 388 | - # The upstream report is not useful if the distibution |
| 389 | - # does not track its bugs on Lauchpad or if it does not have a |
| 390 | - # current distroseries. |
| 391 | - self.has_upstream_report = ( |
| 392 | - self.context.bug_tracking_usage == ServiceUsage.LAUNCHPAD and |
| 393 | - self.current_distro_series is not None) |
| 394 | - if not self.has_upstream_report: |
| 395 | - return |
| 396 | - for (dsp, product, open, triaged, upstream, watched, |
| 397 | - bugs_with_upstream_patches) in counts: |
| 398 | - # The +edit-packaging page is only available for |
| 399 | - # IDistributionSeriesSourcepackages, so deduce one here. If |
| 400 | - # the distribution doesn't have series we can't offer a link |
| 401 | - # to add packaging information. |
| 402 | - dssp = self.current_distro_series.getSourcePackage( |
| 403 | - dsp.sourcepackagename) |
| 404 | - self.total.open_bugs += open |
| 405 | - self.total.triaged_bugs += triaged |
| 406 | - self.total.upstream_bugs += upstream |
| 407 | - self.total.watched_bugs += watched |
| 408 | - |
| 409 | - item = PackageBugReportData( |
| 410 | - dsp, dssp, product, open, triaged, upstream, watched, |
| 411 | - bugs_with_upstream_patches) |
| 412 | - self._data.append(item) |
| 413 | |
| 414 | === removed file 'lib/lp/bugs/browser/tests/test_distribution_upstream_report.py' |
| 415 | --- lib/lp/bugs/browser/tests/test_distribution_upstream_report.py 2012-06-14 05:18:22 +0000 |
| 416 | +++ lib/lp/bugs/browser/tests/test_distribution_upstream_report.py 1970-01-01 00:00:00 +0000 |
| 417 | @@ -1,218 +0,0 @@ |
| 418 | -# Copyright 2009-2012 Canonical Ltd. This software is licensed under the |
| 419 | -# GNU Affero General Public License version 3 (see the file LICENSE). |
| 420 | - |
| 421 | -"""Unit tests for DistributionUpstreamReport.""" |
| 422 | - |
| 423 | -__metaclass__ = type |
| 424 | - |
| 425 | - |
| 426 | -from soupmatchers import ( |
| 427 | - HTMLContains, |
| 428 | - Tag, |
| 429 | - ) |
| 430 | -from testtools.matchers import Not |
| 431 | -from zope.component import getUtility |
| 432 | - |
| 433 | -from lp.app.enums import ServiceUsage |
| 434 | -from lp.app.interfaces.launchpad import ILaunchpadCelebrities |
| 435 | -from lp.bugs.browser.distribution_upstream_report import ( |
| 436 | - BugReportData, |
| 437 | - DistributionUpstreamReport, |
| 438 | - ) |
| 439 | -from lp.testing import ( |
| 440 | - BrowserTestCase, |
| 441 | - person_logged_in, |
| 442 | - TestCase, |
| 443 | - TestCaseWithFactory, |
| 444 | - ) |
| 445 | -from lp.testing.layers import ( |
| 446 | - DatabaseFunctionalLayer, |
| 447 | - LaunchpadFunctionalLayer, |
| 448 | - ) |
| 449 | -from lp.testing.views import ( |
| 450 | - create_initialized_view, |
| 451 | - create_view, |
| 452 | - ) |
| 453 | - |
| 454 | - |
| 455 | -class BugReportDataTestCase(TestCase): |
| 456 | - |
| 457 | - def make_bug_report_data(self): |
| 458 | - return BugReportData( |
| 459 | - open_bugs=90, triaged_bugs=50, upstream_bugs=70, watched_bugs=60) |
| 460 | - |
| 461 | - def test_init(self): |
| 462 | - bug_data = self.make_bug_report_data() |
| 463 | - self.assertEqual(90, bug_data.open_bugs) |
| 464 | - self.assertEqual(50, bug_data.triaged_bugs) |
| 465 | - self.assertEqual(70, bug_data.upstream_bugs) |
| 466 | - self.assertEqual(60, bug_data.watched_bugs) |
| 467 | - |
| 468 | - def test_percentage_properties(self): |
| 469 | - bug_data = self.make_bug_report_data() |
| 470 | - self.assertEqual(55.56, bug_data.triaged_bugs_percentage) |
| 471 | - self.assertEqual(77.78, bug_data.upstream_bugs_percentage) |
| 472 | - self.assertEqual(85.71, bug_data.watched_bugs_percentage) |
| 473 | - |
| 474 | - def test_as_percentage(self): |
| 475 | - bug_data = self.make_bug_report_data() |
| 476 | - self.assertEqual(55.56, bug_data._as_percentage(50, 90)) |
| 477 | - self.assertEqual(0.0, bug_data._as_percentage(50, 0)) |
| 478 | - |
| 479 | - def test_delta_properties(self): |
| 480 | - bug_data = self.make_bug_report_data() |
| 481 | - self.assertEqual(40, bug_data.triaged_bugs_delta) |
| 482 | - self.assertEqual(20, bug_data.upstream_bugs_delta) |
| 483 | - self.assertEqual(10, bug_data.watched_bugs_delta) |
| 484 | - |
| 485 | - def test_as_value_class(self): |
| 486 | - bug_data = self.make_bug_report_data() |
| 487 | - self.assertEqual('good', bug_data._as_value_class(60, 50)) |
| 488 | - self.assertEqual('', bug_data._as_value_class(50, 50)) |
| 489 | - self.assertEqual('', bug_data._as_value_class(40, 50)) |
| 490 | - |
| 491 | - def test_value_class(self): |
| 492 | - bug_data = self.make_bug_report_data() |
| 493 | - bug_data.watched_bugs = 80 |
| 494 | - self.assertEqual('', bug_data.triaged_bugs_class) |
| 495 | - self.assertEqual('', bug_data.upstream_bugs_class) |
| 496 | - self.assertEqual('good', bug_data.watched_bugs_class) |
| 497 | - |
| 498 | - def test_row_class(self): |
| 499 | - bug_data = self.make_bug_report_data() |
| 500 | - self.assertEqual('', bug_data.row_class) |
| 501 | - bug_data.watched_bugs = 80 |
| 502 | - self.assertEqual('good', bug_data.row_class) |
| 503 | - bug_data.watched_bugs = 11 |
| 504 | - self.assertEqual('bad', bug_data.row_class) |
| 505 | - |
| 506 | - |
| 507 | -class TestDistributionUpstreamReport(TestCaseWithFactory): |
| 508 | - |
| 509 | - layer = DatabaseFunctionalLayer |
| 510 | - |
| 511 | - def test_valid_sort_keys_are_valid(self): |
| 512 | - # The valid_sort_keys property of the |
| 513 | - # DistributionUpstreamReport view contains a list of the sort |
| 514 | - # keys that the view considers valid. Using any one of these |
| 515 | - # keys, including when prepended with a '-', will lead to it |
| 516 | - # being set as the view's sort_order key. |
| 517 | - ubuntu = getUtility(ILaunchpadCelebrities).ubuntu |
| 518 | - for sort_key in DistributionUpstreamReport.valid_sort_keys: |
| 519 | - form = {'sort_by': sort_key} |
| 520 | - view = create_view(ubuntu, '+upstreamreport', form) |
| 521 | - |
| 522 | - # The sort_order property of DistributionUpstreamReport is |
| 523 | - # a tuple in the form (sort_key, reversed). |
| 524 | - view_sort_key, view_sort_reversed = view.sort_order |
| 525 | - self.assertEqual(view_sort_key, sort_key, |
| 526 | - "Expected a sort_key of '%s', got '%s'" % |
| 527 | - (sort_key, view_sort_key)) |
| 528 | - |
| 529 | - # By default, reversed is False. |
| 530 | - self.assertFalse(view_sort_reversed, |
| 531 | - "Sort order should not be reversed for a sort_by value of " |
| 532 | - "%s" % sort_key) |
| 533 | - |
| 534 | - # Prepending a '-' to sort_by will reverse the sort. |
| 535 | - reversed_key = '-%s' % sort_key |
| 536 | - form = {'sort_by': reversed_key} |
| 537 | - view = create_view(ubuntu, '+upstreamreport', form) |
| 538 | - |
| 539 | - # The sort_key part of view.sort_order will be the same as |
| 540 | - # for a normal sort. |
| 541 | - view_sort_key, view_sort_reversed = view.sort_order |
| 542 | - self.assertEqual(view_sort_key, sort_key, |
| 543 | - "Expected a sort_key of '%s', got '%s'" % |
| 544 | - (sort_key, view_sort_key)) |
| 545 | - |
| 546 | - # But reversed is now True. |
| 547 | - self.assertTrue(view_sort_reversed, |
| 548 | - "Sort order should be reversed for a sort_by value of " |
| 549 | - "%s" % reversed_key) |
| 550 | - |
| 551 | - def test_has_upstream_report__no_series_no_bug_tracking(self): |
| 552 | - # The property DistributionUpstreamReport.has_upstream_report |
| 553 | - # is False if a distribution does not use Launchpad for bug |
| 554 | - # tracking and if no current distroseries exists. |
| 555 | - distribution = self.factory.makeDistribution() |
| 556 | - view = create_initialized_view(distribution, '+upstreamreport') |
| 557 | - self.assertNotEqual( |
| 558 | - ServiceUsage.LAUNCHPAD, distribution.bug_tracking_usage) |
| 559 | - self.assertIs(None, distribution.currentseries) |
| 560 | - self.assertFalse(view.has_upstream_report) |
| 561 | - |
| 562 | - def test_has_upstream_report__no_distroseries_with_bug_tracking(self): |
| 563 | - # The property DistributionUpstreamReport.has_upstream_report |
| 564 | - # is False if a distribution does not have a current |
| 565 | - # distroseries, even if Luanchpad is used for bug tracking. |
| 566 | - distribution = self.factory.makeDistribution() |
| 567 | - view = create_initialized_view(distribution, '+upstreamreport') |
| 568 | - with person_logged_in(distribution.owner): |
| 569 | - distribution.official_malone = True |
| 570 | - self.assertIs(None, distribution.currentseries) |
| 571 | - self.assertFalse(view.has_upstream_report) |
| 572 | - |
| 573 | - def test_has_upstream_report__with_distroseries_no_bug_tracking(self): |
| 574 | - # The property DistributionUpstreamReport.has_upstream_report |
| 575 | - # is False if a distribution has a current distroseries, but |
| 576 | - # if Launchpad is not used for bug tracking. |
| 577 | - distribution = self.factory.makeDistroSeries().distribution |
| 578 | - view = create_initialized_view(distribution, '+upstreamreport') |
| 579 | - self.assertIsNot(None, distribution.currentseries) |
| 580 | - self.assertNotEqual( |
| 581 | - ServiceUsage.LAUNCHPAD, distribution.bug_tracking_usage) |
| 582 | - self.assertFalse(view.has_upstream_report) |
| 583 | - |
| 584 | - def test_has_upstream_report__with_distroseries_and_bug_tracking(self): |
| 585 | - # The property DistributionUpstreamReport.has_upstream_report |
| 586 | - # is True if a distribution has a current distroseries and if it |
| 587 | - # uses Launchpad for bug tracking. |
| 588 | - distribution = self.factory.makeDistroSeries().distribution |
| 589 | - with person_logged_in(distribution.owner): |
| 590 | - distribution.official_malone = True |
| 591 | - view = create_initialized_view(distribution, '+upstreamreport') |
| 592 | - self.assertIsNot(None, distribution.currentseries) |
| 593 | - self.assertEqual( |
| 594 | - ServiceUsage.LAUNCHPAD, distribution.bug_tracking_usage) |
| 595 | - self.assertTrue(view.has_upstream_report) |
| 596 | - |
| 597 | - |
| 598 | -class TestDistributionUpstreamReportPage(BrowserTestCase): |
| 599 | - """Tests for the +upstream report page.""" |
| 600 | - |
| 601 | - layer = LaunchpadFunctionalLayer |
| 602 | - |
| 603 | - def getTagMatchers(self): |
| 604 | - """Return matchers for the tag saying "launchpad is not used |
| 605 | - for development" and the tag containing the upstream report.""" |
| 606 | - no_lp_usage = Tag( |
| 607 | - 'no-lp-usage', 'div', attrs={'id': 'no-lp-usage'}) |
| 608 | - no_bugs_filed = Tag('lp-used', 'div', attrs={'id': 'lp-used'}) |
| 609 | - return no_lp_usage, no_bugs_filed |
| 610 | - |
| 611 | - def test_no_upstream_report_for_unconfigured_distros(self): |
| 612 | - # If DistributionUpstreamReport.has_upstream_report is False, |
| 613 | - # the +upstream-report page does not show the report. |
| 614 | - distribution = self.factory.makeDistribution() |
| 615 | - browser = self.getViewBrowser( |
| 616 | - distribution, '+upstreamreport', no_login=True) |
| 617 | - no_lp_usage, no_bugs_filed = self.getTagMatchers() |
| 618 | - self.assertThat(browser.contents, Not(HTMLContains(no_bugs_filed))) |
| 619 | - # Instead, a message tells the user that no report is |
| 620 | - # available. |
| 621 | - self.assertThat(browser.contents, HTMLContains(no_lp_usage)) |
| 622 | - |
| 623 | - def test_upstream_report_for_configured_distros(self): |
| 624 | - # If DistributionUpstreamReport.has_upstream_report is True, |
| 625 | - # the +upstream-report page does shows the report. |
| 626 | - distribution = self.factory.makeDistroSeries().distribution |
| 627 | - with person_logged_in(distribution.owner): |
| 628 | - distribution.official_malone = True |
| 629 | - browser = self.getViewBrowser( |
| 630 | - distribution, '+upstreamreport', no_login=True) |
| 631 | - no_lp_usage, no_bugs_filed = self.getTagMatchers() |
| 632 | - self.assertThat(browser.contents, HTMLContains(no_bugs_filed)) |
| 633 | - # A message telling the user that no report is available |
| 634 | - # is not shown. |
| 635 | - self.assertThat(browser.contents, Not(HTMLContains(no_lp_usage))) |
| 636 | |
| 637 | === removed file 'lib/lp/bugs/doc/distribution-upstream-report.txt' |
| 638 | --- lib/lp/bugs/doc/distribution-upstream-report.txt 2012-05-25 20:15:08 +0000 |
| 639 | +++ lib/lp/bugs/doc/distribution-upstream-report.txt 1970-01-01 00:00:00 +0000 |
| 640 | @@ -1,432 +0,0 @@ |
| 641 | -Upstream reports |
| 642 | -================ |
| 643 | - |
| 644 | -For a distribution's bug tracking process to be successful, it's vital |
| 645 | -that it is able to communicate upstream bugs to the relevant upstream |
| 646 | -project and monitor them as they change. Launchpad offers functionality |
| 647 | -to allow a distribution to focus on and improve this process. |
| 648 | - |
| 649 | - >>> from storm.store import Store |
| 650 | - >>> from lp.testing import login |
| 651 | - >>> from lp.bugs.tests.bug import ( |
| 652 | - ... create_bug_from_strings) |
| 653 | - >>> from lp.registry.interfaces.sourcepackagename import ( |
| 654 | - ... ISourcePackageNameSet) |
| 655 | - >>> from lp.registry.interfaces.distribution import IDistributionSet |
| 656 | - >>> from lp.registry.interfaces.product import IProductSet |
| 657 | - >>> from lp.registry.interfaces.packaging import ( |
| 658 | - ... IPackagingUtil, PackagingType) |
| 659 | - >>> from lp.registry.interfaces.person import IPersonSet |
| 660 | - >>> from lp.bugs.interfaces.bugtask import IBugTaskSet, BugTaskStatus |
| 661 | - >>> from lp.bugs.interfaces.bugwatch import IBugWatchSet |
| 662 | - |
| 663 | - >>> distroset = getUtility(IDistributionSet) |
| 664 | - >>> ubuntu = distroset.getByName('ubuntu') |
| 665 | - >>> debian = distroset.getByName('debian') |
| 666 | - >>> kubuntu = distroset.getByName('kubuntu') |
| 667 | - |
| 668 | - |
| 669 | -The API |
| 670 | -------- |
| 671 | - |
| 672 | -IDistribution has a special API that allows you to assemble data for a |
| 673 | -bug report that associates packages with upstream information linked to |
| 674 | -them. |
| 675 | - |
| 676 | - >>> def print_report(data): |
| 677 | - ... for dsp, product, open, triaged, upstream, watch, patch in data: |
| 678 | - ... print dsp.name, product and product.name or None |
| 679 | - ... print open, triaged, upstream, watch, patch |
| 680 | - |
| 681 | -A first set of reports, entirely based on sampledata. There are no |
| 682 | -triaged bugs, but there are some upstream ones with watches: |
| 683 | - |
| 684 | - >>> print_report(ubuntu.getPackagesAndPublicUpstreamBugCounts()) |
| 685 | - linux-source-2.6.15 None 1 0 0 0 0 |
| 686 | - mozilla-firefox firefox 1 0 1 1 0 |
| 687 | - thunderbird None 1 0 1 1 0 |
| 688 | - |
| 689 | - >>> print_report(debian.getPackagesAndPublicUpstreamBugCounts()) |
| 690 | - mozilla-firefox None 3 0 2 1 0 |
| 691 | - |
| 692 | - >>> print_report(kubuntu.getPackagesAndPublicUpstreamBugCounts()) |
| 693 | - |
| 694 | -getPackagesAndPublicUpstreamBugCounts() accepts an `exclude_packages` |
| 695 | -parameter. This is a list of the source packages that shouldn't be |
| 696 | -included in the report that getPackagesAndPublicUpstreamBugCounts() |
| 697 | -returns. |
| 698 | - |
| 699 | - >>> print_report(ubuntu.getPackagesAndPublicUpstreamBugCounts( |
| 700 | - ... exclude_packages=['linux-source-2.6.15'])) |
| 701 | - mozilla-firefox firefox 1 0 1 1 0 |
| 702 | - thunderbird None 1 0 1 1 0 |
| 703 | - |
| 704 | -To get the list of excluded packages for a distribution we can look at |
| 705 | -its `upstream_report_excluded_packages` property. For Kubuntu and |
| 706 | -Debian, this returns an empty list. |
| 707 | - |
| 708 | - >>> debian.upstream_report_excluded_packages |
| 709 | - [] |
| 710 | - |
| 711 | - >>> kubuntu.upstream_report_excluded_packages |
| 712 | - [] |
| 713 | - |
| 714 | -For Ubuntu, however, there is a list of excluded packages. |
| 715 | - |
| 716 | - >>> ubuntu.upstream_report_excluded_packages |
| 717 | - ['apport'...] |
| 718 | - |
| 719 | -If we triage a bugtask on firefox and thunderbird we'll see the count |
| 720 | -for triaged bugs updated: |
| 721 | - |
| 722 | - >>> login('foo.bar@canonical.com') |
| 723 | - >>> mark = getUtility(IPersonSet).getByName('mark') |
| 724 | - >>> ls_bug = getUtility(IBugTaskSet).get(23) |
| 725 | - >>> ls_bug.transitionToStatus(BugTaskStatus.TRIAGED, mark) |
| 726 | - >>> Store.of(ls_bug).flush() |
| 727 | - >>> mf_bug = getUtility(IBugTaskSet).get(17) |
| 728 | - >>> mf_bug.transitionToStatus(BugTaskStatus.TRIAGED, mark) |
| 729 | - >>> Store.of(mf_bug).flush() |
| 730 | - >>> print_report(ubuntu.getPackagesAndPublicUpstreamBugCounts()) |
| 731 | - linux-source-2.6.15 None 1 0 0 0 0 |
| 732 | - mozilla-firefox firefox 1 1 1 1 0 |
| 733 | - thunderbird None 1 1 1 1 0 |
| 734 | - |
| 735 | -We add two new bugs to pmount in Ubuntu. From now on we'll limit the |
| 736 | -results to 3 packages (as a demonstration of the API) so thunderbird |
| 737 | -will be popped off the list: |
| 738 | - |
| 739 | - >>> bug = create_bug_from_strings(distribution='ubuntu', |
| 740 | - ... sourcepackagename='pmount', owner='name12', |
| 741 | - ... summary='pmount used to work', description='fix it', |
| 742 | - ... status=BugTaskStatus.TRIAGED) |
| 743 | - >>> bug = create_bug_from_strings(distribution='ubuntu', |
| 744 | - ... sourcepackagename='pmount', owner='name12', |
| 745 | - ... summary='pmount has issues', description='fix it again', |
| 746 | - ... status=BugTaskStatus.TRIAGED) |
| 747 | - >>> ubuntu_pmount_task = bug.bugtasks[0] |
| 748 | - >>> print_report(ubuntu.getPackagesAndPublicUpstreamBugCounts(limit=3)) |
| 749 | - pmount None 2 2 0 0 0 |
| 750 | - linux-source-2.6.15 None 1 0 0 0 0 |
| 751 | - mozilla-firefox firefox 1 1 1 1 0 |
| 752 | - |
| 753 | -As you can see, there is no packaging data for pmount in Ubuntu, so no |
| 754 | -upstream is reported for it. Let's fix that: |
| 755 | - |
| 756 | - >>> pmount_spn = getUtility(ISourcePackageNameSet).queryByName('pmount') |
| 757 | - >>> name12 = getUtility(IPersonSet).getByName('name12') |
| 758 | - >>> pmount = getUtility(IProductSet).createProduct( |
| 759 | - ... name12, 'pmount', 'pmount', 'pmount', 'pmount') |
| 760 | - >>> packaging = getUtility(IPackagingUtil).createPackaging( |
| 761 | - ... pmount.getSeries('trunk'), pmount_spn, |
| 762 | - ... ubuntu.currentseries, PackagingType.PRIME, name12) |
| 763 | - >>> print_report(ubuntu.getPackagesAndPublicUpstreamBugCounts(limit=3)) |
| 764 | - pmount pmount 2 2 0 0 0 |
| 765 | - linux-source-2.6.15 None 1 0 0 0 0 |
| 766 | - mozilla-firefox firefox 1 1 1 1 0 |
| 767 | - |
| 768 | -We then add an upstream task to the second pmount bug: |
| 769 | - |
| 770 | - >>> task = getUtility(IBugTaskSet).createTask(bug, name12, pmount) |
| 771 | - >>> Store.of(task).flush() |
| 772 | - >>> print_report(ubuntu.getPackagesAndPublicUpstreamBugCounts(limit=3)) |
| 773 | - pmount pmount 2 2 1 0 0 |
| 774 | - linux-source-2.6.15 None 1 0 0 0 0 |
| 775 | - mozilla-firefox firefox 1 1 1 1 0 |
| 776 | - |
| 777 | -The last column counts those bugs with upstream tasks that have patches |
| 778 | -attached but which don't have an upstream bugwatch. If we add a ordinary |
| 779 | -attachment to our pmount bug, the value of the last column does not |
| 780 | -change... |
| 781 | - |
| 782 | - >>> attachment = factory.makeBugAttachment(bug) |
| 783 | - >>> print_report(ubuntu.getPackagesAndPublicUpstreamBugCounts(limit=3)) |
| 784 | - pmount pmount 2 2 1 0 0 |
| 785 | - linux-source-2.6.15 None 1 0 0 0 0 |
| 786 | - mozilla-firefox firefox 1 1 1 1 0 |
| 787 | - |
| 788 | -...but when we make this attachment a patch, the value of the column |
| 789 | -increases. |
| 790 | - |
| 791 | - >>> from lp.bugs.interfaces.bugattachment import BugAttachmentType |
| 792 | - >>> attachment.type = BugAttachmentType.PATCH |
| 793 | - >>> Store.of(attachment).flush() |
| 794 | - >>> print_report(ubuntu.getPackagesAndPublicUpstreamBugCounts(limit=3)) |
| 795 | - pmount pmount 2 2 1 0 1 |
| 796 | - linux-source-2.6.15 None 1 0 0 0 0 |
| 797 | - mozilla-firefox firefox 1 1 1 1 0 |
| 798 | - |
| 799 | -Note that we count only bugs with patches for products that do not |
| 800 | -use Malone officially. |
| 801 | - |
| 802 | - >>> pmount.official_malone = True |
| 803 | - >>> Store.of(pmount).flush() |
| 804 | - >>> print_report(ubuntu.getPackagesAndPublicUpstreamBugCounts(limit=3)) |
| 805 | - pmount pmount 2 2 1 1 0 |
| 806 | - linux-source-2.6.15 None 1 0 0 0 0 |
| 807 | - mozilla-firefox firefox 1 1 1 1 0 |
| 808 | - |
| 809 | - >>> pmount.official_malone = False |
| 810 | - >>> Store.of(pmount).flush() |
| 811 | - |
| 812 | -Linking that task to a bugwatch increases the watch counts and decreases |
| 813 | -the count of bugs having patches but no bug watch. |
| 814 | - |
| 815 | - >>> url = "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=666" |
| 816 | - >>> [watch] = getUtility(IBugWatchSet).fromText(url, bug, name12) |
| 817 | - >>> task.bugwatch = watch |
| 818 | - >>> Store.of(task).flush() |
| 819 | - >>> print_report(ubuntu.getPackagesAndPublicUpstreamBugCounts(limit=3)) |
| 820 | - pmount pmount 2 2 1 1 0 |
| 821 | - linux-source-2.6.15 None 1 0 0 0 0 |
| 822 | - mozilla-firefox firefox 1 1 1 1 0 |
| 823 | - |
| 824 | - |
| 825 | -The view |
| 826 | --------- |
| 827 | - |
| 828 | -We test that the view data is constructed sanely and without any hidden |
| 829 | -defects. Let's set up some helpers to make it easier for us to output |
| 830 | -them: |
| 831 | - |
| 832 | - >>> from lp.testing.systemdocs import create_view |
| 833 | - |
| 834 | - >>> def print_numbers(data): |
| 835 | - ... for f in ['open_bugs', |
| 836 | - ... 'triaged_bugs', |
| 837 | - ... 'upstream_bugs', |
| 838 | - ... 'watched_bugs', |
| 839 | - ... 'triaged_bugs_percentage', |
| 840 | - ... 'upstream_bugs_percentage', |
| 841 | - ... 'watched_bugs_percentage', |
| 842 | - ... 'triaged_bugs_class', |
| 843 | - ... 'upstream_bugs_class', |
| 844 | - ... 'watched_bugs_class', |
| 845 | - ... 'triaged_bugs_delta', |
| 846 | - ... 'upstream_bugs_delta', |
| 847 | - ... 'watched_bugs_delta']: |
| 848 | - ... print getattr(data, f), |
| 849 | - |
| 850 | - >>> def print_helpers(data): |
| 851 | - ... print data.dsp.name, data.dsp.distribution.name, |
| 852 | - ... if data.dssp: |
| 853 | - ... print data.dssp.distroseries.name |
| 854 | - ... else: |
| 855 | - ... print "NO SERIES" |
| 856 | - ... if data.product: |
| 857 | - ... print data.product.name |
| 858 | - ... else: |
| 859 | - ... print "NO PRODUCT" |
| 860 | - ... for f in ['bug_supervisor_url', 'product_edit_url', |
| 861 | - ... 'upstream_bugs_url', 'upstream_bugs_delta_url', |
| 862 | - ... 'watched_bugs_delta_url']: |
| 863 | - ... t = getattr(data, f, "NO URL") |
| 864 | - ... print t.replace( |
| 865 | - ... "http://bugs.launchpad.dev/ubuntu/+source/", "**") |
| 866 | - ... print "--" |
| 867 | - |
| 868 | -Get an Ubuntu view: |
| 869 | - |
| 870 | - >>> view = create_view(ubuntu, '+upstreamreport') |
| 871 | - >>> view.initialize() |
| 872 | - |
| 873 | -Here are the helper URLs we construct: |
| 874 | - |
| 875 | - >>> for item in view.data: |
| 876 | - ... print_helpers(item) |
| 877 | - pmount ubuntu hoary |
| 878 | - pmount |
| 879 | - http://launchpad.dev/pmount/+bugsupervisor |
| 880 | - http://launchpad.dev/pmount/+edit |
| 881 | - **pmount/+bugs?search=Search&field.status_upstream=open_upstream |
| 882 | - **pmount/+bugs?search=Search&field.status_upstream=hide_upstream |
| 883 | - **pmount/+bugs?search=Search&field.status_upstream=pending_bugwatch |
| 884 | - -- |
| 885 | - linux-source-2.6.15 ubuntu hoary |
| 886 | - NO PRODUCT |
| 887 | - NO URL |
| 888 | - NO URL |
| 889 | - **linux-source-2.6.15/+bugs?...&field.status_upstream=open_upstream |
| 890 | - **linux-source-2.6.15/+bugs?...h&field.status_upstream=hide_upstream |
| 891 | - **linux-source-2.6.15/+bugs?...&field.status_upstream=pending_bugwatch |
| 892 | - -- |
| 893 | - mozilla-firefox ubuntu hoary |
| 894 | - firefox |
| 895 | - http://launchpad.dev/firefox/+bugsupervisor |
| 896 | - http://launchpad.dev/firefox/+edit |
| 897 | - **mozilla-firefox/+bugs?search=Search&field.status_upstream=open_upstream |
| 898 | - **mozilla-firefox/+bugs?search=Search&field.status_upstream=hide_upstream |
| 899 | - **mozilla-firefox/+bugs?...&field.status_upstream=pending_bugwatch |
| 900 | - -- |
| 901 | - thunderbird ubuntu hoary |
| 902 | - NO PRODUCT |
| 903 | - NO URL |
| 904 | - NO URL |
| 905 | - **thunderbird/+bugs?search=Search&field.status_upstream=open_upstream |
| 906 | - **thunderbird/+bugs?search=Search&field.status_upstream=hide_upstream |
| 907 | - **thunderbird/+bugs?search=Search&field.status_upstream=pending_bugwatch |
| 908 | - -- |
| 909 | - |
| 910 | -Let's print out the counts and percentages: |
| 911 | - |
| 912 | - >>> for item in view.data: |
| 913 | - ... print_numbers(item) |
| 914 | |
| 915 | - 2 2 1 1 100.0 50.0 100.0 good good 0 1 0 |
| 916 | - 1 0 0 0 0.0 0.0 0.0 1 1 0 |
| 917 | - 1 1 1 1 100.0 100.0 100.0 good good good 0 0 0 |
| 918 | - 1 1 1 1 100.0 100.0 100.0 good good good 0 0 0 |
| 919 | - |
| 920 | -And the total line: |
| 921 | - |
| 922 | - >>> print_numbers(view.total) |
| 923 | - 5 4 3 3 80.0 60.0 100.0 good good 1 2 0 |
| 924 | - |
| 925 | - |
| 926 | -Sorting the report |
| 927 | ------------------- |
| 928 | - |
| 929 | -The upstream report is sortable by each of the columns displayed. We'll |
| 930 | -demonstrate this using the Ubuntu report. |
| 931 | - |
| 932 | - >>> view = create_view(ubuntu, '+upstreamreport') |
| 933 | - |
| 934 | -The view has a sort_order property. This returns a tuple of (sort_key, |
| 935 | -reversed), where sort_key is a string which can be mapped to one of the |
| 936 | -properties of PackageBugReportData and reversed is a boolean which |
| 937 | -indicates whether the current sort is ascending (reversed=False) or |
| 938 | -descending (reversed=True). By default, the sort_order for any report is |
| 939 | -number of open bugs, descending. |
| 940 | - |
| 941 | - >>> view.sort_order |
| 942 | - ('open_bugs', True) |
| 943 | - |
| 944 | -The sort order can be changed by altering the sort_by request parameter. |
| 945 | - |
| 946 | - >>> form = {'sort_by': 'product'} |
| 947 | - |
| 948 | - >>> view = create_view(ubuntu, '+upstreamreport', form) |
| 949 | - >>> view.sort_order |
| 950 | - ('product', False) |
| 951 | - |
| 952 | -Prepending a '-' to the sort_by parameter will cause the sort_order to |
| 953 | -be reversed. |
| 954 | - |
| 955 | - >>> form = {'sort_by': '-product'} |
| 956 | - >>> view = create_view(ubuntu, '+upstreamreport', form) |
| 957 | - |
| 958 | - >>> view.sort_order |
| 959 | - ('product', True) |
| 960 | - |
| 961 | -The DistributionUpstreamReport view has a list of valid sort keys. If |
| 962 | -we try to sort by a key that isn't in that list we'll get the default |
| 963 | -sort_order back. (See test_distribution_upstream_report.py in |
| 964 | -browser/tests for further testing of this). |
| 965 | - |
| 966 | - >>> form = {'sort_by': 'ifthisisvalidilleatmyhat'} |
| 967 | - >>> view = create_view(ubuntu, '+upstreamreport', form) |
| 968 | - |
| 969 | - >>> view.sort_order |
| 970 | - ('open_bugs', True) |
| 971 | - |
| 972 | -The DistributionUpstreamReport view also has a sort_order_links |
| 973 | -property. This is a dict of URLs which is used to create the links in |
| 974 | -the sortable table header on the +upstreamreport page for the |
| 975 | -distribution. |
| 976 | - |
| 977 | -The current sort_order is the default one. |
| 978 | - |
| 979 | - >>> view.sort_order |
| 980 | - ('open_bugs', True) |
| 981 | - |
| 982 | -All the links, by default will link to a standard forward sort for their |
| 983 | -particular sort_key. In this case, this is also true of the open_bugs |
| 984 | -key, since this is at the moment reverse-sorted. |
| 985 | - |
| 986 | - >>> def print_sort_order_links(view, key='link'): |
| 987 | - ... for sort_key in sorted(view.sort_order_links): |
| 988 | - ... link_dict = view.sort_order_links[sort_key] |
| 989 | - ... print sort_key, link_dict[key] |
| 990 | - |
| 991 | - >>> print_sort_order_links(view) |
| 992 | - bug_supervisor_name http://...?sort_by=bug_supervisor_name |
| 993 | - bugs_with_upstream_patches http:...?sort_by=bugs_with_upstream_patches |
| 994 | - bugtracker_name http://...?sort_by=bugtracker_name |
| 995 | - dsp http://...?sort_by=dsp |
| 996 | - open_bugs http://...?sort_by=open_bugs |
| 997 | - product http://...?sort_by=product |
| 998 | - triaged_bugs http://...?sort_by=triaged_bugs |
| 999 | - triaged_bugs_class http://...?sort_by=triaged_bugs_class |
| 1000 | - triaged_bugs_delta http://...?sort_by=triaged_bugs_delta |
| 1001 | - triaged_bugs_percentage http://...?sort_by=triaged_bugs_percentage |
| 1002 | - upstream_bugs http://...?sort_by=upstream_bugs |
| 1003 | - upstream_bugs_class http://...?sort_by=upstream_bugs_class |
| 1004 | - upstream_bugs_delta http://...?sort_by=upstream_bugs_delta |
| 1005 | - upstream_bugs_percentage http://...?sort_by=upstream_bugs_percentage |
| 1006 | - watched_bugs http://...?sort_by=watched_bugs |
| 1007 | - watched_bugs_class http://...?sort_by=watched_bugs_class |
| 1008 | - watched_bugs_delta http://...?sort_by=watched_bugs_delta |
| 1009 | - watched_bugs_percentage http://...?sort_by=watched_bugs_percentage |
| 1010 | - |
| 1011 | -Changing the sort_order to a forward sort of, say, bug_supervisor_name |
| 1012 | -will change the link for that sort key. The others will remain |
| 1013 | -unaffected. |
| 1014 | - |
| 1015 | - >>> form = {'sort_by': 'bug_supervisor_name'} |
| 1016 | - >>> view = create_view(ubuntu, '+upstreamreport', form) |
| 1017 | - |
| 1018 | - >>> view.sort_order |
| 1019 | - ('bug_supervisor_name', False) |
| 1020 | - |
| 1021 | - >>> print_sort_order_links(view) |
| 1022 | - bug_supervisor_name http://...?sort_by=-bug_supervisor_name |
| 1023 | - bugs_with_upstream_patches http:...?sort_by=bugs_with_upstream_patches |
| 1024 | - bugtracker_name http://...?sort_by=bugtracker_name... |
| 1025 | - |
| 1026 | -Each sort_order_links dict has an 'arrow' key. This is the URL of the |
| 1027 | -arrow icon to be displayed next to the link in the table header. |
| 1028 | - |
| 1029 | - >>> print_sort_order_links(view, 'arrow') |
| 1030 | - bug_supervisor_name /@@/arrowUp |
| 1031 | - bugs_with_upstream_patches /@@/arrowBlank |
| 1032 | - bugtracker_name /@@/arrowBlank |
| 1033 | - dsp /@@/arrowBlank |
| 1034 | - open_bugs /@@/arrowBlank |
| 1035 | - product /@@/arrowBlank |
| 1036 | - triaged_bugs /@@/arrowBlank |
| 1037 | - triaged_bugs_class /@@/arrowBlank |
| 1038 | - triaged_bugs_delta /@@/arrowBlank |
| 1039 | - triaged_bugs_percentage /@@/arrowBlank |
| 1040 | - upstream_bugs /@@/arrowBlank |
| 1041 | - upstream_bugs_class /@@/arrowBlank |
| 1042 | - upstream_bugs_delta /@@/arrowBlank |
| 1043 | - upstream_bugs_percentage /@@/arrowBlank |
| 1044 | - watched_bugs /@@/arrowBlank |
| 1045 | - watched_bugs_class /@@/arrowBlank |
| 1046 | - watched_bugs_delta /@@/arrowBlank |
| 1047 | - watched_bugs_percentage /@@/arrowBlank |
| 1048 | - |
| 1049 | -Altering the sort order will change the arrow for the current sort order |
| 1050 | -accordingly. |
| 1051 | - |
| 1052 | - >>> form = {'sort_by': '-bug_supervisor_name'} |
| 1053 | - >>> view = create_view(ubuntu, '+upstreamreport', form) |
| 1054 | - |
| 1055 | - >>> view.sort_order |
| 1056 | - ('bug_supervisor_name', True) |
| 1057 | - |
| 1058 | - >>> print_sort_order_links(view, 'arrow') |
| 1059 | - bug_supervisor_name /@@/arrowDown |
| 1060 | - bugs_with_upstream_patches /@@/arrowBlank |
| 1061 | - bugtracker_name /@@/arrowBlank... |
| 1062 | - |
| 1063 | - >>> form = {'sort_by': '-bugtracker_name'} |
| 1064 | - >>> view = create_view(ubuntu, '+upstreamreport', form) |
| 1065 | - |
| 1066 | - >>> view.sort_order |
| 1067 | - ('bugtracker_name', True) |
| 1068 | - |
| 1069 | - >>> print_sort_order_links(view, 'arrow') |
| 1070 | - bug_supervisor_name /@@/arrowBlank |
| 1071 | - bugs_with_upstream_patches /@@/arrowBlank |
| 1072 | - bugtracker_name /@@/arrowDown... |
| 1073 | |
| 1074 | === removed file 'lib/lp/bugs/stories/distribution/xx-distribution-upstream-report.txt' |
| 1075 | --- lib/lp/bugs/stories/distribution/xx-distribution-upstream-report.txt 2012-10-02 06:36:44 +0000 |
| 1076 | +++ lib/lp/bugs/stories/distribution/xx-distribution-upstream-report.txt 1970-01-01 00:00:00 +0000 |
| 1077 | @@ -1,303 +0,0 @@ |
| 1078 | -Distribution upstream report pages |
| 1079 | -================================== |
| 1080 | - |
| 1081 | -Upstream report pages for distributions contain all sorts of fun |
| 1082 | -information that describe how well the bugs are forwarded to upstreams. |
| 1083 | - |
| 1084 | -We start this test off by creating some bugs and tasks to ensure we have |
| 1085 | -rich enough information to display. We create one bug against |
| 1086 | -linux-source with a firefox task, and we add a tomcat task against |
| 1087 | -pre-existing linux-source bug 10. We transition the Ubuntu tasks to |
| 1088 | -TRIAGED to ensure that they are picked up by the report. |
| 1089 | - |
| 1090 | - >>> from lp.bugs.interfaces.bugtask import BugTaskStatus |
| 1091 | - >>> from lp.testing import login, logout |
| 1092 | - >>> from lp.services.database.sqlbase import flush_database_updates |
| 1093 | - >>> from lp.bugs.tests.bug import ( |
| 1094 | - ... create_bug_from_strings, create_task_from_strings, |
| 1095 | - ... update_task_status) |
| 1096 | - |
| 1097 | - >>> login('foo.bar@canonical.com') |
| 1098 | - |
| 1099 | - >>> watchurl = "http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=%s" |
| 1100 | - >>> bug = create_bug_from_strings(distribution='ubuntu', |
| 1101 | - ... sourcepackagename='linux-source-2.6.15', owner='name12', |
| 1102 | - ... summary='take one', description='funk philosophy', |
| 1103 | - ... status=BugTaskStatus.TRIAGED) |
| 1104 | - >>> update_task_status(bug.bugtasks[0].id, 'mark', |
| 1105 | - ... BugTaskStatus.TRIAGED) |
| 1106 | - >>> update_task_status(25, 'mark', BugTaskStatus.TRIAGED) |
| 1107 | - >>> task = create_task_from_strings(bug.id, 'name12', 'firefox') |
| 1108 | - >>> task = create_task_from_strings(10, 'name12', 'tomcat') |
| 1109 | - >>> update_task_status(23, 'mark', BugTaskStatus.TRIAGED) |
| 1110 | - >>> update_task_status(17, 'mark', BugTaskStatus.TRIAGED) |
| 1111 | - |
| 1112 | - >>> flush_database_updates() |
| 1113 | - >>> import transaction |
| 1114 | - >>> transaction.commit() |
| 1115 | - >>> logout() |
| 1116 | - |
| 1117 | -So let's check out the actual table: |
| 1118 | - |
| 1119 | - >>> browser.open("http://bugs.launchpad.dev/ubuntu/+upstreamreport") |
| 1120 | - >>> table = find_tag_by_id(browser.contents, 'upstream-report-content') |
| 1121 | - >>> print extract_text(table, True) |
| 1122 | - linux-source-2.6.15 Missing corresponding project. (find) (link) |
| 1123 | - 2 2 100.00 0 2 100.00 0 1 50.00 1 - |
| 1124 | - mozilla-firefox Mozilla Firefox Launchpad Unspecified |
| 1125 | - 1 1 100.00 0 1 100.00 0 |
| 1126 | - thunderbird Missing corresponding project. (find) (link) |
| 1127 | - 1 1 100.00 0 1 100.00 0 1 100.00 0 - |
| 1128 | - |
| 1129 | -XXX kiko 2008-02-01 bug=188020: One thing to note from the counts above |
| 1130 | -is that while the linux-source/tomcat task is counted as pending a |
| 1131 | -bugwatch, the mozilla-firefox one is not -- and the reason for that is |
| 1132 | -that mozilla-firefox's linked upstream, firefox, officially uses malone. |
| 1133 | -We count it as "watched" even though it's really native. The problem |
| 1134 | -becomes clearer as you look at the totals: |
| 1135 | - |
| 1136 | - >>> table = find_tag_by_id(browser.contents, 'upstream-report-totals') |
| 1137 | - >>> print extract_text(table) |
| 1138 | - Totals: 4 4 100.00 0 4 100.00 0 3 75.00 1 0 |
| 1139 | - |
| 1140 | -This 3 in the watched column is caused by a problem similar to the |
| 1141 | -above; if you do a count of the values in the cells it would be 2, of |
| 1142 | -course. Reason is that watch counts against mozilla-firefox are not |
| 1143 | -rendered, but totalized as if they were watched, and the total line |
| 1144 | -doesn't add up. |
| 1145 | - |
| 1146 | -This and the display problem above should be fixed. We could avoid |
| 1147 | -totalizing the watched bugs for native upstreams, but then we'd have a |
| 1148 | -broken percentage when comparing with bugs marked upstream. Perhaps |
| 1149 | -we'd solve this by separating the watched column into natively watched |
| 1150 | -and remote watched, but I don't know how to fix this right now. See |
| 1151 | -bug #188020 -- kiko, 2008-02-01 |
| 1152 | - |
| 1153 | - |
| 1154 | -Useful links |
| 1155 | ------------- |
| 1156 | - |
| 1157 | -The table includes a number of convenience links: |
| 1158 | - |
| 1159 | - >>> table = find_tag_by_id(browser.contents, 'upstream-report-content') |
| 1160 | - >>> all_anchors = table.findAll('a') |
| 1161 | - >>> base_href = browser.url |
| 1162 | - >>> for anchor in all_anchors: |
| 1163 | - ... url = extract_link_from_tag(anchor, base_href) |
| 1164 | - ... url = url.replace("http://bugs.launchpad.dev/ubuntu", "**") |
| 1165 | - ... url = url.replace("&", "\n&") |
| 1166 | - ... print extract_text(anchor), url |
| 1167 | - linux-source-2.6.15 **/+source/linux-source-2.6.15 |
| 1168 | - (find) http://bugs.launchpad.dev/projects |
| 1169 | - (link) **/hoary/+source/linux-source-2.6.15/+edit-packaging |
| 1170 | - 2 **/+source/linux-source-2.6.15/+bugs?search=Search |
| 1171 | - 2 **/+source/linux-source-2.6.15/+bugs?search=Search |
| 1172 | - &field.status=TRIAGED |
| 1173 | - 0 **/+source/linux-source-2.6.15/+bugs?search=Search |
| 1174 | - &field.status=CONFIRMED |
| 1175 | - &field.status=INCOMPLETE_WITHOUT_RESPONSE |
| 1176 | - &field.status=INCOMPLETE_WITH_RESPONSE |
| 1177 | - &field.status=NEW |
| 1178 | - 2 **/+source/linux-source-2.6.15/+bugs?search=Search |
| 1179 | - &field.status_upstream=open_upstream |
| 1180 | - 0 **/+source/linux-source-2.6.15/+bugs?search=Search |
| 1181 | - &field.status_upstream=hide_upstream |
| 1182 | - 1 **/+source/linux-source-2.6.15/+bugs?search=Search |
| 1183 | - &field.status_upstream=pending_bugwatch |
| 1184 | - ... |
| 1185 | - |
| 1186 | - |
| 1187 | -Links to bug queries |
| 1188 | -.................... |
| 1189 | - |
| 1190 | -Let's look more carefully at the above six links associated with counts. |
| 1191 | - |
| 1192 | - >>> count_anchors = all_anchors[3:9] |
| 1193 | - >>> (open_url, triaged_url, triaged_delta, upstream_url, |
| 1194 | - ... upstream_delta_url, watch_delta_url) = \ |
| 1195 | - ... [str(extract_link_from_tag(x, base_href)) for x in count_anchors] |
| 1196 | - |
| 1197 | -Link 1. Open bugs (2) |
| 1198 | - |
| 1199 | - >>> from lp.bugs.tests.bug import print_bugtasks |
| 1200 | - >>> browser.open(open_url) |
| 1201 | - >>> browser.title |
| 1202 | - 'Bugs : \xe2\x80\x9clinux-source-2.6.15\xe2\x80\x9d package : Ubuntu' |
| 1203 | - >>> print_bugtasks(browser.contents) |
| 1204 | - 10 another test bug linux-source-2.6.15 (Ubuntu) Medium Triaged |
| 1205 | - 16 take one linux-source-2.6.15 (Ubuntu) Undecided Triaged |
| 1206 | - |
| 1207 | -Link 2. Triaged bugs (2) |
| 1208 | - |
| 1209 | - >>> browser.open(triaged_url) |
| 1210 | - >>> browser.title |
| 1211 | - 'Bugs : \xe2\x80\x9clinux-source-2.6.15\xe2\x80\x9d package : Ubuntu' |
| 1212 | - >>> print_bugtasks(browser.contents) |
| 1213 | - 10 another test bug linux-source-2.6.15 (Ubuntu) Medium Triaged |
| 1214 | - 16 take one linux-source-2.6.15 (Ubuntu) Undecided Triaged |
| 1215 | - |
| 1216 | -Link 3: Open bugs that aren't triaged (0) |
| 1217 | - |
| 1218 | - >>> browser.open(triaged_delta) |
| 1219 | - >>> browser.title |
| 1220 | - 'Bugs : \xe2\x80\x9clinux-source-2.6.15\xe2\x80\x9d package : Ubuntu' |
| 1221 | - >>> print extract_text( |
| 1222 | - ... find_tag_by_id(browser.contents, 'bugs-table-listing')) |
| 1223 | - No results for search |
| 1224 | - |
| 1225 | -Link 4: Triaged bugs that are upstream issues (2) |
| 1226 | - |
| 1227 | - >>> browser.open(upstream_url) |
| 1228 | - >>> browser.title |
| 1229 | - 'Bugs : \xe2\x80\x9clinux-source-2.6.15\xe2\x80\x9d package : Ubuntu' |
| 1230 | - >>> print_bugtasks(browser.contents) |
| 1231 | - 10 another test bug linux-source-2.6.15 (Ubuntu) Medium Triaged |
| 1232 | - 16 take one linux-source-2.6.15 (Ubuntu) Undecided Triaged |
| 1233 | - |
| 1234 | -Link 5: Triaged bugs that haven't been marked upstream (0) |
| 1235 | - |
| 1236 | - >>> browser.open(upstream_delta_url) |
| 1237 | - >>> browser.title |
| 1238 | - 'Bugs : \xe2\x80\x9clinux-source-2.6.15\xe2\x80\x9d package : Ubuntu' |
| 1239 | - >>> print extract_text( |
| 1240 | - ... find_tag_by_id(browser.contents, 'bugs-table-listing')) |
| 1241 | - No results for search |
| 1242 | - |
| 1243 | -Link 6: Triaged bugs marked upstream lacking a watch (1) |
| 1244 | - |
| 1245 | - >>> browser.open(watch_delta_url) |
| 1246 | - >>> browser.title |
| 1247 | - 'Bugs : \xe2\x80\x9clinux-source-2.6.15\xe2\x80\x9d package : Ubuntu' |
| 1248 | - >>> print_bugtasks(browser.contents) |
| 1249 | - 10 another test bug linux-source-2.6.15 (Ubuntu) Medium Triaged |
| 1250 | - |
| 1251 | - |
| 1252 | -Links to fix registration data |
| 1253 | -.............................. |
| 1254 | - |
| 1255 | -As you saw before, we also offer links to find products and connect packages |
| 1256 | -with no packaging links (though you need to be logged in to actually see or |
| 1257 | -link them): |
| 1258 | - |
| 1259 | - >>> browser.open("http://bugs.launchpad.dev/ubuntu/+upstreamreport") |
| 1260 | - >>> browser.getLink('find').click() |
| 1261 | - >>> browser.title |
| 1262 | - 'Projects registered in Launchpad' |
| 1263 | - >>> user_browser.open("http://bugs.launchpad.dev/ubuntu/+upstreamreport") |
| 1264 | - >>> user_browser.getLink('link').click() |
| 1265 | - >>> print user_browser.title |
| 1266 | - Link to an upstream project : ... |
| 1267 | - |
| 1268 | - |
| 1269 | -If you are logged in and can edit the upstream project, you can also set |
| 1270 | -a bug tracker and a bug supervisor. Let's first fix Firefox to stop using |
| 1271 | -Malone officially for the sake of this test: |
| 1272 | - |
| 1273 | - >>> login('foo.bar@canonical.com') |
| 1274 | - >>> from zope.component import getUtility |
| 1275 | - >>> from lp.registry.interfaces.product import IProductSet |
| 1276 | - >>> firefox = getUtility(IProductSet).getByName('firefox') |
| 1277 | - >>> firefox.official_malone = False |
| 1278 | - >>> flush_database_updates() |
| 1279 | - >>> transaction.commit() |
| 1280 | - >>> logout() |
| 1281 | - |
| 1282 | -And check out the report: |
| 1283 | - |
| 1284 | - >>> admin_browser.open("http://bugs.launchpad.dev/ubuntu/+upstreamreport") |
| 1285 | - >>> admin_browser.getLink('fix').click() |
| 1286 | - >>> print admin_browser.title |
| 1287 | - Change Mozilla Firefox's... |
| 1288 | - |
| 1289 | - >>> admin_browser.open("http://bugs.launchpad.dev/ubuntu/+upstreamreport") |
| 1290 | - >>> admin_browser.getLink('change').click() |
| 1291 | - >>> print admin_browser.title |
| 1292 | - Edit bug supervisor for... |
| 1293 | - |
| 1294 | -If you're not allowed to edit the product, no love for you, though: |
| 1295 | - |
| 1296 | - >>> user_browser.open("http://bugs.launchpad.dev/ubuntu/+upstreamreport") |
| 1297 | - >>> user_browser.getLink('fix') |
| 1298 | - Traceback (most recent call last): |
| 1299 | - ... |
| 1300 | - LinkNotFoundError |
| 1301 | - |
| 1302 | - >>> user_browser.getLink('change') |
| 1303 | - Traceback (most recent call last): |
| 1304 | - ... |
| 1305 | - LinkNotFoundError |
| 1306 | - |
| 1307 | -Note that we also cope correctly with the case in which a project's |
| 1308 | -bugtracker is inherited from it's project group: |
| 1309 | - |
| 1310 | - >>> login('foo.bar@canonical.com') |
| 1311 | - >>> from lp.bugs.interfaces.bugtracker import IBugTrackerSet |
| 1312 | - >>> mozilla_org = getUtility(IBugTrackerSet).getByName("mozilla.org") |
| 1313 | - >>> firefox.project.bugtracker = mozilla_org |
| 1314 | - >>> flush_database_updates() |
| 1315 | - >>> transaction.commit() |
| 1316 | - >>> logout() |
| 1317 | - |
| 1318 | -See how we nicely display the bugtracker in the table's second row now. |
| 1319 | -Note also that the watch counts for linux-source and mozilla-firefox |
| 1320 | -change to account for the fact that firefox no longer uses_malone. |
| 1321 | - |
| 1322 | - >>> browser.open("http://bugs.launchpad.dev/ubuntu/+upstreamreport") |
| 1323 | - >>> table = find_tag_by_id(browser.contents, 'upstream-report-content') |
| 1324 | - >>> print extract_text(table, True) |
| 1325 | - linux-source-2.6.15 Missing corresponding project. (find) (link) |
| 1326 | - 2 2 100.00 0 2 100.00 0 0 0.00 2 - |
| 1327 | - mozilla-firefox Mozilla Firefox The Mozilla.org Bug Tracker Unspecified |
| 1328 | - 1 1 100.00 0 1 100.00 0 0 0.00 1 - |
| 1329 | - thunderbird Missing corresponding project. (find) (link) |
| 1330 | - 1 1 100.00 0 1 100.00 0 1 100.00 0 - |
| 1331 | - |
| 1332 | -If we now add an attachment to the bug we created earlier, the number |
| 1333 | -of bugs with patches for upstream increases for linux-source-2.6.15. |
| 1334 | - |
| 1335 | - >>> login('foo.bar@canonical.com') |
| 1336 | - >>> attachment = factory.makeBugAttachment(bug, is_patch=True) |
| 1337 | - >>> logout() |
| 1338 | - >>> browser.open("http://bugs.launchpad.dev/ubuntu/+upstreamreport") |
| 1339 | - >>> table = find_tag_by_id(browser.contents, 'upstream-report-content') |
| 1340 | - >>> print extract_text(table, True) |
| 1341 | - linux-source-2.6.15 Missing corresponding project. (find) (link) |
| 1342 | - 2 2 100.00 0 2 100.00 0 0 0.00 2 1 |
| 1343 | - mozilla-firefox Mozilla Firefox The Mozilla.org Bug Tracker Unspecified |
| 1344 | - 1 1 100.00 0 1 100.00 0 0 0.00 1 - |
| 1345 | - thunderbird Missing corresponding project. (find) (link) |
| 1346 | - 1 1 100.00 0 1 100.00 0 1 100.00 0 - |
| 1347 | - |
| 1348 | -Finally, you can associate default branches to products. This is done by |
| 1349 | -specifying a branch for the product's main_series: |
| 1350 | - |
| 1351 | - >>> admin_browser.open("http://launchpad.dev/firefox/trunk/+linkbranch") |
| 1352 | - >>> branch_control = admin_browser.getControl(name="field.branch") |
| 1353 | - >>> branch_control.value = "~name12/firefox/main" |
| 1354 | - >>> admin_browser.getControl("Update").click() |
| 1355 | - >>> admin_browser.url |
| 1356 | - 'http://launchpad.dev/firefox/trunk' |
| 1357 | - |
| 1358 | -The report now renders an icon and a link to the branch page: |
| 1359 | - |
| 1360 | - >>> browser.open("http://bugs.launchpad.dev/ubuntu/+upstreamreport") |
| 1361 | - >>> browser.getLink('branch').click() |
| 1362 | - >>> browser.url |
| 1363 | - 'http://code.launchpad.dev/~name12/firefox/main' |
| 1364 | - |
| 1365 | -(This means that anyone can use bzr branch lp:firefox to pull this code.) |
| 1366 | - |
| 1367 | - |
| 1368 | -Empty distributions |
| 1369 | -------------------- |
| 1370 | - |
| 1371 | -If a distribution does not use Launchpad for bug tracking, no |
| 1372 | -upstream report is shown, only a message that no data is available. |
| 1373 | - |
| 1374 | - >>> browser.open("http://bugs.launchpad.dev/debian/+upstreamreport") |
| 1375 | - >>> table = find_tag_by_id(browser.contents, 'upstream-report-content') |
| 1376 | - >>> print table |
| 1377 | - None |
| 1378 | - >>> message = find_tag_by_id(browser.contents, 'no-lp-usage') |
| 1379 | - >>> print extract_text(message) |
| 1380 | - This distribution does not use Launchpad for development. |
| 1381 | |
| 1382 | === removed file 'lib/lp/bugs/templates/distribution-upstream-report.pt' |
| 1383 | --- lib/lp/bugs/templates/distribution-upstream-report.pt 2012-05-25 18:39:46 +0000 |
| 1384 | +++ lib/lp/bugs/templates/distribution-upstream-report.pt 1970-01-01 00:00:00 +0000 |
| 1385 | @@ -1,298 +0,0 @@ |
| 1386 | -<distribution-upstream-report |
| 1387 | - xmlns="http://www.w3.org/1999/xhtml" |
| 1388 | - xmlns:tal="http://xml.zope.org/namespaces/tal" |
| 1389 | - xmlns:metal="http://xml.zope.org/namespaces/metal" |
| 1390 | - xmlns:i18n="http://xml.zope.org/namespaces/i18n" |
| 1391 | - metal:use-macro="view/macro:page/main_only" |
| 1392 | - i18n:domain="launchpad"> |
| 1393 | - |
| 1394 | - <metal:heading fill-slot="head_epilogue"> |
| 1395 | - <style type="text/css"> |
| 1396 | - <!-- |
| 1397 | - td.amount a { display: block; } |
| 1398 | - tr.good { background: #d7ffbf; } |
| 1399 | - tr.bad { background: #ffbfbf; } |
| 1400 | - --> |
| 1401 | - </style> |
| 1402 | - </metal:heading> |
| 1403 | - |
| 1404 | - <div metal:fill-slot="heading"> |
| 1405 | - <h1> |
| 1406 | - Upstream report for |
| 1407 | - <tal:distro replace="context/displayname" /> |
| 1408 | - </h1> |
| 1409 | - </div> |
| 1410 | - |
| 1411 | - <div metal:fill-slot="main"> |
| 1412 | - <div class="top-portlet"> |
| 1413 | - <div tal:condition="not:view/has_upstream_report" |
| 1414 | - id="no-lp-usage"> |
| 1415 | - This distribution does not use Launchpad for development. |
| 1416 | - </div> |
| 1417 | - <div tal:condition="view/has_upstream_report" |
| 1418 | - id="lp-used"> |
| 1419 | - <tal:no-bugs tal:condition="not: view/data"> |
| 1420 | - <span tal:replace="context/displayname" /> has no bugs filed |
| 1421 | - against it. |
| 1422 | - </tal:no-bugs> |
| 1423 | - |
| 1424 | - <p tal:condition="view/data"> |
| 1425 | - See the |
| 1426 | - <a href="https://wiki.ubuntu.com/Bugs/Upstream/UpstreamReport" |
| 1427 | - >UpstreamReport wiki page</a> |
| 1428 | - for information on how to read this report. |
| 1429 | - </p> |
| 1430 | - |
| 1431 | - <table class="listing" id="upstream-report" |
| 1432 | - tal:condition="view/data"> |
| 1433 | - <thead tal:define="links view/sort_order_links"> |
| 1434 | - <tr> |
| 1435 | - <th> |
| 1436 | - <a id="sort-dsp" tal:attributes="href links/dsp/link">Package</a> |
| 1437 | - <img id="sortarrow-dsp" tal:attributes="src links/dsp/arrow" /> |
| 1438 | - </th> |
| 1439 | - <th colspan="2"> |
| 1440 | - <a id="sort-product" tal:attributes="href links/product/link">Project</a> |
| 1441 | - <img id="sortarrow-product" tal:attributes="src links/product/arrow" /> |
| 1442 | - </th> |
| 1443 | - <th> |
| 1444 | - <a id="sort-bugtracker-name" |
| 1445 | - tal:attributes="href links/bugtracker_name/link" |
| 1446 | - >Bugtracker</a> |
| 1447 | - <img id="sortarrow-bugtracker-name" |
| 1448 | - tal:attributes="src links/bugtracker_name/arrow" /> |
| 1449 | - </th> |
| 1450 | - <th> |
| 1451 | - <a id="sort-bug-supervisor-name" |
| 1452 | - tal:attributes="href links/bug_supervisor_name/link" |
| 1453 | - >Upstream Contact</a> |
| 1454 | - <img id="sortarrow-bug-supervisor-name" |
| 1455 | - tal:attributes="src links/bug_supervisor_name/arrow" /> |
| 1456 | - </th> |
| 1457 | - <th class="amount"> |
| 1458 | - <a id="sort-open-bugs" |
| 1459 | - tal:attributes="href links/open_bugs/link">Open</a> |
| 1460 | - <img id="sortarrow-open-bugs" |
| 1461 | - tal:attributes="src links/open_bugs/arrow" /> |
| 1462 | - </th> |
| 1463 | - <th class="amount"> |
| 1464 | - <a id="sort-triaged-bugs" |
| 1465 | - tal:attributes="href links/triaged_bugs/link" |
| 1466 | - >Triaged</a> |
| 1467 | - <img id="sortarrow-triaged-bugs" |
| 1468 | - tal:attributes="src links/triaged_bugs/arrow" /> |
| 1469 | - </th> |
| 1470 | - <th class="amount"> |
| 1471 | - <a id="sort-triaged-percentage" |
| 1472 | - tal:attributes="href links/triaged_bugs_percentage/link" |
| 1473 | - >%</a> |
| 1474 | - <img id="sortarrow-triaged-percentage" |
| 1475 | - tal:attributes="src links/triaged_bugs_percentage/arrow" /> |
| 1476 | - </th> |
| 1477 | - <th class="amount"> |
| 1478 | - <a id="sort-triaged-delta" |
| 1479 | - tal:attributes="href links/triaged_bugs_delta/link" |
| 1480 | - >Δ</a> |
| 1481 | - <img id="sortarrow-triaged-delta" |
| 1482 | - tal:attributes="src links/triaged_bugs_delta/arrow" /> |
| 1483 | - </th> |
| 1484 | - <th class="amount"> |
| 1485 | - <a id="sort-upstream-bugs" |
| 1486 | - tal:attributes="href links/upstream_bugs/link" |
| 1487 | - >Upstream</a> |
| 1488 | - <img id="sortarrow-upstream-bugs" |
| 1489 | - tal:attributes="src links/upstream_bugs/arrow" /> |
| 1490 | - </th> |
| 1491 | - <th class="amount"> |
| 1492 | - <a id="sort-upstream-percentage" |
| 1493 | - tal:attributes="href links/upstream_bugs_percentage/link" |
| 1494 | - >%</a> |
| 1495 | - <img id="sortarrow-upstream-percentage" |
| 1496 | - tal:attributes="src links/upstream_bugs_percentage/arrow" /> |
| 1497 | - </th> |
| 1498 | - <th class="amount"> |
| 1499 | - <a id="sort-upstream-delta" |
| 1500 | - tal:attributes="href links/upstream_bugs_delta/link" |
| 1501 | - >Δ</a> |
| 1502 | - <img id="sortarrow-upstream-delta" |
| 1503 | - tal:attributes="src links/upstream_bugs_delta/arrow" /> |
| 1504 | - </th> |
| 1505 | - <th class="amount"> |
| 1506 | - <a id="sort-watched-bugs" |
| 1507 | - tal:attributes="href links/watched_bugs/link">Watch</a> |
| 1508 | - <img id="sortarrow-watched-bugs" |
| 1509 | - tal:attributes="src links/watched_bugs/arrow" /> |
| 1510 | - </th> |
| 1511 | - <th class="amount"> |
| 1512 | - <a id="sort-watched-percentage" |
| 1513 | - tal:attributes="href links/watched_bugs_percentage/link" |
| 1514 | - >%</a> |
| 1515 | - <img id="sortarrow-watched-percentage" |
| 1516 | - tal:attributes="src links/watched_bugs_percentage/arrow" /> |
| 1517 | - </th> |
| 1518 | - <th class="amount"> |
| 1519 | - <a id="sort-watched-delta" |
| 1520 | - tal:attributes="href links/watched_bugs_delta/link" |
| 1521 | - >Δ</a> |
| 1522 | - <img id="sortarrow-watched-delta" |
| 1523 | - tal:attributes="src links/watched_bugs_delta/arrow" /> |
| 1524 | - </th> |
| 1525 | - <th class="amount"> |
| 1526 | - <a id="sort-bugs-with-upstream-patches" |
| 1527 | - tal:attributes="href links/bugs_with_upstream_patches/link" |
| 1528 | - >Patches for upstream</a> |
| 1529 | - <img id="sortarrow-bugs-with-upstream-patches" |
| 1530 | - tal:attributes="src links/bugs_with_upstream_patches/arrow" /> |
| 1531 | - </th> |
| 1532 | - </tr> |
| 1533 | - </thead> |
| 1534 | - <tbody id="upstream-report-content"> |
| 1535 | - <tr tal:repeat="item view/data" tal:attributes="class item/row_class"> |
| 1536 | - <td> |
| 1537 | - <a tal:attributes="href item/dsp/fmt:url" |
| 1538 | - tal:content="item/dsp/name"></a> |
| 1539 | - </td> |
| 1540 | - <tal:has-product condition="item/product"> |
| 1541 | - <td style="padding-right: 0" align="center"> |
| 1542 | - <a tal:attributes="href item/branch/fmt:url; |
| 1543 | - title string:You can use `bzr branch lp:${item/product/name}' to fetch this project's code" |
| 1544 | - tal:condition="item/branch"> |
| 1545 | - <img alt="(branch)" src="/@@/branch" /></a> |
| 1546 | - </td> |
| 1547 | - <td style="padding-left: 0" align="center"> |
| 1548 | - <a tal:attributes="href item/product/fmt:url" |
| 1549 | - ><img src="/@@/yes" |
| 1550 | - tal:attributes="title item/product/title" /></a> |
| 1551 | - </td> |
| 1552 | - <tal:has-bugtracker condition="item/bugtracker"> |
| 1553 | - <td align="center"> |
| 1554 | - <a tal:attributes="href item/bugtracker/fmt:url" |
| 1555 | - ><img src="/@@/yes" |
| 1556 | - tal:attributes="title item/bugtracker/title" /></a> |
| 1557 | - </td> |
| 1558 | - </tal:has-bugtracker> |
| 1559 | - <tal:has-no-bugtracker condition="not: item/bugtracker"> |
| 1560 | - <td tal:condition="item/bug_tracking_usage/enumvalue:LAUNCHPAD" |
| 1561 | - align="center"> |
| 1562 | - <img src="/@@/yes" title="Launchpad" /> |
| 1563 | - </td> |
| 1564 | - <td tal:condition="not: item/bug_tracking_usage/enumvalue:LAUNCHPAD" |
| 1565 | - align="center"> |
| 1566 | - <img src="/@@/no" title="Unknown" /> |
| 1567 | - <a tal:condition="item/product/required:launchpad.Edit" |
| 1568 | - tal:attributes="href item/product_edit_url"> |
| 1569 | - <small>(fix)</small></a></td> |
| 1570 | - </tal:has-no-bugtracker> |
| 1571 | - <tal:has-bug-supervisor condition="item/product/bug_supervisor"> |
| 1572 | - <td align="center"> |
| 1573 | - <a tal:attributes="href item/product/bug_supervisor/fmt:url" |
| 1574 | - ><img src="/@@/yes" |
| 1575 | - tal:attributes="title item/product/bug_supervisor/fmt:displayname" |
| 1576 | - /></a> |
| 1577 | - </td> |
| 1578 | - </tal:has-bug-supervisor> |
| 1579 | - <tal:has-no-bug-supervisor condition="not: item/product/bug_supervisor"> |
| 1580 | - <td align="center"> |
| 1581 | - <img src="/@@/no" title="Unspecified" /> |
| 1582 | - <a tal:condition="item/product/required:launchpad.Edit" |
| 1583 | - tal:attributes="href item/bug_supervisor_url"> |
| 1584 | - <small>(change)</small></a></td> |
| 1585 | - </tal:has-no-bug-supervisor> |
| 1586 | - </tal:has-product> |
| 1587 | - <tal:has-no-product condition="not: item/product"> |
| 1588 | - <td align="center" class="bad" colspan="4"> |
| 1589 | - Missing corresponding project. |
| 1590 | - <a href="/projects"><small>(find)</small></a> |
| 1591 | - <a tal:attributes="href item/packaging_url"> |
| 1592 | - <small>(link)</small></a> |
| 1593 | - </td> |
| 1594 | - </tal:has-no-product> |
| 1595 | - <td class="amount"> |
| 1596 | - <a tal:attributes="href item/open_bugs_url" |
| 1597 | - tal:content="item/open_bugs"></a> |
| 1598 | - </td> |
| 1599 | - <td tal:attributes="class string:amount ${item/triaged_bugs_class}"> |
| 1600 | - <a tal:attributes="href item/triaged_bugs_url" |
| 1601 | - tal:content="item/triaged_bugs"></a> |
| 1602 | - </td> |
| 1603 | - <td tal:attributes="class string:amount ${item/triaged_bugs_class}" |
| 1604 | - tal:content="item/triaged_bugs_percentage/fmt:float/.2" /> |
| 1605 | - <td tal:attributes="class string:amount ${item/triaged_bugs_class}"> |
| 1606 | - <a tal:attributes="href item/triaged_bugs_delta_url" |
| 1607 | - tal:content="item/triaged_bugs_delta"></a> |
| 1608 | - </td> |
| 1609 | - <td tal:attributes="class string:amount ${item/upstream_bugs_class}"> |
| 1610 | - <a tal:attributes="href item/upstream_bugs_url" |
| 1611 | - tal:content="item/upstream_bugs"></a> |
| 1612 | - </td> |
| 1613 | - <td tal:attributes="class string:amount ${item/upstream_bugs_class}" |
| 1614 | - tal:content="item/upstream_bugs_percentage/fmt:float/.2" /> |
| 1615 | - <td tal:attributes="class string:amount ${item/upstream_bugs_class}"> |
| 1616 | - <a tal:attributes="href item/upstream_bugs_delta_url" |
| 1617 | - tal:content="item/upstream_bugs_delta"></a> |
| 1618 | - </td> |
| 1619 | - <tal:upstream-in-launchpad |
| 1620 | - condition="item/bug_tracking_usage/enumvalue:LAUNCHPAD"> |
| 1621 | - <td colspan="4" class="good"> </td> |
| 1622 | - </tal:upstream-in-launchpad> |
| 1623 | - <tal:upstream-not-in-launchpad |
| 1624 | - condition="not: item/bug_tracking_usage/enumvalue:LAUNCHPAD"> |
| 1625 | - <td tal:attributes="class string:amount ${item/watched_bugs_class}" |
| 1626 | - tal:content="item/watched_bugs" /> |
| 1627 | - <td tal:attributes="class string:amount ${item/watched_bugs_class}" |
| 1628 | - tal:content="item/watched_bugs_percentage/fmt:float/.2" /> |
| 1629 | - <td tal:attributes="class string:amount ${item/watched_bugs_class}"> |
| 1630 | - <a tal:attributes="href item/watched_bugs_delta_url" |
| 1631 | - tal:content="item/watched_bugs_delta"></a> |
| 1632 | - </td> |
| 1633 | - <td tal:attributes="class string:amount ${item/watched_bugs_class}"> |
| 1634 | - <tal:has-bugs-with-upstream-patches |
| 1635 | - condition="item/bugs_with_upstream_patches"> |
| 1636 | - <a tal:attributes="href item/bugs_with_upstream_patches_url" |
| 1637 | - tal:content="item/bugs_with_upstream_patches"></a> |
| 1638 | - </tal:has-bugs-with-upstream-patches> |
| 1639 | - <tal:has-no-bugs-with-upstream-patches |
| 1640 | - condition="not: item/bugs_with_upstream_patches"> |
| 1641 | - - |
| 1642 | - </tal:has-no-bugs-with-upstream-patches> |
| 1643 | - </td> |
| 1644 | - </tal:upstream-not-in-launchpad> |
| 1645 | - </tr> |
| 1646 | - </tbody> |
| 1647 | - <tfoot id="upstream-report-totals"> |
| 1648 | - <tr> |
| 1649 | - <td colspan="5" class="amount"><b>Totals:</b></td> |
| 1650 | - <td class="amount" |
| 1651 | - tal:content="view/total/open_bugs" /> |
| 1652 | - <td class="amount" |
| 1653 | - tal:content="view/total/triaged_bugs" /> |
| 1654 | - <td class="amount" |
| 1655 | - tal:content="view/total/triaged_bugs_percentage/fmt:float/.2" /> |
| 1656 | - <td class="amount" |
| 1657 | - tal:content="view/total/triaged_bugs_delta" /> |
| 1658 | - <td class="amount" |
| 1659 | - tal:content="view/total/upstream_bugs" /> |
| 1660 | - <td class="amount" |
| 1661 | - tal:content="view/total/upstream_bugs_percentage/fmt:float/.2" /> |
| 1662 | - <td class="amount" |
| 1663 | - tal:content="view/total/upstream_bugs_delta" /> |
| 1664 | - <td class="amount" |
| 1665 | - tal:content="view/total/watched_bugs" /> |
| 1666 | - <td class="amount" |
| 1667 | - tal:content="view/total/watched_bugs_percentage/fmt:float/.2" /> |
| 1668 | - <td class="amount" |
| 1669 | - tal:content="view/total/watched_bugs_delta" /> |
| 1670 | - <td class="amount" |
| 1671 | - tal:content="view/total/bugs_with_upstream_patches" /> |
| 1672 | - </tr> |
| 1673 | - </tfoot> |
| 1674 | - </table> |
| 1675 | - |
| 1676 | - <div tal:condition="view/data" |
| 1677 | - align="right"><small>Top <span tal:content="view/data/count:len" /> |
| 1678 | - packages listed.</small></div> |
| 1679 | - </div> |
| 1680 | - </div> |
| 1681 | - </div> |
| 1682 | - |
| 1683 | -</distribution-upstream-report> |
| 1684 | |
| 1685 | === modified file 'lib/lp/registry/interfaces/distribution.py' |
| 1686 | --- lib/lp/registry/interfaces/distribution.py 2012-10-24 09:47:43 +0000 |
| 1687 | +++ lib/lp/registry/interfaces/distribution.py 2012-11-02 01:01:22 +0000 |
| 1688 | @@ -346,10 +346,6 @@ |
| 1689 | all_distro_archive_ids = Attribute( |
| 1690 | "A list containing the IDs of all the non-PPA archives.") |
| 1691 | |
| 1692 | - upstream_report_excluded_packages = Attribute( |
| 1693 | - "A list of the source packages that should not be shown on the " |
| 1694 | - "upstream report for this Distribution.") |
| 1695 | - |
| 1696 | has_published_binaries = Bool( |
| 1697 | title=_("Has Published Binaries"), |
| 1698 | description=_("True if this distribution has binaries published " |
| 1699 | @@ -606,25 +602,6 @@ |
| 1700 | If the component_name supplied is unknown, None is returned. |
| 1701 | """ |
| 1702 | |
| 1703 | - def getPackagesAndPublicUpstreamBugCounts(limit=50, |
| 1704 | - exclude_packages=None): |
| 1705 | - """Return list of tuples of packages, upstreams and public bug counts. |
| 1706 | - |
| 1707 | - :param limit: The maximum number of rows to return. |
| 1708 | - :param exclude_packages: A list of source packages to exclude. |
| 1709 | - These should be specified as strings which correspond with |
| 1710 | - SourcePackageName.name. |
| 1711 | - :returns: [(IDistroSourcePackage, IProduct, int, int, int, int), ...] |
| 1712 | - |
| 1713 | - This API is quite specialized; it returns a list of up to limit |
| 1714 | - tuples containing IProducts and three different bug counts: |
| 1715 | - - open bugs |
| 1716 | - - triaged bugs |
| 1717 | - - open bugs with an upstream task |
| 1718 | - - open bugs with upstream tasks that are either linked to |
| 1719 | - bug watches or to products that use_malone. |
| 1720 | - """ |
| 1721 | - |
| 1722 | def getAllowedBugInformationTypes(): |
| 1723 | """Get the information types that a bug in this distribution can have. |
| 1724 | |
| 1725 | |
| 1726 | === modified file 'lib/lp/registry/model/distribution.py' |
| 1727 | --- lib/lp/registry/model/distribution.py 2012-10-24 09:43:58 +0000 |
| 1728 | +++ lib/lp/registry/model/distribution.py 2012-11-02 01:01:22 +0000 |
| 1729 | @@ -81,10 +81,6 @@ |
| 1730 | from lp.blueprints.model.sprint import HasSprintsMixin |
| 1731 | from lp.bugs.interfaces.bugsummary import IBugSummaryDimension |
| 1732 | from lp.bugs.interfaces.bugsupervisor import IHasBugSupervisor |
| 1733 | -from lp.bugs.interfaces.bugtask import ( |
| 1734 | - BugTaskStatus, |
| 1735 | - DB_UNRESOLVED_BUGTASK_STATUSES, |
| 1736 | - ) |
| 1737 | from lp.bugs.interfaces.bugtaskfilter import OrderedBugTask |
| 1738 | from lp.bugs.model.bugtarget import ( |
| 1739 | BugTargetBase, |
| 1740 | @@ -116,7 +112,6 @@ |
| 1741 | MirrorStatus, |
| 1742 | ) |
| 1743 | from lp.registry.interfaces.oopsreferences import IHasOOPSReferences |
| 1744 | -from lp.registry.interfaces.packaging import PackagingType |
| 1745 | from lp.registry.interfaces.person import ( |
| 1746 | validate_person, |
| 1747 | validate_person_or_closed_team, |
| 1748 | @@ -152,7 +147,6 @@ |
| 1749 | from lp.services.database.enumcol import EnumCol |
| 1750 | from lp.services.database.lpstorm import IStore |
| 1751 | from lp.services.database.sqlbase import ( |
| 1752 | - cursor, |
| 1753 | quote, |
| 1754 | SQLBase, |
| 1755 | sqlvalues, |
| 1756 | @@ -339,8 +333,7 @@ |
| 1757 | |
| 1758 | _answers_usage = EnumCol( |
| 1759 | dbName="answers_usage", notNull=True, |
| 1760 | - schema=ServiceUsage, |
| 1761 | - default=ServiceUsage.UNKNOWN) |
| 1762 | + schema=ServiceUsage, default=ServiceUsage.UNKNOWN) |
| 1763 | |
| 1764 | def _get_answers_usage(self): |
| 1765 | if self._answers_usage != ServiceUsage.UNKNOWN: |
| 1766 | @@ -389,8 +382,7 @@ |
| 1767 | |
| 1768 | translations_usage = EnumCol( |
| 1769 | dbName="translations_usage", notNull=True, |
| 1770 | - schema=ServiceUsage, |
| 1771 | - default=ServiceUsage.UNKNOWN) |
| 1772 | + schema=ServiceUsage, default=ServiceUsage.UNKNOWN) |
| 1773 | |
| 1774 | @property |
| 1775 | def codehosting_usage(self): |
| 1776 | @@ -1424,170 +1416,6 @@ |
| 1777 | # Otherwise we defer to the caller. |
| 1778 | return None |
| 1779 | |
| 1780 | - @property |
| 1781 | - def upstream_report_excluded_packages(self): |
| 1782 | - """See `IDistribution`.""" |
| 1783 | - # If the current distribution is Ubuntu, return a specific set |
| 1784 | - # of excluded packages. Otherwise return an empty list. |
| 1785 | - ubuntu = getUtility(ILaunchpadCelebrities).ubuntu |
| 1786 | - if self == ubuntu: |
| 1787 | - #XXX gmb 2009-02-02: bug 324298 |
| 1788 | - # This needs to be managed in a nicer, non-hardcoded |
| 1789 | - # fashion. |
| 1790 | - excluded_packages = [ |
| 1791 | - 'apport', |
| 1792 | - 'casper', |
| 1793 | - 'displayconfig-gtk', |
| 1794 | - 'flashplugin-nonfree', |
| 1795 | - 'gnome-app-install', |
| 1796 | - 'nvidia-graphics-drivers-177', |
| 1797 | - 'software-properties', |
| 1798 | - 'sun-java6', |
| 1799 | - 'synaptic', |
| 1800 | - 'ubiquity', |
| 1801 | - 'ubuntu-meta', |
| 1802 | - 'update-manager', |
| 1803 | - 'update-notifier', |
| 1804 | - 'usb-creator', |
| 1805 | - 'usplash', |
| 1806 | - ] |
| 1807 | - else: |
| 1808 | - excluded_packages = [] |
| 1809 | - |
| 1810 | - return excluded_packages |
| 1811 | - |
| 1812 | - def getPackagesAndPublicUpstreamBugCounts(self, limit=50, |
| 1813 | - exclude_packages=None): |
| 1814 | - """See `IDistribution`.""" |
| 1815 | - from lp.registry.model.product import Product |
| 1816 | - |
| 1817 | - if exclude_packages is None or len(exclude_packages) == 0: |
| 1818 | - # If exclude_packages is None or an empty list we set it to |
| 1819 | - # be a list containing a single empty string. This is so |
| 1820 | - # that we can quote() it properly for the query below ('NOT |
| 1821 | - # IN ()' is not valid SQL). |
| 1822 | - exclude_packages = [''] |
| 1823 | - else: |
| 1824 | - # Otherwise, listify exclude_packages so that we're not |
| 1825 | - # trying to quote() a security proxy object. |
| 1826 | - exclude_packages = list(exclude_packages) |
| 1827 | - |
| 1828 | - # This method collects three open bug counts for |
| 1829 | - # sourcepackagenames in this distribution first, and then caches |
| 1830 | - # product information before rendering everything into a list of |
| 1831 | - # tuples. |
| 1832 | - cur = cursor() |
| 1833 | - cur.execute(""" |
| 1834 | - SELECT SPN.id, SPN.name, |
| 1835 | - COUNT(DISTINCT Bugtask.bug) AS open_bugs, |
| 1836 | - COUNT(DISTINCT CASE WHEN Bugtask.status = %(triaged)s THEN |
| 1837 | - Bugtask.bug END) AS bugs_triaged, |
| 1838 | - COUNT(DISTINCT CASE WHEN Bugtask.status IN %(unresolved)s THEN |
| 1839 | - RelatedBugTask.bug END) AS bugs_affecting_upstream, |
| 1840 | - COUNT(DISTINCT CASE WHEN Bugtask.status in %(unresolved)s AND |
| 1841 | - (RelatedBugTask.bugwatch IS NOT NULL OR |
| 1842 | - RelatedProduct.official_malone IS TRUE) THEN |
| 1843 | - RelatedBugTask.bug END) AS bugs_with_upstream_bugwatch, |
| 1844 | - COUNT(DISTINCT CASE WHEN Bugtask.status in %(unresolved)s AND |
| 1845 | - RelatedBugTask.bugwatch IS NULL AND |
| 1846 | - RelatedProduct.official_malone IS FALSE AND |
| 1847 | - Bug.latest_patch_uploaded IS NOT NULL |
| 1848 | - THEN |
| 1849 | - RelatedBugTask.bug END) |
| 1850 | - AS bugs_with_upstream_patches |
| 1851 | - FROM |
| 1852 | - SourcePackageName AS SPN |
| 1853 | - JOIN Bugtask ON SPN.id = Bugtask.sourcepackagename |
| 1854 | - JOIN Bug ON Bug.id = Bugtask.bug |
| 1855 | - LEFT OUTER JOIN Bugtask AS RelatedBugtask ON ( |
| 1856 | - RelatedBugtask.bug = Bugtask.bug |
| 1857 | - AND RelatedBugtask.id != Bugtask.id |
| 1858 | - AND RelatedBugtask.product IS NOT NULL |
| 1859 | - AND RelatedBugtask.status != %(invalid)s |
| 1860 | - ) |
| 1861 | - LEFT OUTER JOIN Product AS RelatedProduct ON ( |
| 1862 | - RelatedBugtask.product = RelatedProduct.id |
| 1863 | - ) |
| 1864 | - WHERE |
| 1865 | - Bugtask.distribution = %(distro)s |
| 1866 | - AND Bugtask.sourcepackagename = spn.id |
| 1867 | - AND Bugtask.distroseries IS NULL |
| 1868 | - AND Bugtask.status IN %(unresolved)s |
| 1869 | - AND Bug.information_type IN %(public_types)s |
| 1870 | - AND Bug.duplicateof IS NULL |
| 1871 | - AND spn.name NOT IN %(excluded_packages)s |
| 1872 | - GROUP BY SPN.id, SPN.name |
| 1873 | - HAVING COUNT(DISTINCT Bugtask.bug) > 0 |
| 1874 | - ORDER BY open_bugs DESC, SPN.name LIMIT %(limit)s |
| 1875 | - """ % {'invalid': quote(BugTaskStatus.INVALID), |
| 1876 | - 'triaged': quote(BugTaskStatus.TRIAGED), |
| 1877 | - 'limit': limit, |
| 1878 | - 'distro': self.id, |
| 1879 | - 'unresolved': quote(DB_UNRESOLVED_BUGTASK_STATUSES), |
| 1880 | - 'excluded_packages': quote(exclude_packages), |
| 1881 | - 'public_types': quote(PUBLIC_INFORMATION_TYPES), |
| 1882 | - }) |
| 1883 | - counts = cur.fetchall() |
| 1884 | - cur.close() |
| 1885 | - if not counts: |
| 1886 | - # If no counts are returned it means that there are no |
| 1887 | - # source package names in the database -- because the counts |
| 1888 | - # would just return zero if no bugs existed. And if there |
| 1889 | - # are no packages are in the database, all bets are off. |
| 1890 | - return [] |
| 1891 | - |
| 1892 | - # Next step is to extract which IDs actually show up in the |
| 1893 | - # output we generate, and cache them. |
| 1894 | - spn_ids = [item[0] for item in counts] |
| 1895 | - list(SourcePackageName.select("SourcePackageName.id IN %s" |
| 1896 | - % sqlvalues(spn_ids))) |
| 1897 | - |
| 1898 | - # Finally find out what products are attached to these source |
| 1899 | - # packages (if any) and cache them too. The ordering of the |
| 1900 | - # query by Packaging.id ensures that the dictionary holds the |
| 1901 | - # latest entries for situations where we have multiple entries. |
| 1902 | - cur = cursor() |
| 1903 | - cur.execute(""" |
| 1904 | - SELECT Packaging.sourcepackagename, Product.id |
| 1905 | - FROM Product, Packaging, ProductSeries, DistroSeries |
| 1906 | - WHERE ProductSeries.product = Product.id AND |
| 1907 | - DistroSeries.distribution = %s AND |
| 1908 | - Packaging.distroseries = DistroSeries.id AND |
| 1909 | - Packaging.productseries = ProductSeries.id AND |
| 1910 | - Packaging.sourcepackagename IN %s AND |
| 1911 | - Packaging.packaging = %s AND |
| 1912 | - Product.active IS TRUE |
| 1913 | - ORDER BY Packaging.id |
| 1914 | - """ % sqlvalues(self.id, spn_ids, PackagingType.PRIME)) |
| 1915 | - sources_to_products = dict(cur.fetchall()) |
| 1916 | - cur.close() |
| 1917 | - if sources_to_products: |
| 1918 | - # Cache some more information to avoid us having to hit the |
| 1919 | - # database hard for each product rendered. |
| 1920 | - list(Product.select("Product.id IN %s" % |
| 1921 | - sqlvalues(sources_to_products.values()), |
| 1922 | - prejoins=["bug_supervisor", "bugtracker", "project", |
| 1923 | - "development_focus.branch"])) |
| 1924 | - |
| 1925 | - # Okay, we have all the information good to go, so assemble it |
| 1926 | - # in a reasonable data structure. |
| 1927 | - results = [] |
| 1928 | - for (spn_id, spn_name, open_bugs, bugs_triaged, |
| 1929 | - bugs_affecting_upstream, bugs_with_upstream_bugwatch, |
| 1930 | - bugs_with_upstream_patches) in counts: |
| 1931 | - sourcepackagename = SourcePackageName.get(spn_id) |
| 1932 | - dsp = self.getSourcePackage(sourcepackagename) |
| 1933 | - if spn_id in sources_to_products: |
| 1934 | - product_id = sources_to_products[spn_id] |
| 1935 | - product = Product.get(product_id) |
| 1936 | - else: |
| 1937 | - product = None |
| 1938 | - results.append( |
| 1939 | - (dsp, product, open_bugs, bugs_triaged, |
| 1940 | - bugs_affecting_upstream, bugs_with_upstream_bugwatch, |
| 1941 | - bugs_with_upstream_patches)) |
| 1942 | - return results |
| 1943 | - |
| 1944 | def getAllowedBugInformationTypes(self): |
| 1945 | """See `IDistribution.`""" |
| 1946 | return FREE_INFORMATION_TYPES |

Thank you. This page is fatally flawed. I uses data from 2008. It encourages contributors to be working on ekiga instead of zeitgiest. The numbers can be accurately provided by an API script and the community can write and run such a script for packages that are actually seeded in Raring.