Passed
Push — main ( 394fb3...82ed03 )
by Sebastian
03:26
created

Book::validate()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 12
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 6
c 1
b 0
f 0
nc 3
nop 3
dl 0
loc 12
ccs 7
cts 7
cp 1
crap 3
rs 10
1
<?php
2
3
/**
4
 * This file is part of CaptainHook
5
 *
6
 * (c) Sebastian Feldmann <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace CaptainHook\App\Hook\Message\Action;
13
14
use CaptainHook\App\Config;
15
use CaptainHook\App\Console\IO;
16
use CaptainHook\App\Console\IOUtil;
17
use CaptainHook\App\Exception\ActionFailed;
18
use CaptainHook\App\Hook\Action;
19
use CaptainHook\App\Hook\Constrained;
20
use CaptainHook\App\Hook\Message\RuleBook;
21
use CaptainHook\App\Hook\Restriction;
22
use CaptainHook\App\Hooks;
23
use SebastianFeldmann\Cli\Output\Util as OutputUtil;
24
use SebastianFeldmann\Git\Repository;
25
26
/**
27
 * Class Book
28
 *
29
 * @package CaptainHook
30
 * @author  Sebastian Feldmann <[email protected]>
31
 * @link    https://github.com/captainhookphp/captainhook
32
 * @since   Class available since Release 0.9.0
33
 */
34
abstract class Book implements Action, Constrained
35
{
36
    /**
37
     * Returns a list of applicable hooks
38
     *
39
     * @return \CaptainHook\App\Hook\Restriction
40
     */
41 1
    public static function getRestriction(): Restriction
42
    {
43 1
        return Restriction::fromArray([Hooks::COMMIT_MSG]);
44
    }
45
46
    /**
47
     * Execute the configured action
48
     *
49
     * @param  \CaptainHook\App\Config           $config
50
     * @param  \CaptainHook\App\Console\IO       $io
51
     * @param  \SebastianFeldmann\Git\Repository $repository
52
     * @param  \CaptainHook\App\Config\Action    $action
53
     * @return void
54
     * @throws \Exception
55
     */
56
    abstract public function execute(Config $config, IO $io, Repository $repository, Config\Action $action): void;
57
58
    /**
59
     * Validate the message
60
     *
61
     * @param  \CaptainHook\App\Hook\Message\RuleBook $ruleBook
62
     * @param  \SebastianFeldmann\Git\Repository      $repository
63
     * @param  \CaptainHook\App\Console\IO            $io
64
     * @return void
65
     * @throws \CaptainHook\App\Exception\ActionFailed
66
     */
67 8
    protected function validate(RuleBook $ruleBook, Repository $repository, IO $io): void
68
    {
69
        // if this is a merge commit skip enforcing message rules
70 8
        if ($repository->isMerging()) {
71 1
            return;
72
        }
73
74 7
        $problems = $ruleBook->validate($repository->getCommitMsg());
75
76 7
        if (count($problems)) {
77 3
            $this->errorOutput($problems, $io, $repository);
78 3
            throw new ActionFailed('commit message validation failed');
79
        }
80
    }
81
82
    /**
83
     * Write the error message
84
     *
85
     * @param array<string>                     $problems
86
     * @param \CaptainHook\App\Console\IO       $io
87
     * @param \SebastianFeldmann\Git\Repository $repository
88
     * @return void
89
     */
90 3
    private function errorOutput(array $problems, IO $io, Repository $repository): void
91
    {
92 3
        $s = count($problems) > 1 ? 's' : '';
93 3
        $io->write('found ' . count($problems) . ' problem' . $s . ' in your commit message');
94 3
        foreach ($problems as $problem) {
95 3
            $io->write($this->formatProblem($problem));
96
        }
97 3
        $io->write('<comment>--------------------------------------------[ your original message ]----</comment>');
98 3
        $io->write(OutputUtil::trimEmptyLines($repository->getCommitMsg()->getLines()));
99 3
        $io->write('<comment>-------------------------------------------------------------------------</comment>');
100
    }
101
102
    /**
103
     * Indent multi line problems so the lines after the first one are indented for better readability
104
     *
105
     * @param  string $problem
106
     * @return array<string>
107
     */
108 3
    private function formatProblem(string $problem): array
109
    {
110 3
        $lines = explode(PHP_EOL, $problem);
111 3
        foreach ($lines as $index => $line) {
112 3
            $lines[$index] = '  ' . $line;
113
        }
114 3
        return $lines;
115
    }
116
}
117