Merge lp:~adam-collard/tarmac/milestone-filter-by-series into lp:tarmac

Proposed by Adam Collard
Status: Rejected
Rejected by: Adam Collard
Proposed branch: lp:~adam-collard/tarmac/milestone-filter-by-series
Merge into: lp:tarmac
Diff against target: 208 lines (+36/-33)
2 files modified
tarmac/plugins/bugresolver.py (+13/-12)
tarmac/plugins/tests/test_bugresolver.py (+23/-21)
To merge this branch: bzr merge lp:~adam-collard/tarmac/milestone-filter-by-series
Reviewer Review Type Date Requested Status
dobey Needs Fixing
Chris Glass (community) Approve
Данило Шеган (community) Approve
Review via email: mp+278946@code.launchpad.net

Description of the change

When setting the milestone, only look for milestones which match the series that the bug has been committed on.

To post a comment you must log in.
Revision history for this message
Данило Шеган (danilo) wrote :

LGTM (tests, lint all pass as well). FWIW, the default collections batch size LP seems to use is 75 items, so this is needed when you've got more milestones than that.

review: Approve
Revision history for this message
Chris Glass (tribaal) wrote :

+1 !

review: Approve
435. By Adam Collard

No need to walk next_collection links

Revision history for this message
dobey (dobey) wrote :
Download full text (10.2 KiB)

Running the tests with ./run-tests in the tree on my 14.04 system, There are 2 failures and 9 errors:

======================================================================
ERROR: test__find_milestone_no_dates (tarmac.plugins.tests.test_bugresolver.BugResolverTests)
tarmac.plugins.tests.test_bugresolver.BugResolverTests.test__find_milestone_no_dates
----------------------------------------------------------------------
_StringException: Empty attachments:
  log

Traceback (most recent call last):
  File "/home/dobey/Projects/canonical/tarmac/milestone-filter-by-series/tarmac/plugins/tests/test_bugresolver.py", line 233, in test__find_milestone_no_dates
    milestones = list(self.plugin._find_milestones(self.series[1]))
  File "/home/dobey/Projects/canonical/tarmac/milestone-filter-by-series/tarmac/plugins/bugresolver.py", line 116, in _find_milestones
    if milestone.name == default:
AttributeError: 'int' object has no attribute 'name'

======================================================================
ERROR: test__find_milestone_specific_negative (tarmac.plugins.tests.test_bugresolver.BugResolverTests)
tarmac.plugins.tests.test_bugresolver.BugResolverTests.test__find_milestone_specific_negative
----------------------------------------------------------------------
_StringException: Empty attachments:
  log

Traceback (most recent call last):
  File "/home/dobey/Projects/canonical/tarmac/milestone-filter-by-series/tarmac/plugins/tests/test_bugresolver.py", line 226, in test__find_milestone_specific_negative
    milestones = list(self.plugin._find_milestones(self.series[0]))
  File "/home/dobey/Projects/canonical/tarmac/milestone-filter-by-series/tarmac/plugins/bugresolver.py", line 116, in _find_milestones
    if milestone.name == default:
AttributeError: 'int' object has no attribute 'name'

======================================================================
ERROR: test__find_target_milestone_between (tarmac.plugins.tests.test_bugresolver.BugResolverTests)
tarmac.plugins.tests.test_bugresolver.BugResolverTests.test__find_target_milestone_between
----------------------------------------------------------------------
_StringException: Empty attachments:
  log

Traceback (most recent call last):
  File "/home/dobey/Projects/canonical/tarmac/milestone-filter-by-series/tarmac/plugins/tests/test_bugresolver.py", line 184, in test__find_target_milestone_between
    self.milestone_past.date_targeted + timedelta(weeks=1))
  File "/home/dobey/Projects/canonical/tarmac/milestone-filter-by-series/tarmac/plugins/bugresolver.py", line 142, in _find_target_milestone
    if milestone.date_targeted is None:
