Skip to content

Commit

Permalink
[FEATURE] Detect and output warning when files being staged in Git ar…
Browse files Browse the repository at this point in the history
…e physically missing
  • Loading branch information
a-r-m-i-n committed Dec 3, 2023
1 parent 58c4bb9 commit 161239a
Show file tree
Hide file tree
Showing 6 changed files with 126 additions and 2 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ The ``ec`` binary supports the following options:
| ``--uncovered`` | ``-u`` | Lists all files which are not covered by .editorconfig. |
| ``--verbose`` | ``-v`` | Shows additional informations, like detailed info about internal time tracking and which binary files have been skipped. |
| ``--no-interaction`` | ``-n`` | Do not ask for confirmation, if more than 500 files found and continue scanning. |
| ``--no-error-on-exit`` | | By default ``ec`` returns code 2 when issues occurred. With this option set return code is always 0. |
| ``--no-error-on-exit`` | | By default ``ec`` returns code 2 when issues or code 1 when warnings occurred. With this option set return code is always 0. |

**Tip:** The "usage" section on ``ec``'s help page shows some examples.

Expand Down
16 changes: 16 additions & 0 deletions src/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,22 @@ protected function executing(Input $input, Output $output): int
? $this->scan($finder, $count, $io, (bool)$input->getOption('strict'), (bool)$input->getOption('no-progress'), (bool)$input->getOption('compact'), (bool)$input->getOption('uncovered'))
: $this->fix($finder, $io, (bool)$input->getOption('strict'));

if (!empty($this->scanner->getUnavailableFiles())) {
$amountUnavailableFiles = count($this->scanner->getUnavailableFiles());
$io->warning('Found ' . $amountUnavailableFiles . ' unavailable ' . StringFormatUtility::pluralizeFiles($amountUnavailableFiles) . ' not being scanned!');
$filePaths = [];
foreach ($this->scanner->getUnavailableFiles() as $unavailableFile) {
$filePaths[] = $unavailableFile->getPathname();
}
$io->listing($filePaths);
if ($gitOnlyEnabled) {
$io->writeln('<comment>The files listed by the "' . $gitOnlyCommand . '" command are not physically present.</comment>');
$io->writeln('<comment>This typically occurs when files are deleted without being staged in Git. To verify, check "git status".</comment>');
$io->newLine();
}
$returnValue = 1;
}

