diff --git a/src/Test/MakerTestEnvironment.php b/src/Test/MakerTestEnvironment.php index e008e9ce0..bff47f0fd 100644 --- a/src/Test/MakerTestEnvironment.php +++ b/src/Test/MakerTestEnvironment.php @@ -28,10 +28,13 @@ final class MakerTestEnvironment private string $flexPath; private string $path; private MakerTestProcess $runnedMakerProcess; + private bool $isWindows; private function __construct( private MakerTestDetails $testDetails, ) { + $this->isWindows = str_contains(strtolower(\PHP_OS), 'win'); + $this->fs = new Filesystem(); $this->rootPath = realpath(__DIR__.'/../../'); $cachePath = $this->rootPath.'/tests/tmp/cache'; @@ -124,13 +127,18 @@ private function changeRootNamespaceIfNeeded(): void public function prepareDirectory(): void { + // Copy MakerBundle to a "repo" directory for tests + if (!file_exists($makerRepoPath = sprintf('%s/maker-repo', $this->cachePath))) { + MakerTestProcess::create(sprintf('git clone %s %s', $this->rootPath, $makerRepoPath), $this->cachePath)->run(); + } + if (!$this->fs->exists($this->flexPath)) { $this->buildFlexSkeleton(); } if (!$this->fs->exists($this->path)) { try { - // lets do some magic here git is faster than copy + // let's do some magic here git is faster than copy MakerTestProcess::create( '\\' === \DIRECTORY_SEPARATOR ? 'git clone %FLEX_PATH% %APP_PATH%' : 'git clone "$FLEX_PATH" "$APP_PATH"', \dirname($this->flexPath), @@ -141,6 +149,11 @@ public function prepareDirectory(): void ) ->run(); + // In Window's we have to require MakerBundle in each project - git clone doesn't symlink well + if ($this->isWindows) { + $this->composerRequireMakerBundle($this->path); + } + // install any missing dependencies $dependencies = $this->determineMissingDependencies(); if ($dependencies) { @@ -231,33 +244,21 @@ private function buildFlexSkeleton(): void $targetVersion = $this->getTargetSkeletonVersion(); $versionString = $targetVersion ? sprintf(':%s', $targetVersion) : ''; + $flexProjectDir = sprintf('flex_project%s', $targetVersion); + MakerTestProcess::create( - sprintf('composer create-project symfony/skeleton%s flex_project%s --prefer-dist --no-progress', $versionString, $targetVersion), + sprintf('composer create-project symfony/skeleton%s %s --prefer-dist --no-progress', $versionString, $flexProjectDir), $this->cachePath )->run(); $rootPath = str_replace('\\', '\\\\', realpath(__DIR__.'/../..')); - // processes any changes needed to the Flex project - $replacements = [ - [ - 'filename' => 'config/bundles.php', - 'find' => "Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],", - 'replace' => "Symfony\Bundle\FrameworkBundle\FrameworkBundle::class => ['all' => true],\n Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true],", - ], - [ - // ugly way to autoload Maker & any other vendor libs needed in the command - 'filename' => 'composer.json', - 'find' => '"App\\\Tests\\\": "tests/"', - 'replace' => sprintf( - '"App\\\Tests\\\": "tests/",'."\n".' "Symfony\\\Bundle\\\MakerBundle\\\": "%s/src/",'."\n".' "PhpParser\\\": "%s/vendor/nikic/php-parser/lib/PhpParser/"', - // escape \ for Windows - $rootPath, - $rootPath - ), - ], - ]; - $this->processReplacements($replacements, $this->flexPath); + $this->addMakerBundleRepoToComposer(sprintf('%s/%s/composer.json', $this->cachePath, $flexProjectDir)); + + // In Linux, git plays well with symlinks - we can add maker to the flex skeleton. + if (!$this->isWindows) { + $this->composerRequireMakerBundle(sprintf('%s/%s', $this->cachePath, $flexProjectDir)); + } if ($_SERVER['MAKER_ALLOW_DEV_DEPS_IN_APP'] ?? false) { MakerTestProcess::create('composer config minimum-stability dev', $this->flexPath)->run(); @@ -411,4 +412,43 @@ private function getTargetSkeletonVersion(): ?string { return $_SERVER['SYMFONY_VERSION'] ?? ''; } + + private function composerRequireMakerBundle(string $projectDirectory): void + { + MakerTestProcess::create('composer require --dev symfony/maker-bundle', $projectDirectory) + ->run() + ; + + $makerRepoSrcPath = sprintf('%s/maker-repo/src', $this->cachePath); + + // DX - So we can test local changes without having to commit them. + if (!is_link($makerRepoSrcPath)) { + $this->fs->remove($makerRepoSrcPath); + $this->fs->symlink(sprintf('%s/src', $this->rootPath), $makerRepoSrcPath); + } + } + + /** + * Adds Symfony/MakerBundle as a "path" repository to composer.json. + */ + private function addMakerBundleRepoToComposer(string $composerJsonPath): void + { + $composerJson = json_decode( + file_get_contents($composerJsonPath), true, 512, \JSON_THROW_ON_ERROR); + + // Require-dev is empty and composer complains about this being an array when we encode it again. + unset($composerJson['require-dev']); + + $composerJson['repositories']['symfony/maker-bundle'] = [ + 'type' => 'path', + 'url' => sprintf('%s%smaker-repo', $this->cachePath, \DIRECTORY_SEPARATOR), + 'options' => [ + 'versions' => [ + 'symfony/maker-bundle' => '9999.99', // Arbitrary version to avoid stability conflicts + ], + ], + ]; + + file_put_contents($composerJsonPath, json_encode($composerJson, \JSON_THROW_ON_ERROR | \JSON_PRETTY_PRINT | \JSON_UNESCAPED_SLASHES)); + } } diff --git a/src/Test/MakerTestRunner.php b/src/Test/MakerTestRunner.php index dde89ebec..7e1140266 100644 --- a/src/Test/MakerTestRunner.php +++ b/src/Test/MakerTestRunner.php @@ -224,10 +224,17 @@ public function writeFile(string $filename, string $contents): void */ public function addToAutoloader(string $namespace, string $path) { - $this->replaceInFile( - 'composer.json', - '"App\\\Tests\\\": "tests/",', - sprintf('"App\\\Tests\\\": "tests/",'."\n".' "%s": "%s",', $namespace, $path) + $composerJson = json_decode( + json: file_get_contents($this->getPath('composer.json')), + associative: true, + flags: \JSON_THROW_ON_ERROR | \JSON_UNESCAPED_SLASHES + ); + + $composerJson['autoload-dev']['psr-4'][$namespace] = $path; + + $this->filesystem->dumpFile( + $this->getPath('composer.json'), + json_encode($composerJson, \JSON_UNESCAPED_SLASHES | \JSON_PRETTY_PRINT | \JSON_THROW_ON_ERROR) ); $this->environment->runCommand('composer dump-autoload'); diff --git a/tests/Maker/MakeEntityTest.php b/tests/Maker/MakeEntityTest.php index ef6fd375c..bc640b7a3 100644 --- a/tests/Maker/MakeEntityTest.php +++ b/tests/Maker/MakeEntityTest.php @@ -637,7 +637,7 @@ private function setupGroupEntityInVendor(MakerTestRunner $runner): void ); $runner->addToAutoloader( - 'Some\\\Vendor\\\\', + 'Some\\Vendor\\', 'vendor/some-vendor/src' ); }