mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-25 08:12:40 +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',
|
'HeraldInvalidConditionException' => 'applications/herald/engine/exception/HeraldInvalidConditionException.php',
|
||||||
'HeraldMailableState' => 'applications/herald/state/HeraldMailableState.php',
|
'HeraldMailableState' => 'applications/herald/state/HeraldMailableState.php',
|
||||||
'HeraldManageGlobalRulesCapability' => 'applications/herald/capability/HeraldManageGlobalRulesCapability.php',
|
'HeraldManageGlobalRulesCapability' => 'applications/herald/capability/HeraldManageGlobalRulesCapability.php',
|
||||||
|
'HeraldManagementWorkflow' => 'applications/herald/management/HeraldManagementWorkflow.php',
|
||||||
'HeraldManiphestTaskAdapter' => 'applications/maniphest/herald/HeraldManiphestTaskAdapter.php',
|
'HeraldManiphestTaskAdapter' => 'applications/maniphest/herald/HeraldManiphestTaskAdapter.php',
|
||||||
'HeraldNewController' => 'applications/herald/controller/HeraldNewController.php',
|
'HeraldNewController' => 'applications/herald/controller/HeraldNewController.php',
|
||||||
'HeraldNewObjectField' => 'applications/herald/field/HeraldNewObjectField.php',
|
'HeraldNewObjectField' => 'applications/herald/field/HeraldNewObjectField.php',
|
||||||
|
@ -1537,6 +1538,7 @@ phutil_register_library_map(array(
|
||||||
'HeraldSupportActionGroup' => 'applications/herald/action/HeraldSupportActionGroup.php',
|
'HeraldSupportActionGroup' => 'applications/herald/action/HeraldSupportActionGroup.php',
|
||||||
'HeraldSupportFieldGroup' => 'applications/herald/field/HeraldSupportFieldGroup.php',
|
'HeraldSupportFieldGroup' => 'applications/herald/field/HeraldSupportFieldGroup.php',
|
||||||
'HeraldTestConsoleController' => 'applications/herald/controller/HeraldTestConsoleController.php',
|
'HeraldTestConsoleController' => 'applications/herald/controller/HeraldTestConsoleController.php',
|
||||||
|
'HeraldTestManagementWorkflow' => 'applications/herald/management/HeraldTestManagementWorkflow.php',
|
||||||
'HeraldTextFieldValue' => 'applications/herald/value/HeraldTextFieldValue.php',
|
'HeraldTextFieldValue' => 'applications/herald/value/HeraldTextFieldValue.php',
|
||||||
'HeraldTokenizerFieldValue' => 'applications/herald/value/HeraldTokenizerFieldValue.php',
|
'HeraldTokenizerFieldValue' => 'applications/herald/value/HeraldTokenizerFieldValue.php',
|
||||||
'HeraldTransactionQuery' => 'applications/herald/query/HeraldTransactionQuery.php',
|
'HeraldTransactionQuery' => 'applications/herald/query/HeraldTransactionQuery.php',
|
||||||
|
@ -6975,6 +6977,7 @@ phutil_register_library_map(array(
|
||||||
'HeraldInvalidConditionException' => 'Exception',
|
'HeraldInvalidConditionException' => 'Exception',
|
||||||
'HeraldMailableState' => 'HeraldState',
|
'HeraldMailableState' => 'HeraldState',
|
||||||
'HeraldManageGlobalRulesCapability' => 'PhabricatorPolicyCapability',
|
'HeraldManageGlobalRulesCapability' => 'PhabricatorPolicyCapability',
|
||||||
|
'HeraldManagementWorkflow' => 'PhabricatorManagementWorkflow',
|
||||||
'HeraldManiphestTaskAdapter' => 'HeraldAdapter',
|
'HeraldManiphestTaskAdapter' => 'HeraldAdapter',
|
||||||
'HeraldNewController' => 'HeraldController',
|
'HeraldNewController' => 'HeraldController',
|
||||||
'HeraldNewObjectField' => 'HeraldField',
|
'HeraldNewObjectField' => 'HeraldField',
|
||||||
|
@ -7031,6 +7034,7 @@ phutil_register_library_map(array(
|
||||||
'HeraldSupportActionGroup' => 'HeraldActionGroup',
|
'HeraldSupportActionGroup' => 'HeraldActionGroup',
|
||||||
'HeraldSupportFieldGroup' => 'HeraldFieldGroup',
|
'HeraldSupportFieldGroup' => 'HeraldFieldGroup',
|
||||||
'HeraldTestConsoleController' => 'HeraldController',
|
'HeraldTestConsoleController' => 'HeraldController',
|
||||||
|
'HeraldTestManagementWorkflow' => 'HeraldManagementWorkflow',
|
||||||
'HeraldTextFieldValue' => 'HeraldFieldValue',
|
'HeraldTextFieldValue' => 'HeraldFieldValue',
|
||||||
'HeraldTokenizerFieldValue' => 'HeraldFieldValue',
|
'HeraldTokenizerFieldValue' => 'HeraldFieldValue',
|
||||||
'HeraldTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
'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,16 +30,14 @@ final class HeraldTranscriptQuery
|
||||||
|
|
||||||
protected function loadPage() {
|
protected function loadPage() {
|
||||||
$transcript = new HeraldTranscript();
|
$transcript = new HeraldTranscript();
|
||||||
$conn_r = $transcript->establishConnection('r');
|
$conn = $transcript->establishConnection('r');
|
||||||
|
|
||||||
// NOTE: Transcripts include a potentially enormous amount of serialized
|
// NOTE: Transcripts include a potentially enormous amount of serialized
|
||||||
// data, so we're loading only some of the fields here if the caller asked
|
// data, so we're loading only some of the fields here if the caller asked
|
||||||
// for partial records.
|
// for partial records.
|
||||||
|
|
||||||
if ($this->needPartialRecords) {
|
if ($this->needPartialRecords) {
|
||||||
$fields = implode(
|
$fields = array(
|
||||||
', ',
|
|
||||||
array(
|
|
||||||
'id',
|
'id',
|
||||||
'phid',
|
'phid',
|
||||||
'objectPHID',
|
'objectPHID',
|
||||||
|
@ -47,19 +45,20 @@ final class HeraldTranscriptQuery
|
||||||
'duration',
|
'duration',
|
||||||
'dryRun',
|
'dryRun',
|
||||||
'host',
|
'host',
|
||||||
));
|
);
|
||||||
|
$fields = qsprintf($conn, '%LC', $fields);
|
||||||
} else {
|
} else {
|
||||||
$fields = '*';
|
$fields = qsprintf($conn, '*');
|
||||||
}
|
}
|
||||||
|
|
||||||
$rows = queryfx_all(
|
$rows = queryfx_all(
|
||||||
$conn_r,
|
$conn,
|
||||||
'SELECT %Q FROM %T t %Q %Q %Q',
|
'SELECT %Q FROM %T t %Q %Q %Q',
|
||||||
$fields,
|
$fields,
|
||||||
$transcript->getTableName(),
|
$transcript->getTableName(),
|
||||||
$this->buildWhereClause($conn_r),
|
$this->buildWhereClause($conn),
|
||||||
$this->buildOrderClause($conn_r),
|
$this->buildOrderClause($conn),
|
||||||
$this->buildLimitClause($conn_r));
|
$this->buildLimitClause($conn));
|
||||||
|
|
||||||
$transcripts = $transcript->loadAllFromArray($rows);
|
$transcripts = $transcript->loadAllFromArray($rows);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue