Skip to content

Commit 3caec88

Browse files
committed
wip PintPreCommitHook.php
1 parent 66d5e16 commit 3caec88

File tree

7 files changed

+176
-29
lines changed

7 files changed

+176
-29
lines changed

src/Console/Commands/Hooks/PintPreCommitHook.php

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,45 +7,44 @@
77
use Igorsgm\GitHooks\Exceptions\HookFailException;
88
use Igorsgm\GitHooks\Facades\GitHooks;
99
use Igorsgm\GitHooks\Git\ChangedFiles;
10-
use Igorsgm\GitHooks\Traits\ConsoleHelper;
10+
use Igorsgm\GitHooks\Traits\ProcessHelper;
11+
use Illuminate\Console\Command;
1112
use Symfony\Component\Console\Terminal;
1213

1314
class PintPreCommitHook implements PreCommitHook
1415
{
15-
use ConsoleHelper;
16+
use ProcessHelper;
1617

1718
/**
18-
* @var string
19+
* Command instance that is bound automatically by Hooks Pipeline, so it can be used inside the Hook.
20+
*
21+
* @var Command
1922
*/
20-
private $pintExecutable;
23+
public $command;
2124

2225
/**
2326
* @var string
2427
*/
25-
private $pintConfig;
28+
private $pintExecutable;
2629

2730
/**
2831
* @var array
2932
*/
30-
private $filesBadlyFormatted;
31-
32-
public function getName(): ?string
33-
{
34-
return 'Laravel Pint';
35-
}
33+
private $filesBadlyFormatted = [];
3634

3735
/**
3836
* Create a new console command instance.
3937
*
4038
* @return void
4139
*/
42-
public function __construct($argInput = '')
40+
public function __construct()
4341
{
44-
$this->initConsole($argInput);
45-
4642
$this->pintExecutable = './'.trim(config('git-hooks.code_analyzers.laravel_pint.path'), '/');
47-
$this->pintConfig = './'.trim(config('git-hooks.code_analyzers.laravel_pint.config'), '/');
48-
$this->filesBadlyFormatted = [];
43+
}
44+
45+
public function getName(): ?string
46+
{
47+
return 'Laravel Pint';
4948
}
5049

5150
public function handle(ChangedFiles $files, Closure $next)
@@ -62,17 +61,22 @@ public function handle(ChangedFiles $files, Closure $next)
6261

6362
foreach ($stagedFilePaths as $stagedFilePath) {
6463
$isPintProperlyFormatted = $this->runCommands(
65-
sprintf('%s --test --config %s %s', $this->pintExecutable, $this->pintConfig, $stagedFilePath),
64+
implode(' ', [
65+
$this->pintExecutable,
66+
'--test',
67+
$this->getPintConfigParam(),
68+
$stagedFilePath,
69+
]),
6670
[
6771
'cwd' => base_path(),
6872
])->isSuccessful();
6973

7074
if (! $isPintProperlyFormatted) {
7175
if (empty($this->filesBadlyFormatted)) {
72-
$this->newLine();
76+
$this->command->newLine();
7377
}
7478

75-
$this->output->writeln(
79+
$this->command->getOutput()->writeln(
7680
sprintf('<fg=red> Pint Failed:</> %s', "$stagedFilePath")
7781
);
7882
$this->filesBadlyFormatted[] = $stagedFilePath;
@@ -83,15 +87,21 @@ public function handle(ChangedFiles $files, Closure $next)
8387
return $next($files);
8488
}
8589

86-
$this->newLine();
87-
$this->output->writeln(
90+
$this->command->newLine();
91+
$this->command->getOutput()->writeln(
8892
sprintf('<bg=red;fg=white> COMMIT FAILED </> %s',
8993
'Your commit contains files that should pass Pint but do not. Please fix the Pint errors in the files above and try again.')
9094
);
9195

9296
$this->suggestAutoFixOrExit();
9397
}
9498

99+
private function getPintConfigParam(): string
100+
{
101+
$pintConfigFile = trim(config('git-hooks.code_analyzers.laravel_pint.config'), '/');
102+
return empty($pintConfigFile) ? '' : '--config ./'.$pintConfigFile;
103+
}
104+
95105
/**
96106
* @return void
97107
*
@@ -105,12 +115,12 @@ private function validatePintInstallation()
105115
return;
106116
}
107117

108-
$this->newLine(2);
109-
$this->output->writeln(
118+
$this->command->newLine(2);
119+
$this->command->getOutput()->writeln(
110120
sprintf('<bg=red;fg=white> ERROR </> %s',
111121
'Pint is not installed. Please run <info>composer require laravel/pint --dev</info> to install it.')
112122
);
113-
$this->newLine();
123+
$this->command->newLine();
114124
throw new HookFailException();
115125
}
116126

@@ -122,12 +132,16 @@ private function validatePintInstallation()
122132
private function suggestAutoFixOrExit()
123133
{
124134
if (Terminal::hasSttyAvailable() &&
125-
$this->confirm('Would you like to attempt to correct files automagically?', false)
135+
$this->command->confirm('Would you like to attempt to correct files automagically?', false)
126136
) {
127137
$errorFilesString = implode(' ', $this->filesBadlyFormatted);
128138
$this->runCommands(
129139
[
130-
sprintf('%s --config %s %s', $this->pintExecutable, $this->pintConfig, $errorFilesString),
140+
implode(' ', [
141+
$this->pintExecutable,
142+
$this->getPintConfigParam(),
143+
$errorFilesString,
144+
]),
131145
'git add '.$errorFilesString,
132146
],
133147
['cwd' => base_path()]

src/Contracts/Hook.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
namespace Igorsgm\GitHooks\Contracts;
44

5+
/**
6+
* @property \Illuminate\Console\Command $command
7+
*/
58
interface Hook
69
{
710
/**

src/Traits/WithPipeline.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ protected function startHookConsoleTask(): Closure
4949
return function (Hook $hook) {
5050
$this->hookExecuting = $hook;
5151

52+
// Binding the Command instance to the Hook, so it can be used inside the Hook
53+
$hook->command = $this;
54+
5255
$taskTitle = $this->getHookTaskTitle($hook);
5356
$loadingText = 'loading...';
5457
$this->output->write("$taskTitle: <comment>{$loadingText}</comment>");

tests/Datasets/GitLogsDataset.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,7 @@
2323
dataset('listOfChangedFiles', [
2424
'list of changed files' => 'AM src/ChangedFiles.php',
2525
]);
26+
27+
dataset('listOfFixableFiles', [
28+
'list of fixable files' => 'AM temp/ClassWithFixableIssues.php',
29+
]);
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
<?php
2+
3+
use Igorsgm\GitHooks\Console\Commands\Hooks\PintPreCommitHook;
4+
use Igorsgm\GitHooks\Facades\GitHooks;
5+
use Igorsgm\GitHooks\Git\ChangedFiles;
6+
use Igorsgm\GitHooks\Traits\GitHelper;
7+
8+
uses(GitHelper::class);
9+
beforeEach(function () {
10+
$this->gitInit();
11+
$this->initializeTempDirectory(base_path('temp'));
12+
});
13+
14+
test('Skips Pint check if there are no staged files', function () {
15+
$changedFiles = mock(ChangedFiles::class)
16+
->shouldReceive('getStaged')
17+
->andReturn(collect())
18+
->getMock();
19+
20+
$next = function ($files) {
21+
return 'passed';
22+
};
23+
24+
$hook = new PintPreCommitHook();
25+
$result = $hook->handle($changedFiles, $next);
26+
expect($result)->toBe('passed');
27+
});
28+
29+
test('Skips Pint check during a Merge process', function ($modifiedFilesList) {
30+
$changedFiles = new ChangedFiles($modifiedFilesList);
31+
GitHooks::shouldReceive('isMergeInProgress')->andReturn(true);
32+
33+
$next = function ($files) {
34+
return 'passed';
35+
};
36+
37+
$hook = new PintPreCommitHook();
38+
$result = $hook->handle($changedFiles, $next);
39+
expect($result)->toBe('passed');
40+
})->with('modifiedFilesList');
41+
42+
test('Throws HookFailException and notifies when Pint is not installed', function ($listOfFixableFiles) {
43+
$this->config->set('git-hooks.code_analyzers.laravel_pint', [
44+
'path' => 'inexistent/path/to/pint',
45+
]);
46+
47+
$this->config->set('git-hooks.pre-commit', [
48+
PintPreCommitHook::class,
49+
]);
50+
51+
GitHooks::shouldReceive('isMergeInProgress')->andReturn(false);
52+
GitHooks::shouldReceive('getListOfChangedFiles')->andReturn($listOfFixableFiles);
53+
54+
$this->artisan('git-hooks:pre-commit')
55+
->expectsOutputToContain('Pint is not installed.')
56+
->assertExitCode(1);
57+
})->with('listOfFixableFiles');
58+
59+
test('Fails commit when Pint is not passing and user does not autofix the files', function ($listOfFixableFiles) {
60+
$this->config->set('git-hooks.code_analyzers.laravel_pint', [
61+
'path' => '../../../bin/pint',
62+
]);
63+
$this->config->set('git-hooks.pre-commit', [
64+
PintPreCommitHook::class,
65+
]);
66+
67+
$this->makeTempFile('ClassWithFixableIssues.php',
68+
file_get_contents(__DIR__.'/../../../Fixtures/ClassWithFixableIssues.php')
69+
);
70+
71+
GitHooks::shouldReceive('isMergeInProgress')->andReturn(false);
72+
GitHooks::shouldReceive('getListOfChangedFiles')->andReturn($listOfFixableFiles);
73+
74+
$this->artisan('git-hooks:pre-commit')
75+
->expectsOutputToContain('Pint Failed')
76+
->expectsOutputToContain('COMMIT FAILED')
77+
->expectsConfirmation('Would you like to attempt to correct files automagically?', 'no')
78+
->assertExitCode(1);
79+
80+
})->with('listOfFixableFiles');
81+
82+
test('Commit passes when Pint fixes fix the files', function ($listOfFixableFiles) {
83+
$this->config->set('git-hooks.code_analyzers.laravel_pint', [
84+
'path' => '../../../bin/pint',
85+
]);
86+
$this->config->set('git-hooks.pre-commit', [
87+
PintPreCommitHook::class,
88+
]);
89+
90+
$this->makeTempFile('ClassWithFixableIssues.php',
91+
file_get_contents(__DIR__.'/../../../Fixtures/ClassWithFixableIssues.php')
92+
);
93+
94+
GitHooks::shouldReceive('isMergeInProgress')->andReturn(false);
95+
GitHooks::shouldReceive('getListOfChangedFiles')->andReturn($listOfFixableFiles);
96+
97+
$this->artisan('git-hooks:pre-commit')
98+
->expectsOutputToContain('Pint Failed')
99+
->expectsOutputToContain('COMMIT FAILED')
100+
->expectsConfirmation('Would you like to attempt to correct files automagically?', 'yes');
101+
102+
$this->artisan('git-hooks:pre-commit')
103+
->doesntExpectOutputToContain('Pint Failed')
104+
->assertSuccessful();
105+
106+
})->with('listOfFixableFiles');
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
4+
5+
namespace Igorsgm\GitHooks\Tests\Fixtures;
6+
7+
class ClassWithFixableIssues
8+
{
9+
}

tests/TestCase.php

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ public function defineEnvironment($app)
4040
'post-checkout' => [],
4141
'post-merge' => [],
4242
'pre-push' => [],
43+
'code_analyzers' => [],
4344
]);
4445

4546
$this->config = $app['config'];
@@ -71,13 +72,20 @@ protected function getPackageAliases($app)
7172
];
7273
}
7374

75+
public function gitInit()
76+
{
77+
chdir(base_path());
78+
shell_exec('git init --quiet');
79+
80+
return $this;
81+
}
82+
7483
/**
7584
* @return void
7685
*/
7786
public function initializeGitAsTempDirectory()
7887
{
79-
chdir(base_path());
80-
shell_exec('git init --quiet');
81-
$this->initializeTempDirectory(base_path('.git'));
88+
$this->gitInit()
89+
->initializeTempDirectory(base_path('.git'));
8290
}
8391
}

0 commit comments

Comments
 (0)