Skip to content

Commit 53a016d

Browse files
committed
Task style implemented for HooksPipeline
1 parent 3e5a5e1 commit 53a016d

File tree

8 files changed

+198
-29
lines changed

8 files changed

+198
-29
lines changed

composer.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@
2222
],
2323
"require": {
2424
"php": "^7.2|^8.0",
25-
"illuminate/container": "^5.6|^6.0|^7.0|^8.0|^9.0",
26-
"illuminate/config": "^5.6|^6.0|^7.0|^8.0|^9.0",
27-
"illuminate/support": "^5.6|^6.0|^7.0|^8.0|^9.0",
28-
"illuminate/contracts": "^5.6|^6.0|^7.0|^8.0|^9.0",
29-
"illuminate/console": "^5.6|^6.0|^7.0|^8.0|^9.0",
30-
"illuminate/pipeline": "^5.6|^6.0|^7.0|^8.0|^9.0"
25+
"illuminate/config": "^6.0|^7.0|^8.0|^9.0",
26+
"illuminate/console": "^6.0|^7.0|^8.0|^9.0",
27+
"illuminate/container": "^6.0|^7.0|^8.0|^9.0",
28+
"illuminate/contracts": "^6.0|^7.0|^8.0|^9.0",
29+
"illuminate/pipeline": "^6.0|^7.0|^8.0|^9.0",
30+
"illuminate/support": "^6.0|^7.0|^8.0|^9.0"
3131
},
3232
"require-dev": {
3333
"laravel/pint": "^1.2",

src/HooksPipeline.php

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,12 @@ class HooksPipeline extends Pipeline
1212
/**
1313
* @var Closure
1414
*/
15-
protected $callback;
15+
protected $pipeStartCallback;
1616

1717
/**
1818
* @var Closure
1919
*/
20-
protected $exceptionCallback;
20+
protected $pipeEndCallback;
2121

2222
/**
2323
* @var string
@@ -38,9 +38,20 @@ public function __construct(Container $container, string $hook)
3838
* @param Closure $callback
3939
* @return $this
4040
*/
41-
public function withCallback(Closure $callback)
41+
public function withPipeStartCallback(Closure $callback)
4242
{
43-
$this->callback = $callback;
43+
$this->pipeStartCallback = $callback;
44+
45+
return $this;
46+
}
47+
48+
/**
49+
* @param Closure $callback
50+
* @return $this
51+
*/
52+
public function withPipeEndCallback(Closure $callback)
53+
{
54+
$this->pipeEndCallback = $callback;
4455

4556
return $this;
4657
}
@@ -68,8 +79,10 @@ protected function carry()
6879
// execute the pipe function giving in the parameters that are required.
6980
$pipe = $this->getContainer()->make($pipe, ['parameters' => $hookParameters]);
7081

71-
if ($this->callback) {
72-
call_user_func_array($this->callback, [$pipe]);
82+
$this->handlePipeEnd(true);
83+
84+
if ($this->pipeStartCallback) {
85+
call_user_func_array($this->pipeStartCallback, [$pipe]);
7386
}
7487

7588
$parameters = [$passable, $stack];
@@ -81,8 +94,8 @@ protected function carry()
8194
}
8295

8396
$carry = method_exists($pipe, $this->method)
84-
? $pipe->{$this->method}(...$parameters)
85-
: $pipe(...$parameters);
97+
? $pipe->{$this->method}(...$parameters)
98+
: $pipe(...$parameters);
8699

87100
return $this->handleCarry($carry);
88101
} catch (Throwable $e) {
@@ -91,4 +104,46 @@ protected function carry()
91104
};
92105
};
93106
}
107+
108+
/**
109+
* Handle the call back call once a specific pipe has finished or errored.
110+
*
111+
* @param bool $success
112+
* @return void
113+
*/
114+
protected function handlePipeEnd($success)
115+
{
116+
if ($this->pipeEndCallback) {
117+
call_user_func_array($this->pipeEndCallback, [$success]);
118+
}
119+
}
120+
121+
/**
122+
* Handle the value returned from each pipe before passing it to the next.
123+
*
124+
* @param mixed $carry
125+
* @return mixed
126+
*/
127+
protected function handleCarry($carry)
128+
{
129+
$this->handlePipeEnd(true);
130+
131+
return $carry;
132+
}
133+
134+
/**
135+
* Handle the given exception.
136+
*
137+
* @param mixed $passable
138+
* @param \Throwable $e
139+
* @return mixed
140+
*
141+
* @throws \Throwable
142+
*/
143+
protected function handleException($passable, Throwable $e)
144+
{
145+
$this->handlePipeEnd(false);
146+
147+
throw $e;
148+
}
94149
}

