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', | ||||
|     'HarbormasterController' => 'applications/harbormaster/controller/HarbormasterController.php', | ||||
|     'HarbormasterDAO' => 'applications/harbormaster/storage/HarbormasterDAO.php', | ||||
|     'HarbormasterHTTPRequestBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterHTTPRequestBuildStepImplementation.php', | ||||
|     'HarbormasterObject' => 'applications/harbormaster/storage/HarbormasterObject.php', | ||||
|     'HarbormasterPHIDTypeBuild' => 'applications/harbormaster/phid/HarbormasterPHIDTypeBuild.php', | ||||
|     'HarbormasterPHIDTypeBuildItem' => 'applications/harbormaster/phid/HarbormasterPHIDTypeBuildItem.php', | ||||
| @@ -2979,6 +2980,7 @@ phutil_register_library_map(array( | ||||
|     'HarbormasterCapabilityManagePlans' => 'PhabricatorPolicyCapability', | ||||
|     'HarbormasterController' => 'PhabricatorController', | ||||
|     'HarbormasterDAO' => 'PhabricatorLiskDAO', | ||||
|     'HarbormasterHTTPRequestBuildStepImplementation' => 'VariableBuildStepImplementation', | ||||
|     'HarbormasterObject' => 'HarbormasterDAO', | ||||
|     'HarbormasterPHIDTypeBuild' => 'PhabricatorPHIDType', | ||||
|     'HarbormasterPHIDTypeBuildItem' => 'PhabricatorPHIDType', | ||||
|   | ||||
| @@ -26,7 +26,7 @@ final class HarbormasterBuildCancelController | ||||
|     $build_uri = $this->getApplicationURI('/build/'.$build->getID()); | ||||
|  | ||||
|     if ($request->isDialogFormPost()) { | ||||
|       $build->setCancelRequested(true); | ||||
|       $build->setCancelRequested(1); | ||||
|       $build->save(); | ||||
|  | ||||
|       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) { | ||||
|  | ||||
|     $settings = $this->getSettings(); | ||||
|  | ||||
|     $parameters = array(); | ||||
|     $matches = array(); | ||||
|     $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, | ||||
|       $parameters); | ||||
|     $command = $this->mergeVariables( | ||||
|       'vcsprintf', | ||||
|       $settings['command'], | ||||
|       $variables); | ||||
|  | ||||
|     $future = null; | ||||
|     if (empty($settings['sshkey'])) { | ||||
|   | ||||
| @@ -33,17 +33,42 @@ abstract class VariableBuildStepImplementation extends BuildStepImplementation { | ||||
|     return $results; | ||||
|   } | ||||
|  | ||||
|   public function mergeVariables(HarbormasterBuild $build, $string) { | ||||
|     $variables = $this->retrieveVariablesFromBuild($build); | ||||
|     foreach ($variables as $name => $value) { | ||||
|       if ($value === null) { | ||||
|         $value = ''; | ||||
|  | ||||
|   /** | ||||
|    * Convert a user-provided string with variables in it, like: | ||||
|    * | ||||
|    *   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() { | ||||
|     return array( | ||||
|       'buildable.revision' => | ||||
|   | ||||
| @@ -54,7 +54,7 @@ final class HarbormasterBuild extends HarbormasterDAO | ||||
|   public static function initializeNewBuild(PhabricatorUser $actor) { | ||||
|     return id(new HarbormasterBuild()) | ||||
|       ->setBuildStatus(self::STATUS_INACTIVE) | ||||
|       ->setCancelRequested(false); | ||||
|       ->setCancelRequested(0); | ||||
|   } | ||||
|  | ||||
|   public function getConfiguration() { | ||||
| @@ -118,7 +118,7 @@ final class HarbormasterBuild extends HarbormasterDAO | ||||
|     $copy = id(new HarbormasterBuild())->load($this->getID()); | ||||
|     if ($copy->getCancelRequested()) { | ||||
|       $this->setBuildStatus(HarbormasterBuild::STATUS_CANCELLED); | ||||
|       $this->setCancelRequested(false); | ||||
|       $this->setCancelRequested(0); | ||||
|       $this->save(); | ||||
|       return true; | ||||
|     } | ||||
|   | ||||
| @@ -28,7 +28,7 @@ final class HarbormasterBuildLog extends HarbormasterDAO | ||||
|       ->setBuildPHID($build->getPHID()) | ||||
|       ->setBuildStepPHID($build_step->getPHID()) | ||||
|       ->setDuration(null) | ||||
|       ->setLive(false); | ||||
|       ->setLive(0); | ||||
|   } | ||||
|  | ||||
|   public function getConfiguration() { | ||||
| @@ -70,7 +70,7 @@ final class HarbormasterBuildLog extends HarbormasterDAO | ||||
|       throw new Exception("Live logging has already started for this log."); | ||||
|     } | ||||
|  | ||||
|     $this->setLive(true); | ||||
|     $this->setLive(1); | ||||
|     $this->save(); | ||||
|  | ||||
|     return time(); | ||||
| @@ -150,7 +150,7 @@ final class HarbormasterBuildLog extends HarbormasterDAO | ||||
|     if ($start > 0) { | ||||
|       $this->setDuration(time() - $start); | ||||
|     } | ||||
|     $this->setLive(false); | ||||
|     $this->setLive(0); | ||||
|     $this->save(); | ||||
|   } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 epriestley
					epriestley