|
| 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