Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added ability to baseline violations #3387

Open
wants to merge 27 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
210b6fc
Create Reporter for setting up baseline.
frankdekker Jul 11, 2021
0ad8647
Add --baselineFile=<path-to-file> to Config
frankdekker Jul 11, 2021
3228d8f
Read in baseline file and skip baselines
frankdekker Jul 11, 2021
d2384e8
Add coverage for baselines files
frankdekker Jul 11, 2021
cccafdb
Add coverage for baselines report
frankdekker Jul 11, 2021
c9523f1
Added phpcbf fixes
frankdekker Jul 11, 2021
2e23a74
Added phpcbf fixes
frankdekker Jul 11, 2021
57e089d
Added phpcbf fixes
frankdekker Jul 11, 2021
8da5a12
Added phpcbf fixes
frankdekker Jul 11, 2021
fae3721
Added phpcbf fixes
frankdekker Jul 11, 2021
0d7d69b
Added phpcbf fixes
frankdekker Jul 11, 2021
3c29275
Added `baselineFile` to the docblocks
frankdekker Jul 11, 2021
54a4c52
Update file doc block
frankdekker Jul 11, 2021
689a9e2
Bugfix, property should be source
frankdekker Jul 11, 2021
2fa8452
Update file doc block
frankdekker Jul 11, 2021
c998baf
Ensure baseline report only outputs unique violations.
frankdekker Jul 11, 2021
2e7fe27
Ensure baseline report only outputs unique violations.
frankdekker Jul 11, 2021
66cba31
Add code signature
frankdekker Jul 31, 2021
688605f
Add code signature
frankdekker Jul 31, 2021
c19a4d7
Update unit tests to solve coverage
frankdekker Jul 31, 2021
62adaa9
Improve performance at checking existence of sniff and signature
frankdekker Aug 1, 2021
7c83e83
Method explanation docblock fix
frankdekker Aug 1, 2021
631499d
Merge pull request #1 from squizlabs/master
frankdekker Jan 5, 2022
02df42b
Merge branch 'master' into Add_ability_to_baseline_errors
frankdekker Jan 5, 2022
82a5efe
Merge branch 'squizlabs:master' into Add_ability_to_baseline_errors
frankdekker Dec 3, 2023
77f579a
Merge branch 'squizlabs:master' into master
frankdekker Dec 3, 2023
2df1ec5
Merge branch 'master' into Add_ability_to_baseline_errors
frankdekker Dec 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions src/Baseline/BaselineSet.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php
/**
* Baseline collection class to store and query baselined violations
*
* @author Frank Dekker <[email protected]>
* @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/

namespace PHP_CodeSniffer\Baseline;

class BaselineSet
{

/**
* A collection of a baselined violations
*
* @var array<string, ViolationBaseline[]>
*/
private $violations = [];


/**
* Add a single entry to the baseline set
*
* @param ViolationBaseline $entry the entry to add to the collection
*
* @return void
*/
public function addEntry(ViolationBaseline $entry)
{
$this->violations[$entry->getSniffName()][$entry->getSignature()][] = $entry;

}//end addEntry()


