changeset 182:cafe294fa835

* Make the chart generation `ExtensionPoint`-based. * Minor improvements to the generated charts. * Fix display of the charts in IE6/Win.
author cmlenz
date Wed, 31 Aug 2005 13:34:17 +0000
parents 5ab5418d56cc
children fda952491beb
files bitten/trac_ext/api.py bitten/trac_ext/charts.py bitten/trac_ext/summarizers.py bitten/trac_ext/templates/bitten_chart_coverage.cs bitten/trac_ext/templates/bitten_chart_tests.cs bitten/trac_ext/templates/bitten_config.cs bitten/trac_ext/web_ui.py
diffstat 7 files changed, 134 insertions(+), 80 deletions(-) [+]
line wrap: on
line diff
--- a/bitten/trac_ext/api.py
+++ b/bitten/trac_ext/api.py
@@ -33,3 +33,18 @@
     def render_report_summary(req, build, step, report):
         """Render a summary for the given report and return the results HTML as
         a string."""
+
+
+class IReportChartGenerator(Interface):
+    """Extension point interface for components that generator a chart for a
+    set of reports."""
+
+    def get_supported_report_types():
+        """Return a list of strings identifying the types of reports this 
+        component supports."""
+
+    def generate_chart_data(req, config, type):
+        """Generate the data for the chart.
+        
+        This method should store the data in the HDF of the request and return
+        the name of the template that should process the data."""
--- a/bitten/trac_ext/charts.py
+++ b/bitten/trac_ext/charts.py
@@ -14,12 +14,15 @@
 from trac.web import IRequestHandler
 from bitten.model import BuildConfig, Build
 from bitten.store import ReportStore
+from bitten.trac_ext.api import IReportChartGenerator
 from bitten.util import xmlio
 
 
 class BittenChartRenderer(Component):
     implements(IRequestHandler)
 
+    generators = ExtensionPoint(IReportChartGenerator)
+
     # IRequestHandler methods
 
     def match_request(self, req):
@@ -30,26 +33,37 @@
             return True
 
     def process_request(self, req):
-        type = req.args.get('type')
+        report_type = req.args.get('type')
         config = BuildConfig.fetch(self.env, name=req.args.get('config'))
-        if type == 'unittest':
-            return self._render_tests(req, config)
-        elif type == 'trace':
-            return self._render_coverage(req, config)
+
+        for generator in self.generators:
+            if report_type in generator.get_supported_report_types():
+                template = generator.generate_chart_data(req, config,
+                                                         report_type)
+                break
         else:
-            raise TracError, 'Unknown report type'
+            raise TracError, 'Unknown report type "%s"' % report_type
 
-    # Internal methods
+        return template, 'text/xml'
 
-    def _render_tests(self, req, config):
+
+class TestResultsChartGenerator(Component):
+    implements(IReportChartGenerator)
+
+    # IReportChartGenerator methods
+
+    def get_supported_report_types(self):
+        return ['unittest']
+
+    def generate_chart_data(self, req, config, report_type):
         rev_time = {}
         rev = {}
         for build in Build.select(self.env, config=config.name):
             rev[str(build.id)] = build.rev
-            rev_time[str(build.id)] = build.rev_time
+            rev_time[str(build.id)] = datetime.fromtimestamp(build.rev_time)
 
         store = ReportStore(self.env)
-        query = """
+        xquery = """
 for $report in $reports
 return
     <tests build="{dbxml:metadata('build', $report)}"
@@ -59,28 +73,42 @@
 """
 
         tests = []
-        for test in store.query_reports(query, config=config, type='unittest'):
-            tests.append({
-                'time': datetime.fromtimestamp(rev_time[test.attr['build']]),
-                'rev': rev[test.attr['build']], 'total': test.attr['total'],
-                'failed': test.attr['failed'],
-            })
-        tests.sort(lambda x, y: cmp(x['time'], y['time']))
+        for test in store.query_reports(xquery, config=config, type='unittest'):
+            tests.append((
+                rev_time[test.attr['build']], # Changeset date/time
+                rev[test.attr['build']], # Changeset/revision
+                test.attr['total'], # Total number of tests
+                test.attr['failed'] # Number of errors/failures
+            ))
+        tests.sort()
 
         req.hdf['chart.title'] = 'Unit Tests'
-        req.hdf['chart.data'] = tests
+        req.hdf['chart.data'] = [
+            [''] + [item[1] for item in tests],
+            ['Total'] + [item[2] for item in tests],
+            ['Failures'] + [int(item[3]) for item in tests]
+        ]
 
-        return 'bitten_chart_tests.cs', 'text/xml'
+        return 'bitten_chart_tests.cs'
 
-    def _render_coverage(self, req, config):
+
+class TestResultsChartGenerator(Component):
+    implements(IReportChartGenerator)
+
+    # IReportChartGenerator methods
+
+    def get_supported_report_types(self):
+        return ['trace']
+
+    def generate_chart_data(self, req, config, report_type):
         rev_time = {}
         rev = {}
         for build in Build.select(self.env, config=config.name):
             rev[str(build.id)] = build.rev
-            rev_time[str(build.id)] = build.rev_time
+            rev_time[str(build.id)] = datetime.fromtimestamp(build.rev_time)
 
         store = ReportStore(self.env)
-        query = """
+        xquery = """
 for $report in $reports
 return
     <coverage build="{dbxml:metadata('build', $report)}"
@@ -94,17 +122,20 @@
 """
 
         coverage = []
