mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-25 00:02:41 +01:00
Add a bin/herald test ...
for doing test runs via the CLI
Summary: Ref T13216. See D19666. It's currently tricky to profile Herald test runs since you have to submit a form and repeating them is a bit of a mess. Provide a simple CLI wrapper so we can use `--xprofile`. This is also maybe nice-to-have if we're ever debugging anything here. Test Plan: Ran `bin/herald test --object ... --type ...` and got a sensible looking transcript in the UI. Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T13216 Differential Revision: https://secure.phabricator.com/D19806
This commit is contained in:
parent
8a8123c9db
commit
533e4e13b3
6 changed files with 185 additions and 17 deletions
1
bin/herald
Symbolic link
1
bin/herald
Symbolic link
|
@ -0,0 +1 @@
|
|||
../scripts/setup/manage_herald.php
|
21
scripts/setup/manage_herald.php
Executable file
21
scripts/setup/manage_herald.php
Executable file
|
@ -0,0 +1,21 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
$root = dirname(dirname(dirname(__FILE__)));
|
||||
require_once $root.'/scripts/init/init-script.php';
|
||||
|
||||
$args = new PhutilArgumentParser($argv);
|
||||
$args->setTagline(pht('manage Herald'));
|
||||
$args->setSynopsis(<<<EOSYNOPSIS
|
||||
**herald** __command__ [__options__]
|
||||
Manage and debug Herald.
|
||||
|
||||
EOSYNOPSIS
|
||||
);
|
||||
$args->parseStandardArguments();
|
||||
|
||||
$workflows = id(new PhutilClassMapQuery())
|
||||
->setAncestorClass('HeraldManagementWorkflow')
|
||||
->execute();
|
||||
$workflows[] = new PhutilHelpArgumentWorkflow();
|
||||
$args->parseWorkflows($workflows);
|
|
@ -1488,6 +1488,7 @@ phutil_register_library_map(array(
|
|||
'HeraldInvalidConditionException' => 'applications/herald/engine/exception/HeraldInvalidConditionException.php',
|
||||
'HeraldMailableState' => 'applications/herald/state/HeraldMailableState.php',
|
||||
'HeraldManageGlobalRulesCapability' => 'applications/herald/capability/HeraldManageGlobalRulesCapability.php',
|
||||
'HeraldManagementWorkflow' => 'applications/herald/management/HeraldManagementWorkflow.php',
|
||||
'HeraldManiphestTaskAdapter' => 'applications/maniphest/herald/HeraldManiphestTaskAdapter.php',
|
||||
'HeraldNewController' => 'applications/herald/controller/HeraldNewController.php',
|
||||
'HeraldNewObjectField' => 'applications/herald/field/HeraldNewObjectField.php',
|
||||
|
@ -1537,6 +1538,7 @@ phutil_register_library_map(array(
|
|||
'HeraldSupportActionGroup' => 'applications/herald/action/HeraldSupportActionGroup.php',
|
||||
'HeraldSupportFieldGroup' => 'applications/herald/field/HeraldSupportFieldGroup.php',
|
||||
'HeraldTestConsoleController' => 'applications/herald/controller/HeraldTestConsoleController.php',
|
||||
'HeraldTestManagementWorkflow' => 'applications/herald/management/HeraldTestManagementWorkflow.php',
|
||||
'HeraldTextFieldValue' => 'applications/herald/value/HeraldTextFieldValue.php',
|
||||
'HeraldTokenizerFieldValue' => 'applications/herald/value/HeraldTokenizerFieldValue.php',
|
||||
'HeraldTransactionQuery' => 'applications/herald/query/HeraldTransactionQuery.php',
|
||||
|
@ -6975,6 +6977,7 @@ phutil_register_library_map(array(
|
|||
'HeraldInvalidConditionException' => 'Exception',
|
||||
'HeraldMailableState' => 'HeraldState',
|
||||
'HeraldManageGlobalRulesCapability' => 'PhabricatorPolicyCapability',
|
||||
'HeraldManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||
'HeraldManiphestTaskAdapter' => 'HeraldAdapter',
|
||||
'HeraldNewController' => 'HeraldController',
|
||||
'HeraldNewObjectField' => 'HeraldField',
|
||||
|
@ -7031,6 +7034,7 @@ phutil_register_library_map(array(
|
|||
'HeraldSupportActionGroup' => 'HeraldActionGroup',
|
||||
'HeraldSupportFieldGroup' => 'HeraldFieldGroup',
|
||||
'HeraldTestConsoleController' => 'HeraldController',
|
||||
'HeraldTestManagementWorkflow' => 'HeraldManagementWorkflow',
|
||||
'HeraldTextFieldValue' => 'HeraldFieldValue',
|
||||
'HeraldTokenizerFieldValue' => 'HeraldFieldValue',
|
||||
'HeraldTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
<?php
|
||||
|
||||
abstract class HeraldManagementWorkflow
|
||||
extends PhabricatorManagementWorkflow {}
|
|
@ -0,0 +1,139 @@
|
|||
<?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();
|
||||
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)
|
||||
->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;
|
||||
}
|
||||
|
||||
}
|
|
@ -30,36 +30,35 @@ final class HeraldTranscriptQuery
|
|||
|
||||
protected function loadPage() {
|
||||
$transcript = new HeraldTranscript();
|
||||
$conn_r = $transcript->establishConnection('r');
|
||||
$conn = $transcript->establishConnection('r');
|
||||
|
||||
// NOTE: Transcripts include a potentially enormous amount of serialized
|
||||
// data, so we're loading only some of the fields here if the caller asked
|
||||
// for partial records.
|
||||
|
||||
if ($this->needPartialRecords) {
|
||||
$fields = implode(
|
||||
', ',
|
||||
array(
|
||||
'id',
|
||||
'phid',
|
||||
'objectPHID',
|
||||
'time',
|
||||
'duration',
|
||||
'dryRun',
|
||||
'host',
|
||||
));
|
||||
$fields = array(
|
||||
'id',
|
||||
'phid',
|
||||
'objectPHID',
|
||||
'time',
|
||||
'duration',
|
||||
'dryRun',
|
||||
'host',
|
||||
);
|
||||
$fields = qsprintf($conn, '%LC', $fields);
|
||||
} else {
|
||||
$fields = '*';
|
||||
$fields = qsprintf($conn, '*');
|
||||
}
|
||||
|
||||
$rows = queryfx_all(
|
||||
$conn_r,
|
||||
$conn,
|
||||
'SELECT %Q FROM %T t %Q %Q %Q',
|
||||
$fields,
|
||||
$transcript->getTableName(),
|
||||
$this->buildWhereClause($conn_r),
|
||||
$this->buildOrderClause($conn_r),
|
||||
$this->buildLimitClause($conn_r));
|
||||
$this->buildWhereClause($conn),
|
||||
$this->buildOrderClause($conn),
|
||||
$this->buildLimitClause($conn));
|
||||
|
||||
$transcripts = $transcript->loadAllFromArray($rows);
|
||||
|
||||
|
|
Loading…
Reference in a new issue