Skip to content

Commit

Permalink
Add options which check only git changed files (JakubOnderka#103)
Browse files Browse the repository at this point in the history
  • Loading branch information
VincentChataignier committed Nov 6, 2017
1 parent a5c5493 commit a26b959
Show file tree
Hide file tree
Showing 5 changed files with 172 additions and 64 deletions.
33 changes: 17 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,23 @@ For colored output install the suggested package `jakub-onderka/php-console-high

## Options for run

- `-p <php>` Specify PHP-CGI executable to run (default: 'php').
- `-s, --short` Set short_open_tag to On (default: Off).
- `-a, --asp` Set asp_tags to On (default: Off).
- `-e <ext>` Check only files with selected extensions separated by comma. (default: php,php3,php4,php5,phtml)
- `--exclude` Exclude a file or directory. If you want exclude multiple items, use multiple exclude parameters.
- `-j <num>` Run <num> jobs in parallel (default: 10).
- `--colors` Force enable colors in console output.
- `--no-colors` Disable colors in console output.
- `--no-progress` Disable progress in console output.
- `--json` Output results as JSON string (require PHP 5.4).
- `--blame` Try to show git blame for row with error.
- `--git <git>` Path to Git executable to show blame message (default: 'git').
- `--stdin` Load files and folder to test from standard input.
- `--ignore-fails` Ignore failed tests.
- `-h, --help` Print this help.
- `-V, --version` Display this application version.
- `-p <php>` Specify PHP-CGI executable to run (default: 'php').
- `-s, --short` Set short_open_tag to On (default: Off).
- `-a, --asp` Set asp_tags to On (default: Off).
- `-e <ext>` Check only files with selected extensions separated by comma. (default: php,php3,php4,php5,phtml)
- `--exclude` Exclude a file or directory. If you want exclude multiple items, use multiple exclude parameters.
- `-j <num>` Run <num> jobs in parallel (default: 10).
- `--colors` Force enable colors in console output.
- `--no-colors` Disable colors in console output.
- `--no-progress` Disable progress in console output.
- `--json` Output results as JSON string (require PHP 5.4).
- `--blame` Try to show git blame for row with error.
- `--git <git>` Path to Git executable to show blame message (default: 'git').
- `--stdin` Load files and folder to test from standard input.
- `--ignore-fails` Ignore failed tests.
- `--only-git-changed` Check only files which is changed compared to git HEAD (required git)
- `-h, --help` Print this help.
- `-V, --version` Display this application version.


## Recommended setting for usage with Symfony framework
Expand Down
37 changes: 19 additions & 18 deletions parallel-lint.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,24 +20,25 @@ function showOptions()
{
?>
Options:
-p <php> Specify PHP-CGI executable to run (default: 'php').
-s, --short Set short_open_tag to On (default: Off).
-a, -asp Set asp_tags to On (default: Off).
-e <ext> Check only files with selected extensions separated by comma.
(default: php,php3,php4,php5,phtml)
--exclude Exclude a file or directory. If you want exclude multiple items,
use multiple exclude parameters.
-j <num> Run <num> jobs in parallel (default: 10).
--colors Enable colors in console output. (disables auto detection of color support)
--no-colors Disable colors in console output.
--no-progress Disable progress in console output.
--json Output results as JSON string (require PHP 5.4).
--blame Try to show git blame for row with error.
--git <git> Path to Git executable to show blame message (default: 'git').
--stdin Load files and folder to test from standard input.
--ignore-fails Ignore failed tests.
-h, --help Print this help.
-V, --version Display this application version
-p <php> Specify PHP-CGI executable to run (default: 'php').
-s, --short Set short_open_tag to On (default: Off).
-a, -asp Set asp_tags to On (default: Off).
-e <ext> Check only files with selected extensions separated by comma.
(default: php,php3,php4,php5,phtml)
--exclude Exclude a file or directory. If you want exclude multiple items,
use multiple exclude parameters.
-j <num> Run <num> jobs in parallel (default: 10).
--colors Enable colors in console output. (disables auto detection of color support)
--no-colors Disable colors in console output.
--no-progress Disable progress in console output.
--json Output results as JSON string (require PHP 5.4).
--blame Try to show git blame for row with error.
--git <git> Path to Git executable to show blame message (default: 'git').
--stdin Load files and folder to test from standard input.
--ignore-fails Ignore failed tests.
--only-git-changed Check only files which is changed compared to git HEAD (required git)
-h, --help Print this help.
-V, --version Display this application version
<?php
}

Expand Down
120 changes: 90 additions & 30 deletions src/Manager.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,12 @@ public function run(Settings $settings = null)

$output->writeHeader($phpExecutable->getVersionId(), $settings->parallelJobs, $phpExecutable->getHhvmVersion());

$files = $this->getFilesFromPaths($settings->paths, $settings->extensions, $settings->excluded);
$files = $this->getFilesFromPaths(
$settings->paths,
$settings->extensions,
$settings->excluded,
$settings->gitChangedFiles
);

if (empty($files)) {
throw new Exception('No file found to check.');
Expand Down Expand Up @@ -153,10 +158,11 @@ protected function gitBlame(Result $result, Settings $settings)
* @param array $paths
* @param array $extensions
* @param array $excluded
* @param array $changed
* @return array
* @throws NotExistsPathException
*/
protected function getFilesFromPaths(array $paths, array $extensions, array $excluded = array())
protected function getFilesFromPaths(array $paths, array $extensions, array $excluded = [], array $changed = [])
{
$extensions = array_flip($extensions);
$files = array();
Expand All @@ -167,7 +173,10 @@ protected function getFilesFromPaths(array $paths, array $extensions, array $exc
} else if (is_dir($path)) {
$iterator = new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS);
if (!empty($excluded)) {
$iterator = new RecursiveDirectoryFilterIterator($iterator, $excluded);
$iterator = new RecursiveDirectoryExcludedFilterIterator($iterator, $excluded);
}
if (!empty($changed)) {
$iterator = new RecursiveDirectoryChangedFilesFilterIterator($iterator, $changed);
}
$iterator = new \RecursiveIteratorIterator(
$iterator,
Expand All @@ -192,11 +201,51 @@ protected function getFilesFromPaths(array $paths, array $extensions, array $exc
}
}

class RecursiveDirectoryFilterIterator extends \RecursiveFilterIterator
abstract class AbstractRecursiveDirectoryFilterIterator extends \RecursiveFilterIterator
{
/** @var \RecursiveDirectoryIterator */
private $iterator;
protected $iterator;

/**
* (PHP 5 &gt;= 5.1.0)<br/>
* Check whether the inner iterator's current element has children
*
* @link http://php.net/manual/en/recursivefilteriterator.haschildren.php
* @return bool true if the inner iterator has children, otherwise false
*/
public function hasChildren()
{
return $this->iterator->hasChildren();
}

/**
* @param string $file
* @return string
*/
protected function getPathname($file)
{
$file = $this->normalizeDirectorySeparator($file);

if ('.' . DIRECTORY_SEPARATOR !== $file[0] . $file[1]) {
$file = '.' . DIRECTORY_SEPARATOR . $file;
}

$directoryFile = new \SplFileInfo($file);
return $directoryFile->getPathname();
}

/**
* @param string $file
* @return string
*/
protected function normalizeDirectorySeparator($file)
{
return str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, $file);
}
}

class RecursiveDirectoryExcludedFilterIterator extends AbstractRecursiveDirectoryFilterIterator
{
/** @var array */
private $excluded = array();

Expand Down Expand Up @@ -230,18 +279,6 @@ public function accept()
return !in_array($current, $this->excluded);
}

/**
* (PHP 5 &gt;= 5.1.0)<br/>
* Check whether the inner iterator's current element has children
*
* @link http://php.net/manual/en/recursivefilteriterator.haschildren.php
* @return bool true if the inner iterator has children, otherwise false
*/
public function hasChildren()
{
return $this->iterator->hasChildren();
}

/**
* (PHP 5 &gt;= 5.1.0)<br/>
* Return the inner iterator's children contained in a RecursiveFilterIterator
Expand All @@ -253,29 +290,52 @@ public function getChildren()
{
return new self($this->iterator->getChildren(), $this->excluded);
}
}

class RecursiveDirectoryChangedFilesFilterIterator extends AbstractRecursiveDirectoryFilterIterator
{
/** @var array */
private $changedFiles = array();

/**
* @param string $file
* @return string
* @param \RecursiveDirectoryIterator $iterator
* @param array $changedFiles
*/
private function getPathname($file)
public function __construct(\RecursiveDirectoryIterator $iterator, array $changedFiles)
{
$file = $this->normalizeDirectorySeparator($file);
parent::__construct($iterator);
$this->iterator = $iterator;
$this->changedFiles = array_map(array($this, 'getPathname'), $changedFiles);
}

if ('.' . DIRECTORY_SEPARATOR !== $file[0] . $file[1]) {
$file = '.' . DIRECTORY_SEPARATOR . $file;
/**
* (PHP 5 &gt;= 5.1.0)<br/>
* Check whether the current element of the iterator is acceptable
*
* @link http://php.net/manual/en/filteriterator.accept.php
* @return bool true if the current element is acceptable, otherwise false.
*/
public function accept()
{
$current = $this->current()->getPathname();
$current = $this->normalizeDirectorySeparator($current);

if ('.' . DIRECTORY_SEPARATOR !== $current[0] . $current[1]) {
$current = '.' . DIRECTORY_SEPARATOR . $current;
}

$directoryFile = new \SplFileInfo($file);
return $directoryFile->getPathname();
return in_array($current, $this->changedFiles);
}

/**
* @param string $file
* @return string
* (PHP 5 &gt;= 5.1.0)<br/>
* Return the inner iterator's children contained in a RecursiveFilterIterator
*
* @link http://php.net/manual/en/recursivefilteriterator.getchildren.php
* @return \RecursiveFilterIterator containing the inner iterator's children.
*/
private function normalizeDirectorySeparator($file)
public function getChildren()
{
return str_replace(array('\\', '/'), DIRECTORY_SEPARATOR, $file);
return new self($this->iterator->getChildren(), $this->changedFiles);
}
}
}
14 changes: 14 additions & 0 deletions src/Settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,12 @@ class Settings
*/
public $ignoreFails = false;

/**
* Array of file or directories to check because they have been changed
* @var bool
*/
public $gitChangedFiles = array();

/**
* @param array $paths
*/
Expand All @@ -141,6 +147,8 @@ public static function parseArguments(array $arguments)
$arguments = new ArrayIterator(array_slice($arguments, 1));
$settings = new self;

$gitChangedFilesCommand = "git --no-pager diff --name-only --diff-filter=MARC| grep -E '.php'";

foreach ($arguments as $argument) {
if ($argument{0} !== '-') {
$settings->paths[] = $argument;
Expand Down Expand Up @@ -204,6 +212,12 @@ public static function parseArguments(array $arguments)
$settings->ignoreFails = true;
break;

case '--only-git-changed':
$gitChangedFiles = [];
exec($gitChangedFilesCommand, $gitChangedFiles);
$settings->gitChangedFiles = $gitChangedFiles;
break;

default:
throw new InvalidArgumentException($argument);
}
Expand Down
32 changes: 32 additions & 0 deletions tests/Manager.run.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,38 @@ class ManagerRunTest extends Tester\TestCase
Assert::true($result->hasError());
}

public function testOnlyChangedFiles()
{
$settings = $this->prepareSettings();
$settings->paths = array('examples/example-04/');

$manager = $this->getManager($settings);
$result = $manager->run($settings);
Assert::true($result->hasError());

$settings->gitChangedFiles = array('examples/example-04/index.php', 'examples/example-04/dir1/index.php');

$manager = $this->getManager($settings);
$result = $manager->run($settings);
Assert::false($result->hasError());
}

public function testOnlyChangedFilesWithEmptyArray()
{
$settings = $this->prepareSettings();
$settings->paths = array('examples/example-04/');

$manager = $this->getManager($settings);
$result = $manager->run($settings);
Assert::true($result->hasError());

$settings->gitChangedFiles = array();

$manager = $this->getManager($settings);
$result = $manager->run($settings);
Assert::true($result->hasError());
}

public function testExcludeRelativeSubdirectory()
{
$settings = $this->prepareSettings();
Expand Down

0 comments on commit a26b959

Please sign in to comment.