if ($this->isVerbose) {
if (!empty($this->scanner->getSkippedBinaryFiles())) {
$amountBinaryFiles = count($this->scanner->getSkippedBinaryFiles());
Expand Down
24 changes: 24 additions & 0 deletions src/EditorConfig/Rules/FileUnavailableException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

declare(strict_types = 1);

namespace Armin\EditorconfigCli\EditorConfig\Rules;

use Symfony\Component\Finder\SplFileInfo;

class FileUnavailableException extends \Exception
{
private SplFileInfo $unavailableFile;

public function getUnavailableFile(): SplFileInfo
{
return $this->unavailableFile;
}

public function setUnavailableFile(SplFileInfo $unavailableFile): self
{
$this->unavailableFile = $unavailableFile;

return $this;
}
}
5 changes: 5 additions & 0 deletions src/EditorConfig/Rules/Validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ public function createValidatedFileResult(SplFileInfo $file, array $editorConfig
$this->skippingRules = $skippingRules;

$filePath = (string)$file->getRealPath();

if (empty($filePath)) {
throw (new FileUnavailableException())->setUnavailableFile($file);
}

$rules = [];

if (!MimeTypeUtility::isCommonTextType($filePath) && (MimeTypeUtility::isCommonBinaryType($filePath) || MimeTypeUtility::isBinaryFileType($filePath))) {
Expand Down
23 changes: 22 additions & 1 deletion src/EditorConfig/Scanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
namespace Armin\EditorconfigCli\EditorConfig;

use Armin\EditorconfigCli\EditorConfig\Rules\FileResult;
use Armin\EditorconfigCli\EditorConfig\Rules\FileUnavailableException;
use Armin\EditorconfigCli\EditorConfig\Rules\Validator;
use Armin\EditorconfigCli\EditorConfig\Utility\MimeTypeUtility;
use Armin\EditorconfigCli\EditorConfig\Utility\TimeTrackingUtility;
use Idiosyncratic\EditorConfig\EditorConfig;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Finder\SplFileInfo;

class Scanner
{
Expand Down Expand Up @@ -38,6 +40,11 @@ class Scanner
*/
private $skippedBinaryFiles = [];

/**
* @var array|SplFileInfo[]
*/
private $unavailableFiles = [];

public function __construct(?EditorConfig $editorConfig = null, ?Validator $validator = null, string $rootPath = null, array $skippingRules = [])
{
$this->editorConfig = $editorConfig ?? new EditorConfig();
Expand Down Expand Up @@ -71,6 +78,14 @@ public function getSkippedBinaryFiles(): array
return $this->skippedBinaryFiles;
}

/**
* @return array|SplFileInfo[]
*/
public function getUnavailableFiles(): array
{
return $this->unavailableFiles;
}

/**
* @param bool $strict when true, any difference of indention size is spotted
*
Expand All @@ -82,7 +97,13 @@ public function scan(Finder $finderInstance, bool $strict = false, callable $tic
foreach ($finderInstance as $file) {
$config = $this->editorConfig->getConfigForPath((string)$file->getRealPath());

$fileResult = $this->validator->createValidatedFileResult($file, $config, $strict, $this->skippingRules);
try {
$fileResult = $this->validator->createValidatedFileResult($file, $config, $strict, $this->skippingRules);
} catch (FileUnavailableException $e) {
$this->unavailableFiles[] = $e->getUnavailableFile();
continue;
}

$filePath = $fileResult->getFilePath();
if (!empty($this->rootPath)) {
$filePath = substr($filePath, strlen($this->rootPath));
Expand Down
58 changes: 58 additions & 0 deletions tests/Functional/EditorConfig/CommandGitUnavailableFilesTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php declare(strict_types = 1);
namespace Armin\EditorconfigCli\Tests\Functional\EditorConfig;

use Armin\EditorconfigCli\Application;
use Symfony\Component\Console\Tester\CommandTester;

class CommandGitUnavailableFilesTest extends AbstractTestCase
{
private const GIT_BINARY = 'git';

protected $editorConfig = <<<TXT
root = true
[*]
insert_final_newline = true
TXT;

public function setUp(): void
{
$this->workspacePath = sys_get_temp_dir() . '/current_editorconfig_cli_test';

parent::setUp();

// Copy test files
copy(__DIR__ . '/../../Fixtures/image.jpg', $this->workspacePath . '/' . 'image.jpg');
copy(__DIR__ . '/../../Fixtures/document.pdf', $this->workspacePath . '/' . 'document.pdf');
copy(__DIR__ . '/../../Fixtures/kreis-weiß.svg', $this->workspacePath . '/' . 'kreis-weiß.svg');

// Set up Git repository for testing
exec('cd ' . $this->workspacePath . ' && ' . self::GIT_BINARY . ' init', $result, $returnCode);
if ($returnCode !== 0) {
throw new \RuntimeException('Unable to create test git repository!');
}

// Add files to git stage
exec('cd ' . $this->workspacePath . ' && ' . self::GIT_BINARY . ' add image.jpg');
exec('cd ' . $this->workspacePath . ' && ' . self::GIT_BINARY . ' add document.pdf');
exec('cd ' . $this->workspacePath . ' && ' . self::GIT_BINARY . ' add kreis-weiß.svg');

// Remove files physically
exec('rm -f ' . $this->workspacePath . '/image.jpg');
exec('rm -f ' . $this->workspacePath . '/document.pdf');
}

public function testUnavailableFiles()
{
$command = new Application();
$command->setAutoExit(false);
$commandTester = new CommandTester($command);
$commandTester->execute(['-d' => $this->workspacePath, '--no-progress' => true, '--git-only' => true]);

self::assertSame(1, $commandTester->getStatusCode());
self::assertStringContainsString('[WARNING] Found 2 unavailable files not being scanned!', $commandTester->getDisplay());
self::assertStringContainsString('* ' . $this->workspacePath . '/document.pdf', $commandTester->getDisplay());
self::assertStringContainsString('* ' . $this->workspacePath . '/image.jpg', $commandTester->getDisplay());
}
}

0 comments on commit 161239a

Please sign in to comment.