From 6be60fc3360b877bfc613ed36ec5f1efdbda3005 Mon Sep 17 00:00:00 2001 From: cs Date: Wed, 23 Sep 2026 15:06:00 +0200 Subject: [PATCH 1/2] [FEATURE] Add AssetPublishTask for TYPO3 14.2+ Opt-in task that runs `typo3 asset:publish` on the node. Useful when the Composer install happens without the full TYPO3 configuration and asset publishing has to be skipped there. The default workflow stays untouched. --- Documentation/Examples/TYPO3/Index.rst | 22 ++++ src/Task/TYPO3/CMS/AssetPublishTask.php | 55 +++++++++ .../Task/TYPO3/CMS/AssetPublishTaskTest.php | 105 ++++++++++++++++++ 3 files changed, 182 insertions(+) create mode 100644 src/Task/TYPO3/CMS/AssetPublishTask.php create mode 100644 tests/Unit/Task/TYPO3/CMS/AssetPublishTaskTest.php diff --git a/Documentation/Examples/TYPO3/Index.rst b/Documentation/Examples/TYPO3/Index.rst index 8014ffa7..38536e1e 100644 --- a/Documentation/Examples/TYPO3/Index.rst +++ b/Documentation/Examples/TYPO3/Index.rst @@ -44,3 +44,25 @@ If you would like to deploy a TYPO3 website a good starting point is to use TYPO ->afterStage('switch', \TYPO3\Surf\Task\Php\WebOpcacheResetExecuteTask::class, $application); } ); + +Publishing extension assets (TYPO3 14.2 and later) +================================================== + +For how TYPO3 publishes extension assets, see +`Assets `__ +and +`Feature #109163 `__. + +If the Composer install runs without the complete TYPO3 configuration, skip +the publishing there and publish on the node with the +``AssetPublishTask`` instead:: + + $deployment->onInitialize( + function () use ($deployment, $application) { + $deployment->getWorkflow() + ->setTaskOptions('TYPO3\\Surf\\DefinedTask\\Composer\\LocalInstallTask', [ + 'composerCommandPath' => 'TYPO3_SKIP_ASSET_PUBLISH=1 composer', + ]) + ->addTask(\TYPO3\Surf\Task\TYPO3\CMS\AssetPublishTask::class, 'migrate', $application); + } + ); diff --git a/src/Task/TYPO3/CMS/AssetPublishTask.php b/src/Task/TYPO3/CMS/AssetPublishTask.php new file mode 100644 index 00000000..167577f5 --- /dev/null +++ b/src/Task/TYPO3/CMS/AssetPublishTask.php @@ -0,0 +1,55 @@ + $options + */ + public function execute(Node $node, Application $application, Deployment $deployment, array $options = []): void + { + Assert::isInstanceOf($application, CMS::class); + /** @var CMS $application */ + $options = $this->configureOptions($options); + + $this->executeCliCommand( + array_merge( + [$this->getTypo3CoreCliFileName($node, $application, $deployment, $options), 'asset:publish'], + $options['arguments'] + ), + $node, + $application, + $deployment, + $options + ); + } + + protected function resolveOptions(OptionsResolver $resolver): void + { + $resolver->setDefault('arguments', []) + ->setAllowedTypes('arguments', ['array', 'string']) + ->setNormalizer('arguments', fn (Options $options, $value): array => (array)$value); + } +} diff --git a/tests/Unit/Task/TYPO3/CMS/AssetPublishTaskTest.php b/tests/Unit/Task/TYPO3/CMS/AssetPublishTaskTest.php new file mode 100644 index 00000000..94c3783b --- /dev/null +++ b/tests/Unit/Task/TYPO3/CMS/AssetPublishTaskTest.php @@ -0,0 +1,105 @@ +application = new CMS('TestApplication'); + $this->application->setDeploymentPath('/home/jdoe/app'); + } + + protected function createTask(): AssetPublishTask + { + return new AssetPublishTask(); + } + + /** + * @test + */ + public function wrongApplicationTypeGivenThrowsException(): void + { + $invalidApplication = new BaseApplication('Hello world app'); + $this->expectException(InvalidArgumentException::class); + $this->task->execute($this->node, $invalidApplication, $this->deployment, []); + } + + /** + * @test + */ + public function missingTypo3CliFailsTheDeploymentInsteadOfSkippingThePublishing(): void + { + $this->expectException(InvalidConfigurationException::class); + $this->task->execute($this->node, $this->application, $this->deployment, []); + } + + /** + * @test + */ + public function executeWithWrongArgumentsTypeThrowsException(): void + { + $this->expectException(InvalidConfigurationException::class); + $options = [ + 'typo3CliFileName' => 'typo3', + 'arguments' => 1 + ]; + $this->task->execute($this->node, $this->application, $this->deployment, $options); + } + + /** + * @test + */ + public function executeWithoutArgumentsExecutesAssetPublish(): void + { + $options = [ + 'typo3CliFileName' => 'vendor/bin/typo3' + ]; + $this->task->execute($this->node, $this->application, $this->deployment, $options); + $this->assertCommandExecuted("/^cd '\/releases\/[0-9]+'$/"); + $this->assertCommandExecuted("/php 'vendor\/bin\/typo3' 'asset:publish'$/"); + } + + /** + * @test + */ + public function executeWithArgumentsPassesThemToAssetPublish(): void + { + $options = [ + 'typo3CliFileName' => 'vendor/bin/typo3', + 'arguments' => ['-v'] + ]; + $this->task->execute($this->node, $this->application, $this->deployment, $options); + $this->assertCommandExecuted("/php 'vendor\/bin\/typo3' 'asset:publish' '-v'$/"); + } + + /** + * @test + */ + public function executeWithContextOptionSetsTypo3Context(): void + { + $options = [ + 'typo3CliFileName' => 'vendor/bin/typo3', + 'context' => 'Production' + ]; + $this->task->execute($this->node, $this->application, $this->deployment, $options); + $this->assertCommandExecuted("/TYPO3_CONTEXT='Production' php 'vendor\/bin\/typo3' 'asset:publish'$/"); + } +} From 2240287143809475651c01fffba8a5d4ed8d2fbf Mon Sep 17 00:00:00 2001 From: cs Date: Wed, 23 Sep 2026 15:06:00 +0200 Subject: [PATCH 2/2] [DOCS] Add settings.php symlink example for TYPO3 12+ --- Documentation/Examples/TYPO3/Index.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/Examples/TYPO3/Index.rst b/Documentation/Examples/TYPO3/Index.rst index 38536e1e..ddc31572 100644 --- a/Documentation/Examples/TYPO3/Index.rst +++ b/Documentation/Examples/TYPO3/Index.rst @@ -45,6 +45,15 @@ If you would like to deploy a TYPO3 website a good starting point is to use TYPO } ); +Configuration file in TYPO3 12 and later +======================================== + +Since TYPO3 12 the configuration lives in :file:`config/system/settings.php` +instead of :file:`typo3conf/LocalConfiguration.php`. Replace the symlink of the +example above with:: + + $application->addSymlink('config/system/settings.php', '../../../../shared/Configuration/settings.php'); + Publishing extension assets (TYPO3 14.2 and later) ==================================================