src/Traits/ProcessHelper.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public function runCommands($commands, $params = [])
2929
});
3030
}
3131

32-
if ($input && $input->getOption('quiet')) {
32+
if (! empty($input->definition) && $input->definition->hasOption('quiet') && $input->getOption('quiet')) {
3333
$commands = $this->transformCommands($commands, function ($value) {
3434
return $value.' --quiet';
3535
});

src/Traits/WithPipeline.php

Lines changed: 63 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,16 @@
66
use Igorsgm\GitHooks\Contracts\Hook;
77
use Igorsgm\GitHooks\HooksPipeline;
88
use Illuminate\Pipeline\Pipeline;
9-
use Throwable;
109

1110
trait WithPipeline
1211
{
12+
/**
13+
* Hook which is currently running in the Pipeline.
14+
*
15+
* @var Hook
16+
*/
17+
public $hookExecuting;
18+
1319
/**
1420
* Make pipeline instance
1521
*
@@ -21,30 +27,76 @@ protected function makePipeline(): Pipeline
2127

2228
return $pipeline
2329
->through($this->getRegisteredHooks())
24-
->withCallback($this->showInfoAboutHook());
30+
->withPipeStartCallback($this->startHookConsoleTask())
31+
->withPipeEndCallback($this->finishHookConsoleTask());
32+
}
33+
34+
/**
35+
* {@inheritDoc}
36+
*/
37+
public function getRegisteredHooks(): array
38+
{
39+
$hooks = collect((array) config('git-hooks.'.$this->getHook()));
40+
41+
return $hooks->map(function ($hook, $i) {
42+
return is_int($i) ? $hook : $i;
43+
})->all();
2544
}
2645

2746
/**
28-
* Show information about run hook
47+
* Show information about Hook which is being executed
2948
*
3049
* @return Closure
3150
*/
32-
protected function showInfoAboutHook(): Closure
51+
protected function startHookConsoleTask(): Closure
3352
{
3453
return function (Hook $hook) {
35-
$this->info(sprintf('Hook: %s...', $hook->getName()));
54+
$this->hookExecuting = $hook;
55+
56+
$taskTitle = $this->getHookTaskTitle($hook);
57+
$loadingText = 'loading...';
58+
$this->output->write("$taskTitle: <comment>{$loadingText}</comment>");
3659
};
3760
}
3861

3962
/**
40-
* {@inheritDoc}
63+
* Finish the console task of the Hook which just executed, with success or failure
64+
*
65+
* @return Closure
4166
*/
42-
public function getRegisteredHooks(): array
67+
protected function finishHookConsoleTask(): Closure
4368
{
44-
$hooks = collect((array) config('git-hooks.'.$this->getHook()));
69+
return function ($success) {
70+
if (empty($this->hookExecuting)) {
71+
return;
72+
}
4573

46-
return $hooks->map(function ($hook, $i) {
47-
return is_int($i) ? $hook : $i;
48-
})->all();
74+
if ($this->output->isDecorated()) { // Determines if we can use escape sequences
75+
// Move the cursor to the beginning of the line
76+
$this->output->write("\x0D");
77+
78+
// Erase the line
79+
$this->output->write("\x1B[2K");
80+
} else {
81+
$this->output->writeln(''); // Make sure we first close the previous line
82+
}
83+
84+
$taskTitle = $this->getHookTaskTitle($this->hookExecuting);
85+
86+
$this->output->writeln(
87+
"$taskTitle: ".($success ? '<info>✔</info>' : '<error>failed</error>')
88+
);
89+
90+
$this->hookExecuting = null;
91+
};
92+
}
93+
94+
/**
95+
* @param Hook $hook
96+
* @return string
97+
*/
98+
public function getHookTaskTitle(Hook $hook): string
99+
{
100+
return sprintf(' <bg=blue;fg=white> HOOK </> %s', $hook->getName());
49101
}
50102
}

tests/Features/Commands/CommitMessageTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
->assertExitCode(0);
2929

3030
foreach ($commitMessageHooks as $hook) {
31-
$command->expectsOutputToContain(sprintf('Hook: %s...', resolve($hook)->getName()));
31+
$command->expectsOutputToContain(sprintf(' HOOK %s: ✔', resolve($hook)->getName()));
3232
}
3333
})->with('listOfChangedFiles');
3434

