Skip to content

Commit 5a28d30

Browse files
NGSTACK-938 add new hooks for linter, prettier and ts compiler
1 parent c116d7c commit 5a28d30

File tree

3 files changed

+193
-0
lines changed

3 files changed

+193
-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: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
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+
* @return array<string, mixed>
37+
*/
38+
protected function checkLinter(array $directories, string $linterCommand): array
39+
{
40+
$process = new Processor();
41+
$cliString = $linterCommand;
42+
43+
foreach ($directories as $directory) {
44+
$cliString .= ' ' . escapeshellarg($directory);
45+
}
46+
47+
$result = $process->run($cliString);
48+
49+
return [
50+
'success' => $result->isSuccessful(),
51+
'output' => $result->getStdOut(),
52+
];
53+
}
54+
}

src/Action/CheckPrettier.php

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
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+
$extensions = $action->getOptions()->get('extensions', ['js', 'jsx', 'ts', 'tsx', 'css', 'scss']);
26+
$excludedFiles = $action->getOptions()->get('excluded_files') ?? [];
27+
$directories = $action->getOptions()->get('directories', ['assets']);
28+
$prettierCommand = $action->getOptions()->get('prettier_command', 'pnpm prettier');
29+
$formatOptions = $action->getOptions()->get('prettier_options', '--check');
30+
31+
$finder = new Finder();
32+
$finder->in($directories)->files()->name(preg_filter('/^/', '*.', $extensions));
33+
34+
if ($finder->hasResults()) {
35+
$io->write(sprintf('Running %s on files:', $prettierCommand), true, IO::VERBOSE);
36+
37+
foreach ($finder as $file) {
38+
if ($this->shouldSkipFileCheck($file, $excludedFiles)) {
39+
continue;
40+
}
41+
42+
$result = $this->checkPrettier($file->getPath(), $prettierCommand, $formatOptions);
43+
$io->write($result['output']);
44+
45+
if ($result['success'] !== true) {
46+
$this->throwError($action, $io);
47+
}
48+
}
49+
}
50+
}
51+
52+
/**
53+
* @param string[] $excludedFiles
54+
*/
55+
protected function shouldSkipFileCheck(string $file, array $excludedFiles): bool
56+
{
57+
foreach ($excludedFiles as $excludedFile) {
58+
// File definition using regexp
59+
if ($excludedFile[0] === '/') {
60+
if (preg_match($excludedFile, $file) === 1) {
61+
return true;
62+
}
63+
64+
continue;
65+
}
66+
if ($excludedFile === $file) {
67+
return true;
68+
}
69+
}
70+
71+
return false;
72+
}
73+
74+
/**
75+
* @return array<string, mixed>
76+
*/
77+
protected function checkPrettier(string $file, string $prettierCommand, string $prettierOptions): array
78+
{
79+
$process = new Processor();
80+
$result = $process->run($prettierCommand . ' ' . $prettierOptions . ' ' . escapeshellarg($file));
81+
82+
return [
83+
'success' => $result->isSuccessful(),
84+
'output' => $result->getStdOut(),
85+
];
86+
}
87+
}

0 commit comments

Comments
 (0)