Skip to content

Commit ca57fd2

Browse files
authored
Merge pull request #14 from igorsgm/feature/laravel-pint-pre-commit-hook
Pre Commit Hook: Laravel Pint
2 parents be331ac + 8fd351b commit ca57fd2

36 files changed

+431
-141
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/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"
25+
"illuminate/config": "^6.0|^7.0|^8.0|^9.0|^10.0",
26+
"illuminate/console": "^6.0|^7.0|^8.0|^9.0|^10.0",
27+
"illuminate/container": "^6.0|^7.0|^8.0|^9.0|^10.0",
28+
"illuminate/contracts": "^6.0|^7.0|^8.0|^9.0|^10.0",
29+
"illuminate/pipeline": "^6.0|^7.0|^8.0|^9.0|^10.0",
30+
"illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0"
3131
},
3232
"require-dev": {
3333
"laravel/pint": "^1.2",

config/git-hooks.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,4 +155,23 @@
155155
'pre-push' => [
156156

157157
],
158+
159+
/*
160+
|--------------------------------------------------------------------------
161+
| Code Analyzers Configuration
162+
|--------------------------------------------------------------------------
163+
|
164+
| The following variables are used to store the paths to bin executables for
165+
| various code analyzer dependencies used in your Laravel application.
166+
| This configuration node allows you to set up the paths for these executables.
167+
| Here you can also specify the path to the configuration files they use to customize their behavior
168+
|
169+
*/
170+
'code_analyzers' => [
171+
'laravel_pint' => [
172+
'path' => env('LARAVEL_PINT_PATH', 'vendor/bin/pint'),
173+
'config' => env('LARAVEL_PINT_CONFIG', 'pint.json'),
174+
],
175+
],
176+
158177
];
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
<?php
2+
3+
namespace Igorsgm\GitHooks\Console\Commands\Hooks;
4+
5+
use Closure;
6+
use Igorsgm\GitHooks\Contracts\PreCommitHook;
7+
use Igorsgm\GitHooks\Exceptions\HookFailException;
8+
use Igorsgm\GitHooks\Facades\GitHooks;
9+
use Igorsgm\GitHooks\Git\ChangedFiles;
10+
use Igorsgm\GitHooks\Traits\ProcessHelper;
11+
use Illuminate\Console\Command;
12+
use Symfony\Component\Console\Terminal;
13+
14+
class PintPreCommitHook implements PreCommitHook
15+
{
16+
use ProcessHelper;
17+
18+
/**
19+
* Command instance that is bound automatically by Hooks Pipeline, so it can be used inside the Hook.
20+
*
21+
* @var Command
22+
*/
23+
public $command;
24+
25+
/**
26+
* @var string
27+
*/
28+
private $pintExecutable;
29+
30+
/**
31+
* @var array
32+
*/
33+
private $filesBadlyFormatted = [];
34+
35+
/**
36+
* Create a new console command instance.
37+
*
38+
* @return void
39+
*/
40+
public function __construct()
41+
{
42+
$this->pintExecutable = './'.trim(config('git-hooks.code_analyzers.laravel_pint.path'), '/');
43+
}
44+
45+
public function getName(): ?string
46+
{
47+
return 'Laravel Pint';
48+
}
49+
50+
public function handle(ChangedFiles $files, Closure $next)
51+
{
52+
$stagedFilePaths = $files->getStaged()->map(function ($file) {
53+
return $file->getFilePath();
54+
})->toArray();
55+
56+
if (empty($stagedFilePaths) || GitHooks::isMergeInProgress()) {
57+
return $next($files);
58+
}
59+
60+
$this->validatePintInstallation();
61+
62+
foreach ($stagedFilePaths as $stagedFilePath) {
63+
$isPintProperlyFormatted = $this->runCommands(
64+
implode(' ', [
65+
$this->pintExecutable,
66+
'--test',
67+
$this->getPintConfigParam(),
68+
$stagedFilePath,
69+
]),
70+
[
71+
'cwd' => base_path(),
72+
])->isSuccessful();
73+
74+
if (! $isPintProperlyFormatted) {
75+
if (empty($this->filesBadlyFormatted)) {
76+
$this->command->newLine();
77+
}
78+
79+
$this->command->getOutput()->writeln(
80+
sprintf('<fg=red> Pint Failed:</> %s', "$stagedFilePath")
81+
);
82+
$this->filesBadlyFormatted[] = $stagedFilePath;
83+
}
84+
}
85+
86+
if (empty($this->filesBadlyFormatted)) {
87+
return $next($files);
88+
}
89+
90+
$this->command->newLine();
91+
$this->command->getOutput()->writeln(
92+
sprintf('<bg=red;fg=white> COMMIT FAILED </> %s',
93+
'Your commit contains files that should pass Pint but do not. Please fix the Pint errors in the files above and try again.')
94+
);
95+
96+
$this->suggestAutoFixOrExit();
97+
}
98+
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+
105+
/**
106+
* @return void
107+
*
108+
* @throws HookFailException
109+
*/
110+
private function validatePintInstallation()
111+
{
112+
$isPintInstalled = file_exists(base_path(config('git-hooks.code_analyzers.laravel_pint.path')));
113+
114+
if ($isPintInstalled) {
115+
return;
116+
}
117+
118+
$this->command->newLine(2);
119+
$this->command->getOutput()->writeln(
120+
sprintf('<bg=red;fg=white> ERROR </> %s',
121+
'Pint is not installed. Please run <info>composer require laravel/pint --dev</info> to install it.')
122+
);
123+
$this->command->newLine();
124+
throw new HookFailException();
125+
}
126+
127+
/**
128+
* @return void
129+
*
130+
* @throws HookFailException
131+
*/
132+
private function suggestAutoFixOrExit()
133+
{
134+
if (Terminal::hasSttyAvailable() &&
135+
$this->command->confirm('Would you like to attempt to correct files automagically?', false)
136+
) {
137+
$errorFilesString = implode(' ', $this->filesBadlyFormatted);
138+
$this->runCommands(
139+
[
140+
implode(' ', [
141+
$this->pintExecutable,
142+
$this->getPintConfigParam(),
143+
$errorFilesString,
144+
]),
145+
'git add '.$errorFilesString,
146+
],
147+
['cwd' => base_path()]
148+
);
149+
} else {
150+
throw new HookFailException();
151+
}
152+
}
153+
}

