mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-30 17:30:59 +01:00
Add build step implementation infrastructure and sleep build step.
Summary: Depends on D7498. This implements support for a "build step implementation". Build steps have an associated class name (which makes the class in PHP) and a details field, which is serialized JSON (same as PhabricatorRepository). This also implements a SleepBuildStepImplementation which just pauses the build for a specified period of seconds. Test Plan: Inserted a build step with `insert into harbormaster_buildstep (phid, buildPlanPHID, className, details, dateCreated, dateModified) values ('', 'PHID-HMCP-zkh5w6czfbfpk2gxwdeo', 'SleepBuildStepImplementation', '{"seconds":5}', NOW(), NOW());` (adjusting the build plan PHID as appropriate). Started the daemon and applied the build plan to a buildable, and saw the daemon take a 5 second delay after creating `SleepBuildStepImplementation`. Reviewers: epriestley, #blessed_reviewers Reviewed By: epriestley CC: Korvin, epriestley, aran, chad Maniphest Tasks: T1049 Differential Revision: https://secure.phabricator.com/D7499
This commit is contained in:
parent
5c0edc9351
commit
c514d34b94
8 changed files with 201 additions and 6 deletions
11
resources/sql/patches/20131105.buildstep.sql
Normal file
11
resources/sql/patches/20131105.buildstep.sql
Normal file
|
@ -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;
|
|
@ -91,6 +91,7 @@ phutil_register_library_map(array(
|
||||||
'AphrontView' => 'view/AphrontView.php',
|
'AphrontView' => 'view/AphrontView.php',
|
||||||
'AphrontWebpageResponse' => 'aphront/response/AphrontWebpageResponse.php',
|
'AphrontWebpageResponse' => 'aphront/response/AphrontWebpageResponse.php',
|
||||||
'AuditActionMenuEventListener' => 'applications/audit/events/AuditActionMenuEventListener.php',
|
'AuditActionMenuEventListener' => 'applications/audit/events/AuditActionMenuEventListener.php',
|
||||||
|
'BuildStepImplementation' => 'applications/harbormaster/step/BuildStepImplementation.php',
|
||||||
'CelerityAPI' => 'infrastructure/celerity/CelerityAPI.php',
|
'CelerityAPI' => 'infrastructure/celerity/CelerityAPI.php',
|
||||||
'CelerityPhabricatorResourceController' => 'infrastructure/celerity/CelerityPhabricatorResourceController.php',
|
'CelerityPhabricatorResourceController' => 'infrastructure/celerity/CelerityPhabricatorResourceController.php',
|
||||||
'CelerityResourceController' => 'infrastructure/celerity/CelerityResourceController.php',
|
'CelerityResourceController' => 'infrastructure/celerity/CelerityResourceController.php',
|
||||||
|
@ -2195,6 +2196,7 @@ phutil_register_library_map(array(
|
||||||
'ReleephStatusFieldSpecification' => 'applications/releeph/field/specification/ReleephStatusFieldSpecification.php',
|
'ReleephStatusFieldSpecification' => 'applications/releeph/field/specification/ReleephStatusFieldSpecification.php',
|
||||||
'ReleephSummaryFieldSpecification' => 'applications/releeph/field/specification/ReleephSummaryFieldSpecification.php',
|
'ReleephSummaryFieldSpecification' => 'applications/releeph/field/specification/ReleephSummaryFieldSpecification.php',
|
||||||
'ReleephUserView' => 'applications/releeph/view/user/ReleephUserView.php',
|
'ReleephUserView' => 'applications/releeph/view/user/ReleephUserView.php',
|
||||||
|
'SleepBuildStepImplementation' => 'applications/harbormaster/step/SleepBuildStepImplementation.php',
|
||||||
'SlowvoteEmbedView' => 'applications/slowvote/view/SlowvoteEmbedView.php',
|
'SlowvoteEmbedView' => 'applications/slowvote/view/SlowvoteEmbedView.php',
|
||||||
'SlowvoteRemarkupRule' => 'applications/slowvote/remarkup/SlowvoteRemarkupRule.php',
|
'SlowvoteRemarkupRule' => 'applications/slowvote/remarkup/SlowvoteRemarkupRule.php',
|
||||||
),
|
),
|
||||||
|
@ -2872,7 +2874,11 @@ phutil_register_library_map(array(
|
||||||
'HarbormasterBuildPlanTransactionComment' => 'PhabricatorApplicationTransactionComment',
|
'HarbormasterBuildPlanTransactionComment' => 'PhabricatorApplicationTransactionComment',
|
||||||
'HarbormasterBuildPlanTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
'HarbormasterBuildPlanTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||||
'HarbormasterBuildQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'HarbormasterBuildQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'HarbormasterBuildStep' => 'HarbormasterDAO',
|
'HarbormasterBuildStep' =>
|
||||||
|
array(
|
||||||
|
0 => 'HarbormasterDAO',
|
||||||
|
1 => 'PhabricatorPolicyInterface',
|
||||||
|
),
|
||||||
'HarbormasterBuildStepQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'HarbormasterBuildStepQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
'HarbormasterBuildTarget' => 'HarbormasterDAO',
|
'HarbormasterBuildTarget' => 'HarbormasterDAO',
|
||||||
'HarbormasterBuildTargetQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
'HarbormasterBuildTargetQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||||
|
@ -4651,6 +4657,7 @@ phutil_register_library_map(array(
|
||||||
'ReleephStatusFieldSpecification' => 'ReleephFieldSpecification',
|
'ReleephStatusFieldSpecification' => 'ReleephFieldSpecification',
|
||||||
'ReleephSummaryFieldSpecification' => 'ReleephFieldSpecification',
|
'ReleephSummaryFieldSpecification' => 'ReleephFieldSpecification',
|
||||||
'ReleephUserView' => 'AphrontView',
|
'ReleephUserView' => 'AphrontView',
|
||||||
|
'SleepBuildStepImplementation' => 'BuildStepImplementation',
|
||||||
'SlowvoteEmbedView' => 'AphrontView',
|
'SlowvoteEmbedView' => 'AphrontView',
|
||||||
'SlowvoteRemarkupRule' => 'PhabricatorRemarkupRuleObject',
|
'SlowvoteRemarkupRule' => 'PhabricatorRemarkupRuleObject',
|
||||||
),
|
),
|
||||||
|
|
|
@ -5,6 +5,7 @@ final class HarbormasterBuildStepQuery
|
||||||
|
|
||||||
private $ids;
|
private $ids;
|
||||||
private $phids;
|
private $phids;
|
||||||
|
private $buildPlanPHIDs;
|
||||||
|
|
||||||
public function withIDs(array $ids) {
|
public function withIDs(array $ids) {
|
||||||
$this->ids = $ids;
|
$this->ids = $ids;
|
||||||
|
@ -16,6 +17,11 @@ final class HarbormasterBuildStepQuery
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function withBuildPlanPHIDs(array $phids) {
|
||||||
|
$this->buildPlanPHIDs = $phids;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
protected function loadPage() {
|
protected function loadPage() {
|
||||||
$table = new HarbormasterBuildStep();
|
$table = new HarbormasterBuildStep();
|
||||||
$conn_r = $table->establishConnection('r');
|
$conn_r = $table->establishConnection('r');
|
||||||
|
@ -48,11 +54,43 @@ final class HarbormasterBuildStepQuery
|
||||||
$this->phids);
|
$this->phids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->buildPlanPHIDs) {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn_r,
|
||||||
|
'buildPlanPHID in (%Ls)',
|
||||||
|
$this->buildPlanPHIDs);
|
||||||
|
}
|
||||||
|
|
||||||
$where[] = $this->buildPagingClause($conn_r);
|
$where[] = $this->buildPagingClause($conn_r);
|
||||||
|
|
||||||
return $this->formatWhereClause($where);
|
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() {
|
public function getQueryApplicationClass() {
|
||||||
return 'PhabricatorApplicationHarbormaster';
|
return 'PhabricatorApplicationHarbormaster';
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class BuildStepImplementation {
|
||||||
|
|
||||||
|
private $settings;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the implementation.
|
||||||
|
*/
|
||||||
|
abstract public function getName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The description of the implementation.
|
||||||
|
*/
|
||||||
|
public function getDescription() {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run the build step against the specified build.
|
||||||
|
*/
|
||||||
|
abstract public function execute(HarbormasterBuild $build);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the settings for this build step.
|
||||||
|
*/
|
||||||
|
protected function getSettings() {
|
||||||
|
return $this->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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class SleepBuildStepImplementation extends BuildStepImplementation {
|
||||||
|
|
||||||
|
public function getName() {
|
||||||
|
return pht('Sleep');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDescription() {
|
||||||
|
return pht('Sleep for a specified number of seconds.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function execute(HarbormasterBuild $build) {
|
||||||
|
$settings = $this->getSettings();
|
||||||
|
|
||||||
|
sleep($settings['seconds']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSettingDefinitions() {
|
||||||
|
return array(
|
||||||
|
'seconds' => array());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,14 +1,20 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
final class HarbormasterBuildStep extends HarbormasterDAO {
|
final class HarbormasterBuildStep extends HarbormasterDAO
|
||||||
|
implements PhabricatorPolicyInterface {
|
||||||
|
|
||||||
protected $buildPlanPHID;
|
protected $buildPlanPHID;
|
||||||
|
protected $className;
|
||||||
|
protected $details = array();
|
||||||
|
|
||||||
private $buildPlan = self::ATTACHABLE;
|
private $buildPlan = self::ATTACHABLE;
|
||||||
|
|
||||||
public function getConfiguration() {
|
public function getConfiguration() {
|
||||||
return array(
|
return array(
|
||||||
self::CONFIG_AUX_PHID => true,
|
self::CONFIG_AUX_PHID => true,
|
||||||
|
self::CONFIG_SERIALIZATION => array(
|
||||||
|
'details' => self::SERIALIZATION_JSON,
|
||||||
|
)
|
||||||
) + parent::getConfiguration();
|
) + parent::getConfiguration();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,4 +32,47 @@ final class HarbormasterBuildStep extends HarbormasterDAO {
|
||||||
return $this->assertAttached($this->buildPlan);
|
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.');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,11 +32,25 @@ final class HarbormasterBuildWorker extends PhabricatorWorker {
|
||||||
$buildable = $build->getBuildable();
|
$buildable = $build->getBuildable();
|
||||||
$plan = $build->getBuildPlan();
|
$plan = $build->getBuildPlan();
|
||||||
|
|
||||||
// TODO: Do the actual build here.
|
$steps = id(new HarbormasterBuildStepQuery())
|
||||||
sleep(15);
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||||
|
->withBuildPlanPHIDs(array($plan->getPHID()))
|
||||||
|
->execute();
|
||||||
|
|
||||||
// If we get to here, then the build has 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->setBuildStatus(HarbormasterBuild::STATUS_PASSED);
|
||||||
|
}
|
||||||
$build->save();
|
$build->save();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
// If any exception is raised, the build is marked as a failure and
|
// If any exception is raised, the build is marked as a failure and
|
||||||
|
|
|
@ -1720,6 +1720,10 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
|
||||||
'type' => 'sql',
|
'type' => 'sql',
|
||||||
'name' => $this->getPatchPath('20131031.vcspassword.sql'),
|
'name' => $this->getPatchPath('20131031.vcspassword.sql'),
|
||||||
),
|
),
|
||||||
|
'20131105.buildstep.sql' => array(
|
||||||
|
'type' => 'sql',
|
||||||
|
'name' => $this->getPatchPath('20131105.buildstep.sql'),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue