Merge lp:~gmb/lp2kanban/bug-1112622 into lp:~launchpad/lp2kanban/trunk

Proposed by Graham Binns
Status: Merged
Approved by: Brad Crittenden
Approved revision: 74
Merged at revision: 73
Proposed branch: lp:~gmb/lp2kanban/bug-1112622
Merge into: lp:~launchpad/lp2kanban/trunk
Diff against target: 158 lines (+77/-4)
5 files modified
src/lp2kanban/bugs2cards.py (+2/-1)
src/lp2kanban/cards2workitems.py (+15/-0)
src/lp2kanban/kanban.py (+2/-1)
src/lp2kanban/tests/common.py (+10/-1)
src/lp2kanban/tests/test_cards2workitems.py (+48/-1)
To merge this branch: bzr merge lp:~gmb/lp2kanban/bug-1112622
Reviewer Review Type Date Requested Status
Brad Crittenden (community) code Approve
Review via email: mp+153763@code.launchpad.net

Commit message

We now sync cards with blueprints based on their description annotations _or_ external_system_url.

Description of the change

This branch makes the blueprint syncing code use either the external_system_url of a card _or_ its description annotations to decide whether it should be synced. This prevents syncing from getting clobbered by merge proposals.

To post a comment you must log in.
Revision history for this message
Brad Crittenden (bac) wrote :

Looks good Graham. One typo to fix: blueoprint

