Mercurial > bitten > bitten-test
comparison bitten/web_ui.py @ 883:dfbf2f857a50
Fixed handling of active configurations that points to deleted branches.
Configurations and builds can now be checked and displayed even though the repository path cannot be found for last revision. It uses configuration 'last' (`max_rev`) to "close" the configuration.
Closes #606. Thanks to falkb for extensive testing.
author | osimons |
---|---|
date | Fri, 10 Dec 2010 09:23:12 +0000 |
parents | a68027e2245d |
children |
comparison
equal
deleted
inserted
replaced
881:15cf0edad043 | 883:dfbf2f857a50 |
---|---|
20 from genshi.builder import tag | 20 from genshi.builder import tag |
21 from trac.attachment import AttachmentModule, Attachment | 21 from trac.attachment import AttachmentModule, Attachment |
22 from trac.core import * | 22 from trac.core import * |
23 from trac.config import Option | 23 from trac.config import Option |
24 from trac.mimeview.api import Context | 24 from trac.mimeview.api import Context |
25 from trac.perm import PermissionError | |
25 from trac.resource import Resource | 26 from trac.resource import Resource |
26 from trac.timeline import ITimelineEventProvider | 27 from trac.timeline import ITimelineEventProvider |
27 from trac.util import escape, pretty_timedelta, format_datetime, shorten_line, \ | 28 from trac.util import escape, pretty_timedelta, format_datetime, shorten_line, \ |
28 Markup, arity | 29 Markup, arity |
29 from trac.util.datefmt import to_timestamp, to_datetime, utc | 30 from trac.util.datefmt import to_timestamp, to_datetime, utc |
30 from trac.util.html import html | 31 from trac.util.html import html |
31 from trac.web import IRequestHandler, IRequestFilter, HTTPNotFound | 32 from trac.web import IRequestHandler, IRequestFilter, HTTPNotFound |
32 from trac.web.chrome import INavigationContributor, ITemplateProvider, \ | 33 from trac.web.chrome import INavigationContributor, ITemplateProvider, \ |
33 add_link, add_stylesheet, add_ctxtnav, \ | 34 add_link, add_stylesheet, add_ctxtnav, \ |
34 prevnext_nav, add_script | 35 prevnext_nav, add_script, add_warning |
35 from trac.versioncontrol import NoSuchChangeset | 36 from trac.versioncontrol import NoSuchChangeset, NoSuchNode |
36 from trac.wiki import wiki_to_html, wiki_to_oneliner | 37 from trac.wiki import wiki_to_html, wiki_to_oneliner |
37 from bitten.api import ILogFormatter, IReportChartGenerator, IReportSummarizer | 38 from bitten.api import ILogFormatter, IReportChartGenerator, IReportSummarizer |
38 from bitten.master import BuildMaster | 39 from bitten.master import BuildMaster |
39 from bitten.model import BuildConfig, TargetPlatform, Build, BuildStep, \ | 40 from bitten.model import BuildConfig, TargetPlatform, Build, BuildStep, \ |
40 BuildLog, Report | 41 BuildLog, Report |
78 'machine': build.slave_info.get(Build.MACHINE), | 79 'machine': build.slave_info.get(Build.MACHINE), |
79 'processor': build.slave_info.get(Build.PROCESSOR) | 80 'processor': build.slave_info.get(Build.PROCESSOR) |
80 } | 81 } |
81 return data | 82 return data |
82 | 83 |
83 def _has_permission(repos, path, perm, raise_error=False): | 84 def _has_permission(perm, repos, path, rev=None, raise_error=False): |
84 if hasattr(repos, 'authz'): | 85 if hasattr(repos, 'authz'): |
85 if not repos.authz.has_permission(path): | 86 if not repos.authz.has_permission(path): |
86 if not raise_error: | 87 if not raise_error: |
87 return False | 88 return False |
88 repos.authz.assert_permission(path) | 89 repos.authz.assert_permission(path) |
89 else: | 90 else: |
90 node = repos.get_node(path) | 91 node = repos.get_node(path, rev) |
91 if not node.can_view(perm): | 92 if not node.can_view(perm): |
92 if not raise_error: | 93 if not raise_error: |
93 return False | 94 return False |
94 from trac.perm import PermissionError | |
95 raise PermissionError('BROWSER_VIEW', node.resource) | 95 raise PermissionError('BROWSER_VIEW', node.resource) |
96 return True | 96 return True |
97 | 97 |
98 class BittenChrome(Component): | 98 class BittenChrome(Component): |
99 """Provides the Bitten templates and static resources.""" | 99 """Provides the Bitten templates and static resources.""" |
217 assert repos, 'No "(default)" Repository: Add a repository or alias ' \ | 217 assert repos, 'No "(default)" Repository: Add a repository or alias ' \ |
218 'named "(default)" to Trac.' | 218 'named "(default)" to Trac.' |
219 | 219 |
220 configs = [] | 220 configs = [] |
221 for config in BuildConfig.select(self.env, include_inactive=show_all): | 221 for config in BuildConfig.select(self.env, include_inactive=show_all): |
222 if not _has_permission(repos, config.path, req.perm): | 222 rev = config.max_rev or repos.youngest_rev |
223 try: | |
224 if not _has_permission(req.perm, repos, config.path, rev=rev): | |
225 continue | |
226 except NoSuchNode: | |
227 add_warning(req, "Configuration '%s' points to non-existing " | |
228 "path '/%s' at revision '%s'. Configuration skipped." \ | |
229 % (config.name, config.path, rev)) | |
223 continue | 230 continue |
224 | 231 |
225 description = config.description | 232 description = config.description |
226 if description: | 233 if description: |
227 description = wiki_to_html(description, self.env, req) | 234 description = wiki_to_html(description, self.env, req) |
307 assert repos, 'No "(default)" Repository: Add a repository or alias ' \ | 314 assert repos, 'No "(default)" Repository: Add a repository or alias ' \ |
308 'named "(default)" to Trac.' | 315 'named "(default)" to Trac.' |
309 | 316 |
310 configs = [] | 317 configs = [] |
311 for config in BuildConfig.select(self.env, include_inactive=False): | 318 for config in BuildConfig.select(self.env, include_inactive=False): |
312 if not _has_permission(repos, config.path, req.perm): | 319 rev = config.max_rev or repos.youngest_rev |
320 try: | |
321 if not _has_permission(req.perm, repos, config.path, rev=rev): | |
322 continue | |
323 except NoSuchNode: | |
324 add_warning(req, "Configuration '%s' points to non-existing " | |
325 "path '/%s' at revision '%s'. Configuration skipped." \ | |
326 % (config.name, config.path, rev)) | |
313 continue | 327 continue |
314 | 328 |
315 self.log.debug(config.name) | 329 self.log.debug(config.name) |
316 if not config.active: | 330 if not config.active: |
317 continue | 331 continue |
373 % config_name) | 387 % config_name) |
374 | 388 |
375 repos = self.env.get_repository(authname=req.authname) | 389 repos = self.env.get_repository(authname=req.authname) |
376 assert repos, 'No "(default)" Repository: Add a repository or alias ' \ | 390 assert repos, 'No "(default)" Repository: Add a repository or alias ' \ |
377 'named "(default)" to Trac.' | 391 'named "(default)" to Trac.' |
378 _has_permission(repos, config.path, req.perm, True) | 392 rev = config.max_rev or repos.youngest_rev |
393 try: | |
394 _has_permission(req.perm, repos, config.path, rev=rev, | |
395 raise_error=True) | |
396 except NoSuchNode: | |
397 raise TracError("Permission checking against repository path %s " | |
398 "at revision %s failed." % (config.path, rev)) | |
379 | 399 |
380 data = {'title': 'Build Configuration "%s"' \ | 400 data = {'title': 'Build Configuration "%s"' \ |
381 % config.label or config.name, | 401 % config.label or config.name, |
382 'page_mode': 'view_config'} | 402 'page_mode': 'view_config'} |
383 add_link(req, 'up', req.href.build(), 'Build Status') | 403 add_link(req, 'up', req.href.build(), 'Build Status') |
603 and build.status != build.PENDING) | 623 and build.status != build.PENDING) |
604 | 624 |
605 repos = self.env.get_repository(authname=req.authname) | 625 repos = self.env.get_repository(authname=req.authname) |
606 assert repos, 'No "(default)" Repository: Add a repository or alias ' \ | 626 assert repos, 'No "(default)" Repository: Add a repository or alias ' \ |
607 'named "(default)" to Trac.' | 627 'named "(default)" to Trac.' |
608 _has_permission(repos, config.path, req.perm, True) | 628 _has_permission(req.perm, repos, config.path, rev=build.rev, raise_error=True) |
609 chgset = repos.get_changeset(build.rev) | 629 chgset = repos.get_changeset(build.rev) |
610 data['build']['chgset_author'] = chgset.author | 630 data['build']['chgset_author'] = chgset.author |
611 data['build']['display_rev'] = repos.normalize_rev(build.rev) | 631 data['build']['display_rev'] = repos.normalize_rev(build.rev) |
612 | 632 |
613 add_script(req, 'common/js/folding.js') | 633 add_script(req, 'common/js/folding.js') |
652 | 672 |
653 event_kinds = {Build.SUCCESS: 'successbuild', | 673 event_kinds = {Build.SUCCESS: 'successbuild', |
654 Build.FAILURE: 'failedbuild'} | 674 Build.FAILURE: 'failedbuild'} |
655 | 675 |
656 for id_, config, label, path, rev, platform, stopped, status in cursor: | 676 for id_, config, label, path, rev, platform, stopped, status in cursor: |
657 if not _has_permission(repos, path, req.perm): | 677 if not _has_permission(req.perm, repos, path, rev=rev): |
658 continue | 678 continue |
659 errors = [] | 679 errors = [] |
660 if status == Build.FAILURE: | 680 if status == Build.FAILURE: |
661 for step in BuildStep.select(self.env, build=id_, | 681 for step in BuildStep.select(self.env, build=id_, |
662 status=BuildStep.FAILURE, | 682 status=BuildStep.FAILURE, |