PageRenderTime 46ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/src/applications/harbormaster/storage/HarbormasterBuildable.php

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