Author: jure
Date: Tue Mar 12 10:25:30 2013
New Revision: 1455475

URL: http://svn.apache.org/r1455475
Log:
#434, ticket query macro support, patch t434_r1453952_product_ticketquery.diff 
applied (from Olemis)


Added:
    
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/ticket/query.py
Modified:
    
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/dbcursor.py
    
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/env.py
    
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/setup.py
    
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/product-query-link-tests.txt
    
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/product-query2-link-tests.txt
    
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/wiki/formatter.py
    
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/wikisyntax.py

Modified: 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/dbcursor.py
URL: 
http://svn.apache.org/viewvc/incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/dbcursor.py?rev=1455475&r1=1455474&r2=1455475&view=diff
==============================================================================
--- 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/dbcursor.py
 (original)
+++ 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/dbcursor.py
 Tue Mar 12 10:25:30 2013
@@ -65,9 +65,12 @@ def translate_sql(env, sql):
                                                    TRANSLATE_TABLES,
                                                    PRODUCT_COLUMN,
                                                    product_prefix)
-        if log:
-            log.debug('Original SQl: %s', sql)
-    return translator.translate(sql) if (translator is not None) else sql
+    if log:
+        log.debug('Original SQl: %s', sql)
+    realsql = translator.translate(sql) if (translator is not None) else sql
+    if log:
+        log.debug('SQL: %s', realsql)
+    return realsql
 
 class BloodhoundIterableCursor(trac.db.util.IterableCursor):
     __slots__ = trac.db.util.IterableCursor.__slots__ + ['_translator']

Modified: 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/env.py
URL: 
http://svn.apache.org/viewvc/incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/env.py?rev=1455475&r1=1455474&r2=1455475&view=diff
==============================================================================
--- 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/env.py
 (original)
+++ 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/env.py
 Tue Mar 12 10:25:30 2013
@@ -1,4 +1,3 @@
-
 #  Licensed to the Apache Software Foundation (ASF) under one
 #  or more contributor license agreements.  See the NOTICE file
 #  distributed with this work for additional information
