Merge lp:~jkakar/kanban/fix-header-links into lp:kanban

Proposed by Jamu Kakar
Status: Merged
Merged at revision: 23
Proposed branch: lp:~jkakar/kanban/fix-header-links
Merge into: lp:kanban
Diff against target: 588 lines (+203/-154)
7 files modified
kanban/board.py (+37/-20)
kanban/commands.py (+9/-14)
kanban/html.py (+5/-2)
kanban/launchpad.py (+5/-4)
kanban/templates/kanban.html (+15/-9)
kanban/tests/test_board.py (+131/-104)
kanban/tests/test_html.py (+1/-1)
To merge this branch: bzr merge lp:~jkakar/kanban/fix-header-links
Reviewer Review Type Date Requested Status
Martin Pool Approve
Review via email: mp+50118@code.launchpad.net

Description of the change

This branch introduces the following changes:

- The kanban.milestone module has been renamed to kanban.board and the
  Milestone class has been refactored into MilestoneBoard and
  PersonBoard.

- Rendering logic is special cased to behave correctly for each type
  of board.

- A stray LPNET_SERVICE_ROOT has been replaced by the SERVICE_ROOT
  defined in kanban.launchpad. Changing the service root defined
  there will change the service root used throughout the system.

To post a comment you must log in.
Revision history for this message
Martin Pool (mbp) wrote :

