diff --git a/src/Composer/EventDispatcher/EventDispatcher.php b/src/Composer/EventDispatcher/EventDispatcher.php
index ee02381e5..d5bdb4c97 100644
--- a/src/Composer/EventDispatcher/EventDispatcher.php
+++ b/src/Composer/EventDispatcher/EventDispatcher.php
@@ -196,7 +196,9 @@ class EventDispatcher
}
try {
- $return = $this->dispatch($scriptName, new Script\Event($scriptName, $event->getComposer(), $event->getIO(), $event->isDevMode(), $args, $flags));
+ $scriptEvent = new Script\Event($scriptName, $event->getComposer(), $event->getIO(), $event->isDevMode(), $args, $flags);
+ $scriptEvent->setOriginatingEvent($event);
+ $return = $this->dispatch($scriptName, $scriptEvent);
} catch (ScriptExecutionException $e) {
$this->io->writeError(sprintf('Script %s was called via %s', $callable, $event->getName()), true, IOInterface::QUIET);
throw $e;
diff --git a/src/Composer/Script/Event.php b/src/Composer/Script/Event.php
index 138f43c1a..5fab172bf 100644
--- a/src/Composer/Script/Event.php
+++ b/src/Composer/Script/Event.php
@@ -39,6 +39,11 @@ class Event extends BaseEvent
*/
private $devMode;
+ /**
+ * @var BaseEvent
+ */
+ private $originatingEvent;
+
/**
* Constructor.
*
@@ -55,6 +60,7 @@ class Event extends BaseEvent
$this->composer = $composer;
$this->io = $io;
$this->devMode = $devMode;
+ $this->originatingEvent = null;
}
/**
@@ -86,4 +92,42 @@ class Event extends BaseEvent
{
return $this->devMode;
}
+
+ /**
+ * Set the originating event.
+ *
+ * @return \Composer\EventDispatcher\Event|null
+ */
+ public function getOriginatingEvent()
+ {
+ return $this->originatingEvent;
+ }
+
+ /**
+ * Set the originating event.
+ *
+ * @param \Composer\EventDispatcher\Event $event
+ * @return $this
+ */
+ public function setOriginatingEvent(BaseEvent $event)
+ {
+ $this->originatingEvent = $this->calculateOriginatingEvent($event);
+
+ return $this;
+ }
+
+ /**
+ * Returns the upper-most event in chain.
+ *
+ * @param \Composer\EventDispatcher\Event $event
+ * @return \Composer\EventDispatcher\Event
+ */
+ private function calculateOriginatingEvent(BaseEvent $event)
+ {
+ if ($event instanceof Event && $event->getOriginatingEvent()) {
+ return $this->calculateOriginatingEvent($event->getOriginatingEvent());
+ }
+
+ return $event;
+ }
}
diff --git a/tests/Composer/Test/Script/EventTest.php b/tests/Composer/Test/Script/EventTest.php
new file mode 100644
index 000000000..b7c8cd9ff
--- /dev/null
+++ b/tests/Composer/Test/Script/EventTest.php
@@ -0,0 +1,80 @@
+
+ * Jordi Boggiano
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Composer\Test\Script;
+
+use Composer\Composer;
+use Composer\Config;
+use Composer\Script\Event;
+use Composer\Test\TestCase;
+
+class EventTest extends TestCase
+{
+ public function testEventSetsOriginatingEvent()
+ {
+ $io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
+ $composer = $this->createComposerInstance();
+
+ $originatingEvent = new \Composer\EventDispatcher\Event('originatingEvent');
+
+ $scriptEvent = new Event('test', $composer, $io, true);
+
+ $this->assertNull(
+ $scriptEvent->getOriginatingEvent(),
+ 'originatingEvent is initialized as null'
+ );
+
+ $scriptEvent->setOriginatingEvent($originatingEvent);
+
+ $this->assertSame(
+ $originatingEvent,
+ $scriptEvent->getOriginatingEvent(),
+ 'getOriginatingEvent() SHOULD return test event'
+ );
+ }
+
+ public function testEventCalculatesNestedOriginatingEvent()
+ {
+ $io = $this->getMockBuilder('Composer\IO\IOInterface')->getMock();
+ $composer = $this->createComposerInstance();
+
+ $originatingEvent = new \Composer\EventDispatcher\Event('upperOriginatingEvent');
+ $intermediateEvent = new Event('intermediate', $composer, $io, true);
+ $intermediateEvent->setOriginatingEvent($originatingEvent);
+
+ $scriptEvent = new Event('test', $composer, $io, true);
+ $scriptEvent->setOriginatingEvent($intermediateEvent);
+
+ $this->assertNotSame(
+ $intermediateEvent,
+ $scriptEvent->getOriginatingEvent(),
+ 'getOriginatingEvent() SHOULD NOT return intermediate events'
+ );
+
+ $this->assertSame(
+ $originatingEvent,
+ $scriptEvent->getOriginatingEvent(),
+ 'getOriginatingEvent() SHOULD return upper-most event'
+ );
+ }
+
+ private function createComposerInstance()
+ {
+ $composer = new Composer;
+ $config = new Config;
+ $composer->setConfig($config);
+ $package = $this->getMockBuilder('Composer\Package\RootPackageInterface')->getMock();
+ $composer->setPackage($package);
+
+ return $composer;
+ }
+}