@@ -805,24 +804,36 @@ class ProductEnvironment(Component, Comp
     # Multi-product API extensions
 
     @classmethod
-    def lookup_env(cls, env, prefix=None):
-        """Instantiate environment according to product prefix
+    def lookup_env(cls, env, prefix=None, name=None):
+        """Instantiate environment according to product prefix or name
 
-        @throws LookupError if no product matches prefix
+        @throws LookupError if no product matches neither prefix nor name 
         """
         if isinstance(env, ProductEnvironment):
-            if not prefix:
-                return env.parent
-            elif env.product.prefix == prefix:
-                return env
-            else:
-                return ProductEnvironment(env.parent, prefix)
+            global_env = env.parent
         else:
-            # `self` bound to global environment
-            if not prefix:
-                return env
+            global_env = env
+
+        if not prefix and not name:
+            return global_env
+        elif isinstance(env, ProductEnvironment) and \
+                env.product.prefix == prefix:
+            return env
+        if prefix:
+            try:
+                return ProductEnvironment(global_env, prefix)
+            except LookupError:
+                if not name:
+                    raise
+        if name:
+            # Lookup product by name
+            products = Product.select(global_env, where={'name' : name})
+            if products:
+                return ProductEnvironment(global_env, products[0])
             else:
-                return ProductEnvironment(env, prefix)
+                raise LookupError("Missing product '%s'" % (name,))
+        else:
+            raise LookupError("Mising product '%s'" % (prefix or name,))
 
     @classmethod
     def resolve_href(cls, to_env, at_env):

Added: 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/ticket/query.py
URL: 
http://svn.apache.org/viewvc/incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/ticket/query.py?rev=1455475&view=auto
==============================================================================
--- 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/ticket/query.py
 (added)
+++ 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/multiproduct/ticket/query.py
 Tue Mar 12 10:25:30 2013
@@ -0,0 +1,291 @@
+
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing,
+#  software distributed under the License is distributed on an
+#  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+#  KIND, either express or implied.  See the License for the
+#  specific language governing permissions and limitations
+#  under the License.
+
+""" Multi product support for ticket queries."""
+
+from __future__ import with_statement
+
+from itertools import groupby
+from math import ceil
+
+from genshi.builder import tag
+
+from trac.db import get_column_names
+from trac.ticket.query import Query, TicketQueryMacro
+from trac.util import Ranges, as_bool
+from trac.util.datefmt import from_utimestamp
+from trac.util.text import shorten_line
+from trac.util.translation import _, tag_
+from trac.web.chrome import Chrome, add_stylesheet
+
+from multiproduct.dbcursor import GLOBAL_PRODUCT
+from multiproduct.env import lookup_product_env, resolve_product_href
+
+class ProductQuery(Query):
+    """Product Overrides for TracQuery.
+    
+    This class allows for writing TracQuery expressions matching resources
+    beyond product boundaries.
+    """
+    
+    def _count(self, sql, args):
+        cnt = self.env.db_direct_query("SELECT COUNT(*) FROM (%s) AS x"
+                                % sql, args)[0][0]
+        # "AS x" is needed for MySQL ("Subqueries in the FROM Clause")
+        self.env.log.debug("Count results in Query: %d", cnt)
+        return cnt
+
+    def get_columns(self):
+        super(ProductQuery, self).get_columns()
+        if not 'product' in self.cols:
+            # make sure 'product' is always present 
+            # (needed for product context, href, permission checks ...)
+            self.cols.insert(0, 'product')
+        return self.cols
+
+    def execute(self, req=None, db=None, cached_ids=None, authname=None,
+                tzinfo=None, href=None, locale=None):
+        """Retrieve the list of matching tickets.
+
+        :since 1.0: the `db` parameter is no longer needed and will be removed
+        in version 1.1.1
+        """
+        if req is not None:
+            href = req.href
+        with self.env.db_direct_query as db:
+            cursor = db.cursor()
+
+            self.num_items = 0
+            sql, args = self.get_sql(req, cached_ids, authname, tzinfo, locale)
+            self.num_items = self._count(sql, args)
+
+            if self.num_items <= self.max:
+                self.has_more_pages = False
+
+            if self.has_more_pages:
+                max = self.max
+                if self.group:
+                    max += 1
+                sql = sql + " LIMIT %d OFFSET %d" % (max, self.offset)
+                if (self.page > int(ceil(float(self.num_items) / self.max)) and
+                    self.num_items != 0):
+                    raise TracError(_("Page %(page)s is beyond the number of "
+                                      "pages in the query", page=self.page))
+
+            # self.env.log.debug("SQL: " + sql % tuple([repr(a) for a in 
args]))
+            cursor.execute(sql, args)
+            columns = get_column_names(cursor)
+            fields = []
+            for column in columns:
+                fields += [f for f in self.fields if f['name'] == column] or \
+                          [None]
+            results = []
+
+            column_indices = range(len(columns))
+            for row in cursor:
+                result = {}
+                for i in column_indices:
+                    name, field, val = columns[i], fields[i], row[i]
+                    if name == 'reporter':
+                        val = val or 'anonymous'
+                    elif name == 'id':
+                        val = int(val)
+                        if href is not None:
+                            result['href'] = href.ticket(val)
+                    elif name in self.time_fields:
+                        val = from_utimestamp(val)
+                    elif field and field['type'] == 'checkbox':
+                        try:
+                            val = bool(int(val))
+                        except (TypeError, ValueError):
+                            val = False
+                    elif val is None:
+                        val = ''
+                    result[name] = val
+                results.append(result)
+            cursor.close()
+            return results
+
+class ProductTicketQueryMacro(TicketQueryMacro):
+    """TracQuery macro retrieving results across product boundaries. 
+    """
+    def expand_macro(self, formatter, name, content):
+        req = formatter.req
+        query_string, kwargs, format = self.parse_args(content)
+        if query_string:
+            query_string += '&'
+        query_string += '&'.join('%s=%s' % item
+                                 for item in kwargs.iteritems())
+        query = ProductQuery.from_string(self.env, query_string)
+
+        if format == 'count':
+            cnt = query.count(req)
+            return tag.span(cnt, title='%d tickets for which %s' %
+                            (cnt, query_string), class_='query_count')
+
+        tickets = query.execute(req)
+
+        if format == 'table':
+            data = query.template_data(formatter.context, tickets,
+                                       req=formatter.context.req)
+
+            add_stylesheet(req, 'common/css/report.css')
+
+            return Chrome(self.env).render_template(
+                req, 'query_results.html', data, None, fragment=True)
+
+        if format == 'progress':
+            from trac.ticket.roadmap import (RoadmapModule,
+                                             apply_ticket_permissions,
+                                             get_ticket_stats,
+                                             grouped_stats_data)
+
+            add_stylesheet(req, 'common/css/roadmap.css')
+
+            def query_href(extra_args, group_value = None):
+                q = Query.from_string(self.env, query_string)
+                if q.group:
+                    extra_args[q.group] = group_value
+                    q.group = None
+                for constraint in q.constraints:
+                    constraint.update(extra_args)
+                if not q.constraints:
+                    q.constraints.append(extra_args)
+                return q.get_href(formatter.context)
+            chrome = Chrome(self.env)
+            tickets = apply_ticket_permissions(self.env, req, tickets)
+            stats_provider = RoadmapModule(self.env).stats_provider
+            by = query.group
+            if not by:
+                stat = get_ticket_stats(stats_provider, tickets)
+                data = {
+                    'stats': stat,
+                    'stats_href': query_href(stat.qry_args),
+                    'interval_hrefs': [query_href(interval['qry_args'])
+                                       for interval in stat.intervals],
+                    'legend': True,
+                }
+                return tag.div(
+                    chrome.render_template(req, 'progress_bar.html', data,
+                                           None, fragment=True),
+                    class_='trac-progress')
+
+            def per_group_stats_data(gstat, group_name):
+                return {
+                    'stats': gstat,
+                    'stats_href': query_href(gstat.qry_args,  group_name),
+                    'interval_hrefs': [query_href(interval['qry_args'],
+                                                  group_name)
+                                       for interval in gstat.intervals],
+                    'percent': '%d / %d' % (gstat.done_count,
+                                            gstat.count),
+                    'legend': False,
+                }
+
+            groups = grouped_stats_data(self.env, stats_provider, tickets, by,
+                                        per_group_stats_data)
+            data = {
+                'groups': groups, 'grouped_by': by,
+                'summary': _("Ticket completion status for each %(group)s",
+                             group=by),
+            }
+            return tag.div(
+                chrome.render_template(req, 'progress_bar_grouped.html', data,
+                                       None, fragment=True),
+                class_='trac-groupprogress')
+
+        # Formats above had their own permission checks, here we need to
+        # do it explicitly:
+
+        tickets = [t for t in tickets
+                   if 'TICKET_VIEW' in req.perm('ticket', t['id'])]
+
+        if not tickets:
+            return tag.span(_("No results"), class_='query_no_results')
+
+        # Cache resolved href targets
+        hrefcache = {}
+
+        def ticket_anchor(ticket):
+            try:
+                pvalue = ticket.get('product') or GLOBAL_PRODUCT
+                envhref = hrefcache[pvalue]
+            except KeyError:
+                try:
+                    env = lookup_product_env(self.env, prefix= pvalue,
+                                             name=pvalue)
+                except LookupError:
+                    return tag.a('#%s' % ticket['id'], 
+                                 class_='missing product')
+                hrefcache[pvalue] = envhref = resolve_product_href(
+                         to_env=env, at_env=self.env)
+            return tag.a('#%s' % ticket['id'],
+                         class_=ticket['status'],
+                         href=envhref.ticket(int(ticket['id'])),
+                         title=shorten_line(ticket['summary']))
+
+        def ticket_groups():
+            groups = []
+            for v, g in groupby(tickets, lambda t: t[query.group]):
+                q = Query.from_string(self.env, query_string)
+                # produce the hint for the group
+                q.group = q.groupdesc = None
+                order = q.order
+                q.order = None
+                title = _("%(groupvalue)s %(groupname)s tickets matching "
+                          "%(query)s", groupvalue=v, groupname=query.group,
+                          query=q.to_string())
+                # produce the href for the query corresponding to the group
+                for constraint in q.constraints:
+                    constraint[str(query.group)] = v
+                q.order = order
+                href = q.get_href(formatter.context)
+                groups.append((v, [t for t in g], href, title))
+            return groups
+
+        if format == 'compact':
+            if query.group:
+                groups = [(v, ' ',
+                           tag.a('#%s' % u',\u200b'.join(str(t['id'])
+                                                         for t in g),
+                                 href=href, class_='query', title=title))
+                          for v, g, href, title in ticket_groups()]
+                return tag(groups[0], [(', ', g) for g in groups[1:]])
+            else:
+                alist = [ticket_anchor(ticket) for ticket in tickets]
+                return tag.span(alist[0], *[(', ', a) for a in alist[1:]])
+        else:
+            if query.group:
+                return tag.div(
+                    [(tag.p(tag_('%(groupvalue)s %(groupname)s tickets:',
+                                 groupvalue=tag.a(v, href=href, class_='query',
+                                                  title=title),
+                                 groupname=query.group)),
+                      tag.dl([(tag.dt(ticket_anchor(t)),
+                               tag.dd(t['summary'])) for t in g],
+                             class_='wiki compact'))
+                     for v, g, href, title in ticket_groups()])
+            else:
+                return tag.div(tag.dl([(tag.dt(ticket_anchor(ticket)),
+                                        tag.dd(ticket['summary']))
+                                       for ticket in tickets],
+                                      class_='wiki compact'))
+
+    def is_inline(self, content):
+        query_string, kwargs, format = self.parse_args(content)
+        return format in ('count', 'compact')

Modified: 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/setup.py
URL: 
http://svn.apache.org/viewvc/incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/setup.py?rev=1455475&r1=1455474&r2=1455475&view=diff
==============================================================================
--- 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/setup.py
 (original)
+++ 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/setup.py
 Tue Mar 12 10:25:30 2013
@@ -31,6 +31,7 @@ setup(
     entry_points = {'trac.plugins': [
             'multiproduct.model = multiproduct.model',
             'multiproduct.product_admin = multiproduct.product_admin',
+            'multiproduct.ticket.query = multiproduct.ticket.query',
             'multiproduct.ticket.web_ui = multiproduct.ticket.web_ui',
             'multiproduct.web_ui = multiproduct.web_ui',
         ],},

Modified: 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/product-query-link-tests.txt
URL: 
http://svn.apache.org/viewvc/incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/product-query-link-tests.txt?rev=1455475&r1=1455474&r2=1455475&view=diff
==============================================================================
--- 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/product-query-link-tests.txt
 (original)
+++ 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/product-query-link-tests.txt
 Tue Mar 12 10:25:30 2013
@@ -49,45 +49,75 @@
 <a class="query" 
href="%(path_prefix)s/query?summary=r%%C3%%A9sum%%C3%%A9&amp;order=priority">%(link_prefix)squery:summary=résumé</a>
 </p>
 ------------------------------
-============================== %(tc_title_prefix)s - TicketQuery macro: no 
results, list form
-Reopened tickets: [[TicketQuery(status=reopened)]]
+============================== %(tc_title_prefix)s - ProductTicketQuery macro: 
no results, list form
+Reopened tickets: [[ProductTicketQuery(status=reopened)]]
+
+Reopened tickets: [[ProductTicketQuery(status=reopened, 
product=%(setup_product_name)s)]]
 ------------------------------
 <p>
 Reopened tickets: <span class="query_no_results">No results</span>
 </p>
+<p>
+Reopened tickets: <span class="query_no_results">No results</span>
+</p>
 ------------------------------
-============================== %(tc_title_prefix)s - TicketQuery macro: no 
results, count 0
-Reopened tickets: [[TicketQuery(status=reopened, format=count)]]
+============================== %(tc_title_prefix)s - ProductTicketQuery macro: 
no results, count 0
+Reopened tickets: [[ProductTicketQuery(status=reopened, format=count)]]
+
+Reopened tickets: [[ProductTicketQuery(status=reopened, format=count, 
product=%(setup_product_name)s)]]
 ------------------------------
 <p>
 Reopened tickets: <span class="query_count" title="0 tickets for which 
status=reopened&amp;max=0&amp;order=id">0</span>
 </p>
+<p>
+Reopened tickets: <span class="query_count" title="0 tickets for which 
status=reopened&amp;product=%(setup_product_name)s&amp;max=0&amp;order=id">0</span>
+</p>
 ------------------------------
-============================== %(tc_title_prefix)s - TicketQuery macro: no 
results, compact form
-Reopened tickets: [[TicketQuery(status=reopened, format=compact)]]
+============================== %(tc_title_prefix)s - ProductTicketQuery macro: 
no results, compact form
+Reopened tickets: [[ProductTicketQuery(status=reopened, format=compact)]]
+
+Reopened tickets: [[ProductTicketQuery(status=reopened, format=compact, 
product=%(setup_product_name)s)]]
 ------------------------------
 <p>
 Reopened tickets: <span class="query_no_results">No results</span>
 </p>
+<p>
+Reopened tickets: <span class="query_no_results">No results</span>
+</p>
 ------------------------------
-============================== %(tc_title_prefix)s - TicketQuery macro: one 
result, list form
-New tickets: [[TicketQuery(status=new)]]
+============================== %(tc_title_prefix)s - ProductTicketQuery macro: 
one result, list form
+New tickets: [[ProductTicketQuery(status=new)]]
+
+New tickets: [[ProductTicketQuery(status=new, product=%(setup_product_name)s)]]
 ------------------------------
 <p>
 New tickets: </p><div><dl class="wiki compact"><dt><a class="new" 
href="%(path_prefix)s/ticket/1" title="This is the summary">#1</a></dt><dd>This 
is the summary</dd></dl></div><p>
 </p>
+<p>
+New tickets: </p><div><dl class="wiki compact"><dt><a class="new" 
href="%(path_prefix)s/ticket/1" title="This is the summary">#1</a></dt><dd>This 
is the summary</dd></dl></div><p>
+</p>
 ------------------------------
-============================== %(tc_title_prefix)s - TicketQuery macro: one 
result, count 1
-New tickets: [[TicketQuery(status=new, format=count)]]
+============================== %(tc_title_prefix)s - ProductTicketQuery macro: 
one result, count 1
+New tickets: [[ProductTicketQuery(status=new, format=count)]]
+
+New tickets: [[ProductTicketQuery(status=new, format=count, 
product=%(setup_product_name)s)]]
 ------------------------------
 <p>
 New tickets: <span class="query_count" title="1 tickets for which 
status=new&amp;max=0&amp;order=id">1</span>
 </p>
+<p>
+New tickets: <span class="query_count" title="1 tickets for which 
status=new&amp;product=%(setup_product_name)s&amp;max=0&amp;order=id">1</span>
+</p>
 ------------------------------
-============================== %(tc_title_prefix)s - TicketQuery macro: one 
result, compact form
-New tickets: [[TicketQuery(status=new, format=compact)]]
+============================== %(tc_title_prefix)s - ProductTicketQuery macro: 
one result, compact form
+New tickets: [[ProductTicketQuery(status=new, format=compact)]]
+
+New tickets: [[ProductTicketQuery(status=new, format=compact, 
product=%(setup_product_name)s)]]
 ------------------------------
 <p>
 New tickets: <span><a class="new" href="%(path_prefix)s/ticket/1" title="This 
is the summary">#1</a></span>
 </p>
+<p>
+New tickets: <span><a class="new" href="%(path_prefix)s/ticket/1" title="This 
is the summary">#1</a></span>
+</p>
 ------------------------------

Modified: 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/product-query2-link-tests.txt
URL: 
http://svn.apache.org/viewvc/incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/product-query2-link-tests.txt?rev=1455475&r1=1455474&r2=1455475&view=diff
==============================================================================
--- 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/product-query2-link-tests.txt
 (original)
+++ 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/product-query2-link-tests.txt
 Tue Mar 12 10:25:30 2013
@@ -2,22 +2,22 @@
 
         Product query links - part 2
 
-============================== %(tc_title_prefix)s - TicketQuery macro: two 
results, list form
-New tickets: [[TicketQuery(status=new, order=reporter)]]
+============================== %(tc_title_prefix)s - ProductTicketQuery macro: 
two results, list form
+New tickets: [[ProductTicketQuery(status=new, order=reporter)]]
 ------------------------------
 <p>
 New tickets: </p><div><dl class="wiki compact"><dt><a class="new" 
href="%(path_prefix)s/ticket/2" title="This is another 
summary">#2</a></dt><dd>This is another summary</dd><dt><a class="new" 
href="%(path_prefix)s/ticket/1" title="This is the summary">#1</a></dt><dd>This 
is the summary</dd></dl></div><p>
 </p>
 ------------------------------
-============================== %(tc_title_prefix)s - TicketQuery macro: two 
results, count 2
-New tickets: [[TicketQuery(status=new, order=reporter, format=count)]]
+============================== %(tc_title_prefix)s - ProductTicketQuery macro: 
two results, count 2
+New tickets: [[ProductTicketQuery(status=new, order=reporter, format=count)]]
 ------------------------------
 <p>
 New tickets: <span class="query_count" title="2 tickets for which 
status=new&amp;max=0&amp;order=reporter">2</span>
 </p>
 ------------------------------
-============================== %(tc_title_prefix)s - TicketQuery macro: two 
results, compact form
-New tickets: [[TicketQuery(status=new, order=reporter, format=compact)]]
+============================== %(tc_title_prefix)s - ProductTicketQuery macro: 
two results, compact form
+New tickets: [[ProductTicketQuery(status=new, order=reporter, format=compact)]]
 ------------------------------
 <p>
 New tickets: <span><a class="new" href="%(path_prefix)s/ticket/2" title="This 
is another summary">#2</a>, <a class="new" href="%(path_prefix)s/ticket/1" 
title="This is the summary">#1</a></span>

Modified: 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/wiki/formatter.py
URL: 
http://svn.apache.org/viewvc/incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/wiki/formatter.py?rev=1455475&r1=1455474&r2=1455475&view=diff
==============================================================================
--- 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/wiki/formatter.py
 (original)
+++ 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/wiki/formatter.py
 Tue Mar 12 10:25:30 2013
@@ -84,6 +84,8 @@ class ProductWikiTestCase(formatter.Wiki
                     and (self.env is self.global_env or 
                          prefix != self.env.product.prefix):
                 self._env = ProductEnvironment(self.global_env, prefix)
+            # Enable multi-product components
+            self._env.config.set('components', 'multiproduct.*', 'enabled')
 
     def tearDown(self):
         self.global_env.reset_db()

Modified: 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/wikisyntax.py
URL: 
http://svn.apache.org/viewvc/incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/wikisyntax.py?rev=1455475&r1=1455474&r2=1455475&view=diff
==============================================================================
--- 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/wikisyntax.py
 (original)
+++ 
incubator/bloodhound/branches/bep_0003_multiproduct/bloodhound_multiproduct/tests/wikisyntax.py
 Tue Mar 12 10:25:30 2013
@@ -37,6 +37,7 @@ from trac.util.text import to_unicode
 
 from multiproduct.api import PRODUCT_SYNTAX_DELIMITER
 from multiproduct.env import ProductEnvironment
+from multiproduct.ticket.query import ProductTicketQueryMacro
 from tests.env import MultiproductTestCase
 from tests.wiki import formatter
 


Reply via email to