-        for test in store.query_reports(query, config=config, type='trace'):
-            values = [float(val) for val in test.gettext().split()]
-            coverage.append({
-                'time': datetime.fromtimestamp(rev_time[test.attr['build']]),
-                'rev': rev[test.attr['build']], 'loc': test.attr['loc'],
-                'cov': int(sum(values))
-            })
-        coverage.sort(lambda x, y: cmp(x['time'], y['time']))
-
+        for test in store.query_reports(xquery, config=config, type='trace'):
+            coverage.append((
+                rev_time[test.attr['build']], # Changeset date/time
+                rev[test.attr['build']], # Changeset/revision
+                test.attr['loc'], # Lines of code
+                sum([float(val) for val in test.gettext().split()])
+            ))
+        coverage.sort()
 
         req.hdf['chart.title'] = 'Code Coverage'
-        req.hdf['chart.data'] = coverage
+        req.hdf['chart.data'] = [
+            [''] + [item[1] for item in coverage],
+            ['Lines of code'] + [item[2] for item in coverage],
+            ['Coverage'] + [int(item[3]) for item in coverage]
+        ]
 
-        return 'bitten_chart_coverage.cs', 'text/xml'
+        return 'bitten_chart_coverage.cs'
--- a/bitten/trac_ext/summarizers.py
+++ b/bitten/trac_ext/summarizers.py
@@ -31,7 +31,7 @@
         hdf = HDFWrapper(loadpaths=Chrome(self.env).get_all_templates_dirs())
         config = BuildConfig.fetch(self.env, name=build.config)
         store = ReportStore(self.env)
