Initial Drupal 11 with DDEV setup
This commit is contained in:
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer;
|
||||
|
||||
use Symfony\Component\Finder\Finder;
|
||||
|
||||
/**
|
||||
* Some utility functions for testing the Composer integration.
|
||||
*/
|
||||
trait ComposerIntegrationTrait {
|
||||
|
||||
/**
|
||||
* Get a Finder object to traverse all of the composer.json files in core.
|
||||
*
|
||||
* @param string $drupal_root
|
||||
* Absolute path to the root of the Drupal installation.
|
||||
*
|
||||
* @return \Symfony\Component\Finder\Finder
|
||||
* A Finder object able to iterate all the composer.json files in core.
|
||||
*/
|
||||
public static function getComposerJsonFinder($drupal_root) {
|
||||
$composer_json_finder = new Finder();
|
||||
$composer_json_finder->name('composer.json')
|
||||
->in([
|
||||
// Only find composer.json files within composer/ and core/ directories
|
||||
// so we don't inadvertently test contrib in local dev environments.
|
||||
$drupal_root . '/composer',
|
||||
$drupal_root . '/core',
|
||||
])
|
||||
->ignoreUnreadableDirs()
|
||||
->notPath('#^vendor#')
|
||||
->notPath('#/fixture#');
|
||||
return $composer_json_finder;
|
||||
}
|
||||
|
||||
}
|
||||
43
web/core/tests/Drupal/Tests/Composer/ComposerTest.php
Normal file
43
web/core/tests/Drupal/Tests/Composer/ComposerTest.php
Normal file
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer;
|
||||
|
||||
use Drupal\Composer\Composer;
|
||||
use Drupal\Tests\UnitTestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\Composer\Composer
|
||||
* @group Composer
|
||||
*/
|
||||
class ComposerTest extends UnitTestCase {
|
||||
|
||||
/**
|
||||
* Verify that Composer::ensureComposerVersion() doesn't break.
|
||||
*
|
||||
* @covers ::ensureComposerVersion
|
||||
*/
|
||||
public function testEnsureComposerVersion(): void {
|
||||
try {
|
||||
$this->assertNull(Composer::ensureComposerVersion());
|
||||
}
|
||||
catch (\RuntimeException $e) {
|
||||
$this->assertMatchesRegularExpression('/Drupal core development requires Composer 2.3.5, but Composer /', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the configured php version matches the minimum php version.
|
||||
*
|
||||
* Also ensure that the minimum php version in the root-level composer.json
|
||||
* file exactly matches \Drupal::MINIMUM_PHP.
|
||||
*/
|
||||
public function testEnsurePhpConfiguredVersion(): void {
|
||||
$composer_json = json_decode(file_get_contents($this->root . '/composer.json'), TRUE);
|
||||
$composer_core_json = json_decode(file_get_contents($this->root . '/core/composer.json'), TRUE);
|
||||
$this->assertEquals(\Drupal::MINIMUM_PHP, $composer_json['config']['platform']['php'], 'The \Drupal::MINIMUM_PHP constant should always be exactly the same as the config.platform.php in the root composer.json.');
|
||||
$this->assertEquals($composer_core_json['require']['php'], '>=' . $composer_json['config']['platform']['php'], 'The config.platform.php configured version in the root composer.json file should always be exactly the same as the minimum php version configured in core/composer.json.');
|
||||
}
|
||||
|
||||
}
|
||||
101
web/core/tests/Drupal/Tests/Composer/Generator/BuilderTest.php
Normal file
101
web/core/tests/Drupal/Tests/Composer/Generator/BuilderTest.php
Normal file
@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer\Generator;
|
||||
|
||||
use Drupal\Composer\Generator\Builder\DrupalCoreRecommendedBuilder;
|
||||
use Drupal\Composer\Generator\Builder\DrupalDevDependenciesBuilder;
|
||||
use Drupal\Composer\Generator\Builder\DrupalPinnedDevDependenciesBuilder;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Drupal\Composer\Composer;
|
||||
|
||||
/**
|
||||
* Test DrupalCoreRecommendedBuilder.
|
||||
*
|
||||
* @group Metapackage
|
||||
*/
|
||||
class BuilderTest extends TestCase {
|
||||
|
||||
/**
|
||||
* Provides test data for testBuilder.
|
||||
*/
|
||||
public static function builderTestData() {
|
||||
return [
|
||||
[
|
||||
DrupalCoreRecommendedBuilder::class,
|
||||
[
|
||||
'name' => 'drupal/core-recommended',
|
||||
'type' => 'metapackage',
|
||||
'description' => 'Core and its dependencies with known-compatible minor versions. Require this project INSTEAD OF drupal/core.',
|
||||
'license' => 'GPL-2.0-or-later',
|
||||
'require' =>
|
||||
[
|
||||
'drupal/core' => Composer::drupalVersionBranch(),
|
||||
'symfony/polyfill-ctype' => '~v1.12.0',
|
||||
'symfony/yaml' => '~v3.4.32',
|
||||
],
|
||||
'conflict' =>
|
||||
[
|
||||
'webflo/drupal-core-strict' => '*',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
[
|
||||
DrupalDevDependenciesBuilder::class,
|
||||
[
|
||||
'name' => 'drupal/core-dev',
|
||||
'type' => 'metapackage',
|
||||
'description' => 'require-dev dependencies from drupal/drupal; use in addition to drupal/core-recommended to run tests from drupal/core.',
|
||||
'license' => 'GPL-2.0-or-later',
|
||||
'require' =>
|
||||
[
|
||||
'behat/mink' => '^1.8',
|
||||
],
|
||||
'conflict' =>
|
||||
[
|
||||
'webflo/drupal-core-require-dev' => '*',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
[
|
||||
DrupalPinnedDevDependenciesBuilder::class,
|
||||
[
|
||||
'name' => 'drupal/core-dev-pinned',
|
||||
'type' => 'metapackage',
|
||||
'description' => 'Pinned require-dev dependencies from drupal/drupal; use in addition to drupal/core-recommended to run tests from drupal/core.',
|
||||
'license' => 'GPL-2.0-or-later',
|
||||
'require' =>
|
||||
[
|
||||
'drupal/core' => Composer::drupalVersionBranch(),
|
||||
'behat/mink' => 'v1.8.0',
|
||||
'symfony/css-selector' => 'v4.3.5',
|
||||
],
|
||||
'conflict' =>
|
||||
[
|
||||
'webflo/drupal-core-require-dev' => '*',
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests all of the various kinds of builders.
|
||||
*
|
||||
* @dataProvider builderTestData
|
||||
*/
|
||||
public function testBuilder($builderClass, $expected): void {
|
||||
$fixtures = new Fixtures();
|
||||
$drupalCoreInfo = $fixtures->drupalCoreComposerFixture();
|
||||
|
||||
$builder = new $builderClass($drupalCoreInfo);
|
||||
$generatedJson = $builder->getPackage();
|
||||
|
||||
$this->assertEquals($expected, $generatedJson);
|
||||
}
|
||||
|
||||
}
|
||||
121
web/core/tests/Drupal/Tests/Composer/Generator/Fixtures.php
Normal file
121
web/core/tests/Drupal/Tests/Composer/Generator/Fixtures.php
Normal file
@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer\Generator;
|
||||
|
||||
use Drupal\Composer\Generator\Util\DrupalCoreComposer;
|
||||
|
||||
/**
|
||||
* Convenience class for creating fixtures.
|
||||
*/
|
||||
class Fixtures {
|
||||
|
||||
/**
|
||||
* Generate a suitable DrupalCoreComposer fixture for testing.
|
||||
*
|
||||
* @return \Drupal\Composer\Generator\Util\DrupalCoreComposer
|
||||
* DrupalCoreComposer fixture.
|
||||
*/
|
||||
public function drupalCoreComposerFixture() {
|
||||
return new DrupalCoreComposer($this->composerJson(), $this->composerLock());
|
||||
}
|
||||
|
||||
/**
|
||||
* Data for a composer.json fixture.
|
||||
*
|
||||
* @return array
|
||||
* composer.json fixture data.
|
||||
*/
|
||||
protected function composerJson(): array {
|
||||
return [
|
||||
'name' => 'drupal/project-fixture',
|
||||
'description' => 'A fixture for testing the metapackage generator.',
|
||||
'type' => 'project',
|
||||
'license' => 'GPL-2.0-or-later',
|
||||
'require' =>
|
||||
[
|
||||
'composer/installers' => '^1.9',
|
||||
'php' => '>=7.0.8',
|
||||
'symfony/yaml' => '~3.4.5',
|
||||
],
|
||||
'require-dev' =>
|
||||
[
|
||||
'behat/mink' => '^1.8',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Data for a composer.lock fixture.
|
||||
*
|
||||
* @return array
|
||||
* composer.lock fixture data.
|
||||
*/
|
||||
protected function composerLock(): array {
|
||||
return [
|
||||
'_readme' =>
|
||||
[
|
||||
'This is a composer.lock fixture. It contains only a subset of a',
|
||||
'typical composer.lock file (just what is needed for testing).',
|
||||
],
|
||||
'content-hash' => 'da9910627bab73a256b39ceda83d7167',
|
||||
'packages' =>
|
||||
[
|
||||
[
|
||||
'name' => "composer/installers",
|
||||
'version' => 'v1.9.0',
|
||||
'source' => [
|
||||
'type' => 'git',
|
||||
'url' => 'https://github.com/composer/installers.git',
|
||||
'reference' => 'b93bcf0fa1fccb0b7d176b0967d969691cd74cca',
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'symfony/polyfill-ctype',
|
||||
'version' => 'v1.12.0',
|
||||
'source' =>
|
||||
[
|
||||
'type' => 'git',
|
||||
'url' => 'https://github.com/symfony/polyfill-ctype.git',
|
||||
'reference' => '550ebaac289296ce228a706d0867afc34687e3f4',
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'symfony/yaml',
|
||||
'version' => 'v3.4.32',
|
||||
'source' =>
|
||||
[
|
||||
'type' => 'git',
|
||||
'url' => 'https://github.com/symfony/yaml.git',
|
||||
'reference' => '768f817446da74a776a31eea335540f9dcb53942',
|
||||
],
|
||||
],
|
||||
],
|
||||
'packages-dev' =>
|
||||
[
|
||||
[
|
||||
'name' => 'behat/mink',
|
||||
'version' => 'v1.8.0',
|
||||
'source' =>
|
||||
[
|
||||
'type' => 'git',
|
||||
'url' => 'https://github.com/minkphp/Mink.git',
|
||||
'reference' => 'e1772aabb6b654464264a6cc72158c8b3409d8bc',
|
||||
],
|
||||
],
|
||||
[
|
||||
'name' => 'symfony/css-selector',
|
||||
'version' => 'v4.3.5',
|
||||
'source' =>
|
||||
[
|
||||
'type' => 'git',
|
||||
'url' => 'https://github.com/symfony/css-selector.git',
|
||||
'reference' => 'f4b3ff6a549d9ed28b2b0ecd1781bf67cf220ee9',
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer\Generator;
|
||||
|
||||
use Drupal\Composer\Generator\Builder\DrupalCoreRecommendedBuilder;
|
||||
use Drupal\Composer\Generator\Builder\DrupalDevDependenciesBuilder;
|
||||
use Drupal\Composer\Generator\Builder\DrupalPinnedDevDependenciesBuilder;
|
||||
use Drupal\Composer\Generator\PackageGenerator;
|
||||
use Drupal\Composer\Generator\Util\DrupalCoreComposer;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Test to see if the metapackages are up-to-date with the root composer.lock.
|
||||
*
|
||||
* @group Metapackage
|
||||
*/
|
||||
class MetapackageUpdateTest extends TestCase {
|
||||
|
||||
/**
|
||||
* Provides test data for testUpdated.
|
||||
*/
|
||||
public static function updatedTestData() {
|
||||
return [
|
||||
[
|
||||
DrupalCoreRecommendedBuilder::class,
|
||||
'composer/Metapackage/CoreRecommended',
|
||||
],
|
||||
[
|
||||
DrupalDevDependenciesBuilder::class,
|
||||
'composer/Metapackage/DevDependencies',
|
||||
],
|
||||
[
|
||||
DrupalPinnedDevDependenciesBuilder::class,
|
||||
'composer/Metapackage/PinnedDevDependencies',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to see if the generated metapackages are in sync with composer.lock.
|
||||
*
|
||||
* Note that this is not a test of code correctness, but rather it merely
|
||||
* confirms if the package builder was used on the most recent set of
|
||||
* metapackages.
|
||||
*
|
||||
* See BuilderTest.php for a test that checks for code correctness.
|
||||
*
|
||||
* @param string $builderClass
|
||||
* The metapackage builder to test.
|
||||
* @param string $path
|
||||
* The relative path to the metapackage.
|
||||
*
|
||||
* @dataProvider updatedTestData
|
||||
*/
|
||||
public function testUpdated($builderClass, $path): void {
|
||||
// Create a DrupalCoreComposer for the System Under Test (current repo)
|
||||
$repositoryRoot = dirname(__DIR__, 6);
|
||||
$drupalCoreInfo = DrupalCoreComposer::createFromPath($repositoryRoot);
|
||||
|
||||
// Rebuild the metapackage for the composer.json / composer.lock of
|
||||
// the current repo.
|
||||
$builder = new $builderClass($drupalCoreInfo);
|
||||
$generatedJson = $builder->getPackage();
|
||||
$generatedJson = PackageGenerator::encode($generatedJson);
|
||||
|
||||
// Also load the most-recently-generated version of the metapackage.
|
||||
$loadedJson = file_get_contents("$repositoryRoot/$path/composer.json");
|
||||
|
||||
// The generated json is the "expected", what we think the loaded
|
||||
// json would contain, if the current patch is generated correctly
|
||||
// (metapackages updated when composer.lock is updated).
|
||||
$version = str_replace('.0-dev', '.x-dev', \Drupal::VERSION);
|
||||
$message = <<< __EOT__
|
||||
The rebuilt version of $path does not match what is in the source tree.
|
||||
|
||||
To fix, run:
|
||||
|
||||
COMPOSER_ROOT_VERSION=$version composer update --lock
|
||||
|
||||
__EOT__;
|
||||
$this->assertEquals($generatedJson, $loadedJson, $message);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer\Generator;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Tests DrupalCoreRecommendedBuilder.
|
||||
*
|
||||
* @group Metapackage
|
||||
*/
|
||||
class OverlapWithTopLevelDependenciesTest extends TestCase {
|
||||
|
||||
/**
|
||||
* Provides data for testOverlapWithTemplateProject().
|
||||
*/
|
||||
public static function templateProjectPathProvider() {
|
||||
return [
|
||||
[
|
||||
'composer/Template/RecommendedProject',
|
||||
],
|
||||
[
|
||||
'composer/Template/LegacyProject',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests top level and core-recommended dependencies do not overlap.
|
||||
*
|
||||
* @param string $template_project_path
|
||||
* The path of the project template to test.
|
||||
*
|
||||
* @dataProvider templateProjectPathProvider
|
||||
*/
|
||||
public function testOverlapWithTemplateProject($template_project_path): void {
|
||||
$root = dirname(__DIR__, 6);
|
||||
// Read template project composer.json.
|
||||
$top_level_composer_json = json_decode(file_get_contents("$root/$template_project_path/composer.json"), TRUE);
|
||||
|
||||
// Read drupal/core-recommended composer.json.
|
||||
$core_recommended_composer_json = json_decode(file_get_contents("$root/composer/Metapackage/CoreRecommended/composer.json"), TRUE);
|
||||
|
||||
// Fail if any required project in the require section of the template
|
||||
// project also exists in core/recommended.
|
||||
foreach ($top_level_composer_json['require'] as $project => $version_constraint) {
|
||||
$this->assertArrayNotHasKey($project, $core_recommended_composer_json['require'], "Pinned project $project is also a top-level dependency of $template_project_path. This can expose a Composer bug. See https://www.drupal.org/project/drupal/issues/3134648 and https://github.com/composer/composer/issues/8882");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
40
web/core/tests/Drupal/Tests/Composer/Plugin/ExecTrait.php
Normal file
40
web/core/tests/Drupal/Tests/Composer/Plugin/ExecTrait.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer\Plugin;
|
||||
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
/**
|
||||
* Convenience class for creating fixtures.
|
||||
*/
|
||||
trait ExecTrait {
|
||||
|
||||
/**
|
||||
* Runs an arbitrary command.
|
||||
*
|
||||
* @param string $cmd
|
||||
* The command to execute (escaped as required)
|
||||
* @param string $cwd
|
||||
* The current working directory to run the command from.
|
||||
* @param array $env
|
||||
* Environment variables to define for the subprocess.
|
||||
* @param string $error_output
|
||||
* (optional) Passed by reference to allow error output to be tested.
|
||||
*
|
||||
* @return string
|
||||
* Standard output from the command
|
||||
*/
|
||||
protected function mustExec($cmd, $cwd, array $env = [], string &$error_output = ''): string {
|
||||
$process = Process::fromShellCommandline($cmd, $cwd, $env + ['PATH' => getenv('PATH'), 'HOME' => getenv('HOME')]);
|
||||
$process->setTimeout(300)->setIdleTimeout(300)->run();
|
||||
$exitCode = $process->getExitCode();
|
||||
if (0 != $exitCode) {
|
||||
throw new \RuntimeException("Exit code: {$exitCode}\n\n" . $process->getErrorOutput() . "\n\n" . $process->getOutput());
|
||||
}
|
||||
$error_output = $process->getErrorOutput();
|
||||
return $process->getOutput();
|
||||
}
|
||||
|
||||
}
|
||||
272
web/core/tests/Drupal/Tests/Composer/Plugin/FixturesBase.php
Normal file
272
web/core/tests/Drupal/Tests/Composer/Plugin/FixturesBase.php
Normal file
@ -0,0 +1,272 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer\Plugin;
|
||||
|
||||
use Composer\Composer;
|
||||
use Composer\Console\Application;
|
||||
use Composer\Factory;
|
||||
use Composer\IO\BufferIO;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Util\Filesystem;
|
||||
use Drupal\Composer\Plugin\Scaffold\Interpolator;
|
||||
use Symfony\Component\Console\Input\StringInput;
|
||||
use Symfony\Component\Console\Output\BufferedOutput;
|
||||
|
||||
/**
|
||||
* Base class for fixtures to test composer plugins.
|
||||
*/
|
||||
abstract class FixturesBase {
|
||||
|
||||
/**
|
||||
* Keep a persistent prefix to help group our tmp directories together.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected static string $randomPrefix = '';
|
||||
|
||||
/**
|
||||
* Directories to delete when we are done.
|
||||
*
|
||||
* @var string[]
|
||||
*/
|
||||
protected array $tmpDirs = [];
|
||||
|
||||
/**
|
||||
* A Composer IOInterface to write to.
|
||||
*
|
||||
* @var \Composer\IO\IOInterface|null
|
||||
*/
|
||||
protected ?IOInterface $io;
|
||||
|
||||
/**
|
||||
* The composer object.
|
||||
*
|
||||
* @var \Composer\Composer
|
||||
*/
|
||||
protected Composer $composer;
|
||||
|
||||
/**
|
||||
* Gets an IO fixture.
|
||||
*
|
||||
* @return \Composer\IO\IOInterface
|
||||
* A Composer IOInterface to write to; output may be retrieved via
|
||||
* Fixtures::getOutput().
|
||||
*/
|
||||
public function io(): IOInterface {
|
||||
if (!isset($this->io)) {
|
||||
$this->io = new BufferIO();
|
||||
}
|
||||
return $this->io;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the Composer object.
|
||||
*
|
||||
* @return \Composer\Composer
|
||||
* The main Composer object, needed by the scaffold Handler, etc.
|
||||
*/
|
||||
public function getComposer(): Composer {
|
||||
if (!isset($this->composer)) {
|
||||
$this->composer = Factory::create($this->io(), NULL, TRUE);
|
||||
}
|
||||
return $this->composer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the output from the io() fixture.
|
||||
*
|
||||
* @return string
|
||||
* Output captured from tests that write to Fixtures::io().
|
||||
*/
|
||||
public function getOutput(): string {
|
||||
return $this->io()->getOutput();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the path to Scaffold component.
|
||||
*
|
||||
* Used to inject the component into composer.json files.
|
||||
*
|
||||
* @return string
|
||||
* Path to the root of this project.
|
||||
*/
|
||||
abstract public function projectRoot(): string;
|
||||
|
||||
/**
|
||||
* Gets the path to the project fixtures.
|
||||
*
|
||||
* @return string
|
||||
* Path to project fixtures
|
||||
*/
|
||||
abstract public function allFixturesDir(): string;
|
||||
|
||||
/**
|
||||
* Gets the path to one particular project fixture.
|
||||
*
|
||||
* @param string $project_name
|
||||
* The project name to get the path for.
|
||||
*
|
||||
* @return string
|
||||
* Path to project fixture.
|
||||
*/
|
||||
public function projectFixtureDir(string $project_name): string {
|
||||
$dir = $this->allFixturesDir() . '/' . $project_name;
|
||||
if (!is_dir($dir)) {
|
||||
throw new \RuntimeException("Requested fixture project {$project_name} that does not exist.");
|
||||
}
|
||||
return $dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the path to one particular bin path.
|
||||
*
|
||||
* @param string $bin_name
|
||||
* The bin name to get the path for.
|
||||
*
|
||||
* @return string
|
||||
* Path to project fixture.
|
||||
*/
|
||||
public function binFixtureDir(string $bin_name): string {
|
||||
$dir = $this->allFixturesDir() . '/scripts/' . $bin_name;
|
||||
if (!is_dir($dir)) {
|
||||
throw new \RuntimeException("Requested fixture bin dir {$bin_name} that does not exist.");
|
||||
}
|
||||
return $dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a path to a temporary location, but do not create the directory.
|
||||
*
|
||||
* @param string $prefix
|
||||
* A prefix for the temporary directory name.
|
||||
*
|
||||
* @return string
|
||||
* Path to temporary directory
|
||||
*/
|
||||
public function tmpDir(string $prefix): string {
|
||||
$prefix .= static::persistentPrefix();
|
||||
$tmpDir = sys_get_temp_dir() . '/scaffold-' . $prefix . uniqid(md5($prefix . microtime()), TRUE);
|
||||
$this->tmpDirs[] = $tmpDir;
|
||||
return $tmpDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a persistent prefix to use with all of our temporary directories.
|
||||
*
|
||||
* The presumption is that this should reduce collisions in highly-parallel
|
||||
* tests. We prepend the process id to play nicely with phpunit process
|
||||
* isolation.
|
||||
*
|
||||
* @return string
|
||||
* A random string that will remain the same for the entire process run.
|
||||
*/
|
||||
protected static function persistentPrefix(): string {
|
||||
if (empty(static::$randomPrefix)) {
|
||||
static::$randomPrefix = getmypid() . md5(microtime());
|
||||
}
|
||||
return static::$randomPrefix;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a temporary directory.
|
||||
*
|
||||
* @param string $prefix
|
||||
* A prefix for the temporary directory name.
|
||||
*
|
||||
* @return string
|
||||
* Path to temporary directory
|
||||
*/
|
||||
public function mkTmpDir(string $prefix): string {
|
||||
$tmpDir = $this->tmpDir($prefix);
|
||||
$filesystem = new Filesystem();
|
||||
$filesystem->ensureDirectoryExists($tmpDir);
|
||||
return $tmpDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an isolated cache directory for Composer.
|
||||
*/
|
||||
public function createIsolatedComposerCacheDir(): void {
|
||||
$cacheDir = $this->mkTmpDir('composer-cache');
|
||||
putenv("COMPOSER_CACHE_DIR=$cacheDir");
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls 'tearDown' in any test that copies fixtures to transient locations.
|
||||
*/
|
||||
public function tearDown(): void {
|
||||
// Remove any temporary directories that were created.
|
||||
$filesystem = new Filesystem();
|
||||
foreach ($this->tmpDirs as $dir) {
|
||||
$filesystem->remove($dir);
|
||||
}
|
||||
// Clear out variables from the previous pass.
|
||||
$this->tmpDirs = [];
|
||||
$this->io = NULL;
|
||||
// Clear the composer cache dir, if it was set
|
||||
putenv('COMPOSER_CACHE_DIR=');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a temporary copy of all of the fixtures projects into a temp dir.
|
||||
*
|
||||
* The fixtures remain dirty if they already exist. Individual tests should
|
||||
* first delete any fixture directory that needs to remain pristine. Since all
|
||||
* temporary directories are removed in tearDown, this is only an issue when
|
||||
* a) the FIXTURE_DIR environment variable has been set, or b) tests are
|
||||
* calling cloneFixtureProjects more than once per test method.
|
||||
*
|
||||
* @param string $fixturesDir
|
||||
* The directory to place fixtures in.
|
||||
* @param array $replacements
|
||||
* Key : value mappings for placeholders to replace in composer.json
|
||||
* templates.
|
||||
*/
|
||||
public function cloneFixtureProjects(string $fixturesDir, array $replacements = []): void {
|
||||
$filesystem = new Filesystem();
|
||||
// We will replace 'SYMLINK' with the string 'true' in our composer.json
|
||||
// fixture.
|
||||
$replacements += ['SYMLINK' => 'true'];
|
||||
$interpolator = new Interpolator('__', '__');
|
||||
$interpolator->setData($replacements);
|
||||
$filesystem->copy($this->allFixturesDir(), $fixturesDir);
|
||||
$composer_json_templates = glob($fixturesDir . "/*/composer.json.tmpl");
|
||||
foreach ($composer_json_templates as $composer_json_tmpl) {
|
||||
// Inject replacements into composer.json.
|
||||
if (file_exists($composer_json_tmpl)) {
|
||||
$composer_json_contents = file_get_contents($composer_json_tmpl);
|
||||
$composer_json_contents = $interpolator->interpolate($composer_json_contents, [], FALSE);
|
||||
file_put_contents(dirname($composer_json_tmpl) . "/composer.json", $composer_json_contents);
|
||||
@unlink($composer_json_tmpl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a `composer` command.
|
||||
*
|
||||
* @param string $cmd
|
||||
* The Composer command to execute (escaped as required)
|
||||
* @param string $cwd
|
||||
* The current working directory to run the command from.
|
||||
*
|
||||
* @return string
|
||||
* Standard output and standard error from the command.
|
||||
*/
|
||||
public function runComposer(string $cmd, string $cwd): string {
|
||||
chdir($cwd);
|
||||
$input = new StringInput($cmd);
|
||||
$output = new BufferedOutput();
|
||||
$application = new Application();
|
||||
$application->setAutoExit(FALSE);
|
||||
$exitCode = $application->run($input, $output);
|
||||
$output = $output->fetch();
|
||||
if ($exitCode != 0) {
|
||||
throw new \Exception("Fixtures::runComposer failed to set up fixtures.\n\nCommand: '{$cmd}'\nExit code: {$exitCode}\nOutput: \n\n$output");
|
||||
}
|
||||
return $output;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer\Plugin\ProjectMessage;
|
||||
|
||||
use Composer\Package\RootPackageInterface;
|
||||
use Drupal\Composer\Plugin\ProjectMessage\Message;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use org\bovigo\vfs\vfsStream;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass Drupal\Composer\Plugin\ProjectMessage\Message
|
||||
* @group ProjectMessage
|
||||
*/
|
||||
class ConfigTest extends TestCase {
|
||||
|
||||
public static function setUpBeforeClass(): void {
|
||||
parent::setUpBeforeClass();
|
||||
vfsStream::setup('config_test', NULL, [
|
||||
'bespoke' => [
|
||||
'special_file.txt' => "Special\nFile",
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public static function provideGetMessageText() {
|
||||
return [
|
||||
[[], []],
|
||||
[
|
||||
['Special', 'File'],
|
||||
[
|
||||
'drupal-core-project-message' => [
|
||||
'event-name-file' => vfsStream::url('config_test/bespoke/special_file.txt'),
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
['I am the message.'],
|
||||
[
|
||||
'drupal-core-project-message' => [
|
||||
'event-name-message' => ['I am the message.'],
|
||||
],
|
||||
],
|
||||
],
|
||||
[
|
||||
['This message overrides file.'],
|
||||
[
|
||||
'drupal-core-project-message' => [
|
||||
'event-name-message' => ['This message overrides file.'],
|
||||
'event-name-file' => vfsStream::url('config_test/bespoke/special_file.txt'),
|
||||
],
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider provideGetMessageText
|
||||
* @covers ::getText
|
||||
*/
|
||||
public function testGetMessageText($expected, $config): void {
|
||||
// Root package has our config.
|
||||
$root = $this->createMock(RootPackageInterface::class);
|
||||
$root->expects($this->once())
|
||||
->method('getExtra')
|
||||
->willReturn($config);
|
||||
|
||||
$message = new Message($root, 'event-name');
|
||||
|
||||
$this->assertSame($expected, $message->getText());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getText
|
||||
*/
|
||||
public function testDefaultFile(): void {
|
||||
// Root package has no extra field.
|
||||
$root = $this->createMock(RootPackageInterface::class);
|
||||
$root->expects($this->once())
|
||||
->method('getExtra')
|
||||
->willReturn([]);
|
||||
|
||||
// The default is to try to read from event-name-message.txt, so we expect
|
||||
// config to try that.
|
||||
$message = $this->getMockBuilder(Message::class)
|
||||
->setConstructorArgs([$root, 'event-name'])
|
||||
->onlyMethods(['getMessageFromFile'])
|
||||
->getMock();
|
||||
$message->expects($this->once())
|
||||
->method('getMessageFromFile')
|
||||
->with('event-name-message.txt')
|
||||
->willReturn([]);
|
||||
|
||||
$this->assertSame([], $message->getText());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer\Plugin\Scaffold;
|
||||
|
||||
/**
|
||||
* Convenience class for creating fixtures.
|
||||
*/
|
||||
trait AssertUtilsTrait {
|
||||
|
||||
/**
|
||||
* Asserts that a given file exists and is/is not a symlink.
|
||||
*
|
||||
* @param string $path
|
||||
* The path to check exists.
|
||||
* @param bool $is_link
|
||||
* Checks if the file should be a symlink or not.
|
||||
* @param string $contents_contains
|
||||
* Regex to check the file contents.
|
||||
*/
|
||||
protected function assertScaffoldedFile($path, $is_link, $contents_contains) {
|
||||
$this->assertFileExists($path);
|
||||
$contents = file_get_contents($path);
|
||||
$this->assertStringContainsString($contents_contains, basename($path) . ': ' . $contents);
|
||||
$this->assertSame($is_link, is_link($path));
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a file does not exist or exists and does not contain a value.
|
||||
*
|
||||
* @param string $path
|
||||
* The path to check exists.
|
||||
* @param string $contents_not_contains
|
||||
* A string that is expected should NOT occur in the file contents.
|
||||
*/
|
||||
protected function assertScaffoldedFileDoesNotContain($path, $contents_not_contains) {
|
||||
// If the file does not exist at all, we'll count that as a pass.
|
||||
if (!file_exists($path)) {
|
||||
return;
|
||||
}
|
||||
$contents = file_get_contents($path);
|
||||
$this->assertStringNotContainsString($contents_not_contains, $contents, basename($path) . ' contains unexpected contents:');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,155 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer\Plugin\Scaffold;
|
||||
|
||||
use Drupal\Tests\Composer\Plugin\FixturesBase;
|
||||
use Drupal\Composer\Plugin\Scaffold\Handler;
|
||||
use Drupal\Composer\Plugin\Scaffold\Interpolator;
|
||||
use Drupal\Composer\Plugin\Scaffold\Operations\AppendOp;
|
||||
use Drupal\Composer\Plugin\Scaffold\Operations\ReplaceOp;
|
||||
use Drupal\Composer\Plugin\Scaffold\ScaffoldFilePath;
|
||||
|
||||
/**
|
||||
* Convenience class for creating fixtures.
|
||||
*/
|
||||
class Fixtures extends FixturesBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function projectRoot(): string {
|
||||
return realpath(__DIR__) . '/../../../../../../../composer/Plugin/Scaffold';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function allFixturesDir(): string {
|
||||
return realpath(__DIR__ . '/fixtures');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a path to a source scaffold fixture.
|
||||
*
|
||||
* Use in place of ScaffoldFilePath::sourcePath().
|
||||
*
|
||||
* @param string $project_name
|
||||
* The name of the project to fetch; $package_name is
|
||||
* "fixtures/$project_name".
|
||||
* @param string $source
|
||||
* The name of the asset; path is "assets/$source".
|
||||
*
|
||||
* @return \Drupal\Composer\Plugin\Scaffold\ScaffoldFilePath
|
||||
* The full and relative path to the desired asset
|
||||
*
|
||||
* @see \Drupal\Composer\Plugin\Scaffold\ScaffoldFilePath::sourcePath()
|
||||
*/
|
||||
public function sourcePath($project_name, $source) {
|
||||
$package_name = "fixtures/{$project_name}";
|
||||
$source_rel_path = "assets/{$source}";
|
||||
$package_path = $this->projectFixtureDir($project_name);
|
||||
return ScaffoldFilePath::sourcePath($package_name, $package_path, 'unknown', $source_rel_path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an Interpolator with 'web-root' and 'package-name' set.
|
||||
*
|
||||
* Use in place of ManageOptions::getLocationReplacements().
|
||||
*
|
||||
* @return \Drupal\Composer\Plugin\Scaffold\Interpolator
|
||||
* An interpolator with location replacements, including 'web-root'.
|
||||
*
|
||||
* @see \Drupal\Composer\Plugin\Scaffold\ManageOptions::getLocationReplacements()
|
||||
*/
|
||||
public function getLocationReplacements() {
|
||||
$destinationTmpDir = $this->mkTmpDir('location-replacements');
|
||||
$interpolator = new Interpolator();
|
||||
$interpolator->setData(['web-root' => $destinationTmpDir, 'package-name' => 'fixtures/tmp-destination']);
|
||||
return $interpolator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a ReplaceOp fixture.
|
||||
*
|
||||
* @param string $project_name
|
||||
* The name of the project to fetch; $package_name is
|
||||
* "fixtures/$project_name".
|
||||
* @param string $source
|
||||
* The name of the asset; path is "assets/$source".
|
||||
*
|
||||
* @return \Drupal\Composer\Plugin\Scaffold\Operations\ReplaceOp
|
||||
* A replace operation object.
|
||||
*/
|
||||
public function replaceOp($project_name, $source) {
|
||||
$source_path = $this->sourcePath($project_name, $source);
|
||||
return new ReplaceOp($source_path, TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an AppendOp fixture.
|
||||
*
|
||||
* @param string $project_name
|
||||
* The name of the project to fetch; $package_name is
|
||||
* "fixtures/$project_name".
|
||||
* @param string $source
|
||||
* The name of the asset; path is "assets/$source".
|
||||
*
|
||||
* @return \Drupal\Composer\Plugin\Scaffold\Operations\AppendOp
|
||||
* An append operation object.
|
||||
*/
|
||||
public function appendOp($project_name, $source) {
|
||||
$source_path = $this->sourcePath($project_name, $source);
|
||||
return new AppendOp(NULL, $source_path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a destination path in a tmp dir.
|
||||
*
|
||||
* Use in place of ScaffoldFilePath::destinationPath().
|
||||
*
|
||||
* @param string $destination
|
||||
* Destination path; should be in the form '[web-root]/robots.txt', where
|
||||
* '[web-root]' is always literally '[web-root]', with any arbitrarily
|
||||
* desired filename following.
|
||||
* @param \Drupal\Composer\Plugin\Scaffold\Interpolator $interpolator
|
||||
* Location replacements. Obtain via Fixtures::getLocationReplacements()
|
||||
* when creating multiple scaffold destinations.
|
||||
* @param string $package_name
|
||||
* (optional) The name of the fixture package that this path came from.
|
||||
* Taken from interpolator if not provided.
|
||||
*
|
||||
* @return \Drupal\Composer\Plugin\Scaffold\ScaffoldFilePath
|
||||
* A destination scaffold file backed by temporary storage.
|
||||
*
|
||||
* @see \Drupal\Composer\Plugin\Scaffold\ScaffoldFilePath::destinationPath()
|
||||
*/
|
||||
public function destinationPath($destination, ?Interpolator $interpolator = NULL, $package_name = NULL) {
|
||||
$interpolator = $interpolator ?: $this->getLocationReplacements();
|
||||
$package_name = $package_name ?: $interpolator->interpolate('[package-name]');
|
||||
return ScaffoldFilePath::destinationPath($package_name, $destination, $interpolator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the scaffold operation.
|
||||
*
|
||||
* This is equivalent to running `composer composer-scaffold`, but we do the
|
||||
* equivalent operation by instantiating a Handler object in order to continue
|
||||
* running in the same process, so that coverage may be calculated for the
|
||||
* code executed by these tests.
|
||||
*
|
||||
* @param string $cwd
|
||||
* The working directory to run the scaffold command in.
|
||||
*
|
||||
* @return string
|
||||
* Output captured from tests that write to Fixtures::io().
|
||||
*/
|
||||
public function runScaffold($cwd) {
|
||||
chdir($cwd);
|
||||
$handler = new Handler($this->getComposer(), $this->io());
|
||||
$handler->scaffold();
|
||||
return $this->getOutput();
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,163 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer\Plugin\Scaffold\Functional;
|
||||
|
||||
use Composer\Util\Filesystem;
|
||||
use Drupal\BuildTests\Framework\BuildTestBase;
|
||||
use Drupal\Tests\Composer\Plugin\Scaffold\AssertUtilsTrait;
|
||||
use Drupal\Tests\Composer\Plugin\ExecTrait;
|
||||
use Drupal\Tests\Composer\Plugin\Scaffold\Fixtures;
|
||||
|
||||
/**
|
||||
* Tests Composer Hooks that run scaffold operations.
|
||||
*
|
||||
* The purpose of this test file is to exercise all of the different Composer
|
||||
* commands that invoke scaffold operations, and ensure that files are
|
||||
* scaffolded when they should be.
|
||||
*
|
||||
* Note that this test file uses `exec` to run Composer for a pure functional
|
||||
* test. Other functional test files invoke Composer commands directly via the
|
||||
* Composer Application object, in order to get more accurate test coverage
|
||||
* information.
|
||||
*
|
||||
* @group Scaffold
|
||||
* @group #slow
|
||||
*/
|
||||
class ComposerHookTest extends BuildTestBase {
|
||||
|
||||
use ExecTrait;
|
||||
use AssertUtilsTrait;
|
||||
|
||||
/**
|
||||
* Directory to perform the tests in.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fixturesDir;
|
||||
|
||||
/**
|
||||
* The Symfony FileSystem component.
|
||||
*
|
||||
* @var \Symfony\Component\Filesystem\Filesystem
|
||||
*/
|
||||
protected $fileSystem;
|
||||
|
||||
/**
|
||||
* The Fixtures object.
|
||||
*
|
||||
* @var \Drupal\Tests\Composer\Plugin\Scaffold\Fixtures
|
||||
*/
|
||||
protected $fixtures;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
|
||||
$this->fileSystem = new Filesystem();
|
||||
$this->fixtures = new Fixtures();
|
||||
$this->fixtures->createIsolatedComposerCacheDir();
|
||||
$this->fixturesDir = $this->fixtures->tmpDir($this->name());
|
||||
$replacements = ['SYMLINK' => 'false', 'PROJECT_ROOT' => $this->fixtures->projectRoot()];
|
||||
$this->fixtures->cloneFixtureProjects($this->fixturesDir, $replacements);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function tearDown(): void {
|
||||
// Remove any temporary directories et. al. that were created.
|
||||
$this->fixtures->tearDown();
|
||||
|
||||
parent::tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to see if scaffold operation runs at the correct times.
|
||||
*/
|
||||
public function testComposerHooks(): void {
|
||||
$topLevelProjectDir = 'composer-hooks-fixture';
|
||||
$sut = $this->fixturesDir . '/' . $topLevelProjectDir;
|
||||
// First test: run composer install. This is the same as composer update
|
||||
// since there is no lock file. Ensure that scaffold operation ran.
|
||||
$this->mustExec("composer install --no-ansi", $sut);
|
||||
$this->assertScaffoldedFile($sut . '/sites/default/default.settings.php', FALSE, 'Test version of default.settings.php from drupal/core');
|
||||
// Run composer required to add in the scaffold-override-fixture. This
|
||||
// project is "allowed" in our main fixture project, but not required.
|
||||
// We expect that requiring this library should re-scaffold, resulting
|
||||
// in a changed default.settings.php file.
|
||||
$stdout = $this->mustExec("composer require --no-ansi --no-interaction fixtures/drupal-assets-fixture:dev-main fixtures/scaffold-override-fixture:dev-main", $sut);
|
||||
$this->assertScaffoldedFile($sut . '/sites/default/default.settings.php', FALSE, 'scaffolded from the scaffold-override-fixture');
|
||||
// Make sure that the appropriate notice informing us that scaffolding
|
||||
// is allowed was printed.
|
||||
$this->assertStringContainsString('Package fixtures/scaffold-override-fixture has scaffold operations, and is already allowed in the root-level composer.json file.', $stdout);
|
||||
// Delete one scaffold file, just for test purposes, then run
|
||||
// 'composer update' and see if the scaffold file is replaced.
|
||||
@unlink($sut . '/sites/default/default.settings.php');
|
||||
$this->assertFileDoesNotExist($sut . '/sites/default/default.settings.php');
|
||||
$this->mustExec("composer update --no-ansi", $sut);
|
||||
$this->assertScaffoldedFile($sut . '/sites/default/default.settings.php', FALSE, 'scaffolded from the scaffold-override-fixture');
|
||||
// Delete the same test scaffold file again, then run
|
||||
// 'composer drupal:scaffold' and see if the scaffold file is
|
||||
// re-scaffolded.
|
||||
@unlink($sut . '/sites/default/default.settings.php');
|
||||
$this->assertFileDoesNotExist($sut . '/sites/default/default.settings.php');
|
||||
$this->mustExec("composer install --no-ansi", $sut);
|
||||
$this->assertScaffoldedFile($sut . '/sites/default/default.settings.php', FALSE, 'scaffolded from the scaffold-override-fixture');
|
||||
// Delete the same test scaffold file yet again, then run
|
||||
// 'composer install' and see if the scaffold file is re-scaffolded.
|
||||
@unlink($sut . '/sites/default/default.settings.php');
|
||||
$this->assertFileDoesNotExist($sut . '/sites/default/default.settings.php');
|
||||
$this->mustExec("composer drupal:scaffold --no-ansi", $sut);
|
||||
$this->assertScaffoldedFile($sut . '/sites/default/default.settings.php', FALSE, 'scaffolded from the scaffold-override-fixture');
|
||||
// Run 'composer create-project' to create a new test project called
|
||||
// 'create-project-test', which is a copy of 'fixtures/drupal-drupal'.
|
||||
$sut = $this->fixturesDir . '/create-project-test';
|
||||
$filesystem = new Filesystem();
|
||||
$filesystem->remove($sut);
|
||||
$stdout = $this->mustExec("composer create-project --repository=packages.json fixtures/drupal-drupal {$sut}", $this->fixturesDir, ['COMPOSER_MIRROR_PATH_REPOS' => 1]);
|
||||
$this->assertDirectoryExists($sut);
|
||||
$this->assertStringContainsString('Scaffolding files for fixtures/drupal-drupal', $stdout);
|
||||
$this->assertScaffoldedFile($sut . '/index.php', FALSE, 'Test version of index.php from drupal/core');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to see if scaffold messages are omitted when running scaffold twice.
|
||||
*/
|
||||
public function testScaffoldMessagesDoNotPrintTwice(): void {
|
||||
$topLevelProjectDir = 'drupal-drupal';
|
||||
$sut = $this->fixturesDir . '/' . $topLevelProjectDir;
|
||||
// First test: run composer install. This is the same as composer update
|
||||
// since there is no lock file. Ensure that scaffold operation ran.
|
||||
$stdout = $this->mustExec("composer install --no-ansi", $sut);
|
||||
|
||||
$this->assertStringContainsString('- Copy [web-root]/index.php from assets/index.php', $stdout);
|
||||
$this->assertStringContainsString('- Copy [web-root]/update.php from assets/update.php', $stdout);
|
||||
|
||||
// Run scaffold operation again. It should not print anything.
|
||||
$stdout = $this->mustExec("composer scaffold --no-ansi", $sut);
|
||||
|
||||
$this->assertEquals('', $stdout);
|
||||
|
||||
// Delete a file and run it again. It should re-scaffold the removed file.
|
||||
unlink("$sut/index.php");
|
||||
$stdout = $this->mustExec("composer scaffold --no-ansi", $sut);
|
||||
$this->assertStringContainsString('- Copy [web-root]/index.php from assets/index.php', $stdout);
|
||||
$this->assertStringNotContainsString('- Copy [web-root]/update.php from assets/update.php', $stdout);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests to see if scaffold events are dispatched and picked up by the plugin.
|
||||
*/
|
||||
public function testScaffoldEvents(): void {
|
||||
$topLevelProjectDir = 'scaffold-events-fixture';
|
||||
$sut = $this->fixturesDir . '/' . $topLevelProjectDir;
|
||||
$output = $this->mustExec("composer install --no-ansi", $sut);
|
||||
$this->assertStringContainsString('Hello preDrupalScaffoldCmd', $output);
|
||||
$this->assertStringContainsString('Hello postDrupalScaffoldCmd', $output);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,254 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer\Plugin\Scaffold\Functional;
|
||||
|
||||
use Composer\Util\Filesystem;
|
||||
use Drupal\Tests\Composer\Plugin\Scaffold\Fixtures;
|
||||
use Drupal\Tests\Composer\Plugin\Scaffold\AssertUtilsTrait;
|
||||
use Drupal\Tests\Composer\Plugin\ExecTrait;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Tests to see whether .gitignore files are correctly managed.
|
||||
*
|
||||
* The purpose of this test file is to run a scaffold operation and
|
||||
* confirm that the files that were scaffolded are added to the
|
||||
* repository's .gitignore file.
|
||||
*
|
||||
* @group Scaffold
|
||||
*/
|
||||
class ManageGitIgnoreTest extends TestCase {
|
||||
use ExecTrait;
|
||||
use AssertUtilsTrait;
|
||||
|
||||
/**
|
||||
* The root of this project.
|
||||
*
|
||||
* Used to substitute this project's base directory into composer.json files
|
||||
* so Composer can find it.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $projectRoot;
|
||||
|
||||
/**
|
||||
* Directory to perform the tests in.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fixturesDir;
|
||||
|
||||
/**
|
||||
* The Symfony FileSystem component.
|
||||
*
|
||||
* @var \Symfony\Component\Filesystem\Filesystem
|
||||
*/
|
||||
protected $fileSystem;
|
||||
|
||||
/**
|
||||
* The Fixtures object.
|
||||
*
|
||||
* @var \Drupal\Tests\Composer\Plugin\Scaffold\Fixtures
|
||||
*/
|
||||
protected $fixtures;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
$this->fileSystem = new Filesystem();
|
||||
$this->fixtures = new Fixtures();
|
||||
$this->fixtures->createIsolatedComposerCacheDir();
|
||||
$this->projectRoot = $this->fixtures->projectRoot();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function tearDown(): void {
|
||||
// Remove any temporary directories et. al. that were created.
|
||||
$this->fixtures->tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a system-under-test and initialize a git repository for it.
|
||||
*
|
||||
* @param string $fixture_name
|
||||
* The name of the fixture to use from
|
||||
* core/tests/Drupal/Tests/Component/Scaffold/fixtures.
|
||||
*
|
||||
* @return string
|
||||
* The path to the fixture directory.
|
||||
*/
|
||||
protected function createSutWithGit($fixture_name): string {
|
||||
$this->fixturesDir = $this->fixtures->tmpDir($this->name());
|
||||
$sut = $this->fixturesDir . '/' . $fixture_name;
|
||||
$replacements = ['SYMLINK' => 'false', 'PROJECT_ROOT' => $this->projectRoot];
|
||||
$this->fixtures->cloneFixtureProjects($this->fixturesDir, $replacements);
|
||||
// .gitignore files will not be managed unless there is a git repository.
|
||||
$this->mustExec('git init', $sut);
|
||||
// Add some user info so git does not complain.
|
||||
$this->mustExec('git config user.email "test@example.com"', $sut);
|
||||
$this->mustExec('git config user.name "Test User"', $sut);
|
||||
$this->mustExec('git add .', $sut);
|
||||
$this->mustExec('git commit -m "Initial commit."', $sut);
|
||||
// Run composer install, but suppress scaffolding.
|
||||
$this->fixtures->runComposer("install --no-ansi --no-scripts --no-plugins", $sut);
|
||||
return $sut;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests scaffold command correctly manages the .gitignore file.
|
||||
*/
|
||||
public function testManageGitIgnore(): void {
|
||||
// Note that the drupal-composer-drupal-project fixture does not
|
||||
// have any configuration settings related to .gitignore management.
|
||||
$sut = $this->createSutWithGit('drupal-composer-drupal-project');
|
||||
$this->assertFileDoesNotExist($sut . '/docroot/autoload.php');
|
||||
$this->assertFileDoesNotExist($sut . '/docroot/index.php');
|
||||
$this->assertFileDoesNotExist($sut . '/docroot/sites/.gitignore');
|
||||
// Run the scaffold command.
|
||||
$this->fixtures->runScaffold($sut);
|
||||
$this->assertFileExists($sut . '/docroot/autoload.php');
|
||||
$this->assertFileExists($sut . '/docroot/index.php');
|
||||
$expected = <<<EOT
|
||||
/build
|
||||
/.csslintrc
|
||||
/.editorconfig
|
||||
/.eslintignore
|
||||
/.eslintrc.json
|
||||
/.gitattributes
|
||||
/.ht.router.php
|
||||
/autoload.php
|
||||
/index.php
|
||||
/robots.txt
|
||||
/update.php
|
||||
EOT;
|
||||
// At this point we should have a .gitignore file, because although we did
|
||||
// not explicitly ask for .gitignore tracking, the vendor directory is not
|
||||
// tracked, so the default in that instance is to manage .gitignore files.
|
||||
$this->assertScaffoldedFile($sut . '/docroot/.gitignore', FALSE, $expected);
|
||||
$this->assertScaffoldedFile($sut . '/docroot/sites/.gitignore', FALSE, 'example.settings.local.php');
|
||||
$this->assertScaffoldedFile($sut . '/docroot/sites/default/.gitignore', FALSE, 'default.services.yml');
|
||||
$expected = <<<EOT
|
||||
M docroot/.gitignore
|
||||
?? docroot/sites/.gitignore
|
||||
?? docroot/sites/default/.gitignore
|
||||
EOT;
|
||||
// Check to see whether there are any untracked files. We expect that
|
||||
// only the .gitignore files themselves should be untracked.
|
||||
$stdout = $this->mustExec('git status --porcelain', $sut);
|
||||
$this->assertEquals(trim($expected), trim($stdout));
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests scaffold command does not manage the .gitignore file when disabled.
|
||||
*/
|
||||
public function testUnmanagedGitIgnoreWhenDisabled(): void {
|
||||
// Note that the drupal-drupal fixture has a configuration setting
|
||||
// `"gitignore": false,` which disables .gitignore file handling.
|
||||
$sut = $this->createSutWithGit('drupal-drupal');
|
||||
$this->assertFileDoesNotExist($sut . '/docroot/autoload.php');
|
||||
$this->assertFileDoesNotExist($sut . '/docroot/index.php');
|
||||
// Run the scaffold command.
|
||||
$this->fixtures->runScaffold($sut);
|
||||
$this->assertFileExists($sut . '/autoload.php');
|
||||
$this->assertFileExists($sut . '/index.php');
|
||||
$this->assertFileDoesNotExist($sut . '/.gitignore');
|
||||
$this->assertFileDoesNotExist($sut . '/docroot/sites/default/.gitignore');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests appending to an unmanaged file, and confirm it is not .gitignored.
|
||||
*
|
||||
* If we append to an unmanaged (not scaffolded) file, and we are managing
|
||||
* .gitignore files, then we expect that the unmanaged file should not be
|
||||
* added to the .gitignore file, because unmanaged files should be committed.
|
||||
*/
|
||||
public function testAppendToEmptySettingsIsUnmanaged(): void {
|
||||
$sut = $this->createSutWithGit('drupal-drupal-append-settings');
|
||||
$this->assertFileDoesNotExist($sut . '/autoload.php');
|
||||
$this->assertFileDoesNotExist($sut . '/index.php');
|
||||
$this->assertFileDoesNotExist($sut . '/sites/.gitignore');
|
||||
// Run the scaffold command.
|
||||
$this->fixtures->runScaffold($sut);
|
||||
$this->assertFileExists($sut . '/autoload.php');
|
||||
$this->assertFileExists($sut . '/index.php');
|
||||
|
||||
$this->assertScaffoldedFile($sut . '/sites/.gitignore', FALSE, 'example.sites.php');
|
||||
$this->assertScaffoldedFileDoesNotContain($sut . '/sites/.gitignore', 'settings.php');
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests scaffold command disables .gitignore management when git not present.
|
||||
*
|
||||
* The scaffold operation should still succeed if there is no 'git'
|
||||
* executable.
|
||||
*/
|
||||
public function testUnmanagedGitIgnoreWhenGitNotAvailable(): void {
|
||||
// Note that the drupal-composer-drupal-project fixture does not have any
|
||||
// configuration settings related to .gitignore management.
|
||||
$sut = $this->createSutWithGit('drupal-composer-drupal-project');
|
||||
$this->assertFileDoesNotExist($sut . '/docroot/sites/default/.gitignore');
|
||||
$this->assertFileDoesNotExist($sut . '/docroot/index.php');
|
||||
$this->assertFileDoesNotExist($sut . '/docroot/sites/.gitignore');
|
||||
// Confirm that 'git' is available (n.b. if it were not, createSutWithGit()
|
||||
// would fail).
|
||||
$output = [];
|
||||
exec('git --help', $output, $status);
|
||||
$this->assertEquals(0, $status);
|
||||
// Modify our $PATH so that it begins with a path that contains an
|
||||
// executable script named 'git' that always exits with 127, as if git were
|
||||
// not found. Note that we run our tests using process isolation, so we do
|
||||
// not need to restore the PATH when we are done.
|
||||
$unavailableGitPath = $sut . '/bin';
|
||||
mkdir($unavailableGitPath);
|
||||
$bash = <<<SH
|
||||
#!/bin/bash
|
||||
exit 127
|
||||
|
||||
SH;
|
||||
file_put_contents($unavailableGitPath . '/git', $bash);
|
||||
chmod($unavailableGitPath . '/git', 0755);
|
||||
$oldPath = getenv('PATH');
|
||||
putenv('PATH=' . $unavailableGitPath . ':' . getenv('PATH'));
|
||||
// Confirm that 'git' is no longer available.
|
||||
$output = [];
|
||||
exec('git --help', $output, $status);
|
||||
$this->assertEquals(127, $status);
|
||||
// Run the scaffold command.
|
||||
$output = $this->mustExec('composer drupal:scaffold 2>&1', NULL);
|
||||
|
||||
putenv('PATH=' . $oldPath . ':' . getenv('PATH'));
|
||||
|
||||
$expected = <<<EOT
|
||||
Scaffolding files for fixtures/drupal-assets-fixture:
|
||||
- Copy [web-root]/.csslintrc from assets/.csslintrc
|
||||
- Copy [web-root]/.editorconfig from assets/.editorconfig
|
||||
- Copy [web-root]/.eslintignore from assets/.eslintignore
|
||||
- Copy [web-root]/.eslintrc.json from assets/.eslintrc.json
|
||||
- Copy [web-root]/.gitattributes from assets/.gitattributes
|
||||
- Copy [web-root]/.ht.router.php from assets/.ht.router.php
|
||||
- Skip [web-root]/.htaccess: overridden in fixtures/drupal-composer-drupal-project
|
||||
- Copy [web-root]/sites/default/default.services.yml from assets/default.services.yml
|
||||
- Skip [web-root]/sites/default/default.settings.php: overridden in fixtures/scaffold-override-fixture
|
||||
- Copy [web-root]/sites/example.settings.local.php from assets/example.settings.local.php
|
||||
- Copy [web-root]/sites/example.sites.php from assets/example.sites.php
|
||||
- Copy [web-root]/index.php from assets/index.php
|
||||
- Skip [web-root]/robots.txt: overridden in fixtures/drupal-composer-drupal-project
|
||||
- Copy [web-root]/update.php from assets/update.php
|
||||
Scaffolding files for fixtures/scaffold-override-fixture:
|
||||
- Copy [web-root]/sites/default/default.settings.php from assets/override-settings.php
|
||||
Scaffolding files for fixtures/drupal-composer-drupal-project:
|
||||
- Skip [web-root]/.htaccess: disabled
|
||||
- Copy [web-root]/robots.txt from assets/robots-default.txt
|
||||
|
||||
EOT;
|
||||
$this->assertStringContainsString($expected, $output);
|
||||
$this->assertFileExists($sut . '/docroot/index.php');
|
||||
$this->assertFileDoesNotExist($sut . '/docroot/sites/default/.gitignore');
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,440 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer\Plugin\Scaffold\Functional;
|
||||
|
||||
use Composer\Util\Filesystem;
|
||||
use Drupal\Tests\Composer\Plugin\Scaffold\AssertUtilsTrait;
|
||||
use Drupal\Tests\Composer\Plugin\Scaffold\Fixtures;
|
||||
use Drupal\Tests\Composer\Plugin\Scaffold\ScaffoldTestResult;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Tests Composer Scaffold.
|
||||
*
|
||||
* The purpose of this test file is to exercise all of the different kinds of
|
||||
* scaffold operations: copy, symlinks, skips and so on.
|
||||
*
|
||||
* @group Scaffold
|
||||
*/
|
||||
class ScaffoldTest extends TestCase {
|
||||
use AssertUtilsTrait;
|
||||
|
||||
/**
|
||||
* The root of this project.
|
||||
*
|
||||
* Used to substitute this project's base directory into composer.json files
|
||||
* so Composer can find it.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $projectRoot;
|
||||
|
||||
/**
|
||||
* Directory to perform the tests in.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $fixturesDir;
|
||||
|
||||
/**
|
||||
* The Symfony FileSystem component.
|
||||
*
|
||||
* @var \Symfony\Component\Filesystem\Filesystem
|
||||
*/
|
||||
protected $fileSystem;
|
||||
|
||||
/**
|
||||
* The Fixtures object.
|
||||
*
|
||||
* @var \Drupal\Tests\Composer\Plugin\Scaffold\Fixtures
|
||||
*/
|
||||
protected $fixtures;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
$this->fileSystem = new Filesystem();
|
||||
$this->fixtures = new Fixtures();
|
||||
$this->fixtures->createIsolatedComposerCacheDir();
|
||||
$this->projectRoot = $this->fixtures->projectRoot();
|
||||
// The directory used for creating composer projects to test can be
|
||||
// configured using the SCAFFOLD_FIXTURE_DIR environment variable. Otherwise
|
||||
// a directory will be created in the system's temporary directory.
|
||||
$this->fixturesDir = getenv('SCAFFOLD_FIXTURE_DIR');
|
||||
if (!$this->fixturesDir) {
|
||||
$this->fixturesDir = $this->fixtures->tmpDir($this->name());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function tearDown(): void {
|
||||
// Remove any temporary directories et. al. that were created.
|
||||
$this->fixtures->tearDown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the System-Under-Test.
|
||||
*
|
||||
* @param string $fixture_name
|
||||
* The name of the fixture to use from
|
||||
* core/tests/Drupal/Tests/Component/Scaffold/fixtures.
|
||||
* @param array $replacements
|
||||
* Key : value mappings for placeholders to replace in composer.json
|
||||
* templates.
|
||||
*
|
||||
* @return string
|
||||
* The path to the created System-Under-Test.
|
||||
*/
|
||||
protected function createSut($fixture_name, array $replacements = []): string {
|
||||
$sut = $this->fixturesDir . '/' . $fixture_name;
|
||||
// Erase just our sut, to ensure it is clean. Recopy all of the fixtures.
|
||||
$this->fileSystem->remove($sut);
|
||||
$replacements += ['PROJECT_ROOT' => $this->projectRoot];
|
||||
$this->fixtures->cloneFixtureProjects($this->fixturesDir, $replacements);
|
||||
return $sut;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the system-under-test and runs a scaffold operation on it.
|
||||
*
|
||||
* @param string $fixture_name
|
||||
* The name of the fixture to use from
|
||||
* core/tests/Drupal/Tests/Component/Scaffold/fixtures.
|
||||
* @param bool $is_link
|
||||
* Whether to use symlinks for 'replace' operations.
|
||||
* @param bool $relocated_docroot
|
||||
* Whether the named fixture has a relocated document root.
|
||||
*/
|
||||
public function scaffoldSut($fixture_name, $is_link = FALSE, $relocated_docroot = TRUE) {
|
||||
$sut = $this->createSut($fixture_name, ['SYMLINK' => $is_link ? 'true' : 'false']);
|
||||
// Run composer install to get the dependencies we need to test.
|
||||
$this->fixtures->runComposer("install --no-ansi --no-scripts --no-plugins", $sut);
|
||||
// Test drupal:scaffold.
|
||||
$scaffoldOutput = $this->fixtures->runScaffold($sut);
|
||||
|
||||
// Calculate the docroot directory and assert that our fixture layout
|
||||
// matches what was stipulated in $relocated_docroot. Fail fast if
|
||||
// the caller provided the wrong value.
|
||||
$docroot = $sut;
|
||||
if ($relocated_docroot) {
|
||||
$docroot .= '/docroot';
|
||||
$this->assertFileExists($docroot);
|
||||
}
|
||||
else {
|
||||
$this->assertFileDoesNotExist($sut . '/docroot');
|
||||
}
|
||||
|
||||
return new ScaffoldTestResult($docroot, $scaffoldOutput);
|
||||
}
|
||||
|
||||
/**
|
||||
* Data provider for testScaffoldWithExpectedException.
|
||||
*/
|
||||
public static function scaffoldExpectedExceptionTestValues() {
|
||||
return [
|
||||
[
|
||||
'drupal-drupal-missing-scaffold-file',
|
||||
'Scaffold file assets/missing-robots-default.txt not found in package fixtures/drupal-drupal-missing-scaffold-file.',
|
||||
TRUE,
|
||||
],
|
||||
|
||||
[
|
||||
'project-with-empty-scaffold-path',
|
||||
'No scaffold file path given for [web-root]/my-error in package fixtures/project-with-empty-scaffold-path',
|
||||
FALSE,
|
||||
],
|
||||
|
||||
[
|
||||
'project-with-illegal-dir-scaffold',
|
||||
'Scaffold file assets in package fixtures/project-with-illegal-dir-scaffold is a directory; only files may be scaffolded',
|
||||
FALSE,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests that scaffold files throw when they have bad values.
|
||||
*
|
||||
* @param string $fixture_name
|
||||
* The name of the fixture to use from
|
||||
* core/tests/Drupal/Tests/Component/Scaffold/fixtures.
|
||||
* @param string $expected_exception_message
|
||||
* The expected exception message.
|
||||
* @param bool $is_link
|
||||
* Whether or not symlinking should be used.
|
||||
*
|
||||
* @dataProvider scaffoldExpectedExceptionTestValues
|
||||
*/
|
||||
public function testScaffoldWithExpectedException($fixture_name, $expected_exception_message, $is_link): void {
|
||||
// Test scaffold. Expect an error.
|
||||
$this->expectException(\Exception::class);
|
||||
$this->expectExceptionMessage($expected_exception_message);
|
||||
$this->scaffoldSut($fixture_name, $is_link);
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to scaffold a project that does not scaffold anything.
|
||||
*/
|
||||
public function testEmptyProject(): void {
|
||||
$fixture_name = 'empty-fixture';
|
||||
|
||||
$result = $this->scaffoldSut($fixture_name, FALSE, FALSE);
|
||||
$this->assertStringContainsString('Nothing scaffolded because no packages are allowed in the top-level composer.json file', $result->scaffoldOutput());
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to scaffold a project that allows a project with no scaffold files.
|
||||
*/
|
||||
public function testProjectThatScaffoldsEmptyProject(): void {
|
||||
$fixture_name = 'project-allowing-empty-fixture';
|
||||
$result = $this->scaffoldSut($fixture_name, FALSE, FALSE);
|
||||
$this->assertStringContainsString('The allowed package fixtures/empty-fixture does not provide a file mapping for Composer Scaffold', $result->scaffoldOutput());
|
||||
$this->assertCommonDrupalAssetsWereScaffolded($result->docroot(), FALSE);
|
||||
$this->assertAutoloadFileCorrect($result->docroot());
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides test values for testScaffoldOverridingSettingsExcludingHtaccess.
|
||||
*/
|
||||
public static function scaffoldOverridingSettingsExcludingHtaccessValues() {
|
||||
return [
|
||||
[
|
||||
'drupal-composer-drupal-project',
|
||||
TRUE,
|
||||
TRUE,
|
||||
],
|
||||
|
||||
[
|
||||
'drupal-drupal',
|
||||
FALSE,
|
||||
FALSE,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the drupal/assets scaffold files correct for sut.
|
||||
*
|
||||
* @param string $fixture_name
|
||||
* The name of the fixture to use from
|
||||
* core/tests/Drupal/Tests/Component/Scaffold/fixtures.
|
||||
* @param bool $is_link
|
||||
* Whether to use symlinks for 'replace' operations.
|
||||
* @param bool $relocated_docroot
|
||||
* Whether the named fixture has a relocated document root.
|
||||
*
|
||||
* @dataProvider scaffoldOverridingSettingsExcludingHtaccessValues
|
||||
*/
|
||||
public function testScaffoldOverridingSettingsExcludingHtaccess($fixture_name, $is_link, $relocated_docroot): void {
|
||||
$result = $this->scaffoldSut($fixture_name, $is_link, $relocated_docroot);
|
||||
|
||||
$this->assertCommonDrupalAssetsWereScaffolded($result->docroot(), $is_link);
|
||||
$this->assertAutoloadFileCorrect($result->docroot(), $relocated_docroot);
|
||||
$this->assertDefaultSettingsFromScaffoldOverride($result->docroot(), $is_link);
|
||||
$this->assertHtaccessExcluded($result->docroot());
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the appropriate file was replaced.
|
||||
*
|
||||
* Check the drupal/drupal-based project to confirm that the expected file was
|
||||
* replaced, and that files that were not supposed to be replaced remain
|
||||
* unchanged.
|
||||
*/
|
||||
public function testDrupalDrupalFileWasReplaced(): void {
|
||||
$fixture_name = 'drupal-drupal-test-overwrite';
|
||||
$result = $this->scaffoldSut($fixture_name, FALSE, FALSE);
|
||||
|
||||
$this->assertScaffoldedFile($result->docroot() . '/replace-me.txt', FALSE, 'from assets that replaces file');
|
||||
$this->assertScaffoldedFile($result->docroot() . '/keep-me.txt', FALSE, 'File in drupal-drupal-test-overwrite that is not replaced');
|
||||
$this->assertScaffoldedFile($result->docroot() . '/make-me.txt', FALSE, 'from assets that replaces file');
|
||||
$this->assertCommonDrupalAssetsWereScaffolded($result->docroot(), FALSE);
|
||||
$this->assertAutoloadFileCorrect($result->docroot());
|
||||
$this->assertScaffoldedFile($result->docroot() . '/robots.txt', FALSE, $fixture_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides test values for testDrupalDrupalFileWasAppended.
|
||||
*/
|
||||
public static function scaffoldAppendTestValues(): array {
|
||||
return array_merge(
|
||||
static::scaffoldAppendTestValuesToPermute(FALSE),
|
||||
static::scaffoldAppendTestValuesToPermute(TRUE),
|
||||
[
|
||||
[
|
||||
'drupal-drupal-append-settings',
|
||||
FALSE,
|
||||
'sites/default/settings.php',
|
||||
'<?php
|
||||
|
||||
// Default settings.php contents
|
||||
|
||||
include __DIR__ . "/settings-custom-additions.php";',
|
||||
'NOTICE Creating a new file at [web-root]/sites/default/settings.php. Examine the contents and ensure that it came out correctly.',
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests values to run both with $is_link FALSE and $is_link TRUE.
|
||||
*
|
||||
* @param bool $is_link
|
||||
* Whether or not symlinking should be used.
|
||||
*/
|
||||
protected static function scaffoldAppendTestValuesToPermute($is_link): array {
|
||||
return [
|
||||
[
|
||||
'drupal-drupal-test-append',
|
||||
$is_link,
|
||||
'robots.txt',
|
||||
'# robots.txt fixture scaffolded from "file-mappings" in drupal-drupal-test-append composer.json fixture.
|
||||
# This content is prepended to the top of the existing robots.txt fixture.
|
||||
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
# Test version of robots.txt from drupal/core.
|
||||
|
||||
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
# This content is appended to the bottom of the existing robots.txt fixture.
|
||||
# robots.txt fixture scaffolded from "file-mappings" in drupal-drupal-test-append composer.json fixture.
|
||||
',
|
||||
'Prepend to [web-root]/robots.txt from assets/prepend-to-robots.txt',
|
||||
],
|
||||
|
||||
[
|
||||
'drupal-drupal-append-to-append',
|
||||
$is_link,
|
||||
'robots.txt',
|
||||
'# robots.txt fixture scaffolded from "file-mappings" in drupal-drupal-append-to-append composer.json fixture.
|
||||
# This content is prepended to the top of the existing robots.txt fixture.
|
||||
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
# Test version of robots.txt from drupal/core.
|
||||
|
||||
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
# This content is appended to the bottom of the existing robots.txt fixture.
|
||||
# robots.txt fixture scaffolded from "file-mappings" in profile-with-append composer.json fixture.
|
||||
|
||||
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
# This content is appended to the bottom of the existing robots.txt fixture.
|
||||
# robots.txt fixture scaffolded from "file-mappings" in drupal-drupal-append-to-append composer.json fixture.',
|
||||
'Append to [web-root]/robots.txt from assets/append-to-robots.txt',
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests a fixture where the robots.txt file is prepended / appended to.
|
||||
*
|
||||
* @param string $fixture_name
|
||||
* The name of the fixture to use from
|
||||
* core/tests/Drupal/Tests/Component/Scaffold/fixtures.
|
||||
* @param bool $is_link
|
||||
* Whether or not symlinking should be used.
|
||||
* @param string $scaffold_file_path
|
||||
* Relative path to the scaffold file target we are testing.
|
||||
* @param string $scaffold_file_contents
|
||||
* A string expected to be contained inside the scaffold file we are
|
||||
* testing.
|
||||
* @param string $scaffoldOutputContains
|
||||
* A string expected to be contained in the scaffold command output.
|
||||
*
|
||||
* @dataProvider scaffoldAppendTestValues
|
||||
*/
|
||||
public function testDrupalDrupalFileWasAppended(string $fixture_name, bool $is_link, string $scaffold_file_path, string $scaffold_file_contents, string $scaffoldOutputContains): void {
|
||||
$result = $this->scaffoldSut($fixture_name, $is_link, FALSE);
|
||||
$this->assertStringContainsString($scaffoldOutputContains, $result->scaffoldOutput());
|
||||
|
||||
$this->assertScaffoldedFile($result->docroot() . '/' . $scaffold_file_path, FALSE, $scaffold_file_contents);
|
||||
$this->assertCommonDrupalAssetsWereScaffolded($result->docroot(), $is_link);
|
||||
$this->assertAutoloadFileCorrect($result->docroot());
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the default settings file was overridden by the test.
|
||||
*
|
||||
* @param string $docroot
|
||||
* The path to the System-under-Test's docroot.
|
||||
* @param bool $is_link
|
||||
* Whether or not symlinking is used.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function assertDefaultSettingsFromScaffoldOverride(string $docroot, bool $is_link): void {
|
||||
$this->assertScaffoldedFile($docroot . '/sites/default/default.settings.php', $is_link, 'scaffolded from the scaffold-override-fixture');
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the .htaccess file was excluded by the test.
|
||||
*
|
||||
* @param string $docroot
|
||||
* The path to the System-under-Test's docroot.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function assertHtaccessExcluded(string $docroot): void {
|
||||
// Ensure that the .htaccess.txt file was not written, as our
|
||||
// top-level composer.json excludes it from the files to scaffold.
|
||||
$this->assertFileDoesNotExist($docroot . '/.htaccess');
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the scaffold files from drupal/assets are placed as expected.
|
||||
*
|
||||
* This tests that all assets from drupal/assets were scaffolded, save
|
||||
* for .htaccess, robots.txt and default.settings.php, which are scaffolded
|
||||
* in different ways in different tests.
|
||||
*
|
||||
* @param string $docroot
|
||||
* The path to the System-under-Test's docroot.
|
||||
* @param bool $is_link
|
||||
* Whether or not symlinking is used.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function assertCommonDrupalAssetsWereScaffolded(string $docroot, bool $is_link): void {
|
||||
// Assert scaffold files are written in the correct locations.
|
||||
$this->assertScaffoldedFile($docroot . '/.csslintrc', $is_link, 'Test version of .csslintrc from drupal/core.');
|
||||
$this->assertScaffoldedFile($docroot . '/.editorconfig', $is_link, 'Test version of .editorconfig from drupal/core.');
|
||||
$this->assertScaffoldedFile($docroot . '/.eslintignore', $is_link, 'Test version of .eslintignore from drupal/core.');
|
||||
$this->assertScaffoldedFile($docroot . '/.eslintrc.json', $is_link, 'Test version of .eslintrc.json from drupal/core.');
|
||||
$this->assertScaffoldedFile($docroot . '/.gitattributes', $is_link, 'Test version of .gitattributes from drupal/core.');
|
||||
$this->assertScaffoldedFile($docroot . '/.ht.router.php', $is_link, 'Test version of .ht.router.php from drupal/core.');
|
||||
$this->assertScaffoldedFile($docroot . '/sites/default/default.services.yml', $is_link, 'Test version of default.services.yml from drupal/core.');
|
||||
$this->assertScaffoldedFile($docroot . '/sites/example.settings.local.php', $is_link, 'Test version of example.settings.local.php from drupal/core.');
|
||||
$this->assertScaffoldedFile($docroot . '/sites/example.sites.php', $is_link, 'Test version of example.sites.php from drupal/core.');
|
||||
$this->assertScaffoldedFile($docroot . '/index.php', $is_link, 'Test version of index.php from drupal/core.');
|
||||
$this->assertScaffoldedFile($docroot . '/update.php', $is_link, 'Test version of update.php from drupal/core.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that the autoload file was scaffolded and contains correct path.
|
||||
*
|
||||
* @param string $docroot
|
||||
* Location of the doc root, where autoload.php should be written.
|
||||
* @param bool $relocated_docroot
|
||||
* Whether the document root is relocated or now.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
protected function assertAutoloadFileCorrect(string $docroot, bool $relocated_docroot = FALSE): void {
|
||||
$autoload_path = $docroot . '/autoload.php';
|
||||
|
||||
// Ensure that the autoload.php file was written.
|
||||
$this->assertFileExists($autoload_path);
|
||||
$contents = file_get_contents($autoload_path);
|
||||
|
||||
$expected = "return require __DIR__ . '/vendor/autoload.php';";
|
||||
if ($relocated_docroot) {
|
||||
$expected = "return require __DIR__ . '/../vendor/autoload.php';";
|
||||
}
|
||||
|
||||
$this->assertStringContainsString($expected, $contents);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer\Plugin\Scaffold\Functional;
|
||||
|
||||
use Composer\Util\Filesystem;
|
||||
use Drupal\Tests\Composer\Plugin\Scaffold\AssertUtilsTrait;
|
||||
use Drupal\Tests\Composer\Plugin\ExecTrait;
|
||||
use Drupal\Tests\Composer\Plugin\Scaffold\Fixtures;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* Tests Upgrading the Composer Scaffold plugin.
|
||||
*
|
||||
* Upgrading a Composer plugin can be a dangerous operation. If the plugin
|
||||
* instantiates any classes during the activate method, and the plugin code
|
||||
* is subsequently modified by a `composer update` operation, then any
|
||||
* post-update hook (& etc.) may run with inconsistent code, leading to
|
||||
* runtime errors. This test ensures that it is possible to upgrade from the
|
||||
* last available stable 8.8.x tag to the current Scaffold plugin code (e.g. in
|
||||
* the current patch-under-test).
|
||||
*
|
||||
* @group Scaffold
|
||||
*/
|
||||
class ScaffoldUpgradeTest extends TestCase {
|
||||
|
||||
use AssertUtilsTrait;
|
||||
use ExecTrait;
|
||||
|
||||
/**
|
||||
* The Fixtures object.
|
||||
*
|
||||
* @var \Drupal\Tests\Composer\Plugin\Scaffold\Fixtures
|
||||
*/
|
||||
protected $fixtures;
|
||||
|
||||
/**
|
||||
* The Fixtures directory.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected string $fixturesDir;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
$this->fixtures = new Fixtures();
|
||||
$this->fixtures->createIsolatedComposerCacheDir();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests upgrading the Composer Scaffold plugin.
|
||||
*/
|
||||
public function testScaffoldUpgrade(): void {
|
||||
$this->fixturesDir = $this->fixtures->tmpDir($this->name());
|
||||
$replacements = ['SYMLINK' => 'false', 'PROJECT_ROOT' => $this->fixtures->projectRoot()];
|
||||
$this->fixtures->cloneFixtureProjects($this->fixturesDir, $replacements);
|
||||
$topLevelProjectDir = 'drupal-drupal';
|
||||
$sut = $this->fixturesDir . '/' . $topLevelProjectDir;
|
||||
|
||||
// First step: set up the Scaffold plug in. Ensure that scaffold operation
|
||||
// ran. This is more of a control than a test.
|
||||
$this->mustExec("composer install --no-ansi", $sut);
|
||||
$this->assertScaffoldedFile($sut . '/sites/default/default.settings.php', FALSE, 'A settings.php fixture file scaffolded from the scaffold-override-fixture');
|
||||
|
||||
// Next, bring back packagist.org and install core-composer-scaffold:8.8.0.
|
||||
// Packagist is disabled in the fixture; we bring it back by removing the
|
||||
// line that disables it.
|
||||
$this->mustExec("composer config --unset repositories.packagist.org", $sut);
|
||||
$this->mustExec("composer config --unset repositories.composer-scaffold", $sut);
|
||||
$stdout = $this->mustExec("composer require --no-ansi drupal/core-composer-scaffold:9.5.0 --no-plugins 2>&1", $sut);
|
||||
$this->assertStringContainsString(" - Installing drupal/core-composer-scaffold (9.5.0):", $stdout);
|
||||
|
||||
// We can't force the path repo to re-install over the stable version
|
||||
// without removing it, and removing it masks the bugs we are testing for.
|
||||
// We will therefore make a git repo so that we can tag an explicit version
|
||||
// to require.
|
||||
$testVersion = '99.99.99';
|
||||
$scaffoldPluginTmpRepo = $this->createTmpRepo($this->fixtures->projectRoot(), $this->fixturesDir, $testVersion);
|
||||
|
||||
// Disable packagist.org and upgrade back to the Scaffold plugin under test.
|
||||
// This puts the `"packagist.org": false` config line back in composer.json
|
||||
// so that Packagist will no longer be used.
|
||||
$this->mustExec("composer config repositories.packagist.org false", $sut);
|
||||
$this->mustExec("composer config repositories.composer-scaffold vcs 'file:///$scaffoldPluginTmpRepo'", $sut);
|
||||
|
||||
// Using 'mustExec' was giving a strange binary string here.
|
||||
$output = $this->mustExec("composer require --no-ansi drupal/core-composer-scaffold:$testVersion 2>&1", $sut);
|
||||
$this->assertStringContainsString("Installing drupal/core-composer-scaffold ($testVersion)", $output);
|
||||
|
||||
// Remove a scaffold file and run the scaffold command again to prove that
|
||||
// scaffolding is still working.
|
||||
unlink("$sut/index.php");
|
||||
$stdout = $this->mustExec("composer scaffold", $sut);
|
||||
$this->assertStringContainsString("Scaffolding files for", $stdout);
|
||||
$this->assertFileExists("$sut/index.php");
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the provided source directory and create a temporary git repository.
|
||||
*
|
||||
* @param string $source
|
||||
* Path to directory to copy.
|
||||
* @param string $destParent
|
||||
* Path to location to create git repository.
|
||||
* @param string $version
|
||||
* Version to tag the repository with.
|
||||
*
|
||||
* @return string
|
||||
* Path to temporary git repository.
|
||||
*/
|
||||
protected function createTmpRepo($source, $destParent, $version): string {
|
||||
$target = $destParent . '/' . basename($source);
|
||||
$filesystem = new Filesystem();
|
||||
$filesystem->copy($source, $target);
|
||||
$this->mustExec("git init", $target);
|
||||
$this->mustExec('git config user.email "scaffoldtest@example.com"', $target);
|
||||
$this->mustExec('git config user.name "Scaffold Test"', $target);
|
||||
$this->mustExec("git add .", $target);
|
||||
$this->mustExec("git commit -m 'Initial commit'", $target);
|
||||
$this->mustExec("git tag $version", $target);
|
||||
return $target;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer\Plugin\Scaffold\Integration;
|
||||
|
||||
use Drupal\Composer\Plugin\Scaffold\Operations\AppendOp;
|
||||
use Drupal\Composer\Plugin\Scaffold\ScaffoldOptions;
|
||||
use Drupal\Tests\Composer\Plugin\Scaffold\Fixtures;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\Composer\Plugin\Scaffold\Operations\AppendOp
|
||||
*
|
||||
* @group Scaffold
|
||||
*/
|
||||
class AppendOpTest extends TestCase {
|
||||
|
||||
/**
|
||||
* @covers ::process
|
||||
*/
|
||||
public function testProcess(): void {
|
||||
$fixtures = new Fixtures();
|
||||
$destination = $fixtures->destinationPath('[web-root]/robots.txt');
|
||||
$options = ScaffoldOptions::create([]);
|
||||
// Assert that there is no target file before we run our test.
|
||||
$this->assertFileDoesNotExist($destination->fullPath());
|
||||
|
||||
// Create a file.
|
||||
file_put_contents($destination->fullPath(), "# This is a test\n");
|
||||
|
||||
$prepend = $fixtures->sourcePath('drupal-drupal-test-append', 'prepend-to-robots.txt');
|
||||
$append = $fixtures->sourcePath('drupal-drupal-test-append', 'append-to-robots.txt');
|
||||
$sut = new AppendOp($prepend, $append, TRUE);
|
||||
$sut->scaffoldAtNewLocation($destination);
|
||||
|
||||
$expected = <<<EOT
|
||||
# robots.txt fixture scaffolded from "file-mappings" in drupal-drupal-test-append composer.json fixture.
|
||||
# This content is prepended to the top of the existing robots.txt fixture.
|
||||
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
|
||||
# This is a test
|
||||
|
||||
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
# This content is appended to the bottom of the existing robots.txt fixture.
|
||||
# robots.txt fixture scaffolded from "file-mappings" in drupal-drupal-test-append composer.json fixture.
|
||||
EOT;
|
||||
|
||||
$pre_calculated_contents = $sut->contents();
|
||||
$this->assertEquals(trim($expected), trim($pre_calculated_contents));
|
||||
|
||||
// Test the system under test.
|
||||
$sut->process($destination, $fixtures->io(), $options);
|
||||
// Assert that the target file was created.
|
||||
$this->assertFileExists($destination->fullPath());
|
||||
// Assert the target contained the contents from the correct scaffold files.
|
||||
$contents = trim(file_get_contents($destination->fullPath()));
|
||||
$this->assertEquals(trim($expected), $contents);
|
||||
// Confirm that expected output was written to our io fixture.
|
||||
$output = $fixtures->getOutput();
|
||||
$this->assertStringContainsString('Prepend to [web-root]/robots.txt from assets/prepend-to-robots.txt', $output);
|
||||
$this->assertStringContainsString('Append to [web-root]/robots.txt from assets/append-to-robots.txt', $output);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer\Plugin\Scaffold\Integration;
|
||||
|
||||
use Drupal\Composer\Plugin\Scaffold\Operations\ReplaceOp;
|
||||
use Drupal\Composer\Plugin\Scaffold\ScaffoldOptions;
|
||||
use Drupal\Tests\Composer\Plugin\Scaffold\Fixtures;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\Composer\Plugin\Scaffold\Operations\ReplaceOp
|
||||
*
|
||||
* @group Scaffold
|
||||
*/
|
||||
class ReplaceOpTest extends TestCase {
|
||||
|
||||
/**
|
||||
* @covers ::process
|
||||
*/
|
||||
public function testProcess(): void {
|
||||
$fixtures = new Fixtures();
|
||||
$destination = $fixtures->destinationPath('[web-root]/robots.txt');
|
||||
$source = $fixtures->sourcePath('drupal-assets-fixture', 'robots.txt');
|
||||
$options = ScaffoldOptions::create([]);
|
||||
$sut = new ReplaceOp($source, TRUE);
|
||||
// Assert that there is no target file before we run our test.
|
||||
$this->assertFileDoesNotExist($destination->fullPath());
|
||||
// Test the system under test.
|
||||
$sut->process($destination, $fixtures->io(), $options);
|
||||
// Assert that the target file was created.
|
||||
$this->assertFileExists($destination->fullPath());
|
||||
// Assert the target contained the contents from the correct scaffold file.
|
||||
$contents = trim(file_get_contents($destination->fullPath()));
|
||||
$this->assertEquals('# Test version of robots.txt from drupal/core.', $contents);
|
||||
// Confirm that expected output was written to our io fixture.
|
||||
$output = $fixtures->getOutput();
|
||||
$this->assertStringContainsString('Copy [web-root]/robots.txt from assets/robots.txt', $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::process
|
||||
*/
|
||||
public function testEmptyFile(): void {
|
||||
$fixtures = new Fixtures();
|
||||
$destination = $fixtures->destinationPath('[web-root]/empty_file.txt');
|
||||
$source = $fixtures->sourcePath('empty-file', 'empty_file.txt');
|
||||
$options = ScaffoldOptions::create([]);
|
||||
$sut = new ReplaceOp($source, TRUE);
|
||||
// Assert that there is no target file before we run our test.
|
||||
$this->assertFileDoesNotExist($destination->fullPath());
|
||||
// Test the system under test.
|
||||
$sut->process($destination, $fixtures->io(), $options);
|
||||
// Assert that the target file was created.
|
||||
$this->assertFileExists($destination->fullPath());
|
||||
// Assert the target contained the contents from the correct scaffold file.
|
||||
$this->assertSame('', file_get_contents($destination->fullPath()));
|
||||
// Confirm that expected output was written to our io fixture.
|
||||
$output = $fixtures->getOutput();
|
||||
$this->assertStringContainsString('Copy [web-root]/empty_file.txt from assets/empty_file.txt', $output);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer\Plugin\Scaffold\Integration;
|
||||
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Drupal\Tests\Composer\Plugin\Scaffold\Fixtures;
|
||||
use Drupal\Composer\Plugin\Scaffold\Operations\AppendOp;
|
||||
use Drupal\Composer\Plugin\Scaffold\Operations\SkipOp;
|
||||
use Drupal\Composer\Plugin\Scaffold\Operations\ScaffoldFileCollection;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\Composer\Plugin\Scaffold\Operations\ScaffoldFileCollection
|
||||
*
|
||||
* @group Scaffold
|
||||
*/
|
||||
class ScaffoldFileCollectionTest extends TestCase {
|
||||
|
||||
/**
|
||||
* @covers ::__construct
|
||||
*/
|
||||
public function testCreate(): void {
|
||||
$fixtures = new Fixtures();
|
||||
$locationReplacements = $fixtures->getLocationReplacements();
|
||||
$scaffold_file_fixtures = [
|
||||
'fixtures/drupal-assets-fixture' => [
|
||||
'[web-root]/index.php' => $fixtures->replaceOp('drupal-assets-fixture', 'index.php'),
|
||||
'[web-root]/.htaccess' => $fixtures->replaceOp('drupal-assets-fixture', '.htaccess'),
|
||||
'[web-root]/robots.txt' => $fixtures->replaceOp('drupal-assets-fixture', 'robots.txt'),
|
||||
'[web-root]/sites/default/default.services.yml' => $fixtures->replaceOp('drupal-assets-fixture', 'default.services.yml'),
|
||||
],
|
||||
'fixtures/drupal-profile' => [
|
||||
'[web-root]/sites/default/default.services.yml' => $fixtures->replaceOp('drupal-profile', 'profile.default.services.yml'),
|
||||
],
|
||||
'fixtures/drupal-drupal' => [
|
||||
'[web-root]/.htaccess' => new SkipOp(),
|
||||
'[web-root]/robots.txt' => $fixtures->appendOp('drupal-drupal-test-append', 'append-to-robots.txt'),
|
||||
],
|
||||
];
|
||||
$sut = new ScaffoldFileCollection($scaffold_file_fixtures, $locationReplacements);
|
||||
$resolved_file_mappings = iterator_to_array($sut);
|
||||
// Confirm that the keys of the output are the same as the keys of the
|
||||
// input.
|
||||
$this->assertEquals(array_keys($scaffold_file_fixtures), array_keys($resolved_file_mappings));
|
||||
// '[web-root]/robots.txt' is now a SkipOp, as it is now part of an
|
||||
// append operation.
|
||||
$this->assertEquals([
|
||||
'[web-root]/index.php',
|
||||
'[web-root]/.htaccess',
|
||||
'[web-root]/robots.txt',
|
||||
'[web-root]/sites/default/default.services.yml',
|
||||
], array_keys($resolved_file_mappings['fixtures/drupal-assets-fixture']));
|
||||
$this->assertInstanceOf(SkipOp::class, $resolved_file_mappings['fixtures/drupal-assets-fixture']['[web-root]/robots.txt']->op());
|
||||
|
||||
$this->assertEquals([
|
||||
'[web-root]/sites/default/default.services.yml',
|
||||
], array_keys($resolved_file_mappings['fixtures/drupal-profile']));
|
||||
|
||||
$this->assertEquals([
|
||||
'[web-root]/.htaccess',
|
||||
'[web-root]/robots.txt',
|
||||
], array_keys($resolved_file_mappings['fixtures/drupal-drupal']));
|
||||
|
||||
// Test that .htaccess is skipped.
|
||||
$this->assertInstanceOf(SkipOp::class, $resolved_file_mappings['fixtures/drupal-assets-fixture']['[web-root]/.htaccess']->op());
|
||||
// Test that the expected append operation exists.
|
||||
$this->assertInstanceOf(AppendOp::class, $resolved_file_mappings['fixtures/drupal-drupal']['[web-root]/robots.txt']->op());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer\Plugin\Scaffold\Integration;
|
||||
|
||||
use Drupal\Composer\Plugin\Scaffold\Operations\SkipOp;
|
||||
use Drupal\Composer\Plugin\Scaffold\ScaffoldOptions;
|
||||
use Drupal\Tests\Composer\Plugin\Scaffold\Fixtures;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\Composer\Plugin\Scaffold\Operations\SkipOp
|
||||
*
|
||||
* @group Scaffold
|
||||
*/
|
||||
class SkipOpTest extends TestCase {
|
||||
|
||||
/**
|
||||
* @covers ::process
|
||||
*/
|
||||
public function testProcess(): void {
|
||||
$fixtures = new Fixtures();
|
||||
$destination = $fixtures->destinationPath('[web-root]/robots.txt');
|
||||
$options = ScaffoldOptions::create([]);
|
||||
$sut = new SkipOp();
|
||||
// Assert that there is no target file before we run our test.
|
||||
$this->assertFileDoesNotExist($destination->fullPath());
|
||||
// Test the system under test.
|
||||
$sut->process($destination, $fixtures->io(), $options);
|
||||
// Assert that the target file was not created.
|
||||
$this->assertFileDoesNotExist($destination->fullPath());
|
||||
// Confirm that expected output was written to our io fixture.
|
||||
$output = $fixtures->getOutput();
|
||||
$this->assertStringContainsString('Skip [web-root]/robots.txt: disabled', $output);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer\Plugin\Scaffold;
|
||||
|
||||
/**
|
||||
* Holds result of a scaffold test.
|
||||
*/
|
||||
class ScaffoldTestResult {
|
||||
|
||||
/**
|
||||
* The location of the scaffold fixture.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $docroot;
|
||||
|
||||
/**
|
||||
* The stdout from the test.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $scaffoldOutput;
|
||||
|
||||
/**
|
||||
* Holds the location of the scaffold fixture and the stdout from the test.
|
||||
*
|
||||
* @param string $docroot
|
||||
* The location of the scaffold fixture.
|
||||
* @param string $scaffoldOutput
|
||||
* The stdout from the test.
|
||||
*/
|
||||
public function __construct($docroot, $scaffoldOutput) {
|
||||
$this->docroot = $docroot;
|
||||
$this->scaffoldOutput = $scaffoldOutput;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the location of the docroot from the scaffold test.
|
||||
*
|
||||
* @return string
|
||||
* The location of the scaffold fixture.
|
||||
*/
|
||||
public function docroot() {
|
||||
return $this->docroot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the standard output from the scaffold test.
|
||||
*
|
||||
* @return string
|
||||
* The standard output from the scaffold test.
|
||||
*/
|
||||
public function scaffoldOutput() {
|
||||
return $this->scaffoldOutput;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,37 @@
|
||||
# Fixtures README
|
||||
|
||||
These fixtures are automatically copied to a temporary directory during test
|
||||
runs. After the test run, the fixtures are automatically deleted.
|
||||
|
||||
Set the SCAFFOLD_FIXTURE_DIR environment variable to place the fixtures in a
|
||||
specific location rather than a temporary directory. If this is done, then the
|
||||
fixtures will not be deleted after the test run. This is useful for ad-hoc
|
||||
testing.
|
||||
|
||||
Example:
|
||||
|
||||
$ SCAFFOLD_FIXTURE_DIR=$HOME/tmp/scaffold-fixtures composer unit
|
||||
$ cd $HOME/tmp/scaffold-fixtures
|
||||
$ cd drupal-drupal
|
||||
$ composer drupal:scaffold
|
||||
|
||||
Scaffolding files for fixtures/drupal-assets-fixture:
|
||||
- Link [web-root]/.csslintrc from assets/.csslintrc
|
||||
- Link [web-root]/.editorconfig from assets/.editorconfig
|
||||
- Link [web-root]/.eslintignore from assets/.eslintignore
|
||||
- Link [web-root]/.eslintrc.json from assets/.eslintrc.json
|
||||
- Link [web-root]/.gitattributes from assets/.gitattributes
|
||||
- Link [web-root]/.ht.router.php from assets/.ht.router.php
|
||||
- Skip [web-root]/.htaccess: overridden in my/project
|
||||
- Link [web-root]/sites/default/default.services.yml from assets/default.services.yml
|
||||
- Skip [web-root]/sites/default/default.settings.php: overridden in fixtures/scaffold-override-fixture
|
||||
- Link [web-root]/sites/example.settings.local.php from assets/example.settings.local.php
|
||||
- Link [web-root]/sites/example.sites.php from assets/example.sites.php
|
||||
- Link [web-root]/index.php from assets/index.php
|
||||
- Skip [web-root]/robots.txt: overridden in my/project
|
||||
- Link [web-root]/update.php from assets/update.php
|
||||
Scaffolding files for fixtures/scaffold-override-fixture:
|
||||
- Link [web-root]/sites/default/default.settings.php from assets/override-settings.php
|
||||
Scaffolding files for my/project:
|
||||
- Skip [web-root]/.htaccess: disabled
|
||||
- Link [web-root]/robots.txt from assets/robots-default.txt
|
||||
@ -0,0 +1 @@
|
||||
# robots.txt fixture scaffolded from "file-mappings" in composer-hooks-fixture composer.json fixture.
|
||||
@ -0,0 +1,73 @@
|
||||
{
|
||||
"name": "fixtures/drupal-drupal",
|
||||
"type": "project",
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"repositories": {
|
||||
"packagist.org": false,
|
||||
"composer-scaffold": {
|
||||
"type": "path",
|
||||
"url": "__PROJECT_ROOT__",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"drupal-core-fixture": {
|
||||
"type": "path",
|
||||
"url": "../drupal-core-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"drupal-assets-fixture": {
|
||||
"type": "path",
|
||||
"url": "../drupal-assets-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"scaffold-override-fixture": {
|
||||
"type": "path",
|
||||
"url": "../scaffold-override-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"drupal/core-composer-scaffold": "*",
|
||||
"fixtures/drupal-core-fixture": "*"
|
||||
},
|
||||
"extra": {
|
||||
"drupal-scaffold": {
|
||||
"allowed-packages": [
|
||||
"fixtures/drupal-core-fixture",
|
||||
"fixtures/scaffold-override-fixture"
|
||||
],
|
||||
"locations": {
|
||||
"web-root": "./"
|
||||
},
|
||||
"symlink": __SYMLINK__,
|
||||
"file-mapping": {
|
||||
"[web-root]/.htaccess": false,
|
||||
"[web-root]/robots.txt": "assets/robots-default.txt"
|
||||
}
|
||||
},
|
||||
"installer-paths": {
|
||||
"core": ["type:drupal-core"],
|
||||
"modules/contrib/{$name}": ["type:drupal-module"],
|
||||
"modules/custom/{$name}": ["type:drupal-custom-module"],
|
||||
"profiles/contrib/{$name}": ["type:drupal-profile"],
|
||||
"profiles/custom/{$name}": ["type:drupal-custom-profile"],
|
||||
"themes/contrib/{$name}": ["type:drupal-theme"],
|
||||
"themes/custom/{$name}": ["type:drupal-custom-theme"],
|
||||
"libraries/{$name}": ["type:drupal-library"],
|
||||
"drush/Commands/contrib/{$name}": ["type:drupal-drush"]
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"drupal/core-composer-scaffold": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "fixtures/composer-plugin-implements-scaffold-events",
|
||||
"type": "composer-plugin",
|
||||
"require": {
|
||||
"composer-plugin-api": "^2",
|
||||
"drupal/core-composer-scaffold": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Drupal\\Tests\\fixture\\Composer\\Plugin\\": "src"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"class": "Drupal\\Tests\\fixture\\Composer\\Plugin\\ComposerPluginImplementsScaffoldEvents"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types = 1);
|
||||
|
||||
namespace Drupal\Tests\fixture\Composer\Plugin;
|
||||
|
||||
use Composer\EventDispatcher\EventSubscriberInterface;
|
||||
use Composer\Plugin\PluginInterface;
|
||||
use Composer\Composer;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Script\Event;
|
||||
use Drupal\Composer\Plugin\Scaffold\Handler;
|
||||
|
||||
/**
|
||||
* A fixture composer plugin implement Drupal scaffold events.
|
||||
*/
|
||||
class ComposerPluginImplementsScaffoldEvents implements PluginInterface, EventSubscriberInterface {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getSubscribedEvents(): array {
|
||||
return [
|
||||
Handler::PRE_DRUPAL_SCAFFOLD_CMD => 'preDrupalScaffoldCmd',
|
||||
Handler::POST_DRUPAL_SCAFFOLD_CMD => 'postDrupalScaffoldCmd',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements pre Drupal scaffold cmd.
|
||||
*/
|
||||
public static function preDrupalScaffoldCmd(Event $event): void {
|
||||
$event->getIO()->write('Hello preDrupalScaffoldCmd');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements post Drupal scaffold cmd.
|
||||
*/
|
||||
public static function postDrupalScaffoldCmd(Event $event): void {
|
||||
$event->getIO()->write('Hello postDrupalScaffoldCmd');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function activate(Composer $composer, IOInterface $io): void {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function deactivate(Composer $composer, IOInterface $io): void {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function uninstall(Composer $composer, IOInterface $io): void {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
# Test version of .csslintrc from drupal/core.
|
||||
@ -0,0 +1 @@
|
||||
# Test version of .editorconfig from drupal/core.
|
||||
@ -0,0 +1 @@
|
||||
# Test version of .eslintignore from drupal/core.
|
||||
@ -0,0 +1,2 @@
|
||||
// Test version of .eslintrc.json from drupal/core.
|
||||
{}
|
||||
@ -0,0 +1 @@
|
||||
# Test version of .gitattributes from drupal/core.
|
||||
@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// Test version of .ht.router.php from drupal/core.
|
||||
@ -0,0 +1 @@
|
||||
# Test version of .htaccess from drupal/core.
|
||||
@ -0,0 +1 @@
|
||||
# Test version of default.services.yml from drupal/core.
|
||||
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Test version of default.settings.php from drupal/core.
|
||||
*/
|
||||
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Test version of example.settings.local.php from drupal/core.
|
||||
*/
|
||||
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Test version of example.sites.php from drupal/core.
|
||||
*/
|
||||
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Test version of index.php from drupal/core.
|
||||
*/
|
||||
@ -0,0 +1 @@
|
||||
# Test version of robots.txt from drupal/core.
|
||||
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* Test version of update.php from drupal/core.
|
||||
*/
|
||||
@ -0,0 +1,23 @@
|
||||
{
|
||||
"name": "fixtures/drupal-assets-fixture",
|
||||
"extra": {
|
||||
"drupal-scaffold": {
|
||||
"file-mapping": {
|
||||
"[web-root]/.csslintrc": "assets/.csslintrc",
|
||||
"[web-root]/.editorconfig": "assets/.editorconfig",
|
||||
"[web-root]/.eslintignore": "assets/.eslintignore",
|
||||
"[web-root]/.eslintrc.json": "assets/.eslintrc.json",
|
||||
"[web-root]/.gitattributes": "assets/.gitattributes",
|
||||
"[web-root]/.ht.router.php": "assets/.ht.router.php",
|
||||
"[web-root]/.htaccess": "assets/.htaccess",
|
||||
"[web-root]/sites/default/default.services.yml": "assets/default.services.yml",
|
||||
"[web-root]/sites/default/default.settings.php": "assets/default.settings.php",
|
||||
"[web-root]/sites/example.settings.local.php": "assets/example.settings.local.php",
|
||||
"[web-root]/sites/example.sites.php": "assets/example.sites.php",
|
||||
"[web-root]/index.php": "assets/index.php",
|
||||
"[web-root]/robots.txt": "assets/robots.txt",
|
||||
"[web-root]/update.php": "assets/update.php"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,2 @@
|
||||
composer.lock
|
||||
vendor
|
||||
@ -0,0 +1 @@
|
||||
# robots.txt fixture scaffolded from "file-mappings" in drupal-composer-drupal-project composer.json fixture.
|
||||
@ -0,0 +1,74 @@
|
||||
{
|
||||
"name": "fixtures/drupal-composer-drupal-project",
|
||||
"type": "project",
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"repositories": {
|
||||
"packagist.org": false,
|
||||
"composer-scaffold": {
|
||||
"type": "path",
|
||||
"url": "__PROJECT_ROOT__",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"drupal-core-fixture": {
|
||||
"type": "path",
|
||||
"url": "../drupal-core-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"drupal-assets-fixture": {
|
||||
"type": "path",
|
||||
"url": "../drupal-assets-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"scaffold-override-fixture": {
|
||||
"type": "path",
|
||||
"url": "../scaffold-override-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"drupal/core-composer-scaffold": "*",
|
||||
"fixtures/drupal-core-fixture": "*",
|
||||
"fixtures/scaffold-override-fixture": "*"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"drupal/core-composer-scaffold": true
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"drupal-scaffold": {
|
||||
"allowed-packages": [
|
||||
"fixtures/drupal-core-fixture",
|
||||
"fixtures/scaffold-override-fixture"
|
||||
],
|
||||
"locations": {
|
||||
"web-root": "./docroot"
|
||||
},
|
||||
"symlink": __SYMLINK__,
|
||||
"file-mapping": {
|
||||
"[web-root]/.htaccess": false,
|
||||
"[web-root]/robots.txt": "assets/robots-default.txt"
|
||||
}
|
||||
},
|
||||
"installer-paths": {
|
||||
"docroot/core": ["type:drupal-core"],
|
||||
"docroot/modules/contrib/{$name}": ["type:drupal-module"],
|
||||
"docroot/modules/custom/{$name}": ["type:drupal-custom-module"],
|
||||
"docroot/profiles/contrib/{$name}": ["type:drupal-profile"],
|
||||
"docroot/profiles/custom/{$name}": ["type:drupal-custom-profile"],
|
||||
"docroot/themes/contrib/{$name}": ["type:drupal-theme"],
|
||||
"docroot/themes/custom/{$name}": ["type:drupal-custom-theme"],
|
||||
"docroot/libraries/{$name}": ["type:drupal-library"],
|
||||
"drush/Commands/contrib/{$name}": ["type:drupal-drush"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
/build
|
||||
@ -0,0 +1 @@
|
||||
# README
|
||||
@ -0,0 +1 @@
|
||||
# README
|
||||
@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "fixtures/drupal-core-fixture",
|
||||
"require": {
|
||||
"fixtures/drupal-assets-fixture": "*"
|
||||
},
|
||||
"extra": {
|
||||
"drupal-scaffold": {
|
||||
"allowed-packages": [
|
||||
"fixtures/drupal-assets-fixture"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
include __DIR__ . "/settings-custom-additions.php";
|
||||
@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
// Default settings.php contents
|
||||
@ -0,0 +1,64 @@
|
||||
{
|
||||
"name": "fixtures/drupal-drupal-append-settings",
|
||||
"type": "project",
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"repositories": {
|
||||
"packagist.org": false,
|
||||
"composer-scaffold": {
|
||||
"type": "path",
|
||||
"url": "__PROJECT_ROOT__",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"drupal-core-fixture": {
|
||||
"type": "path",
|
||||
"url": "../drupal-core-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"drupal-assets-fixture": {
|
||||
"type": "path",
|
||||
"url": "../drupal-assets-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"drupal/core-composer-scaffold": "*",
|
||||
"fixtures/drupal-core-fixture": "*"
|
||||
},
|
||||
"extra": {
|
||||
"drupal-scaffold": {
|
||||
"allowed-packages": [
|
||||
"fixtures/drupal-core-fixture"
|
||||
],
|
||||
"gitignore": true,
|
||||
"locations": {
|
||||
"web-root": "./"
|
||||
},
|
||||
"symlink": __SYMLINK__,
|
||||
"file-mapping": {
|
||||
"[web-root]/.htaccess": false,
|
||||
"[web-root]/sites/default/settings.php": {
|
||||
"default": "assets/default-settings.txt",
|
||||
"append": "assets/append-to-settings.txt"
|
||||
}
|
||||
}
|
||||
},
|
||||
"installer-paths": {
|
||||
"core": ["type:drupal-core"],
|
||||
"modules/contrib/{$name}": ["type:drupal-module"],
|
||||
"modules/custom/{$name}": ["type:drupal-custom-module"],
|
||||
"profiles/contrib/{$name}": ["type:drupal-profile"],
|
||||
"profiles/custom/{$name}": ["type:drupal-custom-profile"],
|
||||
"themes/contrib/{$name}": ["type:drupal-theme"],
|
||||
"themes/custom/{$name}": ["type:drupal-custom-theme"],
|
||||
"libraries/{$name}": ["type:drupal-library"],
|
||||
"drush/Commands/contrib/{$name}": ["type:drupal-drush"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
# This content is appended to the bottom of the existing robots.txt fixture.
|
||||
# robots.txt fixture scaffolded from "file-mappings" in drupal-drupal-append-to-append composer.json fixture.
|
||||
@ -0,0 +1,3 @@
|
||||
# robots.txt fixture scaffolded from "file-mappings" in drupal-drupal-append-to-append composer.json fixture.
|
||||
# This content is prepended to the top of the existing robots.txt fixture.
|
||||
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
@ -0,0 +1,72 @@
|
||||
{
|
||||
"name": "fixtures/drupal-drupal-test-append",
|
||||
"type": "project",
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"repositories": {
|
||||
"packagist.org": false,
|
||||
"composer-scaffold": {
|
||||
"type": "path",
|
||||
"url": "__PROJECT_ROOT__",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"drupal-core-fixture": {
|
||||
"type": "path",
|
||||
"url": "../drupal-core-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"profile-with-append": {
|
||||
"type": "path",
|
||||
"url": "../profile-with-append",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"drupal-assets-fixture": {
|
||||
"type": "path",
|
||||
"url": "../drupal-assets-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"drupal/core-composer-scaffold": "*",
|
||||
"fixtures/profile-with-append": "*",
|
||||
"fixtures/drupal-core-fixture": "*"
|
||||
},
|
||||
"extra": {
|
||||
"drupal-scaffold": {
|
||||
"allowed-packages": [
|
||||
"fixtures/drupal-core-fixture",
|
||||
"fixtures/profile-with-append"
|
||||
],
|
||||
"locations": {
|
||||
"web-root": "./"
|
||||
},
|
||||
"symlink": __SYMLINK__,
|
||||
"file-mapping": {
|
||||
"[web-root]/.htaccess": false,
|
||||
"[web-root]/robots.txt": {
|
||||
"prepend": "assets/prepend-to-robots.txt",
|
||||
"append": "assets/append-to-robots.txt"
|
||||
}
|
||||
}
|
||||
},
|
||||
"installer-paths": {
|
||||
"core": ["type:drupal-core"],
|
||||
"modules/contrib/{$name}": ["type:drupal-module"],
|
||||
"modules/custom/{$name}": ["type:drupal-custom-module"],
|
||||
"profiles/contrib/{$name}": ["type:drupal-profile"],
|
||||
"profiles/custom/{$name}": ["type:drupal-custom-profile"],
|
||||
"themes/contrib/{$name}": ["type:drupal-theme"],
|
||||
"themes/custom/{$name}": ["type:drupal-custom-theme"],
|
||||
"libraries/{$name}": ["type:drupal-library"],
|
||||
"drush/Commands/contrib/{$name}": ["type:drupal-drush"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,69 @@
|
||||
{
|
||||
"name": "fixtures/drupal-drupal-missing-scaffold-file",
|
||||
"type": "project",
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"repositories": {
|
||||
"packagist.org": false,
|
||||
"composer-scaffold": {
|
||||
"type": "path",
|
||||
"url": "__PROJECT_ROOT__",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"drupal-core-fixture": {
|
||||
"type": "path",
|
||||
"url": "../drupal-core-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"drupal-assets-fixture": {
|
||||
"type": "path",
|
||||
"url": "../drupal-assets-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"scaffold-override-fixture": {
|
||||
"type": "path",
|
||||
"url": "../scaffold-override-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"drupal/core-composer-scaffold": "*",
|
||||
"fixtures/drupal-core-fixture": "*",
|
||||
"fixtures/scaffold-override-fixture": "*"
|
||||
},
|
||||
"extra": {
|
||||
"drupal-scaffold": {
|
||||
"allowed-packages": [
|
||||
"fixtures/drupal-core-fixture",
|
||||
"fixtures/scaffold-override-fixture"
|
||||
],
|
||||
"locations": {
|
||||
"web-root": "./"
|
||||
},
|
||||
"symlink": __SYMLINK__,
|
||||
"file-mapping": {
|
||||
"[web-root]/.htaccess": false,
|
||||
"[web-root]/robots.txt": "assets/missing-robots-default.txt"
|
||||
}
|
||||
},
|
||||
"installer-paths": {
|
||||
"core": ["type:drupal-core"],
|
||||
"modules/contrib/{$name}": ["type:drupal-module"],
|
||||
"modules/custom/{$name}": ["type:drupal-custom-module"],
|
||||
"profiles/contrib/{$name}": ["type:drupal-profile"],
|
||||
"profiles/custom/{$name}": ["type:drupal-custom-profile"],
|
||||
"themes/contrib/{$name}": ["type:drupal-theme"],
|
||||
"themes/custom/{$name}": ["type:drupal-custom-theme"],
|
||||
"libraries/{$name}": ["type:drupal-library"],
|
||||
"drush/Commands/contrib/{$name}": ["type:drupal-drush"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
# This content is appended to the bottom of the existing robots.txt fixture.
|
||||
# robots.txt fixture scaffolded from "file-mappings" in drupal-drupal-test-append composer.json fixture.
|
||||
@ -0,0 +1,3 @@
|
||||
# robots.txt fixture scaffolded from "file-mappings" in drupal-drupal-test-append composer.json fixture.
|
||||
# This content is prepended to the top of the existing robots.txt fixture.
|
||||
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
@ -0,0 +1,63 @@
|
||||
{
|
||||
"name": "fixtures/drupal-drupal-test-append",
|
||||
"type": "project",
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"repositories": {
|
||||
"packagist.org": false,
|
||||
"composer-scaffold": {
|
||||
"type": "path",
|
||||
"url": "__PROJECT_ROOT__",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"drupal-core-fixture": {
|
||||
"type": "path",
|
||||
"url": "../drupal-core-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"drupal-assets-fixture": {
|
||||
"type": "path",
|
||||
"url": "../drupal-assets-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"drupal/core-composer-scaffold": "*",
|
||||
"fixtures/drupal-core-fixture": "*"
|
||||
},
|
||||
"extra": {
|
||||
"drupal-scaffold": {
|
||||
"allowed-packages": [
|
||||
"fixtures/drupal-core-fixture"
|
||||
],
|
||||
"locations": {
|
||||
"web-root": "./"
|
||||
},
|
||||
"symlink": __SYMLINK__,
|
||||
"file-mapping": {
|
||||
"[web-root]/.htaccess": false,
|
||||
"[web-root]/robots.txt": {
|
||||
"prepend": "assets/prepend-to-robots.txt",
|
||||
"append": "assets/append-to-robots.txt"
|
||||
}
|
||||
}
|
||||
},
|
||||
"installer-paths": {
|
||||
"core": ["type:drupal-core"],
|
||||
"modules/contrib/{$name}": ["type:drupal-module"],
|
||||
"modules/custom/{$name}": ["type:drupal-custom-module"],
|
||||
"profiles/contrib/{$name}": ["type:drupal-profile"],
|
||||
"profiles/custom/{$name}": ["type:drupal-custom-profile"],
|
||||
"themes/contrib/{$name}": ["type:drupal-theme"],
|
||||
"themes/custom/{$name}": ["type:drupal-custom-theme"],
|
||||
"libraries/{$name}": ["type:drupal-library"],
|
||||
"drush/Commands/contrib/{$name}": ["type:drupal-drush"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
# File from assets that replaces file in web root.
|
||||
@ -0,0 +1 @@
|
||||
# robots.txt fixture scaffolded from "file-mappings" in drupal-drupal-test-overwrite composer.json fixture.
|
||||
@ -0,0 +1,81 @@
|
||||
{
|
||||
"name": "fixtures/drupal-drupal-test-overwrite",
|
||||
"type": "project",
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"repositories": {
|
||||
"packagist.org": false,
|
||||
"composer-scaffold": {
|
||||
"type": "path",
|
||||
"url": "__PROJECT_ROOT__",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"drupal-core-fixture": {
|
||||
"type": "path",
|
||||
"url": "../drupal-core-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"drupal-assets-fixture": {
|
||||
"type": "path",
|
||||
"url": "../drupal-assets-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"scaffold-override-fixture": {
|
||||
"type": "path",
|
||||
"url": "../scaffold-override-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"drupal/core-composer-scaffold": "*",
|
||||
"fixtures/drupal-core-fixture": "*",
|
||||
"fixtures/scaffold-override-fixture": "*"
|
||||
},
|
||||
"extra": {
|
||||
"drupal-scaffold": {
|
||||
"allowed-packages": [
|
||||
"fixtures/drupal-core-fixture",
|
||||
"fixtures/scaffold-override-fixture"
|
||||
],
|
||||
"locations": {
|
||||
"web-root": "./"
|
||||
},
|
||||
"symlink": __SYMLINK__,
|
||||
"file-mapping": {
|
||||
"[web-root]/.htaccess": false,
|
||||
"[web-root]/robots.txt": "assets/robots-default.txt",
|
||||
"make-me.txt": {
|
||||
"path": "assets/replacement.txt",
|
||||
"overwrite": false
|
||||
},
|
||||
"keep-me.txt": {
|
||||
"path": "assets/replacement.txt",
|
||||
"overwrite": false
|
||||
},
|
||||
"replace-me.txt": {
|
||||
"path": "assets/replacement.txt",
|
||||
"overwrite": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"installer-paths": {
|
||||
"core": ["type:drupal-core"],
|
||||
"modules/contrib/{$name}": ["type:drupal-module"],
|
||||
"modules/custom/{$name}": ["type:drupal-custom-module"],
|
||||
"profiles/contrib/{$name}": ["type:drupal-profile"],
|
||||
"profiles/custom/{$name}": ["type:drupal-custom-profile"],
|
||||
"themes/contrib/{$name}": ["type:drupal-theme"],
|
||||
"themes/custom/{$name}": ["type:drupal-custom-theme"],
|
||||
"libraries/{$name}": ["type:drupal-library"],
|
||||
"drush/Commands/contrib/{$name}": ["type:drupal-drush"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
# File in drupal-drupal-test-overwrite that is not replaced by a scaffold file.
|
||||
@ -0,0 +1 @@
|
||||
# File in drupal-drupal-test-overwrite that is replaced by a scaffold file.
|
||||
@ -0,0 +1 @@
|
||||
# robots.txt fixture scaffolded from "file-mappings" in drupal-drupal composer.json fixture.
|
||||
@ -0,0 +1,76 @@
|
||||
{
|
||||
"name": "fixtures/drupal-drupal",
|
||||
"type": "project",
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"repositories": {
|
||||
"packagist.org": false,
|
||||
"composer-scaffold": {
|
||||
"type": "path",
|
||||
"url": "__PROJECT_ROOT__",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"drupal-core-fixture": {
|
||||
"type": "path",
|
||||
"url": "../drupal-core-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"drupal-assets-fixture": {
|
||||
"type": "path",
|
||||
"url": "../drupal-assets-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"scaffold-override-fixture": {
|
||||
"type": "path",
|
||||
"url": "../scaffold-override-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"drupal/core-composer-scaffold": "*",
|
||||
"fixtures/drupal-core-fixture": "*",
|
||||
"fixtures/scaffold-override-fixture": "*"
|
||||
},
|
||||
"extra": {
|
||||
"drupal-scaffold": {
|
||||
"allowed-packages": [
|
||||
"fixtures/drupal-core-fixture",
|
||||
"fixtures/scaffold-override-fixture"
|
||||
],
|
||||
"gitignore": false,
|
||||
"symlink": __SYMLINK__,
|
||||
"file-mapping": {
|
||||
"[web-root]/.htaccess": false,
|
||||
"[web-root]/robots.txt": {
|
||||
"mode": "replace",
|
||||
"path": "assets/robots-default.txt",
|
||||
"overwrite": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"installer-paths": {
|
||||
"core": ["type:drupal-core"],
|
||||
"modules/contrib/{$name}": ["type:drupal-module"],
|
||||
"modules/custom/{$name}": ["type:drupal-custom-module"],
|
||||
"profiles/contrib/{$name}": ["type:drupal-profile"],
|
||||
"profiles/custom/{$name}": ["type:drupal-custom-profile"],
|
||||
"themes/contrib/{$name}": ["type:drupal-theme"],
|
||||
"themes/custom/{$name}": ["type:drupal-custom-theme"],
|
||||
"libraries/{$name}": ["type:drupal-library"],
|
||||
"drush/Commands/contrib/{$name}": ["type:drupal-drush"]
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"drupal/core-composer-scaffold": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
# default.services.yml fixture scaffolded from "file-mappings" in drupal-project composer.json fixture.
|
||||
@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "fixtures/drupal-profile",
|
||||
"extra": {
|
||||
"drupal-scaffold": {
|
||||
"file-mapping": {
|
||||
"[web-root]/.htaccess": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "fixtures/empty-file",
|
||||
"extra": {
|
||||
"drupal-scaffold": {
|
||||
"file-mapping": {
|
||||
"[web-root]/empty_file.txt": "assets/empty_file.txt"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
{
|
||||
"name": "fixtures/empty-fixture-allowing-core",
|
||||
"extra": {
|
||||
"drupal-scaffold": {
|
||||
"allowed-packages": [
|
||||
"fixtures/drupal-core-fixture"
|
||||
],
|
||||
"locations": {
|
||||
"web-root": "./"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
{
|
||||
"name": "fixtures/empty-fixture"
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
{
|
||||
"packages": {
|
||||
"fixtures/drupal-drupal": {
|
||||
"dev-master": {
|
||||
"name": "fixtures/drupal-drupal",
|
||||
"version": "1.0.0",
|
||||
"dist": {
|
||||
"url": "./drupal-drupal",
|
||||
"type": "path"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
# ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
|
||||
# This content is appended to the bottom of the existing robots.txt fixture.
|
||||
# robots.txt fixture scaffolded from "file-mappings" in profile-with-append composer.json fixture.
|
||||
@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "fixtures/profile-with-append",
|
||||
"extra": {
|
||||
"drupal-scaffold": {
|
||||
"file-mapping": {
|
||||
"[web-root]/robots.txt": {
|
||||
"append": "assets/append-to-robots.txt"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
{
|
||||
"name": "fixtures/project-allowing-empty-fixture",
|
||||
"type": "project",
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"repositories": {
|
||||
"packagist.org": false,
|
||||
"composer-scaffold": {
|
||||
"type": "path",
|
||||
"url": "__PROJECT_ROOT__",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"drupal-core-fixture": {
|
||||
"type": "path",
|
||||
"url": "../drupal-core-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"drupal-assets-fixture": {
|
||||
"type": "path",
|
||||
"url": "../drupal-assets-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"empty-fixture": {
|
||||
"type": "path",
|
||||
"url": "../empty-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"scaffold-override-fixture": {
|
||||
"type": "path",
|
||||
"url": "../scaffold-override-fixture",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"drupal/core-composer-scaffold": "*",
|
||||
"fixtures/drupal-core-fixture": "*",
|
||||
"fixtures/empty-fixture": "*",
|
||||
"fixtures/scaffold-override-fixture": "*"
|
||||
},
|
||||
"extra": {
|
||||
"drupal-scaffold": {
|
||||
"allowed-packages": [
|
||||
"fixtures/drupal-core-fixture",
|
||||
"fixtures/empty-fixture",
|
||||
"fixtures/scaffold-override-fixture"
|
||||
],
|
||||
"locations": {
|
||||
"web-root": "./"
|
||||
},
|
||||
"gitignore": false,
|
||||
"symlink": __SYMLINK__,
|
||||
"file-mapping": {
|
||||
"[web-root]/.htaccess": false
|
||||
}
|
||||
},
|
||||
"installer-paths": {
|
||||
"core": ["type:drupal-core"],
|
||||
"modules/contrib/{$name}": ["type:drupal-module"],
|
||||
"modules/custom/{$name}": ["type:drupal-custom-module"],
|
||||
"profiles/contrib/{$name}": ["type:drupal-profile"],
|
||||
"profiles/custom/{$name}": ["type:drupal-custom-profile"],
|
||||
"themes/contrib/{$name}": ["type:drupal-theme"],
|
||||
"themes/custom/{$name}": ["type:drupal-custom-theme"],
|
||||
"libraries/{$name}": ["type:drupal-library"],
|
||||
"drush/Commands/contrib/{$name}": ["type:drupal-drush"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "fixtures/project-with-empty-scaffold-path",
|
||||
"extra": {
|
||||
"drupal-scaffold": {
|
||||
"locations": {
|
||||
"web-root": "./"
|
||||
},
|
||||
"file-mapping": {
|
||||
"[web-root]/my-error": {
|
||||
"path": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1 @@
|
||||
# README
|
||||
@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "fixtures/project-with-illegal-dir-scaffold",
|
||||
"extra": {
|
||||
"drupal-scaffold": {
|
||||
"locations": {
|
||||
"web-root": "./"
|
||||
},
|
||||
"file-mapping": {
|
||||
"[web-root]/assets": {
|
||||
"path": "assets"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,44 @@
|
||||
{
|
||||
"name": "fixtures/drupal-drupal",
|
||||
"type": "project",
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"repositories": {
|
||||
"packagist.org": false,
|
||||
"composer-scaffold": {
|
||||
"type": "path",
|
||||
"url": "__PROJECT_ROOT__",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"fixtures/composer-plugin-implements-scaffold-events": {
|
||||
"type": "path",
|
||||
"url": "../composer-plugin-implements-scaffold-events",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"drupal/core-composer-scaffold": "*",
|
||||
"fixtures/composer-plugin-implements-scaffold-events": "*"
|
||||
},
|
||||
"extra": {
|
||||
"drupal-scaffold": {
|
||||
"allowed-packages": [
|
||||
"fixtures/composer-plugin-implements-scaffold-events"
|
||||
],
|
||||
"locations": {
|
||||
"web-root": "./"
|
||||
},
|
||||
"symlink": __SYMLINK__
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"drupal/core-composer-scaffold": true,
|
||||
"fixtures/composer-plugin-implements-scaffold-events": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @file
|
||||
* A settings.php fixture file scaffolded from the scaffold-override-fixture.
|
||||
*/
|
||||
@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "fixtures/scaffold-override-fixture",
|
||||
"extra": {
|
||||
"drupal-scaffold": {
|
||||
"file-mapping": {
|
||||
"[web-root]/sites/default/default.settings.php": "assets/override-settings.php"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer\Plugin\Unpack;
|
||||
|
||||
use Drupal\Tests\Composer\Plugin\FixturesBase;
|
||||
|
||||
/**
|
||||
* Fixture for testing the unpack composer plugin.
|
||||
*/
|
||||
class Fixtures extends FixturesBase {
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function projectRoot(): string {
|
||||
return realpath(__DIR__) . '/../../../../../../../composer/Plugin/RecipeUnpack';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function allFixturesDir(): string {
|
||||
return realpath(__DIR__ . '/fixtures');
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function tmpDir(string $prefix): string {
|
||||
$prefix .= static::persistentPrefix();
|
||||
$tmpDir = sys_get_temp_dir() . '/unpack-' . $prefix . uniqid(md5($prefix . microtime()), TRUE);
|
||||
$this->tmpDirs[] = $tmpDir;
|
||||
return $tmpDir;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer\Plugin\Unpack;
|
||||
|
||||
use Composer\Semver\VersionParser;
|
||||
use Drupal\Composer\Plugin\RecipeUnpack\SemVer;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\Composer\Plugin\RecipeUnpack\SemVer
|
||||
*
|
||||
* @group Unpack
|
||||
*/
|
||||
class SemVerTest extends TestCase {
|
||||
|
||||
/**
|
||||
* @testWith ["^6.1", "^6.3", "^6.3"]
|
||||
* ["*", "^6.3", "^6.3"]
|
||||
* ["^6@dev", "^6.3", "^6.3"]
|
||||
*
|
||||
* @covers ::minimizeConstraints
|
||||
*/
|
||||
public function testMinimizeConstraints(string $constraint_a, string $constraint_b, string $expected): void {
|
||||
$version_parser = new VersionParser();
|
||||
$this->assertSame($expected, SemVer::minimizeConstraints($version_parser, $constraint_a, $constraint_b));
|
||||
$this->assertSame($expected, SemVer::minimizeConstraints($version_parser, $constraint_b, $constraint_a));
|
||||
}
|
||||
|
||||
/**
|
||||
* @testWith ["^6.1 || ^4.0", "^6.3 || ^7.4", ">=6.3.0.0-dev, <7.0.0.0-dev"]
|
||||
*
|
||||
* @covers ::minimizeConstraints
|
||||
*/
|
||||
public function testMinimizeConstraintsWhichAreNotSubsets(string $constraint_a, string $constraint_b, string $expected): void {
|
||||
$this->assertSame($expected, SemVer::minimizeConstraints(new VersionParser(), $constraint_a, $constraint_b));
|
||||
}
|
||||
|
||||
/**
|
||||
* @testWith ["^6.1", "^5.1", ">=6.3.0.0-dev, <7.0.0.0-dev"]
|
||||
*
|
||||
* @covers ::minimizeConstraints
|
||||
*/
|
||||
public function testMinimizeConstraintsWhichDoNotIntersect(string $constraint_a, string $constraint_b, string $expected): void {
|
||||
$this->expectException(\LogicException::class);
|
||||
$this->expectExceptionMessage('The constraints "^6.1" and "^5.1" do not intersect and cannot be minimized.');
|
||||
$this->assertSame($expected, SemVer::minimizeConstraints(new VersionParser(), $constraint_a, $constraint_b));
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,98 @@
|
||||
{
|
||||
"name": "fixtures/root",
|
||||
"description": "Test recipe unpacking",
|
||||
"type": "project",
|
||||
"minimum-stability": "dev",
|
||||
"prefer-stable": true,
|
||||
"repositories": {
|
||||
"packagist.org": false,
|
||||
"core-recipe-unpack": {
|
||||
"type": "path",
|
||||
"url": "__PROJECT_ROOT__",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"composer/installers": {
|
||||
"type": "path",
|
||||
"url": "__COMPOSER_INSTALLERS__",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"recipes/recipe-a": {
|
||||
"type": "path",
|
||||
"url": "../recipes/composer-recipe-a",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"recipes/recipe-b": {
|
||||
"type": "path",
|
||||
"url": "../recipes/composer-recipe-b",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"recipes/recipe-c": {
|
||||
"type": "path",
|
||||
"url": "../recipes/composer-recipe-c",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"recipes/recipe-d": {
|
||||
"type": "path",
|
||||
"url": "../recipes/composer-recipe-d",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"modules/module-a": {
|
||||
"type": "path",
|
||||
"url": "../modules/composer-module-a",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"modules/module-b": {
|
||||
"type": "path",
|
||||
"url": "../modules/composer-module-b",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
},
|
||||
"themes/theme-a": {
|
||||
"type": "path",
|
||||
"url": "../themes/composer-theme-a",
|
||||
"options": {
|
||||
"symlink": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"composer/installers": "*",
|
||||
"drupal/core-recipe-unpack": "*",
|
||||
"ext-json": "*"
|
||||
},
|
||||
"extra": {
|
||||
"installer-paths": {
|
||||
"core": ["type:drupal-core"],
|
||||
"modules/contrib/{$name}": ["type:drupal-module"],
|
||||
"modules/custom/{$name}": ["type:drupal-custom-module"],
|
||||
"themes/contrib/{$name}": ["type:drupal-theme"],
|
||||
"themes/custom/{$name}": ["type:drupal-custom-theme"],
|
||||
"recipes/{$name}": ["type:drupal-recipe"],
|
||||
"profiles/contrib/{$name}": ["type:drupal-profile"],
|
||||
"profiles/custom/{$name}": ["type:drupal-custom-profile"],
|
||||
"libraries/{$name}": ["type:drupal-library"],
|
||||
"drush/Commands/contrib/{$name}": ["type:drupal-drush"]
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"composer/installers": true,
|
||||
"drupal/core-recipe-unpack": true
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "fixtures/module-a",
|
||||
"version": "1.0.4",
|
||||
"type": "drupal-module",
|
||||
"description": "A Drupal module's composer for testing."
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
{
|
||||
"name": "fixtures/module-b",
|
||||
"version": "2.0.1",
|
||||
"type": "drupal-module",
|
||||
"description": "A Drupal module's composer for testing."
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "fixtures/recipe-a",
|
||||
"type": "drupal-recipe",
|
||||
"description": "A Drupal recipe's composer for testing.",
|
||||
"require": {
|
||||
"fixtures/recipe-b": "*",
|
||||
"fixtures/module-b": "^2.0"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
name: 'RecipeA'
|
||||
description: 'Recipe A.'
|
||||
type: 'test recipe'
|
||||
@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "fixtures/recipe-b",
|
||||
"type": "drupal-recipe",
|
||||
"description": "A Drupal recipe's composer for testing.",
|
||||
"require": {
|
||||
"fixtures/module-a": "*",
|
||||
"fixtures/theme-a": "*"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
name: 'RecipeB'
|
||||
description: 'Recipe B.'
|
||||
type: 'test recipe'
|
||||
@ -0,0 +1,9 @@
|
||||
{
|
||||
"name": "fixtures/recipe-c",
|
||||
"type": "drupal-recipe",
|
||||
"description": "A Drupal recipe's composer for testing.",
|
||||
"require": {
|
||||
"fixtures/recipe-b": "*",
|
||||
"fixtures/module-b": ">=2.0.1 || 1.1.1"
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
name: 'RecipeC'
|
||||
description: 'Recipe C.'
|
||||
type: 'test recipe'
|
||||
@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "fixtures/recipe-d",
|
||||
"type": "drupal-recipe",
|
||||
"description": "A Drupal recipe's composer for testing."
|
||||
}
|
||||
@ -0,0 +1,3 @@
|
||||
name: 'RecipeD'
|
||||
description: 'Recipe D.'
|
||||
type: 'test recipe'
|
||||
@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "fixtures/theme-a",
|
||||
"type": "drupal-theme",
|
||||
"description": "A Drupal theme's composer for testing."
|
||||
}
|
||||
@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer\Plugin\VendorHardening;
|
||||
|
||||
use Composer\Package\RootPackageInterface;
|
||||
use Drupal\Composer\Plugin\VendorHardening\Config;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass Drupal\Composer\Plugin\VendorHardening\Config
|
||||
* @group VendorHardening
|
||||
*/
|
||||
class ConfigTest extends TestCase {
|
||||
|
||||
/**
|
||||
* @covers ::getPathsForPackage
|
||||
*/
|
||||
public function testGetPathsForPackageMixedCase(): void {
|
||||
$config = $this->getMockBuilder(Config::class)
|
||||
->onlyMethods(['getAllCleanupPaths'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$config->expects($this->once())
|
||||
->method('getAllCleanupPaths')
|
||||
->willReturn(['package' => ['path']]);
|
||||
|
||||
$this->assertSame(['path'], $config->getPathsForPackage('pACKage'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getAllCleanupPaths
|
||||
*/
|
||||
public function testNoRootMergeConfig(): void {
|
||||
// Root package has no extra field.
|
||||
$root = $this->createMock(RootPackageInterface::class);
|
||||
$root->expects($this->once())
|
||||
->method('getExtra')
|
||||
->willReturn([]);
|
||||
|
||||
$config = new Config($root);
|
||||
|
||||
$ref_default = new \ReflectionProperty($config, 'defaultConfig');
|
||||
|
||||
$ref_plugin_config = new \ReflectionMethod($config, 'getAllCleanupPaths');
|
||||
|
||||
$this->assertEquals(
|
||||
$ref_default->getValue($config), $ref_plugin_config->invoke($config)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getAllCleanupPaths
|
||||
*/
|
||||
public function testRootMergeConfig(): void {
|
||||
// Root package has configuration in extra.
|
||||
$root = $this->createMock(RootPackageInterface::class);
|
||||
$root->expects($this->once())
|
||||
->method('getExtra')
|
||||
->willReturn([
|
||||
'drupal-core-vendor-hardening' => [
|
||||
'isa/string' => 'test_dir',
|
||||
'an/array' => ['test_dir', 'doc_dir'],
|
||||
],
|
||||
]);
|
||||
|
||||
$config = new Config($root);
|
||||
|
||||
$ref_plugin_config = new \ReflectionMethod($config, 'getAllCleanupPaths');
|
||||
|
||||
$plugin_config = $ref_plugin_config->invoke($config);
|
||||
|
||||
$this->assertSame(['test_dir'], $plugin_config['isa/string']);
|
||||
$this->assertSame(['test_dir', 'doc_dir'], $plugin_config['an/array']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getAllCleanupPaths
|
||||
*
|
||||
* @runInSeparateProcess
|
||||
*/
|
||||
public function testMixedCaseConfigCleanupPackages(): void {
|
||||
// Root package has configuration in extra.
|
||||
$root = $this->createMock(RootPackageInterface::class);
|
||||
$root->expects($this->once())
|
||||
->method('getExtra')
|
||||
->willReturn([
|
||||
'drupal-core-vendor-hardening' => [
|
||||
'NotMikey179/vfsStream' => ['src/test'],
|
||||
],
|
||||
]);
|
||||
|
||||
$config = new Config($root);
|
||||
|
||||
$ref_plugin_config = new \ReflectionMethod($config, 'getAllCleanupPaths');
|
||||
|
||||
// Put some mixed-case in the defaults.
|
||||
$ref_default = new \ReflectionProperty($config, 'defaultConfig');
|
||||
$ref_default->setValue($config, [
|
||||
'BeHatted/Monk' => ['tests'],
|
||||
'SymPhony/HTTPFoundational' => ['src'],
|
||||
]);
|
||||
|
||||
$plugin_config = $ref_plugin_config->invoke($config);
|
||||
|
||||
foreach (array_keys($plugin_config) as $package_name) {
|
||||
$this->assertDoesNotMatchRegularExpression('/[A-Z]/', $package_name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::getAllCleanupPaths
|
||||
*/
|
||||
public function testSkipClean(): void {
|
||||
$root = $this->createMock(RootPackageInterface::class);
|
||||
$root->expects($this->once())
|
||||
->method('getExtra')
|
||||
->willReturn([
|
||||
'drupal-core-vendor-hardening' => [
|
||||
'composer/composer' => FALSE,
|
||||
],
|
||||
]);
|
||||
|
||||
$plugin_config = (new Config($root))->getAllCleanupPaths();
|
||||
$this->assertArrayNotHasKey('composer/composer', $plugin_config);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,232 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Drupal\Tests\Composer\Plugin\VendorHardening;
|
||||
|
||||
use Composer\Composer;
|
||||
use Composer\IO\IOInterface;
|
||||
use Composer\Package\PackageInterface;
|
||||
use Composer\Package\RootPackageInterface;
|
||||
use Drupal\Composer\Plugin\VendorHardening\Config;
|
||||
use Drupal\Composer\Plugin\VendorHardening\VendorHardeningPlugin;
|
||||
use org\bovigo\vfs\vfsStream;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Prophecy\PhpUnit\ProphecyTrait;
|
||||
|
||||
/**
|
||||
* @coversDefaultClass \Drupal\Composer\Plugin\VendorHardening\VendorHardeningPlugin
|
||||
* @group VendorHardening
|
||||
*/
|
||||
class VendorHardeningPluginTest extends TestCase {
|
||||
|
||||
use ProphecyTrait;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
protected function setUp(): void {
|
||||
parent::setUp();
|
||||
vfsStream::setup('vendor', NULL, [
|
||||
'drupal' => [
|
||||
'package' => [
|
||||
'tests' => [
|
||||
'SomeTest.php' => '<?php',
|
||||
],
|
||||
'SomeFile.php' => '<?php',
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::cleanPackage
|
||||
*/
|
||||
public function testCleanPackage(): void {
|
||||
|
||||
$config = $this->getMockBuilder(Config::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$config->expects($this->once())
|
||||
->method('getPathsForPackage')
|
||||
->willReturn(['tests']);
|
||||
|
||||
$plugin = $this->getMockBuilder(VendorHardeningPlugin::class)
|
||||
->onlyMethods(['getInstallPathForPackage'])
|
||||
->getMock();
|
||||
$plugin->expects($this->once())
|
||||
->method('getInstallPathForPackage')
|
||||
->willReturn(vfsStream::url('vendor/drupal/package'));
|
||||
|
||||
$ref_config = new \ReflectionProperty($plugin, 'config');
|
||||
$ref_config->setValue($plugin, $config);
|
||||
|
||||
$io = $this->prophesize(IOInterface::class);
|
||||
$ref_io = new \ReflectionProperty($plugin, 'io');
|
||||
$ref_io->setValue($plugin, $io->reveal());
|
||||
|
||||
$this->assertFileExists(vfsStream::url('vendor/drupal/package/tests/SomeTest.php'));
|
||||
|
||||
$package = $this->prophesize(PackageInterface::class);
|
||||
$package->getName()->willReturn('drupal/package');
|
||||
|
||||
$plugin->cleanPackage($package->reveal());
|
||||
|
||||
$this->assertFileDoesNotExist(vfsStream::url('vendor/drupal/package/tests'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::cleanPathsForPackage
|
||||
*/
|
||||
public function testCleanPathsForPackage(): void {
|
||||
$plugin = $this->getMockBuilder(VendorHardeningPlugin::class)
|
||||
->onlyMethods(['getInstallPathForPackage'])
|
||||
->getMock();
|
||||
$plugin->expects($this->once())
|
||||
->method('getInstallPathForPackage')
|
||||
->willReturn(vfsStream::url('vendor/drupal/package'));
|
||||
|
||||
$io = $this->prophesize(IOInterface::class);
|
||||
$ref_io = new \ReflectionProperty($plugin, 'io');
|
||||
$ref_io->setValue($plugin, $io->reveal());
|
||||
|
||||
$this->assertFileExists(vfsStream::url('vendor/drupal/package/tests/SomeTest.php'));
|
||||
$this->assertFileExists(vfsStream::url('vendor/drupal/package/SomeFile.php'));
|
||||
|
||||
$package = $this->prophesize(PackageInterface::class);
|
||||
$package->getName()->willReturn('drupal/package');
|
||||
|
||||
$ref_clean = new \ReflectionMethod($plugin, 'cleanPathsForPackage');
|
||||
$ref_clean->invokeArgs($plugin, [$package->reveal(), ['tests', 'SomeFile.php']]);
|
||||
|
||||
$this->assertFileDoesNotExist(vfsStream::url('vendor/drupal/package/tests'));
|
||||
$this->assertFileDoesNotExist(vfsStream::url('vendor/drupal/package/SomeFile.php'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::cleanAllPackages
|
||||
*/
|
||||
public function testCleanAllPackages(): void {
|
||||
$config = $this->getMockBuilder(Config::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$config->expects($this->once())
|
||||
->method('getAllCleanupPaths')
|
||||
->willReturn(['drupal/package' => ['tests']]);
|
||||
|
||||
$package = $this->createMock(PackageInterface::class);
|
||||
$package->expects($this->any())
|
||||
->method('getName')
|
||||
->willReturn('drupal/package');
|
||||
|
||||
$plugin = $this->getMockBuilder(VendorHardeningPlugin::class)
|
||||
->onlyMethods(['getInstalledPackages', 'getInstallPathForPackage'])
|
||||
->getMock();
|
||||
$plugin->expects($this->once())
|
||||
->method('getInstalledPackages')
|
||||
->willReturn([$package]);
|
||||
$plugin->expects($this->once())
|
||||
->method('getInstallPathForPackage')
|
||||
->willReturn(vfsStream::url('vendor/drupal/package'));
|
||||
|
||||
$io = $this->prophesize(IOInterface::class);
|
||||
$ref_io = new \ReflectionProperty($plugin, 'io');
|
||||
$ref_io->setValue($plugin, $io->reveal());
|
||||
|
||||
$ref_config = new \ReflectionProperty($plugin, 'config');
|
||||
$ref_config->setValue($plugin, $config);
|
||||
|
||||
$this->assertFileExists(vfsStream::url('vendor/drupal/package/tests/SomeTest.php'));
|
||||
|
||||
$plugin->cleanAllPackages();
|
||||
|
||||
$this->assertFileDoesNotExist(vfsStream::url('vendor/drupal/package/tests'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::writeAccessRestrictionFiles
|
||||
*/
|
||||
public function testWriteAccessRestrictionFiles(): void {
|
||||
$dir = vfsStream::url('vendor');
|
||||
|
||||
// Set up mocks so that writeAccessRestrictionFiles() can eventually use
|
||||
// the IOInterface object.
|
||||
$composer = $this->getMockBuilder(Composer::class)
|
||||
->onlyMethods(['getPackage'])
|
||||
->getMock();
|
||||
$composer->expects($this->once())
|
||||
->method('getPackage')
|
||||
->willReturn($this->prophesize(RootPackageInterface::class)->reveal());
|
||||
|
||||
$plugin = new VendorHardeningPlugin();
|
||||
$plugin->activate($composer, $this->prophesize(IOInterface::class)->reveal());
|
||||
|
||||
$this->assertDirectoryExists($dir);
|
||||
|
||||
$this->assertFileDoesNotExist($dir . '/.htaccess');
|
||||
|
||||
$plugin->writeAccessRestrictionFiles($dir);
|
||||
|
||||
$this->assertFileExists($dir . '/.htaccess');
|
||||
}
|
||||
|
||||
public static function providerFindBinOverlap() {
|
||||
return [
|
||||
[
|
||||
[],
|
||||
['bin/script'],
|
||||
['tests'],
|
||||
],
|
||||
[
|
||||
['bin/composer' => 'bin/composer'],
|
||||
['bin/composer'],
|
||||
['bin', 'tests'],
|
||||
],
|
||||
[
|
||||
['bin/composer' => 'bin/composer'],
|
||||
['bin/composer'],
|
||||
['bin/composer'],
|
||||
],
|
||||
[
|
||||
[],
|
||||
['bin/composer'],
|
||||
['bin/something_else'],
|
||||
],
|
||||
[
|
||||
[],
|
||||
['test/script'],
|
||||
['test/longer'],
|
||||
],
|
||||
[
|
||||
['bin/very/long/path/script' => 'bin/very/long/path/script'],
|
||||
['bin/very/long/path/script'],
|
||||
['bin'],
|
||||
],
|
||||
[
|
||||
['bin/bin/bin' => 'bin/bin/bin'],
|
||||
['bin/bin/bin'],
|
||||
['bin/bin'],
|
||||
],
|
||||
[
|
||||
[],
|
||||
['bin/bin'],
|
||||
['bin/bin/bin'],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::findBinOverlap
|
||||
* @dataProvider providerFindBinOverlap
|
||||
*/
|
||||
public function testFindBinOverlap($expected, $binaries, $clean_paths): void {
|
||||
$plugin = $this->getMockBuilder(VendorHardeningPlugin::class)
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
|
||||
$ref_find_bin_overlap = new \ReflectionMethod($plugin, 'findBinOverlap');
|
||||
|
||||
$this->assertSame($expected, $ref_find_bin_overlap->invokeArgs($plugin, [$binaries, $clean_paths]));
|
||||
}
|
||||
|
||||
}
|
||||
17
web/core/tests/Drupal/Tests/Composer/fixtures/ensureBehatDriverVersionsFixture/composer.lock
generated
Normal file
17
web/core/tests/Drupal/Tests/Composer/fixtures/ensureBehatDriverVersionsFixture/composer.lock
generated
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"_readme": [
|
||||
"This file is a fixture used to test Drupal."
|
||||
],
|
||||
"content-hash": "da9910627bab73a256b39ceda83d7167",
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "lullabot/mink-selenium2-driver",
|
||||
"version": "dev-main",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Lullabot/MinkSelenium2Driver.git",
|
||||
"reference": "228004452354c1945fec2d273de2586da8c29213"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user