Much better, thanks.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== renamed file 'kanban/milestone.py' => 'kanban/board.py'
2--- kanban/milestone.py 2011-02-15 11:27:45 +0000
3+++ kanban/board.py 2011-02-17 10:14:45 +0000
4@@ -155,21 +155,21 @@
5 self.queued.append(bug)
6
7
8-class Milestone(BugCollectionMixin):
9- """
10- An milestone is a collection of L{Bug}s targetted as part of an
11- incremental development process.
12-
13- @param project: The name of the project in Launchpad this milestone is
14- part of.
15- @param name: The name of this milestone.
16- @param warning_limit: Optionally, the number of days to wait before
17- showing a warning icon.
18- """
19-
20- def __init__(self, project, name, warning_limit=None):
21- super(Milestone, self).__init__(name)
22- self.project = project
23+class Story(BugCollectionMixin):
24+ """A story is a collection of L{Bug}s related to a particular feature.
25+
26+ @param name: The name of this story.
27+ """
28+
29+
30+class StoryCollectionMixin(BugCollectionMixin):
31+ """A collection of L{Bug}s grouped into L{Story}s.
32+
33+ @param name: The name of this collection.
34+ """
35+
36+ def __init__(self, name):
37+ super(StoryCollectionMixin, self).__init__(name)
38 self._stories = {}
39
40 @property
41@@ -179,7 +179,7 @@
42
43 def add(self, bug):
44 """Add C{bug} to this milestone."""
45- super(Milestone, self).add(bug)
46+ super(StoryCollectionMixin, self).add(bug)
47 stories = self._get_stories(bug)
48 for story in stories:
49 story.add(bug)
50@@ -205,10 +205,27 @@
51 return stories
52
53
54-class Story(BugCollectionMixin):
55- """A story is a collection of L{Bug}s related to a particular feature.
56-
57- @param name: The name of this story.
58+class MilestoneBoard(StoryCollectionMixin):
59+ """
60+ A milestone board contains a collection of L{Bug}s targetted to a
61+ milestone in Launchpad.
62+
63+ @param project_name: The name of the project or project group in Launchpad
64+ this milestone is part of.
65+ @param milestone_name: The name of this milestone.
66+ """
67+
68+ def __init__(self, project_name, milestone_name):
69+ super(MilestoneBoard, self).__init__(milestone_name)
70+ self.project_name = project_name
71+
72+
73+class PersonBoard(StoryCollectionMixin):
74+ """
75+ A person board contains a collection of L{Bug}s targetted to a particular
76+ person or team.
77+
78+ @param name: The name of the person or team.
79 """
80
81
82
83=== modified file 'kanban/commands.py'
84--- kanban/commands.py 2011-02-17 07:07:56 +0000
85+++ kanban/commands.py 2011-02-17 10:14:45 +0000
86@@ -5,11 +5,11 @@
87
88 from launchpadlib.launchpad import Launchpad
89
90+from kanban.board import MilestoneBoard, PersonBoard, compare_bugs
91 from kanban.html import generate_html, generate_roadmap_html
92 from kanban.launchpad import (
93 get_config_path, get_cache_path, get_launchpad, get_milestone_bugs,
94 get_person_assigned_bugs, SERVICE_ROOT)
95-from kanban.milestone import Milestone, compare_bugs
96 from kanban.roadmap import load_roadmap
97
98
99@@ -62,11 +62,11 @@
100
101 def run(self, person_name, output_file=None):
102 launchpad = get_launchpad()
103- milestone = Milestone(person_name, "assigned")
104+ person_board = PersonBoard(person_name)
105 bugs = get_person_assigned_bugs(launchpad, person_name)
106 for bug in sorted(bugs, compare_bugs):
107- milestone.add(bug)
108- self.write_output(generate_html(milestone), output_file)
109+ person_board.add(bug)
110+ self.write_output(generate_html(person_board), output_file)
111
112
113 class cmd_generate_milestone_kanban(HTMLOutputMixin, Command):
114@@ -74,21 +74,16 @@
115
116 takes_args = ["project_group", "milestone_name"]
117 takes_options = [Option("output-file", short_name="o", type=str,
118- help="Write HTML to file."),
119- Option("warning-limit", short_name="w", type=int,
120- help="The number of days to wait before showing "
121- "a warning signal.")]
122+ help="Write HTML to file.")]
123 _see_also = ["launchpad-login"]
124
125- def run(self, project_group, milestone_name, output_file=None,
126- warning_limit=None):
127+ def run(self, project_group, milestone_name, output_file=None):
128 launchpad = get_launchpad()
129- milestone = Milestone(project_group, milestone_name,
130- warning_limit=warning_limit)
131+ milestone_board = MilestoneBoard(project_group, milestone_name)
132 bugs = get_milestone_bugs(launchpad, project_group, milestone_name)
133 for bug in sorted(bugs, compare_bugs):
134- milestone.add(bug)
135- self.write_output(generate_html(milestone), output_file)
136+ milestone_board.add(bug)
137+ self.write_output(generate_html(milestone_board), output_file)
138
139
140 class cmd_generate_roadmap(HTMLOutputMixin, Command):
141
142=== modified file 'kanban/html.py'
143--- kanban/html.py 2011-02-15 11:27:45 +0000
144+++ kanban/html.py 2011-02-17 10:14:45 +0000
145@@ -2,6 +2,8 @@
146
147 from jinja2 import Environment, PackageLoader
148
149+from kanban.board import MilestoneBoard
150+
151
152 def branch_name(branch_url):
153 """Extract and return the branch name from a branch URL."""
154@@ -55,7 +57,7 @@
155 return False
156
157
158-def generate_html(milestone):
159+def generate_html(kanban_board):
160 """Generate an HTML kanban board to represent L{Bug}s in C{milestone}."""
161 environment = Environment(loader=PackageLoader("kanban", "templates"))
162 environment.filters["branch_name"] = branch_name
163@@ -64,7 +66,8 @@
164 environment.filters["warn"] = lambda bug: warn(bug, 3, 1)
165 environment.filters["danger"] = lambda bug: warn(bug, 7, 3)
166 template = environment.get_template("kanban.html")
167- data = {"milestone": milestone,
168+ data = {"kanban_board": kanban_board,
169+ "is_milestone": isinstance(kanban_board, MilestoneBoard),
170 "now": datetime.utcnow().strftime("%a %e %b at %H:%M UTC")}
171 return template.render(**data)
172
173
174=== modified file 'kanban/launchpad.py'
175--- kanban/launchpad.py 2011-02-17 07:07:39 +0000
176+++ kanban/launchpad.py 2011-02-17 10:14:45 +0000
177@@ -12,12 +12,13 @@
178
179 from launchpadlib.credentials import Credentials
180 from launchpadlib.launchpad import Launchpad
181-
182 from launchpadlib.uris import LPNET_SERVICE_ROOT
183+
184+from kanban.board import Bug
185+
186+
187 SERVICE_ROOT = LPNET_SERVICE_ROOT
188
189-from kanban.milestone import Bug
190-
191
192 def _make_path(path):
193 """Ensure that C{path} exists in the current user's home directory."""
194@@ -49,7 +50,7 @@
195 "Run the launchpad-login command to create OAuth credentials.")
196 credentials = Credentials()
197 credentials.load(open(credentials_path, "r"))
198- return Launchpad(credentials, LPNET_SERVICE_ROOT, get_cache_path())
199+ return Launchpad(credentials, SERVICE_ROOT, get_cache_path())
200
201
202 def get_project_group(launchpad, name):
203
204=== modified file 'kanban/templates/kanban.html'
205--- kanban/templates/kanban.html 2011-02-15 11:27:45 +0000
206+++ kanban/templates/kanban.html 2011-02-17 10:14:45 +0000
207@@ -1,6 +1,6 @@
208 <html>
209 <head>
210- <title>{{ milestone.project }} {{ milestone.name }}</title>
211+ <title>{{ kanban_board.project_name }} {{ kanban_board.name }}</title>
212 <link rel="stylesheet" type="text/css" href="media/decogrids-12.css" />
213 <link rel="stylesheet" type="text/css" href="media/kanban.css" />
214 </head>
215@@ -8,19 +8,25 @@
216 <body>
217 <div id="container">
218 <div id="heading" class="row">
219- <div class="position-0 width-12 cell"><h1><a href="https://launchpad.net/{{ milestone.project }}">{{ milestone.project }}</a> <a href="https://launchpad.net/{{ milestone.project }}/+milestone/{{ milestone.name}}">{{ milestone.name }}</a> <span class="bug-count">{{ milestone.bugs|length }} bugs</span></h1></div>
220+ <div class="position-0 width-12 cell">
221+ {% if is_milestone %}
222+ <h1><a href="https://launchpad.net/{{ kanban_board.project_name }}">{{ kanban_board.project_name }}</a> <a href="https://launchpad.net/{{ kanban_board.project_name }}/+milestone/{{ kanban_board.name}}">{{ kanban_board.name }}</a> <span class="bug-count">{{ kanban_board.bugs|length }} bugs</span></h1>
223+ {% else %}
224+ <h1><a href="https://launchpad.net/~{{ kanban_board.name }}">{{ kanban_board.name }}</a> <span class="bug-count">{{ kanban_board.bugs|length }} bugs</span></h1>
225+ {% endif %}
226+ </div>
227 </div>
228
229 <div id="header" class="row">
230- <div class="position-0 width-2 cell"><h2>Queued <span class="bug-count">{{ milestone.queued|length }} bugs</span></h2></div>
231- <div class="position-2 width-2 cell"><h2>In progress <span class="bug-count">{{ milestone.in_progress|length }} bugs</span></h2></div>
232- <div class="position-4 width-2 cell"><h2>Needs review <span class="bug-count">{{ milestone.needs_review|length }} bugs</span></h2></div>
233- <div class="position-6 width-2 cell"><h2>Needs testing <span class="bug-count">{{ milestone.needs_testing|length }} bugs</span></h2></div>
234- <div class="position-8 width-2 cell"><h2>Needs release <span class="bug-count">{{ milestone.needs_release|length }} bugs</span></h2></div>
235- <div class="position-10 width-2 cell"><h2>Released <span class="bug-count">{{ milestone.released|length }} bugs</span></h2></div>
236+ <div class="position-0 width-2 cell"><h2>Queued <span class="bug-count">{{ kanban_board.queued|length }} bugs</span></h2></div>
237+ <div class="position-2 width-2 cell"><h2>In progress <span class="bug-count">{{ kanban_board.in_progress|length }} bugs</span></h2></div>
238+ <div class="position-4 width-2 cell"><h2>Needs review <span class="bug-count">{{ kanban_board.needs_review|length }} bugs</span></h2></div>
239+ <div class="position-6 width-2 cell"><h2>Needs testing <span class="bug-count">{{ kanban_board.needs_testing|length }} bugs</span></h2></div>
240+ <div class="position-8 width-2 cell"><h2>Needs release <span class="bug-count">{{ kanban_board.needs_release|length }} bugs</span></h2></div>
241+ <div class="position-10 width-2 cell"><h2>Released <span class="bug-count">{{ kanban_board.released|length }} bugs</span></h2></div>
242 </div>
243
244- {% for story in milestone.stories %}
245+ {% for story in kanban_board.stories %}
246 <div class="tiles row story">
247 {% if story.name %}
248 <div class="position-0 width-12 cell">{{ story.name }}</div>
249
250=== renamed file 'kanban/tests/test_milestone.py' => 'kanban/tests/test_board.py'
251--- kanban/tests/test_milestone.py 2011-02-15 11:27:45 +0000
252+++ kanban/tests/test_board.py 2011-02-17 10:14:45 +0000
253@@ -2,11 +2,11 @@
254
255 from testtools import TestCase
256
257-from kanban.milestone import (
258- Bug, Milestone, Story, compare_bugs, compare_stories, NEW, CONFIRMED,
259- TRIAGED, IN_PROGRESS, FIX_COMMITTED, FIX_RELEASED, UNDECIDED, WISHLIST,
260- LOW, MEDIUM, HIGH, CRITICAL, WORK_IN_PROGRESS, NEEDS_REVIEW, APPROVED,
261- MERGED)
262+from kanban.board import (
263+ Bug, MilestoneBoard, PersonBoard, Story, compare_bugs, compare_stories,
264+ NEW, CONFIRMED, TRIAGED, IN_PROGRESS, FIX_COMMITTED, FIX_RELEASED,
265+ UNDECIDED, WISHLIST, LOW, MEDIUM, HIGH, CRITICAL, WORK_IN_PROGRESS,
266+ NEEDS_REVIEW, APPROVED, MERGED)
267
268
269 class BugTest(TestCase):
270@@ -282,15 +282,15 @@
271 story.
272 """
273 bug = Bug("1", "kanban", MEDIUM, NEW, "A title")
274- milestone = self.create_test_class()
275- milestone.add(bug)
276- self.assertEqual([bug], milestone.bugs)
277- self.assertEqual([bug], milestone.queued)
278- self.assertEqual([], milestone.in_progress)
279- self.assertEqual([], milestone.needs_review)
280- self.assertEqual([], milestone.needs_testing)
281- self.assertEqual([], milestone.needs_release)
282- self.assertEqual([], milestone.released)
283+ kanban_board = self.create_test_class()
284+ kanban_board.add(bug)
285+ self.assertEqual([bug], kanban_board.bugs)
286+ self.assertEqual([bug], kanban_board.queued)
287+ self.assertEqual([], kanban_board.in_progress)
288+ self.assertEqual([], kanban_board.needs_review)
289+ self.assertEqual([], kanban_board.needs_testing)
290+ self.assertEqual([], kanban_board.needs_release)
291+ self.assertEqual([], kanban_board.released)
292
293 def test_add_in_progress(self):
294 """
295@@ -299,15 +299,15 @@
296 default story.
297 """
298 bug = Bug("1", "kanban", MEDIUM, IN_PROGRESS, "A title")
299- milestone = self.create_test_class()
300- milestone.add(bug)
301- self.assertEqual([bug], milestone.bugs)
302- self.assertEqual([], milestone.queued)
303- self.assertEqual([bug], milestone.in_progress)
304- self.assertEqual([], milestone.needs_review)
305- self.assertEqual([], milestone.needs_testing)
306- self.assertEqual([], milestone.needs_release)
307- self.assertEqual([], milestone.released)
308+ kanban_board = self.create_test_class()
309+ kanban_board.add(bug)
310+ self.assertEqual([bug], kanban_board.bugs)
311+ self.assertEqual([], kanban_board.queued)
312+ self.assertEqual([bug], kanban_board.in_progress)
313+ self.assertEqual([], kanban_board.needs_review)
314+ self.assertEqual([], kanban_board.needs_testing)
315+ self.assertEqual([], kanban_board.needs_release)
316+ self.assertEqual([], kanban_board.released)
317
318 def test_add_needs_review(self):
319 """
320@@ -317,15 +317,15 @@
321 """
322 bug = Bug("1", "kanban", MEDIUM, IN_PROGRESS, "A title",
323 merge_proposal="url", merge_proposal_status=NEEDS_REVIEW)
324- milestone = self.create_test_class()
325- milestone.add(bug)
326- self.assertEqual([bug], milestone.bugs)
327- self.assertEqual([], milestone.queued)
328- self.assertEqual([], milestone.in_progress)
329- self.assertEqual([bug], milestone.needs_review)
330- self.assertEqual([], milestone.needs_testing)
331- self.assertEqual([], milestone.needs_release)
332- self.assertEqual([], milestone.released)
333+ kanban_board = self.create_test_class()
334+ kanban_board.add(bug)
335+ self.assertEqual([bug], kanban_board.bugs)
336+ self.assertEqual([], kanban_board.queued)
337+ self.assertEqual([], kanban_board.in_progress)
338+ self.assertEqual([bug], kanban_board.needs_review)
339+ self.assertEqual([], kanban_board.needs_testing)
340+ self.assertEqual([], kanban_board.needs_release)
341+ self.assertEqual([], kanban_board.released)
342
343 def test_add_needs_testing(self):
344 """
345@@ -335,15 +335,15 @@
346 """
347 bug = Bug("1", "kanban", MEDIUM, IN_PROGRESS, "A title",
348 merge_proposal="url", merge_proposal_status=APPROVED)
349- milestone = self.create_test_class()
350- milestone.add(bug)
351- self.assertEqual([bug], milestone.bugs)
352- self.assertEqual([], milestone.queued)
353- self.assertEqual([], milestone.in_progress)
354- self.assertEqual([], milestone.needs_review)
355- self.assertEqual([bug], milestone.needs_testing)
356- self.assertEqual([], milestone.needs_release)
357- self.assertEqual([], milestone.released)
358+ kanban_board = self.create_test_class()
359+ kanban_board.add(bug)
360+ self.assertEqual([bug], kanban_board.bugs)
361+ self.assertEqual([], kanban_board.queued)
362+ self.assertEqual([], kanban_board.in_progress)
363+ self.assertEqual([], kanban_board.needs_review)
364+ self.assertEqual([bug], kanban_board.needs_testing)
365+ self.assertEqual([], kanban_board.needs_release)
366+ self.assertEqual([], kanban_board.released)
367
368 def test_add_needs_release(self):
369 """
370@@ -354,15 +354,15 @@
371 bug = Bug("1", "kanban", MEDIUM, FIX_COMMITTED, "A title",
372 merge_proposal="url", merge_proposal_status=MERGED,
373 tags=["verified"])
374- milestone = self.create_test_class()
375- milestone.add(bug)
376- self.assertEqual([bug], milestone.bugs)
377- self.assertEqual([], milestone.queued)
378- self.assertEqual([], milestone.in_progress)
379- self.assertEqual([], milestone.needs_review)
380- self.assertEqual([], milestone.needs_testing)
381- self.assertEqual([bug], milestone.needs_release)
382- self.assertEqual([], milestone.released)
383+ kanban_board = self.create_test_class()
384+ kanban_board.add(bug)
385+ self.assertEqual([bug], kanban_board.bugs)
386+ self.assertEqual([], kanban_board.queued)
387+ self.assertEqual([], kanban_board.in_progress)
388+ self.assertEqual([], kanban_board.needs_review)
389+ self.assertEqual([], kanban_board.needs_testing)
390+ self.assertEqual([bug], kanban_board.needs_release)
391+ self.assertEqual([], kanban_board.released)
392
393 def test_add_released(self):
394 """
395@@ -371,47 +371,31 @@
396 default story.
397 """
398 bug = Bug("1", "kanban", MEDIUM, FIX_RELEASED, "A title")
399- milestone = self.create_test_class()
400- milestone.add(bug)
401- self.assertEqual([bug], milestone.bugs)
402- self.assertEqual([], milestone.queued)
403- self.assertEqual([], milestone.in_progress)
404- self.assertEqual([], milestone.needs_review)
405- self.assertEqual([], milestone.needs_testing)
406- self.assertEqual([], milestone.needs_release)
407- self.assertEqual([bug], milestone.released)
408-
409-
410-class MilestoneTest(BugCollectionMixinTestBase, TestCase):
411-
412- def create_test_class(self):
413- """
414- Create an L{Milestone} for use in L{BugCollectionMixinTestBase} tests.
415- """
416- return Milestone("project", "name")
417-
418- def test_instantiate(self):
419- """
420- An L{Milestone} needs the name of the project and its own name when
421- its instantiated.
422- """
423- milestone = Milestone("project", "name")
424- self.assertEqual("project", milestone.project)
425- self.assertEqual("name", milestone.name)
426- self.assertEqual([], milestone.stories)
427+ kanban_board = self.create_test_class()
428+ kanban_board.add(bug)
429+ self.assertEqual([bug], kanban_board.bugs)
430+ self.assertEqual([], kanban_board.queued)
431+ self.assertEqual([], kanban_board.in_progress)
432+ self.assertEqual([], kanban_board.needs_review)
433+ self.assertEqual([], kanban_board.needs_testing)
434+ self.assertEqual([], kanban_board.needs_release)
435+ self.assertEqual([bug], kanban_board.released)
436+
437+
438+class StoryCollectionMixinTestBase(object):
439
440 def test_add_bug_with_story_tag_creates_story(self):
441 """
442- If a L{Bug} with a C{story-<name>} tag is added to an L{Milestone},
443- and a L{Story} with a matching name doesn't exist, one will be created
444- and the bug will be added to it.
445+ If a L{Bug} with a C{story-<name>} tag is added to a
446+ L{StoryCollectionMixin}, and a L{Story} with a matching name doesn't
447+ exist, one will be created and the bug will be added to it.
448 """
449 bug = Bug("1", "kanban", MEDIUM, NEW, "A title", tags=["story-test"])
450- milestone = Milestone("project", "name")
451- milestone.add(bug)
452- self.assertEqual([bug], milestone.bugs)
453- self.assertEqual(1, len(milestone.stories))
454- story = milestone.stories[0]
455+ kanban_board = self.create_test_class()
456+ kanban_board.add(bug)
457+ self.assertEqual([bug], kanban_board.bugs)
458+ self.assertEqual(1, len(kanban_board.stories))
459+ story = kanban_board.stories[0]
460 self.assertIs("story-test", story.name)
461 self.assertEqual([bug], story.queued)
462 self.assertEqual([], story.in_progress)
463@@ -423,15 +407,16 @@
464 def test_add_bug_with_story_tag_adds_to_existing_story(self):
465 """
466 If a L{Story} already exists, and a L{Bug} with a matching tag is
467- added to an L{Milestone}, it will be added to the existing story.
468+ added to a L{StoryCollectionMixin}, it will be added to the existing
469+ story.
470 """
471 bug1 = Bug("1", "kanban", MEDIUM, NEW, "A title", tags=["story-test"])
472 bug2 = Bug("2", "kanban", MEDIUM, NEW, "A title", tags=["story-test"])
473- milestone = Milestone("project", "name")
474- milestone.add(bug1)
475- milestone.add(bug2)
476- self.assertEqual(1, len(milestone.stories))
477- story = milestone.stories[0]
478+ kanban_board = self.create_test_class()
479+ kanban_board.add(bug1)
480+ kanban_board.add(bug2)
481+ self.assertEqual(1, len(kanban_board.stories))
482+ story = kanban_board.stories[0]
483 self.assertIs("story-test", story.name)
484 self.assertEqual([bug1, bug2], story.queued)
485 self.assertEqual([], story.in_progress)
486@@ -443,35 +428,77 @@
487 def test_add_bug_with_multiple_story_tags(self):
488 """
489 If a L{Bug} has more than one C{story-<name>} tag it will be added to
490- multiple L{Story}s when its added to an L{Milestone}.
491+ multiple L{Story}s when its added to a L{StoryCollectionMixin}.
492 """
493 bug = Bug("1", "kanban", MEDIUM, NEW, "A title",
494 tags=["story-test1", "story-test2"])
495- milestone = Milestone("project", "name")
496- milestone.add(bug)
497- self.assertEqual(2, len(milestone.stories))
498+ kanban_board = self.create_test_class()
499+ kanban_board.add(bug)
500+ self.assertEqual(2, len(kanban_board.stories))
501
502- story1 = milestone.stories[0]
503+ story1 = kanban_board.stories[0]
504 self.assertIs("story-test1", story1.name)
505 self.assertEqual([bug], story1.queued)
506
507- story2 = milestone.stories[1]
508+ story2 = kanban_board.stories[1]
509 self.assertIs("story-test2", story2.name)
510 self.assertEqual([bug], story2.queued)
511
512 def test_stories_sorting(self):
513 """
514- The L{Milestone.stories} property sorts L{Story}s alphabetically. The
515- default L{Story} is always at the end of the list.
516+ The L{StoryCollectionMixin.stories} property sorts L{Story}s
517+ alphabetically. The default L{Story} is always at the end of the
518+ list.
519 """
520 bug1 = Bug("1", "kanban", MEDIUM, NEW, "A title")
521 bug2 = Bug("2", "kanban", MEDIUM, NEW, "A title",
522 tags=["story-test1", "story-test2"])
523- milestone = Milestone("project", "name")
524- milestone.add(bug1)
525- milestone.add(bug2)
526+ kanban_board = self.create_test_class()
527+ kanban_board.add(bug1)
528+ kanban_board.add(bug2)
529 self.assertEqual(["story-test1", "story-test2", None],
530- [story.name for story in milestone.stories])
531+ [story.name for story in kanban_board.stories])
532+
533+
534+class MilestoneBoardTest(BugCollectionMixinTestBase,
535+ StoryCollectionMixinTestBase, TestCase):
536+
537+ def create_test_class(self):
538+ """
539+ Create a L{MilestoneBoard} for use in L{BugCollectionMixinTestBase}
540+ and L{StoryCollectionMixinTestBase} tests.
541+ """
542+ return MilestoneBoard("project", "milestone")
543+
544+ def test_instantiate(self):
545+ """
546+ A L{MilestoneBoard} needs the name of the project and its own name
547+ when its instantiated.
548+ """
549+ kanban_board = MilestoneBoard("project", "milestone")
550+ self.assertEqual("project", kanban_board.project_name)
551+ self.assertEqual("milestone", kanban_board.name)
552+ self.assertEqual([], kanban_board.stories)
553+
554+
555+class PersonBoardTest(BugCollectionMixinTestBase, StoryCollectionMixinTestBase,
556+ TestCase):
557+
558+ def create_test_class(self):
559+ """
560+ Create a L{PersonBoard} for use in L{BugCollectionMixinTestBase} and
561+ L{StoryCollectionMixinTestBase} tests.
562+ """
563+ return PersonBoard("team")
564+
565+ def test_instantiate(self):
566+ """
567+ A L{PersonBoard} needs the name of the person or team when its
568+ instantiated.
569+ """
570+ kanban_board = PersonBoard("person")
571+ self.assertEqual("person", kanban_board.name)
572+ self.assertEqual([], kanban_board.stories)
573
574
575 class StoryTest(BugCollectionMixinTestBase, TestCase):
576
577=== modified file 'kanban/tests/test_html.py'
578--- kanban/tests/test_html.py 2011-02-08 10:28:49 +0000
579+++ kanban/tests/test_html.py 2011-02-17 10:14:45 +0000
580@@ -2,9 +2,9 @@
581
582 from testtools import TestCase
583
584+from kanban.board import Bug, MEDIUM, CRITICAL, IN_PROGRESS, NEEDS_REVIEW
585 from kanban.html import (
586 branch_name, branch_url, importance_css_class, status_css_class, warn)
587-from kanban.milestone import Bug, MEDIUM, CRITICAL, IN_PROGRESS, NEEDS_REVIEW
588 from kanban.roadmap import QUEUED
589
590

Subscribers

People subscribed via source and target branches

to all changes: