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
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,12 @@ path to your custom configuration file to the environment variable
`TYPO3_EXCLUDE_FROM_PACKAGING`. This file must return an
`array` with the keys `directories` and `files` on root level.

The entries are plain directory and file names, matched case-insensitively -
directories against the beginning of the path, files against the end of the
filename. Nested directories can be written as they appear on disk
(`Resources/Private/Build`); slashes escaped as `Resources\/Private\/Build`
are still accepted and describe the very same directory.

## Overview of all available commands

| Commands | Arguments | Options | Description |
Expand Down
21 changes: 19 additions & 2 deletions src/Service/VersionService.php
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ public function createZipArchiveFromPath(string $path): string
if ($current->isDir()) {
// if $current is a directory, check for excluded directories
foreach ($this->excludeConfiguration['directories'] as $excludeDirectory) {
if (preg_match('/^' . preg_quote((string)$excludeDirectory, '/') . '/i', $path)) {
if (preg_match('/^' . $this->quoteExcludePattern((string)$excludeDirectory) . '/i', $path)) {
return false;
}
}
Expand All @@ -90,7 +90,7 @@ public function createZipArchiveFromPath(string $path): string
if ($current->isFile()) {
// if $current is a file, check for excluded files
foreach ($this->excludeConfiguration['files'] as $excludeFile) {
if (preg_match('/' . preg_quote((string)$excludeFile, '/') . '$/i', $filename)) {
if (preg_match('/' . $this->quoteExcludePattern((string)$excludeFile) . '$/i', $filename)) {
return false;
}
}
Expand Down Expand Up @@ -127,6 +127,23 @@ public function createZipArchiveFromPath(string $path): string
return $this->getVersionFilePath();
}

/**
* Quote a configured exclude entry for use within a slash delimited pattern.
*
* The entries are documented as plain directory and file names. Some extensions
* however escape the slashes of a nested directory name (`Resources\/Private\/Build`)
* to work around the unquoted interpolation used in earlier versions. Those escapes
* are removed first, so both notations describe the very same directory.
*
* @param string $excludeEntry The configured directory or file name
*
* @return string The quoted pattern part
*/
protected function quoteExcludePattern(string $excludeEntry): string
{
return preg_quote(str_replace('\\/', '/', $excludeEntry), '/');
}

/**
* Extract the given artefact (from either local or remote),
* store it in a temporary transaction path and finally call
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

return [
'directories' => [
'Resources\/Private\/Build',
],
'files' => [],
];
30 changes: 27 additions & 3 deletions tests/Unit/Service/VersionServiceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,34 @@ public function getVersionFilenameAsMd5Test(): void

#[Test]
public function excludedDirectoryContainingASlashIsNotPackaged(): void
{
$packagedFiles = $this->packageExtensionWithExcludeConfiguration('config_nested_directory.php');

self::assertContains('ext_emconf.php', $packagedFiles);
self::assertNotContains('Resources/Private/Build/gulpfile.js', $packagedFiles);
}

#[Test]
public function excludedDirectoryContainingAnEscapedSlashIsNotPackaged(): void
{
$packagedFiles = $this->packageExtensionWithExcludeConfiguration('config_nested_directory_escaped.php');

self::assertContains('ext_emconf.php', $packagedFiles);
self::assertNotContains('Resources/Private/Build/gulpfile.js', $packagedFiles);
}

/**
* Package an extension directory with the given exclude configuration
* and return the filenames the created archive contains.
*
* @param string $configurationFilename Filename of the exclude configuration fixture
*
* @return list<string> The packaged filenames
*/
protected function packageExtensionWithExcludeConfiguration(string $configurationFilename): array
{
unset($_ENV);
putenv('TYPO3_EXCLUDE_FROM_PACKAGING=' . __DIR__ . '/../Fixtures/ExcludeFromPackaging/config_nested_directory.php');
putenv('TYPO3_EXCLUDE_FROM_PACKAGING=' . __DIR__ . '/../Fixtures/ExcludeFromPackaging/' . $configurationFilename);

$extensionPath = $this->createExtensionDirectory();
$transactionPath = $this->createTemporaryDirectory();
Expand All @@ -130,8 +155,7 @@ public function excludedDirectoryContainingASlashIsNotPackaged(): void

$archive->close();

self::assertContains('ext_emconf.php', $packagedFiles);
self::assertNotContains('Resources/Private/Build/gulpfile.js', $packagedFiles);
return $packagedFiles;
}

/**
Expand Down
Loading