From 8d63d75b9f5125a06e0516d7459ed2643a0ffaec Mon Sep 17 00:00:00 2001 From: ochorocho Date: Sun, 1 May 2022 19:24:23 +0200 Subject: [PATCH 1/7] [FEATURE] Add command 'make:runtests'. Downloads runTests.sh and docker-compose.yml, modify for the selected extensions and put it into Build folder. --- Classes/Command/RunTestsCommand.php | 106 ++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 Classes/Command/RunTestsCommand.php diff --git a/Classes/Command/RunTestsCommand.php b/Classes/Command/RunTestsCommand.php new file mode 100644 index 0000000..b378c4f --- /dev/null +++ b/Classes/Command/RunTestsCommand.php @@ -0,0 +1,106 @@ +setDescription('Setup runTests.sh to run tests, linter, cgl in a Docker environment'); + $this->filesystem = GeneralUtility::makeInstance(Filesystem::class); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $this->io = new SymfonyStyle($input, $output); + $this->package = $this->askForPackage($this->io); + + $templatesToCreate = [ + [ + 'source' => 'https://raw.githubusercontent.com/TYPO3/styleguide/main/Build/Scripts/runTests.sh', + 'target' => $this->package->getPackagePath() . 'Build/Scripts/runTests.sh' + ], + [ + 'source' => 'https://raw.githubusercontent.com/TYPO3/styleguide/main/Build/testing-docker/docker-compose.yml', + 'target' => $this->package->getPackagePath() . 'Build/testing-docker/docker-compose.yml' + ] + ]; + + foreach ($templatesToCreate as $template) { + $this->prepareTemplate( + $template['source'], + $template['target'] + ); + } + + return 0; + } + + protected function prepareTemplate(string $source, string $target): void + { + try { + $template = $this->getGuzzleClient()->get($source); + } catch (GuzzleException $exception) { + $this->io->writeln('Failed to get remote file ' . $source . ''); + return; + } + + $markerService = GeneralUtility::makeInstance(MarkerBasedTemplateService::class); + $templateContent = $markerService->substituteMarker( + $template->getBody(), + 'styleguide', + $this->package->getPackageKey() + ); + + try { + $this->filesystem->dumpFile($target, $templateContent); + } catch (IOException $exception) { + $this->io->writeln('Failed to save file in ' . $target . PHP_EOL . $exception->getMessage() . ''); + } + } + + protected function getGuzzleClient(): Client + { + return GeneralUtility::makeInstance(GuzzleClientFactory::class)->getClient(); + } +} From 13a34b554b3684fdcc994419855572594535c29c Mon Sep 17 00:00:00 2001 From: ochorocho Date: Fri, 29 Apr 2022 14:41:32 +0200 Subject: [PATCH 2/7] [FEATURE] Add command 'make:acceptance' The command 'make:acceptance' has been added to create basic files and config to run acceptance tests. --- Classes/Command/AcceptanceTestsCommand.php | 168 ++++++++++++++++++ Configuration/Services.yaml | 6 + .../Acceptance/Application.suite.yml | 23 +++ .../Acceptance/Application/ExampleCest.php | 30 ++++ .../Acceptance/Fixtures/be_sessions.xml | 19 ++ .../Acceptance/Fixtures/pages.xml | 24 +++ .../Acceptance/Fixtures/sys_template.xml | 16 ++ .../Acceptance/Support/ApplicationTester.php | 17 ++ .../Extension/ExtensionEnvironment.php | 52 ++++++ .../AcceptanceTests/codeception.yml | 13 ++ 10 files changed, 368 insertions(+) create mode 100644 Classes/Command/AcceptanceTestsCommand.php create mode 100644 Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Application.suite.yml create mode 100644 Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Application/ExampleCest.php create mode 100644 Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Fixtures/be_sessions.xml create mode 100644 Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Fixtures/pages.xml create mode 100644 Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Fixtures/sys_template.xml create mode 100644 Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Support/ApplicationTester.php create mode 100644 Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Support/Extension/ExtensionEnvironment.php create mode 100644 Resources/Private/CodeTemplates/AcceptanceTests/codeception.yml diff --git a/Classes/Command/AcceptanceTestsCommand.php b/Classes/Command/AcceptanceTestsCommand.php new file mode 100644 index 0000000..d09e0a3 --- /dev/null +++ b/Classes/Command/AcceptanceTestsCommand.php @@ -0,0 +1,168 @@ +setDescription('Prepare extensions to run acceptance tests'); + $this->filesystem = GeneralUtility::makeInstance(Filesystem::class); + } + + protected function execute(InputInterface $input, OutputInterface $output): int + { + $this->io = new SymfonyStyle($input, $output); + $packages = $this->getPackageResolver()->getPackageManager()->getActivePackages(); + + $choices = array_reduce($packages, function ($result, PackageInterface $package) { + if ($package->getPackageMetaData()->getPackageType() === 'typo3-cms-extension') { + $packageKey = $package->getPackageKey(); + $result[$packageKey] = $packageKey; + } + return $result; + }, []); + + $selectedPackageName = $this->io->choice('Select a package to create acceptance tests for', $choices); + $this->package = $this->getPackageResolver()->resolvePackage($selectedPackageName); + + $packageKey = $this->package->getPackageKey(); + $this->io->writeln('Selected package: ' . $packageKey); + $finder = GeneralUtility::makeInstance(Finder::class); + + $targetPackage = $this->package->getPackagePath(); + $codeTemplatePath = '/Resources/Private/CodeTemplates/AcceptanceTests'; + $templatePath = $this->getPackageResolver()->resolvePackage('b13/make')->getPackagePath() . $codeTemplatePath; + + $this->filesystem->mkdir([ + $targetPackage . '/Tests/Acceptance', + $targetPackage . '/Tests/Acceptance/Fixtures', + $targetPackage . '/Tests/Acceptance/Application', + $targetPackage . '/Tests/Acceptance/Support/Extension' + ]); + + // Create public folder which is required for e.g. acceptance tests to work + $publicFolderPath = $targetPackage . '/Resources/Public'; + if (!is_dir($publicFolderPath)) { + $createPublic = $this->io->confirm('Resource/Public is necessary e.g. for acceptance tests. Do you want to create it now?', true); + if ($createPublic) { + $this->filesystem->mkdir([$publicFolderPath]); + // Ensure the folder will be detected by git and committed + $this->filesystem->touch([$publicFolderPath . '/.gitkeep']); + } + } + + $files = $finder->in($templatePath)->files(); + + foreach ($files as $file) { + $target = $targetPackage . 'Tests' . explode('AcceptanceTests', $file->getRealPath())[1]; + + if (!is_file($target)) { + $content = $file->getContents(); + $this->substituteMarkersAndSave($content, $target); + } else { + $overwrite = $this->io->confirm('File exists ' . basename($target) . '. Do you want to overwrite it?'); + if ($overwrite) { + $content = $file->getContents(); + $this->substituteMarkersAndSave($content, $target); + } + } + } + + if ($this->updateComposerFile($targetPackage)) { + $this->io->writeln('Updated composer.json for EXT:' . $packageKey . ''); + } else { + $this->io->writeln('Failed to update composer.json for EXT:' . $packageKey . ''); + } + + return 0; + } + + /** + * Extend/prepare composer.json of the extension + * for acceptance tests + * + * @throws \JsonException + */ + protected function updateComposerFile(string $packagePath): bool + { + $composerFile = $packagePath . '/composer.json'; + $composerJson = file_get_contents($composerFile); + $composer = json_decode($composerJson, true, 512, JSON_THROW_ON_ERROR); + $namespace = rtrim($this->getNamespace(), '\\'); + + // @todo: if a value already exists ask for permission to change it?! + $composer['require-dev']['codeception/codeception'] = '^4.1'; + $composer['require-dev']['codeception/module-asserts'] = '^1.2'; + $composer['require-dev']['codeception/module-webdriver'] = '^1.1'; + $composer['require-dev']['typo3/testing-framework'] = '^6.16.2'; + + $composer['autoload-dev']['psr-4'][$namespace . '\\Tests\\'] = 'Tests/'; + + $composer['config']['vendor-dir'] = '.Build/vendor'; + $composer['config']['bin-dir'] = '.Build/bin'; + + $composer['extra']['typo3/cms']['app-dir'] = '.Build'; + $composer['extra']['typo3/cms']['web-dir'] = '.Build/Web'; + + return GeneralUtility::writeFile($composerFile, json_encode($composer, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), true); + } + + /** + * Substitute marker values and save file to extension_key/Tests/ + * + * @param string $content + * @param string $target + */ + protected function substituteMarkersAndSave(string $content, string $target): void + { + $markerService = GeneralUtility::makeInstance(MarkerBasedTemplateService::class); + $templateContent = $markerService->substituteMarker($content, '{{NAMESPACE}}', rtrim($this->getNamespace(), '\\')); + $templateContent = $markerService->substituteMarker($templateContent, '{{EXTENSION_KEY}}', $this->package->getPackageKey()); + + try { + $this->filesystem->dumpFile($target, $templateContent); + } catch (IOException $exception) { + $this->io->writeln('Failed to save file in ' . $target . ''); + } + } + + protected function getPackageResolver(): PackageResolver + { + return GeneralUtility::makeInstance(PackageResolver::class); + } + + protected function getNamespace(): string + { + return (string)key((array)($this->package->getValueFromComposerManifest('autoload')->{'psr-4'} ?? [])); + } +} diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index fafe6ed..eafa3fd 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -51,3 +51,9 @@ services: command: 'make:testing:setup' description: 'Create a docker based testing environment setup' schedulable: false + B13\Make\Command\AcceptanceTestsCommand: + tags: + - name: 'console.command' + command: 'make:acceptance' + description: 'Create files required to run acceptance tests' + schedulable: false diff --git a/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Application.suite.yml b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Application.suite.yml new file mode 100644 index 0000000..810a6cd --- /dev/null +++ b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Application.suite.yml @@ -0,0 +1,23 @@ +class_name: ApplicationTester +modules: + enabled: + - WebDriver: + url: http://web:8000/typo3temp/var/tests/acceptance + browser: chrome + wait: 1 + host: chrome + window_size: 1400x800 + - \TYPO3\TestingFramework\Core\Acceptance\Helper\Acceptance + - \TYPO3\TestingFramework\Core\Acceptance\Helper\Login: + sessions: + # This sessions must exist in the database fixture to get a logged in state. + editor: ff83dfd81e20b34c27d3e97771a4525a + admin: 886526ce72b86870739cc41991144ec1 + - Asserts + +extensions: + enabled: + - {{NAMESPACE}}\Tests\Acceptance\Support\Extension\ExtensionEnvironment + +groups: + AcceptanceTests-Job-*: AcceptanceTests-Job-* diff --git a/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Application/ExampleCest.php b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Application/ExampleCest.php new file mode 100644 index 0000000..5af86a6 --- /dev/null +++ b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Application/ExampleCest.php @@ -0,0 +1,30 @@ +useExistingSession('admin'); + $I->switchToMainFrame(); + } + + /** + * @param ApplicationTester $I + * @throws \Exception + */ + public function seeTestExample(ApplicationTester $I): void + { + $I->click('Page'); + $I->switchToContentFrame(); + $I->see('Web>Page module', '.callout-info'); + } +} diff --git a/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Fixtures/be_sessions.xml b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Fixtures/be_sessions.xml new file mode 100644 index 0000000..4160903 --- /dev/null +++ b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Fixtures/be_sessions.xml @@ -0,0 +1,19 @@ + + + + + 9869d429fc72742a476d5073d006d45dfb732962d9c024423efafef537e1c5bd + [DISABLED] + 1 + 1777777777 + + + + + f4c02f70058e79a8e7b523a266d4291007deacba6b2ca2536dd72d2fbb23696a + [DISABLED] + 2 + 1777777777 + + + diff --git a/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Fixtures/pages.xml b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Fixtures/pages.xml new file mode 100644 index 0000000..43a50f7 --- /dev/null +++ b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Fixtures/pages.xml @@ -0,0 +1,24 @@ + + + + + 1 + 0 + Home + + 1 + 0 + 1 + 15 + + + 2 + 1 + 128 + Subpage + subpage + 0 + 1 + 15 + + diff --git a/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Fixtures/sys_template.xml b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Fixtures/sys_template.xml new file mode 100644 index 0000000..7d9b169 --- /dev/null +++ b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Fixtures/sys_template.xml @@ -0,0 +1,16 @@ + + + + 1 + 1 + Root Template + 0 + 1 + 3 + +page = PAGE +page.10 = TEXT +page.10.data = page:title + + + diff --git a/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Support/ApplicationTester.php b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Support/ApplicationTester.php new file mode 100644 index 0000000..2704bd8 --- /dev/null +++ b/Resources/Private/CodeTemplates/AcceptanceTests/Acceptance/Support/ApplicationTester.php @@ -0,0 +1,17 @@ + [ + 'core', + 'extbase', + 'filelist', + 'setup', + 'frontend', + 'fluid', + 'recordlist', + 'backend', + 'install', + ], + 'testExtensionsToLoad' => [ + 'typo3conf/ext/{{EXTENSION_KEY}}', + ], + 'xmlDatabaseFixtures' => [ + 'PACKAGE:typo3/testing-framework/Resources/Core/Acceptance/Fixtures/be_users.xml', + 'PACKAGE:../Web/typo3conf/ext/{{EXTENSION_KEY}}/Tests/Acceptance/Fixtures/pages.xml', + 'PACKAGE:../Web/typo3conf/ext/{{EXTENSION_KEY}}/Tests/Acceptance/Fixtures/be_sessions.xml', + 'PACKAGE:../Web/typo3conf/ext/{{EXTENSION_KEY}}/Tests/Acceptance/Fixtures/sys_template.xml', + ], + 'configurationToUseInTestInstance' => [ + 'MAIL' => [ + 'transport' => NullTransport::class, + ], + ], + + // Link files/folders required for your acceptance tests to run + // 'pathsToLinkInTestInstance' => [ + // 'typo3conf/ext/{{EXTENSION_KEY}}/Tests/Acceptance/Fixtures/sites' => 'typo3conf/sites', + // ] + ]; +} diff --git a/Resources/Private/CodeTemplates/AcceptanceTests/codeception.yml b/Resources/Private/CodeTemplates/AcceptanceTests/codeception.yml new file mode 100644 index 0000000..6509bba --- /dev/null +++ b/Resources/Private/CodeTemplates/AcceptanceTests/codeception.yml @@ -0,0 +1,13 @@ +namespace: {{NAMESPACE}}\Tests\Acceptance\Support +paths: + tests: Acceptance + data: . + log: ../.Build/Web/typo3temp/var/tests/AcceptanceReports + support: Acceptance/Support +settings: + colors: true + memory_limit: 1024M +extensions: + enabled: + - Codeception\Extension\RunFailed + - Codeception\Extension\Recorder From ee7ad4523ae41f36f3c0fc248c0acc515de3bedd Mon Sep 17 00:00:00 2001 From: ochorocho Date: Fri, 29 Apr 2022 15:10:22 +0200 Subject: [PATCH 3/7] [TASK] Add PHP 7.2 compatability The lint task not ignores files in "Resources/Private/CodeTemplates/" --- Build/testing-docker/docker-compose.yml | 2 +- Classes/Command/AcceptanceTestsCommand.php | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Build/testing-docker/docker-compose.yml b/Build/testing-docker/docker-compose.yml index 5cb3439..a35aaa7 100644 --- a/Build/testing-docker/docker-compose.yml +++ b/Build/testing-docker/docker-compose.yml @@ -285,7 +285,7 @@ services: set -x fi php -v | grep '^PHP'; - find . -name \\*.php ! -path "./.Build/\\*" ! -path "./Resources/Private/CodeTemplates\\*" -print0 | xargs -0 -n1 -P4 php -dxdebug.mode=off -l >/dev/null + find . -name \\*.php ! -path "./.Build/\\*" ! -path "./Resources/Private/CodeTemplates/\\*" -print0 | xargs -0 -n1 -P4 php -dxdebug.mode=off -l >/dev/null " phpstan: diff --git a/Classes/Command/AcceptanceTestsCommand.php b/Classes/Command/AcceptanceTestsCommand.php index d09e0a3..3ea2e51 100644 --- a/Classes/Command/AcceptanceTestsCommand.php +++ b/Classes/Command/AcceptanceTestsCommand.php @@ -28,9 +28,20 @@ */ class AcceptanceTestsCommand extends AbstractCommand { - protected Filesystem $filesystem; - protected SymfonyStyle $io; - protected PackageInterface $package; + /** + * @var Filesystem $filesystem + */ + protected $filesystem; + + /** + * @var SymfonyStyle $io + */ + protected $io; + + /** + * @var PackageInterface $package + */ + protected $package; protected function configure(): void { @@ -117,7 +128,7 @@ protected function updateComposerFile(string $packagePath): bool { $composerFile = $packagePath . '/composer.json'; $composerJson = file_get_contents($composerFile); - $composer = json_decode($composerJson, true, 512, JSON_THROW_ON_ERROR); + $composer = json_decode($composerJson, true); $namespace = rtrim($this->getNamespace(), '\\'); // @todo: if a value already exists ask for permission to change it?! From fc58c33dddcc2d7da34d18e790bf9ba9349a1e71 Mon Sep 17 00:00:00 2001 From: ochorocho Date: Sun, 1 May 2022 12:31:34 +0200 Subject: [PATCH 4/7] [TASK] Ask for permission to modify if composer property already exists. --- Classes/Command/AcceptanceTestsCommand.php | 106 ++++++++++++++------- 1 file changed, 73 insertions(+), 33 deletions(-) diff --git a/Classes/Command/AcceptanceTestsCommand.php b/Classes/Command/AcceptanceTestsCommand.php index 3ea2e51..8b4f502 100644 --- a/Classes/Command/AcceptanceTestsCommand.php +++ b/Classes/Command/AcceptanceTestsCommand.php @@ -53,8 +53,8 @@ protected function configure(): void protected function execute(InputInterface $input, OutputInterface $output): int { $this->io = new SymfonyStyle($input, $output); - $packages = $this->getPackageResolver()->getPackageManager()->getActivePackages(); + $packages = $this->getPackageResolver()->getPackageManager()->getActivePackages(); $choices = array_reduce($packages, function ($result, PackageInterface $package) { if ($package->getPackageMetaData()->getPackageType() === 'typo3-cms-extension') { $packageKey = $package->getPackageKey(); @@ -65,26 +65,35 @@ protected function execute(InputInterface $input, OutputInterface $output): int $selectedPackageName = $this->io->choice('Select a package to create acceptance tests for', $choices); $this->package = $this->getPackageResolver()->resolvePackage($selectedPackageName); - $packageKey = $this->package->getPackageKey(); + $targetPackagePath = $this->package->getPackagePath(); + + if ($this->updateComposerFile($targetPackagePath)) { + $this->io->writeln('Updated composer.json for EXT:' . $packageKey . ''); + } else { + $this->io->writeln('Failed to update composer.json for EXT:' . $packageKey . ''); + } + $this->io->writeln('Selected package: ' . $packageKey); $finder = GeneralUtility::makeInstance(Finder::class); - $targetPackage = $this->package->getPackagePath(); $codeTemplatePath = '/Resources/Private/CodeTemplates/AcceptanceTests'; $templatePath = $this->getPackageResolver()->resolvePackage('b13/make')->getPackagePath() . $codeTemplatePath; $this->filesystem->mkdir([ - $targetPackage . '/Tests/Acceptance', - $targetPackage . '/Tests/Acceptance/Fixtures', - $targetPackage . '/Tests/Acceptance/Application', - $targetPackage . '/Tests/Acceptance/Support/Extension' + $targetPackagePath . '/Tests/Acceptance/Fixtures', + $targetPackagePath . '/Tests/Acceptance/Application', + $targetPackagePath . '/Tests/Acceptance/Support/Extension' ]); // Create public folder which is required for e.g. acceptance tests to work - $publicFolderPath = $targetPackage . '/Resources/Public'; + $publicFolderPath = $targetPackagePath . '/Resources/Public'; if (!is_dir($publicFolderPath)) { - $createPublic = $this->io->confirm('Resource/Public is necessary e.g. for acceptance tests. Do you want to create it now?', true); + $createPublic = $this->io->confirm( + 'Resource/Public is necessary e.g. for acceptance tests. Do you want to create it now?', + true + ); + if ($createPublic) { $this->filesystem->mkdir([$publicFolderPath]); // Ensure the folder will be detected by git and committed @@ -95,7 +104,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $files = $finder->in($templatePath)->files(); foreach ($files as $file) { - $target = $targetPackage . 'Tests' . explode('AcceptanceTests', $file->getRealPath())[1]; + $target = $targetPackagePath . 'Tests' . explode('AcceptanceTests', $file->getRealPath())[1]; if (!is_file($target)) { $content = $file->getContents(); @@ -109,12 +118,6 @@ protected function execute(InputInterface $input, OutputInterface $output): int } } - if ($this->updateComposerFile($targetPackage)) { - $this->io->writeln('Updated composer.json for EXT:' . $packageKey . ''); - } else { - $this->io->writeln('Failed to update composer.json for EXT:' . $packageKey . ''); - } - return 0; } @@ -129,23 +132,39 @@ protected function updateComposerFile(string $packagePath): bool $composerFile = $packagePath . '/composer.json'; $composerJson = file_get_contents($composerFile); $composer = json_decode($composerJson, true); - $namespace = rtrim($this->getNamespace(), '\\'); - - // @todo: if a value already exists ask for permission to change it?! - $composer['require-dev']['codeception/codeception'] = '^4.1'; - $composer['require-dev']['codeception/module-asserts'] = '^1.2'; - $composer['require-dev']['codeception/module-webdriver'] = '^1.1'; - $composer['require-dev']['typo3/testing-framework'] = '^6.16.2'; - - $composer['autoload-dev']['psr-4'][$namespace . '\\Tests\\'] = 'Tests/'; - - $composer['config']['vendor-dir'] = '.Build/vendor'; - $composer['config']['bin-dir'] = '.Build/bin'; + if (json_last_error() !== JSON_ERROR_NONE) { + throw new \JsonException('Could not parse ' . $composerFile); + } - $composer['extra']['typo3/cms']['app-dir'] = '.Build'; - $composer['extra']['typo3/cms']['web-dir'] = '.Build/Web'; + $namespace = rtrim($this->getNamespace(), '\\'); - return GeneralUtility::writeFile($composerFile, json_encode($composer, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), true); + $addToComposerFile = [ + 'require-dev' => [ + 'codeception/codeception' => '^4.1', + 'codeception/module-asserts' => '^1.2', + 'codeception/module-webdriver' => '^1.1', + 'typo3/testing-framework' => '^6.16.2' + ], + 'autoload-dev' => [ + 'psr-4' => [ + $namespace . '\\Tests\\' => 'Tests/' + ] + ], + 'config' => [ + 'vendor-dir' => '.Build/vendor', + 'bin-dir' => '.Build/bin', + ], + 'extra' => [ + 'typo3/cms' => [ + 'app-dir' => '.Build', + 'web-dir' => '.Build/Web', + ] + ] + ]; + + $enhancedComposer = $this->enhanceComposerFile($composer, $addToComposerFile); + + return GeneralUtility::writeFile($composerFile, json_encode($enhancedComposer, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), true); } /** @@ -157,8 +176,16 @@ protected function updateComposerFile(string $packagePath): bool protected function substituteMarkersAndSave(string $content, string $target): void { $markerService = GeneralUtility::makeInstance(MarkerBasedTemplateService::class); - $templateContent = $markerService->substituteMarker($content, '{{NAMESPACE}}', rtrim($this->getNamespace(), '\\')); - $templateContent = $markerService->substituteMarker($templateContent, '{{EXTENSION_KEY}}', $this->package->getPackageKey()); + $templateContent = $markerService->substituteMarker( + $content, + '{{NAMESPACE}}', + rtrim($this->getNamespace(), '\\') + ); + $templateContent = $markerService->substituteMarker( + $templateContent, + '{{EXTENSION_KEY}}', + $this->package->getPackageKey() + ); try { $this->filesystem->dumpFile($target, $templateContent); @@ -176,4 +203,17 @@ protected function getNamespace(): string { return (string)key((array)($this->package->getValueFromComposerManifest('autoload')->{'psr-4'} ?? [])); } + + private function enhanceComposerFile(array &$composer, array &$addToComposerFile): array + { + foreach ($addToComposerFile as $key => $value) { + if (is_array($value) && isset($composer[$key])) { + $this->enhanceComposerFile($composer[$key], $value); + } else { + $composer[$key] = $value; + } + } + + return $composer; + } } From 48a344b0aae66078f908bebc1250489a167c7362 Mon Sep 17 00:00:00 2001 From: ochorocho Date: Sun, 1 May 2022 21:25:51 +0200 Subject: [PATCH 5/7] [TASK] Use methods from abstract command. --- Classes/Command/AcceptanceTestsCommand.php | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/Classes/Command/AcceptanceTestsCommand.php b/Classes/Command/AcceptanceTestsCommand.php index 8b4f502..a74bf92 100644 --- a/Classes/Command/AcceptanceTestsCommand.php +++ b/Classes/Command/AcceptanceTestsCommand.php @@ -12,7 +12,6 @@ namespace B13\Make\Command; -use B13\Make\PackageResolver; use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; @@ -50,21 +49,14 @@ protected function configure(): void $this->filesystem = GeneralUtility::makeInstance(Filesystem::class); } + /** + * @throws \JsonException + */ protected function execute(InputInterface $input, OutputInterface $output): int { $this->io = new SymfonyStyle($input, $output); + $this->package = $this->askForPackage($this->io); - $packages = $this->getPackageResolver()->getPackageManager()->getActivePackages(); - $choices = array_reduce($packages, function ($result, PackageInterface $package) { - if ($package->getPackageMetaData()->getPackageType() === 'typo3-cms-extension') { - $packageKey = $package->getPackageKey(); - $result[$packageKey] = $packageKey; - } - return $result; - }, []); - - $selectedPackageName = $this->io->choice('Select a package to create acceptance tests for', $choices); - $this->package = $this->getPackageResolver()->resolvePackage($selectedPackageName); $packageKey = $this->package->getPackageKey(); $targetPackagePath = $this->package->getPackagePath(); @@ -194,11 +186,6 @@ protected function substituteMarkersAndSave(string $content, string $target): vo } } - protected function getPackageResolver(): PackageResolver - { - return GeneralUtility::makeInstance(PackageResolver::class); - } - protected function getNamespace(): string { return (string)key((array)($this->package->getValueFromComposerManifest('autoload')->{'psr-4'} ?? [])); From 3b651e4959d37fd47626b29f964c142d0cbe25d6 Mon Sep 17 00:00:00 2001 From: ochorocho Date: Fri, 27 May 2022 00:18:52 +0200 Subject: [PATCH 6/7] [TASK] Use newly introduced extension selection and cleanup old code --- Classes/Command/AcceptanceTestsCommand.php | 11 ++--------- Classes/Command/RunTestsCommand.php | 8 ++++++++ 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Classes/Command/AcceptanceTestsCommand.php b/Classes/Command/AcceptanceTestsCommand.php index a74bf92..3a4c1b6 100644 --- a/Classes/Command/AcceptanceTestsCommand.php +++ b/Classes/Command/AcceptanceTestsCommand.php @@ -14,7 +14,6 @@ use Symfony\Component\Console\Input\InputInterface; use Symfony\Component\Console\Output\OutputInterface; -use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Filesystem\Exception\IOException; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\Finder\Finder; @@ -32,11 +31,6 @@ class AcceptanceTestsCommand extends AbstractCommand */ protected $filesystem; - /** - * @var SymfonyStyle $io - */ - protected $io; - /** * @var PackageInterface $package */ @@ -54,8 +48,7 @@ protected function configure(): void */ protected function execute(InputInterface $input, OutputInterface $output): int { - $this->io = new SymfonyStyle($input, $output); - $this->package = $this->askForPackage($this->io); + $this->package = $this->packageResolver->resolvePackage($this->askForExtensionKey()); $packageKey = $this->package->getPackageKey(); $targetPackagePath = $this->package->getPackagePath(); @@ -70,7 +63,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $finder = GeneralUtility::makeInstance(Finder::class); $codeTemplatePath = '/Resources/Private/CodeTemplates/AcceptanceTests'; - $templatePath = $this->getPackageResolver()->resolvePackage('b13/make')->getPackagePath() . $codeTemplatePath; + $templatePath = $this->packageResolver->resolvePackage('b13/make')->getPackagePath() . $codeTemplatePath; $this->filesystem->mkdir([ $targetPackagePath . '/Tests/Acceptance/Fixtures', diff --git a/Classes/Command/RunTestsCommand.php b/Classes/Command/RunTestsCommand.php index b378c4f..e6becf8 100644 --- a/Classes/Command/RunTestsCommand.php +++ b/Classes/Command/RunTestsCommand.php @@ -73,6 +73,11 @@ protected function execute(InputInterface $input, OutputInterface $output): int ); } + $this->io->writeln('Created docker environment for testing:'); + $filePaths = array_map(function ($ar) {return $ar['target'];}, $templatesToCreate); + $this->io->listing($filePaths); + $this->io->writeln('For details run "cd ' . $this->package->getPackagePath() . ' && ' . 'Build/Scripts/runTests.sh -h"'); + return 0; } @@ -94,6 +99,9 @@ protected function prepareTemplate(string $source, string $target): void try { $this->filesystem->dumpFile($target, $templateContent); + if ((pathinfo($target)['extension'] ?? '') === 'sh') { + $this->filesystem->chmod([$target], 0770); + } } catch (IOException $exception) { $this->io->writeln('Failed to save file in ' . $target . PHP_EOL . $exception->getMessage() . ''); } From 86abbe7ee53f799edcc5634d6a47e319797f4b1d Mon Sep 17 00:00:00 2001 From: ochorocho Date: Thu, 14 Jul 2022 13:19:34 +0200 Subject: [PATCH 7/7] [TASK] Rename 'make:acceptance' to 'make:testing:acceptance' --- Build/testing-docker/docker-compose.yml | 2 +- Classes/Command/RunTestsCommand.php | 114 ------------------------ Configuration/Services.yaml | 2 +- 3 files changed, 2 insertions(+), 116 deletions(-) delete mode 100644 Classes/Command/RunTestsCommand.php diff --git a/Build/testing-docker/docker-compose.yml b/Build/testing-docker/docker-compose.yml index a35aaa7..5cb3439 100644 --- a/Build/testing-docker/docker-compose.yml +++ b/Build/testing-docker/docker-compose.yml @@ -285,7 +285,7 @@ services: set -x fi php -v | grep '^PHP'; - find . -name \\*.php ! -path "./.Build/\\*" ! -path "./Resources/Private/CodeTemplates/\\*" -print0 | xargs -0 -n1 -P4 php -dxdebug.mode=off -l >/dev/null + find . -name \\*.php ! -path "./.Build/\\*" ! -path "./Resources/Private/CodeTemplates\\*" -print0 | xargs -0 -n1 -P4 php -dxdebug.mode=off -l >/dev/null " phpstan: diff --git a/Classes/Command/RunTestsCommand.php b/Classes/Command/RunTestsCommand.php deleted file mode 100644 index e6becf8..0000000 --- a/Classes/Command/RunTestsCommand.php +++ /dev/null @@ -1,114 +0,0 @@ -setDescription('Setup runTests.sh to run tests, linter, cgl in a Docker environment'); - $this->filesystem = GeneralUtility::makeInstance(Filesystem::class); - } - - protected function execute(InputInterface $input, OutputInterface $output): int - { - $this->io = new SymfonyStyle($input, $output); - $this->package = $this->askForPackage($this->io); - - $templatesToCreate = [ - [ - 'source' => 'https://raw.githubusercontent.com/TYPO3/styleguide/main/Build/Scripts/runTests.sh', - 'target' => $this->package->getPackagePath() . 'Build/Scripts/runTests.sh' - ], - [ - 'source' => 'https://raw.githubusercontent.com/TYPO3/styleguide/main/Build/testing-docker/docker-compose.yml', - 'target' => $this->package->getPackagePath() . 'Build/testing-docker/docker-compose.yml' - ] - ]; - - foreach ($templatesToCreate as $template) { - $this->prepareTemplate( - $template['source'], - $template['target'] - ); - } - - $this->io->writeln('Created docker environment for testing:'); - $filePaths = array_map(function ($ar) {return $ar['target'];}, $templatesToCreate); - $this->io->listing($filePaths); - $this->io->writeln('For details run "cd ' . $this->package->getPackagePath() . ' && ' . 'Build/Scripts/runTests.sh -h"'); - - return 0; - } - - protected function prepareTemplate(string $source, string $target): void - { - try { - $template = $this->getGuzzleClient()->get($source); - } catch (GuzzleException $exception) { - $this->io->writeln('Failed to get remote file ' . $source . ''); - return; - } - - $markerService = GeneralUtility::makeInstance(MarkerBasedTemplateService::class); - $templateContent = $markerService->substituteMarker( - $template->getBody(), - 'styleguide', - $this->package->getPackageKey() - ); - - try { - $this->filesystem->dumpFile($target, $templateContent); - if ((pathinfo($target)['extension'] ?? '') === 'sh') { - $this->filesystem->chmod([$target], 0770); - } - } catch (IOException $exception) { - $this->io->writeln('Failed to save file in ' . $target . PHP_EOL . $exception->getMessage() . ''); - } - } - - protected function getGuzzleClient(): Client - { - return GeneralUtility::makeInstance(GuzzleClientFactory::class)->getClient(); - } -} diff --git a/Configuration/Services.yaml b/Configuration/Services.yaml index eafa3fd..15bf9fa 100644 --- a/Configuration/Services.yaml +++ b/Configuration/Services.yaml @@ -54,6 +54,6 @@ services: B13\Make\Command\AcceptanceTestsCommand: tags: - name: 'console.command' - command: 'make:acceptance' + command: 'make:testing:acceptance' description: 'Create files required to run acceptance tests' schedulable: false