Skip to content

Commit 533e4e1

Browse files
author
epriestley
committedNov 15, 2018
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
1 parent 8a8123c commit 533e4e1

File tree

6 files changed

+185
-17
lines changed

6 files changed

+185
-17
lines changed
 

‎bin/herald

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../scripts/setup/manage_herald.php

‎scripts/setup/manage_herald.php

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#!/usr/bin/env php
2+
<?php
3+
4+
$root = dirname(dirname(dirname(__FILE__)));
5+
require_once $root.'/scripts/init/init-script.php';
6+
7+
$args = new PhutilArgumentParser($argv);
8+
$args->setTagline(pht('manage Herald'));
9+
$args->setSynopsis(<<<EOSYNOPSIS
10+
**herald** __command__ [__options__]
11+
Manage and debug Herald.
12+
13+
EOSYNOPSIS
14+
);
15+
$args->parseStandardArguments();
16+
17+
$workflows = id(new PhutilClassMapQuery())
18+
->setAncestorClass('HeraldManagementWorkflow')
19+
->execute();
20+
$workflows[] = new PhutilHelpArgumentWorkflow();
21+
$args->parseWorkflows($workflows);

‎src/__phutil_library_map__.php

+4
Original file line numberDiff line numberDiff line change
@@ -1488,6 +1488,7 @@
14881488
'HeraldInvalidConditionException' => 'applications/herald/engine/exception/HeraldInvalidConditionException.php',
14891489
'HeraldMailableState' => 'applications/herald/state/HeraldMailableState.php',
14901490
'HeraldManageGlobalRulesCapability' => 'applications/herald/capability/HeraldManageGlobalRulesCapability.php',
1491+
'HeraldManagementWorkflow' => 'applications/herald/management/HeraldManagementWorkflow.php',
14911492
'HeraldManiphestTaskAdapter' => 'applications/maniphest/herald/HeraldManiphestTaskAdapter.php',
14921493
'HeraldNewController' => 'applications/herald/controller/HeraldNewController.php',
14931494
'HeraldNewObjectField' => 'applications/herald/field/HeraldNewObjectField.php',
@@ -1537,6 +1538,7 @@
15371538
'HeraldSupportActionGroup' => 'applications/herald/action/HeraldSupportActionGroup.php',
15381539
'HeraldSupportFieldGroup' => 'applications/herald/field/HeraldSupportFieldGroup.php',
15391540
'HeraldTestConsoleController' => 'applications/herald/controller/HeraldTestConsoleController.php',
1541+
'HeraldTestManagementWorkflow' => 'applications/herald/management/HeraldTestManagementWorkflow.php',
15401542
'HeraldTextFieldValue' => 'applications/herald/value/HeraldTextFieldValue.php',
15411543
'HeraldTokenizerFieldValue' => 'applications/herald/value/HeraldTokenizerFieldValue.php',
15421544
'HeraldTransactionQuery' => 'applications/herald/query/HeraldTransactionQuery.php',
@@ -6975,6 +6977,7 @@
69756977
'HeraldInvalidConditionException' => 'Exception',
69766978
'HeraldMailableState' => 'HeraldState',
69776979
'HeraldManageGlobalRulesCapability' => 'PhabricatorPolicyCapability',
6980+
'HeraldManagementWorkflow' => 'PhabricatorManagementWorkflow',
69786981
'HeraldManiphestTaskAdapter' => 'HeraldAdapter',
69796982
'HeraldNewController' => 'HeraldController',
69806983
'HeraldNewObjectField' => 'HeraldField',
@@ -7031,6 +7034,7 @@
70317034
'HeraldSupportActionGroup' => 'HeraldActionGroup',
70327035
'HeraldSupportFieldGroup' => 'HeraldFieldGroup',
70337036
'HeraldTestConsoleController' => 'HeraldController',
7037+
'HeraldTestManagementWorkflow' => 'HeraldManagementWorkflow',
70347038
'HeraldTextFieldValue' => 'HeraldFieldValue',
70357039
'HeraldTokenizerFieldValue' => 'HeraldFieldValue',
70367040
'HeraldTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?php
2+
3+
abstract class HeraldManagementWorkflow
4+
extends PhabricatorManagementWorkflow {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
<?php
2+
3+
final class HeraldTestManagementWorkflow
4+
extends HeraldManagementWorkflow {
5+
6+
protected function didConstruct() {
7+
$this
8+
->setName('test')
9+
->setExamples('**test** --object __object__ --type __type__')
10+
->setSynopsis(
11+
pht(
12+
'Test content rules for an object. Executes a dry run, like the '.
13+
'web UI test console.'))
14+
->setArguments(
15+
array(
16+
array(
17+
'name' => 'object',
18+
'param' => 'object',
19+
'help' => pht('Run rules on this object.'),
20+
),
21+
array(
22+
'name' => 'type',
23+
'param' => 'type',
24+
'help' => pht('Run rules for this content type.'),
25+
),
26+
));
27+
}
28+
29+
public function execute(PhutilArgumentParser $args) {
30+
$viewer = $this->getViewer();
31+
32+
$object_name = $args->getArg('object');
33+
if (!strlen($object_name)) {
34+
throw new PhutilArgumentUsageException(
35+
pht('Specify an object to test rules for with "--object".'));
36+
}
37+
38+
$objects = id(new PhabricatorObjectQuery())
39+
->setViewer($viewer)
40+
->withNames(array($object_name))
41+
->execute();
42+
if (!$objects) {
43+
throw new PhutilArgumentUsageException(
44+
pht(
45+
'Unable to load specified object ("%s").',
46+
$object_name));
47+
}
48+
$object = head($objects);
49+
50+
$adapters = HeraldAdapter::getAllAdapters();
51+
52+
$can_select = array();
53+
$display_adapters = array();
54+
foreach ($adapters as $key => $adapter) {
55+
if (!$adapter->isTestAdapterForObject($object)) {
56+
continue;
57+
}
58+
59+
if (!$adapter->isAvailableToUser($viewer)) {
60+
continue;
61+
}
62+
63+
$display_adapters[$key] = $adapter;
64+
65+
if ($adapter->canCreateTestAdapterForObject($object)) {
66+
$can_select[$key] = $adapter;
67+
}
68+
}
69+
70+
71+
$content_type = $args->getArg('type');
72+
if (!strlen($content_type)) {
73+
throw new PhutilArgumentUsageException(
74+
pht(
75+
'Specify a content type to run rules for. For this object, valid '.
76+
'content types are: %s.',
77+
implode(', ', array_keys($can_select))));
78+
}
79+
80+
if (!isset($can_select[$content_type])) {
81+
if (!isset($display_adapters[$content_type])) {
82+
throw new PhutilArgumentUsageException(
83+
pht(
84+
'Specify a content type to run rules for. The specified content '.
85+
'type ("%s") is not valid. For this object, valid content types '.
86+
'are: %s.',
87+
$content_type,
88+
implode(', ', array_keys($can_select))));
89+
} else {
90+
throw new PhutilArgumentUsageException(
91+
pht(
92+
'The specified content type ("%s") does not support dry runs. '.
93+
'Choose a testable content type. For this object, valid content '.
94+
'types are: %s.',
95+
$content_type,
96+
implode(', ', array_keys($can_select))));
97+
}
98+
}
99+
100+
$adapter = $can_select[$content_type]->newTestAdapter(
101+
$viewer,
102+
$object);
103+
104+
$content_source = $this->newContentSource();
105+
106+
$adapter
107+
->setContentSource($content_source)
108+
->setIsNewObject(false)
109+
->setViewer($viewer);
110+
111+
$rules = id(new HeraldRuleQuery())
112+
->setViewer($viewer)
113+
->withContentTypes(array($adapter->getAdapterContentType()))
114+
->withDisabled(false)
115+
->needConditionsAndActions(true)
116+
->needAppliedToPHIDs(array($object->getPHID()))
117+
->needValidateAuthors(true)
118+
->execute();
119+
120+
$engine = id(new HeraldEngine())
121+
->setDryRun(true);
122+
123+
$effects = $engine->applyRules($rules, $adapter);
124+
$engine->applyEffects($effects, $adapter, $rules);
125+
126+
$xscript = $engine->getTranscript();
127+
128+
$uri = '/herald/transcript/'.$xscript->getID().'/';
129+
$uri = PhabricatorEnv::getProductionURI($uri);
130+
131+
echo tsprintf(
132+
"%s\n\n __%s__\n\n",
133+
pht('Test run complete. Transcript:'),
134+
$uri);
135+
136+
return 0;
137+
}
138+
139+
}

‎src/applications/herald/query/HeraldTranscriptQuery.php

+16-17
Original file line numberDiff line numberDiff line change
@@ -30,36 +30,35 @@ public function needPartialRecords($need_partial) {
3030

3131
protected function loadPage() {
3232
$transcript = new HeraldTranscript();
33-
$conn_r = $transcript->establishConnection('r');
33+
$conn = $transcript->establishConnection('r');
3434

3535
// NOTE: Transcripts include a potentially enormous amount of serialized
3636
// data, so we're loading only some of the fields here if the caller asked
3737
// for partial records.
3838

3939
if ($this->needPartialRecords) {
40-
$fields = implode(
41-
', ',
42-
array(
43-
'id',
44-
'phid',
45-
'objectPHID',
46-
'time',
47-
'duration',
48-
'dryRun',
49-
'host',
50-
));
40+
$fields = array(
41+
'id',
42+
'phid',
43+
'objectPHID',
44+
'time',
45+
'duration',
46+
'dryRun',
47+
'host',
48+
);
49+
$fields = qsprintf($conn, '%LC', $fields);
5150
} else {
52-
$fields = '*';
51+
$fields = qsprintf($conn, '*');
5352
}
5453

5554
$rows = queryfx_all(
56-
$conn_r,
55+
$conn,
5756
'SELECT %Q FROM %T t %Q %Q %Q',
5857
$fields,
5958
$transcript->getTableName(),
60-
$this->buildWhereClause($conn_r),
61-
$this->buildOrderClause($conn_r),
62-
$this->buildLimitClause($conn_r));
59+
$this->buildWhereClause($conn),
60+
$this->buildOrderClause($conn),
61+
$this->buildLimitClause($conn));
6362

6463
$transcripts = $transcript->loadAllFromArray($rows);
6564

0 commit comments

Comments
 (0)
Failed to load comments.