Changeset View
Changeset View
Standalone View
Standalone View
src/applications/herald/management/HeraldTestManagementWorkflow.php
- This file was added.
| <?php | |||||
| final class HeraldTestManagementWorkflow | |||||
| extends HeraldManagementWorkflow { | |||||
| protected function didConstruct() { | |||||
| $this | |||||
| ->setName('test') | |||||
| ->setExamples('**test** --object __object__ --type __type__') | |||||
| ->setSynopsis( | |||||
| pht( | |||||
| 'Test content rules for an object. Executes a dry run, like the '. | |||||
| 'web UI test console.')) | |||||
| ->setArguments( | |||||
| array( | |||||
| array( | |||||
| 'name' => 'object', | |||||
| 'param' => 'object', | |||||
| 'help' => pht('Run rules on this object.'), | |||||
| ), | |||||
| array( | |||||
| 'name' => 'type', | |||||
| 'param' => 'type', | |||||
| 'help' => pht('Run rules for this content type.'), | |||||
| ), | |||||
| )); | |||||
| } | |||||
| public function execute(PhutilArgumentParser $args) { | |||||
| $viewer = $this->getViewer(); | |||||
| $object_name = $args->getArg('object'); | |||||
| if (!strlen($object_name)) { | |||||
| throw new PhutilArgumentUsageException( | |||||
| pht('Specify an object to test rules for with "--object".')); | |||||
| } | |||||
| $objects = id(new PhabricatorObjectQuery()) | |||||
| ->setViewer($viewer) | |||||
| ->withNames(array($object_name)) | |||||
| ->execute(); | |||||
amckinley: Maybe we want to take a PHID as an argument in addition to an object name? | |||||
Done Inline ActionswithNames() is roughly withMonogramsOrPHIDs(...) and will load objects by PHID if PHIDs are passed in. epriestley: `withNames()` is roughly `withMonogramsOrPHIDs(...)` and will load objects by PHID if PHIDs are… | |||||
| if (!$objects) { | |||||
| throw new PhutilArgumentUsageException( | |||||
| pht( | |||||
| 'Unable to load specified object ("%s").', | |||||
| $object_name)); | |||||
| } | |||||
| $object = head($objects); | |||||
| $adapters = HeraldAdapter::getAllAdapters(); | |||||
| $can_select = array(); | |||||
| $display_adapters = array(); | |||||
| foreach ($adapters as $key => $adapter) { | |||||
| if (!$adapter->isTestAdapterForObject($object)) { | |||||
| continue; | |||||
| } | |||||
| if (!$adapter->isAvailableToUser($viewer)) { | |||||
| continue; | |||||
| } | |||||
| $display_adapters[$key] = $adapter; | |||||
| if ($adapter->canCreateTestAdapterForObject($object)) { | |||||
| $can_select[$key] = $adapter; | |||||
| } | |||||
| } | |||||
| $content_type = $args->getArg('type'); | |||||
| if (!strlen($content_type)) { | |||||
| throw new PhutilArgumentUsageException( | |||||
| pht( | |||||
| 'Specify a content type to run rules for. For this object, valid '. | |||||
| 'content types are: %s.', | |||||
| implode(', ', array_keys($can_select)))); | |||||
| } | |||||
| if (!isset($can_select[$content_type])) { | |||||
| if (!isset($display_adapters[$content_type])) { | |||||
| throw new PhutilArgumentUsageException( | |||||
| pht( | |||||
| 'Specify a content type to run rules for. The specified content '. | |||||
| 'type ("%s") is not valid. For this object, valid content types '. | |||||
| 'are: %s.', | |||||
| $content_type, | |||||
| implode(', ', array_keys($can_select)))); | |||||
| } else { | |||||
| throw new PhutilArgumentUsageException( | |||||
| pht( | |||||
| 'The specified content type ("%s") does not support dry runs. '. | |||||
| 'Choose a testable content type. For this object, valid content '. | |||||
| 'types are: %s.', | |||||
| $content_type, | |||||
| implode(', ', array_keys($can_select)))); | |||||
| } | |||||
| } | |||||
| $adapter = $can_select[$content_type]->newTestAdapter( | |||||
| $viewer, | |||||
| $object); | |||||
| $content_source = $this->newContentSource(); | |||||
| $adapter | |||||
| ->setContentSource($content_source) | |||||
| ->setIsNewObject(false) | |||||
| ->setViewer($viewer); | |||||
| $rules = id(new HeraldRuleQuery()) | |||||
| ->setViewer($viewer) | |||||
| ->withContentTypes(array($adapter->getAdapterContentType())) | |||||
| ->withDisabled(false) | |||||
| ->needConditionsAndActions(true) | |||||
Not Done Inline ActionsIt might make sense to test a disabled Herald rule, since the rule might be disabled for bugginess but someone wants to test it from here before reenabling it. amckinley: It might make sense to test a disabled Herald rule, since the rule might be disabled for… | |||||
Done Inline ActionsWe could theoretically offer single-rule test runs but it would be slightly tricky because of the "Another Herald Rule: ..." condition, which can mean that individual rules don't truly run in isolation. Reasonable-ish workarounds today are to remove the actions or add an impossible condition at the end of the rule you want to test. epriestley: We could theoretically offer single-rule test runs but it would be slightly tricky because of… | |||||
| ->needAppliedToPHIDs(array($object->getPHID())) | |||||
| ->needValidateAuthors(true) | |||||
| ->execute(); | |||||
| $engine = id(new HeraldEngine()) | |||||
| ->setDryRun(true); | |||||
| $effects = $engine->applyRules($rules, $adapter); | |||||
| $engine->applyEffects($effects, $adapter, $rules); | |||||
| $xscript = $engine->getTranscript(); | |||||
| $uri = '/herald/transcript/'.$xscript->getID().'/'; | |||||
| $uri = PhabricatorEnv::getProductionURI($uri); | |||||
| echo tsprintf( | |||||
| "%s\n\n __%s__\n\n", | |||||
| pht('Test run complete. Transcript:'), | |||||
| $uri); | |||||
| return 0; | |||||
| } | |||||
| } | |||||
Maybe we want to take a PHID as an argument in addition to an object name?