-        results = store.query_reports(self.query, config=config,build=build,
+        results = store.query_reports(self.query, config=config, build=build,
                                       step=step, type=self.report_type)
         for idx, elem in enumerate(results):
             data = {}
--- a/bitten/trac_ext/templates/bitten_chart_coverage.cs
+++ b/bitten/trac_ext/templates/bitten_chart_coverage.cs
@@ -3,33 +3,37 @@
   <value>area</value>
   <value>area</value>
  </chart_type>
- <axis_category size='10'
-   skip='<?cs var:len(chart.data) / 6 ?>' orientation='vertical' />
- <axis_ticks value_ticks='false' category_ticks='true' major_thickness='1'
-   minor_thickness='0' major_color='000000' position='outside' />
- 
- <chart_data>
-  <row><string /><?cs
-   each:item = chart.data ?><string><?cs var:item.rev ?></string><?cs
-   /each ?></row><row><string>Lines of Code</string><?cs
-   each:item = chart.data ?><string><?cs var:item.loc ?></string><?cs
-   /each ?></row><row><string>Coverage</string><?cs
-   each:item = chart.data ?><string><?cs var:item.cov ?></string><?cs
-   /each ?></row>
- </chart_data>
- 
- <chart_grid_h alpha='5' color='333333' thickness='2'/>
- <chart_pref line_thickness='2' point_shape='none'/> 
- <legend_rect x='-100' y='-100' width='10' height='10'/>
+
+ <axis_category size="10"
+   skip="<?cs var:len(chart.data.0) / 6 ?>" orientation="vertical" />
+ <axis_ticks value_ticks="false" category_ticks="true" major_thickness="1"
+   minor_thickness="0" major_color="000000" position="outside" />
+
+ <chart_data><?cs
+  each:row = chart.data ?><row><?cs
+   each:value = row ?><?cs
+    if:name(value) == 0 ?><string><?cs
+     var:value ?></string><?cs
+    else ?><number><?cs
+     var:value ?></number><?cs
+    /if ?><?cs
+   /each ?></row><?cs
+  /each ?></chart_data>
+
+ <chart_border color="999999" left_thickness="1" bottom_thickness="1"/>
+ <chart_grid_h alpha="5" color="666666" thickness="3"/>
+ <chart_pref line_thickness="2" point_shape="none"/>
+ <series_color>
+  <color>bbbbbb</color>
+  <color>9999ff</color>
+ </series_color>
+
+ <legend_label layout="vertical" alpha="60"/>
+ <legend_rect x="60" y="50" width="10"/>
 
  <draw>
   <text width="320" height="40" h_align="center" v_align="bottom" size="12" ><?cs
     var:chart.title ?></text>
  </draw>
- 
- <series_color>
-  <color>bbbbbb</color>
-  <color>99ff99</color>
- </series_color>
 
 </chart>
--- a/bitten/trac_ext/templates/bitten_chart_tests.cs
+++ b/bitten/trac_ext/templates/bitten_chart_tests.cs
@@ -3,32 +3,36 @@
   <value>area</value>
   <value>column</value>
  </chart_type>
- <axis_category size='10'
-   skip='<?cs var:len(chart.data) / 6 ?>' orientation='vertical' />
- <axis_ticks value_ticks='false' category_ticks='true' major_thickness='2'
-   minor_thickness='0' major_color='000000' position='outside' />
+ <axis_category size="10"
+   skip="<?cs var:len(chart.data.0) / 6 ?>" orientation="vertical" />
+ <axis_ticks value_ticks="false" category_ticks="true" major_thickness="2"
+   minor_thickness="0" major_color="000000" position="outside" />
  
- <chart_data>
-  <row><string /><?cs
-   each:item = chart.data ?><string><?cs var:item.rev ?></string><?cs
-   /each ?></row><row><string>Total</string><?cs
-   each:item = chart.data ?><string><?cs var:item.total ?></string><?cs
-   /each ?></row><row><string>Failures</string><?cs
-   each:item = chart.data ?><string><?cs var:item.failed ?></string><?cs
-   /each ?></row>
- </chart_data>
- 
- <chart_grid_h alpha='5' color='333333' thickness='2'/>
- <legend_rect x='-100' y='-100' width='10' height='10'/>
+ <chart_data><?cs
+  each:row = chart.data ?><row><?cs
+   each:value = row ?><?cs
+    if:name(value) == 0 ?><string><?cs
+     var:value ?></string><?cs
+    else ?><number><?cs
+     var:value ?></number><?cs
+    /if ?><?cs
+   /each ?></row><?cs
+  /each ?></chart_data>
+  
+ <chart_border color="999999" left_thickness="1" bottom_thickness="1"/>
+ <chart_grid_h alpha="5" color="666666" thickness="3"/>
+ <chart_pref line_thickness="2" point_shape="none"/>
+ <series_color>
+  <color>99dd99</color>
+  <color>ff0000</color>
+ </series_color>
+
+ <legend_label layout="vertical" alpha="60"/>
+ <legend_rect x="60" y="50" width="10"/>
 
  <draw>
   <text width="320" height="40" h_align="center" v_align="bottom" size="12" ><?cs
     var:chart.title ?></text>
  </draw>
- 
- <series_color>
-  <color>99dd99</color>
-  <color>ff0000</color>
- </series_color>
 
 </chart>
--- a/bitten/trac_ext/templates/bitten_config.cs
+++ b/bitten/trac_ext/templates/bitten_config.cs
@@ -103,7 +103,8 @@
    <div id="charts"><?cs
     each:chart = config.charts ?>
      <object type="application/x-shockwave-flash" width="320" height="240" data="<?cs
-      var:chrome.href ?>/bitten/charts.swf">
+       var:chrome.href ?>/bitten/charts.swf">
+      <param name="movie" value="<?cs var:chrome.href ?>/bitten/charts.swf" />
       <param name="FlashVars" value="library_path=<?cs
         var:chrome.href ?>/bitten&amp;xml_source=<?cs
         var:chart.href ?><?cs if:config.charts_license ?>&amp;license=<?cs
--- a/bitten/trac_ext/web_ui.py
+++ b/bitten/trac_ext/web_ui.py
@@ -495,7 +495,6 @@
         for summarizer in self.report_summarizers:
             types = summarizer.get_supported_report_types()
             summarizers.update(dict([(type, summarizer) for type in types]))
-        self.log.debug("Report summarizers: %s", summarizers)
 
         store = ReportStore(self.env)
         reports = []
Copyright (C) 2012-2017 Edgewall Software