src/Console/Commands/PreCommit.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,6 @@ public function handle()
5555

5656
/**
5757
* Send the changed files through the pipes
58-
*
59-
* @param ChangedFiles $files
6058
*/
6159
protected function sendChangedFilesThroughHooks(ChangedFiles $files): void
6260
{

src/Console/Commands/PrepareCommitMessage.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ class PrepareCommitMessage extends Command implements HookCommand
2626

2727
/**
2828
* Get hook name
29-
*
30-
* @return string
3129
*/
3230
public function getHook(): string
3331
{

src/Console/Commands/RegisterHooks.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ class RegisterHooks extends Command
2525
/**
2626
* Execute the console command.
2727
*
28-
* @param GitHooks $gitHooks
2928
* @return void
3029
*
3130
* @throws Exception

src/Console/Commands/stubs/hook

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
#!/bin/sh
2+
# Detect whether /dev/tty is available & functional
3+
if sh -c ": >/dev/tty" >/dev/null 2>/dev/null; then
4+
exec < /dev/tty
5+
fi
26

37
php {path}/artisan {command} $@ >&2

src/Contracts/Hook.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@
22

33
namespace Igorsgm\GitHooks\Contracts;
44

5+
/**
6+
* @property \Illuminate\Console\Command $command
7+
*/
58
interface Hook
69
{
710
/**
811
* Get hook name
912
*
1013
* @return string
1114
*/
12-
public function getName(): string;
15+
public function getName(): ?string;
1316
}

src/Contracts/HookCommand.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,11 @@ interface HookCommand
66
{
77
/**
88
* Get hook name
9-
*
10-
* @return string
119
*/
1210
public function getHook(): string;
1311

1412
/**
1513
* Get array of registered hooks
16-
*
17-
* @return array
1814
*/
1915
public function getRegisteredHooks(): array;
2016
}

src/Contracts/MessageHook.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,5 @@
77

88
interface MessageHook extends Hook
99
{
10-
/**
11-
* @param CommitMessage $message
12-
* @param Closure $next
13-
*/
1410
public function handle(CommitMessage $message, Closure $next);
1511
}

0 commit comments

Comments
 (0)