Skip to content

Add phpcs baseline support #115

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

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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, 14) === 'baseline-file=') {
if (substr($arg, 14) === '') {
$this->baselineFile = null;
break;
}

$this->baselineFile = Util\Common::realpath(substr($arg, 14));
if (is_file($this->baselineFile) === false) {
$error = 'ERROR: The specified baseline-file "'.substr($arg, 14).'" 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>] [--baseline-file=<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