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

PHPCSStandards / PHP_CodeSniffer / 15253296250

26 May 2025 11:55AM UTC coverage: 78.632% (+0.3%) from 78.375%
15253296250

Pull #1105

github

web-flow
Merge d9441d98f into caf806050
Pull Request #1105: Skip tests when 'git' command is not available

19665 of 25009 relevant lines covered (78.63%)

88.67 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($report, File $phpcsFile, $showSources=false, $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
        }//end foreach
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
        }//end foreach
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
    }//end generateFileReport()
132

133

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

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

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

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

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

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

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

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

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

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

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

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

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

257
        $fixableSources = 0;
×
258

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

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

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

278
            echo $line.PHP_EOL;
×
279

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

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

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

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

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

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

309
                        echo '] ';
×
310
                    }
311

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

319
                    echo $line.PHP_EOL;
×
320
                }//end foreach
321
            }//end if
322
        }//end foreach
323

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

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

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

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

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

349
    }//end generate()
350

351

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

361

362
    /**
363
     * Gets the blame output.
364
     *
365
     * @param string $filename File to blame.
366
     *
367
     * @return array
368
     */
369
    abstract protected function getBlameContent($filename);
370

371

372
}//end class
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