AttributeError: 'int' object has no attribute 'date_targeted'

======================================================================
ERROR: test__find_target_milestone_lexical_sort_past_dates (tarmac.plugins.tests.test_bugresolver.BugResolverTests)
tarmac.plugins.tests.test_bugresolver.BugResolverTests.test__find_target_milestone_lexical_sort_past_dates
----------------------------------------------------------------------
_StringException: Empty attachments:
  log

Traceback (most recent call last):
  File "/home/dobey/Projects/canonical/tar...

review: Needs Fixing

Unmerged revisions

435. By Adam Collard

No need to walk next_collection links

434. By Adam Collard

fix lint

433. By Adam Collard

Filter by series

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'tarmac/plugins/bugresolver.py'
--- tarmac/plugins/bugresolver.py 2014-03-24 21:38:36 +0000
+++ tarmac/plugins/bugresolver.py 2015-12-02 15:37:05 +0000
@@ -57,7 +57,7 @@
5757
58 if task:58 if task:
59 task.status = u'Fix Committed'59 task.status = u'Fix Committed'
60 self._set_milestone_on_task(project, task)60 self._set_milestone_on_task(series, task)
61 task.lp_save()61 task.lp_save()
62 else:62 else:
63 self.logger.info('Target %s/%s not found in bug #%s.',63 self.logger.info('Target %s/%s not found in bug #%s.',
@@ -82,7 +82,7 @@
82 "set_milestone": set_milestone,82 "set_milestone": set_milestone,
83 "default_milestone": default_milestone}83 "default_milestone": default_milestone}
8484
85 def _set_milestone_on_task(self, project, task):85 def _set_milestone_on_task(self, series, task):
86 """86 """
87 Attempt to auto-determine the milestone to set, and set the milestone87 Attempt to auto-determine the milestone to set, and set the milestone
88 of the given task. If the task already has a milestone set => noop.88 of the given task. If the task already has a milestone set => noop.
@@ -97,27 +97,28 @@
97 task.bug.id, task.bug_target_name, task_milestone.name))97 task.bug.id, task.bug_target_name, task_milestone.name))
98 return98 return
99 now = datetime.utcnow()99 now = datetime.utcnow()
100 target_milestone = self._find_target_milestone(project, now)100 target_milestone = self._find_target_milestone(series, now)
101 self.logger.info("%s/%s: Setting Milestone: %s",101 self.logger.info("%s/%s: Setting Milestone: %s",
102 task.bug.id, task.bug_target_name, target_milestone)102 task.bug.id, task.bug_target_name, target_milestone)
103 task.milestone = target_milestone103 task.milestone = target_milestone
104104
105 def _find_milestones(self, project):105 def _find_milestones(self, series):
106 """106 """
107 Return list of active milestones in a project. If the config107 Return iterable of active milestones in a series. If
108 `default_milestone` is set filter by that. If not found, an 108 the config `default_milestone` is set filter by that. If not
109 empty list will be returned.109 found, an empty list will be returned.
110 """110 """
111 default = self.config["default_milestone"]111 default = self.config["default_milestone"]
112 milestones = series.active_milestones
112 if default is None:113 if default is None:
113 return list(project.active_milestones)114 return milestones
114 for milestone in project.active_milestones:115 for milestone in milestones:
115 if milestone.name == default:116 if milestone.name == default:
116 return [milestone]117 return [milestone]
117 self.logger.warning("Default Milestone not found: %s" % default)118 self.logger.warning("Default Milestone not found: %s" % default)
118 return []119 return []
119120
120 def _find_target_milestone(self, project, now):121 def _find_target_milestone(self, series, now):
121 """122 """
122 Find a target milestone when resolving a bug task.123 Find a target milestone when resolving a bug task.
123124
@@ -135,7 +136,7 @@
135 2) least lexically sorting milestone (by name)136 2) least lexically sorting milestone (by name)
136 3) the last milestone in the list (covers len()==1 case).137 3) the last milestone in the list (covers len()==1 case).
137 """138 """
138 milestones = self._find_milestones(project)139 milestones = self._find_milestones(series)
139 earliest_after = latest_before = untargeted = None140 earliest_after = latest_before = untargeted = None
140 for milestone in milestones:141 for milestone in milestones:
141 if milestone.date_targeted is None:142 if milestone.date_targeted is None:
142143
=== modified file 'tarmac/plugins/tests/test_bugresolver.py'
--- tarmac/plugins/tests/test_bugresolver.py 2014-03-24 21:38:36 +0000
+++ tarmac/plugins/tests/test_bugresolver.py 2015-12-02 15:37:05 +0000
@@ -76,15 +76,15 @@
76 bug=Thing(id="1"),76 bug=Thing(id="1"),
77 bug_target_name=self.targets[2].name)])}77 bug_target_name=self.targets[2].name)])}
78 # Insert out of order to make sure they sort correctly.78 # Insert out of order to make sure they sort correctly.
79 self.milestones = [79 self.milestones = Thing(total_size=4, entries=[
80 self.milestone_far_future, self.milestone_with_bug,80 self.milestone_far_future, self.milestone_with_bug,
81 self.milestone_past, self.milestone_future]81 self.milestone_past, self.milestone_future])
82 self.milestones_extended = [82 self.milestones_extended = Thing(total_size=3, entries=[
83 self.milestone_untargeted_c, self.milestone_untargeted_b,83 self.milestone_untargeted_c, self.milestone_untargeted_b,
84 self.milestone_untargeted_a]84 self.milestone_untargeted_a])
85 self.milestones_extended.extend(self.milestones)85 self.milestones_extended.entries.extend(self.milestones.entries)
86 self.projects[0].active_milestones = self.milestones86 self.series[0].active_milestones = self.milestones
87 self.projects[1].active_milestones = self.milestones_extended87 self.series[1].active_milestones = self.milestones_extended
8888
89 def getSeries(self, name=None):89 def getSeries(self, name=None):
90 """Faux getSeries for testing."""90 """Faux getSeries for testing."""
@@ -124,7 +124,7 @@
124 launchpad = Thing(bugs=self.bugs)124 launchpad = Thing(bugs=self.bugs)
125 command = Thing(launchpad=launchpad)125 command = Thing(launchpad=launchpad)
126 self.plugin.run(command=command, target=target, source=None,126 self.plugin.run(command=command, target=target, source=None,
127 proposal=self.proposal)127 proposal=self.proposal)
128 self.assertEqual(self.bugs['0'].bug_tasks[0].milestone,128 self.assertEqual(self.bugs['0'].bug_tasks[0].milestone,
129 self.milestone_future)129 self.milestone_future)
130 self.assertEqual(self.bugs['1'].bug_tasks[0].milestone,130 self.assertEqual(self.bugs['1'].bug_tasks[0].milestone,
@@ -173,14 +173,14 @@
173 def test__find_target_milestone_older(self):173 def test__find_target_milestone_older(self):
174 """Dates before all milestones return the oldest milestone."""174 """Dates before all milestones return the oldest milestone."""
175 milestone = self.plugin._find_target_milestone(175 milestone = self.plugin._find_target_milestone(
176 self.projects[0],176 self.series[0],
177 self.milestone_past.date_targeted - timedelta(weeks=1))177 self.milestone_past.date_targeted - timedelta(weeks=1))
178 self.assertEqual(milestone, self.milestone_past)178 self.assertEqual(milestone, self.milestone_past)
179179
180 def test__find_target_milestone_between(self):180 def test__find_target_milestone_between(self):
181 """Test that dates between milestones return the closest newest."""181 """Test that dates between milestones return the closest newest."""
182 milestone = self.plugin._find_target_milestone(182 milestone = self.plugin._find_target_milestone(
183 self.projects[1],183 self.series[1],
184 self.milestone_past.date_targeted + timedelta(weeks=1))184 self.milestone_past.date_targeted + timedelta(weeks=1))
185 self.assertTrue(self.now < self.milestone_future.date_targeted)185 self.assertTrue(self.now < self.milestone_future.date_targeted)
186 self.assertTrue(self.now > self.milestone_past.date_targeted)186 self.assertTrue(self.now > self.milestone_past.date_targeted)
@@ -189,14 +189,14 @@
189 def test__find_target_milestone_newer(self):189 def test__find_target_milestone_newer(self):
190 """Test that dates after all milestones return the newest."""190 """Test that dates after all milestones return the newest."""
191 milestone = self.plugin._find_target_milestone(191 milestone = self.plugin._find_target_milestone(
192 self.projects[0],192 self.series[0],
193 self.milestone_far_future.date_targeted + timedelta(weeks=1))193 self.milestone_far_future.date_targeted + timedelta(weeks=1))
194 self.assertEqual(milestone, self.milestone_far_future)194 self.assertEqual(milestone, self.milestone_far_future)
195195
196 def test__find_target_milestone_lexical_sort_past_dates(self):196 def test__find_target_milestone_lexical_sort_past_dates(self):
197 """Dates after milestones return the least sorted no-expected-date."""197 """Dates after milestones return the least sorted no-expected-date."""
198 milestone = self.plugin._find_target_milestone(198 milestone = self.plugin._find_target_milestone(
199 self.projects[1],199 self.series[1],
200 self.milestone_far_future.date_targeted + timedelta(weeks=1))200 self.milestone_far_future.date_targeted + timedelta(weeks=1))
201 self.assertEqual(milestone, self.milestone_untargeted_a)201 self.assertEqual(milestone, self.milestone_untargeted_a)
202202
@@ -204,32 +204,33 @@
204 """Test that specifying a default gets a specific milestone."""204 """Test that specifying a default gets a specific milestone."""
205 self.plugin.config["default_milestone"] = "c"205 self.plugin.config["default_milestone"] = "c"
206 milestone = self.plugin._find_target_milestone(206 milestone = self.plugin._find_target_milestone(
207 self.projects[1],207 self.series[1],
208 self.milestone_far_future.date_targeted + timedelta(weeks=1))208 self.milestone_far_future.date_targeted + timedelta(weeks=1))
209 self.assertEqual(milestone, self.milestone_untargeted_c)209 self.assertEqual(milestone, self.milestone_untargeted_c)
210210
211 def test__find_milestone_positive(self):211 def test__find_milestone_positive(self):
212 """Given a project, the list of milestones is returned."""212 """Given a project, the list of milestones is returned."""
213 milestones = self.plugin._find_milestones(self.projects[1])213 milestones = list(self.plugin._find_milestones(self.series[1]))
214 self.assertEqual(len(milestones), 7)214 self.assertEqual(len(milestones), 7)
215215
216 def test__find_milestone_negative(self):216 def test__find_milestone_negative(self):
217 """Given a project with no milestones, _find_milestone handles it"""217 """Given a project with no milestones, _find_milestone handles it"""
218 milestones = self.plugin._find_milestones(Thing(active_milestones=[]))218 milestones = list(self.plugin._find_milestones(
219 Thing(active_milestones=Thing(total_size=0, entries=[]))))
219 self.assertEqual(len(milestones), 0)220 self.assertEqual(len(milestones), 0)
220221
221 def test__find_milestone_specific_negative(self):222 def test__find_milestone_specific_negative(self):
222 """Find a secific milestone that isn't there, check for log"""223 """Find a secific milestone that isn't there, check for log"""
223 self.plugin.logger.warning = MagicMock()224 self.plugin.logger.warning = MagicMock()
224 self.plugin.config["default_milestone"] = "FOO"225 self.plugin.config["default_milestone"] = "FOO"
225 milestones = self.plugin._find_milestones(self.projects[0])226 milestones = list(self.plugin._find_milestones(self.series[0]))
226 self.assertEqual(len(milestones), 0)227 self.assertEqual(len(milestones), 0)
227 self.assertEqual(self.plugin.logger.warning.call_count, 1)228 self.assertEqual(self.plugin.logger.warning.call_count, 1)
228229
229 def test__find_milestone_no_dates(self):230 def test__find_milestone_no_dates(self):
230 """Find a specific milestones without a targeted date"""231 """Find a specific milestones without a targeted date"""
231 self.plugin.config["default_milestone"] = "b"232 self.plugin.config["default_milestone"] = "b"
232 milestones = self.plugin._find_milestones(self.projects[1])233 milestones = list(self.plugin._find_milestones(self.series[1]))
233 self.assertEqual(len(milestones), 1)234 self.assertEqual(len(milestones), 1)
234 self.assertEqual(milestones[0], self.milestone_untargeted_b)235 self.assertEqual(milestones[0], self.milestone_untargeted_b)
235236
@@ -277,7 +278,7 @@
277 self.plugin.config = {278 self.plugin.config = {
278 "set_milestone": False, "default_milestone": None}279 "set_milestone": False, "default_milestone": None}
279 self.plugin._set_milestone_on_task(280 self.plugin._set_milestone_on_task(
280 self.projects[0], self.bugs['0'].bug_tasks[0])281 self.series[0], self.bugs['0'].bug_tasks[0])
281 self.assertEqual(self.bugs['0'].bug_tasks[0].milestone, None)282 self.assertEqual(self.bugs['0'].bug_tasks[0].milestone, None)
282 self.assertEqual(self.plugin.logger.info.call_count, 0)283 self.assertEqual(self.plugin.logger.info.call_count, 0)
283 self.assertEqual(self.plugin.logger.warning.call_count, 0)284 self.assertEqual(self.plugin.logger.warning.call_count, 0)
@@ -285,9 +286,10 @@
285 def test__set_milestone_on_task_milestone_already_set(self):286 def test__set_milestone_on_task_milestone_already_set(self):
286 """milestone is already set, should leave task untouched"""287 """milestone is already set, should leave task untouched"""
287 self.plugin.logger.info = MagicMock()288 self.plugin.logger.info = MagicMock()
288 self.plugin.config = {"set_milestone": True, "default_milestone": "past"}289 self.plugin.config = {"set_milestone": True,
290 "default_milestone": "past"}
289 self.plugin._set_milestone_on_task(291 self.plugin._set_milestone_on_task(
290 self.projects[0], self.bugs['1'].bug_tasks[0])292 self.series[0], self.bugs['1'].bug_tasks[0])
291 self.assertEqual(293 self.assertEqual(
292 self.bugs['1'].bug_tasks[0].milestone, self.milestone_with_bug)294 self.bugs['1'].bug_tasks[0].milestone, self.milestone_with_bug)
293 self.assertIn("already has milestone",295 self.assertIn("already has milestone",
@@ -298,7 +300,7 @@
298 self.plugin.logger.info = MagicMock()300 self.plugin.logger.info = MagicMock()
299 self.plugin.config = {"set_milestone": True, "default_milestone": None}301 self.plugin.config = {"set_milestone": True, "default_milestone": None}
300 self.plugin._set_milestone_on_task(302 self.plugin._set_milestone_on_task(
301 self.projects[0], self.bugs['0'].bug_tasks[0])303 self.series[0], self.bugs['0'].bug_tasks[0])
302 self.assertEqual(304 self.assertEqual(
303 self.bugs['0'].bug_tasks[0].milestone, self.milestone_future)305 self.bugs['0'].bug_tasks[0].milestone, self.milestone_future)
304 self.assertEqual(self.plugin.logger.info.call_count, 1)306 self.assertEqual(self.plugin.logger.info.call_count, 1)

Subscribers

People subscribed via source and target branches