review: Approve (code)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/lp2kanban/bugs2cards.py'
2--- src/lp2kanban/bugs2cards.py 2013-03-05 20:42:37 +0000
3+++ src/lp2kanban/bugs2cards.py 2013-03-18 11:38:32 +0000
4@@ -6,6 +6,7 @@
5 from launchpadlib.launchpad import Launchpad
6 from lp2kanban.cards2workitems import (
7 convert_cards_to_work_items,
8+ get_blueprint_linked_cards,
9 update_blueprints_from_work_items,
10 )
11 from lp2kanban.kanban import (
12@@ -439,7 +440,7 @@
13 if bconf.get("convert_cards_to_work_items", False) == "on":
14 # Sync cards to blueprint work items, if so configured.
15 print " Checking for cards to sync with work items..."
16- cards_to_convert = board.getCardsWithExternalLinks()
17+ cards_to_convert = get_blueprint_linked_cards(board)
18 work_items = convert_cards_to_work_items(
19 cards_to_convert, board, lp_users)
20 if len(work_items) == 0:
21
22=== modified file 'src/lp2kanban/cards2workitems.py'
23--- src/lp2kanban/cards2workitems.py 2013-01-19 13:36:31 +0000
24+++ src/lp2kanban/cards2workitems.py 2013-03-18 11:38:32 +0000
25@@ -105,3 +105,18 @@
26 len(work_items), blueprint.name)
27 blueprint.workitems_text = work_items_text
28 blueprint.lp_save()
29+
30+
31+def get_blueprint_linked_cards(board):
32+ """Return the cards on `board` that need to be converted."""
33+ blueprint_linked_cards = set()
34+ for card in board.getCardsWithDescriptionAnnotations():
35+ blueprint_url = card.description_annotations.get(
36+ 'blueprint_url', None)
37+ if blueprint_url is not None:
38+ blueprint_linked_cards.add(card)
39+ blueprint_url_pattern = re.compile(BLUEPRINT_URL_PATTERN)
40+ for card in board.getCardsWithExternalLinks():
41+ if blueprint_url_pattern.match(card.external_system_url):
42+ blueprint_linked_cards.add(card)
43+ return blueprint_linked_cards
44
45=== modified file 'src/lp2kanban/kanban.py'
46--- src/lp2kanban/kanban.py 2013-03-15 07:57:56 +0000
47+++ src/lp2kanban/kanban.py 2013-03-18 11:38:32 +0000
48@@ -480,7 +480,8 @@
49 "/Board/" + str(self.id) + "/Archive").ReplyData[0]
50 archive_lanes = [lane_dict['Lane'] for lane_dict in self._archive]
51 archive_lanes.extend(
52- [lane_dict['Lane'] for lane_dict in self._archive[0]['ChildLanes']])
53+ [lane_dict['Lane'] for
54+ lane_dict in self._archive[0]['ChildLanes']])
55 self._backlog = self.connector.get(
56 "/Board/" + str(self.id) + "/Backlog").ReplyData[0]
57 self._populateLanes(
58
59=== modified file 'src/lp2kanban/tests/common.py'
60--- src/lp2kanban/tests/common.py 2013-02-01 14:52:54 +0000
61+++ src/lp2kanban/tests/common.py 2013-03-18 11:38:32 +0000
62@@ -18,12 +18,21 @@
63
64 class FauxBoard:
65
66- def __init__(self, cards, users_by_id=None, default_cardtype=None, is_archived=False):
67+ def __init__(self, cards, users_by_id=None, default_cardtype=None,
68+ is_archived=False):
69 self.cards = cards
70 self.users_by_id = users_by_id
71 self.default_cardtype = default_cardtype or FauxCardType()
72 self.cardtypes = {1: FauxCardType()}
73 self.is_archived = is_archived
74+ self._cards_with_description_annotations = set()
75+ self._cards_with_external_links = set()
76+
77+ def getCardsWithDescriptionAnnotations(self):
78+ return self._cards_with_description_annotations
79+
80+ def getCardsWithExternalLinks(self):
81+ return self._cards_with_external_links
82
83
84 class FauxLane:
85
86=== modified file 'src/lp2kanban/tests/test_cards2workitems.py'
87--- src/lp2kanban/tests/test_cards2workitems.py 2013-02-01 14:52:54 +0000
88+++ src/lp2kanban/tests/test_cards2workitems.py 2013-03-18 11:38:32 +0000
89@@ -9,6 +9,7 @@
90 LANE_TYPE_TO_WORK_ITEM_STATUS_MAP,
91 convert_card_to_work_item,
92 convert_cards_to_work_items,
93+ get_blueprint_linked_cards,
94 update_blueprints_from_work_items,
95 )
96 from lp2kanban.kanban import (
97@@ -65,10 +66,12 @@
98 blueprint_url=self.blueprint_url)
99 if title is None:
100 title = "A card"
101- return FauxCard(
102+ card = FauxCard(
103 title=title, lane=lane, assigned_user_id=assigned_user_id,
104 description_annotations=description_annotations,
105 external_system_url=external_system_url)
106+ board.cards.append(card)
107+ return card
108
109
110 class CardsToWorkItemsTestCase(CardsToWorkItemsBase):
111@@ -286,3 +289,47 @@
112 update_blueprints_from_work_items(lp=None, work_items=self.work_items)
113 # No assert here; we just want to make sure that
114 # update_blueprints_from_work_items() doesn't error.
115+
116+
117+class GetBluePrintLinkedCardsTestCase(CardsToWorkItemsBase):
118+ """Tests for get_blueprint_linked_cards()."""
119+
120+ def test_returns_cards_with_blueprint_url_annotations(self):
121+ # get_blueprint_linked_cards() returns cards with a blueprint url in
122+ # their description_annotations.
123+ blueprint_card = self._generateCard(
124+ title="Card 1",
125+ description_annotations=Record(blueprint_url=self.blueprint_url))
126+ self.board._cards_with_description_annotations.add(blueprint_card)
127+ cards_to_convert = get_blueprint_linked_cards(self.board)
128+ self.assertIn(blueprint_card, cards_to_convert)
129+
130+ def test_doesnt_return_non_blueprint_cards(self):
131+ # get_blueprint_linked_cards() doesn't return cards that don't have a
132+ # blueprint_url set.
133+ non_blueprint_card = self._generateCard(
134+ title="Card 1", description_annotations=Record(foo='bar'))
135+ self.board._cards_with_description_annotations.add(non_blueprint_card)
136+ cards_to_convert = get_blueprint_linked_cards(self.board)
137+ self.assertNotIn(non_blueprint_card, cards_to_convert)
138+
139+ def test_returns_cards_with_external_link_to_blueprint(self):
140+ # get_blueprint_linked_cards() returns cards that have an
141+ # external_system_url that points to a blueprint.
142+ blueprint_card = self._generateCard(
143+ title="Card 1", description_annotations={})
144+ blueprint_card.external_system_url = self.blueprint_url
145+ self.board._cards_with_external_links.add(blueprint_card)
146+ cards_to_convert = get_blueprint_linked_cards(self.board)
147+ self.assertIn(blueprint_card, cards_to_convert)
148+
149+ def test_does_not_return_cards_with_links_not_to_blueprints(self):
150+ # get_blueprint_linked_cards() won't return cards that have a
151+ # external_system_url that points to something other than a
152+ # blueoprint.
153+ non_blueprint_card = self._generateCard(
154+ title="Card 1", description_annotations={})
155+ non_blueprint_card.external_system_url = "http://example.com"
156+ self.board._cards_with_external_links.add(non_blueprint_card)
157+ cards_to_convert = get_blueprint_linked_cards(self.board)
158+ self.assertNotIn(non_blueprint_card, cards_to_convert)

Subscribers

People subscribed via source and target branches