• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

PHPCSStandards / PHP_CodeSniffer / 17663981080

12 Sep 2025 03:49AM UTC coverage: 78.786%. Remained the same
17663981080

push

github

web-flow
Merge pull request #1245 from PHPCSStandards/phpcs-4.x/feature/155-normalize-some-code-style-rules-7

CS: normalize code style rules [7]

677 of 1022 new or added lines in 17 files covered. (66.24%)

7 existing lines in 1 file now uncovered.

19732 of 25045 relevant lines covered (78.79%)

96.47 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/Reports/VersionControl.php
1
<?php
2
/**
3
 * Version control report base class for PHP_CodeSniffer.
4
 *
5
 * @author    Ben Selby <benmatselby@gmail.com>
6
 * @author    Greg Sherwood <gsherwood@squiz.net>
7
 * @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
8
 * @license   https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
9
 */
10

11
namespace PHP_CodeSniffer\Reports;
12

13
use PHP_CodeSniffer\Files\File;
14

15
abstract class VersionControl implements Report
16
{
17

18
    /**
19
     * The name of the report we want in the output.
20
     *
21
     * @var string
22
     */
23
    protected $reportName = 'VERSION CONTROL';
24

25

26
    /**
27
     * Generate a partial report for a single processed file.
28
     *
29
     * Function should return TRUE if it printed or stored data about the file
30
     * and FALSE if it ignored the file. Returning TRUE indicates that the file and
31
     * its data should be counted in the grand totals.
32
     *
33
     * @param array<string, string|int|array> $report      Prepared report data.
34
     *                                                     See the {@see Report} interface for a detailed specification.
35
     * @param \PHP_CodeSniffer\Files\File     $phpcsFile   The file being reported on.
36
     * @param bool                            $showSources Show sources?
37
     * @param int                             $width       Maximum allowed line width.
38
     *
39
     * @return bool
40
     */
41
    public function generateFileReport(array $report, File $phpcsFile, bool $showSources = false, int $width = 80)
×
42
    {
43
        $blames = $this->getBlameContent($phpcsFile->getFilename());
×
44

45
        $authorCache = [];
×
46
        $praiseCache = [];
×
47
        $sourceCache = [];
×
48

49
        foreach ($report['messages'] as $line => $lineErrors) {
×
50
            $author = 'Unknown';
×
51
            if (isset($blames[($line - 1)]) === true) {
×
52
                $blameAuthor = $this->getAuthor($blames[($line - 1)]);
×
53
                if ($blameAuthor !== false) {
×
54
                    $author = $blameAuthor;
×
55
                }
56
            }
57

58
            if (isset($authorCache[$author]) === false) {
×
59
                $authorCache[$author] = 0;
×
60
                $praiseCache[$author] = [
×
61
                    'good' => 0,
×
62
                    'bad'  => 0,
×
63
                ];
×
64
            }
65

66
            $praiseCache[$author]['bad']++;
×
67

68
            foreach ($lineErrors as $colErrors) {
×
69
                foreach ($colErrors as $error) {
×
70
                    $authorCache[$author]++;
×
71

72
                    if ($showSources === true) {
×
73
                        $source = $error['source'];
×
74
                        if (isset($sourceCache[$author][$source]) === false) {
×
75
                            $sourceCache[$author][$source] = [
×
76
                                'count'   => 1,
×
77
                                'fixable' => $error['fixable'],
×
78
                            ];
×
79
                        } else {
80
                            $sourceCache[$author][$source]['count']++;
×
81
                        }
82
                    }
83
                }
84
            }
85

86
            unset($blames[($line - 1)]);
×
87
        }
88

89
        // Now go through and give the authors some credit for
90
        // all the lines that do not have errors.
91
        foreach ($blames as $line) {
×
92
            $author = $this->getAuthor($line);
×
93
            if ($author === false) {
×
94
                $author = 'Unknown';
×
95
            }
96

97
            if (isset($authorCache[$author]) === false) {
×
98
                // This author doesn't have any errors.
99
                if (PHP_CODESNIFFER_VERBOSITY === 0) {
×
100
                    continue;
×
101
                }
102

103
                $authorCache[$author] = 0;
×
104
                $praiseCache[$author] = [
×
105
                    'good' => 0,
×
106
                    'bad'  => 0,
×
107
                ];
×
108
            }
109

110
            $praiseCache[$author]['good']++;
×
111
        }
112

113
        foreach ($authorCache as $author => $errors) {
×
114
            echo "AUTHOR>>$author>>$errors" . PHP_EOL;
×
115
        }
116

117
        foreach ($praiseCache as $author => $praise) {
×
118
            echo "PRAISE>>$author>>" . $praise['good'] . '>>' . $praise['bad'] . PHP_EOL;
×
119
        }
120

121
        foreach ($sourceCache as $author => $sources) {
×
122
            foreach ($sources as $source => $sourceData) {
×
123
                $count   = $sourceData['count'];
×
124
                $fixable = (int) $sourceData['fixable'];
×
125
                echo "SOURCE>>$author>>$source>>$count>>$fixable" . PHP_EOL;
×
126
            }
127
        }
128

129
        return true;
×
130
    }
131

132

133
    /**
134
     * Prints the author of all errors and warnings, as given by "version control blame".
135
     *
136
     * @param string $cachedData    Any partial report data that was returned from
137
     *                              generateFileReport during the run.
138
     * @param int    $totalFiles    Total number of files processed during the run.
139
     * @param int    $totalErrors   Total number of errors found during the run.
140
     * @param int    $totalWarnings Total number of warnings found during the run.
141
     * @param int    $totalFixable  Total number of problems that can be fixed.
142
     * @param bool   $showSources   Show sources?
143
     * @param int    $width         Maximum allowed line width.
144
     * @param bool   $interactive   Are we running in interactive mode?
145
     * @param bool   $toScreen      Is the report being printed to screen?
146
     *
147
     * @return void
148
     */
149
    public function generate(
×
150
        string $cachedData,
151
        int $totalFiles,
152
        int $totalErrors,
153
        int $totalWarnings,
154
        int $totalFixable,
155
        bool $showSources = false,
156
        int $width = 80,
157
        bool $interactive = false,
158
        bool $toScreen = true
159
    ) {
160
        $errorsShown = ($totalErrors + $totalWarnings);
×
161
        if ($errorsShown === 0) {
×
162
            // Nothing to show.
163
            return;
×
164
        }
165

166
        $lines = explode(PHP_EOL, $cachedData);
×
167
        array_pop($lines);
×
168

169
        if (empty($lines) === true) {
×
170
            return;
×
171
        }
172

173
        $authorCache = [];
×
174
        $praiseCache = [];
×
175
        $sourceCache = [];
×
176

177
        foreach ($lines as $line) {
×
178
            $parts = explode('>>', $line);
×
179
            switch ($parts[0]) {
×
NEW
180
                case 'AUTHOR':
×
NEW
181
                    if (isset($authorCache[$parts[1]]) === false) {
×
NEW
182
                        $authorCache[$parts[1]] = $parts[2];
×
183
                    } else {
NEW
184
                        $authorCache[$parts[1]] += $parts[2];
×
185
                    }
NEW
186
                    break;
×
NEW
187
                case 'PRAISE':
×
NEW
188
                    if (isset($praiseCache[$parts[1]]) === false) {
×
NEW
189
                        $praiseCache[$parts[1]] = [
×
NEW
190
                            'good' => $parts[2],
×
NEW
191
                            'bad'  => $parts[3],
×
NEW
192
                        ];
×
193
                    } else {
NEW
194
                        $praiseCache[$parts[1]]['good'] += $parts[2];
×
NEW
195
                        $praiseCache[$parts[1]]['bad']  += $parts[3];
×
196
                    }
NEW
197
                    break;
×
NEW
198
                case 'SOURCE':
×
NEW
199
                    if (isset($praiseCache[$parts[1]]) === false) {
×
NEW
200
                        $praiseCache[$parts[1]] = [];
×
201
                    }
202

NEW
203
                    if (isset($sourceCache[$parts[1]][$parts[2]]) === false) {
×
NEW
204
                        $sourceCache[$parts[1]][$parts[2]] = [
×
NEW
205
                            'count'   => $parts[3],
×
NEW
206
                            'fixable' => (bool) $parts[4],
×
NEW
207
                        ];
×
208
                    } else {
NEW
209
                        $sourceCache[$parts[1]][$parts[2]]['count'] += $parts[3];
×
210
                    }
NEW
211
                    break;
×
212
                default:
NEW
213
                    break;
×
214
            }
215
        }
216

217
        // Make sure the report width isn't too big.
218
        $maxLength = 0;
×
219
        foreach ($authorCache as $author => $count) {
×
220
            $maxLength = max($maxLength, strlen($author));
×
221
            if ($showSources === true && isset($sourceCache[$author]) === true) {
×
222
                foreach ($sourceCache[$author] as $source => $sourceData) {
×
223
                    if ($source === 'count') {
×
224
                        continue;
×
225
                    }
226

227
                    $maxLength = max($maxLength, (strlen($source) + 9));
×
228
                }
229
            }
230
        }
231

232
        $width = min($width, ($maxLength + 30));
×
233
        $width = max($width, 70);
×
234
        arsort($authorCache);
×
235

236
        echo PHP_EOL . "\033[1m" . 'PHP CODE SNIFFER ' . $this->reportName . ' BLAME SUMMARY' . "\033[0m" . PHP_EOL;
×
237
        echo str_repeat('-', $width) . PHP_EOL . "\033[1m";
×
238
        if ($showSources === true) {
×
239
            echo 'AUTHOR   SOURCE' . str_repeat(' ', ($width - 43)) . '(Author %) (Overall %) COUNT' . PHP_EOL;
×
240
            echo str_repeat('-', $width) . PHP_EOL;
×
241
        } else {
242
            echo 'AUTHOR' . str_repeat(' ', ($width - 34)) . '(Author %) (Overall %) COUNT' . PHP_EOL;
×
243
            echo str_repeat('-', $width) . PHP_EOL;
×
244
        }
245

246
        echo "\033[0m";
×
247

248
        if ($showSources === true) {
×
249
            $maxSniffWidth = ($width - 15);
×
250

251
            if ($totalFixable > 0) {
×
252
                $maxSniffWidth -= 4;
×
253
            }
254
        }
255

256
        $fixableSources = 0;
×
257

258
        foreach ($authorCache as $author => $count) {
×
259
            if ($praiseCache[$author]['good'] === 0) {
×
260
                $percent = 0;
×
261
            } else {
262
                $total   = ($praiseCache[$author]['bad'] + $praiseCache[$author]['good']);
×
263
                $percent = round(($praiseCache[$author]['bad'] / $total * 100), 2);
×
264
            }
265

266
            $overallPercent = '(' . round((($count / $errorsShown) * 100), 2) . ')';
×
267
            $authorPercent  = '(' . $percent . ')';
×
268
            $line           = str_repeat(' ', (6 - strlen($count))) . $count;
×
269
            $line           = str_repeat(' ', (12 - strlen($overallPercent))) . $overallPercent . $line;
×
270
            $line           = str_repeat(' ', (11 - strlen($authorPercent))) . $authorPercent . $line;
×
271
            $line           = $author . str_repeat(' ', ($width - strlen($author) - strlen($line))) . $line;
×
272

273
            if ($showSources === true) {
×
274
                $line = "\033[1m$line\033[0m";
×
275
            }
276

277
            echo $line . PHP_EOL;
×
278

279
            if ($showSources === true && isset($sourceCache[$author]) === true) {
×
280
                $errors = $sourceCache[$author];
×
281
                asort($errors);
×
282
                $errors = array_reverse($errors);
×
283

284
                foreach ($errors as $source => $sourceData) {
×
285
                    if ($source === 'count') {
×
286
                        continue;
×
287
                    }
288

289
                    $count = $sourceData['count'];
×
290

291
                    $srcLength = strlen($source);
×
292
                    if ($srcLength > $maxSniffWidth) {
×
293
                        $source = substr($source, 0, $maxSniffWidth);
×
294
                    }
295

296
                    $line = str_repeat(' ', (5 - strlen($count))) . $count;
×
297

298
                    echo '         ';
×
299
                    if ($totalFixable > 0) {
×
300
                        echo '[';
×
301
                        if ($sourceData['fixable'] === true) {
×
302
                            echo 'x';
×
303
                            $fixableSources++;
×
304
                        } else {
305
                            echo ' ';
×
306
                        }
307

308
                        echo '] ';
×
309
                    }
310

311
                    echo $source;
×
312
                    if ($totalFixable > 0) {
×
313
                        echo str_repeat(' ', ($width - 18 - strlen($source)));
×
314
                    } else {
315
                        echo str_repeat(' ', ($width - 14 - strlen($source)));
×
316
                    }
317

318
                    echo $line . PHP_EOL;
×
319
                }
320
            }
321
        }
322

323
        echo str_repeat('-', $width) . PHP_EOL;
×
324
        echo "\033[1m" . 'A TOTAL OF ' . $errorsShown . ' SNIFF VIOLATION';
×
325
        if ($errorsShown !== 1) {
×
326
            echo 'S';
×
327
        }
328

329
        echo ' WERE COMMITTED BY ' . count($authorCache) . ' AUTHOR';
×
330
        if (count($authorCache) !== 1) {
×
331
            echo 'S';
×
332
        }
333

334
        echo "\033[0m";
×
335

336
        if ($totalFixable > 0) {
×
337
            if ($showSources === true) {
×
338
                echo PHP_EOL . str_repeat('-', $width) . PHP_EOL;
×
339
                echo "\033[1mPHPCBF CAN FIX THE $fixableSources MARKED SOURCES AUTOMATICALLY ($totalFixable VIOLATIONS IN TOTAL)\033[0m";
×
340
            } else {
341
                echo PHP_EOL . str_repeat('-', $width) . PHP_EOL;
×
342
                echo "\033[1mPHPCBF CAN FIX $totalFixable OF THESE SNIFF VIOLATIONS AUTOMATICALLY\033[0m";
×
343
            }
344
        }
345

346
        echo PHP_EOL . str_repeat('-', $width) . PHP_EOL . PHP_EOL;
×
347
    }
348

349

350
    /**
351
     * Extract the author from a blame line.
352
     *
353
     * @param string $line Line to parse.
354
     *
355
     * @return mixed string or false if impossible to recover.
356
     */
357
    abstract protected function getAuthor(string $line);
358

359

360
    /**
361
     * Gets the blame output.
362
     *
363
     * @param string $filename File to blame.
364
     *
365
     * @return array
366
     */
367
    abstract protected function getBlameContent(string $filename);
368
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc