Merge lp:~cjwatson/launchpad/snap-revision-id into lp:launchpad
- snap-revision-id
- Merge into devel
Proposed by
Colin Watson
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | 18366 | ||||
Proposed branch: | lp:~cjwatson/launchpad/snap-revision-id | ||||
Merge into: | lp:launchpad | ||||
Diff against target: |
254 lines (+96/-18) 9 files modified
lib/lp/buildmaster/interactor.py (+7/-10) lib/lp/buildmaster/interfaces/buildqueue.py (+4/-1) lib/lp/buildmaster/model/buildqueue.py (+14/-1) lib/lp/buildmaster/tests/test_manager.py (+37/-6) lib/lp/snappy/browser/tests/test_snapbuild.py (+10/-0) lib/lp/snappy/interfaces/snapbuild.py (+6/-0) lib/lp/snappy/model/snapbuild.py (+6/-0) lib/lp/snappy/templates/snapbuild-index.pt (+3/-0) lib/lp/snappy/tests/test_snapbuild.py (+9/-0) |
||||
To merge this branch: | bzr merge lp:~cjwatson/launchpad/snap-revision-id | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
William Grant (community) | code | Approve | |
Review via email: mp+321690@code.launchpad.net |
Commit message
Populate SnapBuild.
Description of the change
To post a comment you must log in.
Revision history for this message
Adam Collard (adam-collard) : | # |
Revision history for this message
Colin Watson (cjwatson) : | # |
Revision history for this message
William Grant (wgrant) : | # |
review:
Approve
(code)
Revision history for this message
Colin Watson (cjwatson) : | # |
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'lib/lp/buildmaster/interactor.py' | |||
2 | --- lib/lp/buildmaster/interactor.py 2016-06-06 12:55:36 +0000 | |||
3 | +++ lib/lp/buildmaster/interactor.py 2017-04-27 15:55:40 +0000 | |||
4 | @@ -1,4 +1,4 @@ | |||
6 | 1 | # Copyright 2009-2016 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2017 Canonical Ltd. This software is licensed under the |
7 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
8 | 3 | 3 | ||
9 | 4 | __metaclass__ = type | 4 | __metaclass__ = type |
10 | @@ -536,15 +536,12 @@ | |||
11 | 536 | # matches the DB, and this method isn't called unless the DB | 536 | # matches the DB, and this method isn't called unless the DB |
12 | 537 | # says there's a job. | 537 | # says there's a job. |
13 | 538 | builder_status = slave_status['builder_status'] | 538 | builder_status = slave_status['builder_status'] |
23 | 539 | if builder_status == 'BuilderStatus.BUILDING': | 539 | if builder_status in ( |
24 | 540 | # Build still building, collect the logtail. | 540 | 'BuilderStatus.BUILDING', 'BuilderStatus.ABORTING'): |
25 | 541 | vitals.build_queue.logtail = str( | 541 | vitals.build_queue.collectStatus(slave_status) |
26 | 542 | slave_status.get('logtail')).decode('UTF-8', errors='replace') | 542 | vitals.build_queue.specific_build.updateStatus( |
27 | 543 | transaction.commit() | 543 | vitals.build_queue.specific_build.status, |
28 | 544 | elif builder_status == 'BuilderStatus.ABORTING': | 544 | slave_status=slave_status) |
20 | 545 | # Build is being aborted. | ||
21 | 546 | vitals.build_queue.logtail = ( | ||
22 | 547 | "Waiting for slave process to be terminated") | ||
29 | 548 | transaction.commit() | 545 | transaction.commit() |
30 | 549 | elif builder_status == 'BuilderStatus.WAITING': | 546 | elif builder_status == 'BuilderStatus.WAITING': |
31 | 550 | # Build has finished. Delegate handling to the build itself. | 547 | # Build has finished. Delegate handling to the build itself. |
32 | 551 | 548 | ||
33 | === modified file 'lib/lp/buildmaster/interfaces/buildqueue.py' | |||
34 | --- lib/lp/buildmaster/interfaces/buildqueue.py 2015-04-20 09:48:57 +0000 | |||
35 | +++ lib/lp/buildmaster/interfaces/buildqueue.py 2017-04-27 15:55:40 +0000 | |||
36 | @@ -1,4 +1,4 @@ | |||
38 | 1 | # Copyright 2009-2013 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2017 Canonical Ltd. This software is licensed under the |
39 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
40 | 3 | 3 | ||
41 | 4 | """Build interfaces.""" | 4 | """Build interfaces.""" |
42 | @@ -86,6 +86,9 @@ | |||
43 | 86 | def markAsBuilding(builder): | 86 | def markAsBuilding(builder): |
44 | 87 | """Set this queue item to a 'building' state.""" | 87 | """Set this queue item to a 'building' state.""" |
45 | 88 | 88 | ||
46 | 89 | def collectStatus(slave_status): | ||
47 | 90 | """Collect status information from the builder.""" | ||
48 | 91 | |||
49 | 89 | def suspend(): | 92 | def suspend(): |
50 | 90 | """Suspend this waiting job, removing it from the active queue.""" | 93 | """Suspend this waiting job, removing it from the active queue.""" |
51 | 91 | 94 | ||
52 | 92 | 95 | ||
53 | === modified file 'lib/lp/buildmaster/model/buildqueue.py' | |||
54 | --- lib/lp/buildmaster/model/buildqueue.py 2016-05-14 00:25:07 +0000 | |||
55 | +++ lib/lp/buildmaster/model/buildqueue.py 2017-04-27 15:55:40 +0000 | |||
56 | @@ -1,4 +1,4 @@ | |||
58 | 1 | # Copyright 2009-2013 Canonical Ltd. This software is licensed under the | 1 | # Copyright 2009-2017 Canonical Ltd. This software is licensed under the |
59 | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). | 2 | # GNU Affero General Public License version 3 (see the file LICENSE). |
60 | 3 | 3 | ||
61 | 4 | __metaclass__ = type | 4 | __metaclass__ = type |
62 | @@ -180,6 +180,19 @@ | |||
63 | 180 | if builder is not None: | 180 | if builder is not None: |
64 | 181 | del get_property_cache(builder).currentjob | 181 | del get_property_cache(builder).currentjob |
65 | 182 | 182 | ||
66 | 183 | def collectStatus(self, slave_status): | ||
67 | 184 | """See `IBuildQueue`.""" | ||
68 | 185 | builder_status = slave_status["builder_status"] | ||
69 | 186 | if builder_status == "BuilderStatus.ABORTING": | ||
70 | 187 | self.logtail = "Waiting for slave process to be terminated" | ||
71 | 188 | elif slave_status.get("logtail") is not None: | ||
72 | 189 | # slave_status["logtail"] is normally an xmlrpclib.Binary | ||
73 | 190 | # instance, and the contents might include invalid UTF-8 due to | ||
74 | 191 | # being a fixed number of bytes from the tail of the log. Turn | ||
75 | 192 | # it into Unicode as best we can. | ||
76 | 193 | self.logtail = str( | ||
77 | 194 | slave_status.get("logtail")).decode("UTF-8", errors="replace") | ||
78 | 195 | |||
79 | 183 | def suspend(self): | 196 | def suspend(self): |
80 | 184 | """See `IBuildQueue`.""" | 197 | """See `IBuildQueue`.""" |
81 | 185 | if self.status != BuildQueueStatus.WAITING: | 198 | if self.status != BuildQueueStatus.WAITING: |
82 | 186 | 199 | ||
83 | === modified file 'lib/lp/buildmaster/tests/test_manager.py' | |||
84 | --- lib/lp/buildmaster/tests/test_manager.py 2016-06-06 12:50:55 +0000 | |||
85 | +++ lib/lp/buildmaster/tests/test_manager.py 2017-04-27 15:55:40 +0000 | |||
86 | @@ -2,7 +2,7 @@ | |||
87 | 2 | # NOTE: The first line above must stay first; do not move the copyright | 2 | # NOTE: The first line above must stay first; do not move the copyright |
88 | 3 | # notice to the top. See http://www.python.org/dev/peps/pep-0263/. | 3 | # notice to the top. See http://www.python.org/dev/peps/pep-0263/. |
89 | 4 | # | 4 | # |
91 | 5 | # Copyright 2009-2014 Canonical Ltd. This software is licensed under the | 5 | # Copyright 2009-2017 Canonical Ltd. This software is licensed under the |
92 | 6 | # GNU Affero General Public License version 3 (see the file LICENSE). | 6 | # GNU Affero General Public License version 3 (see the file LICENSE). |
93 | 7 | 7 | ||
94 | 8 | """Tests for the renovated slave scanner aka BuilddManager.""" | 8 | """Tests for the renovated slave scanner aka BuilddManager.""" |
95 | @@ -113,11 +113,11 @@ | |||
96 | 113 | """ | 113 | """ |
97 | 114 | super(TestSlaveScannerScan, self).setUp() | 114 | super(TestSlaveScannerScan, self).setUp() |
98 | 115 | # Creating the required chroots needed for dispatching. | 115 | # Creating the required chroots needed for dispatching. |
100 | 116 | test_publisher = make_publisher() | 116 | self.test_publisher = make_publisher() |
101 | 117 | ubuntu = getUtility(IDistributionSet).getByName('ubuntu') | 117 | ubuntu = getUtility(IDistributionSet).getByName('ubuntu') |
102 | 118 | hoary = ubuntu.getSeries('hoary') | 118 | hoary = ubuntu.getSeries('hoary') |
105 | 119 | test_publisher.setUpDefaultDistroSeries(hoary) | 119 | self.test_publisher.setUpDefaultDistroSeries(hoary) |
106 | 120 | test_publisher.addFakeChroots(db_only=True) | 120 | self.test_publisher.addFakeChroots(db_only=True) |
107 | 121 | 121 | ||
108 | 122 | def _resetBuilder(self, builder): | 122 | def _resetBuilder(self, builder): |
109 | 123 | """Reset the given builder and its job.""" | 123 | """Reset the given builder and its job.""" |
110 | @@ -139,8 +139,7 @@ | |||
111 | 139 | self.assertEqual(job.builder, builder) | 139 | self.assertEqual(job.builder, builder) |
112 | 140 | self.assertTrue(job.date_started is not None) | 140 | self.assertTrue(job.date_started is not None) |
113 | 141 | self.assertEqual(job.status, BuildQueueStatus.RUNNING) | 141 | self.assertEqual(job.status, BuildQueueStatus.RUNNING) |
116 | 142 | build = getUtility(IBinaryPackageBuildSet).getByQueueEntry(job) | 142 | self.assertEqual(job.specific_build.status, BuildStatus.BUILDING) |
115 | 143 | self.assertEqual(build.status, BuildStatus.BUILDING) | ||
117 | 144 | self.assertEqual(job.logtail, logtail) | 143 | self.assertEqual(job.logtail, logtail) |
118 | 145 | 144 | ||
119 | 146 | def _getScanner(self, builder_name=None, clock=None, builder_factory=None): | 145 | def _getScanner(self, builder_name=None, clock=None, builder_factory=None): |
120 | @@ -397,6 +396,38 @@ | |||
121 | 397 | self.assertEqual(2, fake_scan.call_count) | 396 | self.assertEqual(2, fake_scan.call_count) |
122 | 398 | 397 | ||
123 | 399 | @defer.inlineCallbacks | 398 | @defer.inlineCallbacks |
124 | 399 | def test_scan_of_snap_build(self): | ||
125 | 400 | # Snap builds return additional status information, which the scan | ||
126 | 401 | # collects. | ||
127 | 402 | class SnapBuildingSlave(BuildingSlave): | ||
128 | 403 | revision_id = None | ||
129 | 404 | |||
130 | 405 | @defer.inlineCallbacks | ||
131 | 406 | def status(self): | ||
132 | 407 | status = yield super(SnapBuildingSlave, self).status() | ||
133 | 408 | status["revision_id"] = self.revision_id | ||
134 | 409 | defer.returnValue(status) | ||
135 | 410 | |||
136 | 411 | build = self.factory.makeSnapBuild( | ||
137 | 412 | distroarchseries=self.test_publisher.distroseries.architectures[0]) | ||
138 | 413 | job = build.queueBuild() | ||
139 | 414 | builder = self.factory.makeBuilder( | ||
140 | 415 | processors=[job.processor], vm_host="fake_vm_host") | ||
141 | 416 | job.markAsBuilding(builder) | ||
142 | 417 | slave = SnapBuildingSlave(build_id="SNAPBUILD-%d" % build.id) | ||
143 | 418 | self.patch(BuilderSlave, "makeBuilderSlave", FakeMethod(slave)) | ||
144 | 419 | transaction.commit() | ||
145 | 420 | scanner = self._getScanner(builder_name=builder.name) | ||
146 | 421 | yield scanner.scan() | ||
147 | 422 | self.assertBuildingJob(job, builder, logtail="This is a build log: 0") | ||
148 | 423 | self.assertIsNone(build.revision_id) | ||
149 | 424 | slave.revision_id = "dummy" | ||
150 | 425 | scanner = self._getScanner(builder_name=builder.name) | ||
151 | 426 | yield scanner.scan() | ||
152 | 427 | self.assertBuildingJob(job, builder, logtail="This is a build log: 1") | ||
153 | 428 | self.assertEqual("dummy", build.revision_id) | ||
154 | 429 | |||
155 | 430 | @defer.inlineCallbacks | ||
156 | 400 | def _assertFailureCounting(self, builder_count, job_count, | 431 | def _assertFailureCounting(self, builder_count, job_count, |
157 | 401 | expected_builder_count, expected_job_count): | 432 | expected_builder_count, expected_job_count): |
158 | 402 | # If scan() fails with an exception, failure_counts should be | 433 | # If scan() fails with an exception, failure_counts should be |
159 | 403 | 434 | ||
160 | === modified file 'lib/lp/snappy/browser/tests/test_snapbuild.py' | |||
161 | --- lib/lp/snappy/browser/tests/test_snapbuild.py 2017-01-27 12:44:41 +0000 | |||
162 | +++ lib/lp/snappy/browser/tests/test_snapbuild.py 2017-04-27 15:55:40 +0000 | |||
163 | @@ -77,6 +77,16 @@ | |||
164 | 77 | build_view = create_initialized_view(build, "+index") | 77 | build_view = create_initialized_view(build, "+index") |
165 | 78 | self.assertEqual([], build_view.files) | 78 | self.assertEqual([], build_view.files) |
166 | 79 | 79 | ||
167 | 80 | def test_revision_id(self): | ||
168 | 81 | build = self.factory.makeSnapBuild() | ||
169 | 82 | build.updateStatus( | ||
170 | 83 | BuildStatus.FULLYBUILT, slave_status={"revision_id": "dummy"}) | ||
171 | 84 | build_view = create_initialized_view(build, "+index") | ||
172 | 85 | self.assertThat(build_view(), soupmatchers.HTMLContains( | ||
173 | 86 | soupmatchers.Tag( | ||
174 | 87 | "revision ID", "li", attrs={"id": "revision-id"}, | ||
175 | 88 | text=re.compile(r"^\s*Revision: dummy\s*$")))) | ||
176 | 89 | |||
177 | 80 | def test_store_upload_status_in_progress(self): | 90 | def test_store_upload_status_in_progress(self): |
178 | 81 | build = self.factory.makeSnapBuild(status=BuildStatus.FULLYBUILT) | 91 | build = self.factory.makeSnapBuild(status=BuildStatus.FULLYBUILT) |
179 | 82 | getUtility(ISnapStoreUploadJobSource).create(build) | 92 | getUtility(ISnapStoreUploadJobSource).create(build) |
180 | 83 | 93 | ||
181 | === modified file 'lib/lp/snappy/interfaces/snapbuild.py' | |||
182 | --- lib/lp/snappy/interfaces/snapbuild.py 2017-04-03 14:43:22 +0000 | |||
183 | +++ lib/lp/snappy/interfaces/snapbuild.py 2017-04-27 15:55:40 +0000 | |||
184 | @@ -175,6 +175,12 @@ | |||
185 | 175 | title=_("The date when the build completed or is estimated to " | 175 | title=_("The date when the build completed or is estimated to " |
186 | 176 | "complete."), readonly=True) | 176 | "complete."), readonly=True) |
187 | 177 | 177 | ||
188 | 178 | revision_id = exported(TextLine( | ||
189 | 179 | title=_("Revision ID"), required=False, readonly=True, | ||
190 | 180 | description=_( | ||
191 | 181 | "The revision ID of the branch used for this build, if " | ||
192 | 182 | "available."))) | ||
193 | 183 | |||
194 | 178 | store_upload_jobs = CollectionField( | 184 | store_upload_jobs = CollectionField( |
195 | 179 | title=_("Store upload jobs for this build."), | 185 | title=_("Store upload jobs for this build."), |
196 | 180 | # Really ISnapStoreUploadJob. | 186 | # Really ISnapStoreUploadJob. |
197 | 181 | 187 | ||
198 | === modified file 'lib/lp/snappy/model/snapbuild.py' | |||
199 | --- lib/lp/snappy/model/snapbuild.py 2017-04-03 14:43:22 +0000 | |||
200 | +++ lib/lp/snappy/model/snapbuild.py 2017-04-27 15:55:40 +0000 | |||
201 | @@ -158,6 +158,8 @@ | |||
202 | 158 | 158 | ||
203 | 159 | status = DBEnum(name='status', enum=BuildStatus, allow_none=False) | 159 | status = DBEnum(name='status', enum=BuildStatus, allow_none=False) |
204 | 160 | 160 | ||
205 | 161 | revision_id = Unicode(name='revision_id') | ||
206 | 162 | |||
207 | 161 | log_id = Int(name='log') | 163 | log_id = Int(name='log') |
208 | 162 | log = Reference(log_id, 'LibraryFileAlias.id') | 164 | log = Reference(log_id, 'LibraryFileAlias.id') |
209 | 163 | 165 | ||
210 | @@ -337,6 +339,10 @@ | |||
211 | 337 | status, builder=builder, slave_status=slave_status, | 339 | status, builder=builder, slave_status=slave_status, |
212 | 338 | date_started=date_started, date_finished=date_finished, | 340 | date_started=date_started, date_finished=date_finished, |
213 | 339 | force_invalid_transition=force_invalid_transition) | 341 | force_invalid_transition=force_invalid_transition) |
214 | 342 | if slave_status is not None: | ||
215 | 343 | revision_id = slave_status.get("revision_id") | ||
216 | 344 | if revision_id is not None: | ||
217 | 345 | self.revision_id = unicode(revision_id) | ||
218 | 340 | notify(SnapBuildStatusChangedEvent(self)) | 346 | notify(SnapBuildStatusChangedEvent(self)) |
219 | 341 | 347 | ||
220 | 342 | def notify(self, extra_info=None): | 348 | def notify(self, extra_info=None): |
221 | 343 | 349 | ||
222 | === modified file 'lib/lp/snappy/templates/snapbuild-index.pt' | |||
223 | --- lib/lp/snappy/templates/snapbuild-index.pt 2017-02-27 18:46:38 +0000 | |||
224 | +++ lib/lp/snappy/templates/snapbuild-index.pt 2017-04-27 15:55:40 +0000 | |||
225 | @@ -112,6 +112,9 @@ | |||
226 | 112 | </p> | 112 | </p> |
227 | 113 | 113 | ||
228 | 114 | <ul> | 114 | <ul> |
229 | 115 | <li id="revision-id" tal:condition="context/revision_id"> | ||
230 | 116 | Revision: <span tal:replace="context/revision_id" /> | ||
231 | 117 | </li> | ||
232 | 115 | <li tal:condition="context/dependencies"> | 118 | <li tal:condition="context/dependencies"> |
233 | 116 | Missing build dependencies: <em tal:content="context/dependencies"/> | 119 | Missing build dependencies: <em tal:content="context/dependencies"/> |
234 | 117 | </li> | 120 | </li> |
235 | 118 | 121 | ||
236 | === modified file 'lib/lp/snappy/tests/test_snapbuild.py' | |||
237 | --- lib/lp/snappy/tests/test_snapbuild.py 2017-03-20 00:03:52 +0000 | |||
238 | +++ lib/lp/snappy/tests/test_snapbuild.py 2017-04-27 15:55:40 +0000 | |||
239 | @@ -218,6 +218,15 @@ | |||
240 | 218 | self.factory.makeSnapFile(snapbuild=self.build) | 218 | self.factory.makeSnapFile(snapbuild=self.build) |
241 | 219 | self.assertTrue(self.build.verifySuccessfulUpload()) | 219 | self.assertTrue(self.build.verifySuccessfulUpload()) |
242 | 220 | 220 | ||
243 | 221 | def test_updateStatus_stores_revision_id(self): | ||
244 | 222 | # If the builder reports a revision_id, updateStatus saves it. | ||
245 | 223 | self.assertIsNone(self.build.revision_id) | ||
246 | 224 | self.build.updateStatus(BuildStatus.BUILDING, slave_status={}) | ||
247 | 225 | self.assertIsNone(self.build.revision_id) | ||
248 | 226 | self.build.updateStatus( | ||
249 | 227 | BuildStatus.BUILDING, slave_status={"revision_id": "dummy"}) | ||
250 | 228 | self.assertEqual("dummy", self.build.revision_id) | ||
251 | 229 | |||
252 | 221 | def test_updateStatus_triggers_webhooks(self): | 230 | def test_updateStatus_triggers_webhooks(self): |
253 | 222 | # Updating the status of a SnapBuild triggers webhooks on the | 231 | # Updating the status of a SnapBuild triggers webhooks on the |
254 | 223 | # corresponding Snap. | 232 | # corresponding Snap. |