diff --git a/src/Command/Work.php b/src/Command/Work.php index d5a0a26..b74df96 100644 --- a/src/Command/Work.php +++ b/src/Command/Work.php @@ -3,11 +3,18 @@ namespace Innmind\LabStation\Command; -use Innmind\LabStation\Monitor; +use Innmind\LabStation\{ + Monitor, + Triggers, +}; use Innmind\CLI\{ Command, Console, }; +use Innmind\Immutable\{ + Str, + Set, +}; final class Work implements Command { @@ -20,7 +27,23 @@ public function __construct(Monitor $monitor) public function __invoke(Console $console): Console { - return ($this->monitor)($console); + $triggers = $console + ->options() + ->maybe('triggers') + ->map(Str::of(...)) + ->map( + static fn($triggers) => $triggers + ->split(',') + ->map(static fn($trigger) => $trigger->trim()->toString()) + ->filter(Triggers::allow(...)) + ->map(Triggers::of(...)), + ) + ->match( + static fn($triggers) => $triggers->toList(), + static fn() => Triggers::cases(), + ); + + return ($this->monitor)($console, Set::of(...$triggers)); } /** @@ -28,6 +51,12 @@ public function __invoke(Console $console): Console */ public function usage(): string { - return 'work --silent --keep-output'; + return <<agents = $agents; } - public function __invoke(Console $console): Console + /** + * @param Set $triggers + */ + public function __invoke(Console $console, Set $triggers): Console { $project = $console->workingDirectory(); $manager = $this->manager; @@ -66,7 +70,7 @@ public function __invoke(Console $console): Console return $manager ->start() ->maybe() - ->flatMap(fn($agents) => $this->start($agents, $console)) + ->flatMap(fn($agents) => $this->start($agents, $console, $triggers)) ->match( static fn($console) => $console ->error(Str::of("Terminated\n")) @@ -78,21 +82,26 @@ public function __invoke(Console $console): Console } /** + * @param Set $triggers + * * @return Maybe */ - private function start(Running $agents, Console $console): Maybe - { - $console = ($this->trigger)(new Activity(Type::start), $console); + private function start( + Running $agents, + Console $console, + Set $triggers, + ): Maybe { + $console = ($this->trigger)(new Activity(Type::start), $console, $triggers); $server = $this->ipc->listen($this->name); /** @psalm-suppress InvalidArgument */ return $server( $console, - function($message, $continuation, Console $console) { + function($message, $continuation, Console $console) use ($triggers) { $activity = $this->protocol->decode($message); $this->iteration->start(); - $console = ($this->trigger)($activity, $console); + $console = ($this->trigger)($activity, $console, $triggers); $console = $this->iteration->end($console); return $continuation->continue($console); diff --git a/src/Trigger.php b/src/Trigger.php index 69183db..7b246d3 100644 --- a/src/Trigger.php +++ b/src/Trigger.php @@ -4,8 +4,16 @@ namespace Innmind\LabStation; use Innmind\CLI\Console; +use Innmind\Immutable\Set; interface Trigger { - public function __invoke(Activity $activity, Console $console): Console; + /** + * @param Set $triggers + */ + public function __invoke( + Activity $activity, + Console $console, + Set $triggers, + ): Console; } diff --git a/src/Trigger/All.php b/src/Trigger/All.php index 1d56388..2ef6f6c 100644 --- a/src/Trigger/All.php +++ b/src/Trigger/All.php @@ -8,6 +8,7 @@ Activity, }; use Innmind\CLI\Console; +use Innmind\Immutable\Set; final class All implements Trigger { @@ -22,10 +23,13 @@ public function __construct(Trigger ...$triggers) $this->triggers = $triggers; } - public function __invoke(Activity $activity, Console $console): Console - { + public function __invoke( + Activity $activity, + Console $console, + Set $triggers, + ): Console { foreach ($this->triggers as $trigger) { - $console = $trigger($activity, $console); + $console = $trigger($activity, $console, $triggers); } return $console; diff --git a/src/Trigger/CodingStandard.php b/src/Trigger/CodingStandard.php index dc0ead7..1c5982b 100644 --- a/src/Trigger/CodingStandard.php +++ b/src/Trigger/CodingStandard.php @@ -5,6 +5,7 @@ use Innmind\LabStation\{ Trigger, + Triggers, Activity, Activity\Type, Iteration, @@ -17,7 +18,10 @@ }; use Innmind\OperatingSystem\Filesystem; use Innmind\Filesystem\Name; -use Innmind\Immutable\Map; +use Innmind\Immutable\{ + Map, + Set, +}; final class CodingStandard implements Trigger { @@ -35,8 +39,15 @@ public function __construct( $this->iteration = $iteration; } - public function __invoke(Activity $activity, Console $console): Console - { + public function __invoke( + Activity $activity, + Console $console, + Set $triggers, + ): Console { + if (!$triggers->contains(Triggers::codingStandard)) { + return $console; + } + return match ($activity->type()) { Type::sourcesModified => $this->attempt($console), Type::testsModified => $this->attempt($console), diff --git a/src/Trigger/ComposerUpdate.php b/src/Trigger/ComposerUpdate.php index 2f902d4..a558be6 100644 --- a/src/Trigger/ComposerUpdate.php +++ b/src/Trigger/ComposerUpdate.php @@ -5,6 +5,7 @@ use Innmind\LabStation\{ Trigger, + Triggers, Activity, Activity\Type, }; @@ -20,6 +21,7 @@ use Innmind\Immutable\{ Map, Str, + Set, }; final class ComposerUpdate implements Trigger @@ -31,8 +33,15 @@ public function __construct(Processes $processes) $this->processes = $processes; } - public function __invoke(Activity $activity, Console $console): Console - { + public function __invoke( + Activity $activity, + Console $console, + Set $triggers, + ): Console { + if (!$triggers->contains(Triggers::composerUpdate)) { + return $console; + } + return match ($activity->type()) { Type::start => $this->ask($console), default => $console, diff --git a/src/Trigger/DockerCompose.php b/src/Trigger/DockerCompose.php index 7a0b09a..23a274b 100644 --- a/src/Trigger/DockerCompose.php +++ b/src/Trigger/DockerCompose.php @@ -5,6 +5,7 @@ use Innmind\LabStation\{ Trigger, + Triggers, Activity, Activity\Type, }; @@ -18,6 +19,7 @@ use Innmind\Immutable\{ Map, Str, + Set, }; final class DockerCompose implements Trigger @@ -31,8 +33,15 @@ public function __construct(Filesystem $filesystem, Processes $processes) $this->processes = $processes; } - public function __invoke(Activity $activity, Console $console): Console - { + public function __invoke( + Activity $activity, + Console $console, + Set $triggers, + ): Console { + if (!$triggers->contains(Triggers::dockerCompose)) { + return $console; + } + return match ($activity->type()) { Type::start => $this->attempt($console), default => $console, diff --git a/src/Trigger/Psalm.php b/src/Trigger/Psalm.php index b2f01c1..d932439 100644 --- a/src/Trigger/Psalm.php +++ b/src/Trigger/Psalm.php @@ -5,6 +5,7 @@ use Innmind\LabStation\{ Trigger, + Triggers, Activity, Activity\Type, Iteration, @@ -17,7 +18,10 @@ }; use Innmind\OperatingSystem\Filesystem; use Innmind\Filesystem\Name; -use Innmind\Immutable\Map; +use Innmind\Immutable\{ + Map, + Set, +}; final class Psalm implements Trigger { @@ -35,8 +39,15 @@ public function __construct( $this->iteration = $iteration; } - public function __invoke(Activity $activity, Console $console): Console - { + public function __invoke( + Activity $activity, + Console $console, + Set $triggers, + ): Console { + if (!$triggers->contains(Triggers::psalm)) { + return $console; + } + return match ($activity->type()) { Type::sourcesModified => $this->ettempt($console), Type::testsModified => $this->ettempt($console), diff --git a/src/Trigger/Tests.php b/src/Trigger/Tests.php index 05be29e..bd3c74e 100644 --- a/src/Trigger/Tests.php +++ b/src/Trigger/Tests.php @@ -5,6 +5,7 @@ use Innmind\LabStation\{ Trigger, + Triggers, Activity, Activity\Type, Iteration, @@ -17,7 +18,10 @@ Process\Output, }; use Innmind\Filesystem\Name; -use Innmind\Immutable\Map; +use Innmind\Immutable\{ + Map, + Set, +}; final class Tests implements Trigger { @@ -35,8 +39,15 @@ public function __construct( $this->iteration = $iteration; } - public function __invoke(Activity $activity, Console $console): Console - { + public function __invoke( + Activity $activity, + Console $console, + Set $triggers, + ): Console { + if (!$triggers->contains(Triggers::tests)) { + return $console; + } + return match ($activity->type()) { Type::sourcesModified => $this->attempt($console), Type::testsModified => $this->attempt($console), diff --git a/src/Triggers.php b/src/Triggers.php new file mode 100644 index 0000000..c1000cb --- /dev/null +++ b/src/Triggers.php @@ -0,0 +1,45 @@ + self::codingStandard, + 'composer', 'composerUpdate' => self::composerUpdate, + 'docker', 'dockerCompose' => self::dockerCompose, + 'psalm' => self::psalm, + 'tests', 'phpunit' => self::tests, + }; + } + + /** + * @psalm-pure + */ + public static function allow(string $value): bool + { + return match ($value) { + 'cs', 'codingStandard' => true, + 'composer', 'composerUpdate' => true, + 'docker', 'dockerCompose' => true, + 'psalm' => true, + 'tests', 'phpunit' => true, + default => false, + }; + } +} diff --git a/tests/Command/WorkTest.php b/tests/Command/WorkTest.php index 3a6282e..5fabcd1 100644 --- a/tests/Command/WorkTest.php +++ b/tests/Command/WorkTest.php @@ -54,7 +54,13 @@ public function testInterface() public function testUsage() { $this->assertSame( - 'work --silent --keep-output', + <<createMock(Protocol::class), diff --git a/tests/Trigger/AllTest.php b/tests/Trigger/AllTest.php index b9e0de8..2452e7b 100644 --- a/tests/Trigger/AllTest.php +++ b/tests/Trigger/AllTest.php @@ -15,6 +15,7 @@ Command\Arguments, Command\Options, }; +use Innmind\Immutable\Set; use PHPUnit\Framework\TestCase; class AllTest extends TestCase @@ -31,6 +32,7 @@ public function testTriggerAllSubTriggers() $trigger2 = $this->createMock(Trigger::class), $trigger3 = $this->createMock(Trigger::class), ); + $triggers = Set::of(); $activity = new Activity(Type::start); $console = Console::of( $this->createMock(Environment::class), @@ -40,19 +42,19 @@ public function testTriggerAllSubTriggers() $trigger1 ->expects($this->once()) ->method('__invoke') - ->with($activity, $console) + ->with($activity, $console, $triggers) ->willReturn($console); $trigger2 ->expects($this->once()) ->method('__invoke') - ->with($activity, $console) + ->with($activity, $console, $triggers) ->willReturn($console); $trigger3 ->expects($this->once()) ->method('__invoke') - ->with($activity, $console) + ->with($activity, $console, $triggers) ->willReturn($console); - $this->assertSame($console, $trigger($activity, $console)); + $this->assertSame($console, $trigger($activity, $console, $triggers)); } } diff --git a/tests/Trigger/CodingStandardTest.php b/tests/Trigger/CodingStandardTest.php index 05cc657..ef54b5f 100644 --- a/tests/Trigger/CodingStandardTest.php +++ b/tests/Trigger/CodingStandardTest.php @@ -6,6 +6,7 @@ use Innmind\LabStation\{ Trigger\CodingStandard, Trigger, + Triggers, Activity, Activity\Type, Iteration, @@ -36,6 +37,7 @@ Either, SideEffect, Map, + Set, }; use PHPUnit\Framework\TestCase; @@ -72,6 +74,7 @@ public function testDoNothingWhenNotOfExpectedType() $this->assertSame($console, $trigger( new Activity(Type::start), $console, + Set::of(Triggers::codingStandard), )); } @@ -104,9 +107,50 @@ public function testDoNothingWhenPsalmNotInstalled() $this->assertSame($console, $trigger( new Activity(Type::sourcesModified), $console, + Set::of(Triggers::codingStandard), )); } + public function testDoNothingWhenTriggerNotEnabled() + { + $trigger = new CodingStandard( + $processes = $this->createMock(Processes::class), + $filesystem = $this->createMock(Filesystem::class), + new Iteration, + ); + $filesystem + ->expects($this->never()) + ->method('mount'); + $processes + ->expects($this->never()) + ->method('execute'); + $console = Console::of( + Environment\InMemory::of( + [], + true, + [], + [], + '/somewhere', + ), + new Arguments, + new Options, + ); + + $console = $trigger( + new Activity(Type::sourcesModified), + $console, + Set::of(), + ); + $this->assertSame( + [], + $console->environment()->outputs(), + ); + $this->assertSame( + [], + $console->environment()->errors(), + ); + } + public function testTriggerTestsSuiteWhenSourcesModified() { $trigger = new CodingStandard( @@ -174,6 +218,7 @@ public function testTriggerTestsSuiteWhenSourcesModified() $console = $trigger( new Activity(Type::sourcesModified), $console, + Set::of(Triggers::codingStandard), ); $console = $iteration->end($console); $this->assertSame( @@ -245,6 +290,7 @@ public function testDoesnClearTerminalOnSuccessfullTestWhenSpecifiedOptionProvid $console = $trigger( new Activity(Type::sourcesModified), $console, + Set::of(Triggers::codingStandard), ); $console = $iteration->end($console); $this->assertSame([], $console->environment()->outputs()); @@ -318,6 +364,7 @@ public function testTriggerTestsSuiteWhenTestsModified() $console = $trigger( new Activity(Type::testsModified), $console, + Set::of(Triggers::codingStandard), ); $console = $iteration->end($console); $this->assertSame( @@ -397,6 +444,7 @@ public function testTriggerForPHPCSFixer3() $console = $trigger( new Activity(Type::testsModified), $console, + Set::of(Triggers::codingStandard), ); $console = $iteration->end($console); $this->assertSame( @@ -473,6 +521,7 @@ public function testSaidMessageIsChangedWhenTestsAreFailing() $console = $trigger( new Activity(Type::sourcesModified), $console, + Set::of(Triggers::codingStandard), ); $console = $iteration->end($console); $this->assertSame([], $console->environment()->outputs()); @@ -531,6 +580,7 @@ public function testNoMessageIsSpokenWhenUsingTheSilentOption() $console = $trigger( new Activity(Type::sourcesModified), $console, + Set::of(Triggers::codingStandard), ); $console = $iteration->end($console); $this->assertSame(["\033[2J\033[H"], $console->environment()->outputs()); diff --git a/tests/Trigger/ComposerUpdateTest.php b/tests/Trigger/ComposerUpdateTest.php index 6a3c8cf..89196b8 100644 --- a/tests/Trigger/ComposerUpdateTest.php +++ b/tests/Trigger/ComposerUpdateTest.php @@ -6,6 +6,7 @@ use Innmind\LabStation\{ Trigger\ComposerUpdate, Trigger, + Triggers, Activity, Activity\Type, }; @@ -23,6 +24,7 @@ use Innmind\Immutable\{ Str, Sequence, + Set, }; use PHPUnit\Framework\TestCase; @@ -61,9 +63,45 @@ public function testDoNothingWhenNotOfExpectedType() $this->assertSame($console, $trigger( new Activity(Type::sourcesModified), $console, + Set::of(Triggers::composerUpdate), )); } + public function testDoNothingWhenTriggerNotEnabled() + { + $trigger = new ComposerUpdate( + $processes = $this->createMock(Processes::class), + ); + $processes + ->expects($this->never()) + ->method('execute'); + $console = Console::of( + Environment\InMemory::of( + ["\n"], + true, + [], + [], + '/somewhere', + ), + new Arguments, + new Options, + ); + + $console = $trigger( + new Activity(Type::start), + $console, + Set::of(), + ); + $this->assertSame( + [], + $console->environment()->outputs(), + ); + $this->assertSame( + [], + $console->environment()->errors(), + ); + } + public function testTriggerUpdateOnStart() { $trigger = new ComposerUpdate( @@ -102,6 +140,7 @@ public function testTriggerUpdateOnStart() $console = $trigger( new Activity(Type::start), $console, + Set::of(Triggers::composerUpdate), ); $this->assertSame( ['Update dependencies? [Y/n] ', 'some output', "Dependencies updated!\n"], @@ -136,6 +175,7 @@ public function testDoesntTriggerUpdateWhenNegativeResponse() $console = $trigger( new Activity(Type::start), $console, + Set::of(Triggers::composerUpdate), ); $this->assertSame( ['Update dependencies? [Y/n] '], diff --git a/tests/Trigger/DockerComposeTest.php b/tests/Trigger/DockerComposeTest.php index 11a689d..24f2c79 100644 --- a/tests/Trigger/DockerComposeTest.php +++ b/tests/Trigger/DockerComposeTest.php @@ -6,6 +6,7 @@ use Innmind\LabStation\{ Trigger\DockerCompose, Trigger, + Triggers, Activity, Activity\Type, }; @@ -30,6 +31,7 @@ use Innmind\Immutable\{ Either, SideEffect, + Set, }; use PHPUnit\Framework\TestCase; @@ -67,6 +69,7 @@ public function testDoesntStartDockerComposeWhenNotStartActivity() $this->assertSame($console, $trigger( new Activity(Type::sourcesModified), $console, + Set::of(Triggers::dockerCompose), )); } @@ -99,9 +102,49 @@ public function testDoesntStartDockerComposeWhenNoConfigFile() $this->assertSame($console, $trigger( new Activity(Type::start), $console, + Set::of(Triggers::dockerCompose), )); } + public function testDoNothingWhenTriggerNotEnabled() + { + $trigger = new DockerCompose( + $filesystem = $this->createMock(Filesystem::class), + $processes = $this->createMock(Processes::class), + ); + $filesystem + ->expects($this->never()) + ->method('mount'); + $processes + ->expects($this->never()) + ->method('execute'); + $console = Console::of( + Environment\InMemory::of( + [], + true, + [], + [], + '/path/to/project/vendor/package', + ), + new Arguments, + new Options, + ); + + $console = $trigger( + new Activity(Type::start), + $console, + Set::of(), + ); + $this->assertSame( + [], + $console->environment()->outputs(), + ); + $this->assertSame( + [], + $console->environment()->errors(), + ); + } + public function testStartDockerCompose() { $trigger = new DockerCompose( @@ -148,6 +191,7 @@ public function testStartDockerCompose() $this->assertSame($console, $trigger( new Activity(Type::start), $console, + Set::of(Triggers::dockerCompose), )); } } diff --git a/tests/Trigger/PsalmTest.php b/tests/Trigger/PsalmTest.php index dd492f3..93135d1 100644 --- a/tests/Trigger/PsalmTest.php +++ b/tests/Trigger/PsalmTest.php @@ -6,6 +6,7 @@ use Innmind\LabStation\{ Trigger\Psalm, Trigger, + Triggers, Activity, Activity\Type, Iteration, @@ -36,6 +37,7 @@ Either, SideEffect, Map, + Set, }; use PHPUnit\Framework\TestCase; @@ -72,6 +74,7 @@ public function testDoNothingWhenNotOfExpectedType() $this->assertSame($console, $trigger( new Activity(Type::start), $console, + Set::of(Triggers::psalm), )); } @@ -104,9 +107,50 @@ public function testDoNothingWhenPsalmNotInstalled() $this->assertSame($console, $trigger( new Activity(Type::sourcesModified), $console, + Set::of(Triggers::psalm), )); } + public function testDoNothingWhenTriggerNotEnabled() + { + $trigger = new Psalm( + $processes = $this->createMock(Processes::class), + $filesystem = $this->createMock(Filesystem::class), + new Iteration, + ); + $filesystem + ->expects($this->never()) + ->method('mount'); + $processes + ->expects($this->never()) + ->method('execute'); + $console = Console::of( + Environment\InMemory::of( + [], + true, + [], + [], + '/somewhere', + ), + new Arguments, + new Options, + ); + + $console = $trigger( + new Activity(Type::sourcesModified), + $console, + Set::of(), + ); + $this->assertSame( + [], + $console->environment()->outputs(), + ); + $this->assertSame( + [], + $console->environment()->errors(), + ); + } + public function testTriggerTestsSuiteWhenSourcesModified() { $trigger = new Psalm( @@ -176,6 +220,7 @@ public function testTriggerTestsSuiteWhenSourcesModified() $console = $trigger( new Activity(Type::sourcesModified), $console, + Set::of(Triggers::psalm), ); $console = $iteration->end($console); $this->assertSame( @@ -249,6 +294,7 @@ public function testDoesnClearTerminalOnSuccessfullTestWhenSpecifiedOptionProvid $console = $trigger( new Activity(Type::sourcesModified), $console, + Set::of(Triggers::psalm), ); $console = $iteration->end($console); $this->assertSame([], $console->environment()->outputs()); @@ -323,6 +369,7 @@ public function testTriggerTestsSuiteWhenTestsModified() $console = $trigger( new Activity(Type::testsModified), $console, + Set::of(Triggers::psalm), ); $console = $iteration->end($console); $this->assertSame( @@ -399,6 +446,7 @@ public function testSaidMessageIsChangedWhenTestsAreFailing() $console = $trigger( new Activity(Type::sourcesModified), $console, + Set::of(Triggers::psalm), ); $console = $iteration->end($console); $this->assertSame([], $console->environment()->outputs()); @@ -456,6 +504,7 @@ public function testNoMessageIsSpokenWhenUsingTheSilentOption() $console = $trigger( new Activity(Type::sourcesModified), $console, + Set::of(Triggers::psalm), ); $console = $iteration->end($console); $this->assertSame(["\033[2J\033[H"], $console->environment()->outputs()); diff --git a/tests/Trigger/TestsTest.php b/tests/Trigger/TestsTest.php index 15e8d8d..a7c6f83 100644 --- a/tests/Trigger/TestsTest.php +++ b/tests/Trigger/TestsTest.php @@ -6,6 +6,7 @@ use Innmind\LabStation\{ Trigger\Tests, Trigger, + Triggers, Activity, Activity\Type, Iteration, @@ -34,6 +35,7 @@ Either, SideEffect, Map, + Set as ISet, }; use PHPUnit\Framework\TestCase; use Innmind\BlackBox\{ @@ -76,9 +78,59 @@ public function testDoNothingWhenNotOfExpectedType() $this->assertSame($console, $trigger( new Activity(Type::start), $console, + ISet::of(Triggers::tests), )); } + public function testDoNothingWhenTriggerNotEnabled() + { + $this + ->forAll(Set\Elements::of( + Type::sourcesModified, + Type::testsModified, + Type::fixturesModified, + Type::propertiesModified, + )) + ->then(function($type) { + $trigger = new Tests( + $filesystem = $this->createMock(Filesystem::class), + $processes = $this->createMock(Processes::class), + new Iteration, + ); + $filesystem + ->expects($this->never()) + ->method('mount'); + $processes + ->expects($this->never()) + ->method('execute'); + $console = Console::of( + Environment\InMemory::of( + [], + true, + [], + [], + '/somewhere', + ), + new Arguments, + new Options, + ); + + $console = $trigger( + new Activity($type), + $console, + ISet::of(), + ); + $this->assertSame( + [], + $console->environment()->outputs(), + ); + $this->assertSame( + [], + $console->environment()->errors(), + ); + }); + } + public function testTriggerTestsSuiteWhenActivity() { $this @@ -156,6 +208,7 @@ public function testTriggerTestsSuiteWhenActivity() $console = $trigger( new Activity($type), $console, + ISet::of(Triggers::tests), ); $console = $iteration->end($console); $this->assertSame( @@ -208,6 +261,7 @@ public function testDoesntTriggerWhenNoPHPUnitFile() $console = $trigger( new Activity($type), $console, + ISet::of(Triggers::tests), ); $console = $iteration->end($console); $this->assertSame( @@ -284,6 +338,7 @@ public function testDoesntClearTerminalOnSuccessfullTestWhenSpecifiedOptionProvi $console = $trigger( new Activity(Type::sourcesModified), $console, + ISet::of(Triggers::tests), ); $console = $iteration->end($console); $this->assertSame([], $console->environment()->outputs()); @@ -352,6 +407,7 @@ public function testSaidMessageIsChangedWhenTestsAreFailing() $console = $trigger( new Activity(Type::sourcesModified), $console, + ISet::of(Triggers::tests), ); $console = $iteration->end($console); $this->assertSame([], $console->environment()->outputs()); @@ -408,6 +464,7 @@ public function testNoMessageIsSpokenWhenUsingTheSilentOption() $console = $trigger( new Activity(Type::sourcesModified), $console, + ISet::of(Triggers::tests), ); $console = $iteration->end($console); $this->assertSame(["\033[2J\033[H"], $console->environment()->outputs());