PhpStan::canExecuteOnStage()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 2
1
<?php
2
3
namespace Fabrica\Tools\Plugin;
4
5
use Fabrica\Tools;
6
use Fabrica\Tools\Builder;
7
use Fabrica\Models\Infra\Ci\Build;
8
use Fabrica\Models\Infra\Ci\BuildError;
9
use Fabrica\Tools\Plugin;
10
11
/**
12
 * PHPStan focuses on finding errors in your code without actually running it. It catches whole classes of bugs even
13
 * before you write tests for the code. It moves PHP closer to compiled languages in the sense that the correctness of
14
 * each line of the code can be checked before you run the actual line.
15
 * https://github.com/phpstan/phpstan
16
 */
17
class PhpStan extends Plugin
18
{
19
    /**
20
     * @var int 
21
     */
22
    protected $allowedErrors = 0;
23
24
    /**
25
     * @param Builder $builder
26
     * @param Build   $build
27
     * @param array   $options
28
     *
29
     * @throws \Exception
30
     */
31 View Code Duplication
    public function __construct(Builder $builder, Build $build, array $options = [])
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
32
    {
33
        parent::__construct($builder, $build, $options);
34
35
        $this->executable = $this->findBinary('phpstan');
36
37
        if (isset($options['allowed_errors']) && \is_int($options['allowed_errors'])) {
38
            $this->allowedErrors = $options['allowed_errors'];
39
        }
40
    }
41
42
    /**
43
     * @return bool
44
     */
45
    public function execute()
46
    {
47
        $phpstan = $this->executable;
48
49 View Code Duplication
        if ((!\defined('DEBUG_MODE') || !DEBUG_MODE) && !(bool)$this->build->getExtra('debug')) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
50
            $this->builder->logExecOutput(false);
51
        }
52
53
        $this->builder->executeCommand(
54
            'cd "%s" && ' . $phpstan . ' analyze --error-format=json',
55
            $this->builder->buildPath
56
        );
57
        $this->builder->logExecOutput(true);
58
59
        // Define that the plugin succeed
60
        $success = true;
61
62
        list($total_errors, $files) = $this->processReport($this->builder->getLastOutput());
63
64
        if (0 < $total_errors) {
65
            if (-1 !== $this->allowedErrors && $total_errors > $this->allowedErrors) {
66
                $success = false;
67
            }
68
69
            foreach ($files as $file => $payload) {
70
                if (0 < $payload['errors']) {
71
                    $file = \str_replace($this->build->getBuildPath(), '', $file);
72
                    $len = \strlen($file);
73
                    $out = '';
74
                    $filename = (false !== \strpos($file, ' (')) ? \strstr($file, ' (', true) : $file;
75
76
                    foreach ($payload['messages'] as $message) {
77
                        if (\strlen($message['message']) > $len) {
78
                            $len = \strlen($message['message']);
79
                        }
80
                        $out .= \vsprintf(
81
                            ' %d%s %s' . PHP_EOL, [
82
                            $message['line'],
83
                            \str_repeat(' ', 6 - \strlen($message['line'])),
84
                            $message['message']
85
                            ]
86
                        );
87
88
                        $this->build->reportError(
89
                            $this->builder,
90
                            self::pluginName(),
91
                            $message['message'],
92
                            BuildError::SEVERITY_NORMAL,
93
                            $filename,
94
                            $message['line']
95
                        );
96
                    }
97
                    $separator = \str_repeat('-', 6) . ' ' . \str_repeat('-', $len + 2) . PHP_EOL;
98
99
                    $this->builder->logFailure(
100
                        \vsprintf(
101
                            '%s Line   %s' . PHP_EOL . '%s', [
102
                            $separator,
103
                            $file,
104
                            $separator . $out . $separator
105
                            ]
106
                        )
107
                    );
108
                }
109
            }
110
        }
111
112
        if ($success) {
113
            $this->builder->logSuccess('[OK] No errors');
114
        } else {
115
            $this->builder->log(\sprintf('[ERROR] Found %d errors', $total_errors));
116
        }
117
118
        return $success;
119
    }
120
121
    /**
122
     * @return string
123
     */
124
    public static function pluginName()
125
    {
126
        return 'phpstan';
127
    }
128
129
    /**
130
     * @param string $stage
131
     * @param Build  $build
132
     *
133
     * @return bool
134
     */
135
    public static function canExecuteOnStage($stage, Build $build)
0 ignored issues
show
Unused Code introduced by
The parameter $build is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
136
    {
137
        return Build::STAGE_TEST === $stage;
138
    }
139
140
    /**
141
     * @param  string $output
142
     * @return array
143
     */
144
    protected function processReport($output)
145
    {
146
        $data = \json_decode(\trim($output), true);
147
148
        $totalErrors = 0;
149
        $files        = [];
150
151
        if (!empty($data) && \is_array($data) && (0 < $data['totals']['file_errors'])) {
152
            $totalErrors = $data['totals']['file_errors'];
153
            $files = $data['files'];
154
        }
155
156
        return [$totalErrors, $files];
157
    }
158
}
159