/**
* Test if the given sniff and filename is in the baseline collection
*
* @param string $sniffName the name of the sniff to search for
* @param string $fileName the full filename of the file to match
* @param string $signature the code signature of the violation
*
* @return bool
*/
public function contains($sniffName, $fileName, $signature)
{
if (isset($this->violations[$sniffName][$signature]) === false) {
return false;
}

// Normalize slashes in file name.
$fileName = str_replace('\\', '/', $fileName);

foreach ($this->violations[$sniffName][$signature] as $baseline) {
if ($baseline->matches($fileName) === true) {
return true;
}
}

return false;

}//end contains()


}//end class
67 changes: 67 additions & 0 deletions src/Baseline/BaselineSetFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?php
/**
* A factory to create a baseline collection from a given file
*
* @author Frank Dekker <[email protected]>
* @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/

namespace PHP_CodeSniffer\Baseline;

use PHP_CodeSniffer\Exceptions\RuntimeException;

class BaselineSetFactory
{


/**
* Read the baseline violations from the given filename path.
*
* @param string $fileName the baseline file to import
*
* @return BaselineSet|null
* @throws RuntimeException
*/
public static function fromFile($fileName)
{
if (file_exists($fileName) === false) {
return null;
}

$xml = @simplexml_load_string(file_get_contents($fileName));
if ($xml === false) {
throw new RuntimeException('Unable to read xml from: '.$fileName);
}

$baselineSet = new BaselineSet();

foreach ($xml->children() as $node) {
if ($node->getName() !== 'violation') {
continue;
}

if (isset($node['sniff']) === false) {
throw new RuntimeException('Missing `sniff` attribute in `violation` in '.$fileName);
}

if (isset($node['file']) === false) {
throw new RuntimeException('Missing `file` attribute in `violation` in '.$fileName);
}

if (isset($node['signature']) === false) {
throw new RuntimeException('Missing `signature` attribute in `violation` in '.$fileName);
}

// Normalize filepath (if needed).
$filePath = '/'.ltrim(str_replace('\\', '/', (string) $node['file']), '/');

$baselineSet->addEntry(new ViolationBaseline((string) $node['sniff'], $filePath, (string) $node['signature']));
}//end foreach

return $baselineSet;

}//end fromFile()


}//end class
99 changes: 99 additions & 0 deletions src/Baseline/ViolationBaseline.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<?php
/**
* A class to manage a single baselined violation
*
* @author Frank Dekker <[email protected]>
* @copyright 2006-2015 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/squizlabs/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/

namespace PHP_CodeSniffer\Baseline;

class ViolationBaseline
{

/**
* The name of the sniff
*
* @var string
*/
private $sniffName;

/**
* The relative file path
*
* @var string
*/
private $fileName;

/**
* The length of the filename to improve comparison performance
*
* @var integer
*/
private $fileNameLength;

/**
* The code signature for the baseline
*
* @var string
*/
private $signature;


/**
* Initialize the violation baseline
*
* @param string $sniffName The name of the sniff that's baselined.
* @param string $fileName The relative file path.
* @param string $signature The code signature for the baseline.
*/
public function __construct($sniffName, $fileName, $signature)
{
$this->sniffName = $sniffName;
$this->fileName = $fileName;
$this->fileNameLength = strlen($fileName);
$this->signature = $signature;

}//end __construct()


/**
* Get the sniff name that was baselined
*
* @return string
*/
public function getSniffName()
{
return $this->sniffName;

}//end getSniffName()


/**
* Get the code signature for this baseline
*
* @return string
*/
public function getSignature()
{
return $this->signature;

}//end getSignature()


/**
* Test if the given filepath matches the relative filename in the baseline
*
* @param string $filepath the full filepath to match against
*
* @return bool
*/
public function matches($filepath)
{
return substr($filepath, -$this->fileNameLength) === $this->fileName;

}//end matches()


}//end class
36 changes: 33 additions & 3 deletions src/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

namespace PHP_CodeSniffer;

use PHP_CodeSniffer\Baseline\BaselineSetFactory;
use PHP_CodeSniffer\Exceptions\DeepExitException;
use PHP_CodeSniffer\Exceptions\RuntimeException;
use PHP_CodeSniffer\Util\Common;
Expand Down Expand Up @@ -45,6 +46,7 @@
* If empty, all sniffs in the supplied standards will be used.
* @property string[] $ignored Regular expressions used to ignore files and folders during checking.
* @property string $reportFile A file where the report output should be written.
* @property string $baselineFile The baselined violations file to include.
* @property string $generator The documentation generator to use.
* @property string $filter The filter to use for the run.
* @property string[] $bootstrap One of more files to include before the run begins.
Expand Down Expand Up @@ -130,6 +132,7 @@ class Config
'exclude' => null,
'ignored' => null,
'reportFile' => null,
'baselineFile' => null,
'generator' => null,
'filter' => null,
'bootstrap' => null,
Expand All @@ -146,6 +149,13 @@ class Config
'unknown' => null,
];

/**
* The configured baselined violations
*
* @var \PHP_CodeSniffer\Baseline\BaselineSet|null
*/
public $baseline = null;

