Skip to content

Commit 952e9ae

Browse files
committed
Merge branch 'master' into develop
2 parents 993f56a + 20801ed commit 952e9ae

23 files changed

+523
-34
lines changed

src/Console/Commands/Hooks/BaseCodeAnalyzerPreCommitHook.php

Lines changed: 48 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use Igorsgm\GitHooks\Git\ChangedFiles;
1010
use Igorsgm\GitHooks\Traits\ProcessHelper;
1111
use Illuminate\Console\Command;
12+
use Illuminate\Support\Collection;
1213
use Symfony\Component\Console\Terminal;
1314

1415
abstract class BaseCodeAnalyzerPreCommitHook
@@ -93,14 +94,15 @@ public function handleCommittedFiles(ChangedFiles $files, Closure $next)
9394
}
9495

9596
/**
96-
* Analyzes the committed files and checks if they are properly formatted.
97+
* Analyzes an array of ChangedFile objects and checks whether each file can be analyzed,
98+
* whether it is properly formatted according to the configured analyzer, and collects
99+
* paths of any files that are not properly formatted.
97100
*
98-
* @param mixed $commitFiles The files to analyze.
101+
* @param ChangedFile[]|Collection $commitFiles The files to analyze.
99102
* @return $this
100103
*/
101104
protected function analizeCommittedFiles($commitFiles)
102105
{
103-
/** @var ChangedFile $file */
104106
foreach ($commitFiles as $file) {
105107
if (! $this->canFileBeAnalyzed($file)) {
106108
continue;
@@ -181,6 +183,14 @@ protected function validateAnalyzerInstallation()
181183
throw new HookFailException();
182184
}
183185

186+
/**
187+
* Validates the given configuration path.
188+
*
189+
* @param string $path The path to the configuration file.
190+
* @return $this This instance for method chaining.
191+
*
192+
* @throws HookFailException If the configuration file does not exist.
193+
*/
184194
protected function validateConfigPath($path)
185195
{
186196
if (file_exists($path)) {
@@ -199,27 +209,50 @@ protected function validateConfigPath($path)
199209

200210
/**
201211
* Suggests attempting to automatically fix the incorrectly formatted files or exit.
202-
*
203-
* @return void
212+
* If any files cannot be fixed, throws a HookFailException to cancel the commit.
204213
*
205214
* @throws HookFailException
206215
*/
207-
protected function suggestAutoFixOrExit()
216+
protected function suggestAutoFixOrExit(): bool
208217
{
209218
$hasFixerCommand = ! empty($this->fixerCommand());
210219

211220
if ($hasFixerCommand && Terminal::hasSttyAvailable() &&
212-
$this->command->confirm('Would you like to attempt to correct files automagically?')
221+
$this->command->confirm('Would you like to attempt to correct files automagically?') &&
222+
$this->autoFixFiles()
213223
) {
214-
$errorFilesString = implode(' ', $this->filesBadlyFormattedPaths);
215-
216-
$this->runCommands([
217-
$this->fixerCommand().' '.$errorFilesString,
218-
'git add '.$errorFilesString,
219-
]);
220-
} else {
221-
throw new HookFailException();
224+
return true;
225+
}
226+
227+
throw new HookFailException();
228+
}
229+
230+
/**
231+
* Automatically fixes any files in the `$filesBadlyFormattedPaths` array using the
232+
* configured fixer command. For each fixed file, adds it to Git and removes its path
233+
* from the `$filesBadlyFormattedPaths` array.
234+
*
235+
*
236+
* @throws HookFailException if any files cannot be fixed.
237+
*/
238+
private function autoFixFiles(): bool
239+
{
240+
foreach ($this->filesBadlyFormattedPaths as $key => $filePath) {
241+
$wasProperlyFixed = $this->runCommands($this->fixerCommand().' '.$filePath)->isSuccessful();
242+
243+
if ($wasProperlyFixed) {
244+
$this->runCommands('git add '.$filePath);
245+
unset($this->filesBadlyFormattedPaths[$key]);
246+
247+
continue;
248+
}
249+
250+
$this->command->getOutput()->writeln(
251+
sprintf('<fg=red> %s Autofix Failed:</> %s', $this->getName(), $filePath)
252+
);
222253
}
254+
255+
return empty($this->filesBadlyFormattedPaths);
223256
}
224257

225258
/**

src/Console/Commands/Hooks/PintPreCommitHook.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,7 @@ protected function configParam(): string
6161
{
6262
$pintConfigFile = config('git-hooks.code_analyzers.laravel_pint.config');
6363

64-
if (! empty($pintConfigFile)) {
65-
$this->validateConfigPath($pintConfigFile);
66-
64+
if (! empty($pintConfigFile) && $this->validateConfigPath($pintConfigFile)) {
6765
return '--config '.trim($pintConfigFile, '/');
6866
}
6967

src/Console/Commands/MakeHook.php

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
<?php
2+
3+
namespace Igorsgm\GitHooks\Console\Commands;
4+
5+
use Igorsgm\GitHooks\Facades\GitHooks;
6+
use Illuminate\Console\Concerns\CreatesMatchingTest;
7+
use Illuminate\Console\GeneratorCommand;
8+
use Illuminate\Support\Str;
9+
use Symfony\Component\Console\Input\InputArgument;
10+
use Symfony\Component\Console\Input\InputOption;
11+
12+
class MakeHook extends GeneratorCommand
13+
{
14+
use CreatesMatchingTest;
15+
16+
/**
17+
* The console command name.
18+
*
19+
* @var string
20+
*/
21+
protected $name = 'git-hooks:make';
22+
23+
/**
24+
* The console command description.
25+
*
26+
* @var string
27+
*/
28+
protected $description = 'Create a new Hook';
29+
30+
/**
31+
* The type of class being generated.
32+
*
33+
* @var string
34+
*/
35+
protected $type = 'Git Hook';
36+
37+
/**
38+
* Execute the console command.
39+
*
40+
* @return bool|null
41+
*
42+
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
43+
*/
44+
public function handle()
45+
{
46+
$supportedHooks = GitHooks::getSupportedHooks();
47+
48+
if (! in_array($this->argument('hookType'), $supportedHooks)) {
49+
$this->getOutput()->writeln(sprintf(
50+
'<bg=red;fg=white> ERROR </> Invalid hook type. Valid types are: <comment>%s</comment>',
51+
implode(', ', $supportedHooks)
52+
));
53+
54+
return 1;
55+
}
56+
57+
return parent::handle();
58+
}
59+
60+
/**
61+
* Replace the class name for the given stub.
62+
*
63+
* @param string $stub
64+
* @param string $name
65+
* @return string
66+
*/
67+
protected function replaceClass($stub, $name)
68+
{
69+
$stub = parent::replaceClass($stub, $name);
70+
71+
$hookName = Str::of($name)->classBasename()->snake()->replace('_', ' ')->title()->value();
72+
73+
return str_replace(['{{ hookName }}'], $hookName, $stub);
74+
}
75+
76+
/**
77+
* Get the stub file for the generator.
78+
*
79+
* @return string
80+
*/
81+
protected function getStub()
82+
{
83+
$relativePath = '/stubs/'.$this->argument('hookType').'-console.stub';
84+
85+
return file_exists($customPath = $this->laravel->basePath(trim($relativePath, '/')))
86+
? $customPath
87+
: __DIR__.$relativePath;
88+
}
89+
90+
/**
91+
* Get the default namespace for the class.
92+
*
93+
* @param string $rootNamespace
94+
* @return string
95+
*/
96+
protected function getDefaultNamespace($rootNamespace)
97+
{
98+
return $rootNamespace.'\Console\GitHooks';
99+
}
100+
101+
/**
102+
* Get the console command arguments.
103+
*
104+
* @return array
105+
*/
106+
protected function getArguments()
107+
{
108+
return [
109+
['hookType', InputArgument::REQUIRED, 'The type of the Git Hook', null, GitHooks::getSupportedHooks()],
110+
['name', InputArgument::REQUIRED, 'The name of the Git Hook'],
111+
];
112+
}
113+
114+
/**
115+
* Get the console command options.
116+
*
117+
* @return array
118+
*/
119+
protected function getOptions()
120+
{
121+
return [
122+
['force', 'f', InputOption::VALUE_NONE, 'Create the class even if the Git Hook already exists'],
123+
];
124+
}
125+
126+
/**
127+
* Prompt for missing input arguments using the returned questions.
128+
*
129+
* @return array
130+
*/
131+
protected function promptForMissingArgumentsUsing()
132+
{
133+
$supportedHooks = implode(', ', GitHooks::getSupportedHooks());
134+
135+
return [
136+
'name' => 'What should the '.strtolower($this->type).' be named?',
137+
'hookType' => 'What type of the '.strtolower($this->type)."? Possible values: ($supportedHooks)",
138+
];
139+
}
140+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
<?php
2+
3+
namespace {{ namespace }};
4+
5+
use Closure;
6+
use Igorsgm\GitHooks\Git\CommitMessage;
7+
use Igorsgm\GitHooks\Contracts\MessageHook;
8+
9+
class {{ class }} implements MessageHook
10+
{
11+
/**
12+
* Get the name of the hook.
13+
*/
14+
public function getName(): ?string
15+
{
16+
return '{{ hookName }}';
17+
}
18+
19+
/**
20+
* Execute the Hook.
21+
*
22+
* @param CommitMessage $message The commit message.
23+
* @param Closure $next The next hook in the chain to execute.
24+
* @return mixed|null
25+
*/
26+
public function handle(CommitMessage $message, Closure $next)
27+
{
28+
// TODO: Implement your commit msg hook logic here.
29+
30+
$currentMessage = $message->getMessage();
31+
// You can update commit message text
32+
$message->setMessage(str_replace('issue', 'fixed', $currentMessage));
33+
34+
// If you want to cancel the commit, you have to throw an exception.
35+
// i.e: throw new HookFailException();
36+
37+
// Run the next hook in the chain
38+
return $next($message);
39+
}
40+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace {{ namespace }};
4+
5+
use Closure;
6+
use Igorsgm\GitHooks\Git\Log;
7+
use Igorsgm\GitHooks\Contracts\PostCommitHook;
8+
9+
class {{ class }} implements PostCommitHook
10+
{
11+
/**
12+
* Get the name of the hook.
13+
*/
14+
public function getName(): ?string
15+
{
16+
return '{{ hookName }}';
17+
}
18+
19+
/**
20+
* Execute the Hook.
21+
*
22+
* @param Log $log
23+
* @param Closure $next The next hook in the chain to execute.
24+
* @return mixed|null
25+
*/
26+
public function handle(Log $log, Closure $next)
27+
{
28+
// TODO: Implement post commit hook logic here.
29+
30+
// You can interact with the commit log
31+
$hash = $log->getHash();
32+
$author = $log->getAuthor();
33+
$date = $log->getDate();
34+
$message = $log->getMessage();
35+
36+
// If you want to cancel the commit, you have to throw an exception.
37+
// i.e: throw new HookFailException();
38+
39+
// Run the next hook in the chain
40+
return $next($log);
41+
}
42+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
namespace {{ namespace }};
4+
5+
use Closure;
6+
use Igorsgm\GitHooks\Git\ChangedFiles;
7+
use Igorsgm\GitHooks\Contracts\PreCommitHook;
8+
9+
class {{ class }} implements PreCommitHook
10+
{
11+
/**
12+
* Get the name of the hook.
13+
*/
14+
public function getName(): ?string
15+
{
16+
return '{{ hookName }}';
17+
}
18+
19+
/**
20+
* Execute the Hook.
21+
*
22+
* @param ChangedFiles $files The list of changed files to analyze.
23+
* @param Closure $next The next hook in the chain to execute.
24+
* @return mixed|null
25+
*/
26+
public function handle(ChangedFiles $files, Closure $next)
27+
{
28+
// TODO: Implement your pre commit hook logic here.
29+
30+
// If you want to cancel the commit, you have to throw an exception.
31+
// i.e: throw new HookFailException();
32+
33+
// Run the next hook in the chain
34+
return $next($files);
35+
}
36+
}

0 commit comments

Comments
 (0)