Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/workflows/continuous-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ jobs:
sed -i 's@'$GITHUB_WORKSPACE'@/github/workspace/@g' tests-junit.xml

- name: SonarCloud Scan
uses: SonarSource/sonarqube-scan-action@v8.1.0
uses: SonarSource/sonarqube-scan-action@v8.2.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
1 change: 1 addition & 0 deletions tests/PHPCSFixer/Command/CommandTestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ abstract protected function getCommandName(): string;
protected function setUp(): void
{
$application = new Application();
$application->setCatchExceptions(false);
$application->addCommand($this->getCommand());

$this->tester = new CommandTester($application->find($this->getCommandName()));
Expand Down
33 changes: 33 additions & 0 deletions tests/PHPCSFixer/Command/CsFixerCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ final class CsFixerCommandTest extends CommandTestCase

TEXT;

private ?string $tempDir = null;
private ?string $tempFile = null;
private string $oldCwd;

#[DataProvider('csFixerCommandDataProvider')]
public function testCsFixerCommand(string $before, string $after): void
Expand Down Expand Up @@ -110,6 +112,31 @@ public function testCsFixerCommandReturnsFailureWhenProcessFails(): void
self::assertEquals(CsFixerCommand::FAILURE, $exitCode);
}

public function testCsFixerCommandReturnsFailureWhenBinaryIsMissing(): void
{
// Outside a Composer project there is no vendor-dir to read, so the command falls back to
// resolving one from its own location, where no PHP CS Fixer binary is installed.
$this->tempDir = sprintf('%s/csfixer_no_project_%s', sys_get_temp_dir(), uniqid('', true));
mkdir($this->tempDir, 0777, true);
chdir($this->tempDir);

$this->tempFile = self::createTempFile(self::TEMPLATE);

$exitCode = $this->tester->execute([
'files' => [$this->tempFile],
]);

self::assertEquals(CsFixerCommand::FAILURE, $exitCode);
self::assertStringContainsString('PHP CS Fixer binary not found', $this->tester->getDisplay());
}

protected function setUp(): void
{
parent::setUp();

$this->oldCwd = (string) getcwd();
}

protected function getCommand(): CsFixerCommand
{
return new CsFixerCommand();
Expand All @@ -122,9 +149,15 @@ protected function getCommandName(): string

protected function tearDown(): void
{
chdir($this->oldCwd);

if ($this->tempFile !== null && is_file($this->tempFile)) {
unlink($this->tempFile);
}

if ($this->tempDir !== null && is_dir($this->tempDir)) {
rmdir($this->tempDir);
}
}

private static function createTempFile(mixed $content): string
Expand Down
112 changes: 81 additions & 31 deletions tests/PHPCSFixer/Command/CsFixerGitHookCommandTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,7 @@ public function testInstallsHookSuccessfully(): void
chdir($this->repoDir);
exec('git init 2>/dev/null');

// Create the vendor tree where your current code expects it:
// - resolveVendorDir(dirname($rootGitPath))
// - If rootGitPath is $this->repoDir, it will look under $this->baseDir/vendor
$vendorBase = sprintf('%s/vendor', $this->baseDir);
$codeToolsDir = sprintf('%s/kununu/code-tools', $vendorBase);
$binDir = sprintf('%s/bin', $vendorBase);
mkdir($codeToolsDir, 0777, true);
mkdir($binDir, 0777, true);

// Files the command symlinks to:
file_put_contents(sprintf('%s/php-cs-fixer', $binDir), "#!/usr/bin/env php\n<?php\n");
@chmod(filename: sprintf('%s/php-cs-fixer', $binDir), permissions: 0755);
$this->createVendorTree();

$exitCode = $this->tester->execute([]);

Expand Down Expand Up @@ -103,12 +92,7 @@ public function testScopeMarkerIsWrittenOnlyForAProjectRootedConfig(): void
chdir($this->repoDir);
exec('git init 2>/dev/null');

$vendorBase = sprintf('%s/vendor', $this->baseDir);
$binDir = sprintf('%s/bin', $vendorBase);
mkdir(sprintf('%s/kununu/code-tools', $vendorBase), 0777, true);
mkdir($binDir, 0777, true);
file_put_contents(sprintf('%s/php-cs-fixer', $binDir), "#!/usr/bin/env php\n<?php\n");
@chmod(sprintf('%s/php-cs-fixer', $binDir), 0755);
$this->createVendorTree();

$marker = sprintf('%s/.git/kununu/filter-by-config', $this->repoDir);

Expand All @@ -129,12 +113,7 @@ public function testFailedReinstallKeepsTheExistingSymlinks(): void
chdir($this->repoDir);
exec('git init 2>/dev/null');

$vendorBase = sprintf('%s/vendor', $this->baseDir);
$binDir = sprintf('%s/bin', $vendorBase);
mkdir(sprintf('%s/kununu/code-tools', $vendorBase), 0777, true);
mkdir($binDir, 0777, true);
file_put_contents(sprintf('%s/php-cs-fixer', $binDir), "#!/usr/bin/env php\n<?php\n");
@chmod(sprintf('%s/php-cs-fixer', $binDir), 0755);
$binDir = $this->createVendorTree();

self::assertEquals(CsFixerGitHookCommand::SUCCESS, $this->tester->execute([]));

Expand All @@ -158,13 +137,7 @@ public function testReinstallRemovesExistingHookAndSymlinks(): void
chdir($this->repoDir);
exec('git init 2>/dev/null');

$vendorBase = sprintf('%s/vendor', $this->baseDir);
$codeToolsDir = sprintf('%s/kununu/code-tools', $vendorBase);
$binDir = sprintf('%s/bin', $vendorBase);
mkdir($codeToolsDir, 0777, true);
mkdir($binDir, 0777, true);
file_put_contents(sprintf('%s/php-cs-fixer', $binDir), "#!/usr/bin/env php\n<?php\n");
@chmod(sprintf('%s/php-cs-fixer', $binDir), 0755);
$this->createVendorTree();

$this->tester->execute([]);

Expand Down Expand Up @@ -253,6 +226,66 @@ public function testFailsWhenVendorDirNotFound(): void
self::assertStringContainsString('Could not find vendor directory', $this->tester->getDisplay());
}

