From a941773cb0fad28bb4e3ea7028ea9059feb95c32 Mon Sep 17 00:00:00 2001 From: phenaproxima <phenaproxima@205645.no-reply.drupal.org> Date: Fri, 17 Dec 2021 16:03:49 +0000 Subject: [PATCH] Issue #3254616 by phenaproxima, tedbow: Update Composer Stager to 0.3.0 --- composer.json | 2 +- package_manager/package_manager.services.yml | 10 +- .../src/Event/ExcludedPathsTrait.php | 17 +- .../ComposerExecutableValidator.php | 10 +- .../ExcludedPathsSubscriber.php | 169 ++++++++++++------ package_manager/src/FileSyncerFactory.php | 14 +- .../tests/fixtures/fake_site/vendor/.htaccess | 1 + .../package_manager_bypass/src/Beginner.php | 4 +- .../package_manager_bypass/src/Committer.php | 4 +- .../package_manager_bypass/src/Stager.php | 4 +- .../src/Functional/ExcludedPathsTest.php | 60 ++++--- .../ComposerExecutableValidatorTest.php | 4 +- .../Kernel/ComposerSettingsValidatorTest.php | 1 + .../src/Kernel/DiskSpaceValidatorTest.php | 1 + .../Kernel/ExcludedPathsSubscriberTest.php | 8 +- .../WritableFileSystemValidatorTest.php | 1 + tests/src/Build/UpdateTestBase.php | 5 +- .../StagedProjectsValidatorTest.php | 1 + tests/src/Kernel/UpdaterTest.php | 1 + 19 files changed, 197 insertions(+), 120 deletions(-) create mode 100644 package_manager/tests/fixtures/fake_site/vendor/.htaccess diff --git a/composer.json b/composer.json index 36692bf5da..39bd124972 100644 --- a/composer.json +++ b/composer.json @@ -13,7 +13,7 @@ "require": { "ext-json": "*", "drupal/core": "^9.2", - "php-tuf/composer-stager": "0.2.3", + "php-tuf/composer-stager": "0.3.0", "composer/composer": "^2" }, "config": { diff --git a/package_manager/package_manager.services.yml b/package_manager/package_manager.services.yml index d2b01442f1..f5e04442d0 100644 --- a/package_manager/package_manager.services.yml +++ b/package_manager/package_manager.services.yml @@ -4,8 +4,6 @@ services: class: Symfony\Component\Filesystem\Filesystem package_manager.symfony_executable_finder: class: Symfony\Component\Process\ExecutableFinder - package_manager.symfony_finder: - class: Symfony\Component\Finder\Finder # Basic infrastructure services. package_manager.process_factory: @@ -45,8 +43,6 @@ services: class: PhpTuf\ComposerStager\Infrastructure\FileSyncer\PhpFileSyncer arguments: - '@package_manager.file_system' - - '@package_manager.symfony_finder' - - '@package_manager.symfony_finder' package_manager.file_syncer.factory: class: Drupal\package_manager\FileSyncerFactory arguments: @@ -55,7 +51,7 @@ services: - '@package_manager.file_syncer.rsync' - '@config.factory' package_manager.file_syncer: - class: PhpTuf\ComposerStager\Infrastructure\FileSyncer\FileSyncerInterface + class: PhpTuf\ComposerStager\Domain\FileSyncer\FileSyncerInterface factory: ['@package_manager.file_syncer.factory', 'create'] # Domain services. @@ -127,10 +123,10 @@ services: package_manager.excluded_paths_subscriber: class: Drupal\package_manager\EventSubscriber\ExcludedPathsSubscriber arguments: - - '%app.root%' - '%site.path%' - - '@file_system' + - '@package_manager.symfony_file_system' - '@stream_wrapper_manager' - '@database' + - '@package_manager.path_locator' tags: - { name: event_subscriber } diff --git a/package_manager/src/Event/ExcludedPathsTrait.php b/package_manager/src/Event/ExcludedPathsTrait.php index 3648446b80..fc7e690440 100644 --- a/package_manager/src/Event/ExcludedPathsTrait.php +++ b/package_manager/src/Event/ExcludedPathsTrait.php @@ -15,12 +15,23 @@ trait ExcludedPathsTrait { protected $excludedPaths = []; /** - * Adds an absolute path to exclude from the current operation. + * Adds a path to exclude from the current operation. * - * @todo This should only accept paths relative to the active directory. + * If called on an instance of \Drupal\package_manager\Event\PreCreateEvent, + * excluded paths will not be copied into the staging area when the stage is + * created. If called on an instance of + * \Drupal\package_manager\Event\PreApplyEvent, excluded paths will not be + * deleted from the active directory when staged changes are applied. So, + * to ensure that a given path is never staged, but also preserved in the + * active directory, it should be passed to this method on both PreCreateEvent + * and PreApplyEvent. See + * \Drupal\package_manager\EventSubscriber\ExcludedPathsSubscriber for an + * example. * * @param string $path - * The path to exclude. + * The path to exclude, relative to the project root. + * + * @see \Drupal\package_manager\EventSubscriber\ExcludedPathsSubscriber */ public function excludePath(string $path): void { $this->excludedPaths[] = $path; diff --git a/package_manager/src/EventSubscriber/ComposerExecutableValidator.php b/package_manager/src/EventSubscriber/ComposerExecutableValidator.php index a4df9a3591..f91e852930 100644 --- a/package_manager/src/EventSubscriber/ComposerExecutableValidator.php +++ b/package_manager/src/EventSubscriber/ComposerExecutableValidator.php @@ -7,21 +7,21 @@ use Drupal\package_manager\Event\PreOperationStageEvent; use Drupal\Core\Extension\ExtensionVersion; use Drupal\Core\StringTranslation\StringTranslationTrait; use Drupal\Core\StringTranslation\TranslationInterface; -use PhpTuf\ComposerStager\Domain\Output\ProcessOutputCallbackInterface; +use PhpTuf\ComposerStager\Domain\Process\OutputCallbackInterface; +use PhpTuf\ComposerStager\Domain\Process\Runner\ComposerRunnerInterface; use PhpTuf\ComposerStager\Exception\ExceptionInterface; -use PhpTuf\ComposerStager\Infrastructure\Process\Runner\ComposerRunnerInterface; /** * Validates that the Composer executable can be found in the correct version. */ -class ComposerExecutableValidator implements PreOperationStageValidatorInterface, ProcessOutputCallbackInterface { +class ComposerExecutableValidator implements PreOperationStageValidatorInterface, OutputCallbackInterface { use StringTranslationTrait; /** * The Composer runner. * - * @var \PhpTuf\ComposerStager\Infrastructure\Process\Runner\ComposerRunnerInterface + * @var \PhpTuf\ComposerStager\Domain\Process\Runner\ComposerRunnerInterface */ protected $composer; @@ -35,7 +35,7 @@ class ComposerExecutableValidator implements PreOperationStageValidatorInterface /** * Constructs a ComposerExecutableValidator object. * - * @param \PhpTuf\ComposerStager\Infrastructure\Process\Runner\ComposerRunnerInterface $composer + * @param \PhpTuf\ComposerStager\Domain\Process\Runner\ComposerRunnerInterface $composer * The Composer runner. * @param \Drupal\Core\StringTranslation\TranslationInterface $translation * The translation service. diff --git a/package_manager/src/EventSubscriber/ExcludedPathsSubscriber.php b/package_manager/src/EventSubscriber/ExcludedPathsSubscriber.php index 4663284c79..b65ff7a709 100644 --- a/package_manager/src/EventSubscriber/ExcludedPathsSubscriber.php +++ b/package_manager/src/EventSubscriber/ExcludedPathsSubscriber.php @@ -3,25 +3,20 @@ namespace Drupal\package_manager\EventSubscriber; use Drupal\Core\Database\Connection; -use Drupal\Core\File\FileSystemInterface; use Drupal\Core\StreamWrapper\LocalStream; use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface; use Drupal\package_manager\Event\PreApplyEvent; use Drupal\package_manager\Event\PreCreateEvent; +use Drupal\package_manager\Event\StageEvent; +use Drupal\package_manager\PathLocator; use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\Filesystem\Filesystem; /** * Defines an event subscriber to exclude certain paths from staging areas. */ class ExcludedPathsSubscriber implements EventSubscriberInterface { - /** - * The Drupal root. - * - * @var string - */ - protected $appRoot; - /** * The current site path, relative to the Drupal root. * @@ -30,9 +25,9 @@ class ExcludedPathsSubscriber implements EventSubscriberInterface { protected $sitePath; /** - * The file system service. + * The Symfony file system service. * - * @var \Drupal\Core\File\FileSystemInterface + * @var \Symfony\Component\Filesystem\Filesystem */ protected $fileSystem; @@ -50,91 +45,157 @@ class ExcludedPathsSubscriber implements EventSubscriberInterface { */ protected $database; + /** + * The path locator service. + * + * @var \Drupal\package_manager\PathLocator + */ + protected $pathLocator; + /** * Constructs an ExcludedPathsSubscriber. * - * @param string $app_root - * The Drupal root. * @param string $site_path * The current site path, relative to the Drupal root. - * @param \Drupal\Core\File\FileSystemInterface $file_system - * The file system service. + * @param \Symfony\Component\Filesystem\Filesystem $file_system + * The Symfony file system service. * @param \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $stream_wrapper_manager * The stream wrapper manager service. * @param \Drupal\Core\Database\Connection $database * The database connection. + * @param \Drupal\package_manager\PathLocator $path_locator + * The path locator service. */ - public function __construct(string $app_root, string $site_path, FileSystemInterface $file_system, StreamWrapperManagerInterface $stream_wrapper_manager, Connection $database) { - $this->appRoot = $app_root; + public function __construct(string $site_path, Filesystem $file_system, StreamWrapperManagerInterface $stream_wrapper_manager, Connection $database, PathLocator $path_locator) { $this->sitePath = $site_path; $this->fileSystem = $file_system; $this->streamWrapperManager = $stream_wrapper_manager; $this->database = $database; + $this->pathLocator = $path_locator; } /** - * Reacts before staged changes are committed the active directory. + * Flags paths to be excluded, relative to the web root. * - * @param \Drupal\package_manager\Event\PreApplyEvent $event + * This should only be used for paths that, if they exist at all, are + * *guaranteed* to exist within the web root. + * + * @param \Drupal\package_manager\Event\PreCreateEvent|\Drupal\package_manager\Event\PreApplyEvent $event * The event object. + * @param string[] $paths + * The paths to exclude. These should be relative to the web root, and will + * be made relative to the project root. */ - public function preApply(PreApplyEvent $event): void { - // Don't copy anything from the staging area's sites/default. - // @todo Make this a lot smarter in https://www.drupal.org/i/3228955. - $event->excludePath('sites/default'); + protected function excludeInWebRoot(StageEvent $event, array $paths): void { + $web_root = $this->pathLocator->getWebRoot(); + if ($web_root) { + $web_root .= '/'; + } - // If the core-vendor-hardening plugin (used in the legacy-project template) - // is present, it may have written a web.config file into the vendor - // directory. We don't want to copy that. - $event->excludePath('web.config'); + foreach ($paths as $path) { + // Make the path relative to the project root by prefixing the web root. + $event->excludePath($web_root . $path); + } } /** - * Excludes paths from a staging area before it is created. + * Flags paths to be excluded, relative to the project root. * - * @param \Drupal\package_manager\Event\PreCreateEvent $event + * @param \Drupal\package_manager\Event\PreCreateEvent|\Drupal\package_manager\Event\PreApplyEvent $event * The event object. + * @param string[] $paths + * The paths to exclude. Absolute paths will be made relative to the project + * root; relative paths will be assumed to already be relative to the + * project root, and excluded as given. */ - public function preCreate(PreCreateEvent $event): void { - // Automated test site directories should never be staged. - $event->excludePath('sites/simpletest'); - - // Windows server configuration files, like web.config, should never be - // staged either. (These can be written in the vendor directory by the - // core-vendor-hardening plugin, which is used in the drupal/legacy-project - // template.) - $event->excludePath('web.config'); - - if ($public = $this->getFilesPath('public')) { - $event->excludePath($public); + protected function excludeInProjectRoot(StageEvent $event, array $paths): void { + $project_root = $this->pathLocator->getProjectRoot(); + + foreach ($paths as $path) { + // Make absolute paths relative to the project root. + $path = str_replace($project_root, NULL, $path); + $path = ltrim($path, '/'); + $event->excludePath($path); } - if ($private = $this->getFilesPath('private')) { - $event->excludePath($private); + } + + /** + * Excludes common paths from staging operations. + * + * @param \Drupal\package_manager\Event\PreApplyEvent|\Drupal\package_manager\Event\PreCreateEvent $event + * The event object. + * + * @see \Drupal\package_manager\Event\ExcludedPathsTrait::excludePath() + */ + public function ignoreCommonPaths(StageEvent $event): void { + // Compile two lists of paths to exclude: paths that are relative to the + // project root, and paths that are relative to the web root. + $web = $project = []; + + // Always ignore automated test directories. If they exist, they will be in + // the web root. + $web[] = 'sites/simpletest'; + + // If the core-vendor-hardening plugin (used in the legacy-project template) + // is present, it may have written security hardening files in the vendor + // directory. They should always be ignored. + $vendor_dir = $this->pathLocator->getVendorDirectory(); + $project[] = $vendor_dir . '/web.config'; + $project[] = $vendor_dir . '/.htaccess'; + + // Ignore public and private files. These paths could be either absolute or + // relative, depending on site settings. If they are absolute, treat them + // as relative to the project root. Otherwise, treat them as relative to + // the web root. + $files = array_filter([ + $this->getFilesPath('public'), + $this->getFilesPath('private'), + ]); + foreach ($files as $path) { + if ($this->fileSystem->isAbsolutePath($path)) { + $project[] = $path; + } + else { + $web[] = $path; + } } - // Exclude site-specific settings files. + // Ignore site-specific settings files, which are always in the web root. $settings_files = [ 'settings.php', 'settings.local.php', 'services.yml', ]; - $default_site = 'sites' . DIRECTORY_SEPARATOR . 'default'; - foreach ($settings_files as $settings_file) { - $event->excludePath($this->sitePath . DIRECTORY_SEPARATOR . $settings_file); - $event->excludePath($default_site . DIRECTORY_SEPARATOR . $settings_file); + $web[] = $this->sitePath . '/' . $settings_file; + $web[] = 'sites/default/' . $settings_file; } // If the database is SQLite, it might be located in the active directory - // and we should not stage it. + // and we should ignore it. Always treat it as relative to the project root. if ($this->database->driver() === 'sqlite') { $options = $this->database->getConnectionOptions(); - $database = str_replace($this->appRoot, NULL, $options['database']); - $database = ltrim($database, '/'); - $event->excludePath($database); - $event->excludePath("$database-shm"); - $event->excludePath("$database-wal"); + $project[] = $options['database']; + $project[] = $options['database'] . '-shm'; + $project[] = $options['database'] . '-wal'; } + + $this->excludeInWebRoot($event, $web); + $this->excludeInProjectRoot($event, $project); + } + + /** + * Reacts before staged changes are committed the active directory. + * + * @param \Drupal\package_manager\Event\PreApplyEvent $event + * The event object. + */ + public function preApply(PreApplyEvent $event): void { + // Don't copy anything from the staging area's sites/default. + // @todo Make this a lot smarter in https://www.drupal.org/i/3228955. + $this->excludeInWebRoot($event, ['sites/default']); + + $this->ignoreCommonPaths($event); } /** @@ -165,7 +226,7 @@ class ExcludedPathsSubscriber implements EventSubscriberInterface { */ public static function getSubscribedEvents() { return [ - PreCreateEvent::class => 'preCreate', + PreCreateEvent::class => 'ignoreCommonPaths', PreApplyEvent::class => 'preApply', ]; } diff --git a/package_manager/src/FileSyncerFactory.php b/package_manager/src/FileSyncerFactory.php index 727620a248..ee96aa1e57 100644 --- a/package_manager/src/FileSyncerFactory.php +++ b/package_manager/src/FileSyncerFactory.php @@ -3,9 +3,9 @@ namespace Drupal\package_manager; use Drupal\Core\Config\ConfigFactoryInterface; -use PhpTuf\ComposerStager\Infrastructure\FileSyncer\FileSyncerFactoryInterface; +use PhpTuf\ComposerStager\Domain\FileSyncer\FileSyncerFactoryInterface; +use PhpTuf\ComposerStager\Domain\FileSyncer\FileSyncerInterface; use PhpTuf\ComposerStager\Infrastructure\FileSyncer\FileSyncerFactory as StagerFileSyncerFactory; -use PhpTuf\ComposerStager\Infrastructure\FileSyncer\FileSyncerInterface; use Symfony\Component\Process\ExecutableFinder; /** @@ -16,21 +16,21 @@ class FileSyncerFactory implements FileSyncerFactoryInterface { /** * The decorated file syncer factory. * - * @var \PhpTuf\ComposerStager\Infrastructure\FileSyncer\FileSyncerFactoryInterface + * @var \PhpTuf\ComposerStager\Domain\FileSyncer\FileSyncerFactoryInterface */ protected $decorated; /** * The PHP file syncer service. * - * @var \PhpTuf\ComposerStager\Infrastructure\FileSyncer\FileSyncerInterface + * @var \PhpTuf\ComposerStager\Domain\FileSyncer\FileSyncerInterface */ protected $phpFileSyncer; /** * The rsync file syncer service. * - * @var \PhpTuf\ComposerStager\Infrastructure\FileSyncer\FileSyncerInterface + * @var \PhpTuf\ComposerStager\Domain\FileSyncer\FileSyncerInterface */ protected $rsyncFileSyncer; @@ -46,9 +46,9 @@ class FileSyncerFactory implements FileSyncerFactoryInterface { * * @param \Symfony\Component\Process\ExecutableFinder $executable_finder * The Symfony executable finder. - * @param \PhpTuf\ComposerStager\Infrastructure\FileSyncer\FileSyncerInterface $php_file_syncer + * @param \PhpTuf\ComposerStager\Domain\FileSyncer\FileSyncerInterface $php_file_syncer * The PHP file syncer service. - * @param \PhpTuf\ComposerStager\Infrastructure\FileSyncer\FileSyncerInterface $rsync_file_syncer + * @param \PhpTuf\ComposerStager\Domain\FileSyncer\FileSyncerInterface $rsync_file_syncer * The rsync file syncer service. * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * The config factory service. diff --git a/package_manager/tests/fixtures/fake_site/vendor/.htaccess b/package_manager/tests/fixtures/fake_site/vendor/.htaccess new file mode 100644 index 0000000000..e11552b41d --- /dev/null +++ b/package_manager/tests/fixtures/fake_site/vendor/.htaccess @@ -0,0 +1 @@ +# This file should never be staged. diff --git a/package_manager/tests/modules/package_manager_bypass/src/Beginner.php b/package_manager/tests/modules/package_manager_bypass/src/Beginner.php index 742d38bd85..e9ff25509f 100644 --- a/package_manager/tests/modules/package_manager_bypass/src/Beginner.php +++ b/package_manager/tests/modules/package_manager_bypass/src/Beginner.php @@ -3,7 +3,7 @@ namespace Drupal\package_manager_bypass; use PhpTuf\ComposerStager\Domain\BeginnerInterface; -use PhpTuf\ComposerStager\Domain\Output\ProcessOutputCallbackInterface; +use PhpTuf\ComposerStager\Domain\Process\OutputCallbackInterface; /** * Defines an update beginner which doesn't do anything. @@ -13,7 +13,7 @@ class Beginner extends InvocationRecorderBase implements BeginnerInterface { /** * {@inheritdoc} */ - public function begin(string $activeDir, string $stagingDir, ?array $exclusions = [], ?ProcessOutputCallbackInterface $callback = NULL, ?int $timeout = 120): void { + public function begin(string $activeDir, string $stagingDir, ?array $exclusions = [], ?OutputCallbackInterface $callback = NULL, ?int $timeout = 120): void { $this->saveInvocationArguments($activeDir, $stagingDir, $exclusions); } diff --git a/package_manager/tests/modules/package_manager_bypass/src/Committer.php b/package_manager/tests/modules/package_manager_bypass/src/Committer.php index 3518237b5b..2feb0d0f70 100644 --- a/package_manager/tests/modules/package_manager_bypass/src/Committer.php +++ b/package_manager/tests/modules/package_manager_bypass/src/Committer.php @@ -3,7 +3,7 @@ namespace Drupal\package_manager_bypass; use PhpTuf\ComposerStager\Domain\CommitterInterface; -use PhpTuf\ComposerStager\Domain\Output\ProcessOutputCallbackInterface; +use PhpTuf\ComposerStager\Domain\Process\OutputCallbackInterface; /** * Defines an update committer which doesn't do any actual committing. @@ -30,7 +30,7 @@ class Committer extends InvocationRecorderBase implements CommitterInterface { /** * {@inheritdoc} */ - public function commit(string $stagingDir, string $activeDir, ?array $exclusions = [], ?ProcessOutputCallbackInterface $callback = NULL, ?int $timeout = 120): void { + public function commit(string $stagingDir, string $activeDir, ?array $exclusions = [], ?OutputCallbackInterface $callback = NULL, ?int $timeout = 120): void { $this->saveInvocationArguments($activeDir, $stagingDir, $exclusions); } diff --git a/package_manager/tests/modules/package_manager_bypass/src/Stager.php b/package_manager/tests/modules/package_manager_bypass/src/Stager.php index bb93e47271..237eccab38 100644 --- a/package_manager/tests/modules/package_manager_bypass/src/Stager.php +++ b/package_manager/tests/modules/package_manager_bypass/src/Stager.php @@ -2,7 +2,7 @@ namespace Drupal\package_manager_bypass; -use PhpTuf\ComposerStager\Domain\Output\ProcessOutputCallbackInterface; +use PhpTuf\ComposerStager\Domain\Process\OutputCallbackInterface; use PhpTuf\ComposerStager\Domain\StagerInterface; /** @@ -13,7 +13,7 @@ class Stager extends InvocationRecorderBase implements StagerInterface { /** * {@inheritdoc} */ - public function stage(array $composerCommand, string $stagingDir, ?ProcessOutputCallbackInterface $callback = NULL, ?int $timeout = 120): void { + public function stage(array $composerCommand, string $stagingDir, ?OutputCallbackInterface $callback = NULL, ?int $timeout = 120): void { $this->saveInvocationArguments($composerCommand, $stagingDir); } diff --git a/package_manager/tests/src/Functional/ExcludedPathsTest.php b/package_manager/tests/src/Functional/ExcludedPathsTest.php index 2870806996..dbc3dab973 100644 --- a/package_manager/tests/src/Functional/ExcludedPathsTest.php +++ b/package_manager/tests/src/Functional/ExcludedPathsTest.php @@ -117,38 +117,44 @@ class ExcludedPathsTest extends BrowserTestBase { }; $stage::$stagingRoot = $this->siteDirectory . '/stage'; $stage_dir = $stage::$stagingRoot . DIRECTORY_SEPARATOR . $stage->create(); - $this->assertDirectoryExists($stage_dir); - $this->assertDirectoryDoesNotExist("$stage_dir/sites/simpletest"); - $this->assertFileDoesNotExist("$stage_dir/vendor/web.config"); - $this->assertDirectoryDoesNotExist("$stage_dir/$site_path/files"); - $this->assertDirectoryDoesNotExist("$stage_dir/private"); - $this->assertFileDoesNotExist("$stage_dir/$site_path/settings.php"); - $this->assertFileDoesNotExist("$stage_dir/$site_path/settings.local.php"); - $this->assertFileDoesNotExist("$stage_dir/$site_path/services.yml"); - // SQLite databases and their support files should never be staged. - $this->assertFileDoesNotExist("$stage_dir/$site_path/db.sqlite"); - $this->assertFileDoesNotExist("$stage_dir/$site_path/db.sqlite-shm"); - $this->assertFileDoesNotExist("$stage_dir/$site_path/db.sqlite-wal"); - // Default site-specific settings files should never be staged. - $this->assertFileDoesNotExist("$stage_dir/sites/default/settings.php"); - $this->assertFileDoesNotExist("$stage_dir/sites/default/settings.local.php"); - $this->assertFileDoesNotExist("$stage_dir/sites/default/services.yml"); - // A non-excluded file in the default site directory should be staged. - $this->assertFileExists("$stage_dir/sites/default/stage.txt"); - $files = [ - 'sites/default/no-copy.txt', - 'web.config', + $ignore = [ + 'sites/simpletest', + 'vendor/.htaccess', + 'vendor/web.config', + "$site_path/files/ignore.txt", + 'private/ignore.txt', + "$site_path/settings.php", + "$site_path/settings.local.php", + "$site_path/services.yml", + // SQLite databases and their support files should always be ignored. + "$site_path/db.sqlite", + "$site_path/db.sqlite-shm", + "$site_path/db.sqlite-wal", + // Default site-specific settings files should be ignored. + 'sites/default/settings.php', + 'sites/default/settings.local.php', + 'sites/default/services.yml', ]; - foreach ($files as $file) { - $file = "$stage_dir/$file"; - touch($file); - $this->assertFileExists($file); + foreach ($ignore as $path) { + $this->assertFileExists("$active_dir/$path"); + $this->assertFileDoesNotExist("$stage_dir/$path"); } + // A non-excluded file in the default site directory should be staged. + $this->assertFileExists("$stage_dir/sites/default/stage.txt"); + + // A new file added to the staging area in an excluded directory, should not + // be copied to the active directory. + $file = "$stage_dir/sites/default/no-copy.txt"; + touch($file); + $this->assertFileExists($file); $stage->apply(); - foreach ($files as $file) { - $this->assertFileDoesNotExist("$active_dir/$file"); + $this->assertFileDoesNotExist("$active_dir/sites/default/no-copy.txt"); + + // The ignored files should still be in the active directory. + foreach ($ignore as $path) { + $this->assertFileExists("$active_dir/$path"); } } diff --git a/package_manager/tests/src/Kernel/ComposerExecutableValidatorTest.php b/package_manager/tests/src/Kernel/ComposerExecutableValidatorTest.php index 8905f788ed..bc57b4fa75 100644 --- a/package_manager/tests/src/Kernel/ComposerExecutableValidatorTest.php +++ b/package_manager/tests/src/Kernel/ComposerExecutableValidatorTest.php @@ -112,8 +112,8 @@ class ComposerExecutableValidatorTest extends PackageManagerKernelTestBase { // Mock the output of `composer --version`, will be passed to the validator, // which is itself a callback function that gets called repeatedly as // Composer produces output. - /** @var \PhpTuf\ComposerStager\Infrastructure\Process\Runner\ComposerRunnerInterface|\Prophecy\Prophecy\ObjectProphecy $runner */ - $runner = $this->prophesize('\PhpTuf\ComposerStager\Infrastructure\Process\Runner\ComposerRunnerInterface'); + /** @var \PhpTuf\ComposerStager\Domain\Process\Runner\ComposerRunnerInterface|\Prophecy\Prophecy\ObjectProphecy $runner */ + $runner = $this->prophesize('\PhpTuf\ComposerStager\Domain\Process\Runner\ComposerRunnerInterface'); $runner->run(['--version'], Argument::type(ComposerExecutableValidator::class)) // Whatever is passed to ::run() will be passed to this mock callback in diff --git a/package_manager/tests/src/Kernel/ComposerSettingsValidatorTest.php b/package_manager/tests/src/Kernel/ComposerSettingsValidatorTest.php index fae703f6e0..ff09f97428 100644 --- a/package_manager/tests/src/Kernel/ComposerSettingsValidatorTest.php +++ b/package_manager/tests/src/Kernel/ComposerSettingsValidatorTest.php @@ -85,6 +85,7 @@ class ComposerSettingsValidatorTest extends PackageManagerKernelTestBase { $locator = $this->prophesize(PathLocator::class); $locator->getActiveDirectory()->willReturn($active_dir); $locator->getProjectRoot()->willReturn($active_dir); + $locator->getWebRoot()->willReturn(''); $locator->getVendorDirectory()->willReturn($active_dir); $this->container->set('package_manager.path_locator', $locator->reveal()); diff --git a/package_manager/tests/src/Kernel/DiskSpaceValidatorTest.php b/package_manager/tests/src/Kernel/DiskSpaceValidatorTest.php index ea15bb086e..3195b51d3a 100644 --- a/package_manager/tests/src/Kernel/DiskSpaceValidatorTest.php +++ b/package_manager/tests/src/Kernel/DiskSpaceValidatorTest.php @@ -168,6 +168,7 @@ class DiskSpaceValidatorTest extends PackageManagerKernelTestBase { public function testDiskSpaceValidation(bool $shared_disk, array $free_space, array $expected_results): void { $path_locator = $this->prophesize('\Drupal\package_manager\PathLocator'); $path_locator->getProjectRoot()->willReturn('root'); + $path_locator->getWebRoot()->willReturn(''); $path_locator->getActiveDirectory()->willReturn('root'); $path_locator->getVendorDirectory()->willReturn('vendor'); $this->container->set('package_manager.path_locator', $path_locator->reveal()); diff --git a/package_manager/tests/src/Kernel/ExcludedPathsSubscriberTest.php b/package_manager/tests/src/Kernel/ExcludedPathsSubscriberTest.php index b44f7811d6..538232d5b5 100644 --- a/package_manager/tests/src/Kernel/ExcludedPathsSubscriberTest.php +++ b/package_manager/tests/src/Kernel/ExcludedPathsSubscriberTest.php @@ -83,15 +83,15 @@ class ExcludedPathsSubscriberTest extends PackageManagerKernelTestBase { $connection->getConnectionOptions()->willReturn(['database' => $database]); $subscriber = new ExcludedPathsSubscriber( - $this->getDrupalRoot(), 'sites/default', - $this->container->get('file_system'), + $this->container->get('package_manager.symfony_file_system'), $this->container->get('stream_wrapper_manager'), - $connection->reveal() + $connection->reveal(), + $this->container->get('package_manager.path_locator') ); $event = new PreCreateEvent($this->createStage()); - $subscriber->preCreate($event); + $subscriber->ignoreCommonPaths($event); // All of the expected exclusions should be flagged. $this->assertEmpty(array_diff($expected_exclusions, $event->getExcludedPaths())); } diff --git a/package_manager/tests/src/Kernel/WritableFileSystemValidatorTest.php b/package_manager/tests/src/Kernel/WritableFileSystemValidatorTest.php index 136d6b37cb..871d42c4aa 100644 --- a/package_manager/tests/src/Kernel/WritableFileSystemValidatorTest.php +++ b/package_manager/tests/src/Kernel/WritableFileSystemValidatorTest.php @@ -113,6 +113,7 @@ class WritableFileSystemValidatorTest extends PackageManagerKernelTestBase { $path_locator = $this->prophesize(PathLocator::class); $path_locator->getActiveDirectory()->willReturn($root->url()); + $path_locator->getProjectRoot()->willReturn($root->url()); $path_locator->getWebRoot()->willReturn(''); $path_locator->getVendorDirectory()->willReturn($vendor->url()); $this->container->set('package_manager.path_locator', $path_locator->reveal()); diff --git a/tests/src/Build/UpdateTestBase.php b/tests/src/Build/UpdateTestBase.php index e33f5ed6a3..367e0f8241 100644 --- a/tests/src/Build/UpdateTestBase.php +++ b/tests/src/Build/UpdateTestBase.php @@ -220,10 +220,7 @@ END; // Packagist. $repositories['packagist.org'] = FALSE; - $repositories['drupal/automatic_updates'] = [ - 'type' => 'path', - 'url' => __DIR__ . '/../../..', - ]; + $repositories['drupal/automatic_updates'] = $this->createPathRepository(__DIR__ . '/../../..'); // Use whatever the current branch of automatic_updates is. $data['require']['drupal/automatic_updates'] = '*'; diff --git a/tests/src/Kernel/ReadinessValidation/StagedProjectsValidatorTest.php b/tests/src/Kernel/ReadinessValidation/StagedProjectsValidatorTest.php index 1b21d13605..6a2dc5aebf 100644 --- a/tests/src/Kernel/ReadinessValidation/StagedProjectsValidatorTest.php +++ b/tests/src/Kernel/ReadinessValidation/StagedProjectsValidatorTest.php @@ -64,6 +64,7 @@ class StagedProjectsValidatorTest extends AutomaticUpdatesKernelTestBase { $locator->getActiveDirectory()->willReturn($active_dir); $locator->getProjectRoot()->willReturn($active_dir); + $locator->getWebRoot()->willReturn(''); $locator->getVendorDirectory()->willReturn($active_dir); $stage_dir_exists = is_dir($stage_dir); diff --git a/tests/src/Kernel/UpdaterTest.php b/tests/src/Kernel/UpdaterTest.php index 034514a3b9..5881d85144 100644 --- a/tests/src/Kernel/UpdaterTest.php +++ b/tests/src/Kernel/UpdaterTest.php @@ -51,6 +51,7 @@ class UpdaterTest extends AutomaticUpdatesKernelTestBase { $locator = $this->prophesize(PathLocator::class); $locator->getActiveDirectory()->willReturn($fixture_dir); $locator->getProjectRoot()->willReturn($fixture_dir); + $locator->getWebRoot()->willReturn(''); $locator->getVendorDirectory()->willReturn($fixture_dir); $this->container->set('package_manager.path_locator', $locator->reveal()); -- GitLab