Add a "Make an HTTP Request" build step
Summary:
Ref T1049. This is very minimal, but does what it says.
I merged the variable replacement code so Remote + HTTP can share more stuff.
Test Plan:
Ran "HTTP" and "Remote" build plans.
{F79886}
{F79887}
Reviewers: hach-que, btrahan
Reviewed By: hach-que
CC: zeeg, aran
Maniphest Tasks: T1049
Differential Revision: https://secure.phabricator.com/D7541
			
			
This commit is contained in:
		| @@ -682,6 +682,7 @@ phutil_register_library_map(array( | |||||||
|     'HarbormasterCapabilityManagePlans' => 'applications/harbormaster/capability/HarbormasterCapabilityManagePlans.php', |     'HarbormasterCapabilityManagePlans' => 'applications/harbormaster/capability/HarbormasterCapabilityManagePlans.php', | ||||||
|     'HarbormasterController' => 'applications/harbormaster/controller/HarbormasterController.php', |     'HarbormasterController' => 'applications/harbormaster/controller/HarbormasterController.php', | ||||||
|     'HarbormasterDAO' => 'applications/harbormaster/storage/HarbormasterDAO.php', |     'HarbormasterDAO' => 'applications/harbormaster/storage/HarbormasterDAO.php', | ||||||
|  |     'HarbormasterHTTPRequestBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterHTTPRequestBuildStepImplementation.php', | ||||||
|     'HarbormasterObject' => 'applications/harbormaster/storage/HarbormasterObject.php', |     'HarbormasterObject' => 'applications/harbormaster/storage/HarbormasterObject.php', | ||||||
|     'HarbormasterPHIDTypeBuild' => 'applications/harbormaster/phid/HarbormasterPHIDTypeBuild.php', |     'HarbormasterPHIDTypeBuild' => 'applications/harbormaster/phid/HarbormasterPHIDTypeBuild.php', | ||||||
|     'HarbormasterPHIDTypeBuildItem' => 'applications/harbormaster/phid/HarbormasterPHIDTypeBuildItem.php', |     'HarbormasterPHIDTypeBuildItem' => 'applications/harbormaster/phid/HarbormasterPHIDTypeBuildItem.php', | ||||||
| @@ -2979,6 +2980,7 @@ phutil_register_library_map(array( | |||||||
|     'HarbormasterCapabilityManagePlans' => 'PhabricatorPolicyCapability', |     'HarbormasterCapabilityManagePlans' => 'PhabricatorPolicyCapability', | ||||||
|     'HarbormasterController' => 'PhabricatorController', |     'HarbormasterController' => 'PhabricatorController', | ||||||
|     'HarbormasterDAO' => 'PhabricatorLiskDAO', |     'HarbormasterDAO' => 'PhabricatorLiskDAO', | ||||||
|  |     'HarbormasterHTTPRequestBuildStepImplementation' => 'VariableBuildStepImplementation', | ||||||
|     'HarbormasterObject' => 'HarbormasterDAO', |     'HarbormasterObject' => 'HarbormasterDAO', | ||||||
|     'HarbormasterPHIDTypeBuild' => 'PhabricatorPHIDType', |     'HarbormasterPHIDTypeBuild' => 'PhabricatorPHIDType', | ||||||
|     'HarbormasterPHIDTypeBuildItem' => 'PhabricatorPHIDType', |     'HarbormasterPHIDTypeBuildItem' => 'PhabricatorPHIDType', | ||||||
|   | |||||||
| @@ -26,7 +26,7 @@ final class HarbormasterBuildCancelController | |||||||
|     $build_uri = $this->getApplicationURI('/build/'.$build->getID()); |     $build_uri = $this->getApplicationURI('/build/'.$build->getID()); | ||||||
|  |  | ||||||
|     if ($request->isDialogFormPost()) { |     if ($request->isDialogFormPost()) { | ||||||
|       $build->setCancelRequested(true); |       $build->setCancelRequested(1); | ||||||
|       $build->save(); |       $build->save(); | ||||||
|  |  | ||||||
|       return id(new AphrontRedirectResponse())->setURI($build_uri); |       return id(new AphrontRedirectResponse())->setURI($build_uri); | ||||||
|   | |||||||
| @@ -0,0 +1,70 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | final class HarbormasterHTTPRequestBuildStepImplementation | ||||||
|  |   extends VariableBuildStepImplementation { | ||||||
|  |  | ||||||
|  |   public function getName() { | ||||||
|  |     return pht('Make HTTP Request'); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function getGenericDescription() { | ||||||
|  |     return pht('Make an HTTP request.'); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function getDescription() { | ||||||
|  |     $settings = $this->getSettings(); | ||||||
|  |  | ||||||
|  |     $uri = new PhutilURI($settings['uri']); | ||||||
|  |     $domain = $uri->getDomain(); | ||||||
|  |     return pht('Make an HTTP request to %s', $domain); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function execute( | ||||||
|  |     HarbormasterBuild $build, | ||||||
|  |     HarbormasterBuildStep $build_step) { | ||||||
|  |  | ||||||
|  |     $settings = $this->getSettings(); | ||||||
|  |     $variables = $this->retrieveVariablesFromBuild($build); | ||||||
|  |  | ||||||
|  |     $uri = $this->mergeVariables( | ||||||
|  |       'vurisprintf', | ||||||
|  |       $settings['uri'], | ||||||
|  |       $variables); | ||||||
|  |  | ||||||
|  |     $log_body = $build->createLog($build_step, $uri, 'http-body'); | ||||||
|  |     $start = $log_body->start(); | ||||||
|  |  | ||||||
|  |     list($status, $body, $headers) = id(new HTTPSFuture($uri)) | ||||||
|  |       ->setMethod('POST') | ||||||
|  |       ->setTimeout(60) | ||||||
|  |       ->resolve(); | ||||||
|  |  | ||||||
|  |     $log_body->append($body); | ||||||
|  |     $log_body->finalize($start); | ||||||
|  |  | ||||||
|  |     if ($status->getStatusCode() != 200) { | ||||||
|  |       $build->setBuildStatus(HarbormasterBuild::STATUS_FAILED); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function validateSettings() { | ||||||
|  |     $settings = $this->getSettings(); | ||||||
|  |  | ||||||
|  |     if ($settings['uri'] === null || !is_string($settings['uri'])) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function getSettingDefinitions() { | ||||||
|  |     return array( | ||||||
|  |       'uri' => array( | ||||||
|  |         'name' => 'URI', | ||||||
|  |         'description' => pht('The URI to request.'), | ||||||
|  |         'type' => BuildStepImplementation::SETTING_TYPE_STRING, | ||||||
|  |       ), | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -25,24 +25,12 @@ final class RemoteCommandBuildStepImplementation | |||||||
|     HarbormasterBuildStep $build_step) { |     HarbormasterBuildStep $build_step) { | ||||||
|  |  | ||||||
|     $settings = $this->getSettings(); |     $settings = $this->getSettings(); | ||||||
|  |  | ||||||
|     $parameters = array(); |  | ||||||
|     $matches = array(); |  | ||||||
|     $variables = $this->retrieveVariablesFromBuild($build); |     $variables = $this->retrieveVariablesFromBuild($build); | ||||||
|     $command = $settings['command']; |  | ||||||
|     preg_match_all( |  | ||||||
|       "/\\\$\\{(?P<name>[a-z\.]+)\\}/", |  | ||||||
|       $command, |  | ||||||
|       $matches); |  | ||||||
|     foreach ($matches["name"] as $match) { |  | ||||||
|       $parameters[] = idx($variables, $match, ""); |  | ||||||
|     } |  | ||||||
|     $command = str_replace("%", "%%", $command); |  | ||||||
|     $command = preg_replace("/\\\$\\{(?P<name>[a-z\.]+)\\}/", "%s", $command); |  | ||||||
|  |  | ||||||
|     $command = vcsprintf( |     $command = $this->mergeVariables( | ||||||
|       $command, |       'vcsprintf', | ||||||
|       $parameters); |       $settings['command'], | ||||||
|  |       $variables); | ||||||
|  |  | ||||||
|     $future = null; |     $future = null; | ||||||
|     if (empty($settings['sshkey'])) { |     if (empty($settings['sshkey'])) { | ||||||
|   | |||||||
| @@ -33,17 +33,42 @@ abstract class VariableBuildStepImplementation extends BuildStepImplementation { | |||||||
|     return $results; |     return $results; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public function mergeVariables(HarbormasterBuild $build, $string) { |  | ||||||
|     $variables = $this->retrieveVariablesFromBuild($build); |   /** | ||||||
|     foreach ($variables as $name => $value) { |    * Convert a user-provided string with variables in it, like: | ||||||
|       if ($value === null) { |    * | ||||||
|         $value = ''; |    *   ls ${dirname} | ||||||
|  |    * | ||||||
|  |    * ...into a string with variables merged into it safely: | ||||||
|  |    * | ||||||
|  |    *   ls 'dir with spaces' | ||||||
|  |    * | ||||||
|  |    * @param string Name of a `vxsprintf` function, like @{function:vcsprintf}. | ||||||
|  |    * @param string User-provided pattern string containing `${variables}`. | ||||||
|  |    * @param dict   List of available replacement variables. | ||||||
|  |    * @return string String with variables replaced safely into it. | ||||||
|  |    */ | ||||||
|  |   protected function mergeVariables($function, $pattern, array $variables) { | ||||||
|  |     $regexp = '/\\$\\{(?P<name>[a-z\\.]+)\\}/'; | ||||||
|  |  | ||||||
|  |     $matches = null; | ||||||
|  |     preg_match_all($regexp, $pattern, $matches); | ||||||
|  |  | ||||||
|  |     $argv = array(); | ||||||
|  |     foreach ($matches['name'] as $name) { | ||||||
|  |       if (!array_key_exists($name, $variables)) { | ||||||
|  |         throw new Exception(pht("No such variable '%s'!", $name)); | ||||||
|       } |       } | ||||||
|       $string = str_replace('${'.$name.'}', $value, $string); |       $argv[] = $variables[$name]; | ||||||
|     } |     } | ||||||
|     return $string; |  | ||||||
|  |     $pattern = str_replace('%', '%%', $pattern); | ||||||
|  |     $pattern = preg_replace($regexp, '%s', $pattern); | ||||||
|  |  | ||||||
|  |     return call_user_func($function, $pattern, $argv); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|   public function getAvailableVariables() { |   public function getAvailableVariables() { | ||||||
|     return array( |     return array( | ||||||
|       'buildable.revision' => |       'buildable.revision' => | ||||||
|   | |||||||
| @@ -54,7 +54,7 @@ final class HarbormasterBuild extends HarbormasterDAO | |||||||
|   public static function initializeNewBuild(PhabricatorUser $actor) { |   public static function initializeNewBuild(PhabricatorUser $actor) { | ||||||
|     return id(new HarbormasterBuild()) |     return id(new HarbormasterBuild()) | ||||||
|       ->setBuildStatus(self::STATUS_INACTIVE) |       ->setBuildStatus(self::STATUS_INACTIVE) | ||||||
|       ->setCancelRequested(false); |       ->setCancelRequested(0); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public function getConfiguration() { |   public function getConfiguration() { | ||||||
| @@ -118,7 +118,7 @@ final class HarbormasterBuild extends HarbormasterDAO | |||||||
|     $copy = id(new HarbormasterBuild())->load($this->getID()); |     $copy = id(new HarbormasterBuild())->load($this->getID()); | ||||||
|     if ($copy->getCancelRequested()) { |     if ($copy->getCancelRequested()) { | ||||||
|       $this->setBuildStatus(HarbormasterBuild::STATUS_CANCELLED); |       $this->setBuildStatus(HarbormasterBuild::STATUS_CANCELLED); | ||||||
|       $this->setCancelRequested(false); |       $this->setCancelRequested(0); | ||||||
|       $this->save(); |       $this->save(); | ||||||
|       return true; |       return true; | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -28,7 +28,7 @@ final class HarbormasterBuildLog extends HarbormasterDAO | |||||||
|       ->setBuildPHID($build->getPHID()) |       ->setBuildPHID($build->getPHID()) | ||||||
|       ->setBuildStepPHID($build_step->getPHID()) |       ->setBuildStepPHID($build_step->getPHID()) | ||||||
|       ->setDuration(null) |       ->setDuration(null) | ||||||
|       ->setLive(false); |       ->setLive(0); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public function getConfiguration() { |   public function getConfiguration() { | ||||||
| @@ -70,7 +70,7 @@ final class HarbormasterBuildLog extends HarbormasterDAO | |||||||
|       throw new Exception("Live logging has already started for this log."); |       throw new Exception("Live logging has already started for this log."); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     $this->setLive(true); |     $this->setLive(1); | ||||||
|     $this->save(); |     $this->save(); | ||||||
|  |  | ||||||
|     return time(); |     return time(); | ||||||
| @@ -150,7 +150,7 @@ final class HarbormasterBuildLog extends HarbormasterDAO | |||||||
|     if ($start > 0) { |     if ($start > 0) { | ||||||
|       $this->setDuration(time() - $start); |       $this->setDuration(time() - $start); | ||||||
|     } |     } | ||||||
|     $this->setLive(false); |     $this->setLive(0); | ||||||
|     $this->save(); |     $this->save(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 epriestley
					epriestley