Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/phabricator
Path: blob/master/src/applications/harbormaster/storage/HarbormasterBuildable.php
12256 views
1
<?php
2
3
final class HarbormasterBuildable
4
extends HarbormasterDAO
5
implements
6
PhabricatorApplicationTransactionInterface,
7
PhabricatorPolicyInterface,
8
HarbormasterBuildableInterface,
9
PhabricatorConduitResultInterface,
10
PhabricatorDestructibleInterface {
11
12
protected $buildablePHID;
13
protected $containerPHID;
14
protected $buildableStatus;
15
protected $isManualBuildable;
16
17
private $buildableObject = self::ATTACHABLE;
18
private $containerObject = self::ATTACHABLE;
19
private $builds = self::ATTACHABLE;
20
21
public static function initializeNewBuildable(PhabricatorUser $actor) {
22
return id(new HarbormasterBuildable())
23
->setIsManualBuildable(0)
24
->setBuildableStatus(HarbormasterBuildableStatus::STATUS_PREPARING);
25
}
26
27
public function getMonogram() {
28
return 'B'.$this->getID();
29
}
30
31
public function getURI() {
32
return '/'.$this->getMonogram();
33
}
34
35
/**
36
* Returns an existing buildable for the object's PHID or creates a
37
* new buildable implicitly if needed.
38
*/
39
public static function createOrLoadExisting(
40
PhabricatorUser $actor,
41
$buildable_object_phid,
42
$container_object_phid) {
43
44
$buildable = id(new HarbormasterBuildableQuery())
45
->setViewer($actor)
46
->withBuildablePHIDs(array($buildable_object_phid))
47
->withManualBuildables(false)
48
->setLimit(1)
49
->executeOne();
50
if ($buildable) {
51
return $buildable;
52
}
53
$buildable = self::initializeNewBuildable($actor)
54
->setBuildablePHID($buildable_object_phid)
55
->setContainerPHID($container_object_phid);
56
$buildable->save();
57
return $buildable;
58
}
59
60
/**
61
* Start builds for a given buildable.
62
*
63
* @param phid PHID of the object to build.
64
* @param phid Container PHID for the buildable.
65
* @param list<HarbormasterBuildRequest> List of builds to perform.
66
* @return void
67
*/
68
public static function applyBuildPlans(
69
$phid,
70
$container_phid,
71
array $requests) {
72
73
assert_instances_of($requests, 'HarbormasterBuildRequest');
74
75
if (!$requests) {
76
return;
77
}
78
79
// Skip all of this logic if the Harbormaster application
80
// isn't currently installed.
81
82
$harbormaster_app = 'PhabricatorHarbormasterApplication';
83
if (!PhabricatorApplication::isClassInstalled($harbormaster_app)) {
84
return;
85
}
86
87
$viewer = PhabricatorUser::getOmnipotentUser();
88
89
$buildable = self::createOrLoadExisting(
90
$viewer,
91
$phid,
92
$container_phid);
93
94
$plan_phids = mpull($requests, 'getBuildPlanPHID');
95
$plans = id(new HarbormasterBuildPlanQuery())
96
->setViewer($viewer)
97
->withPHIDs($plan_phids)
98
->execute();
99
$plans = mpull($plans, null, 'getPHID');
100
101
foreach ($requests as $request) {
102
$plan_phid = $request->getBuildPlanPHID();
103
$plan = idx($plans, $plan_phid);
104
105
if (!$plan) {
106
throw new Exception(
107
pht(
108
'Failed to load build plan ("%s").',
109
$plan_phid));
110
}
111
112
if ($plan->isDisabled()) {
113
// TODO: This should be communicated more clearly -- maybe we should
114
// create the build but set the status to "disabled" or "derelict".
115
continue;
116
}
117
118
$parameters = $request->getBuildParameters();
119
$buildable->applyPlan($plan, $parameters, $request->getInitiatorPHID());
120
}
121
}
122
123
public function applyPlan(
124
HarbormasterBuildPlan $plan,
125
array $parameters,
126
$initiator_phid) {
127
128
$viewer = PhabricatorUser::getOmnipotentUser();
129
$build = HarbormasterBuild::initializeNewBuild($viewer)
130
->setBuildablePHID($this->getPHID())
131
->setBuildPlanPHID($plan->getPHID())
132
->setBuildParameters($parameters)
133
->setBuildStatus(HarbormasterBuildStatus::STATUS_PENDING);
134
if ($initiator_phid) {
135
$build->setInitiatorPHID($initiator_phid);
136
}
137
138
$auto_key = $plan->getPlanAutoKey();
139
if ($auto_key) {
140
$build->setPlanAutoKey($auto_key);
141
}
142
143
$build->save();
144
145
$steps = id(new HarbormasterBuildStepQuery())
146
->setViewer($viewer)
147
->withBuildPlanPHIDs(array($plan->getPHID()))
148
->execute();
149
150
foreach ($steps as $step) {
151
$step->willStartBuild($viewer, $this, $build, $plan);
152
}
153
154
PhabricatorWorker::scheduleTask(
155
'HarbormasterBuildWorker',
156
array(
157
'buildID' => $build->getID(),
158
),
159
array(
160
'objectPHID' => $build->getPHID(),
161
));
162
163
return $build;
164
}
165
166
protected function getConfiguration() {
167
return array(
168
self::CONFIG_AUX_PHID => true,
169
self::CONFIG_COLUMN_SCHEMA => array(
170
'containerPHID' => 'phid?',
171
'buildableStatus' => 'text32',
172
'isManualBuildable' => 'bool',
173
),
174
self::CONFIG_KEY_SCHEMA => array(
175
'key_buildable' => array(
176
'columns' => array('buildablePHID'),
177
),
178
'key_container' => array(
179
'columns' => array('containerPHID'),
180
),
181
'key_manual' => array(
182
'columns' => array('isManualBuildable'),
183
),
184
),
185
) + parent::getConfiguration();
186
}
187
188
public function generatePHID() {
189
return PhabricatorPHID::generateNewPHID(
190
HarbormasterBuildablePHIDType::TYPECONST);
191
}
192
193
public function attachBuildableObject($buildable_object) {
194
$this->buildableObject = $buildable_object;
195
return $this;
196
}
197
198
public function getBuildableObject() {
199
return $this->assertAttached($this->buildableObject);
200
}
201
202
public function attachContainerObject($container_object) {
203
$this->containerObject = $container_object;
204
return $this;
205
}
206
207
public function getContainerObject() {
208
return $this->assertAttached($this->containerObject);
209
}
210
211
public function attachBuilds(array $builds) {
212
assert_instances_of($builds, 'HarbormasterBuild');
213
$this->builds = $builds;
214
return $this;
215
}
216
217
public function getBuilds() {
218
return $this->assertAttached($this->builds);
219
}
220
221
222
/* -( Status )------------------------------------------------------------- */
223
224
225
public function getBuildableStatusObject() {
226
$status = $this->getBuildableStatus();
227
return HarbormasterBuildableStatus::newBuildableStatusObject($status);
228
}
229
230
public function getStatusIcon() {
231
return $this->getBuildableStatusObject()->getIcon();
232
}
233
234
public function getStatusDisplayName() {
235
return $this->getBuildableStatusObject()->getDisplayName();
236
}
237
238
public function getStatusColor() {
239
return $this->getBuildableStatusObject()->getColor();
240
}
241
242
public function isPreparing() {
243
return $this->getBuildableStatusObject()->isPreparing();
244
}
245
246
public function isBuilding() {
247
return $this->getBuildableStatusObject()->isBuilding();
248
}
249
250
251
/* -( Messages )----------------------------------------------------------- */
252
253
254
public function sendMessage(
255
PhabricatorUser $viewer,
256
$message_type,
257
$queue_update) {
258
259
$message = HarbormasterBuildMessage::initializeNewMessage($viewer)
260
->setReceiverPHID($this->getPHID())
261
->setType($message_type)
262
->save();
263
264
if ($queue_update) {
265
PhabricatorWorker::scheduleTask(
266
'HarbormasterBuildWorker',
267
array(
268
'buildablePHID' => $this->getPHID(),
269
),
270
array(
271
'objectPHID' => $this->getPHID(),
272
));
273
}
274
275
return $message;
276
}
277
278
279
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
280
281
282
public function getApplicationTransactionEditor() {
283
return new HarbormasterBuildableTransactionEditor();
284
}
285
286
public function getApplicationTransactionTemplate() {
287
return new HarbormasterBuildableTransaction();
288
}
289
290
291
/* -( PhabricatorPolicyInterface )----------------------------------------- */
292
293
294
public function getCapabilities() {
295
return array(
296
PhabricatorPolicyCapability::CAN_VIEW,
297
PhabricatorPolicyCapability::CAN_EDIT,
298
);
299
}
300
301
public function getPolicy($capability) {
302
return $this->getBuildableObject()->getPolicy($capability);
303
}
304
305
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
306
return $this->getBuildableObject()->hasAutomaticCapability(
307
$capability,
308
$viewer);
309
}
310
311
public function describeAutomaticCapability($capability) {
312
return pht('A buildable inherits policies from the underlying object.');
313
}
314
315
316
317
/* -( HarbormasterBuildableInterface )------------------------------------- */
318
319
320
public function getHarbormasterBuildableDisplayPHID() {
321
return $this->getBuildableObject()->getHarbormasterBuildableDisplayPHID();
322
}
323
324
public function getHarbormasterBuildablePHID() {
325
// NOTE: This is essentially just for convenience, as it allows you create
326
// a copy of a buildable by specifying `B123` without bothering to go
327
// look up the underlying object.
328
return $this->getBuildablePHID();
329
}
330
331
public function getHarbormasterContainerPHID() {
332
return $this->getContainerPHID();
333
}
334
335
public function getBuildVariables() {
336
return array();
337
}
338
339
public function getAvailableBuildVariables() {
340
return array();
341
}
342
343
public function newBuildableEngine() {
344
return $this->getBuildableObject()->newBuildableEngine();
345
}
346
347
348
/* -( PhabricatorConduitResultInterface )---------------------------------- */
349
350
351
public function getFieldSpecificationsForConduit() {
352
return array(
353
id(new PhabricatorConduitSearchFieldSpecification())
354
->setKey('objectPHID')
355
->setType('phid')
356
->setDescription(pht('PHID of the object that is built.')),
357
id(new PhabricatorConduitSearchFieldSpecification())
358
->setKey('containerPHID')
359
->setType('phid')
360
->setDescription(pht('PHID of the object containing this buildable.')),
361
id(new PhabricatorConduitSearchFieldSpecification())
362
->setKey('buildableStatus')
363
->setType('map<string, wild>')
364
->setDescription(pht('The current status of this buildable.')),
365
id(new PhabricatorConduitSearchFieldSpecification())
366
->setKey('isManual')
367
->setType('bool')
368
->setDescription(pht('True if this is a manual buildable.')),
369
id(new PhabricatorConduitSearchFieldSpecification())
370
->setKey('uri')
371
->setType('uri')
372
->setDescription(pht('View URI for the buildable.')),
373
);
374
}
375
376
public function getFieldValuesForConduit() {
377
return array(
378
'objectPHID' => $this->getBuildablePHID(),
379
'containerPHID' => $this->getContainerPHID(),
380
'buildableStatus' => array(
381
'value' => $this->getBuildableStatus(),
382
),
383
'isManual' => (bool)$this->getIsManualBuildable(),
384
'uri' => PhabricatorEnv::getURI($this->getURI()),
385
);
386
}
387
388
public function getConduitSearchAttachments() {
389
return array();
390
}
391
392
393
/* -( PhabricatorDestructibleInterface )----------------------------------- */
394
395
396
public function destroyObjectPermanently(
397
PhabricatorDestructionEngine $engine) {
398
$viewer = $engine->getViewer();
399
400
$this->openTransaction();
401
$builds = id(new HarbormasterBuildQuery())
402
->setViewer($viewer)
403
->withBuildablePHIDs(array($this->getPHID()))
404
->execute();
405
foreach ($builds as $build) {
406
$engine->destroyObject($build);
407
}
408
409
$messages = id(new HarbormasterBuildMessageQuery())
410
->setViewer($viewer)
411
->withReceiverPHIDs(array($this->getPHID()))
412
->execute();
413
foreach ($messages as $message) {
414
$engine->destroyObject($message);
415
}
416
417
$this->delete();
418
$this->saveTransaction();
419
}
420
421
}
422
423