Index: resources/sql/autopatches/20150715.harbor.1.buildparam.sql =================================================================== --- /dev/null +++ resources/sql/autopatches/20150715.harbor.1.buildparam.sql @@ -0,0 +1,6 @@ +ALTER TABLE {$NAMESPACE}_harbormaster.harbormaster_build + ADD buildParameters LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL; + +ALTER TABLE {$NAMESPACE}_harbormaster.harbormaster_build + ADD buildParametersHash VARCHAR(32) COLLATE {$COLLATE_TEXT} + NOT NULL DEFAULT '2c08d653e1ee60d55cd0da551026ea56'; Index: src/applications/harbormaster/controller/HarbormasterBuildableViewController.php =================================================================== --- src/applications/harbormaster/controller/HarbormasterBuildableViewController.php +++ src/applications/harbormaster/controller/HarbormasterBuildableViewController.php @@ -191,6 +191,10 @@ HarbormasterBuild::getBuildStatusName($status)); $item->addAttribute(HarbormasterBuild::getBuildStatusName($status)); + $parameters = $build->getBuildParametersAsString(); + if ($parameters !== '') { + $item->addAttribute($parameters); + } if ($build->isRestarting()) { $item->addIcon('fa-repeat', pht('Restarting')); Index: src/applications/harbormaster/step/HarbormasterRunBuildPlanBuildImplementation.php =================================================================== --- src/applications/harbormaster/step/HarbormasterRunBuildPlanBuildImplementation.php +++ src/applications/harbormaster/step/HarbormasterRunBuildPlanBuildImplementation.php @@ -33,12 +33,39 @@ $name); } + public static function parseParameters($text) { + if (trim($text) === '') { + return array(); + } + + $pairs = phutil_split_lines($text); + $attributes = array(); + + foreach ($pairs as $line) { + $kv = explode('=', $line, 2); + if (count($kv) === 0) { + continue; + } else if (count($kv) === 1) { + $attributes[$kv[0]] = true; + } else { + $attributes[$kv[0]] = trim($kv[1]); + } + } + + return $attributes; + } + public function execute( HarbormasterBuild $build, HarbormasterBuildTarget $build_target) { $target_plan_id = $this->getSetting('id'); + $parameters = self::parseParameters( + $this->getSetting('parameters')); + $parameters_hash = + HarbormasterBuild::getBuildParametersHashForArray($parameters); + // Get the target build plan type. $target_plan = id(new HarbormasterBuildPlanQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) @@ -64,7 +91,8 @@ // Find the build for that build plan (if it exists). $target_build = null; foreach ($other_builds as $other_build) { - if ($other_build->getBuildPlanPHID() === $target_plan->getPHID()) { + if ($other_build->getBuildPlanPHID() === $target_plan->getPHID() && + $other_build->getBuildParametersHash() === $parameters_hash) { $target_build = $other_build; break; } @@ -73,7 +101,9 @@ if ($target_build === null) { // There is no current build with this build plan on the buildable, // so now we're going to start one. - $target_build = $build->getBuildable()->applyPlan($target_plan); + $target_build = $build->getBuildable()->applyPlan( + $target_plan, + $parameters); } else { // If the build plan has failed on a previous run, restart it. switch ($target_build->getBuildStatus()) { @@ -162,6 +192,14 @@ 'type' => 'text', 'required' => true, ), + 'parameters' => array( + 'name' => pht('Build Plan Parameters'), + 'type' => 'textarea', + 'caption' => pht( + 'A newline separated list of parameters to pass into the build. '. + 'Each attribute should be specified in a key=value format.'), + 'monospace' => true, + ), ); } Index: src/applications/harbormaster/storage/HarbormasterBuildable.php =================================================================== --- src/applications/harbormaster/storage/HarbormasterBuildable.php +++ src/applications/harbormaster/storage/HarbormasterBuildable.php @@ -136,11 +136,19 @@ } } - public function applyPlan(HarbormasterBuildPlan $plan) { + public function applyPlan( + HarbormasterBuildPlan $plan, + array $parameters = null) { + + if ($parameters === null) { + $parameters = array(); + } + $viewer = PhabricatorUser::getOmnipotentUser(); $build = HarbormasterBuild::initializeNewBuild($viewer) ->setBuildablePHID($this->getPHID()) ->setBuildPlanPHID($plan->getPHID()) + ->setBuildParameters($parameters) ->setBuildStatus(HarbormasterBuild::STATUS_PENDING); $auto_key = $plan->getPlanAutoKey(); Index: src/applications/harbormaster/storage/build/HarbormasterBuild.php =================================================================== --- src/applications/harbormaster/storage/build/HarbormasterBuild.php +++ src/applications/harbormaster/storage/build/HarbormasterBuild.php @@ -9,6 +9,8 @@ protected $buildPlanPHID; protected $buildStatus; protected $buildGeneration; + protected $buildParameters; + protected $buildParametersHash; protected $planAutoKey; private $buildable = self::ATTACHABLE; @@ -138,10 +140,35 @@ } } - public static function initializeNewBuild(PhabricatorUser $actor) { + public static function initializeNewBuild( + PhabricatorUser $actor) { return id(new HarbormasterBuild()) ->setBuildStatus(self::STATUS_INACTIVE) - ->setBuildGeneration(0); + ->setBuildGeneration(0) + ->setBuildParameters(array()); + } + + public function setBuildParameters(array $parameters) { + $this->buildParameters = $parameters; + $this->buildParametersHash = + self::getBuildParametersHashForArray($parameters); + return $this; + } + + public function getBuildParametersAsString() { + $strs = array(); + $parameters = $this->buildParameters; + if ($parameters === null) { + $parameters = array(); + } + foreach ($parameters as $key => $value) { + $strs[] = $key.'='.$value; + } + return implode(', ', $strs); + } + + public static function getBuildParametersHashForArray(array $parameters) { + return md5(print_r($parameters, true)); } public function delete() { @@ -156,9 +183,14 @@ protected function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, + self::CONFIG_SERIALIZATION => array( + 'buildParameters' => self::SERIALIZATION_JSON, + ), self::CONFIG_COLUMN_SCHEMA => array( 'buildStatus' => 'text32', 'buildGeneration' => 'uint32', + 'buildParameters' => 'text', + 'buildParametersHash' => 'text32', 'planAutoKey' => 'text32?', ), self::CONFIG_KEY_SCHEMA => array( @@ -272,6 +304,11 @@ } public function retrieveVariablesFromBuild() { + $parameters = $this->getBuildParameters(); + if ($parameters === null) { + $parameters = array(); + } + $results = array( 'buildable.diff' => null, 'buildable.revision' => null, @@ -281,7 +318,7 @@ 'repository.uri' => null, 'step.timestamp' => null, 'build.id' => null, - ); + ) + $parameters; $buildable = $this->getBuildable(); $object = $buildable->getBuildableObject();