Index: src/__phutil_library_map__.php =================================================================== --- src/__phutil_library_map__.php +++ src/__phutil_library_map__.php @@ -26,6 +26,7 @@ 'ArcanistBranchWorkflow' => 'workflow/ArcanistBranchWorkflow.php', 'ArcanistBritishTestCase' => 'configuration/__tests__/ArcanistBritishTestCase.php', 'ArcanistBrowseWorkflow' => 'workflow/ArcanistBrowseWorkflow.php', + 'ArcanistBuildAgentWorkflow' => 'workflow/ArcanistBuildAgentWorkflow.php', 'ArcanistBundle' => 'parser/ArcanistBundle.php', 'ArcanistBundleTestCase' => 'parser/__tests__/ArcanistBundleTestCase.php', 'ArcanistCSSLintLinter' => 'lint/linter/ArcanistCSSLintLinter.php', @@ -167,6 +168,7 @@ 'ArcanistXHPASTLinter' => 'lint/linter/ArcanistXHPASTLinter.php', 'ArcanistXHPASTLinterTestCase' => 'lint/linter/__tests__/ArcanistXHPASTLinterTestCase.php', 'ArcanistXUnitTestResultParser' => 'unit/engine/ArcanistXUnitTestResultParser.php', + 'BuildStepImplementation' => 'build/BuildStepImplementation.php', 'CSharpToolsTestEngine' => 'unit/engine/CSharpToolsTestEngine.php', 'ComprehensiveLintEngine' => 'lint/engine/ComprehensiveLintEngine.php', 'ExampleLintEngine' => 'lint/engine/ExampleLintEngine.php', @@ -180,6 +182,7 @@ 'PhutilUnitTestEngine' => 'unit/engine/PhutilUnitTestEngine.php', 'PhutilUnitTestEngineTestCase' => 'unit/engine/__tests__/PhutilUnitTestEngineTestCase.php', 'PytestTestEngine' => 'unit/engine/PytestTestEngine.php', + 'SleepBuildStepImplementation' => 'build/SleepBuildStepImplementation.php', 'UnitTestableArcanistLintEngine' => 'lint/engine/UnitTestableArcanistLintEngine.php', 'XUnitTestEngine' => 'unit/engine/XUnitTestEngine.php', 'XUnitTestResultParserTestCase' => 'unit/engine/__tests__/XUnitTestResultParserTestCase.php', @@ -202,6 +205,7 @@ 'ArcanistBranchWorkflow' => 'ArcanistFeatureWorkflow', 'ArcanistBritishTestCase' => 'ArcanistTestCase', 'ArcanistBrowseWorkflow' => 'ArcanistBaseWorkflow', + 'ArcanistBuildAgentWorkflow' => 'ArcanistBaseWorkflow', 'ArcanistBundleTestCase' => 'ArcanistTestCase', 'ArcanistCSSLintLinter' => 'ArcanistExternalLinter', 'ArcanistCSSLintLinterTestCase' => 'ArcanistArcanistLinterTestCase', @@ -323,6 +327,7 @@ 'PhutilUnitTestEngine' => 'ArcanistBaseUnitTestEngine', 'PhutilUnitTestEngineTestCase' => 'ArcanistTestCase', 'PytestTestEngine' => 'ArcanistBaseUnitTestEngine', + 'SleepBuildStepImplementation' => 'BuildStepImplementation', 'UnitTestableArcanistLintEngine' => 'ArcanistLintEngine', 'XUnitTestEngine' => 'ArcanistBaseUnitTestEngine', 'XUnitTestResultParserTestCase' => 'ArcanistTestCase', Index: src/build/BuildStepImplementation.php =================================================================== --- /dev/null +++ src/build/BuildStepImplementation.php @@ -0,0 +1,88 @@ +setAncestorClass("BuildStepImplementation") + ->setConcreteOnly(true) + ->selectAndLoadSymbols(); + return ipull($symbols, 'name'); + } + + /** + * The name of the implementation. + */ + abstract public function getName(); + + /** + * The generic description of the implementation. + */ + public function getGenericDescription() { + return ''; + } + + /** + * The description of the implementation, based on the current settings. + */ + public function getDescription() { + return ''; + } + + /** + * Run the build step against the specified build. + */ + abstract public function execute(RemoteHarbormasterBuild $build); + + /** + * Gets the settings for this build step. + */ + public function getSettings() { + return $this->settings; + } + + /** + * Validate the current settings of this build step. + */ + public function validate() { + return true; + } + + /** + * Loads the settings for this build step implementation from the build step. + */ + public final function loadSettings(array $details) { + $this->settings = array(); + $this->validateSettingDefinitions(); + foreach ($this->getSettingDefinitions() as $name => $opt) { + $this->settings[$name] = idx($details, $name, null); + } + return $this->settings; + } + + /** + * Validates that the setting definitions for this implementation are valid. + */ + public final function validateSettingDefinitions() { + foreach ($this->getSettingDefinitions() as $name => $opt) { + if (!isset($opt['type'])) { + throw new Exception( + 'Setting definition \''.$name. + '\' is missing type requirement.'); + } + } + } + + /** + * Return an array of settings for this step implementation. + */ + public function getSettingDefinitions() { + return array(); + } +} Index: src/build/RemoteHarbormasterBuild.php =================================================================== --- /dev/null +++ src/build/RemoteHarbormasterBuild.php @@ -0,0 +1,5 @@ +getSettings(); + + return pht('Sleep for %s seconds.', $settings['seconds']); + } + + public function execute(RemoteHarbormasterBuild $build) { + $settings = $this->getSettings(); + + sleep($settings['seconds']); + } + + public function validateSettings() { + $settings = $this->getSettings(); + + if ($settings['seconds'] === null) { + return false; + } + if (!is_int($settings['seconds'])) { + return false; + } + return true; + } + + public function getSettingDefinitions() { + return array( + 'seconds' => array( + 'name' => 'Seconds', + 'description' => 'The number of seconds to sleep for.', + 'type' => BuildStepImplementation::SETTING_TYPE_INTEGER)); + } + +} Index: src/workflow/ArcanistBuildAgentWorkflow.php =================================================================== --- /dev/null +++ src/workflow/ArcanistBuildAgentWorkflow.php @@ -0,0 +1,75 @@ + array( + 'short' => 'c', + 'param' => 'category', + 'help' => "Specify the category of the build agent.", + ) + ); + } + + public function run() { + $console = PhutilConsole::getConsole(); + $console->writeOut("Starting build agent...\n"); + + // Pool for agent instructions. + $conduit = $this->getConduit(); + while (true) { + $item = $conduit->callMethodSynchronous('agent.nextbuild', array()); + if ($item["exists"]) { + $steps = $item["steps"]; + + // $steps is an array like so: + // array( + // array( + // "class" => "SleepBuildStepImplementation", + // "details" => "{\"seconds\":5}"), + // array( + // "class" => "SleepBuildStepImplementation", + // "details" => "{\"seconds\":15}")) + // TODO: Do something with this. + } else { + $console->writeOut("> No build to pick up. \n"); + sleep(15); + } + } + + } +} +