Index: resources/sql/patches/20131105.buildstep.sql =================================================================== --- /dev/null +++ resources/sql/patches/20131105.buildstep.sql @@ -0,0 +1,11 @@ +CREATE TABLE {$NAMESPACE}_harbormaster.harbormaster_buildstep ( + id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, + phid VARCHAR(64) NOT NULL COLLATE utf8_bin, + buildPlanPHID VARCHAR(64) NOT NULL COLLATE utf8_bin, + className VARCHAR(255) NOT NULL COLLATE utf8_bin, + details LONGTEXT CHARACTER SET utf8 COLLATE utf8_bin NOT NULL, + dateCreated INT UNSIGNED NOT NULL, + dateModified INT UNSIGNED NOT NULL, + KEY `key_plan` (buildPlanPHID), + UNIQUE KEY `key_phid` (phid) +) ENGINE=InnoDB, COLLATE utf8_general_ci; Index: src/__phutil_library_map__.php =================================================================== --- src/__phutil_library_map__.php +++ src/__phutil_library_map__.php @@ -91,6 +91,7 @@ 'AphrontView' => 'view/AphrontView.php', 'AphrontWebpageResponse' => 'aphront/response/AphrontWebpageResponse.php', 'AuditActionMenuEventListener' => 'applications/audit/events/AuditActionMenuEventListener.php', + 'BuildStepImplementation' => 'applications/harbormaster/step/BuildStepImplementation.php', 'CelerityAPI' => 'infrastructure/celerity/CelerityAPI.php', 'CelerityPhabricatorResourceController' => 'infrastructure/celerity/CelerityPhabricatorResourceController.php', 'CelerityResourceController' => 'infrastructure/celerity/CelerityResourceController.php', @@ -2195,6 +2196,7 @@ 'ReleephStatusFieldSpecification' => 'applications/releeph/field/specification/ReleephStatusFieldSpecification.php', 'ReleephSummaryFieldSpecification' => 'applications/releeph/field/specification/ReleephSummaryFieldSpecification.php', 'ReleephUserView' => 'applications/releeph/view/user/ReleephUserView.php', + 'SleepBuildStepImplementation' => 'applications/harbormaster/step/SleepBuildStepImplementation.php', 'SlowvoteEmbedView' => 'applications/slowvote/view/SlowvoteEmbedView.php', 'SlowvoteRemarkupRule' => 'applications/slowvote/remarkup/SlowvoteRemarkupRule.php', ), @@ -2872,7 +2874,11 @@ 'HarbormasterBuildPlanTransactionComment' => 'PhabricatorApplicationTransactionComment', 'HarbormasterBuildPlanTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'HarbormasterBuildQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', - 'HarbormasterBuildStep' => 'HarbormasterDAO', + 'HarbormasterBuildStep' => + array( + 0 => 'HarbormasterDAO', + 1 => 'PhabricatorPolicyInterface', + ), 'HarbormasterBuildStepQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildTarget' => 'HarbormasterDAO', 'HarbormasterBuildTargetQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', @@ -4651,6 +4657,7 @@ 'ReleephStatusFieldSpecification' => 'ReleephFieldSpecification', 'ReleephSummaryFieldSpecification' => 'ReleephFieldSpecification', 'ReleephUserView' => 'AphrontView', + 'SleepBuildStepImplementation' => 'BuildStepImplementation', 'SlowvoteEmbedView' => 'AphrontView', 'SlowvoteRemarkupRule' => 'PhabricatorRemarkupRuleObject', ), Index: src/applications/harbormaster/query/HarbormasterBuildStepQuery.php =================================================================== --- src/applications/harbormaster/query/HarbormasterBuildStepQuery.php +++ src/applications/harbormaster/query/HarbormasterBuildStepQuery.php @@ -5,6 +5,7 @@ private $ids; private $phids; + private $buildPlanPHIDs; public function withIDs(array $ids) { $this->ids = $ids; @@ -16,6 +17,11 @@ return $this; } + public function withBuildPlanPHIDs(array $phids) { + $this->buildPlanPHIDs = $phids; + return $this; + } + protected function loadPage() { $table = new HarbormasterBuildStep(); $conn_r = $table->establishConnection('r'); @@ -48,11 +54,43 @@ $this->phids); } + if ($this->buildPlanPHIDs) { + $where[] = qsprintf( + $conn_r, + 'buildPlanPHID in (%Ls)', + $this->buildPlanPHIDs); + } + $where[] = $this->buildPagingClause($conn_r); return $this->formatWhereClause($where); } + protected function willFilterPage(array $page) { + $plans = array(); + + $buildplan_phids = array_filter(mpull($page, 'getBuildPlanPHID')); + if ($buildplan_phids) { + $plans = id(new PhabricatorObjectQuery()) + ->setViewer($this->getViewer()) + ->withPHIDs($buildplan_phids) + ->setParentQuery($this) + ->execute(); + $plans = mpull($plans, null, 'getPHID'); + } + + foreach ($page as $key => $build) { + $buildable_phid = $build->getBuildPlanPHID(); + if (empty($plans[$buildable_phid])) { + unset($page[$key]); + continue; + } + $build->attachBuildPlan($plans[$buildable_phid]); + } + + return $page; + } + public function getQueryApplicationClass() { return 'PhabricatorApplicationHarbormaster'; } Index: src/applications/harbormaster/step/BuildStepImplementation.php =================================================================== --- /dev/null +++ src/applications/harbormaster/step/BuildStepImplementation.php @@ -0,0 +1,48 @@ +settings; + } + + /** + * Loads the settings for this build step implementation from the build step. + */ + public final function loadSettings(HarbormasterBuildStep $build_step) { + $this->settings = array(); + foreach ($this->getSettingDefinitions() as $name => $opt) { + $this->settings[$name] = $build_step->getDetail($name); + } + return $this->settings; + } + + /** + * Return an array of settings for this step implementation. + */ + public function getSettingDefinitions() { + return array(); + } +} Index: src/applications/harbormaster/step/SleepBuildStepImplementation.php =================================================================== --- /dev/null +++ src/applications/harbormaster/step/SleepBuildStepImplementation.php @@ -0,0 +1,24 @@ +getSettings(); + + sleep($settings['seconds']); + } + + public function getSettingDefinitions() { + return array( + 'seconds' => array()); + } + +} Index: src/applications/harbormaster/storage/configuration/HarbormasterBuildStep.php =================================================================== --- src/applications/harbormaster/storage/configuration/HarbormasterBuildStep.php +++ src/applications/harbormaster/storage/configuration/HarbormasterBuildStep.php @@ -1,14 +1,20 @@ true, + self::CONFIG_SERIALIZATION => array( + 'details' => self::SERIALIZATION_JSON, + ) ) + parent::getConfiguration(); } @@ -26,4 +32,47 @@ return $this->assertAttached($this->buildPlan); } + public function getDetail($key, $default = null) { + return idx($this->details, $key, $default); + } + + public function setDetail($key, $value) { + $this->details[$key] = $value; + return $this; + } + + public function getStepImplementation() { + if ($this->className === null) { + throw new Exception("No implementation set for the given step."); + } + + // TODO: We should look up the class in phutil's system to ensure + // that it actually extends BuildStepImplementation. + $class = $this->className; + $implementation = newv($class, array()); + $implementation->loadSettings($this); + return $implementation; + } + + +/* -( PhabricatorPolicyInterface )----------------------------------------- */ + + + public function getCapabilities() { + return array( + PhabricatorPolicyCapability::CAN_VIEW, + ); + } + + public function getPolicy($capability) { + return $this->getBuildPlan()->getPolicy($capability); + } + + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { + return $this->getBuildPlan()->hasAutomaticCapability($capability, $viewer); + } + + public function describeAutomaticCapability($capability) { + return pht('A build step has the same policies as its build plan.'); + } } Index: src/applications/harbormaster/worker/HarbormasterBuildWorker.php =================================================================== --- src/applications/harbormaster/worker/HarbormasterBuildWorker.php +++ src/applications/harbormaster/worker/HarbormasterBuildWorker.php @@ -32,11 +32,25 @@ $buildable = $build->getBuildable(); $plan = $build->getBuildPlan(); - // TODO: Do the actual build here. - sleep(15); + $steps = id(new HarbormasterBuildStepQuery()) + ->setViewer(PhabricatorUser::getOmnipotentUser()) + ->withBuildPlanPHIDs(array($plan->getPHID())) + ->execute(); - // If we get to here, then the build has passed. - $build->setBuildStatus(HarbormasterBuild::STATUS_PASSED); + // Perform the build. + foreach ($steps as $step) { + $implementation = $step->getStepImplementation(); + $implementation->execute($build); + if ($build->getBuildStatus() !== HarbormasterBuild::STATUS_BUILDING) { + break; + } + } + + // If we get to here, then the build has finished. Set it to passed + // if no build step explicitly set the status. + if ($build->getBuildStatus() === HarbormasterBuild::STATUS_BUILDING) { + $build->setBuildStatus(HarbormasterBuild::STATUS_PASSED); + } $build->save(); } catch (Exception $e) { // If any exception is raised, the build is marked as a failure and Index: src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php =================================================================== --- src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php +++ src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php @@ -1720,6 +1720,10 @@ 'type' => 'sql', 'name' => $this->getPatchPath('20131031.vcspassword.sql'), ), + '20131105.buildstep.sql' => array( + 'type' => 'sql', + 'name' => $this->getPatchPath('20131105.buildstep.sql'), + ), ); } }