mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-25 08:12:40 +01:00
Add an example event listener, improve documentation, and add a commit discovery event
Summary: Improve documentation around Phabricator events. Test Plan: Generated and read documentation. Ran test script. Reviewers: btrahan, jungejason Reviewed By: jungejason CC: aran Maniphest Tasks: T1092 Differential Revision: https://secure.phabricator.com/D2917
This commit is contained in:
parent
61b79b5359
commit
ddf67fce58
8 changed files with 322 additions and 10 deletions
57
scripts/util/emit_test_event.php
Executable file
57
scripts/util/emit_test_event.php
Executable file
|
@ -0,0 +1,57 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
$root = dirname(dirname(dirname(__FILE__)));
|
||||
require_once $root.'/scripts/__init_script__.php';
|
||||
|
||||
$args = new PhutilArgumentParser($argv);
|
||||
$args->setTagline('emit a test event');
|
||||
$args->setSynopsis(<<<EOHELP
|
||||
**emit_test_event.php** [--listen listener] ...
|
||||
Emit a test event after installing any specified __listener__s.
|
||||
EOHELP
|
||||
);
|
||||
$args->parseStandardArguments();
|
||||
$args->parse(
|
||||
array(
|
||||
array(
|
||||
'name' => 'listen',
|
||||
'param' => 'listener',
|
||||
'repeat' => true,
|
||||
),
|
||||
));
|
||||
|
||||
$console = PhutilConsole::getConsole();
|
||||
foreach ($args->getArg('listen') as $listener) {
|
||||
$console->writeOut("Installing '%s'...\n", $listener);
|
||||
newv($listener, array())->register();
|
||||
}
|
||||
|
||||
|
||||
$console->writeOut("Emitting event...\n");
|
||||
|
||||
PhutilEventEngine::dispatchEvent(
|
||||
new PhabricatorEvent(
|
||||
PhabricatorEventType::TYPE_TEST_DIDRUNTEST,
|
||||
array(
|
||||
'time' => time(),
|
||||
)));
|
||||
|
||||
$console->writeOut("Done.\n");
|
||||
exit(0);
|
|
@ -632,6 +632,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorEvent' => 'infrastructure/events/PhabricatorEvent.php',
|
||||
'PhabricatorEventEngine' => 'infrastructure/events/PhabricatorEventEngine.php',
|
||||
'PhabricatorEventType' => 'infrastructure/events/constant/PhabricatorEventType.php',
|
||||
'PhabricatorExampleEventListener' => 'infrastructure/events/PhabricatorExampleEventListener.php',
|
||||
'PhabricatorFeedBuilder' => 'applications/feed/builder/PhabricatorFeedBuilder.php',
|
||||
'PhabricatorFeedConstants' => 'applications/feed/constants/PhabricatorFeedConstants.php',
|
||||
'PhabricatorFeedController' => 'applications/feed/controller/PhabricatorFeedController.php',
|
||||
|
@ -1647,9 +1648,12 @@ phutil_register_library_map(array(
|
|||
'PhabricatorErrorExample' => 'PhabricatorUIExample',
|
||||
'PhabricatorEvent' => 'PhutilEvent',
|
||||
'PhabricatorEventType' => 'PhutilEventType',
|
||||
'PhabricatorExampleEventListener' => 'PhutilEventListener',
|
||||
'PhabricatorFeedController' => 'PhabricatorController',
|
||||
'PhabricatorFeedDAO' => 'PhabricatorLiskDAO',
|
||||
'PhabricatorFeedPublicStreamController' => 'PhabricatorFeedController',
|
||||
'PhabricatorFeedQuery' => 'PhabricatorIDPagedPolicyQuery',
|
||||
'PhabricatorFeedStory' => 'PhabricatorPolicyInterface',
|
||||
'PhabricatorFeedStoryAggregate' => 'PhabricatorFeedStory',
|
||||
'PhabricatorFeedStoryAudit' => 'PhabricatorFeedStory',
|
||||
'PhabricatorFeedStoryCommit' => 'PhabricatorFeedStory',
|
||||
|
|
|
@ -374,6 +374,15 @@ final class PhabricatorRepositoryPullLocalDaemon
|
|||
}
|
||||
|
||||
$this->setCache($repository, $commit_identifier);
|
||||
|
||||
PhutilEventEngine::dispatchEvent(
|
||||
new PhabricatorEvent(
|
||||
PhabricatorEventType::TYPE_DIFFUSION_DIDDISCOVERCOMMIT,
|
||||
array(
|
||||
'repository' => $repository,
|
||||
'commit' => $commit,
|
||||
)));
|
||||
|
||||
} catch (AphrontQueryDuplicateKeyException $ex) {
|
||||
$commit->killTransaction();
|
||||
// Ignore. This can happen because we discover the same new commit
|
||||
|
|
|
@ -9,12 +9,68 @@ Phabricator allows you to install custom runtime event listeners which can react
|
|||
to certain things happening (like a Maniphest Task being edited) and run custom
|
||||
code to perform logging, synchronize with other systems, or modify workflows.
|
||||
|
||||
NOTE: This feature is new and experimental, so few events are available and
|
||||
things might not be completely stable.
|
||||
These listeners are PHP classes which you install beside Phabricator, and which
|
||||
Phabricator loads at runtime and runs in-process. They are the most direct and
|
||||
powerful way to respond to events.
|
||||
|
||||
= Installing Event Listeners =
|
||||
|
||||
To install event listeners, follow these steps:
|
||||
|
||||
- Write a listener class which extends @{class:PhutilEventListener}.
|
||||
- Add it to a libphutil library, or create a new library (for instructions,
|
||||
see @{article:libphutil Libraries User Guide}.
|
||||
- Configure Phabricator to load the library by adding it to `load-libraries`
|
||||
in the Phabricator config.
|
||||
- Configure Phabricator to install the event listener by adding the class
|
||||
name to `events.listeners` in the Phabricator config.
|
||||
|
||||
You can verify your listener is registered in the "Events" tab of DarkConsole.
|
||||
It should appear at the top under "Registered Event Listeners". You can also
|
||||
see any events the page emitted there. For details on DarkConsole, see
|
||||
@{article:Using DarkConsole}.
|
||||
|
||||
= Example Listener =
|
||||
|
||||
Phabricator includes an example event listener,
|
||||
@{class:PhabricatorExampleEventListener}, which may be useful as a starting
|
||||
point in developing your own listeners. This listener listens for a test
|
||||
event that is emitted by the script `scripts/util/emit_test_event.php`.
|
||||
|
||||
If you run this script normally, it should output something like this:
|
||||
|
||||
$ ./scripts/util/emit_test_event.php
|
||||
Emitting event...
|
||||
Done.
|
||||
|
||||
This is because there are no listeners for the event, so nothing reacts to it
|
||||
when it is emitted. You can add the example listener by either adding it to
|
||||
your `events.listeners` configuration or with the `--listen` command-line flag:
|
||||
|
||||
$ ./scripts/util/emit_test_event.php --listen PhabricatorExampleEventListener
|
||||
Installing 'PhabricatorExampleEventListener'...
|
||||
Emitting event...
|
||||
PhabricatorExampleEventListener got test event at 1341344566
|
||||
Done.
|
||||
|
||||
This time, the listener was installed and had its callback invoked when the
|
||||
test event was emitted.
|
||||
|
||||
= Available Events =
|
||||
|
||||
== PhabricatorEventType::TYPE_MANIPHEST_WILLEDITTASK ==
|
||||
You can find a list of all Phabricator events in @{class:PhabricatorEventType}.
|
||||
|
||||
== All Events ==
|
||||
|
||||
The special constant `PhutilEventType::TYPE_ALL` will let you listen for all
|
||||
events. Normally, you want to listen only to specific events, but if you're
|
||||
writing a generic handler you can listen to all events with this constant
|
||||
rather than by enumerating each event.
|
||||
|
||||
== Maniphest: Will Edit Task ==
|
||||
|
||||
The constant for this event is
|
||||
`PhabricatorEventType::TYPE_MANIPHEST_WILLEDITTASK`.
|
||||
|
||||
This event is dispatched before a task is edited, and allows you to respond to
|
||||
or alter the edit. Data available on this event:
|
||||
|
@ -26,14 +82,41 @@ or alter the edit. Data available on this event:
|
|||
- ##mail## If this edit originates from email, the
|
||||
@{class:PhabricatorMetaMTAReceivedMail} object.
|
||||
|
||||
== PhabricatorEventType::TYPE_DIFFERENTIAL_WILLSENDMAIL ==
|
||||
This is similar to the next event (did edit task) but occurs before the edit
|
||||
begins.
|
||||
|
||||
== Maniphest: Did Edit Task ==
|
||||
|
||||
The constant for this event is
|
||||
`PhabricatorEventType::TYPE_MANIPHEST_DIDEDITTASK`.
|
||||
|
||||
This event is dispatched after a task is edited, and allows you to react to the
|
||||
edit. Data available on this event:
|
||||
|
||||
- ##task## The @{class:ManiphestTask} that was edited.
|
||||
- ##transactions## The list of edits (objects of class
|
||||
@{class:ManiphestTransaction}) that were applied.
|
||||
- ##new## A boolean indicating if this task was newly created.
|
||||
- ##mail## If this edit originates from email, the
|
||||
@{class:PhabricatorMetaMTAReceivedMail} object.
|
||||
|
||||
This is similar to the previous event (will edit task) but occurs after the
|
||||
edit completes.
|
||||
|
||||
== Differential: Will Send Mail ==
|
||||
|
||||
The constant for this event is
|
||||
`PhabricatorEventType::TYPE_DIFFERENTIAL_WILLSENDMAIL`
|
||||
|
||||
This event is dispatched before Differential sends an email, and allows you to
|
||||
edit the message that will be sent. Data available on this event:
|
||||
|
||||
- ##mail## The @{class:PhabricatorMetaMTAMail} being edited.
|
||||
|
||||
== PhabricatorEventType::TYPE_DIFFERENTIAL_WILLMARKGENERATED ==
|
||||
== Differential: Will Mark Generated ==
|
||||
|
||||
The constant for this event is
|
||||
`PhabricatorEventType::TYPE_DIFFERENTIAL_WILLMARKGENERATED`.
|
||||
|
||||
This event is dispatched before Differential decides if a file is generated (and
|
||||
doesn't need to be reviewed) or not. Data available on this event:
|
||||
|
@ -41,3 +124,92 @@ doesn't need to be reviewed) or not. Data available on this event:
|
|||
- ##corpus## Body of the file.
|
||||
- ##is_generated## Boolean indicating if this file should be treated as
|
||||
generated.
|
||||
|
||||
== Diffusion: Did Discover Commit ==
|
||||
|
||||
The constant for this event is
|
||||
`PhabricatorEventType::TYPE_DIFFUSION_DIDDISCOVERCOMMIT`.
|
||||
|
||||
This event is dispatched when the daemons discover a commit for the first time.
|
||||
This event happens very early in the pipeline, and not all commit information
|
||||
will be available yet. Data available on this event:
|
||||
|
||||
- `commit` The @{class:PhabricatorRepositoryCommit} that was discovered.
|
||||
- `repository` The @{class:PhabricatorRepository} the commit was discovered
|
||||
in.
|
||||
|
||||
== Edge: Will Edit Edges ==
|
||||
|
||||
NOTE: Edge events are low-level events deep in the core. It is more difficult to
|
||||
correct implement listeners for these events than for higher-level events.
|
||||
|
||||
The constant for this event is
|
||||
`PhabricatorEventType::TYPE_EDGE_WILLEDITEDGES`.
|
||||
|
||||
This event is dispatched before @{class:PhabricatorEdgeEditor} makes an edge
|
||||
edit.
|
||||
|
||||
- `id` An identifier for this edit operation.
|
||||
- `add` A list of dictionaries, each representing a new edge.
|
||||
- `rem` A list of dictionaries, each representing a removed edge.
|
||||
|
||||
This is similar to the next event (did edit edges) but occurs before the
|
||||
edit begins.
|
||||
|
||||
== Edge: Did Edit Edges ==
|
||||
|
||||
The constant for this event is
|
||||
`PhabricatorEventType::TYPE_EDGE_DIDEDITEDGES`.
|
||||
|
||||
This event is dispatched after @{class:PhabricatorEdgeEditor} makes an edge
|
||||
edit, but before it commits the transactions. Data available on this event:
|
||||
|
||||
- `id` An identifier for this edit operation. This is the same ID as
|
||||
the one included in the corresponding "will edit edges" event.
|
||||
- `add` A list of dictionaries, each representing a new edge.
|
||||
- `rem` A list of dictionaries, each representing a removed edge.
|
||||
|
||||
This is similar to the previous event (will edit edges) but occurs after the
|
||||
edit completes.
|
||||
|
||||
== Test: Did Run Test ==
|
||||
|
||||
The constant for this event is
|
||||
`PhabricatorEventType::TYPE_TEST_DIDRUNTEST`.
|
||||
|
||||
This is a test event for testing event listeners. See above for details.
|
||||
|
||||
= Debugging Listeners =
|
||||
|
||||
If you're having problems with your listener, try these steps:
|
||||
|
||||
- If you're getting an error about Phabricator being unable to find the
|
||||
listener class, make sure you've added it to a libphutil library and
|
||||
configured Phabricator to load the library with `load-libraries`.
|
||||
- Make sure the listener is registered. It should appear in the "Events" tab
|
||||
of DarkConsole. If it's not there, you may have forgotten to add it to
|
||||
`events.listeners`.
|
||||
- Make sure it calls `listen()` on the right events in its `register()`
|
||||
method. If you don't listen for the events you're interested in, you
|
||||
won't get a callback.
|
||||
- Make sure the events you're listening for are actually happening. If they
|
||||
occur on a normal page they should appear in the "Events" tab of
|
||||
DarkConsole. If they occur on a POST, you could add a `phlog()`
|
||||
to the source code near the event and check your error log to make sure the
|
||||
code ran.
|
||||
- You can check if your callback is getting invoked by adding `phlog()` with
|
||||
a message and checking the error log.
|
||||
- You can try listening to `PhutilEventType::TYPE_ALL` instead of a specific
|
||||
event type to get all events, to narrow down whether problems are caused
|
||||
by the types of events you're listening to.
|
||||
- You can edit the `emit_test_event.php` script to emit other types of
|
||||
events instead, to test that your listener reacts to them properly. You
|
||||
might have to use fake data, but this gives you an easy way to test the
|
||||
at least the basics.
|
||||
|
||||
= Next Steps =
|
||||
|
||||
Continue by:
|
||||
|
||||
- taking a look at @{class:PhabricatorExampleEventListener}; or
|
||||
- building a library with @{article:@{article:libphutil Libraries User Guide}.
|
|
@ -16,6 +16,10 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @group events
|
||||
*/
|
||||
final class PhabricatorEvent extends PhutilEvent {
|
||||
|
||||
private $user;
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @group events
|
||||
*/
|
||||
final class PhabricatorEventEngine {
|
||||
|
||||
public static function initialize() {
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* Copyright 2012 Facebook, Inc.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Example event listener. For details about installing Phabricator event hooks,
|
||||
* refer to @{article:Events User Guide: Installing Event Listeners}.
|
||||
*
|
||||
* @group events
|
||||
*/
|
||||
final class PhabricatorExampleEventListener extends PhutilEventListener {
|
||||
|
||||
public function register() {
|
||||
// When your listener is installed, its register() method will be called.
|
||||
// You should listen() to any events you are interested in here.
|
||||
|
||||
$this->listen(PhabricatorEventType::TYPE_TEST_DIDRUNTEST);
|
||||
}
|
||||
|
||||
public function handleEvent(PhutilEvent $event) {
|
||||
// When an event you have called listen() for in your register() method
|
||||
// occurs, this method will be invoked. You should respond to the event.
|
||||
|
||||
// In this case, we just echo a message out so the event test script will
|
||||
// do something visible.
|
||||
|
||||
$console = PhutilConsole::getConsole();
|
||||
$console->writeOut(
|
||||
"PhabricatorExampleEventListener got test event at %d\n",
|
||||
$event->getValue('time'));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -16,14 +16,25 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* For detailed explanations of these events, see
|
||||
* @{article:Events User Guide: Installing Event Listeners}.
|
||||
*
|
||||
* @group events
|
||||
*/
|
||||
final class PhabricatorEventType extends PhutilEventType {
|
||||
|
||||
const TYPE_MANIPHEST_WILLEDITTASK = 'maniphest.willEditTask';
|
||||
const TYPE_MANIPHEST_DIDEDITTASK = 'maniphest.didEditTask';
|
||||
const TYPE_DIFFERENTIAL_WILLSENDMAIL = 'differential.willSendMail';
|
||||
const TYPE_MANIPHEST_WILLEDITTASK = 'maniphest.willEditTask';
|
||||
const TYPE_MANIPHEST_DIDEDITTASK = 'maniphest.didEditTask';
|
||||
|
||||
const TYPE_DIFFERENTIAL_WILLSENDMAIL = 'differential.willSendMail';
|
||||
const TYPE_DIFFERENTIAL_WILLMARKGENERATED = 'differential.willMarkGenerated';
|
||||
|
||||
const TYPE_EDGE_WILLEDITEDGES = 'edge.willEditEdges';
|
||||
const TYPE_EDGE_DIDEDITEDGES = 'edge.didEditEdges';
|
||||
const TYPE_DIFFUSION_DIDDISCOVERCOMMIT = 'diffusion.didDiscoverCommit';
|
||||
|
||||
const TYPE_EDGE_WILLEDITEDGES = 'edge.willEditEdges';
|
||||
const TYPE_EDGE_DIDEDITEDGES = 'edge.didEditEdges';
|
||||
|
||||
const TYPE_TEST_DIDRUNTEST = 'test.didRunTest';
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue