Merge lp:~adam-collard/tarmac/milestone-filter-by-series into lp:tarmac
- milestone-filter-by-series
- Merge into main
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
dobey | Needs Fixing | ||
Chris Glass (community) | Approve | ||
Данило Шеган (community) | Approve | ||
Review via email: mp+278946@code.launchpad.net |
Commit message
Description of the change
When setting the milestone, only look for milestones which match the series that the bug has been committed on.
- 435. By Adam Collard
-
No need to walk next_collection links
dobey (dobey) wrote : | # |
Running the tests with ./run-tests in the tree on my 14.04 system, There are 2 failures and 9 errors:
=======
ERROR: test__find_
tarmac.
-------
_StringException: Empty attachments:
log
Traceback (most recent call last):
File "/home/
milestones = list(self.
File "/home/
if milestone.name == default:
AttributeError: 'int' object has no attribute 'name'
=======
ERROR: test__find_
tarmac.
-------
_StringException: Empty attachments:
log
Traceback (most recent call last):
File "/home/
milestones = list(self.
File "/home/
if milestone.name == default:
AttributeError: 'int' object has no attribute 'name'
=======
ERROR: test__find_
tarmac.
-------
_StringException: Empty attachments:
log
Traceback (most recent call last):
File "/home/
self.
File "/home/
if milestone.
AttributeError: 'int' object has no attribute 'date_targeted'
=======
ERROR: test__find_
tarmac.
-------
_StringException: Empty attachments:
log
Traceback (most recent call last):
File "/home/
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
1 | === modified file 'tarmac/plugins/bugresolver.py' | |||
2 | --- tarmac/plugins/bugresolver.py 2014-03-24 21:38:36 +0000 | |||
3 | +++ tarmac/plugins/bugresolver.py 2015-12-02 15:37:05 +0000 | |||
4 | @@ -57,7 +57,7 @@ | |||
5 | 57 | 57 | ||
6 | 58 | if task: | 58 | if task: |
7 | 59 | task.status = u'Fix Committed' | 59 | task.status = u'Fix Committed' |
9 | 60 | self._set_milestone_on_task(project, task) | 60 | self._set_milestone_on_task(series, task) |
10 | 61 | task.lp_save() | 61 | task.lp_save() |
11 | 62 | else: | 62 | else: |
12 | 63 | self.logger.info('Target %s/%s not found in bug #%s.', | 63 | self.logger.info('Target %s/%s not found in bug #%s.', |
13 | @@ -82,7 +82,7 @@ | |||
14 | 82 | "set_milestone": set_milestone, | 82 | "set_milestone": set_milestone, |
15 | 83 | "default_milestone": default_milestone} | 83 | "default_milestone": default_milestone} |
16 | 84 | 84 | ||
18 | 85 | def _set_milestone_on_task(self, project, task): | 85 | def _set_milestone_on_task(self, series, task): |
19 | 86 | """ | 86 | """ |
20 | 87 | Attempt to auto-determine the milestone to set, and set the milestone | 87 | Attempt to auto-determine the milestone to set, and set the milestone |
21 | 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. |
22 | @@ -97,27 +97,28 @@ | |||
23 | 97 | task.bug.id, task.bug_target_name, task_milestone.name)) | 97 | task.bug.id, task.bug_target_name, task_milestone.name)) |
24 | 98 | return | 98 | return |
25 | 99 | now = datetime.utcnow() | 99 | now = datetime.utcnow() |
27 | 100 | target_milestone = self._find_target_milestone(project, now) | 100 | target_milestone = self._find_target_milestone(series, now) |
28 | 101 | self.logger.info("%s/%s: Setting Milestone: %s", | 101 | self.logger.info("%s/%s: Setting Milestone: %s", |
30 | 102 | task.bug.id, task.bug_target_name, target_milestone) | 102 | task.bug.id, task.bug_target_name, target_milestone) |
31 | 103 | task.milestone = target_milestone | 103 | task.milestone = target_milestone |
32 | 104 | 104 | ||
34 | 105 | def _find_milestones(self, project): | 105 | def _find_milestones(self, series): |
35 | 106 | """ | 106 | """ |
39 | 107 | Return list of active milestones in a project. If the config | 107 | Return iterable of active milestones in a series. If |
40 | 108 | `default_milestone` is set filter by that. If not found, an | 108 | the config `default_milestone` is set filter by that. If not |
41 | 109 | empty list will be returned. | 109 | found, an empty list will be returned. |
42 | 110 | """ | 110 | """ |
43 | 111 | default = self.config["default_milestone"] | 111 | default = self.config["default_milestone"] |
44 | 112 | milestones = series.active_milestones | ||
45 | 112 | if default is None: | 113 | if default is None: |
48 | 113 | return list(project.active_milestones) | 114 | return milestones |
49 | 114 | for milestone in project.active_milestones: | 115 | for milestone in milestones: |
50 | 115 | if milestone.name == default: | 116 | if milestone.name == default: |
51 | 116 | return [milestone] | 117 | return [milestone] |
52 | 117 | self.logger.warning("Default Milestone not found: %s" % default) | 118 | self.logger.warning("Default Milestone not found: %s" % default) |
53 | 118 | return [] | 119 | return [] |
54 | 119 | 120 | ||
56 | 120 | def _find_target_milestone(self, project, now): | 121 | def _find_target_milestone(self, series, now): |
57 | 121 | """ | 122 | """ |
58 | 122 | Find a target milestone when resolving a bug task. | 123 | Find a target milestone when resolving a bug task. |
59 | 123 | 124 | ||
60 | @@ -135,7 +136,7 @@ | |||
61 | 135 | 2) least lexically sorting milestone (by name) | 136 | 2) least lexically sorting milestone (by name) |
62 | 136 | 3) the last milestone in the list (covers len()==1 case). | 137 | 3) the last milestone in the list (covers len()==1 case). |
63 | 137 | """ | 138 | """ |
65 | 138 | milestones = self._find_milestones(project) | 139 | milestones = self._find_milestones(series) |
66 | 139 | earliest_after = latest_before = untargeted = None | 140 | earliest_after = latest_before = untargeted = None |
67 | 140 | for milestone in milestones: | 141 | for milestone in milestones: |
68 | 141 | if milestone.date_targeted is None: | 142 | if milestone.date_targeted is None: |
69 | 142 | 143 | ||
70 | === modified file 'tarmac/plugins/tests/test_bugresolver.py' | |||
71 | --- tarmac/plugins/tests/test_bugresolver.py 2014-03-24 21:38:36 +0000 | |||
72 | +++ tarmac/plugins/tests/test_bugresolver.py 2015-12-02 15:37:05 +0000 | |||
73 | @@ -76,15 +76,15 @@ | |||
74 | 76 | bug=Thing(id="1"), | 76 | bug=Thing(id="1"), |
75 | 77 | bug_target_name=self.targets[2].name)])} | 77 | bug_target_name=self.targets[2].name)])} |
76 | 78 | # Insert out of order to make sure they sort correctly. | 78 | # Insert out of order to make sure they sort correctly. |
78 | 79 | self.milestones = [ | 79 | self.milestones = Thing(total_size=4, entries=[ |
79 | 80 | self.milestone_far_future, self.milestone_with_bug, | 80 | self.milestone_far_future, self.milestone_with_bug, |
82 | 81 | self.milestone_past, self.milestone_future] | 81 | self.milestone_past, self.milestone_future]) |
83 | 82 | self.milestones_extended = [ | 82 | self.milestones_extended = Thing(total_size=3, entries=[ |
84 | 83 | self.milestone_untargeted_c, self.milestone_untargeted_b, | 83 | self.milestone_untargeted_c, self.milestone_untargeted_b, |
89 | 84 | self.milestone_untargeted_a] | 84 | self.milestone_untargeted_a]) |
90 | 85 | self.milestones_extended.extend(self.milestones) | 85 | self.milestones_extended.entries.extend(self.milestones.entries) |
91 | 86 | self.projects[0].active_milestones = self.milestones | 86 | self.series[0].active_milestones = self.milestones |
92 | 87 | self.projects[1].active_milestones = self.milestones_extended | 87 | self.series[1].active_milestones = self.milestones_extended |
93 | 88 | 88 | ||
94 | 89 | def getSeries(self, name=None): | 89 | def getSeries(self, name=None): |
95 | 90 | """Faux getSeries for testing.""" | 90 | """Faux getSeries for testing.""" |
96 | @@ -124,7 +124,7 @@ | |||
97 | 124 | launchpad = Thing(bugs=self.bugs) | 124 | launchpad = Thing(bugs=self.bugs) |
98 | 125 | command = Thing(launchpad=launchpad) | 125 | command = Thing(launchpad=launchpad) |
99 | 126 | self.plugin.run(command=command, target=target, source=None, | 126 | self.plugin.run(command=command, target=target, source=None, |
101 | 127 | proposal=self.proposal) | 127 | proposal=self.proposal) |
102 | 128 | self.assertEqual(self.bugs['0'].bug_tasks[0].milestone, | 128 | self.assertEqual(self.bugs['0'].bug_tasks[0].milestone, |
103 | 129 | self.milestone_future) | 129 | self.milestone_future) |
104 | 130 | self.assertEqual(self.bugs['1'].bug_tasks[0].milestone, | 130 | self.assertEqual(self.bugs['1'].bug_tasks[0].milestone, |
105 | @@ -173,14 +173,14 @@ | |||
106 | 173 | def test__find_target_milestone_older(self): | 173 | def test__find_target_milestone_older(self): |
107 | 174 | """Dates before all milestones return the oldest milestone.""" | 174 | """Dates before all milestones return the oldest milestone.""" |
108 | 175 | milestone = self.plugin._find_target_milestone( | 175 | milestone = self.plugin._find_target_milestone( |
110 | 176 | self.projects[0], | 176 | self.series[0], |
111 | 177 | self.milestone_past.date_targeted - timedelta(weeks=1)) | 177 | self.milestone_past.date_targeted - timedelta(weeks=1)) |
112 | 178 | self.assertEqual(milestone, self.milestone_past) | 178 | self.assertEqual(milestone, self.milestone_past) |
113 | 179 | 179 | ||
114 | 180 | def test__find_target_milestone_between(self): | 180 | def test__find_target_milestone_between(self): |
115 | 181 | """Test that dates between milestones return the closest newest.""" | 181 | """Test that dates between milestones return the closest newest.""" |
116 | 182 | milestone = self.plugin._find_target_milestone( | 182 | milestone = self.plugin._find_target_milestone( |
118 | 183 | self.projects[1], | 183 | self.series[1], |
119 | 184 | self.milestone_past.date_targeted + timedelta(weeks=1)) | 184 | self.milestone_past.date_targeted + timedelta(weeks=1)) |
120 | 185 | self.assertTrue(self.now < self.milestone_future.date_targeted) | 185 | self.assertTrue(self.now < self.milestone_future.date_targeted) |
121 | 186 | self.assertTrue(self.now > self.milestone_past.date_targeted) | 186 | self.assertTrue(self.now > self.milestone_past.date_targeted) |
122 | @@ -189,14 +189,14 @@ | |||
123 | 189 | def test__find_target_milestone_newer(self): | 189 | def test__find_target_milestone_newer(self): |
124 | 190 | """Test that dates after all milestones return the newest.""" | 190 | """Test that dates after all milestones return the newest.""" |
125 | 191 | milestone = self.plugin._find_target_milestone( | 191 | milestone = self.plugin._find_target_milestone( |
127 | 192 | self.projects[0], | 192 | self.series[0], |
128 | 193 | self.milestone_far_future.date_targeted + timedelta(weeks=1)) | 193 | self.milestone_far_future.date_targeted + timedelta(weeks=1)) |
129 | 194 | self.assertEqual(milestone, self.milestone_far_future) | 194 | self.assertEqual(milestone, self.milestone_far_future) |
130 | 195 | 195 | ||
131 | 196 | def test__find_target_milestone_lexical_sort_past_dates(self): | 196 | def test__find_target_milestone_lexical_sort_past_dates(self): |
132 | 197 | """Dates after milestones return the least sorted no-expected-date.""" | 197 | """Dates after milestones return the least sorted no-expected-date.""" |
133 | 198 | milestone = self.plugin._find_target_milestone( | 198 | milestone = self.plugin._find_target_milestone( |
135 | 199 | self.projects[1], | 199 | self.series[1], |
136 | 200 | self.milestone_far_future.date_targeted + timedelta(weeks=1)) | 200 | self.milestone_far_future.date_targeted + timedelta(weeks=1)) |
137 | 201 | self.assertEqual(milestone, self.milestone_untargeted_a) | 201 | self.assertEqual(milestone, self.milestone_untargeted_a) |
138 | 202 | 202 | ||
139 | @@ -204,32 +204,33 @@ | |||
140 | 204 | """Test that specifying a default gets a specific milestone.""" | 204 | """Test that specifying a default gets a specific milestone.""" |
141 | 205 | self.plugin.config["default_milestone"] = "c" | 205 | self.plugin.config["default_milestone"] = "c" |
142 | 206 | milestone = self.plugin._find_target_milestone( | 206 | milestone = self.plugin._find_target_milestone( |
144 | 207 | self.projects[1], | 207 | self.series[1], |
145 | 208 | self.milestone_far_future.date_targeted + timedelta(weeks=1)) | 208 | self.milestone_far_future.date_targeted + timedelta(weeks=1)) |
146 | 209 | self.assertEqual(milestone, self.milestone_untargeted_c) | 209 | self.assertEqual(milestone, self.milestone_untargeted_c) |
147 | 210 | 210 | ||
148 | 211 | def test__find_milestone_positive(self): | 211 | def test__find_milestone_positive(self): |
149 | 212 | """Given a project, the list of milestones is returned.""" | 212 | """Given a project, the list of milestones is returned.""" |
151 | 213 | milestones = self.plugin._find_milestones(self.projects[1]) | 213 | milestones = list(self.plugin._find_milestones(self.series[1])) |
152 | 214 | self.assertEqual(len(milestones), 7) | 214 | self.assertEqual(len(milestones), 7) |
153 | 215 | 215 | ||
154 | 216 | def test__find_milestone_negative(self): | 216 | def test__find_milestone_negative(self): |
155 | 217 | """Given a project with no milestones, _find_milestone handles it""" | 217 | """Given a project with no milestones, _find_milestone handles it""" |
157 | 218 | milestones = self.plugin._find_milestones(Thing(active_milestones=[])) | 218 | milestones = list(self.plugin._find_milestones( |
158 | 219 | Thing(active_milestones=Thing(total_size=0, entries=[])))) | ||
159 | 219 | self.assertEqual(len(milestones), 0) | 220 | self.assertEqual(len(milestones), 0) |
160 | 220 | 221 | ||
161 | 221 | def test__find_milestone_specific_negative(self): | 222 | def test__find_milestone_specific_negative(self): |
162 | 222 | """Find a secific milestone that isn't there, check for log""" | 223 | """Find a secific milestone that isn't there, check for log""" |
163 | 223 | self.plugin.logger.warning = MagicMock() | 224 | self.plugin.logger.warning = MagicMock() |
164 | 224 | self.plugin.config["default_milestone"] = "FOO" | 225 | self.plugin.config["default_milestone"] = "FOO" |
166 | 225 | milestones = self.plugin._find_milestones(self.projects[0]) | 226 | milestones = list(self.plugin._find_milestones(self.series[0])) |
167 | 226 | self.assertEqual(len(milestones), 0) | 227 | self.assertEqual(len(milestones), 0) |
168 | 227 | self.assertEqual(self.plugin.logger.warning.call_count, 1) | 228 | self.assertEqual(self.plugin.logger.warning.call_count, 1) |
169 | 228 | 229 | ||
170 | 229 | def test__find_milestone_no_dates(self): | 230 | def test__find_milestone_no_dates(self): |
171 | 230 | """Find a specific milestones without a targeted date""" | 231 | """Find a specific milestones without a targeted date""" |
172 | 231 | self.plugin.config["default_milestone"] = "b" | 232 | self.plugin.config["default_milestone"] = "b" |
174 | 232 | milestones = self.plugin._find_milestones(self.projects[1]) | 233 | milestones = list(self.plugin._find_milestones(self.series[1])) |
175 | 233 | self.assertEqual(len(milestones), 1) | 234 | self.assertEqual(len(milestones), 1) |
176 | 234 | self.assertEqual(milestones[0], self.milestone_untargeted_b) | 235 | self.assertEqual(milestones[0], self.milestone_untargeted_b) |
177 | 235 | 236 | ||
178 | @@ -277,7 +278,7 @@ | |||
179 | 277 | self.plugin.config = { | 278 | self.plugin.config = { |
180 | 278 | "set_milestone": False, "default_milestone": None} | 279 | "set_milestone": False, "default_milestone": None} |
181 | 279 | self.plugin._set_milestone_on_task( | 280 | self.plugin._set_milestone_on_task( |
183 | 280 | self.projects[0], self.bugs['0'].bug_tasks[0]) | 281 | self.series[0], self.bugs['0'].bug_tasks[0]) |
184 | 281 | self.assertEqual(self.bugs['0'].bug_tasks[0].milestone, None) | 282 | self.assertEqual(self.bugs['0'].bug_tasks[0].milestone, None) |
185 | 282 | self.assertEqual(self.plugin.logger.info.call_count, 0) | 283 | self.assertEqual(self.plugin.logger.info.call_count, 0) |
186 | 283 | self.assertEqual(self.plugin.logger.warning.call_count, 0) | 284 | self.assertEqual(self.plugin.logger.warning.call_count, 0) |
187 | @@ -285,9 +286,10 @@ | |||
188 | 285 | def test__set_milestone_on_task_milestone_already_set(self): | 286 | def test__set_milestone_on_task_milestone_already_set(self): |
189 | 286 | """milestone is already set, should leave task untouched""" | 287 | """milestone is already set, should leave task untouched""" |
190 | 287 | self.plugin.logger.info = MagicMock() | 288 | self.plugin.logger.info = MagicMock() |
192 | 288 | self.plugin.config = {"set_milestone": True, "default_milestone": "past"} | 289 | self.plugin.config = {"set_milestone": True, |
193 | 290 | "default_milestone": "past"} | ||
194 | 289 | self.plugin._set_milestone_on_task( | 291 | self.plugin._set_milestone_on_task( |
196 | 290 | self.projects[0], self.bugs['1'].bug_tasks[0]) | 292 | self.series[0], self.bugs['1'].bug_tasks[0]) |
197 | 291 | self.assertEqual( | 293 | self.assertEqual( |
198 | 292 | self.bugs['1'].bug_tasks[0].milestone, self.milestone_with_bug) | 294 | self.bugs['1'].bug_tasks[0].milestone, self.milestone_with_bug) |
199 | 293 | self.assertIn("already has milestone", | 295 | self.assertIn("already has milestone", |
200 | @@ -298,7 +300,7 @@ | |||
201 | 298 | self.plugin.logger.info = MagicMock() | 300 | self.plugin.logger.info = MagicMock() |
202 | 299 | self.plugin.config = {"set_milestone": True, "default_milestone": None} | 301 | self.plugin.config = {"set_milestone": True, "default_milestone": None} |
203 | 300 | self.plugin._set_milestone_on_task( | 302 | self.plugin._set_milestone_on_task( |
205 | 301 | self.projects[0], self.bugs['0'].bug_tasks[0]) | 303 | self.series[0], self.bugs['0'].bug_tasks[0]) |
206 | 302 | self.assertEqual( | 304 | self.assertEqual( |
207 | 303 | self.bugs['0'].bug_tasks[0].milestone, self.milestone_future) | 305 | self.bugs['0'].bug_tasks[0].milestone, self.milestone_future) |
208 | 304 | self.assertEqual(self.plugin.logger.info.call_count, 1) | 306 | self.assertEqual(self.plugin.logger.info.call_count, 1) |
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.