Skip to content

Commit 1c1f32c

Browse files
authored
Merge pull request #14 from netgen/NGSTACK-938-new-hooks
HGSTACK-938 new hooks
2 parents c116d7c + d15c095 commit 1c1f32c

File tree

3 files changed

+208
-0
lines changed

3 files changed

+208
-0
lines changed
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Netgen\GitHooks\Action;
6+
7+
use CaptainHook\App\Config;
8+
use CaptainHook\App\Config\Action as ActionConfig;
9+
use CaptainHook\App\Console\IO;
10+
use SebastianFeldmann\Cli\Processor\ProcOpen as Processor;
11+
use SebastianFeldmann\Git\Repository;
12+
13+
use function escapeshellarg;
14+
use function sprintf;
15+
16+
final class CheckForTypescriptErrors extends Action
17+
{
18+
protected const ERROR_MESSAGE = 'Committed code has typescript errors. Please check the output for suggested diff.';
19+
20+
protected function doExecute(Config $config, IO $io, Repository $repository, ActionConfig $action): void
21+
{
22+
$configDirs = $action->getOptions()->get('config_dirs', ['.']);
23+
$typescriptCompilerCommand = $action->getOptions()->get('typescript_compiler_command', 'npx tsc');
24+
$typescriptCompilerOptions = $action->getOptions()->get('typescript_compiler_options', '--noEmit');
25+
26+
$io->write(sprintf('Running %s on files:', $typescriptCompilerCommand), true, IO::VERBOSE);
27+
foreach ($configDirs as $dir) {
28+
$io->write(sprintf(' - %s', $dir), true, IO::VERBOSE);
29+
30+
$result = $this->checkTypescriptErrors($dir, $typescriptCompilerCommand, $typescriptCompilerOptions);
31+
$io->write($result['output']);
32+
33+
if ($result['success'] !== true) {
34+
$this->throwError($action, $io);
35+
}
36+
}
37+
}
38+
39+
/**
40+
* @return array<string, mixed>
41+
*/
42+
protected function checkTypescriptErrors(string $dir, string $typescriptCompilerCommand, string $typescriptCompilerOptions): array
43+
{
44+
$process = new Processor();
45+
$result = $process->run($typescriptCompilerCommand . ' ' . $typescriptCompilerOptions . ' --project ' . escapeshellarg($dir));
46+
47+
return [
48+
'success' => $result->isSuccessful(),
49+
'output' => $result->getStdOut(),
50+
];
51+
}
52+
}

src/Action/CheckLinter.php

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Netgen\GitHooks\Action;
6+
7+
use CaptainHook\App\Config;
8+
use CaptainHook\App\Config\Action as ActionConfig;
9+
use CaptainHook\App\Console\IO;
10+
use SebastianFeldmann\Cli\Processor\ProcOpen as Processor;
11+
use SebastianFeldmann\Git\Repository;
12+
13+
use function escapeshellarg;
14+
use function sprintf;
15+
16+
final class CheckLinter extends Action
17+
{
18+
protected const ERROR_MESSAGE = 'Committed JS code did not pass linter. Please check the output for suggested diff.';
19+
20+
protected function doExecute(Config $config, IO $io, Repository $repository, ActionConfig $action): void
21+
{
22+
$directories = $action->getOptions()->get('directories', ['assets']);
23+
$linterCommand = $action->getOptions()->get('linter_command', 'pnpm eslint');
24+
25+
$io->write(sprintf('Running %s on files:', $linterCommand), true, IO::VERBOSE);
26+
27+
$result = $this->checkLinter($directories, $linterCommand);
28+
$io->write($result['output']);
29+
30+
if ($result['success'] !== true) {
31+
$this->throwError($action, $io);
32+
}
33+
}
34+
35+
/**
36+
* @param string[] $directories
37+
*
38+
* @return array<string, mixed>
39+
*/
40+
protected function checkLinter(array $directories, string $linterCommand): array
41+
{
42+
$process = new Processor();
43+
$cliString = $linterCommand;
44+
45+
foreach ($directories as $directory) {
46+
$cliString .= ' ' . escapeshellarg($directory);
47+
}
48+
49+
$result = $process->run($cliString);
50+
51+
return [
52+
'success' => $result->isSuccessful(),
53+
'output' => $result->getStdOut(),
54+
];
55+
}
56+
}

