Merge lp:~robru/cupstream2distro/detect-new-commits-when-building into lp:cupstream2distro
- detect-new-commits-when-building
- Merge into trunk
Status: | Merged |
---|---|
Merged at revision: | 1160 |
Proposed branch: | lp:~robru/cupstream2distro/detect-new-commits-when-building |
Merge into: | lp:cupstream2distro |
Diff against target: |
330 lines (+85/-106) 6 files modified
citrain/build.py (+12/-32) citrain/recipes/manager.py (+1/-1) citrain/recipes/merge.py (+19/-15) tests/unit/__init__.py (+1/-0) tests/unit/test_recipe_merge.py (+2/-0) tests/unit/test_script_build.py (+50/-58) |
To merge this branch: | bzr merge lp:~robru/cupstream2distro/detect-new-commits-when-building |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
PS Jenkins bot | continuous-integration | Needs Fixing | |
Robert Bruce Park (community) | Approve | ||
Review via email: mp+274960@code.launchpad.net |
Commit message
Detect which packages have new commits to build.
Description of the change
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1168
http://
Executed test runs:
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1170
http://
Executed test runs:
Click here to trigger a rebuild:
http://
Robert Bruce Park (robru) wrote : | # |
Ok I think this is making sense, will just test in staging tomorrow before merging.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1172
http://
Executed test runs:
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:1173
http://
Executed test runs:
Click here to trigger a rebuild:
http://
PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:1174
http://
Executed test runs:
Click here to trigger a rebuild:
http://
Robert Bruce Park (robru) wrote : | # |
Staging instance has apparently imploded so I'm not able to test this, but I'm confident with the tests and will monitor production closely for regressions.
PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Autolanding.
More details in the following jenkins job:
http://
Executed test runs:
Preview Diff
1 | === modified file 'citrain/build.py' | |||
2 | --- citrain/build.py 2015-10-17 09:26:56 +0000 | |||
3 | +++ citrain/build.py 2015-10-20 09:18:51 +0000 | |||
4 | @@ -47,49 +47,30 @@ | |||
5 | 47 | 47 | ||
6 | 48 | sys.path.append(os.path.dirname(os.path.dirname(__file__))) | 48 | sys.path.append(os.path.dirname(os.path.dirname(__file__))) |
7 | 49 | 49 | ||
8 | 50 | from glob import glob | ||
9 | 51 | from os.path import basename | ||
10 | 52 | |||
11 | 53 | from citrain.recipes.base import missing | 50 | from citrain.recipes.base import missing |
12 | 51 | from citrain.recipes.merge import check_for_unbuilt_revids | ||
13 | 54 | from citrain.recipes.manager import Manager | 52 | from citrain.recipes.manager import Manager |
15 | 55 | from cupstream2distro.silomanager import SiloState | 53 | from cupstream2distro.silomanager import SiloState, get_dirty, splitter |
16 | 56 | from cupstream2distro.errors import BuildError, CITrainError | 54 | from cupstream2distro.errors import BuildError, CITrainError |
27 | 57 | from cupstream2distro.utils import SILO_DIR, env, run_script | 55 | from cupstream2distro.utils import env, run_script |
18 | 58 | |||
19 | 59 | |||
20 | 60 | def find_all_uploaded(): | ||
21 | 61 | """Return all source package names and versions uploaded to the ppa. | ||
22 | 62 | |||
23 | 63 | :yields: Source package names that have been uploaded. | ||
24 | 64 | """ | ||
25 | 65 | for uploaded in glob(SILO_DIR('*_source.ppa.upload')): | ||
26 | 66 | yield basename(uploaded).split('_')[0] | ||
28 | 67 | 56 | ||
29 | 68 | 57 | ||
30 | 69 | class BuildManager(Manager): | 58 | class BuildManager(Manager): |
31 | 70 | """Honor PACKAGES_TO_REBUILD during building.""" | 59 | """Honor PACKAGES_TO_REBUILD during building.""" |
32 | 71 | 60 | ||
33 | 72 | def include_all(self): | ||
34 | 73 | """Ignore PACKAGES_TO_REBUILD and include all.""" | ||
35 | 74 | self.choose_packages = super().choose_packages | ||
36 | 75 | self.types.clear() | ||
37 | 76 | |||
38 | 77 | def choose_packages(self): | 61 | def choose_packages(self): |
39 | 78 | """Decide which packages need to be built.""" | 62 | """Decide which packages need to be built.""" |
42 | 79 | self.names = set(env.PACKAGES_TO_REBUILD.split() | 63 | all_projects = set(self.silo_state.all_projects) |
43 | 80 | or self.silo_state.all_projects) | 64 | self.names = set(splitter(env.PACKAGES_TO_REBUILD) or all_projects) |
44 | 81 | self.names.update(missing(self.names)) | 65 | self.names.update(missing(self.names)) |
45 | 82 | include_all = 'true' in (env.FORCE_REBUILD, env.WATCH_ONLY) | 66 | include_all = 'true' in (env.FORCE_REBUILD, env.WATCH_ONLY) |
46 | 83 | if not (include_all or env.PACKAGES_TO_REBUILD): | 67 | if not (include_all or env.PACKAGES_TO_REBUILD): |
56 | 84 | # Don't rebuild existing builds without forcing. | 68 | for source, merges in self.silo_state.mps.items(): |
57 | 85 | previous = self.names & set(find_all_uploaded()) | 69 | if check_for_unbuilt_revids(source, merges) == []: |
58 | 86 | if previous: | 70 | logging.info(source + ' has no new commits, skipping.') |
59 | 87 | logging.info('{} already built, skipping.'.format( | 71 | self.names.discard(source) |
60 | 88 | ', '.join(previous))) | 72 | self.names.update(set(get_dirty(env.SILONAME)) & all_projects) |
61 | 89 | self.names -= previous | 73 | if not self.names: |
53 | 90 | if self.names: | ||
54 | 91 | logging.info('Including {}.'.format(', '.join(self.names))) | ||
55 | 92 | else: | ||
62 | 93 | raise BuildError( | 74 | raise BuildError( |
63 | 94 | 'No packages are being considered. You probably want one of ' | 75 | 'No packages are being considered. You probably want one of ' |
64 | 95 | 'PACKAGES_TO_REBUILD, FORCE_REBUILD, or WATCH_ONLY.') | 76 | 'PACKAGES_TO_REBUILD, FORCE_REBUILD, or WATCH_ONLY.') |
65 | @@ -106,8 +87,7 @@ | |||
66 | 106 | manager.do('validate') | 87 | manager.do('validate') |
67 | 107 | if env.WATCH_ONLY != 'true': | 88 | if env.WATCH_ONLY != 'true': |
68 | 108 | manager.do('clean', 'collect', 'build', 'upload') | 89 | manager.do('clean', 'collect', 'build', 'upload') |
71 | 109 | manager.include_all() | 90 | Manager(silo_state).do('watch', 'diff') |
70 | 110 | manager.do('watch', 'diff') | ||
72 | 111 | silo_state.status = 'Packages built.' | 91 | silo_state.status = 'Packages built.' |
73 | 112 | except CITrainError as err: | 92 | except CITrainError as err: |
74 | 113 | logging.error(str(err)) | 93 | logging.error(str(err)) |
75 | 114 | 94 | ||
76 | === modified file 'citrain/recipes/manager.py' | |||
77 | --- citrain/recipes/manager.py 2015-10-07 19:47:09 +0000 | |||
78 | +++ citrain/recipes/manager.py 2015-10-20 09:18:51 +0000 | |||
79 | @@ -54,6 +54,7 @@ | |||
80 | 54 | self.choose_packages() | 54 | self.choose_packages() |
81 | 55 | self.choose_classes() | 55 | self.choose_classes() |
82 | 56 | self.instantiate_build_objects() | 56 | self.instantiate_build_objects() |
83 | 57 | logging.info('Including {}.'.format(', '.join(sorted(self.names)))) | ||
84 | 57 | for phase in phases: | 58 | for phase in phases: |
85 | 58 | self.execute_phase(phase) | 59 | self.execute_phase(phase) |
86 | 59 | 60 | ||
87 | @@ -64,7 +65,6 @@ | |||
88 | 64 | def choose_packages(self): | 65 | def choose_packages(self): |
89 | 65 | """Act on all silo packages.""" | 66 | """Act on all silo packages.""" |
90 | 66 | self.names = set(self.silo_state.all_projects) | 67 | self.names = set(self.silo_state.all_projects) |
91 | 67 | logging.info('Including {}.'.format(', '.join(self.names))) | ||
92 | 68 | 68 | ||
93 | 69 | def choose_classes(self): | 69 | def choose_classes(self): |
94 | 70 | """Decide which class to use for each individual package build.""" | 70 | """Decide which class to use for each individual package build.""" |
95 | 71 | 71 | ||
96 | === modified file 'citrain/recipes/merge.py' | |||
97 | --- citrain/recipes/merge.py 2015-10-19 22:13:22 +0000 | |||
98 | +++ citrain/recipes/merge.py 2015-10-20 09:18:51 +0000 | |||
99 | @@ -77,6 +77,21 @@ | |||
100 | 77 | raise PrepError('Not all MPs targeting same branch.') | 77 | raise PrepError('Not all MPs targeting same branch.') |
101 | 78 | 78 | ||
102 | 79 | 79 | ||
103 | 80 | def check_for_unbuilt_revids(source, merges): | ||
104 | 81 | """Return a list of MPs that have new commits since last build.""" | ||
105 | 82 | unbuilt = [] | ||
106 | 83 | logging.info('Checking {} for new commits...'.format(source)) | ||
107 | 84 | # TODO: check also the merge target revids, which only just started being | ||
108 | 85 | # recorded and need time to appear in production. | ||
109 | 86 | for merge in merges: | ||
110 | 87 | url = merge.web_link | ||
111 | 88 | revid = Rev(source, url).read() | ||
112 | 89 | if merge.source_branch.last_scanned_id != revid: | ||
113 | 90 | unbuilt.append(url) | ||
114 | 91 | logging.info('New commits: ' + url) | ||
115 | 92 | return unbuilt | ||
116 | 93 | |||
117 | 94 | |||
118 | 80 | class Merge(BuildBase): | 95 | class Merge(BuildBase): |
119 | 81 | """Build a source package from a series of merge proposals. | 96 | """Build a source package from a series of merge proposals. |
120 | 82 | 97 | ||
121 | @@ -86,18 +101,6 @@ | |||
122 | 86 | all_mps = {} | 101 | all_mps = {} |
123 | 87 | merges = None | 102 | merges = None |
124 | 88 | 103 | ||
125 | 89 | def check_for_unbuilt_revids(self): | ||
126 | 90 | """Return a list of MPs that have new commits since last build.""" | ||
127 | 91 | unbuilt = [] | ||
128 | 92 | logging.info('Checking {} for new commits...'.format(self.name)) | ||
129 | 93 | for merge in self.merges: | ||
130 | 94 | url = merge.web_link | ||
131 | 95 | revid = Rev(self.name, url).read() | ||
132 | 96 | if merge.source_branch.last_scanned_id != revid: | ||
133 | 97 | unbuilt.append(url) | ||
134 | 98 | logging.error('New commits: ' + url) | ||
135 | 99 | return unbuilt | ||
136 | 100 | |||
137 | 101 | def enforce_merge_states(self, acceptable): | 104 | def enforce_merge_states(self, acceptable): |
138 | 102 | """Block when merges have bad states.""" | 105 | """Block when merges have bad states.""" |
139 | 103 | # (\/) (°,,,°) (\/) | 106 | # (\/) (°,,,°) (\/) |
140 | @@ -128,8 +131,9 @@ | |||
141 | 128 | """ | 131 | """ |
142 | 129 | logging.info('Preparing merges for {}.'.format(self.name)) | 132 | logging.info('Preparing merges for {}.'.format(self.name)) |
143 | 130 | merges = self.merges = reorder_branches(self.merges) | 133 | merges = self.merges = reorder_branches(self.merges) |
146 | 131 | target = merges[0].target_branch.web_link | 134 | target = merges[0].target_branch |
147 | 132 | self.get_branch(target) | 135 | Rev(self.name, target.web_link).write(target.last_scanned_id) |
148 | 136 | self.get_branch(target.web_link) | ||
149 | 133 | trunk_version = self.get_package_version() | 137 | trunk_version = self.get_package_version() |
150 | 134 | DotProject.soft_save(self.name, dest=trunk_version) | 138 | DotProject.soft_save(self.name, dest=trunk_version) |
151 | 135 | for merge in merges: | 139 | for merge in merges: |
152 | @@ -238,7 +242,7 @@ | |||
153 | 238 | 242 | ||
154 | 239 | def unbuilt_phase(self): | 243 | def unbuilt_phase(self): |
155 | 240 | """Block publication of merges that have new commits.""" | 244 | """Block publication of merges that have new commits.""" |
157 | 241 | if self.check_for_unbuilt_revids(): | 245 | if check_for_unbuilt_revids(self.name, self.merges): |
158 | 242 | self.failures.add(self.name + ' has new, unbuilt commits.') | 246 | self.failures.add(self.name + ' has new, unbuilt commits.') |
159 | 243 | 247 | ||
160 | 244 | def merge_phase(self): | 248 | def merge_phase(self): |
161 | 245 | 249 | ||
162 | === modified file 'tests/unit/__init__.py' | |||
163 | --- tests/unit/__init__.py 2015-09-22 06:53:49 +0000 | |||
164 | +++ tests/unit/__init__.py 2015-10-20 09:18:51 +0000 | |||
165 | @@ -144,6 +144,7 @@ | |||
166 | 144 | self.script.Archive = Mock() | 144 | self.script.Archive = Mock() |
167 | 145 | self.script.Branch = Mock() | 145 | self.script.Branch = Mock() |
168 | 146 | self.script.DotProject = Mock() | 146 | self.script.DotProject = Mock() |
169 | 147 | self.script.Manager = Mock() | ||
170 | 147 | self.script.Package = Mock() | 148 | self.script.Package = Mock() |
171 | 148 | self.script.Rev = Mock() | 149 | self.script.Rev = Mock() |
172 | 149 | self.script.SiloState = Mock() | 150 | self.script.SiloState = Mock() |
173 | 150 | 151 | ||
174 | === modified file 'tests/unit/test_recipe_merge.py' | |||
175 | --- tests/unit/test_recipe_merge.py 2015-10-19 22:13:22 +0000 | |||
176 | +++ tests/unit/test_recipe_merge.py 2015-10-20 09:18:51 +0000 | |||
177 | @@ -242,6 +242,8 @@ | |||
178 | 242 | ]) | 242 | ]) |
179 | 243 | authors = merge.get_remote_branch_authors() | 243 | authors = merge.get_remote_branch_authors() |
180 | 244 | self.assertEqual(rev_mock.mock_calls, [ | 244 | self.assertEqual(rev_mock.mock_calls, [ |
181 | 245 | call('a', merge1.target_branch.web_link), | ||
182 | 246 | call().write(merge1.target_branch.last_scanned_id), | ||
183 | 245 | call('a', merge1.web_link), | 247 | call('a', merge1.web_link), |
184 | 246 | call().write(merge1.source_branch.last_scanned_id), | 248 | call().write(merge1.source_branch.last_scanned_id), |
185 | 247 | call('a', merge2.web_link), | 249 | call('a', merge2.web_link), |
186 | 248 | 250 | ||
187 | === modified file 'tests/unit/test_script_build.py' | |||
188 | --- tests/unit/test_script_build.py 2015-10-17 09:26:56 +0000 | |||
189 | +++ tests/unit/test_script_build.py 2015-10-20 09:18:51 +0000 | |||
190 | @@ -56,52 +56,40 @@ | |||
191 | 56 | self.series = Mock() | 56 | self.series = Mock() |
192 | 57 | self.ppa = Mock() | 57 | self.ppa = Mock() |
193 | 58 | 58 | ||
194 | 59 | def test_find_all_uploaded(self): | ||
195 | 60 | """Find everything that has been uploaded from this silo.""" | ||
196 | 61 | self.script.glob.return_value = [ | ||
197 | 62 | '/path/to/foo_0.1_source.ppa.upload', | ||
198 | 63 | '/path/to/bar_0.2_source.ppa.upload', | ||
199 | 64 | ] | ||
200 | 65 | self.assertEqual( | ||
201 | 66 | sorted(self.script.find_all_uploaded()), ['bar', 'foo']) | ||
202 | 67 | |||
203 | 68 | def test_find_all_uploaded_multiple_series(self): | ||
204 | 69 | """We can handle uploading multiple series from a single silo.""" | ||
205 | 70 | self.script.glob.return_value = [ | ||
206 | 71 | '/path/to/foo_0.1_source.ppa.upload', | ||
207 | 72 | '/path/to/foo_0.1~utopic_source.ppa.upload', | ||
208 | 73 | '/path/to/bar_0.2_source.ppa.upload', | ||
209 | 74 | '/path/to/bar_0.2~utopic_source.ppa.upload', | ||
210 | 75 | ] | ||
211 | 76 | self.assertEqual( | ||
212 | 77 | sorted(self.script.find_all_uploaded()), | ||
213 | 78 | ['bar', 'bar', 'foo', 'foo']) | ||
214 | 79 | self.assertEqual( | ||
215 | 80 | set(self.script.find_all_uploaded()), set(['foo', 'bar'])) | ||
216 | 81 | |||
217 | 82 | def test_buildmanager_include_all(self): | ||
218 | 83 | """Correctly switch to watching all packages.""" | ||
219 | 84 | bman = self.script.BuildManager(Mock()) | ||
220 | 85 | bman.types['foo'] = 'bar' | ||
221 | 86 | self.assertEqual( | ||
222 | 87 | bman.choose_packages.__doc__, | ||
223 | 88 | 'Decide which packages need to be built.') | ||
224 | 89 | bman.include_all() | ||
225 | 90 | self.assertEqual( | ||
226 | 91 | bman.choose_packages.__doc__, | ||
227 | 92 | 'Act on all silo packages.') | ||
228 | 93 | self.assertFalse(bman.types) | ||
229 | 94 | |||
230 | 95 | def test_buildmanager_choose_packages(self): | 59 | def test_buildmanager_choose_packages(self): |
231 | 96 | """Determine what packages to act upon.""" | 60 | """Determine what packages to act upon.""" |
232 | 97 | silo_state = Mock( | 61 | silo_state = Mock( |
240 | 98 | all_projects=['a', 'b', 'c'], mps=['a'], sources=['b', 'c']) | 62 | all_projects=list('abcd'), |
241 | 99 | self.script.env.PACKAGES_TO_REBUILD = '' | 63 | mps=dict( |
242 | 100 | self.script.env.FORCE_REBUILD = 'false' | 64 | c=[Mock( |
243 | 101 | self.script.find_all_uploaded = Mock(return_value=['c']) | 65 | source_branch=Mock(last_scanned_id=None), |
244 | 102 | bman = self.script.BuildManager(silo_state) | 66 | web_link='foo/123')], |
245 | 103 | bman.choose_packages() | 67 | d=[Mock( |
246 | 104 | self.assertEqual(bman.names, set(['a', 'b'])) | 68 | source_branch=Mock(last_scanned_id='stale'), |
247 | 69 | web_link='foo/789')]), | ||
248 | 70 | sources=list('abcd')) | ||
249 | 71 | self.script.env.PACKAGES_TO_REBUILD = '' | ||
250 | 72 | self.script.env.FORCE_REBUILD = 'false' | ||
251 | 73 | bman = self.script.BuildManager(silo_state) | ||
252 | 74 | bman.choose_packages() | ||
253 | 75 | self.assertEqual(bman.names, {'a', 'b', 'd'}) | ||
254 | 76 | |||
255 | 77 | def test_buildmanager_choose_packages_dirty(self): | ||
256 | 78 | """Include dirty packages by default.""" | ||
257 | 79 | self.script.get_dirty = Mock(return_value=list('abcde')) | ||
258 | 80 | silo_state = Mock( | ||
259 | 81 | all_projects=list('abcd'), | ||
260 | 82 | mps=dict( | ||
261 | 83 | c=[Mock( | ||
262 | 84 | source_branch=Mock(last_scanned_id=None), | ||
263 | 85 | web_link='foo/123')]), | ||
264 | 86 | sources=list('abcd')) | ||
265 | 87 | self.script.env.PACKAGES_TO_REBUILD = '' | ||
266 | 88 | self.script.env.FORCE_REBUILD = 'false' | ||
267 | 89 | bman = self.script.BuildManager(silo_state) | ||
268 | 90 | bman.choose_packages() | ||
269 | 91 | self.script.get_dirty.assert_called_once_with(self.tempdir) | ||
270 | 92 | self.assertEqual(bman.names, set('abcd')) | ||
271 | 105 | 93 | ||
272 | 106 | def test_buildmanager_choose_packages_twins(self): | 94 | def test_buildmanager_choose_packages_twins(self): |
273 | 107 | """Always add twins for all builds.""" | 95 | """Always add twins for all builds.""" |
274 | @@ -116,10 +104,14 @@ | |||
275 | 116 | def test_buildmanager_choose_packages_none_found(self): | 104 | def test_buildmanager_choose_packages_none_found(self): |
276 | 117 | """Fail when no packages to act upon.""" | 105 | """Fail when no packages to act upon.""" |
277 | 118 | silo_state = Mock( | 106 | silo_state = Mock( |
279 | 119 | all_projects=['a', 'b', 'c'], mps=['a'], sources=['b', 'c']) | 107 | all_projects=['a'], |
280 | 108 | mps=dict(a=[Mock( | ||
281 | 109 | source_branch=Mock(last_scanned_id=None), | ||
282 | 110 | web_link='foo/123')]), | ||
283 | 111 | sources=[]) | ||
284 | 120 | self.script.env.PACKAGES_TO_REBUILD = '' | 112 | self.script.env.PACKAGES_TO_REBUILD = '' |
285 | 121 | self.script.env.FORCE_REBUILD = 'false' | 113 | self.script.env.FORCE_REBUILD = 'false' |
287 | 122 | self.script.find_all_uploaded = Mock(return_value=list('abc')) | 114 | self.script.env.WATCH_ONLY = 'false' |
288 | 123 | bman = self.script.BuildManager(silo_state) | 115 | bman = self.script.BuildManager(silo_state) |
289 | 124 | with self.assertRaisesRegexp(BuildError, 'No packages are being'): | 116 | with self.assertRaisesRegexp(BuildError, 'No packages are being'): |
290 | 125 | bman.choose_packages() | 117 | bman.choose_packages() |
291 | @@ -132,13 +124,13 @@ | |||
292 | 132 | bman = self.script.BuildManager = Mock() | 124 | bman = self.script.BuildManager = Mock() |
293 | 133 | self.assertEqual(self.script.main(bman), 0) | 125 | self.assertEqual(self.script.main(bman), 0) |
294 | 134 | bman.assert_called_once_with(silo_state) | 126 | bman.assert_called_once_with(silo_state) |
302 | 135 | self.assertEqual( | 127 | self.assertEqual(bman.return_value.mock_calls, [ |
303 | 136 | bman.return_value.mock_calls, [ | 128 | call.do('validate'), |
304 | 137 | call.do('validate'), | 129 | call.do('clean', 'collect', 'build', 'upload'), |
305 | 138 | call.do('clean', 'collect', 'build', 'upload'), | 130 | ]) |
306 | 139 | call.include_all(), | 131 | self.assertEqual(self.script.Manager.return_value.mock_calls, [ |
307 | 140 | call.do('watch', 'diff'), | 132 | call.do('watch', 'diff'), |
308 | 141 | ]) | 133 | ]) |
309 | 142 | self.assertEqual(silo_state.status, 'Packages built.') | 134 | self.assertEqual(silo_state.status, 'Packages built.') |
310 | 143 | silo_state.mark_dirty.assert_called_once_with() | 135 | silo_state.mark_dirty.assert_called_once_with() |
311 | 144 | silo_state.save_config.assert_called_once_with() | 136 | silo_state.save_config.assert_called_once_with() |
312 | @@ -150,12 +142,12 @@ | |||
313 | 150 | bman = self.script.BuildManager = Mock() | 142 | bman = self.script.BuildManager = Mock() |
314 | 151 | self.assertEqual(self.script.main(bman), 0) | 143 | self.assertEqual(self.script.main(bman), 0) |
315 | 152 | bman.assert_called_once_with(silo_state) | 144 | bman.assert_called_once_with(silo_state) |
322 | 153 | self.assertEqual( | 145 | self.assertEqual(bman.return_value.mock_calls, [ |
323 | 154 | bman.return_value.mock_calls, [ | 146 | call.do('validate'), |
324 | 155 | call.do('validate'), | 147 | ]) |
325 | 156 | call.include_all(), | 148 | self.assertEqual(self.script.Manager.return_value.mock_calls, [ |
326 | 157 | call.do('watch', 'diff'), | 149 | call.do('watch', 'diff'), |
327 | 158 | ]) | 150 | ]) |
328 | 159 | silo_state.save_config.assert_called_once_with() | 151 | silo_state.save_config.assert_called_once_with() |
329 | 160 | 152 | ||
330 | 161 | def test_main_error(self): | 153 | def test_main_error(self): |
TODO:
* write tests
* test in staging
* should probably also scan trunk revids
* should also include packages marked dirty.