public function testScopeMarkerIsRemovedWhenTheProjectConfigGoesAway(): void
{
chdir($this->repoDir);
exec('git init 2>/dev/null');
$this->createVendorTree();

$config = sprintf('%s/php-cs-fixer.php', $this->repoDir);
$marker = sprintf('%s/.git/kununu/filter-by-config', $this->repoDir);

file_put_contents($config, "<?php\nreturn null;\n");

self::assertEquals(CsFixerGitHookCommand::SUCCESS, $this->tester->execute([]));
self::assertFileExists($marker);

// The project dropped its own config, so the hook falls back to the packaged template and
// must stop narrowing staged files through a config that is no longer there.
unlink($config);

self::assertEquals(CsFixerGitHookCommand::SUCCESS, $this->tester->execute([]));
self::assertFileDoesNotExist($marker);
}

public function testFailsWhenSymlinkDirectoryCannotBeCreated(): void
{
chdir($this->repoDir);
exec('git init 2>/dev/null');
$this->createVendorTree();

// The hooks directory already exists and stays writable, so installation gets past the hook
// itself and only then fails to create the directory holding the symlinks.
$gitPath = sprintf('%s/.git', $this->repoDir);
chmod($gitPath, 0555);

$exitCode = $this->tester->execute([]);

chmod($gitPath, 0755);

self::assertEquals(CsFixerGitHookCommand::FAILURE, $exitCode);
self::assertStringContainsString('Could not create directory', $this->tester->getDisplay());
}

public function testFailsWhenSymlinkCannotBeCreated(): void
{
chdir($this->repoDir);
exec('git init 2>/dev/null');
$this->createVendorTree();

// Here the directory is already there, so it is the symlink itself that cannot be written.
$kununuDir = sprintf('%s/.git/kununu', $this->repoDir);
mkdir($kununuDir, 0777, true);
chmod($kununuDir, 0555);

$exitCode = $this->tester->execute([]);

chmod($kununuDir, 0755);

self::assertEquals(CsFixerGitHookCommand::FAILURE, $exitCode);
self::assertStringContainsString('Failed to create symlink', $this->tester->getDisplay());
}

protected function setUp(): void
{
parent::setUp();
Expand Down Expand Up @@ -285,6 +318,23 @@ protected function getCommandName(): string
return 'kununu:cs-fixer-git-hook';
}

// The vendor tree where the command looks for it: resolveVendorDir() walks up from the
// repository, so for $this->repoDir that is $this->baseDir/vendor. Returns the bin directory,
// which holds the binary the command symlinks to.
private function createVendorTree(): string
{
$vendorBase = sprintf('%s/vendor', $this->baseDir);
$binDir = sprintf('%s/bin', $vendorBase);

mkdir(sprintf('%s/kununu/code-tools', $vendorBase), 0777, true);
mkdir($binDir, 0777, true);

file_put_contents(sprintf('%s/php-cs-fixer', $binDir), "#!/usr/bin/env php\n<?php\n");
@chmod(sprintf('%s/php-cs-fixer', $binDir), 0755);

return $binDir;
}

private function resolveConfigTemplate(string $gitPath): mixed
{
return $this->method->invoke($this->getCommand(), $gitPath);
Expand Down