src/Action/CheckPrettier.php

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Netgen\GitHooks\Action;
6+
7+
use CaptainHook\App\Config;
8+
use CaptainHook\App\Config\Action as ActionConfig;
9+
use CaptainHook\App\Console\IO;
10+
use SebastianFeldmann\Cli\Processor\ProcOpen as Processor;
11+
use SebastianFeldmann\Git\Repository;
12+
use Symfony\Component\Finder\Finder;
13+
14+
use function escapeshellarg;
15+
use function preg_filter;
16+
use function preg_match;
17+
use function sprintf;
18+
19+
final class CheckPrettier extends Action
20+
{
21+
protected const ERROR_MESSAGE = 'Committed code was not formatted correctly. Please check the output for suggested diff.';
22+
23+
protected function doExecute(Config $config, IO $io, Repository $repository, ActionConfig $action): void
24+
{
25+
/** @var string|string[] $extensions */
26+
$extensions = $action->getOptions()->get('extensions', ['js', 'jsx', 'ts', 'tsx', 'css', 'scss']);
27+
$excludedFiles = $action->getOptions()->get('excluded_files') ?? [];
28+
$directories = $action->getOptions()->get('directories', ['assets']);
29+
$prettierCommand = $action->getOptions()->get('prettier_command', 'pnpm prettier');
30+
$formatOptions = $action->getOptions()->get('prettier_options', '--check');
31+
32+
$finder = new Finder();
33+
preg_filter('/^/', '*.', $extensions);
34+
$finder->in($directories)->files()->name($extensions);
35+
36+
if ($finder->hasResults()) {
37+
$io->write(sprintf('Running %s on files:', $prettierCommand));
38+
39+
foreach ($finder as $file) {
40+
if ($this->shouldSkipFileCheck($file->getPath(), $excludedFiles)) {
41+
continue;
42+
}
43+
44+
$result = $this->checkPrettier($file->getPath(), $prettierCommand, $formatOptions);
45+
46+
$io->write(sprintf('<info>%s: </info>', $file->getPath()));
47+
48+
/** @var bool $isResultSuccess */
49+
$isResultSuccess = $result['success'];
50+
51+
if ($isResultSuccess) {
52+
$io->write($result['output']);
53+
} else {
54+
$io->writeError(sprintf('<error>%s</error>', $result['error']));
55+
}
56+
57+
if ($result['success'] !== true) {
58+
$this->throwError($action, $io);
59+
}
60+
}
61+
}
62+
}
63+
64+
/**
65+
* @param string[] $excludedFiles
66+
*/
67+
protected function shouldSkipFileCheck(string $file, array $excludedFiles): bool
68+
{
69+
foreach ($excludedFiles as $excludedFile) {
70+
// File definition using regexp
71+
if ($excludedFile[0] === '/') {
72+
if (preg_match($excludedFile, $file) === 1) {
73+
return true;
74+
}
75+
76+
continue;
77+
}
78+
if ($excludedFile === $file) {
79+
return true;
80+
}
81+
}
82+
83+
return false;
84+
}
85+
86+
/**
87+
* @return array<string, mixed>
88+
*/
89+
protected function checkPrettier(string $file, string $prettierCommand, string $prettierOptions): array
90+
{
91+
$process = new Processor();
92+
$result = $process->run($prettierCommand . ' ' . $prettierOptions . ' ' . escapeshellarg($file));
93+
94+
return [
95+
'success' => $result->isSuccessful(),
96+
'output' => $result->getStdOut(),
97+
'error' => $result->getStdErr(),
98+
];
99+
}
100+
}

0 commit comments

Comments
 (0)