/**
* Whether or not to kill the process when an unknown command line arg is found.
*
Expand Down Expand Up @@ -381,6 +391,11 @@ public function __construct(array $cliArgs=[], $dieOnUnknownArg=true)
} while ($currentDir !== '.' && $currentDir !== $lastDir && Common::isReadable($currentDir) === true);
}//end if

// Load baseline file, only if no baseline should be created.
if (isset($this->settings['reports']['baseline']) === false) {
$this->baseline = BaselineSetFactory::fromFile($this->baselineFile);
}

if (defined('STDIN') === false
|| stripos(PHP_OS, 'WIN') === 0
) {
Expand Down Expand Up @@ -504,6 +519,7 @@ public function restoreDefaults()
$this->exclude = [];
$this->ignored = [];
$this->reportFile = null;
$this->baselineFile = 'phpcs.baseline.xml';
$this->generator = null;
$this->filter = null;
$this->bootstrap = [];
Expand Down Expand Up @@ -1038,6 +1054,18 @@ public function processLongArgument($arg, $pos)
$error .= $this->printShortUsage(true);
throw new DeepExitException($error, 3);
}
} else if (substr($arg, 0, 13) === 'baselineFile=') {
if (substr($arg, 13) === '') {
$this->basepath = null;
break;
}

$this->baselineFile = Util\Common::realpath(substr($arg, 13));
if (is_file($this->baselineFile) === false) {
$error = 'ERROR: The specified baselineFile "'.substr($arg, 13).'" points to a non-existent file'.PHP_EOL.PHP_EOL;
$error .= $this->printShortUsage(true);
throw new DeepExitException($error, 3);
}
} else if ((substr($arg, 0, 7) === 'report=' || substr($arg, 0, 7) === 'report-')) {
$reports = [];

Expand Down Expand Up @@ -1361,9 +1389,10 @@ public function printPHPCSUsage()
echo 'Usage: phpcs [-nwlsaepqvi] [-d key[=value]] [--colors] [--no-colors]'.PHP_EOL;
echo ' [--cache[=<cacheFile>]] [--no-cache] [--tab-width=<tabWidth>]'.PHP_EOL;
echo ' [--report=<report>] [--report-file=<reportFile>] [--report-<report>=<reportFile>]'.PHP_EOL;
echo ' [--report-width=<reportWidth>] [--basepath=<basepath>] [--bootstrap=<bootstrap>]'.PHP_EOL;
echo ' [--severity=<severity>] [--error-severity=<severity>] [--warning-severity=<severity>]'.PHP_EOL;
echo ' [--runtime-set key value] [--config-set key value] [--config-delete key] [--config-show]'.PHP_EOL;
echo ' [--report-width=<reportWidth>] [--basepath=<basepath>] [--baselineFile=<baselineFile>]'.PHP_EOL;
echo ' [--bootstrap=<bootstrap>] [--severity=<severity>] [--error-severity=<severity>]'.PHP_EOL;
echo ' [--warning-severity=<severity>] [--runtime-set key value]'.PHP_EOL;
echo ' [--config-set key value] [--config-delete key] [--config-show]'.PHP_EOL;
echo ' [--standard=<standard>] [--sniffs=<sniffs>] [--exclude=<sniffs>]'.PHP_EOL;
echo ' [--encoding=<encoding>] [--parallel=<processes>] [--generator=<generator>]'.PHP_EOL;
echo ' [--extensions=<extensions>] [--ignore=<patterns>] [--ignore-annotations]'.PHP_EOL;
Expand Down Expand Up @@ -1396,6 +1425,7 @@ public function printPHPCSUsage()
echo PHP_EOL;
echo ' <cacheFile> Use a specific file for caching (uses a temporary file by default)'.PHP_EOL;
echo ' <basepath> A path to strip from the front of file paths inside reports'.PHP_EOL;
echo ' <baselineFile> The path to the file with the baselined violations'.PHP_EOL;
echo ' <bootstrap> A comma separated list of files to run before processing begins'.PHP_EOL;
echo ' <encoding> The encoding of the files being checked (default is utf-8)'.PHP_EOL;
echo ' <extensions> A comma separated list of file extensions to check'.PHP_EOL;
Expand Down
8 changes: 8 additions & 0 deletions src/Files/File.php
Original file line number Diff line number Diff line change
Expand Up @@ -1037,6 +1037,14 @@ protected function addMessage($error, $message, $line, $column, $code, $data, $s
return false;
}

// The message is part of the baselined violations.
if ($this->config->baseline !== null) {
$signature = Util\CodeSignature::createSignature($this->getTokens(), $line);
if ($this->config->baseline->contains($sniffCode, $this->path, $signature) === true) {
return false;
}
}

$messageCount++;
if ($fixable === true) {
$this->fixableCount++;
Expand Down
Loading