@@ -58,6 +58,6 @@
5858

5959
foreach ($commitMessageHooks as $hook => $parameters) {
6060
$hook = resolve($hook, compact('parameters'));
61-
$command->expectsOutputToContain(sprintf('Hook: %s...', $hook->getName()));
61+
$command->expectsOutputToContain(sprintf(' HOOK %s: ✔', $hook->getName()));
6262
}
6363
})->with('listOfChangedFiles');

tests/Features/Commands/PrepareCommitMessageTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
->assertExitCode(0);
3131

3232
foreach ($prepareCommitMessageHooks as $hook) {
33-
$command->expectsOutputToContain(sprintf('Hook: %s...', resolve($hook)->getName()));
33+
$command->expectsOutputToContain(sprintf(' HOOK %s: ✔', resolve($hook)->getName()));
3434
}
3535
})->with('listOfChangedFiles');
3636

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace Igorsgm\GitHooks\Tests\Fixtures;
4+
5+
use Closure;
6+
use Igorsgm\GitHooks\Contracts\PreCommitHook;
7+
use Igorsgm\GitHooks\Git\ChangedFiles;
8+
9+
class PreCommitFixtureHook implements PreCommitHook
10+
{
11+
public function getName(): string
12+
{
13+
return 'MyPreCommitHook1';
14+
}
15+
16+
public function handle(ChangedFiles $files, Closure $next)
17+
{
18+
return $next($files);
19+
}
20+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
use Igorsgm\GitHooks\Console\Commands\PreCommit;
4+
use Igorsgm\GitHooks\Tests\Fixtures\PreCommitFixtureHook;
5+
use Symfony\Component\Console\Output\OutputInterface;
6+
7+
test('Starts and Finishes Pipe Task with decorated output', function () {
8+
$command = new PreCommit();
9+
$hook = new PreCommitFixtureHook();
10+
$outputMock = $this->createMock(OutputInterface::class);
11+
12+
$outputMock->expects($this->once())
13+
->method('isDecorated')
14+
->willReturn(true);
15+
16+
$outputMock->expects($this->exactly(3))
17+
->method('write')
18+
->withConsecutive(
19+
[$this->equalTo(' <bg=blue;fg=white> HOOK </> '.$hook->getName().': <comment>loading...</comment>')],
20+
[$this->equalTo("\x0D")],
21+
[$this->equalTo("\x1B[2K")]
22+
);
23+
24+
$outputMock->expects($this->once())
25+
->method('writeln')
26+
->with(' <bg=blue;fg=white> HOOK </> '.$hook->getName().': <info>✔</info>');
27+
28+
$commandReflection = new ReflectionClass($command);
29+
30+
$commandOutputProperty = $commandReflection->getProperty('output');
31+
$commandOutputProperty->setValue($command, $outputMock);
32+
33+
$startHookConsoleTask = $commandReflection->getMethod('startHookConsoleTask');
34+
$startClosure = $startHookConsoleTask->invoke($command);
35+
expect($startClosure)->toBeCallable();
36+
$startClosure($hook);
37+
38+
$finishHookConsoleTask = $commandReflection->getMethod('finishHookConsoleTask');
39+
$finishClosure = $finishHookConsoleTask->invoke($command);
40+
expect($finishClosure)->toBeCallable();
41+
$finishClosure(true);
42+
});

0 commit comments

Comments
 (0)