svn commit: r1574841 - in /bloodhound/trunk/bloodhound_relations/bhrelations/tests: api.py base.py notification.py search.py web_ui.py
Author: astaric Date: Thu Mar 6 11:12:21 2014 New Revision: 1574841 URL: http://svn.apache.org/r1574841 Log: Refactor bhrelations tests. Modified: bloodhound/trunk/bloodhound_relations/bhrelations/tests/api.py bloodhound/trunk/bloodhound_relations/bhrelations/tests/base.py bloodhound/trunk/bloodhound_relations/bhrelations/tests/notification.py bloodhound/trunk/bloodhound_relations/bhrelations/tests/search.py bloodhound/trunk/bloodhound_relations/bhrelations/tests/web_ui.py Modified: bloodhound/trunk/bloodhound_relations/bhrelations/tests/api.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_relations/bhrelations/tests/api.py?rev=1574841r1=1574840r2=1574841view=diff == --- bloodhound/trunk/bloodhound_relations/bhrelations/tests/api.py (original) +++ bloodhound/trunk/bloodhound_relations/bhrelations/tests/api.py Thu Mar 6 11:12:21 2014 @@ -18,10 +18,13 @@ # under the License. from datetime import datetime import unittest + from bhrelations.api import TicketRelationsSpecifics from bhrelations.tests.mocks import TestRelationChangingListener from bhrelations.validation import ValidationError -from bhrelations.tests.base import BaseRelationsTestCase +from bhrelations.tests.base import BaseRelationsTestCase, PARENT, CHILD, \ +DEPENDS_ON, DEPENDENCY_OF, BLOCKS, BLOCKED_BY, REFERS_TO, DUPLICATE_OF, \ +MULTIPRODUCT_REL from multiproduct.env import ProductEnvironment from trac.ticket.model import Ticket from trac.core import TracError @@ -32,146 +35,124 @@ class ApiTestCase(BaseRelationsTestCase) def test_can_add_two_ways_relations(self): #arrange ticket = self._insert_and_load_ticket(A1) -dependent = self._insert_and_load_ticket(A2) +ticket2 = self._insert_and_load_ticket(A2) #act -relations_system = self.relations_system -relations_system.add( -ticket, dependent, dependent) -#assert -relations = relations_system.get_relations(ticket) -self.assertEqual(dependent, relations[0][type]) -self.assertEqual(unicode(dependent.id), relations[0][destination].id) +self.add_relation(ticket, DEPENDENCY_OF, ticket2) +#assert +relations = self.get_relations(ticket) +self.assertEqual(DEPENDENCY_OF, relations[0][type]) +self.assertEqual(unicode(ticket2.id), relations[0][destination].id) -relations = relations_system.get_relations(dependent) -self.assertEqual(dependson, relations[0][type]) +relations = self.get_relations(ticket2) +self.assertEqual(DEPENDS_ON, relations[0][type]) self.assertEqual(unicode(ticket.id), relations[0][destination].id) def test_can_add_single_way_relations(self): #arrange ticket = self._insert_and_load_ticket(A1) -referred = self._insert_and_load_ticket(A2) +ticket2 = self._insert_and_load_ticket(A2) #act -relations_system = self.relations_system -relations_system.add(ticket, referred, refersto) +self.add_relation(ticket, REFERS_TO, ticket2) #assert -relations = relations_system.get_relations(ticket) -self.assertEqual(refersto, relations[0][type]) -self.assertEqual(unicode(referred.id), relations[0][destination].id) +relations = self.get_relations(ticket) +self.assertEqual(1, len(relations)) +self.assertEqual(REFERS_TO, relations[0][type]) +self.assertEqual(unicode(ticket2.id), relations[0][destination].id) -relations = relations_system.get_relations(referred) -self.assertEqual(0, len(relations)) +self.assertEqual(0, len(self.get_relations(ticket2))) def test_can_add_multiple_relations(self): #arrange ticket = self._insert_and_load_ticket(A1) -dependent1 = self._insert_and_load_ticket(A2) -dependent2 = self._insert_and_load_ticket(A3) +ticket2 = self._insert_and_load_ticket(A2) +ticket3 = self._insert_and_load_ticket(A3) #act -relations_system = self.relations_system -relations_system.add( -ticket, dependent1, dependent) -relations_system.add( -ticket, dependent2, dependent) +self.add_relation(ticket, DEPENDS_ON, ticket2) +self.add_relation(ticket, DEPENDS_ON, ticket3) #assert -relations = relations_system.get_relations(ticket) -self.assertEqual(2, len(relations)) +self.assertEqual(2, len(self.get_relations(ticket))) +self.assertEqual(1, len(self.get_relations(ticket2))) +self.assertEqual(1, len(self.get_relations(ticket3))) def test_will_not_create_more_than_one_identical_relations(self): #arrange ticket = self._insert_and_load_ticket(A1) -dependent1 = self._insert_and_load_ticket(A2) +ticket2 = self
svn commit: r1573485 - /bloodhound/trunk/bloodhound_search/bhsearch/api.py
Author: astaric Date: Mon Mar 3 09:25:53 2014 New Revision: 1573485 URL: http://svn.apache.org/r1573485 Log: Use get to access product in search documents. Refs: #773 Modified: bloodhound/trunk/bloodhound_search/bhsearch/api.py Modified: bloodhound/trunk/bloodhound_search/bhsearch/api.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_search/bhsearch/api.py?rev=1573485r1=1573484r2=1573485view=diff == --- bloodhound/trunk/bloodhound_search/bhsearch/api.py (original) +++ bloodhound/trunk/bloodhound_search/bhsearch/api.py Mon Mar 3 09:25:53 2014 @@ -347,7 +347,7 @@ class BloodhoundSearchApi(Component): for doc in docs: self.log.debug( Indexing document %s:%s/%s % ( -doc['product'], +doc.get('product'), doc['type'], doc['id'], )
svn commit: r1573264 - in /bloodhound/trunk/bloodhound_search/bhsearch: search_resources/milestone_search.py search_resources/ticket_search.py search_resources/wiki_search.py security.py web_ui.py
Author: astaric Date: Sun Mar 2 06:52:21 2014 New Revision: 1573264 URL: http://svn.apache.org/r1573264 Log: Use get to access product in search documents. Refs: #773 Modified: bloodhound/trunk/bloodhound_search/bhsearch/search_resources/milestone_search.py bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py bloodhound/trunk/bloodhound_search/bhsearch/search_resources/wiki_search.py bloodhound/trunk/bloodhound_search/bhsearch/security.py bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py Modified: bloodhound/trunk/bloodhound_search/bhsearch/search_resources/milestone_search.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/milestone_search.py?rev=1573264r1=1573263r2=1573264view=diff == --- bloodhound/trunk/bloodhound_search/bhsearch/search_resources/milestone_search.py (original) +++ bloodhound/trunk/bloodhound_search/bhsearch/search_resources/milestone_search.py Sun Mar 2 06:52:21 2014 @@ -171,4 +171,8 @@ class MilestoneSearchParticipant(BaseSea #TODO: add better milestone rendering name = res['hilited_name'] or res['name'] -return tag(u'[', res['product'], u'] Milestone:', name) +product = res.get('product') +if product: +return tag(u'[', product, u'] Milestone:', name) +else: +return tag(u'Milestone:', name) Modified: bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py?rev=1573264r1=1573263r2=1573264view=diff == --- bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py (original) +++ bloodhound/trunk/bloodhound_search/bhsearch/search_resources/ticket_search.py Sun Mar 2 06:52:21 2014 @@ -248,6 +248,10 @@ class TicketSearchParticipant(BaseSearch stat = res[TicketFields.STATUS] id = res['hilited_id'] or res['id'] -id = tag.span('#', id, class_=css_class) +id = tag.span(u'#', id, class_=css_class) summary = res['hilited_summary'] or res['summary'] -return tag('[', res['product'], '] ', id, ': ', summary, ' (%s)' % stat) +product = res.get('product') +if product: +return tag(u'[', product, u'] ', id, u': ', summary, u' (%s)' % stat) +else: +return tag(id, u': ', summary, u' (%s)' % stat) Modified: bloodhound/trunk/bloodhound_search/bhsearch/search_resources/wiki_search.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_search/bhsearch/search_resources/wiki_search.py?rev=1573264r1=1573263r2=1573264view=diff == --- bloodhound/trunk/bloodhound_search/bhsearch/search_resources/wiki_search.py (original) +++ bloodhound/trunk/bloodhound_search/bhsearch/search_resources/wiki_search.py Sun Mar 2 06:52:21 2014 @@ -161,4 +161,8 @@ class WikiSearchParticipant(BaseSearchPa def format_search_results(self, res): title = res['hilited_name'] or res['name'] -return tag('[', res['product'], '] ', title) +product = res.get('product') +if product: +return tag(u'[', product, u'] ', title) +else: +return tag(title) Modified: bloodhound/trunk/bloodhound_search/bhsearch/security.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_search/bhsearch/security.py?rev=1573264r1=1573263r2=1573264view=diff == --- bloodhound/trunk/bloodhound_search/bhsearch/security.py (original) +++ bloodhound/trunk/bloodhound_search/bhsearch/security.py Sun Mar 2 06:52:21 2014 @@ -42,7 +42,7 @@ class SecurityPreprocessor(Component): self._required_permissions[doc_type] = permission def check_permission(self, doc, context): -product, doctype, id = doc['product'], doc['type'], doc['id'] +product, doctype, id = doc.get('product'), doc['type'], doc['id'] username = context.req.authname env = self.env if product: Modified: bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py?rev=1573264r1=1573263r2=1573264view=diff == --- bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py (original) +++ bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py Sun Mar 2 06:52:21 2014 @@ -697,7 +697,7 @@ class RequestContext(object): def _process_doc(self, doc): ui_doc = dict(doc) -if doc['product']: +if doc.get('product'): env
svn commit: r1564692 - /bloodhound/trunk/bloodhound_relations/bhrelations/web_ui.py
Author: astaric Date: Wed Feb 5 09:55:33 2014 New Revision: 1564692 URL: http://svn.apache.org/r1564692 Log: Do not send notification if relation could not be created. Modified: bloodhound/trunk/bloodhound_relations/bhrelations/web_ui.py Modified: bloodhound/trunk/bloodhound_relations/bhrelations/web_ui.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_relations/bhrelations/web_ui.py?rev=1564692r1=1564691r2=1564692view=diff == --- bloodhound/trunk/bloodhound_relations/bhrelations/web_ui.py (original) +++ bloodhound/trunk/bloodhound_relations/bhrelations/web_ui.py Wed Feb 5 09:55:33 2014 @@ -104,18 +104,18 @@ class RelationManagementModule(Component data['error'] = _('Unknown relation type.') except ValidationError as ex: data['error'] = ex.message - -# Notify -try: -self.notify_relation_changed(dbrel) -except Exception, e: -self.log.error(Failure sending notification on - creation of relation: %s, - exception_to_unicode(e)) -add_warning(req, _(The relation has been added, but an - error occurred while sending - notifications: %(message)s, - message=to_unicode(e))) +else: +# Notify +try: +self.notify_relation_changed(dbrel) +except Exception, e: +self.log.error(Failure sending notification on + creation of relation: %s, + exception_to_unicode(e)) +add_warning(req, _(The relation has been added, but an + error occurred while sending + notifications: %(message)s, + message=to_unicode(e))) if 'error' in data: data['relation'] = relation
svn commit: r1559082 - /bloodhound/trunk/bloodhound_search/bhsearch/tests/security.py
Author: astaric Date: Fri Jan 17 11:55:37 2014 New Revision: 1559082 URL: http://svn.apache.org/r1559082 Log: Handle a case where document has no field 'product'. (Whoosh 2.5 compatibility) With Whoosh 2.4 all documents have a value in field 'product' (our workaround to keep faceting from braking). In Whoosh 2.5 this is no longer the case so this test failed. Refs: #741 Modified: bloodhound/trunk/bloodhound_search/bhsearch/tests/security.py Modified: bloodhound/trunk/bloodhound_search/bhsearch/tests/security.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_search/bhsearch/tests/security.py?rev=1559082r1=1559081r2=1559082view=diff == --- bloodhound/trunk/bloodhound_search/bhsearch/tests/security.py (original) +++ bloodhound/trunk/bloodhound_search/bhsearch/tests/security.py Fri Jan 17 11:55:37 2014 @@ -252,7 +252,7 @@ class MultiProductSecurityTestCase(Secur self._add_permission('x', 'TRAC_ADMIN') security.SecurityPreprocessor.check_permission = \ -lambda x, doc, z: doc['product'] == 'p1' +lambda x, doc, z: doc.get('product', None) == 'p1' results = self.search_api.query( *,
svn commit: r1526812 - /bloodhound/trunk/bloodhound_multiproduct/multiproduct/model.py
Author: astaric Date: Fri Sep 27 07:36:28 2013 New Revision: 1526812 URL: http://svn.apache.org/r1526812 Log: Fetch product tickets using product environment. Product.get_tickets uses direct query that sees tickets from all products, but Ticket(id) does not, so it needs to be instantiated with the right env. Modified: bloodhound/trunk/bloodhound_multiproduct/multiproduct/model.py Modified: bloodhound/trunk/bloodhound_multiproduct/multiproduct/model.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/multiproduct/model.py?rev=1526812r1=1526811r2=1526812view=diff == --- bloodhound/trunk/bloodhound_multiproduct/multiproduct/model.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/multiproduct/model.py Fri Sep 27 07:36:28 2013 @@ -74,8 +74,12 @@ class Product(ModelBase): now = datetime.now(utc) comment = 'Product %s renamed to %s' % (old_name, new_name) if old_name != new_name: +env = self._env.parent or self._env +if self._data['prefix']: +from multiproduct.env import ProductEnvironment +env = ProductEnvironment(env, self._data['prefix']) for t in Product.get_tickets(self._env, self._data['prefix']): -ticket = Ticket(self._env, t['id'], db) +ticket = Ticket(env, t['id'], db) ticket.save_changes(author, comment, now) @classmethod
svn commit: r1526822 - in /bloodhound/trunk: bloodhound_dashboard/bhdashboard/widgets/templates/widget_relations.html bloodhound_relations/bhrelations/templates/relations_manage.html
Author: astaric Date: Fri Sep 27 07:59:57 2013 New Revision: 1526822 URL: http://svn.apache.org/r1526822 Log: Display relation type in all rows. Fixes #670 Modified: bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/templates/widget_relations.html bloodhound/trunk/bloodhound_relations/bhrelations/templates/relations_manage.html Modified: bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/templates/widget_relations.html URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/templates/widget_relations.html?rev=1526822r1=1526821r2=1526822view=diff == --- bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/templates/widget_relations.html (original) +++ bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/templates/widget_relations.html Fri Sep 27 07:59:57 2013 @@ -33,7 +33,7 @@ tbody py:for=relgroup,items in relations.iteritems() tr py:for=item in items class=relation -td${relgroup if items.index(item) == 0 else None}/td +td$relgroup/td td a href=${href.products(item['destticket'].env.product.prefix)} span class=hidden-phone${item['destticket'].env.product.name} (${item['destticket'].env.product.prefix})/span Modified: bloodhound/trunk/bloodhound_relations/bhrelations/templates/relations_manage.html URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_relations/bhrelations/templates/relations_manage.html?rev=1526822r1=1526821r2=1526822view=diff == --- bloodhound/trunk/bloodhound_relations/bhrelations/templates/relations_manage.html (original) +++ bloodhound/trunk/bloodhound_relations/bhrelations/templates/relations_manage.html Fri Sep 27 07:59:57 2013 @@ -96,7 +96,7 @@ tbody py:for=relgroup,items in relations.iteritems() tr py:for=item in items td class=selinput type=checkbox name=sel value=${item.relation_id} //td - td${relgroup if items.index(item) == 0 else None}/td + td$relgroup/td td a href=${href.products(item['destticket'].env.product.prefix)} span class=hidden-phone${item['destticket'].env.product.name} (${item['destticket'].env.product.prefix})/span
svn commit: r1526159 - in /bloodhound/trunk/bloodhound_relations/bhrelations: api.py tests/api.py
Author: astaric Date: Wed Sep 25 11:29:51 2013 New Revision: 1526159 URL: http://svn.apache.org/r1526159 Log: Support #product-ticket_id syntax when adding relations. Only non standard ways of specifying ticekts from different prouct were supported before. (product_prefix:ticket:ticket_id) Modified: bloodhound/trunk/bloodhound_relations/bhrelations/api.py bloodhound/trunk/bloodhound_relations/bhrelations/tests/api.py Modified: bloodhound/trunk/bloodhound_relations/bhrelations/api.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_relations/bhrelations/api.py?rev=1526159r1=1526158r2=1526159view=diff == --- bloodhound/trunk/bloodhound_relations/bhrelations/api.py (original) +++ bloodhound/trunk/bloodhound_relations/bhrelations/api.py Wed Sep 25 11:29:51 2013 @@ -561,23 +561,31 @@ class TicketRelationsSpecifics(Component def find_ticket(self, ticket_spec): ticket = None -m = re.match(r'#?(?Ptid\d+)', ticket_spec) +m = re.match(r'#?(?:(?Ppid[^-]+)-)?(?Ptid\d+)', ticket_spec) if m: +pid = m.group('pid') tid = m.group('tid') -try: -ticket = Ticket(self.env, tid) -except ResourceNotFound: -# ticket not found in current product, try all other products -for p in Product.select(self.env): -if p.prefix != self.env.product.prefix: -# TODO: check for PRODUCT_VIEW permissions -penv = ProductEnvironment(self.env.parent, p.prefix) -try: -ticket = Ticket(penv, tid) -except ResourceNotFound: -pass -else: -break +if pid: +try: +env = ProductEnvironment(self.env.parent, pid) +ticket = Ticket(env, tid) +except: +pass +else: +try: +ticket = Ticket(self.env, tid) +except ResourceNotFound: +# ticket not found in current product, try all other products +for p in Product.select(self.env): +if p.prefix != self.env.product.prefix: +# TODO: check for PRODUCT_VIEW permissions +penv = ProductEnvironment(self.env.parent, p.prefix) +try: +ticket = Ticket(penv, tid) +except ResourceNotFound: +pass +else: +break # ticket still not found, use fallback for prefix:ticket:id syntax if ticket is None: Modified: bloodhound/trunk/bloodhound_relations/bhrelations/tests/api.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_relations/bhrelations/tests/api.py?rev=1526159r1=1526158r2=1526159view=diff == --- bloodhound/trunk/bloodhound_relations/bhrelations/tests/api.py (original) +++ bloodhound/trunk/bloodhound_relations/bhrelations/tests/api.py Wed Sep 25 11:29:51 2013 @@ -496,6 +496,42 @@ class ApiTestCase(BaseRelationsTestCase) self.relations_system.add(t1, t2, refersto) self.relations_system.add(t2, t1, refersto) +def test_can_find_ticket_by_id_from_same_env(self): + Can find ticket given #id +product2 = tp2 +self._load_product_from_data(self.global_env, product2) +p2_env = ProductEnvironment(self.global_env, product2) +t1 = self._insert_and_load_ticket_with_env(p2_env, T1) +trs = TicketRelationsSpecifics(p2_env) + +ticket = trs.find_ticket(#%d % t1.id) + +self.assertEqual(ticket.id, 1) + +def test_can_find_ticket_by_id_from_different_env(self): + Can find ticket from different env given #id +product2 = tp2 +self._load_product_from_data(self.global_env, product2) +p2_env = ProductEnvironment(self.global_env, product2) +t1 = self._insert_and_load_ticket_with_env(p2_env, T1) +trs = TicketRelationsSpecifics(self.env) + +ticket = trs.find_ticket(#%d % t1.id) + +self.assertEqual(ticket.id, 1) + +def test_can_find_ticket_by_product_and_id(self): + Can find ticket given #prefix-id +product2 = tp2 +self._load_product_from_data(self.global_env, product2) +p2_env = ProductEnvironment(self.global_env, product2) +t1 = self._insert_and_load_ticket_with_env(p2_env, T1) +trs = TicketRelationsSpecifics(self.env) + +ticket = trs.find_ticket(#%s-%d % (product2, t1.id)) + +self.assertEqual(ticket.id, 1) + class
svn commit: r1525106 - /bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py
Author: astaric Date: Fri Sep 20 19:05:34 2013 New Revision: 1525106 URL: http://svn.apache.org/r1525106 Log: Use resolve_href to generate links in search results. resolve_href returns abs_href when environments are on different subdomains. Refs #663 Modified: bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py Modified: bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py?rev=1525106r1=1525105r2=1525106view=diff == --- bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py (original) +++ bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py Fri Sep 20 19:05:34 2013 @@ -694,7 +694,8 @@ class RequestContext(object): def _process_doc(self, doc): ui_doc = dict(doc) if doc['product']: -product_href = ProductEnvironment(self.env, doc['product']).href +env = ProductEnvironment(self.env, doc['product']) +product_href = ProductEnvironment.resolve_href(env, self.env) # pylint: disable=too-many-function-args ui_doc[href] = product_href(doc['type'], doc['id']) else:
svn commit: r1517459 - /bloodhound/trunk/bloodhound_relations/bhrelations/tests/notification.py
Author: astaric Date: Mon Aug 26 08:33:55 2013 New Revision: 1517459 URL: http://svn.apache.org/r1517459 Log: Fixed notification tests. Notifications are no longer created in api, so they have to be constructed manually in tests. Refs: #644 Modified: bloodhound/trunk/bloodhound_relations/bhrelations/tests/notification.py Modified: bloodhound/trunk/bloodhound_relations/bhrelations/tests/notification.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_relations/bhrelations/tests/notification.py?rev=1517459r1=1517458r2=1517459view=diff == --- bloodhound/trunk/bloodhound_relations/bhrelations/tests/notification.py (original) +++ bloodhound/trunk/bloodhound_relations/bhrelations/tests/notification.py Mon Aug 26 08:33:55 2013 @@ -69,8 +69,7 @@ class NotificationTestCase(BaseRelations relation = self.relations_system.add( ticket, ticket2, dependent) -rn = RelationNotifyEmail(self.env) -rn.notify(relation) +self.notifier.notify(relation) recipients = self.smtpd.get_recipients() # checks there is no duplicate in the recipient list @@ -95,7 +94,8 @@ class NotificationTestCase(BaseRelations ticket = self._insert_and_load_ticket('Foo', reporter='anonymous') ticket2 = self._insert_and_load_ticket('Bar', reporter='anonymous') -self.relations_system.add(ticket, ticket2, dependent) +relation = self.relations_system.add(ticket, ticket2, dependent) +self.notifier.notify(relation) sender = self.smtpd.get_sender() recipients = self.smtpd.get_recipients() @@ -110,6 +110,7 @@ class NotificationTestCase(BaseRelations ticket2 = self._insert_and_load_ticket('Bar', reporter='anonymous') relation = self.relations_system.add(ticket, ticket2, dependent) +self.notifier.notify(relation) relations = self.env.db_direct_query( SELECT * FROM bloodhound_relations)
svn commit: r1516129 - /bloodhound/branches/bep_0010_ticket_numbering/bloodhound_theme/bhtheme/theme.py
Author: astaric Date: Wed Aug 21 10:13:00 2013 New Revision: 1516129 URL: http://svn.apache.org/r1516129 Log: QCT: Create product tickets in product env. If ticket is created in global environment, but with product field specified, returned ticket id is invalid. When product specific ticket id is queried from the database, the query returns no results if it is executed in environment that does not contain the ticket. Modified: bloodhound/branches/bep_0010_ticket_numbering/bloodhound_theme/bhtheme/theme.py Modified: bloodhound/branches/bep_0010_ticket_numbering/bloodhound_theme/bhtheme/theme.py URL: http://svn.apache.org/viewvc/bloodhound/branches/bep_0010_ticket_numbering/bloodhound_theme/bhtheme/theme.py?rev=1516129r1=1516128r2=1516129view=diff == --- bloodhound/branches/bep_0010_ticket_numbering/bloodhound_theme/bhtheme/theme.py (original) +++ bloodhound/branches/bep_0010_ticket_numbering/bloodhound_theme/bhtheme/theme.py Wed Aug 21 10:13:00 2013 @@ -551,7 +551,16 @@ class QuickCreateTicketDialog(Component) PS: Borrowed from XmlRpcPlugin. -t = Ticket(self.env) +if 'product' in attributes: +if attributes['product']: +env = ProductEnvironment(self.env, attributes['product']) +else: +# Global product +env = self.env.parent or self.env +else: +env = self.env + +t = Ticket(env) t['summary'] = summary t['description'] = description t['reporter'] = req.authname @@ -563,7 +572,7 @@ class QuickCreateTicketDialog(Component) if notify: try: -tn = TicketNotifyEmail(self.env) +tn = TicketNotifyEmail(env) tn.notify(t, newticket=True) except Exception, e: self.log.exception(Failure sending notification on creation
svn commit: r1505980 - /bloodhound/trunk/bloodhound_theme/bhtheme/theme.py
Author: astaric Date: Tue Jul 23 11:25:13 2013 New Revision: 1505980 URL: http://svn.apache.org/r1505980 Log: Reverted r1505666. It causes additional problems when default_product is set in config. Original issue will need to be solved by patching sql translator. Refs #601 Modified: bloodhound/trunk/bloodhound_theme/bhtheme/theme.py Modified: bloodhound/trunk/bloodhound_theme/bhtheme/theme.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_theme/bhtheme/theme.py?rev=1505980r1=1505979r2=1505980view=diff == --- bloodhound/trunk/bloodhound_theme/bhtheme/theme.py (original) +++ bloodhound/trunk/bloodhound_theme/bhtheme/theme.py Tue Jul 23 11:25:13 2013 @@ -550,15 +550,11 @@ class QuickCreateTicketDialog(Component) PS: Borrowed from XmlRpcPlugin. -attrs = dict(attributes) -product = attrs.pop('product', '') -env = self._get_env(product) - -t = Ticket(env) +t = Ticket(self.env) t['summary'] = summary t['description'] = description t['reporter'] = req.authname -for k, v in attrs.iteritems(): +for k, v in attributes.iteritems(): t[k] = v t['status'] = 'new' t['resolution'] = '' @@ -566,21 +562,12 @@ class QuickCreateTicketDialog(Component) if notify: try: -tn = TicketNotifyEmail(env) +tn = TicketNotifyEmail(self.env) tn.notify(t, newticket=True) except Exception, e: self.log.exception(Failure sending notification on creation of ticket #%s: %s % (t.id, e)) -return product, t.id - -def _get_env(self, product): -global_env = self.env.parent or self.env -if product: -env = ProductEnvironment(global_env, product) -else: -env = global_env -return env - +return t['product'], t.id from pkg_resources import get_distribution application_version = get_distribution('BloodhoundTheme').version
svn commit: r1505992 - /bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_admin_products.html
Author: astaric Date: Tue Jul 23 11:50:20 2013 New Revision: 1505992 URL: http://svn.apache.org/r1505992 Log: Value of default combo in product admin should be product.prefix, not product.name. Modified: bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_admin_products.html Modified: bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_admin_products.html URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_admin_products.html?rev=1505992r1=1505991r2=1505992view=diff == --- bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_admin_products.html (original) +++ bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_admin_products.html Tue Jul 23 11:50:20 2013 @@ -142,7 +142,7 @@ /td td class=owner$prod.owner/td td class=default -input type=radio name=default value=$prod.name +input type=radio name=default value=$prod.prefix checked=${prod.name==default or None} / /td /tr
svn commit: r1506014 - /bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_admin_products.html
Author: astaric Date: Tue Jul 23 12:37:26 2013 New Revision: 1506014 URL: http://svn.apache.org/r1506014 Log: Check product.prefix when marking the currently selected default product in product admin. Modified: bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_admin_products.html Modified: bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_admin_products.html URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_admin_products.html?rev=1506014r1=1506013r2=1506014view=diff == --- bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_admin_products.html (original) +++ bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_admin_products.html Tue Jul 23 12:37:26 2013 @@ -143,7 +143,7 @@ td class=owner$prod.owner/td td class=default input type=radio name=default value=$prod.prefix - checked=${prod.name==default or None} / + checked=${prod.prefix==default or None} / /td /tr /tbody
svn commit: r1506038 - /bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_ticket.html
Author: astaric Date: Tue Jul 23 13:29:18 2013 New Revision: 1506038 URL: http://svn.apache.org/r1506038 Log: Add current product as a ticket field to newticket form. Refs: #608 Modified: bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_ticket.html Modified: bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_ticket.html URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_ticket.html?rev=1506038r1=1506037r2=1506038view=diff == --- bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_ticket.html (original) +++ bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_ticket.html Tue Jul 23 13:29:18 2013 @@ -426,6 +426,9 @@ /label /p + !-- Current product prefix, used to override default_product from config. -- + input type=hidden id=field-product name=field_product value=$req.perm.env.product.prefix / + div class=buttons input type=submit class=btn name=submit value=${_('Create ticket')} / /div
svn commit: r1506070 - in /bloodhound/trunk/bloodhound_multiproduct: multiproduct/dbcursor.py tests/db/cursor.py
Author: astaric Date: Tue Jul 23 14:37:58 2013 New Revision: 1506070 URL: http://svn.apache.org/r1506070 Log: Do not add product column when translating INSERT statements, if one already exists. Refs: #601 Modified: bloodhound/trunk/bloodhound_multiproduct/multiproduct/dbcursor.py bloodhound/trunk/bloodhound_multiproduct/tests/db/cursor.py Modified: bloodhound/trunk/bloodhound_multiproduct/multiproduct/dbcursor.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/multiproduct/dbcursor.py?rev=1506070r1=1506069r2=1506070view=diff == --- bloodhound/trunk/bloodhound_multiproduct/multiproduct/dbcursor.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/multiproduct/dbcursor.py Tue Jul 23 14:37:58 2013 @@ -533,6 +533,11 @@ class BloodhoundProductSQLTranslate(obje ptoken = self._token_next(columns_token, ptoken) last_token = ptoken while ptoken: +if isinstance(ptoken, Types.IdentifierList): +if any(i.get_name() == 'product' + for i in ptoken.get_identifiers() + if isinstance(i, Types.Identifier)): +return True last_token = ptoken ptoken = self._token_next(columns_token, ptoken) if not last_token or \ @@ -540,7 +545,7 @@ class BloodhoundProductSQLTranslate(obje raise Exception(Invalid INSERT statement, unable to find column parenthesis end) for keyword in [',', ' ', self._product_column]: self._token_insert_before(columns_token, last_token, Types.Token(Tokens.Keyword, keyword)) -return +return False def insert_extra_column_value(tablename, ptoken, before_token): if tablename in self._translate_tables: for keyword in [',', ', self._product_prefix, ']: @@ -548,6 +553,7 @@ class BloodhoundProductSQLTranslate(obje return tablename = None table_name_token = self._token_next(parent, token) +has_product_column = False if isinstance(table_name_token, Types.Function): token = self._token_first(table_name_token) if isinstance(token, Types.Identifier): @@ -556,7 +562,7 @@ class BloodhoundProductSQLTranslate(obje if columns_token.match(Tokens.Keyword, 'VALUES'): token = columns_token else: -insert_extra_column(tablename, columns_token) +has_product_column = insert_extra_column(tablename, columns_token) token = self._token_next(parent, table_name_token) else: tablename = table_name_token.value @@ -564,9 +570,11 @@ class BloodhoundProductSQLTranslate(obje if columns_token.match(Tokens.Keyword, 'VALUES'): token = columns_token else: -insert_extra_column(tablename, columns_token) +has_product_column = insert_extra_column(tablename, columns_token) token = self._token_next(parent, columns_token) -if token.match(Tokens.Keyword, 'VALUES'): +if has_product_column: +pass # INSERT already has product, no translation needed +elif token.match(Tokens.Keyword, 'VALUES'): separators = [',', '(', ')'] token = self._token_next(parent, token) while token: Modified: bloodhound/trunk/bloodhound_multiproduct/tests/db/cursor.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/tests/db/cursor.py?rev=1506070r1=1506069r2=1506070view=diff == --- bloodhound/trunk/bloodhound_multiproduct/tests/db/cursor.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/tests/db/cursor.py Tue Jul 23 14:37:58 2013 @@ -987,7 +987,14 @@ data = { create temporary table table_old as select * from table, create temporary table PRODUCT_table_old as select * from (SELECT * FROM PRODUCT_table) AS table, ) -] +], +# insert with specified product (#601) +'insert_with_product': [ +( +INSERT INTO ticket (summary, product) VALUES ('S', 'swlcu'), +INSERT INTO ticket (summary, product) VALUES ('S', 'swlcu') +), +], } @@ -1045,6 +1052,9 @@ class DbCursorTestCase(unittest.TestCase def test_lowercase_tokens(self): self._run_test('lowercase_tokens') +def test_insert_with_product(self): +self._run_test('insert_with_product') + if __name__ == '__main__': unittest.main()
svn commit: r1503598 - /bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py
Author: astaric Date: Tue Jul 16 07:58:33 2013 New Revision: 1503598 URL: http://svn.apache.org/r1503598 Log: Fixed a failing multiproduct upgrade test. Upgrade to multiproduct grants PRODUCT_VIEW permissions to anonymous and authenticated users, which broke asserts. Now the test only checks if permissions created before the upgrade are populated in new products. Modified: bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py Modified: bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py?rev=1503598r1=1503597r2=1503598view=diff == --- bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py Tue Jul 16 07:58:33 2013 @@ -190,7 +190,7 @@ class EnvironmentUpgradeTestCase(unittes % (table, len(rows), 6, rows)) for table in ('permission',): # Permissions also hold rows for global product. -rows = db(SELECT * FROM %s % table) +rows = db(SELECT * FROM %s WHERE username='x' % table) self.assertEqual( len(rows), 7, Wrong number of lines in %s (%d instead of %d)\n%s
svn commit: r1503620 - /bloodhound/trunk/trac/trac/wiki/tests/wiki-tests.txt
Author: astaric Date: Tue Jul 16 09:00:10 2013 New Revision: 1503620 URL: http://svn.apache.org/r1503620 Log: Split a failing unit test, skipping the failing part. Syntax of links with custom protocol containing - (rfc-2396://...) collides with Jira ticket syntax, thus causing the test to fail. The problematic links in original test were surrouded with [], which makes the test pass. Links without the [] were moved to another test that is marked as skipped. Modified: bloodhound/trunk/trac/trac/wiki/tests/wiki-tests.txt Modified: bloodhound/trunk/trac/trac/wiki/tests/wiki-tests.txt URL: http://svn.apache.org/viewvc/bloodhound/trunk/trac/trac/wiki/tests/wiki-tests.txt?rev=1503620r1=1503619r2=1503620view=diff == --- bloodhound/trunk/trac/trac/wiki/tests/wiki-tests.txt (original) +++ bloodhound/trunk/trac/trac/wiki/tests/wiki-tests.txt Tue Jul 16 09:00:10 2013 @@ -474,9 +474,9 @@ th:'wiki:my test spaced wiki3' == Another arbitrary protocol Link svn+ssh://secureserver.org [svn+ssh://secureserver.org SVN link] -rfc-2396.compatible://link +[rfc-2396.compatible://link] [rfc-2396.compatible://link RFC 2396] -rfc-2396+under_score://link +[rfc-2396+under_score://link] [rfc-2396+under_score://link underscore] unsafe://scheme is not rendered -- @@ -490,6 +490,15 @@ unsafe://scheme is not rendered unsafe://scheme is not rendered /p -- +== Another arbitrary protocol Link without [] - SKIP as it clashes with Jira ticket syntax +rfc-2396.compatible://link +rfc-2396+under_score://link +-- +p +a class=ext-link href=rfc-2396.compatible://linkspan class=icon/spanrfc-2396.compatible://link/a +a class=ext-link href=rfc-2396+under_score://linkspan class=icon/spanrfc-2396+under_score://link/a +/p +-- == WikiCreole style for the above examples [[link:WikiStart| Foo]] [[http://www.edgewall.com/|Edgewall]]
svn commit: r1502480 - in /bloodhound/trunk/bloodhound_relations/bhrelations: api.py tests/web_ui.py web_ui.py
Author: astaric Date: Fri Jul 12 08:51:54 2013 New Revision: 1502480 URL: http://svn.apache.org/r1502480 Log: Handling of cases when resource id cannot be constructed from resource_instance. Refs: #588 Modified: bloodhound/trunk/bloodhound_relations/bhrelations/api.py bloodhound/trunk/bloodhound_relations/bhrelations/tests/web_ui.py bloodhound/trunk/bloodhound_relations/bhrelations/web_ui.py Modified: bloodhound/trunk/bloodhound_relations/bhrelations/api.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_relations/bhrelations/api.py?rev=1502480r1=1502479r2=1502480view=diff == --- bloodhound/trunk/bloodhound_relations/bhrelations/api.py (original) +++ bloodhound/trunk/bloodhound_relations/bhrelations/api.py Fri Jul 12 08:51:54 2013 @@ -445,6 +445,9 @@ class ResourceIdSerializer(object): #TODO: temporary workaround for the ticket specific behavior #change it to generic resource behaviour ticket = resource_instance +if ticket.id is None: +raise ValueError(Cannot get resource id for ticket + that does not exist yet.) nbhprefix = ticket[product] resource_full_id = cls.RESOURCE_ID_DELIMITER.join( Modified: bloodhound/trunk/bloodhound_relations/bhrelations/tests/web_ui.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_relations/bhrelations/tests/web_ui.py?rev=1502480r1=1502479r2=1502480view=diff == --- bloodhound/trunk/bloodhound_relations/bhrelations/tests/web_ui.py (original) +++ bloodhound/trunk/bloodhound_relations/bhrelations/tests/web_ui.py Fri Jul 12 08:51:54 2013 @@ -120,7 +120,6 @@ class ResolveTicketIntegrationTestCase(B t1 = self._insert_and_load_ticket(Foo) t2 = self._insert_and_load_ticket(Bar) self.relations_system.add(t2, t1, 'duplicateof') -self.req.args['id'] = t2.id self.req.path_info = '/ticket/%d' % t2.id data = self.process_request() @@ -141,6 +140,15 @@ class ResolveTicketIntegrationTestCase(B self.assertEqual(t2['status'], 'closed') self.assertEqual(t2['resolution'], 'duplicate') +def test_post_process_request_does_not_break_ticket(self): +t1 = self._insert_and_load_ticket(Foo) +self.req.path_info = '/ticket/%d' % t1.id +self.process_request() + +def test_post_process_request_does_not_break_newticket(self): +self.req.path_info = '/newticket' +self.process_request() + def resolve_as_duplicate(self, ticket, duplicate_id): self.req.method = 'POST' self.req.path_info = '/ticket/%d' % ticket.id @@ -154,8 +162,10 @@ class ResolveTicketIntegrationTestCase(B return self.process_request() def process_request(self): -template, data, content_type = \ -TicketModule(self.env).process_request(self.req) +ticket_module = TicketModule(self.env) + +ticket_module.match_request(self.req) +template, data, content_type = ticket_module.process_request(self.req) template, data, content_type = \ RelationManagementModule(self.env).post_process_request( self.req, template, data, content_type) Modified: bloodhound/trunk/bloodhound_relations/bhrelations/web_ui.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_relations/bhrelations/web_ui.py?rev=1502480r1=1502479r2=1502480view=diff == --- bloodhound/trunk/bloodhound_relations/bhrelations/web_ui.py (original) +++ bloodhound/trunk/bloodhound_relations/bhrelations/web_ui.py Fri Jul 12 08:51:54 2013 @@ -134,10 +134,13 @@ class RelationManagementModule(Component if 'ticket' in data: ticket = data['ticket'] rls = RelationsSystem(self.env) -resid = ResourceIdSerializer.get_resource_id_from_instance( -self.env, ticket) +try: +resid = ResourceIdSerializer.get_resource_id_from_instance( +self.env, ticket) +except ValueError: +resid = None -if rls.duplicate_relation_type: +if rls.duplicate_relation_type and resid is not None: duplicate_relations = \ rls._select_relations(resid, rls.duplicate_relation_type) if duplicate_relations:
svn commit: r1501127 - /bloodhound/trunk/bloodhound_multiproduct/tests/env.py
Author: astaric Date: Tue Jul 9 08:27:23 2013 New Revision: 1501127 URL: http://svn.apache.org/r1501127 Log: Removed a reference to self that was missed in r1499182. Modified: bloodhound/trunk/bloodhound_multiproduct/tests/env.py Modified: bloodhound/trunk/bloodhound_multiproduct/tests/env.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/tests/env.py?rev=1501127r1=1501126r2=1501127view=diff == --- bloodhound/trunk/bloodhound_multiproduct/tests/env.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/tests/env.py Tue Jul 9 08:27:23 2013 @@ -233,7 +233,7 @@ class MultiproductTestCase(unittest.Test except OperationalError: # Database is upgraded, but database version was deleted. # Complete the upgrade by inserting default product. -self.mpsystem._insert_default_product(env.db_transaction) +mpsystem._insert_default_product(env.db_transaction) # assume that the database schema has been upgraded, enable # multi-product schema support in environment env.enable_multiproduct_schema(True)
svn commit: r1501152 - in /bloodhound/trunk: bloodhound_relations/bhrelations/ bloodhound_relations/bhrelations/tests/ bloodhound_relations/bhrelations/widgets/ bloodhound_theme/bhtheme/htdocs/ bloodh
Author: astaric Date: Tue Jul 9 09:19:00 2013 New Revision: 1501152 URL: http://svn.apache.org/r1501152 Log: Integration of duplicate relations to close as duplicate workflow. Refs: #588 Added: bloodhound/trunk/bloodhound_relations/bhrelations/tests/base.py bloodhound/trunk/bloodhound_relations/bhrelations/utils.py Modified: bloodhound/trunk/bloodhound_relations/bhrelations/api.py bloodhound/trunk/bloodhound_relations/bhrelations/tests/api.py bloodhound/trunk/bloodhound_relations/bhrelations/tests/notification.py bloodhound/trunk/bloodhound_relations/bhrelations/tests/search.py bloodhound/trunk/bloodhound_relations/bhrelations/tests/validation.py bloodhound/trunk/bloodhound_relations/bhrelations/tests/web_ui.py bloodhound/trunk/bloodhound_relations/bhrelations/web_ui.py bloodhound/trunk/bloodhound_relations/bhrelations/widgets/relations.py bloodhound/trunk/bloodhound_theme/bhtheme/htdocs/bloodhound.css bloodhound/trunk/bloodhound_theme/bhtheme/templates/bh_ticket.html bloodhound/trunk/installer/bloodhound_setup.py Modified: bloodhound/trunk/bloodhound_relations/bhrelations/api.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_relations/bhrelations/api.py?rev=1501152r1=1501151r2=1501152view=diff == --- bloodhound/trunk/bloodhound_relations/bhrelations/api.py (original) +++ bloodhound/trunk/bloodhound_relations/bhrelations/api.py Tue Jul 9 09:19:00 2013 @@ -17,17 +17,24 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. +import itertools + +import re from datetime import datetime from pkg_resources import resource_filename from bhrelations import db_default from bhrelations.model import Relation +from bhrelations.utils import unique from multiproduct.api import ISupportMultiProductEnvironment -from trac.config import OrderedExtensionsOption +from multiproduct.model import Product +from multiproduct.env import ProductEnvironment + +from trac.config import OrderedExtensionsOption, Option from trac.core import (Component, implements, TracError, Interface, ExtensionPoint) from trac.env import IEnvironmentSetupParticipant from trac.db import DatabaseManager -from trac.resource import (ResourceSystem, Resource, +from trac.resource import (ResourceSystem, Resource, ResourceNotFound, get_resource_shortname, Neighborhood) from trac.ticket import Ticket, ITicketManipulator, ITicketChangeListener from trac.util.datefmt import utc, to_utimestamp @@ -167,6 +174,12 @@ class RelationsSystem(Component): regardless of their type. ) +duplicate_relation_type = Option( +'bhrelations', +'duplicate_relation', +'', +Relation type to be used with the resolve as duplicate workflow.) + def __init__(self): links, labels, validators, blockers, copy_fields, exclusive = \ self._parse_config() @@ -443,28 +456,46 @@ class ResourceIdSerializer(object): class TicketRelationsSpecifics(Component): implements(ITicketManipulator, ITicketChangeListener) -#ITicketChangeListener methods +def __init__(self): +self.rls = RelationsSystem(self.env) +#ITicketChangeListener methods def ticket_created(self, ticket): pass def ticket_changed(self, ticket, comment, author, old_values): -pass +if ( +self._closed_as_duplicate(ticket) and +self.rls.duplicate_relation_type +): +try: +self.rls.add(ticket, ticket.duplicate, + self.rls.duplicate_relation_type, + comment, author) +except TracError: +pass + +def _closed_as_duplicate(self, ticket): +return (ticket['status'] == 'closed' and +ticket['resolution'] == 'duplicate') def ticket_deleted(self, ticket): -RelationsSystem(self.env).delete_resource_relations(ticket) +self.rls.delete_resource_relations(ticket) #ITicketManipulator methods - def prepare_ticket(self, req, ticket, fields, actions): pass def validate_ticket(self, req, ticket): -action = req.args.get('action') -if action == 'resolve': -rls = RelationsSystem(self.env) -blockers = rls.find_blockers( -ticket, self.is_blocker) +return itertools.chain( +self._check_blockers(req, ticket), +self._check_open_children(req, ticket), +self._check_duplicate_id(req, ticket), +) + +def _check_blockers(self, req, ticket): +if req.args.get('action') == 'resolve': +blockers = self.rls.find_blockers(ticket, self.is_blocker) if blockers
svn commit: r1487776 - in /bloodhound/trunk/bloodhound_relations/bhrelations: api.py templates/manage.html tests/__init__.py tests/api.py tests/web_ui.py web_ui.py
Author: astaric Date: Thu May 30 07:52:22 2013 New Revision: 1487776 URL: http://svn.apache.org/r1487776 Log: Refs #537: Better handling of errors in bhrelations web ui. Added: bloodhound/trunk/bloodhound_relations/bhrelations/tests/web_ui.py Modified: bloodhound/trunk/bloodhound_relations/bhrelations/api.py bloodhound/trunk/bloodhound_relations/bhrelations/templates/manage.html bloodhound/trunk/bloodhound_relations/bhrelations/tests/__init__.py bloodhound/trunk/bloodhound_relations/bhrelations/tests/api.py bloodhound/trunk/bloodhound_relations/bhrelations/web_ui.py Modified: bloodhound/trunk/bloodhound_relations/bhrelations/api.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_relations/bhrelations/api.py?rev=1487776r1=1487775r2=1487776view=diff == --- bloodhound/trunk/bloodhound_relations/bhrelations/api.py (original) +++ bloodhound/trunk/bloodhound_relations/bhrelations/api.py Thu May 30 07:52:22 2013 @@ -197,6 +197,8 @@ class RelationsSystem(Component): self.env, source_resource_instance) destination = ResourceIdSerializer.get_resource_id_from_instance( self.env, destination_resource_instance) +if relation_type not in self.link_ends_map: +raise UnknownRelationType(relation_type) if when is None: when = datetime.now(utc) relation = Relation(self.env) @@ -579,3 +581,6 @@ def unique(seq): seen = set() return (x for x in seq if x not in seen and not seen.add(x)) + +class UnknownRelationType(ValueError): +pass Modified: bloodhound/trunk/bloodhound_relations/bhrelations/templates/manage.html URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_relations/bhrelations/templates/manage.html?rev=1487776r1=1487775r2=1487776view=diff == --- bloodhound/trunk/bloodhound_relations/bhrelations/templates/manage.html (original) +++ bloodhound/trunk/bloodhound_relations/bhrelations/templates/manage.html Thu May 30 07:52:22 2013 @@ -37,6 +37,14 @@ div class=row div class=span8 +py:if test='error' + div class=alert alert-error +span class=label label-importantOops !/span +Could not create relation. +$error + /div +/py:if + form id=addrelation class=well form-horizontal method=post action= fieldset legendAdd relation:/legend @@ -45,7 +53,7 @@ div class=control-group label class=control-label for=dest_tidRelated ticket:/label div class=controls - input type=text id=dest_tid class=span4 name=dest_tid / + input type=text id=dest_tid class=span4 name=dest_tid value=$relation.destination / /div /div @@ -53,7 +61,7 @@ label class=control-label for=reltypeRelation type:/label div class=controls select class=span4 id=reltype name=reltype -option py:for=reltype,label in reltypes.iteritems() value=$reltype$label/option +option py:for=reltype,label in reltypes.iteritems() value=$reltype selected=${True if reltype == relation.type else None}$label/option /select /div /div @@ -61,7 +69,7 @@ div class=control-group label class=control-label for=commentComment:/label div class=controls - textarea name=comment rows=3 class=span4 / + textarea name=comment rows=3 class=span4${relation.comment}/textarea /div /div Modified: bloodhound/trunk/bloodhound_relations/bhrelations/tests/__init__.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_relations/bhrelations/tests/__init__.py?rev=1487776r1=1487775r2=1487776view=diff == --- bloodhound/trunk/bloodhound_relations/bhrelations/tests/__init__.py (original) +++ bloodhound/trunk/bloodhound_relations/bhrelations/tests/__init__.py Thu May 30 07:52:22 2013 @@ -25,7 +25,8 @@ # import unittest import unittest -from bhrelations.tests import api, notification, search, validation +from bhrelations.tests import api, notification, search, validation, web_ui + def suite(): test_suite = unittest.TestSuite() @@ -33,7 +34,7 @@ def suite(): test_suite.addTest(notification.suite()) test_suite.addTest(search.suite()) test_suite.addTest(validation.suite()) - +test_suite.addTest(web_ui.suite()) return test_suite if __name__ == '__main__': Modified: bloodhound/trunk/bloodhound_relations/bhrelations/tests/api.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_relations/bhrelations/tests/api.py?rev=1487776r1=1487775r2=1487776view=diff
svn commit: r1487398 - in /bloodhound/trunk: bloodhound_relations/setup.py bloodhound_search/bhsearch/whoosh_backend.py
Author: astaric Date: Wed May 29 08:26:47 2013 New Revision: 1487398 URL: http://svn.apache.org/r1487398 Log: Added relations to search index. Towards #543. Modified: bloodhound/trunk/bloodhound_relations/setup.py bloodhound/trunk/bloodhound_search/bhsearch/whoosh_backend.py Modified: bloodhound/trunk/bloodhound_relations/setup.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_relations/setup.py?rev=1487398r1=1487397r2=1487398view=diff == --- bloodhound/trunk/bloodhound_relations/setup.py (original) +++ bloodhound/trunk/bloodhound_relations/setup.py Wed May 29 08:26:47 2013 @@ -104,6 +104,7 @@ PKG_INFO = {'bhrelations': ('bhrelations ENTRY_POINTS = { 'trac.plugins': [ 'bhrelations.api = bhrelations.api', +'bhrelations.search = bhrelations.search', 'bhrelations.validation = bhrelations.validation', 'bhrelations.web_ui = bhrelations.web_ui', 'bhrelations.widgets.ticketrelations = bhrelations.widgets.relations', Modified: bloodhound/trunk/bloodhound_search/bhsearch/whoosh_backend.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_search/bhsearch/whoosh_backend.py?rev=1487398r1=1487397r2=1487398view=diff == --- bloodhound/trunk/bloodhound_search/bhsearch/whoosh_backend.py (original) +++ bloodhound/trunk/bloodhound_search/bhsearch/whoosh_backend.py Wed May 29 08:26:47 2013 @@ -114,6 +114,7 @@ class WhooshBackend(Component): analyzer=analysis.SimpleAnalyzer()), query_suggestion_basket=TEXT(analyzer=analysis.SimpleAnalyzer(), spelling=True), +relations=TEXT(analyzer=analysis.SimpleAnalyzer()), ) def __init__(self):
svn commit: r1486635 - in /bloodhound/trunk/bloodhound_multiproduct/tests: env.py wiki/formatter.py
Author: astaric Date: Mon May 27 14:34:12 2013 New Revision: 1486635 URL: http://svn.apache.org/r1486635 Log: Moved env creation in ProductWikiTestCase from __init__ to setUp. Config in product environments is stored in database and should be part of the setUp method. This replaces the quickfix introduced in r1486610. Modified: bloodhound/trunk/bloodhound_multiproduct/tests/env.py bloodhound/trunk/bloodhound_multiproduct/tests/wiki/formatter.py Modified: bloodhound/trunk/bloodhound_multiproduct/tests/env.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/tests/env.py?rev=1486635r1=1486634r2=1486635view=diff == --- bloodhound/trunk/bloodhound_multiproduct/tests/env.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/tests/env.py Mon May 27 14:34:12 2013 @@ -47,22 +47,6 @@ from multiproduct.api import MultiProduc from multiproduct.env import ProductEnvironment from multiproduct.model import Product -# unittests in python2.7 run in the same process and share the same connection -# pool. This basically means that all tests share the same in-memory database, -# and calling reset_db in teardown methods destroys data prepared in __init__ -# of other tests. Trac tests do not do prepare data in __init__, but when run -# with a product env, which stores config values to database, this behavior -# causes multiple tests to fail. -# -# We workaround this issue by monkey patching trac's ConnectionPool. We force -# it to establish a separate connection for each DatabaseManager. -from trac.db.pool import ConnectionPool, ConnectionPoolBackend -def ConnectionPool_get_cnx(self, timeout=None): -if not hasattr(self, '_backend'): -self._backend = ConnectionPoolBackend(1) -return self._backend.get_cnx(self._connector, self._kwargs, timeout) -ConnectionPool.get_cnx = ConnectionPool_get_cnx - class ProductEnvironmentStub(ProductEnvironment): rA product environment slightly tweaked for testing purposes Modified: bloodhound/trunk/bloodhound_multiproduct/tests/wiki/formatter.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/tests/wiki/formatter.py?rev=1486635r1=1486634r2=1486635view=diff == --- bloodhound/trunk/bloodhound_multiproduct/tests/wiki/formatter.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/tests/wiki/formatter.py Mon May 27 14:34:12 2013 @@ -22,6 +22,9 @@ import os.path import re import unittest +from trac.test import Mock, MockPerm, locale_en +from trac.util.datefmt import utc +from trac.web.href import Href from trac.web.main import FakeSession from trac.wiki.tests import formatter @@ -29,42 +32,15 @@ from multiproduct.env import ProductEnvi from multiproduct.model import Product from tests.env import MultiproductTestCase -class ProductWikiTestCase(formatter.WikiTestCase, MultiproductTestCase): -maxDiff = None -@property -def env(self): -env = getattr(self, '_env', None) -if env is None: -all_test_components = [ -formatter.HelloWorldMacro, formatter.DivHelloWorldMacro, -formatter.TableHelloWorldMacro, formatter.DivCodeMacro, -formatter.DivCodeElementMacro, formatter.DivCodeStreamMacro, -formatter.NoneMacro, formatter.WikiProcessorSampleMacro, -formatter.SampleResolver] -self.global_env = self._setup_test_env( -enable=['trac.*', 'multiproduct.*'] + all_test_components -) -self._upgrade_mp(self.global_env) -self._load_product_from_data(self.global_env, self.default_product) -prefix = self.default_product -if self.mpctx: -prefix = self.mpctx.get('setup_product', prefix) -if prefix and prefix != self.default_product: -self._load_product_from_data(self.global_env, prefix) -if prefix: -self._env = env = ProductEnvironment( -self.global_env, prefix or self.default_product) -else: -self._env = env = self.global_env -return env -@env.setter -def env(self, value): -pass +class ProductWikiTestCase(formatter.WikiTestCase, MultiproductTestCase): +maxDiff = None def setUp(self): +self._prepare_env() + self._setup_test_log(self.global_env) formatter.WikiTestCase.setUp(self) if self.context.req: @@ -79,13 +55,60 @@ class ProductWikiTestCase(formatter.Wiki prefix = self.mpctx.get('main_product', NotImplemented) if prefix is None: -self._env = self.global_env +self.env = self.global_env elif prefix is not NotImplemented
svn commit: r1486642 - in /bloodhound/trunk/bloodhound_multiproduct/tests: env.py wiki/formatter.py
Author: astaric Date: Mon May 27 15:38:00 2013 New Revision: 1486642 URL: http://svn.apache.org/r1486642 Log: Database should always contain default product after _upgrade_mp is run. Inconsistent behavior caused some tests to pass if run standalone, but fail as a part of the suite. Modified: bloodhound/trunk/bloodhound_multiproduct/tests/env.py bloodhound/trunk/bloodhound_multiproduct/tests/wiki/formatter.py Modified: bloodhound/trunk/bloodhound_multiproduct/tests/env.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/tests/env.py?rev=1486642r1=1486641r2=1486642view=diff == --- bloodhound/trunk/bloodhound_multiproduct/tests/env.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/tests/env.py Mon May 27 15:38:00 2013 @@ -230,8 +230,9 @@ class MultiproductTestCase(unittest.Test try: self.mpsystem.upgrade_environment(env.db_transaction) except OperationalError: -# table remains but database version is deleted -pass +# Database is upgraded, but database version was deleted. +# Complete the upgrade by inserting default product. +self.mpsystem._insert_default_product(env.db_transaction) # assume that the database schema has been upgraded, enable # multi-product schema support in environment env.enable_multiproduct_schema(True) Modified: bloodhound/trunk/bloodhound_multiproduct/tests/wiki/formatter.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/tests/wiki/formatter.py?rev=1486642r1=1486641r2=1486642view=diff == --- bloodhound/trunk/bloodhound_multiproduct/tests/wiki/formatter.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/tests/wiki/formatter.py Mon May 27 15:38:00 2013 @@ -33,8 +33,6 @@ from multiproduct.model import Product from tests.env import MultiproductTestCase - - class ProductWikiTestCase(formatter.WikiTestCase, MultiproductTestCase): maxDiff = None
svn commit: r1486658 - /bloodhound/trunk/bloodhound_multiproduct/tests/env.py
Author: astaric Date: Mon May 27 16:33:02 2013 New Revision: 1486658 URL: http://svn.apache.org/r1486658 Log: Unregister class with invalid __module__ after test is done. Components are saved to ComponentMeta._components class variable (shared between all tests run in the same process). When get_plugin_info is called, it traverses this list of registered classes, and fails if a class with invalid __module__ is encountered. Modified: bloodhound/trunk/bloodhound_multiproduct/tests/env.py Modified: bloodhound/trunk/bloodhound_multiproduct/tests/env.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/tests/env.py?rev=1486658r1=1486657r2=1486658view=diff == --- bloodhound/trunk/bloodhound_multiproduct/tests/env.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/tests/env.py Mon May 27 16:33:02 2013 @@ -35,7 +35,7 @@ else: from unittest.case import _AssertRaisesContext from trac.config import Option -from trac.core import Component +from trac.core import Component, ComponentMeta from trac.env import Environment from trac.test import EnvironmentStub, MockPerm from trac.tests.env import EnvironmentTestCase @@ -472,6 +472,10 @@ class ProductEnvApiTestCase(Multiproduct # Test the rules against Trac component class _test_component_enabled(TicketModule) +# ComponentMeta._components is shared between multiple tests. +# Unregister class C as its fake module might break something else. +ComponentMeta._components.remove(C) + def test_path(self): Testing env.path self.assertEqual(self.product_env.path,
svn commit: r1486035 - /bloodhound/trunk/bloodhound_multiproduct/tests/config.py
Author: astaric Date: Fri May 24 12:27:06 2013 New Revision: 1486035 URL: http://svn.apache.org/r1486035 Log: Expand symlinks in path. Fixes two failing tests when there are symlinks in the path to the tempdir. Modified: bloodhound/trunk/bloodhound_multiproduct/tests/config.py Modified: bloodhound/trunk/bloodhound_multiproduct/tests/config.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/tests/config.py?rev=1486035r1=1486034r2=1486035view=diff == --- bloodhound/trunk/bloodhound_multiproduct/tests/config.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/tests/config.py Fri May 24 12:27:06 2013 @@ -45,7 +45,8 @@ class ProductConfigTestCase(Configuratio self.env = self._setup_test_env() # Dummy config file, a sibling of trac.ini -self.filename = os.path.join(self.env.path, 'conf', 'product.ini') +tmpdir = os.path.realpath(self.env.path) +self.filename = os.path.join(tmpdir, 'conf', 'product.ini') # Ensure conf sub-folder is created os.mkdir(os.path.dirname(self.filename))
svn commit: r1484438 - in /bloodhound/trunk: bloodhound_relations/bhrelations/tests/api.py bloodhound_relations/bhrelations/validation.py installer/bloodhound_setup.py
Author: astaric Date: Mon May 20 11:47:24 2013 New Revision: 1484438 URL: http://svn.apache.org/r1484438 Log: Cycle detection for blocker relations. Closes #528. Modified: bloodhound/trunk/bloodhound_relations/bhrelations/tests/api.py bloodhound/trunk/bloodhound_relations/bhrelations/validation.py bloodhound/trunk/installer/bloodhound_setup.py Modified: bloodhound/trunk/bloodhound_relations/bhrelations/tests/api.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_relations/bhrelations/tests/api.py?rev=1484438r1=1484437r2=1484438view=diff == --- bloodhound/trunk/bloodhound_relations/bhrelations/tests/api.py (original) +++ bloodhound/trunk/bloodhound_relations/bhrelations/tests/api.py Mon May 20 11:47:24 2013 @@ -46,12 +46,13 @@ class BaseApiApiTestCase(MultiproductTes enable=['trac.*', 'multiproduct.*', 'bhrelations.*'] ) env.config.set('bhrelations', 'global_validators', - 'NoSelfReferenceValidator,ExclusiveValidator') + 'NoSelfReferenceValidator,ExclusiveValidator,' + 'BlockerValidator') config_name = RelationsSystem.RELATIONS_CONFIG_NAME env.config.set(config_name, 'dependency', 'dependson,dependent') env.config.set(config_name, 'dependency.validators', 'NoCycles,SingleProduct') -env.config.set(config_name, 'dependent.blocks', 'true') +env.config.set(config_name, 'dependson.blocks', 'true') env.config.set(config_name, 'parent_children', 'parent,children') env.config.set(config_name, 'parent_children.validators', 'OneToMany,SingleProduct,NoCycles') @@ -65,6 +66,8 @@ class BaseApiApiTestCase(MultiproductTes env.config.set(config_name, 'duplicate.validators', 'ReferencesOlder') env.config.set(config_name, 'duplicateof.label', 'Duplicate of') env.config.set(config_name, 'duplicatedby.label', 'Duplicated by') +env.config.set(config_name, 'blocker', 'blockedby,blocks') +env.config.set(config_name, 'blockedby.blocks', 'true') self.global_env = env self._upgrade_mp(self.global_env) @@ -351,7 +354,7 @@ class ApiTestCase(BaseApiApiTestCase): #arrange ticket1 = self._insert_and_load_ticket(A1) ticket2 = self._insert_and_load_ticket(A2) -self.relations_system.add(ticket1, ticket2, dependent) +self.relations_system.add(ticket1, ticket2, dependson) #act self.req.args[action] = 'resolve' warnings = TicketRelationsSpecifics(self.env).validate_ticket( @@ -363,7 +366,7 @@ class ApiTestCase(BaseApiApiTestCase): #arrange ticket1 = self._insert_and_load_ticket(A1) ticket2 = self._insert_and_load_ticket(A2, status=closed) -self.relations_system.add(ticket1, ticket2, dependent) +self.relations_system.add(ticket1, ticket2, dependson) #act self.req.args[action] = 'resolve' warnings = TicketRelationsSpecifics(self.env).validate_ticket( @@ -547,6 +550,30 @@ class ApiTestCase(BaseApiApiTestCase): ) self.relations_system.add(t2, t1, duplicateof) +def test_detects_blocker_cycles(self): +t1, t2, t3, t4, t5 = map(self._insert_and_load_ticket, range(5)) +self.relations_system.add(t1, t2, blocks) +self.relations_system.add(t3, t2, dependson) +self.relations_system.add(t4, t3, blockedby) +self.relations_system.add(t4, t5, dependent) + +self.assertRaises(ValidationError, + self.relations_system.add, t2, t1, blocks) +self.assertRaises(ValidationError, + self.relations_system.add, t3, t1, dependent) +self.assertRaises(ValidationError, + self.relations_system.add, t1, t2, blockedby) +self.assertRaises(ValidationError, + self.relations_system.add, t1, t5, dependson) + +self.relations_system.add(t1, t2, dependent) +self.relations_system.add(t2, t3, blocks) +self.relations_system.add(t4, t3, dependson) +self.relations_system.add(t5, t4, blockedby) + +self.relations_system.add(t1, t2, refersto) +self.relations_system.add(t2, t1, refersto) + class RelationChangingListenerTestCase(BaseApiApiTestCase): def test_can_sent_adding_event(self): Modified: bloodhound/trunk/bloodhound_relations/bhrelations/validation.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_relations/bhrelations/validation.py?rev=1484438r1=1484437r2=1484438view=diff == --- bloodhound/trunk/bloodhound_relations/bhrelations/validation.py (original) +++ bloodhound/trunk/bloodhound_relations/bhrelations/validation.py Mon May 20 11:47:24
svn commit: r1480186 - in /bloodhound/trunk/bloodhound_multiproduct: multiproduct/dbcursor.py tests/db/cursor.py
Author: astaric Date: Wed May 8 08:53:50 2013 New Revision: 1480186 URL: http://svn.apache.org/r1480186 Log: Also translate CREATE TEMPORARY TABLE statements. Fixes an error encountered when upgrading spamfilter plugin to multiproduct. Modified: bloodhound/trunk/bloodhound_multiproduct/multiproduct/dbcursor.py bloodhound/trunk/bloodhound_multiproduct/tests/db/cursor.py Modified: bloodhound/trunk/bloodhound_multiproduct/multiproduct/dbcursor.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/multiproduct/dbcursor.py?rev=1480186r1=1480185r2=1480186view=diff == --- bloodhound/trunk/bloodhound_multiproduct/multiproduct/dbcursor.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/multiproduct/dbcursor.py Wed May 8 08:53:50 2013 @@ -690,6 +690,8 @@ class BloodhoundProductSQLTranslate(obje def _create(self, parent, start_token): token = self._token_next(parent, start_token) +if token.match(Tokens.Keyword, 'TEMPORARY'): +token = self._token_next(parent, token) if token.match(Tokens.Keyword, 'TABLE'): token = self._token_next(parent, token) while token.match(Tokens.Keyword, ['IF', 'NOT', 'EXIST']) or \ Modified: bloodhound/trunk/bloodhound_multiproduct/tests/db/cursor.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/tests/db/cursor.py?rev=1480186r1=1480185r2=1480186view=diff == --- bloodhound/trunk/bloodhound_multiproduct/tests/db/cursor.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/tests/db/cursor.py Wed May 8 08:53:50 2013 @@ -948,6 +948,16 @@ data = { tkt_order REAL, PRIMARY KEY(bklg_id, tkt_id)) ), +( +CREATE TEMPORARY TABLE backlog_ticket (bklg_id INTEGER NOT NULL, + tkt_id INTEGER NOT NULL, + tkt_order REAL, + PRIMARY KEY(bklg_id, tkt_id)), +CREATE TEMPORARY TABLE PRODUCT_backlog_ticket (bklg_id INTEGER NOT NULL, + tkt_id INTEGER NOT NULL, + tkt_order REAL, + PRIMARY KEY(bklg_id, tkt_id)) +), ], # custom ALTER TABLE
svn commit: r1480224 - in /bloodhound/trunk/bloodhound_multiproduct: multiproduct/dbcursor.py tests/db/cursor.py tests/upgrade.py
Author: astaric Date: Wed May 8 11:14:34 2013 New Revision: 1480224 URL: http://svn.apache.org/r1480224 Log: Translate SELECT part of CREATE TABLE ... AS SELECT ... queries. Fixes an issue where some product plugin tables were prepopulated with rows from global product. Modified: bloodhound/trunk/bloodhound_multiproduct/multiproduct/dbcursor.py bloodhound/trunk/bloodhound_multiproduct/tests/db/cursor.py bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py Modified: bloodhound/trunk/bloodhound_multiproduct/multiproduct/dbcursor.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/multiproduct/dbcursor.py?rev=1480224r1=1480223r2=1480224view=diff == --- bloodhound/trunk/bloodhound_multiproduct/multiproduct/dbcursor.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/multiproduct/dbcursor.py Wed May 8 11:14:34 2013 @@ -700,7 +700,16 @@ class BloodhoundProductSQLTranslate(obje table_name = self._get_entity_name_from_token(parent, token) if not table_name: raise Exception(Invalid CREATE TABLE statement, expected table name) + +as_token = self._token_next_match(parent, token, + Tokens.Keyword, 'AS') self._replace_table_entity_name(parent, token, table_name) + +if as_token: +select_token = self._token_next_match(parent, as_token, + Tokens.DML, 'SELECT') +if select_token: +return self._select(parent, select_token) elif token.match(Tokens.Keyword, ['UNIQUE', 'INDEX']): if token.match(Tokens.Keyword, 'UNIQUE'): token = self._token_next(parent, token) Modified: bloodhound/trunk/bloodhound_multiproduct/tests/db/cursor.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/tests/db/cursor.py?rev=1480224r1=1480223r2=1480224view=diff == --- bloodhound/trunk/bloodhound_multiproduct/tests/db/cursor.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/tests/db/cursor.py Wed May 8 11:14:34 2013 @@ -955,8 +955,13 @@ data = { PRIMARY KEY(bklg_id, tkt_id)), CREATE TEMPORARY TABLE PRODUCT_backlog_ticket (bklg_id INTEGER NOT NULL, tkt_id INTEGER NOT NULL, - tkt_order REAL, - PRIMARY KEY(bklg_id, tkt_id)) + tkt_order REAL, + PRIMARY KEY(bklg_id, tkt_id)) +), +( +CREATE TEMPORARY TABLE table_old AS SELECT * FROM table, +CREATE TEMPORARY TABLE PRODUCT_table_old AS SELECT * FROM + (SELECT * FROM PRODUCT_table) AS table, ), ], Modified: bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py?rev=1480224r1=1480223r2=1480224view=diff == --- bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py Wed May 8 11:14:34 2013 @@ -312,6 +312,7 @@ class EnvironmentUpgradeTestCase(unittes db(SELECT * FROM @_dummy_table ) def test_upgrading_existing_plugin_leaves_data_in_global_env(self): +DummyPlugin.version = 2 self._enable_component(DummyPlugin) self.env.upgrade() with self.env.db_direct_transaction as db: @@ -427,27 +428,45 @@ class DummyPlugin(Component): def upgrade_environment(self, db): old_version = current_version = self.get_version(db) +db_connector, dummy = DatabaseManager(self.env)._get_connector() -if current_version 1 = self.version: -db_connector, dummy = DatabaseManager(self.env)._get_connector() -for statement in db_connector.to_sql(DUMMY_TABLE): -db(statement) -current_version = 1 while current_version self.version: +if current_version 0: +db(CREATE TEMPORARY TABLE dummy_table_old AS + SELECT * FROM dummy_table) +db(DROP TABLE dummy_table) + +table = self.construct_dummy_table(current_version+1) +for statement in db_connector.to_sql(table): +db(statement) + +if current_version 0: +cols = ['id'] + ['v%i' % (i+1) + for i in range(current_version+1)] +db(INSERT INTO dummy_table (%s) + SELECT %s, '' FROM dummy_table_old
svn commit: r1479822 - in /bloodhound/trunk: bloodhound_dashboard/ bloodhound_dashboard/bhdashboard/widgets/ bloodhound_relations/ bloodhound_relations/bhrelations/widgets/
Author: astaric Date: Tue May 7 09:05:30 2013 New Revision: 1479822 URL: http://svn.apache.org/r1479822 Log: Moved relations widget to bhrelations module. -- towards BEP-0006 Added: bloodhound/trunk/bloodhound_relations/bhrelations/widgets/ bloodhound/trunk/bloodhound_relations/bhrelations/widgets/__init__.py bloodhound/trunk/bloodhound_relations/bhrelations/widgets/relations.py - copied unchanged from r1479567, bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/relations.py Removed: bloodhound/trunk/bloodhound_dashboard/bhdashboard/widgets/relations.py Modified: bloodhound/trunk/bloodhound_dashboard/setup.py bloodhound/trunk/bloodhound_relations/setup.py Modified: bloodhound/trunk/bloodhound_dashboard/setup.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_dashboard/setup.py?rev=1479822r1=1479821r2=1479822view=diff == --- bloodhound/trunk/bloodhound_dashboard/setup.py (original) +++ bloodhound/trunk/bloodhound_dashboard/setup.py Tue May 7 09:05:30 2013 @@ -125,7 +125,6 @@ ENTRY_POINTS = r bhdashboard.widgets.product = bhdashboard.widgets.product bhdashboard.widgets.query = bhdashboard.widgets.query bhdashboard.widgets.report = bhdashboard.widgets.report - bhdashboard.widgets.ticketrelations = bhdashboard.widgets.relations bhdashboard.widgets.ticket = bhdashboard.widgets.ticket bhdashboard.widgets.timeline = bhdashboard.widgets.timeline bhdashboard.wiki = bhdashboard.wiki Added: bloodhound/trunk/bloodhound_relations/bhrelations/widgets/__init__.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_relations/bhrelations/widgets/__init__.py?rev=1479822view=auto == --- bloodhound/trunk/bloodhound_relations/bhrelations/widgets/__init__.py (added) +++ bloodhound/trunk/bloodhound_relations/bhrelations/widgets/__init__.py Tue May 7 09:05:30 2013 @@ -0,0 +1,19 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +# 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. Modified: bloodhound/trunk/bloodhound_relations/setup.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_relations/setup.py?rev=1479822r1=1479821r2=1479822view=diff == --- bloodhound/trunk/bloodhound_relations/setup.py (original) +++ bloodhound/trunk/bloodhound_relations/setup.py Tue May 7 09:05:30 2013 @@ -105,8 +105,9 @@ ENTRY_POINTS = { 'trac.plugins': [ 'bhrelations.api = bhrelations.api', 'bhrelations.web_ui = bhrelations.web_ui', +'bhrelations.widgets.ticketrelations = bhrelations.widgets.relations', ], -} +} setup( name=DIST_NM, version=latest,
svn commit: r1476922 - in /bloodhound/trunk/bloodhound_multiproduct/tests: core.py perm.py upgrade.py upgrade_postgres.py
Author: astaric Date: Mon Apr 29 08:48:39 2013 New Revision: 1476922 URL: http://svn.apache.org/r1476922 Log: Python2.6 compatibility. Modified: bloodhound/trunk/bloodhound_multiproduct/tests/core.py bloodhound/trunk/bloodhound_multiproduct/tests/perm.py bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py bloodhound/trunk/bloodhound_multiproduct/tests/upgrade_postgres.py Modified: bloodhound/trunk/bloodhound_multiproduct/tests/core.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/tests/core.py?rev=1476922r1=1476921r2=1476922view=diff == --- bloodhound/trunk/bloodhound_multiproduct/tests/core.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/tests/core.py Mon Apr 29 08:48:39 2013 @@ -15,7 +15,11 @@ # specific language governing permissions and limitations # under the License. -import unittest +import sys +if sys.version (2, 7): +import unittest2 as unittest +else: +import unittest from trac.core import Interface, implements, Component Modified: bloodhound/trunk/bloodhound_multiproduct/tests/perm.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/tests/perm.py?rev=1476922r1=1476921r2=1476922view=diff == --- bloodhound/trunk/bloodhound_multiproduct/tests/perm.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/tests/perm.py Mon Apr 29 08:48:39 2013 @@ -35,6 +35,10 @@ from multiproduct.model import Product from multiproduct.perm import MultiproductPermissionPolicy, sudo from tests.env import MultiproductTestCase +# DefaultPermission policy has its own cache that causes +# test_product_trac_admin_actions to fail sometimes. +perm.DefaultPermissionPolicy.CACHE_EXPIRY = 0 + class ProductDefaultPermissionStoreTestCase(DefaultPermissionStoreTestCase, MultiproductTestCase): Modified: bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py?rev=1476922r1=1476921r2=1476922view=diff == --- bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py Mon Apr 29 08:48:39 2013 @@ -21,9 +21,13 @@ from sqlite3 import OperationalError from contextlib import contextmanager import os import shutil +import sys import tempfile -import unittest import uuid +if sys.version_info (2, 7): +import unittest2 as unittest +else: +import unittest from trac.attachment import Attachment, AttachmentAdmin from trac.core import Component, implements Modified: bloodhound/trunk/bloodhound_multiproduct/tests/upgrade_postgres.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/tests/upgrade_postgres.py?rev=1476922r1=1476921r2=1476922view=diff == --- bloodhound/trunk/bloodhound_multiproduct/tests/upgrade_postgres.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/tests/upgrade_postgres.py Mon Apr 29 08:48:39 2013 @@ -31,7 +31,11 @@ except Exception as err: database_available = False from contextlib import contextmanager -import unittest +import sys +if sys.version_info (2, 7): +import unittest2 as unittest +else: +import unittest import upgrade
svn commit: r1476926 - in /bloodhound/trunk/bloodhound_search/bhsearch/tests: __init__.py base.py search_resources/base.py web_ui.py whoosh_backend.py
Author: astaric Date: Mon Apr 29 08:57:19 2013 New Revision: 1476926 URL: http://svn.apache.org/r1476926 Log: Python2.6 compatibility for bhsearch tests. Modified: bloodhound/trunk/bloodhound_search/bhsearch/tests/__init__.py bloodhound/trunk/bloodhound_search/bhsearch/tests/base.py bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/base.py bloodhound/trunk/bloodhound_search/bhsearch/tests/web_ui.py bloodhound/trunk/bloodhound_search/bhsearch/tests/whoosh_backend.py Modified: bloodhound/trunk/bloodhound_search/bhsearch/tests/__init__.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_search/bhsearch/tests/__init__.py?rev=1476926r1=1476925r2=1476926view=diff == --- bloodhound/trunk/bloodhound_search/bhsearch/tests/__init__.py (original) +++ bloodhound/trunk/bloodhound_search/bhsearch/tests/__init__.py Mon Apr 29 08:57:19 2013 @@ -17,7 +17,12 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import unittest +import sys +if sys.version (2, 7): +import unittest2 as unittest +else: +import unittest + from bhsearch.tests import (whoosh_backend, index_with_whoosh, web_ui, api, query_parser, query_suggestion, security) from bhsearch.tests.search_resources import (ticket_search, wiki_search, Modified: bloodhound/trunk/bloodhound_search/bhsearch/tests/base.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_search/bhsearch/tests/base.py?rev=1476926r1=1476925r2=1476926view=diff == --- bloodhound/trunk/bloodhound_search/bhsearch/tests/base.py (original) +++ bloodhound/trunk/bloodhound_search/bhsearch/tests/base.py Mon Apr 29 08:57:19 2013 @@ -22,9 +22,14 @@ r Test utils methods import contextlib -import unittest -import tempfile import shutil +import sys +import tempfile +if sys.version (2, 7): +import unittest2 as unittest +else: +import unittest + from bhsearch.web_ui import BloodhoundSearchModule from trac.ticket import Ticket, Milestone Modified: bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/base.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/base.py?rev=1476926r1=1476925r2=1476926view=diff == --- bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/base.py (original) +++ bloodhound/trunk/bloodhound_search/bhsearch/tests/search_resources/base.py Mon Apr 29 08:57:19 2013 @@ -18,7 +18,12 @@ # specific language governing permissions and limitations # under the License. -import unittest +import sys +if sys.version (2, 7): +import unittest2 as unittest +else: +import unittest + from bhsearch.search_resources.base import SimpleSearchWikiSyntaxFormatter from bhsearch.tests.base import BaseBloodhoundSearchTest from trac.web import Href Modified: bloodhound/trunk/bloodhound_search/bhsearch/tests/web_ui.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_search/bhsearch/tests/web_ui.py?rev=1476926r1=1476925r2=1476926view=diff == --- bloodhound/trunk/bloodhound_search/bhsearch/tests/web_ui.py (original) +++ bloodhound/trunk/bloodhound_search/bhsearch/tests/web_ui.py Mon Apr 29 08:57:19 2013 @@ -17,7 +17,11 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -import unittest +import sys +if sys.version (2, 7): +import unittest2 as unittest +else: +import unittest from urllib import urlencode, unquote, unquote_plus Modified: bloodhound/trunk/bloodhound_search/bhsearch/tests/whoosh_backend.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_search/bhsearch/tests/whoosh_backend.py?rev=1476926r1=1476925r2=1476926view=diff == --- bloodhound/trunk/bloodhound_search/bhsearch/tests/whoosh_backend.py (original) +++ bloodhound/trunk/bloodhound_search/bhsearch/tests/whoosh_backend.py Mon Apr 29 08:57:19 2013 @@ -19,9 +19,14 @@ # under the License. from datetime import datetime import os -import unittest -import tempfile import shutil +import sys +import tempfile +if sys.version (2, 7): +import unittest2 as unittest +else: +import unittest + from bhsearch.api import ASC, DESC, SCORE, SortInstruction from bhsearch.query_parser import DefaultQueryParser from bhsearch.tests.base import BaseBloodhoundSearchTest
svn commit: r1476944 - in /bloodhound/trunk/bloodhound_multiproduct: multiproduct/api.py tests/upgrade.py
Author: astaric Date: Mon Apr 29 09:45:38 2013 New Revision: 1476944 URL: http://svn.apache.org/r1476944 Log: Upgrade to multiproduct moves all wikis to the default product. Modified: bloodhound/trunk/bloodhound_multiproduct/multiproduct/api.py bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py Modified: bloodhound/trunk/bloodhound_multiproduct/multiproduct/api.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/multiproduct/api.py?rev=1476944r1=1476943r2=1476944view=diff == --- bloodhound/trunk/bloodhound_multiproduct/multiproduct/api.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/multiproduct/api.py Mon Apr 29 09:45:38 2013 @@ -225,7 +225,7 @@ class MultiProductSystem(Component): self._insert_default_product(db) self._upgrade_tickets(db, TICKET_TABLES, create_temp_table) -self._upgrade_wikis(db, create_temp_table, table_columns) +self._upgrade_wikis(db, create_temp_table) self._upgrade_system_tables(db, create_temp_table) self._soft_link_repositories_to_default_product(db) self._upgrade_table_system(SYSTEM_TABLES, create_temp_table, db) @@ -380,76 +380,31 @@ class MultiProductSystem(Component): (table, cols, cols, '', temp_table_name)) self._drop_temp_table(db, temp_table_name) -def _upgrade_wikis(self, db, create_temp_table, - table_columns): +def _upgrade_wikis(self, db, create_temp_table): # migrate wiki table # - populate system wikis to all products + global scope # - update wiki attachment product to match wiki product table = 'wiki' temp_table_name, cols = create_temp_table(table) -self.log.info(Migrating wikis to global context) -db(INSERT INTO %s (%s, product) SELECT %s, '' FROM %s % - (table, cols, cols, temp_table_name)) +self.log.info(Migrating wikis to default product) +db(INSERT INTO %(table)s (%(cols)s, product) + SELECT %(cols)s, '%(default_product)s' FROM %(temp_table)s +% dict(table=table, + temp_table=temp_table_name, + cols=cols, + default_product=DEFAULT_PRODUCT,)) db(UPDATE attachment - SET product='' - WHERE attachment.type='wiki') -for wiki_name, wiki_version, wiki_product in db( -SELECT name, version, product FROM %s % table): -attachment_cols = ','.join(table_columns['attachment']) -if wiki_name in self.system_wiki_list: -for product in Product.select(self.env): -db(INSERT INTO %s (%s, product) - SELECT %s, '%s' FROM %s - WHERE name='%s' AND version=%s AND product='%s' % - (table, cols, cols, product.prefix, table, -wiki_name, wiki_version, wiki_product)) -db(INSERT INTO attachment (%(cols)s, product) - SELECT %(cols)s, '%(new_product)s' -FROM attachment a - WHERE type='wiki' - AND id='%(wiki_name)s' - AND product='%(old_product)s' - AND NOT EXISTS(SELECT * FROM attachment - WHERE type='wiki' - AND id='%(wiki_name)s' - AND product='%(new_product)s') -% dict(cols=attachment_cols, - wiki_name=wiki_name, - old_product=wiki_product, - new_product=product.prefix)) -self._migrate_attachments( -db(SELECT type, id, filename -FROM attachment - WHERE type='wiki' - AND id='%s' - AND product='%s' -% (wiki_name, DEFAULT_PRODUCT)), -to_product=DEFAULT_PRODUCT, -copy=True -) -else: -self.log.info(Moving wiki page '%s' to default product, - wiki_name) -db(UPDATE wiki - SET product='%s' - WHERE name='%s' AND version=%s AND product='%s' -% (DEFAULT_PRODUCT
svn commit: r1476118 - in /bloodhound/trunk/bloodhound_multiproduct: multiproduct/api.py tests/upgrade.py
Author: astaric Date: Fri Apr 26 09:10:14 2013 New Revision: 1476118 URL: http://svn.apache.org/r1476118 Log: Added more tests for multiproduct upgrade, refactoring. Modified: bloodhound/trunk/bloodhound_multiproduct/multiproduct/api.py bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py Modified: bloodhound/trunk/bloodhound_multiproduct/multiproduct/api.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/multiproduct/api.py?rev=1476118r1=1476117r2=1476118view=diff == --- bloodhound/trunk/bloodhound_multiproduct/multiproduct/api.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/multiproduct/api.py Fri Apr 26 09:10:14 2013 @@ -30,6 +30,7 @@ from trac.attachment import Attachment from trac.config import Option, PathOption from trac.core import Component, TracError, implements, Interface from trac.db import Table, Column, DatabaseManager, Index +import trac.db_default from trac.env import IEnvironmentSetupParticipant, Environment from trac.perm import IPermissionRequestor, PermissionCache from trac.resource import IExternalResourceConnector, IResourceChangeListener,\ @@ -97,7 +98,7 @@ class MultiProductSystem(Component): global environment configuration. ) -SCHEMA = [mcls._get_schema() \ +SCHEMA = [mcls._get_schema() for mcls in (Product, ProductResourceMap)] # Tables which should be migrated (extended with 'product' column) @@ -202,171 +203,207 @@ class MultiProductSystem(Component): db_installed_version = self.get_version() with self.env.db_direct_transaction as db: if db_installed_version 1: -# Initial installation -db(ALTER TABLE ticket ADD COLUMN product TEXT) -self.log.debug(creating initial db tables for %s plugin. % - PLUGIN_NAME) -db_connector, dummy = DatabaseManager(self.env)._get_connector() -for table in self.SCHEMA: -for statement in db_connector.to_sql(table): -db(statement) +self._add_column_product_to_ticket(db) +self._create_multiproduct_tables(db) db_installed_version = self._update_db_version(db, 1) if db_installed_version 2: -from multiproduct.model import Product -products = Product.select(self.env) -for prod in products: -db(UPDATE ticket SET product=%s - WHERE product=%s, (prod.prefix, prod.name)) +self._replace_product_on_ticket_with_product_prefix(db) db_installed_version = self._update_db_version(db, 2) if db_installed_version 3: -from multiproduct.model import Product -import trac.db_default - -def create_temp_table(table): -creates temporary table with the new schema and -drops original table -table_temp_name = '%s_temp' % table -if table == 'report': -cols = ','.join([c for c in table_columns[table] if c != 'id']) -else: -cols = ','.join(table_columns[table]) -self.log.info(Migrating table '%s' to a new schema, table) -db(CREATE TABLE %s AS SELECT %s FROM %s % - (table_temp_name, cols, table)) -db(DROP TABLE %s % table) -db_connector, _ = DatabaseManager(self.env)._get_connector() -table_schema = [t for t in table_defs if t.name == table][0] -for sql in db_connector.to_sql(table_schema): -db(sql) -return table_temp_name, cols - -def drop_temp_table(table): -drops specified temporary table -db(DROP TABLE %s % table) - -TICKET_TABLES = ['ticket_change', 'ticket_custom', - 'attachment', -] SYSTEM_TABLES = ['system'] +TICKET_TABLES = [ +'ticket_change', 'ticket_custom', 'attachment', +] +table_defs = self._add_product_column_to_tables( +self.MIGRATE_TABLES + TICKET_TABLES + SYSTEM_TABLES, +db_installed_version) +table_columns = self._get_table_columns(table_defs) +create_temp_table = lambda table: self._create_temp_table( +db, table, table_columns, table_defs) + +self._insert_default_product(db) +self._upgrade_tickets(db, TICKET_TABLES, create_temp_table) +self._upgrade_wikis
svn commit: r1476152 - in /bloodhound/trunk/bloodhound_multiproduct/tests: upgrade.py upgrade_postgres.py
Author: astaric Date: Fri Apr 26 11:56:33 2013 New Revision: 1476152 URL: http://svn.apache.org/r1476152 Log: Added upgrade tests for postgres backend. Added: bloodhound/trunk/bloodhound_multiproduct/tests/upgrade_postgres.py Modified: bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py Modified: bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py?rev=1476152r1=1476151r2=1476152view=diff == --- bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py Fri Apr 26 11:56:33 2013 @@ -20,6 +20,7 @@ from sqlite3 import OperationalError from contextlib import contextmanager import os +import shutil import tempfile import unittest import uuid @@ -51,23 +52,25 @@ TABLES_WITH_PRODUCT_FIELD = ( class EnvironmentUpgradeTestCase(unittest.TestCase): -def setUp(self): +def setUp(self, options=()): self.env_path = tempfile.mkdtemp('multiproduct-tempenv') -self.env = Environment(self.env_path, create=True) +self.env = Environment(self.env_path, create=True, options=options) DummyPlugin.version = 1 +def tearDown(self): +shutil.rmtree(self.env_path) + def test_can_upgrade_environment_with_multi_product_disabled(self): self.env.upgrade() # Multiproduct was not enabled so multiproduct tables should not exist -with self.env.db_direct_transaction as db: -for table in BLOODHOUND_TABLES: -with self.assertFailsWithMissingTable(): -db(SELECT * FROM %s % table) +for table in BLOODHOUND_TABLES: +with self.assertFailsWithMissingTable(): +self.env.db_direct_query(SELECT * FROM %s % table) -for table in TABLES_WITH_PRODUCT_FIELD: -with self.assertFailsWithMissingColumn(): -db(SELECT product FROM %s % table) +for table in TABLES_WITH_PRODUCT_FIELD: +with self.assertFailsWithMissingColumn(): +self.env.db_direct_query(SELECT product FROM %s % table) def test_upgrade_creates_multi_product_tables_and_adds_product_column(self): self._enable_multiproduct() @@ -91,8 +94,8 @@ class EnvironmentUpgradeTestCase(unittes self._add_custom_field('custom_field') with self.env.db_direct_transaction as db: db(INSERT INTO ticket (id) VALUES (1)) -db(INSERT INTO attachment (type, id) - VALUES ('ticket', '1')) +db(INSERT INTO attachment (type, id, filename) + VALUES ('ticket', '1', '')) db(INSERT INTO ticket_custom (ticket, name, value) VALUES (1, 'custom_field', '42')) db(INSERT INTO ticket_change (ticket, time, field) @@ -114,8 +117,8 @@ class EnvironmentUpgradeTestCase(unittes def test_upgrade_moves_custom_wikis_to_default_product(self): with self.env.db_direct_transaction as db: db(INSERT INTO wiki (name, version) VALUES ('MyPage', 1)) -db(INSERT INTO attachment (type, id) - VALUES ('wiki', 'MyPage')) +db(INSERT INTO attachment (type, id, filename) + VALUES ('wiki', 'MyPage', '')) self._enable_multiproduct() self.env.upgrade() @@ -131,8 +134,8 @@ class EnvironmentUpgradeTestCase(unittes def test_upgrade_duplicates_system_wikis_to_products(self): with self.env.db_direct_transaction as db: db(INSERT INTO wiki (name, version) VALUES ('WikiStart', 1)) -db(INSERT INTO attachment (type, id) - VALUES ('wiki', 'WikiStart')) +db(INSERT INTO attachment (type, id, filename) + VALUES ('wiki', 'WikiStart', '')) self._enable_multiproduct() self.env.upgrade() @@ -227,18 +230,18 @@ class EnvironmentUpgradeTestCase(unittes def test_can_upgrade_database_with_ticket_attachment_with_text_ids(self): with self.env.db_direct_transaction as db: -db(INSERT INTO attachment (id, type) - VALUES ('abc', 'ticket')) +db(INSERT INTO attachment (id, type, filename) + VALUES ('abc', 'ticket', '')) self._enable_multiproduct() self.env.upgrade() def test_can_upgrade_database_with_orphaned_attachments(self): with self.env.db_direct_transaction as db: -db(INSERT INTO attachment (id, type) - VALUES ('5', 'ticket')) -db(INSERT INTO attachment (id, type) - VALUES ('MyWiki', 'wiki')) +db(INSERT INTO attachment (id, type, filename) + VALUES ('5', 'ticket
svn commit: r1475690 - in /bloodhound/trunk/bloodhound_multiproduct: multiproduct/api.py tests/upgrade.py
Author: astaric Date: Thu Apr 25 10:21:14 2013 New Revision: 1475690 URL: http://svn.apache.org/r1475690 Log: Move/copy attachment files when migrating attachments during the upgrade. Modified: bloodhound/trunk/bloodhound_multiproduct/multiproduct/api.py bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py Modified: bloodhound/trunk/bloodhound_multiproduct/multiproduct/api.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/multiproduct/api.py?rev=1475690r1=1475689r2=1475690view=diff == --- bloodhound/trunk/bloodhound_multiproduct/multiproduct/api.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/multiproduct/api.py Thu Apr 25 10:21:14 2013 @@ -20,11 +20,13 @@ import copy import os +import shutil from genshi.builder import tag, Element from genshi.core import escape, Markup, unescape from pkg_resources import resource_filename +from trac.attachment import Attachment from trac.config import Option, PathOption from trac.core import Component, TracError, implements, Interface from trac.db import Table, Column, DatabaseManager, Index @@ -284,6 +286,14 @@ class MultiProductSystem(Component): self.log.info(Migrating tickets w/o product to default product) db(UPDATE ticket SET product='%s' WHERE (product IS NULL OR product='') % DEFAULT_PRODUCT) +self._migrate_attachments( +db(SELECT a.type, a.id, a.filename +FROM attachment a + INNER JOIN ticket t ON a.id = %(t.id)s + WHERE a.type='ticket' +% {'t.id': db.cast('t.id', 'text')}), +to_product=DEFAULT_PRODUCT +) self.log.info(Migrating ticket tables to a new schema) for table in TICKET_TABLES: @@ -370,19 +380,39 @@ class MultiProductSystem(Component): wiki_name=wiki_name, old_product=wiki_product, new_product=product.prefix)) +self._migrate_attachments( +db(SELECT type, id, filename +FROM attachment + WHERE type='wiki' + AND id='%s' + AND product='%s' +% (wiki_name, DEFAULT_PRODUCT)), +to_product=DEFAULT_PRODUCT, +copy=True +) else: self.log.info(Moving wiki page '%s' to default product, wiki_name) db(UPDATE wiki SET product='%s' - WHERE name='%s' AND version=%s AND product='%s' % - (DEFAULT_PRODUCT, - wiki_name, wiki_version, wiki_product)) + WHERE name='%s' AND version=%s AND product='%s' +% (DEFAULT_PRODUCT, + wiki_name, wiki_version, wiki_product)) db(UPDATE attachment SET product='%s' WHERE type='wiki' AND id='%s' AND product='%s' % (DEFAULT_PRODUCT, wiki_name, wiki_product)) +self._migrate_attachments( +db(SELECT type, id, filename +FROM attachment + WHERE type='wiki' + AND id='%s' + AND product='%s' +% (wiki_name, DEFAULT_PRODUCT)), +to_product=DEFAULT_PRODUCT, +) + drop_temp_table(temp_table_name) # soft link existing repositories to default product @@ -434,6 +464,39 @@ class MultiProductSystem(Component): self.env.enable_multiproduct_schema(True) +def _migrate_attachments(self, attachments, to_product=None, copy=False): +for type, id, filename in attachments: +old_path = Attachment._get_path(self.env.path, type, id, filename) +new_path = self.env.path +if to_product: +new_path = os.path.join(new_path, 'products', to_product) +new_path = Attachment._get_path(new_path, type, id, filename) +dirname = os.path.dirname(new_path) +if not os.path.exists(old_path): +self.log.warning
svn commit: r1470836 - /bloodhound/trunk/bloodhound_multiproduct/tests/__init__.py
Author: astaric Date: Tue Apr 23 07:26:10 2013 New Revision: 1470836 URL: http://svn.apache.org/r1470836 Log: Fixed test discovery for cases when subfolder is prefixed with '.'. Modified: bloodhound/trunk/bloodhound_multiproduct/tests/__init__.py Modified: bloodhound/trunk/bloodhound_multiproduct/tests/__init__.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/tests/__init__.py?rev=1470836r1=1470835r2=1470836view=diff == --- bloodhound/trunk/bloodhound_multiproduct/tests/__init__.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/tests/__init__.py Tue Apr 23 07:26:10 2013 @@ -52,7 +52,7 @@ class TestLoader(unittest.TestLoader): mdlnm, loader, isdir = pending.popleft() try: mdl = self._get_module_from_name(mdlnm) -except ImportError: +except (ImportError, ValueError): # Skip packages not having __init__.py continue loader = getattr(mdl, self.testLoaderAttribute, None) or loader @@ -75,6 +75,7 @@ class TestLoader(unittest.TestLoader): __import__(name) return sys.modules[name] + def test_suite(): return TestLoader().discover_package('tests', pattern='*.py')
svn commit: r1470886 - in /bloodhound/trunk/bloodhound_multiproduct: multiproduct/dbcursor.py tests/db/cursor.py
Author: astaric Date: Tue Apr 23 10:48:22 2013 New Revision: 1470886 URL: http://svn.apache.org/r1470886 Log: Wrap table names in . Tables prefixes for default product cannot be used unquoted. Modified: bloodhound/trunk/bloodhound_multiproduct/multiproduct/dbcursor.py bloodhound/trunk/bloodhound_multiproduct/tests/db/cursor.py Modified: bloodhound/trunk/bloodhound_multiproduct/multiproduct/dbcursor.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/multiproduct/dbcursor.py?rev=1470886r1=1470885r2=1470886view=diff == --- bloodhound/trunk/bloodhound_multiproduct/multiproduct/dbcursor.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/multiproduct/dbcursor.py Tue Apr 23 10:48:22 2013 @@ -262,7 +262,7 @@ class BloodhoundProductSQLTranslate(obje return sql def _prefixed_table_entity_name(self, tablename): -return %s_%s % (self._product_prefix, tablename) if self._product_prefix else tablename +return '%s_%s' % (self._product_prefix, tablename) if self._product_prefix else tablename def _prefixed_table_view_sql(self, name, alias): return '(SELECT * FROM %s) AS %s' % (self._prefixed_table_entity_name(name), Modified: bloodhound/trunk/bloodhound_multiproduct/tests/db/cursor.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/tests/db/cursor.py?rev=1470886r1=1470885r2=1470886view=diff == --- bloodhound/trunk/bloodhound_multiproduct/tests/db/cursor.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/tests/db/cursor.py Tue Apr 23 10:48:22 2013 @@ -502,7 +502,7 @@ data = { summary, description, keywords, product) SELECT id, 'defect', time, changetime, component, severity, priority, owner, reporter, cc, version, milestone, status, resolution, summary, - description, keywords, 'PRODUCT' FROM (SELECT * FROM PRODUCT_ticket_old) AS ticket_old + description, keywords, 'PRODUCT' FROM (SELECT * FROM PRODUCT_ticket_old) AS ticket_old WHERE COALESCE(severity,'') 'enhancement' ), ( @@ -518,7 +518,7 @@ data = { summary, description, keywords, product) SELECT id, 'enhancement', time, changetime, component, 'normal', priority, owner, reporter, cc, version, milestone, status, resolution, summary, - description, keywords, 'PRODUCT' FROM (SELECT * FROM PRODUCT_ticket_old) AS ticket_old + description, keywords, 'PRODUCT' FROM (SELECT * FROM PRODUCT_ticket_old) AS ticket_old WHERE severity = 'enhancement' ), ( @@ -596,7 +596,7 @@ data = { GROUP BY bklg_id , SELECT bklg_id, count(*) as total -FROM (SELECT * FROM PRODUCT_backlog_ticket) AS backlog_ticket +FROM (SELECT * FROM PRODUCT_backlog_ticket) AS backlog_ticket WHERE tkt_order IS NULL OR tkt_order -1 GROUP BY bklg_id @@ -608,7 +608,7 @@ data = { AND (bt.tkt_order IS NULL OR bt.tkt_order -1) GROUP BY bklg_id, status, SELECT bt.bklg_id, t.status, count(*) as total -FROM (SELECT * FROM PRODUCT_backlog_ticket) AS bt, (SELECT * FROM ticket WHERE product='PRODUCT') AS t +FROM (SELECT * FROM PRODUCT_backlog_ticket) AS bt, (SELECT * FROM ticket WHERE product='PRODUCT') AS t WHERE t.id = bt.tkt_id AND (bt.tkt_order IS NULL OR bt.tkt_order -1) GROUP BY bklg_id, status @@ -651,7 +651,7 @@ data = { WHERE s.sid IS NOT NULL, INSERT INTO session (sid, last_visit, authenticated) SELECT distinct s.sid,COALESCE(%s,0),s.authenticated -FROM (SELECT * FROM PRODUCT_session_old) AS s LEFT JOIN (SELECT * FROM PRODUCT_session_old) AS s2 +FROM (SELECT * FROM PRODUCT_session_old) AS s LEFT JOIN (SELECT * FROM PRODUCT_session_old) AS s2 ON (s.sid=s2.sid AND s2.var_name='last_visit') WHERE s.sid IS NOT NULL ), @@ -662,7 +662,7 @@ data = { WHERE s.var_name 'last_visit' AND s.sid IS NOT NULL, INSERT INTO session_attribute (sid, authenticated, name, value) SELECT s.sid, s.authenticated, s.var_name, s.var_value -FROM (SELECT * FROM PRODUCT_session_old) AS s +FROM (SELECT * FROM PRODUCT_session_old) AS s WHERE s.var_name 'last_visit' AND s.sid IS NOT NULL ), ( @@ -688,7 +688,7 @@ data = { INSERT INTO node_change (rev,path,kind,change,base_path,base_rev) SELECT rev,path,kind,change,base_path,base_rev FROM node_change_old, INSERT INTO node_change (rev,path,kind,change,base_path,base_rev) -SELECT rev,path,kind,change,base_path,base_rev FROM (SELECT * FROM PRODUCT_node_change_old) AS node_change_old
svn commit: r1470952 - in /bloodhound/trunk/bloodhound_multiproduct: multiproduct/env.py tests/upgrade.py
Author: astaric Date: Tue Apr 23 13:44:14 2013 New Revision: 1470952 URL: http://svn.apache.org/r1470952 Log: Refactored environment upgrade and added tests. Added: bloodhound/trunk/bloodhound_multiproduct/tests/upgrade.py Modified: bloodhound/trunk/bloodhound_multiproduct/multiproduct/env.py Modified: bloodhound/trunk/bloodhound_multiproduct/multiproduct/env.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_multiproduct/multiproduct/env.py?rev=1470952r1=1470951r2=1470952view=diff == --- bloodhound/trunk/bloodhound_multiproduct/multiproduct/env.py (original) +++ bloodhound/trunk/bloodhound_multiproduct/multiproduct/env.py Tue Apr 23 13:44:14 2013 @@ -42,6 +42,7 @@ from multiproduct.model import Product import trac.env + class ComponentEnvironmentContext(object): def __init__(self, env, component): self._env = env @@ -53,6 +54,7 @@ class ComponentEnvironmentContext(object def __exit__(self, type, value, traceback): self._old_env.component_activated(self._component) + class Environment(trac.env.Environment): Bloodhound environment manager @@ -72,6 +74,39 @@ class Environment(trac.env.Environment): multi_product_support_components = ExtensionPoint(ISupportMultiProductEnvironment) +@property +def global_setup_participants(self): +If multi product schema is enabled, return only setup participants +that implement ISupportMultiProduct. Otherwise, all setup participants +are considered global. + +if self._multiproduct_schema_enabled: +all_participants = self.setup_participants +multiproduct_aware = set(self.multi_product_support_components) +priority = lambda x: 0 if isinstance(x, MultiProductSystem) else 10 + +return sorted( +(c for c in all_participants if c in multiproduct_aware), +key=priority +) +else: +return self.setup_participants + +@property +def product_setup_participants(self): +If multi product schema is enabled, return setup participants that +need to be instantiated for each product env. Otherwise, return an +empty list. + +if self._multiproduct_schema_enabled: +all_participants = self.setup_participants +multiproduct_aware = set(self.multi_product_support_components) +return [ +c for c in all_participants if c not in multiproduct_aware +] +else: +return [] + def __init__(self, path, create=False, options=[]): # global environment w/o parent, set these two before super.__init__ # as database access can take place within trac.env.Environment @@ -95,29 +130,10 @@ class Environment(trac.env.Environment): self.verify() self.setup_config() -self._global_setup_participants = list(set.intersection(set(self.setup_participants), - set(self.multi_product_support_components))) -# make sure MultiProductSystem is always the first in the global setup -# participant list -for idx, participant in zip(range(0, len(self._global_setup_participants)), -self._global_setup_participants): -if isinstance(participant, MultiProductSystem): -if not idx: -break -self._global_setup_participants.insert(0, - self._global_setup_participants.pop(idx)) -break - -self._product_setup_participants = [participant for participant in self.setup_participants -if not participant in self._global_setup_participants] - # invoke `IEnvironmentSetupParticipant.environment_created` for all # global setup participants if create: -# when creating environment, run global setup participants if schema has been upgraded -# to multi-product. If not, run setup participants ... -for participant in self._global_setup_participants if self._multiproduct_schema_enabled \ - else self.setup_participants: +for participant in self.global_setup_participants: with ComponentEnvironmentContext(self, participant): participant.environment_created() @@ -144,28 +160,24 @@ class Environment(trac.env.Environment): def needs_upgrade(self): Return whether the environment needs to be upgraded. -def needs_upgrade_in_env_list(env_list, participants): -for env in env_list: -for participant in participants: -# make
svn commit: r1470615 - /bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py
Author: astaric Date: Mon Apr 22 16:44:22 2013 New Revision: 1470615 URL: http://svn.apache.org/r1470615 Log: Fixed QuickLink search in default product. Part of #450. Modified: bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py Modified: bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py URL: http://svn.apache.org/viewvc/bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py?rev=1470615r1=1470614r2=1470615view=diff == --- bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py (original) +++ bloodhound/trunk/bloodhound_search/bhsearch/web_ui.py Mon Apr 22 16:44:22 2013 @@ -558,7 +558,9 @@ class RequestContext(object): description = link.attrib.get('title', '') if quickjump_href: # Only automatically redirect to local quickjump links -if not quickjump_href.startswith(req.base_path or '/'): +base_path = req.base_path.replace('@', '%40') +redirect_href = quickjump_href.replace('@', '%40') +if not redirect_href.startswith(base_path or '/'): noquickjump = True if noquickjump: return {'href': quickjump_href, 'name': tag.EM(name),