diff --git a/composer.json b/composer.json index f99913123ef4db8148e2a1f1c96f4d1b6b1f5136..569097373ef9a185c8d982f8e34718df313bc376 100644 --- a/composer.json +++ b/composer.json @@ -71,11 +71,15 @@ } }, "scripts": { - "pre-install-cmd": "Drupal\\Core\\Composer\\Composer::ensureComposerVersion", - "pre-update-cmd": "Drupal\\Core\\Composer\\Composer::ensureComposerVersion", + "pre-install-cmd": "Drupal\\Composer\\Composer::ensureComposerVersion", + "pre-update-cmd": "Drupal\\Composer\\Composer::ensureComposerVersion", "pre-autoload-dump": "Drupal\\Core\\Composer\\Composer::preAutoloadDump", "drupal-phpunit-upgrade-check": "Drupal\\Core\\Composer\\Composer::upgradePHPUnit", "drupal-phpunit-upgrade": "@composer update phpunit/phpunit symfony/phpunit-bridge phpspec/prophecy symfony/yaml --with-dependencies --no-progress", + "post-update-cmd": [ + "Drupal\\Composer\\Composer::generateMetapackages", + "Drupal\\Composer\\Composer::ensureBehatDriverVersions" + ], "phpcs": "phpcs --standard=core/phpcs.xml.dist --runtime-set installed_paths $($COMPOSER_BINARY config vendor-dir)/drupal/coder/coder_sniffer --", "phpcbf": "phpcbf --standard=core/phpcs.xml.dist --runtime-set installed_paths $($COMPOSER_BINARY config vendor-dir)/drupal/coder/coder_sniffer --" }, diff --git a/composer.lock b/composer.lock index e51f6c0bcc8e49bd5a1a9ac4c3632e09f23e7524..9b2b43dfe3195c84a7377be279ffe2a3f3677e3d 100644 --- a/composer.lock +++ b/composer.lock @@ -947,14 +947,14 @@ "authors": [ { "name": "Nicholas Humfrey", - "role": "Developer", "email": "njh@aelius.com", - "homepage": "http://www.aelius.com/njh/" + "homepage": "http://www.aelius.com/njh/", + "role": "Developer" }, { "name": "Alexey Zakhlestin", - "role": "Developer", - "email": "indeyets@gmail.com" + "email": "indeyets@gmail.com", + "role": "Developer" } ], "description": "EasyRdf is a PHP library designed to make it easy to consume and produce RDF.", @@ -4025,16 +4025,16 @@ }, { "name": "behat/mink-selenium2-driver", - "version": "dev-master", + "version": "1.3.x-dev", "source": { "type": "git", "url": "https://github.com/minkphp/MinkSelenium2Driver.git", - "reference": "8684ee4e634db7abda9039ea53545f86fc1e105a" + "reference": "0a09c4341621fca937a726827611b20ce3e2c259" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/minkphp/MinkSelenium2Driver/zipball/8684ee4e634db7abda9039ea53545f86fc1e105a", - "reference": "8684ee4e634db7abda9039ea53545f86fc1e105a", + "url": "https://api.github.com/repos/minkphp/MinkSelenium2Driver/zipball/0a09c4341621fca937a726827611b20ce3e2c259", + "reference": "0a09c4341621fca937a726827611b20ce3e2c259", "shasum": "" }, "require": { @@ -4061,15 +4061,15 @@ "MIT" ], "authors": [ - { - "name": "Konstantin Kudryashov", - "email": "ever.zet@gmail.com", - "homepage": "http://everzet.com" - }, { "name": "Pete Otaqui", "email": "pete@otaqui.com", "homepage": "https://github.com/pete-otaqui" + }, + { + "name": "Konstantin Kudryashov", + "email": "ever.zet@gmail.com", + "homepage": "http://everzet.com" } ], "description": "Selenium2 (WebDriver) driver for Mink framework", @@ -4082,7 +4082,7 @@ "testing", "webdriver" ], - "time": "2018-10-10T12:39:06+00:00" + "time": "2019-09-02T09:46:54+00:00" }, { "name": "composer/ca-bundle", @@ -4883,18 +4883,18 @@ "authors": [ { "name": "Arne Blankerts", - "role": "Developer", - "email": "arne@blankerts.de" + "email": "arne@blankerts.de", + "role": "Developer" }, { "name": "Sebastian Heuer", - "role": "Developer", - "email": "sebastian@phpeople.de" + "email": "sebastian@phpeople.de", + "role": "Developer" }, { "name": "Sebastian Bergmann", - "role": "Developer", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "Developer" } ], "description": "Library for handling version information and constraints", @@ -5253,8 +5253,8 @@ "authors": [ { "name": "Sebastian Bergmann", - "role": "lead", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], "description": "Simple template engine.", @@ -6057,8 +6057,8 @@ "authors": [ { "name": "Sebastian Bergmann", - "role": "lead", - "email": "sebastian@phpunit.de" + "email": "sebastian@phpunit.de", + "role": "lead" } ], "description": "Library that helps with managing the version number of Git-hosted PHP projects", diff --git a/composer/Composer.php b/composer/Composer.php new file mode 100644 index 0000000000000000000000000000000000000000..c3c6a39e939c65af7639f3eed28126f3b609b508 --- /dev/null +++ b/composer/Composer.php @@ -0,0 +1,81 @@ +<?php + +namespace Drupal\Composer; + +use Composer\Composer as ComposerApp; +use Composer\Script\Event; +use Composer\Semver\Comparator; +use Drupal\Composer\Generator\PackageGenerator; +use Drupal\Composer\Generator\Util\DrupalCoreComposer; + +/** + * Provides static functions for composer script events. See also + * core/lib/Drupal/Composer/Composer.php, which contains similar + * scripts needed by projects that include drupal/core. Scripts that + * are only needed by drupal/drupal go here. + * + * @see https://getcomposer.org/doc/articles/scripts.md + */ +class Composer { + + /** + * Update metapackages whenever composer.lock is updated. + * + * @param \Composer\Script\Event $event + */ + public static function generateMetapackages(Event $event) { + $generator = new PackageGenerator(); + $generator->generate($event->getIO(), getcwd()); + } + + /** + * Ensure that the minimum required version of Composer is running. + * Throw an exception if Composer is too old. + */ + public static function ensureComposerVersion() { + $composerVersion = method_exists(ComposerApp::class, 'getVersion') ? + ComposerApp::getVersion() : ComposerApp::VERSION; + if (Comparator::lessThan($composerVersion, '1.9.0')) { + throw new \RuntimeException("Drupal core development requires Composer 1.9.0, but Composer $composerVersion is installed. Please run 'composer self-update'."); + } + } + + /** + * Ensure that the right version of behat/mink-selenium2-driver is locked. + * Throw an exception if we do not have 1.3.x-dev. + * + * @todo: Remove this once https://www.drupal.org/node/3078671 is fixed. + */ + public static function ensureBehatDriverVersions() { + $drupalCoreComposer = DrupalCoreComposer::createFromPath(getcwd()); + + $expectedVersion = '1.3.x-dev'; + $behatMinkSelenium2DriverInfo = $drupalCoreComposer->packageLockInfo('behat/mink-selenium2-driver', TRUE); + if ($behatMinkSelenium2DriverInfo['version'] != $expectedVersion) { + $drupalVersion = static::drupalVersionBranch(); + $message = <<< __EOT__ +Drupal requires behat/mink-selenium2-driver:$expectedVersion in its composer.json +file, but it is pinned to {$behatMinkSelenium2DriverInfo['version']} in the composer.lock file. +This sometimes happens when Composer becomes confused. To fix: + +1. `git checkout -- composer.lock`, or otherwise reset to a known-good lock file. +2. `rm -rf vendor` +3. `composer install` +4. `COMPOSER_ROOT_VERSION={$drupalVersion} composer update ...` (where ... is + the update arguments you wish to run, e.g. --lock). +__EOT__; + throw new \RuntimeException($message); + } + } + + /** + * Return the branch name the current Drupal version is associated with. + * + * @return string + * A branch name, e.g. 8.9.x or 9.0.x. + */ + public static function drupalVersionBranch() { + return preg_replace('#\.[0-9]+-dev#', '.x-dev', \Drupal::VERSION); + } + +} diff --git a/composer/Generator/Builder/DrupalCoreRecommendedBuilder.php b/composer/Generator/Builder/DrupalCoreRecommendedBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..7964f0610b5fd8802ebddffa658a4d949de2bd02 --- /dev/null +++ b/composer/Generator/Builder/DrupalCoreRecommendedBuilder.php @@ -0,0 +1,68 @@ +<?php + +namespace Drupal\Composer\Generator\Builder; + +/** + * Builder to produce metapackage for drupal/core-recommended. + */ +class DrupalCoreRecommendedBuilder extends DrupalPackageBuilder { + + /** + * {@inheritdoc} + */ + public function getPath() { + return 'CoreRecommended'; + } + + /** + * {@inheritdoc} + */ + public function getPackage() { + + $composer = $this->initialPackageMetadata(); + + // Pull up the composer lock data. + $composerLockData = $this->drupalCoreInfo->composerLock(); + if (!isset($composerLockData['packages'])) { + return $composer; + } + + // Make a list of packages we do not want to put in the 'require' section. + $remove_list = ['drupal/core', 'wikimedia/composer-merge-plugin']; + + // Copy the 'packages' section from the Composer lock into our 'require' + // section. There is also a 'packages-dev' section, but we do not need + // to pin 'require-dev' versions, as 'require-dev' dependencies are never + // included from subprojects. Use 'drupal/core-dev-dependencies' to get + // Drupal's dev dependencies. + foreach ($composerLockData['packages'] as $package) { + // If there is no 'source' record, then this is a path repository + // or something else that we do not want to include. + if (isset($package['source']) && !in_array($package['name'], $remove_list)) { + $composer['require'][$package['name']] = $package['version']; + } + } + return $composer; + } + + /** + * Returns the initial package metadata that describes the metapackage. + * + * @return array + */ + protected function initialPackageMetadata() { + return [ + "name" => "drupal/core-recommended", + "type" => "metapackage", + "description" => "Locked core dependencies; require this project INSTEAD OF drupal/core.", + "license" => "GPL-2.0-or-later", + "conflict" => [ + "webflo/drupal-core-strict" => "*", + ], + "require" => [ + "drupal/core" => "self.version", + ], + ]; + } + +} diff --git a/composer/Generator/Builder/DrupalDevDependenciesBuilder.php b/composer/Generator/Builder/DrupalDevDependenciesBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..0b68b4a0e46fbc172a7c682084f95defb282259e --- /dev/null +++ b/composer/Generator/Builder/DrupalDevDependenciesBuilder.php @@ -0,0 +1,62 @@ +<?php + +namespace Drupal\Composer\Generator\Builder; + +/** + * Builder to produce metapackage for drupal/dev-dependencies. + */ +class DrupalDevDependenciesBuilder extends DrupalPackageBuilder { + + /** + * {@inheritdoc} + */ + public function getPath() { + return 'DevDependencies'; + } + + /** + * {@inheritdoc} + */ + public function getPackage() { + + $composer = $this->initialPackageMetadata(); + + // Put everything from Drupal's "require-dev" into our "require" section. + $composer['require'] = $this->drupalCoreInfo->getRequireDev(); + + // If the require-dev is bringing in a dev version of behat/mink, convert + // the requirement to a more flexible set of versions. + // @todo: remove when https://www.drupal.org/node/3078671 is fixed. + if (isset($composer['require']['behat/mink']) && ($composer['require']['behat/mink'] == '1.7.x-dev')) { + $composer['require']['behat/mink'] = '1.8.0 | 1.7.1.1 | 1.7.x-dev'; + } + + // Do the same sort of conversion for behat/mink-selenium2-driver. + if (isset($composer['require']['behat/mink-selenium2-driver']) && ($composer['require']['behat/mink-selenium2-driver'] == '1.3.x-dev')) { + $composer['require']['behat/mink-selenium2-driver'] = '1.4.0 | 1.3.1.1 | 1.3.x-dev'; + } + + // Sort our required packages by key. + ksort($composer['require']); + + return $composer; + } + + /** + * Returns the initial package metadata that describes the metapackage. + * + * @return array + */ + protected function initialPackageMetadata() { + return [ + "name" => "drupal/dev-dependencies", + "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", + "conflict" => [ + "webflo/drupal-core-require-dev" => "*", + ], + ]; + } + +} diff --git a/composer/Generator/Builder/DrupalPackageBuilder.php b/composer/Generator/Builder/DrupalPackageBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..6c0872164794be98781e9501d5b478e0b4559a5a --- /dev/null +++ b/composer/Generator/Builder/DrupalPackageBuilder.php @@ -0,0 +1,30 @@ +<?php + +namespace Drupal\Composer\Generator\Builder; + +use Drupal\Composer\Generator\BuilderInterface; +use Drupal\Composer\Generator\Util\DrupalCoreComposer; + +/** + * Base class that includes helpful utility routine for Drupal builder classes. + */ +abstract class DrupalPackageBuilder implements BuilderInterface { + + /** + * Information about composer.json, composer.lock etc. in current release. + * + * @var \Drupal\Composer\Generator\Util\DrupalCoreComposer + */ + protected $drupalCoreInfo; + + /** + * DrupalPackageBuilder constructor. + * + * @param \Drupal\Composer\Generator\Util\DrupalCoreComposer $drupalCoreInfo + * Information about composer.json and composer.lock from current release. + */ + public function __construct(DrupalCoreComposer $drupalCoreInfo) { + $this->drupalCoreInfo = $drupalCoreInfo; + } + +} diff --git a/composer/Generator/Builder/DrupalPinnedDevDependenciesBuilder.php b/composer/Generator/Builder/DrupalPinnedDevDependenciesBuilder.php new file mode 100644 index 0000000000000000000000000000000000000000..4a4abb3c1cc880828d369a47a66e6375f74611c0 --- /dev/null +++ b/composer/Generator/Builder/DrupalPinnedDevDependenciesBuilder.php @@ -0,0 +1,69 @@ +<?php + +namespace Drupal\Composer\Generator\Builder; + +/** + * Builder to produce metapackage for drupal/pinned-dev-dependencies. + */ +class DrupalPinnedDevDependenciesBuilder extends DrupalPackageBuilder { + + /** + * {@inheritdoc} + */ + public function getPath() { + return 'PinnedDevDependencies'; + } + + /** + * {@inheritdoc} + */ + public function getPackage() { + + $composer = $this->initialPackageMetadata(); + + // Pull the exact versions of the dependencies from the composer.lock + // file and use it to build our 'require' section. + $composerLockData = $this->drupalCoreInfo->composerLock(); + + if (isset($composerLockData['packages-dev'])) { + + foreach ($composerLockData['packages-dev'] as $package) { + $composer['require'][$package['name']] = $package['version']; + + // If the require-dev is bringing in a dev version of behat/mink, + // convert the requirement to a more flexible set of versions. + // @todo: remove when https://www.drupal.org/node/3078671 is fixed. + if (($package['name'] == 'behat/mink') && (($package['version'] == 'dev-master') || ($package['version'] == '1.7.x-dev'))) { + $composer['require']['behat/mink'] = '1.8.0 | 1.7.1.1 | 1.7.x-dev'; + } + + // Do the same sort of conversion for behat/mink-selenium2-driver. + if (($package['name'] == 'behat/mink-selenium2-driver') && (($package['version'] == 'dev-master') || ($package['version'] == '1.3.x-dev'))) { + $composer['require']['behat/mink-selenium2-driver'] = '1.4.0 | 1.3.1.1 | 1.3.x-dev'; + } + } + } + return $composer; + } + + /** + * Returns the initial package metadata that describes the metapackage. + * + * @return array + */ + protected function initialPackageMetadata() { + return [ + "name" => "drupal/pinned-dev-dependencies", + "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", + "conflict" => [ + "webflo/drupal-core-require-dev" => "*", + ], + "require" => [ + "drupal/core" => "self.version", + ], + ]; + } + +} diff --git a/composer/Generator/BuilderInterface.php b/composer/Generator/BuilderInterface.php new file mode 100644 index 0000000000000000000000000000000000000000..de4ddf8cc00ba3983a0fb20af10c68697921b317 --- /dev/null +++ b/composer/Generator/BuilderInterface.php @@ -0,0 +1,44 @@ +<?php + +namespace Drupal\Composer\Generator; + +use Drupal\Composer\Generator\Util\DrupalCoreComposer; + +/** + * Produce the output for a metapackage. + * + * BuilderInterface provides an interface for builder classes which are + * called by the PackageGenerator in order to produce a derived metapackage from + * the provided source package. + * + * See the README.txt file in composer/Metapackage for a description of what + * a metapackage is, and an explanation of the metapackages produced by the + * generator. + */ +interface BuilderInterface { + + /** + * BuilderInterface constructor. + * + * @param \Drupal\Composer\Generator\Util\DrupalCoreComposer $drupalCoreInfo + * Information about the composer.json, composer.lock, and repository path. + */ + public function __construct(DrupalCoreComposer $drupalCoreInfo); + + /** + * Return the path to where the metapackage should be written. + * + * @return string + * Path to the metapackage. + */ + public function getPath(); + + /** + * Generate the Composer.json data for the current tag or branch. + * + * @return array + * Composer json data. + */ + public function getPackage(); + +} diff --git a/composer/Generator/PackageGenerator.php b/composer/Generator/PackageGenerator.php new file mode 100644 index 0000000000000000000000000000000000000000..1dacb05654a68ee21d8cf7b888b68390b78514bd --- /dev/null +++ b/composer/Generator/PackageGenerator.php @@ -0,0 +1,127 @@ +<?php + +namespace Drupal\Composer\Generator; + +use Drupal\Composer\Generator\Builder\DrupalCoreRecommendedBuilder; +use Drupal\Composer\Generator\Builder\DrupalDevDependenciesBuilder; +use Drupal\Composer\Generator\Builder\DrupalPinnedDevDependenciesBuilder; +use Drupal\Composer\Generator\Util\DrupalCoreComposer; +use Composer\Util\Filesystem; +use Composer\IO\IOInterface; + +/** + * Generates metapackages. + */ +class PackageGenerator { + + /** + * Base directory where generated projects are written. + * + * @var string + */ + protected $generatedProjectBaseDir; + + /** + * PackageGenerator constructor. + */ + public function __construct() { + $this->generatedProjectBaseDir = dirname(__DIR__) . '/Metapackage'; + } + + /** + * Generate Drupal's metapackages whenever composer.lock is updated + * + * @param \Composer\IO\IOInterface $io + * Composer IO object for interacting with the user. + * @param string $base_dir + * Directory where drupal/drupal repository is located. + */ + public function generate(IOInterface $io, $base_dir) { + // General information from drupal/drupal and drupal/core composer.json + // and composer.lock files. + $drupalCoreInfo = DrupalCoreComposer::createFromPath($base_dir); + + // Exit early if there is no composer.lock file. + if (empty($drupalCoreInfo->composerLock())) { + return; + } + + // Run all of our available builders. + $builders = $this->builders(); + $changed = FALSE; + foreach ($builders as $builder_class) { + $builder = new $builder_class($drupalCoreInfo); + $changed |= $this->generateMetapackage($io, $builder); + } + + // Remind the user not to miss files in a patch. + if ($changed) { + $io->write("If you make a patch, ensure that the files above are included."); + } + } + + /** + * Returns a list of metapackage builders. + * + * @return BuilderInterface[] + */ + protected function builders() { + return [ + DrupalCoreRecommendedBuilder::class, + DrupalDevDependenciesBuilder::class, + DrupalPinnedDevDependenciesBuilder::class, + ]; + } + + /** + * Generate one metapackage. + * + * @param \Composer\IO\IOInterface $io + * Composer IO object for interacting with the user. + * @param BuilderInterface $builder + * An object that can build a metapackage. + * + * @return bool + * TRUE if the generated metapackage is different than what is on disk. + */ + protected function generateMetapackage(IOInterface $io, BuilderInterface $builder) { + + // Load the existing composer.json file for drupal/core-recommended + $relative_path = $builder->getPath() . '/composer.json'; + $composer_json_path = $this->generatedProjectBaseDir . '/' . $relative_path; + $original_composer_json = file_exists($composer_json_path) ? file_get_contents($composer_json_path) : ''; + + // Get the composer.json file from the builder. + $composer_json_data = $builder->getPackage(); + $updated_composer_json = static::encode($composer_json_data); + + // Exit early if nothing changed. + if (trim($original_composer_json, " \t\r\0\x0B") == trim($updated_composer_json, " \t\r\0\x0B")) { + return FALSE; + } + + // Warn the user that a metapackage file has been updated.. + $io->write("Updated metapackage file <info>composer/Metapackage/$relative_path</info>."); + + // Write the composer.json file back to disk + $fs = new Filesystem(); + $fs->ensureDirectoryExists(dirname($composer_json_path)); + file_put_contents($composer_json_path, $updated_composer_json); + + return TRUE; + } + + /** + * Utility function to encode metapackage json in a consistent way. + * + * @param array $composer_json_data + * Data to encode into a json string. + * + * @return string + * Encoded version of provided json data. + */ + public static function encode($composer_json_data) { + return json_encode($composer_json_data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n"; + } + +} diff --git a/composer/Generator/TESTING.txt b/composer/Generator/TESTING.txt new file mode 100644 index 0000000000000000000000000000000000000000..59ccd78314a6610e8337816262fbe5da7d08154b --- /dev/null +++ b/composer/Generator/TESTING.txt @@ -0,0 +1,18 @@ +HOW-TO: Test this Drupal composer script + +In order to test this script, you'll need to get the entire Drupal repo and +run the tests there. + +You'll find the tests under core/tests/Drupal/Tests/Composer/Generator. + +You can get the full Drupal repo here: +https://www.drupal.org/project/drupal/git-instructions + +You can find more information about running PHPUnit tests with Drupal here: +https://www.drupal.org/node/2116263 + +Each component in the Drupal\Composer\Plugin namespace has its own annotated test +group. You can use this group to run only the tests for this component. Like +this: + +$ ./vendor/bin/phpunit -c core --group Metapackage diff --git a/composer/Generator/Util/DrupalCoreComposer.php b/composer/Generator/Util/DrupalCoreComposer.php new file mode 100644 index 0000000000000000000000000000000000000000..f33e759e20ce0afd105b9977cb4b0b5bfa89328d --- /dev/null +++ b/composer/Generator/Util/DrupalCoreComposer.php @@ -0,0 +1,123 @@ +<?php + +namespace Drupal\Composer\Generator\Util; + +/** + * Utilities for accessing composer.json data from drupal/drupal and drupal/core. + * + * Some data is stored in the root composer.json file, while others is found + * in the core/composer.json file. + */ +class DrupalCoreComposer { + + /** + * Cached composer.json data. + * + * @var array + */ + protected $composerJson = []; + + /** + * Cached composer.lock data. + * + * @var array + */ + protected $composerLock = []; + + /** + * DrupalCoreComposer constructor. + * + * @param array $composerJson + * The composer.json data. + * @param array $composerLock + * The composer.lock data. + */ + public function __construct(array $composerJson, array $composerLock) { + $this->composerJson = $composerJson; + $this->composerLock = $composerLock; + } + + /** + * DrupalCoreComposer factory. + * + * @param string $repositoryPath + * Path to a directory containing a composer.json and composer.lock files. + * + * @return static + * New DrupalCoreComposer object containing composer.json and lock data. + */ + public static function createFromPath(string $repositoryPath) { + $composerJson = static::loadJsonFromPath("$repositoryPath/composer.json"); + $composerLock = static::loadJsonFromPath("$repositoryPath/composer.lock"); + return new self($composerJson, $composerLock); + } + + /** + * Fetch the composer data from the root drupal/drupal project. + * + * @return array + * Composer json data + */ + public function rootComposerJson() { + return $this->composerJson; + } + + /** + * Fetch the composer lock data. + * + * @return array + * Composer lock data + */ + public function composerLock() { + return $this->composerLock; + } + + /** + * Return the "require-dev" section from root or core composer.json file. + * + * The require-dev constraints moved from core/composer.json (8.7.x and + * earlier) to the root composer.json file (8.8.x and later). + * + * @return array + * The contents of the "require-dev" section. + */ + public function getRequireDev() { + $composerJsonData = $this->rootComposerJson(); + return isset($composerJsonData['require-dev']) ? $composerJsonData['require-dev'] : []; + } + + /** + * Look up the info for one package in the composer.lock file. + * + * @param string $packageName + * Name of package to find, e.g. 'behat/mink-selenium2-driver'. + * @param bool $dev + * TRUE: consider only 'packages-dev'. Default: consider only 'packages' + * + * @return array + * Package info from composer.lock. + */ + public function packageLockInfo($packageName, $dev = FALSE) { + $packagesSection = $dev ? 'packages-dev' : 'packages'; + foreach ($this->composerLock[$packagesSection] as $info) { + if ($info['name'] == $packageName) { + return $info; + } + } + return []; + } + + /** + * Load json data from the specified path. + * + * @param string $path + * Relative path to the json file to load. + * + * @return array + * The contents of the json data for the specified file. + */ + protected static function loadJsonFromPath($path) { + return file_exists($path) ? json_decode(file_get_contents($path), TRUE) : []; + } + +} diff --git a/composer/Metapackage/CoreRecommended/composer.json b/composer/Metapackage/CoreRecommended/composer.json new file mode 100644 index 0000000000000000000000000000000000000000..c42c8708a846d78a8c4b59b93eaba4bf94fcc032 --- /dev/null +++ b/composer/Metapackage/CoreRecommended/composer.json @@ -0,0 +1,69 @@ +{ + "name": "drupal/core-recommended", + "type": "metapackage", + "description": "Locked core dependencies; require this project INSTEAD OF drupal/core.", + "license": "GPL-2.0-or-later", + "conflict": { + "webflo/drupal-core-strict": "*" + }, + "require": { + "drupal/core": "self.version", + "asm89/stack-cors": "1.2.0", + "composer/installers": "v1.7.0", + "composer/semver": "1.5.0", + "doctrine/annotations": "v1.4.0", + "doctrine/cache": "v1.6.2", + "doctrine/collections": "v1.4.0", + "doctrine/common": "v2.7.3", + "doctrine/inflector": "v1.2.0", + "doctrine/lexer": "1.0.2", + "easyrdf/easyrdf": "0.9.1", + "egulias/email-validator": "2.1.11", + "guzzlehttp/guzzle": "6.3.3", + "guzzlehttp/promises": "v1.3.1", + "guzzlehttp/psr7": "1.6.1", + "masterminds/html5": "2.7.0", + "pear/archive_tar": "1.4.8", + "pear/console_getopt": "v1.4.2", + "pear/pear-core-minimal": "v1.10.9", + "pear/pear_exception": "v1.0.0", + "psr/container": "1.0.0", + "psr/http-message": "1.0.1", + "psr/log": "1.1.0", + "ralouphie/getallheaders": "3.0.3", + "stack/builder": "v1.0.5", + "symfony-cmf/routing": "2.1.0", + "symfony/class-loader": "v3.4.32", + "symfony/console": "4.4.x-dev", + "symfony/debug": "4.4.x-dev", + "symfony/dependency-injection": "4.4.x-dev", + "symfony/error-handler": "dev-master", + "symfony/error-renderer": "4.4.x-dev", + "symfony/event-dispatcher": "4.4.x-dev", + "symfony/event-dispatcher-contracts": "v1.1.7", + "symfony/http-foundation": "4.4.x-dev", + "symfony/http-kernel": "4.4.x-dev", + "symfony/mime": "v4.3.5", + "symfony/polyfill-ctype": "v1.12.0", + "symfony/polyfill-iconv": "v1.12.0", + "symfony/polyfill-intl-idn": "v1.12.0", + "symfony/polyfill-mbstring": "v1.12.0", + "symfony/polyfill-php72": "v1.12.0", + "symfony/polyfill-php73": "v1.12.0", + "symfony/process": "4.4.x-dev", + "symfony/psr-http-message-bridge": "v1.2.0", + "symfony/routing": "4.4.x-dev", + "symfony/serializer": "4.4.x-dev", + "symfony/service-contracts": "v1.1.7", + "symfony/translation": "4.4.x-dev", + "symfony/translation-contracts": "v1.1.7", + "symfony/validator": "4.4.x-dev", + "symfony/yaml": "4.4.x-dev", + "twig/twig": "v1.42.3", + "typo3/phar-stream-wrapper": "v3.1.3", + "zendframework/zend-diactoros": "1.8.7", + "zendframework/zend-escaper": "2.6.1", + "zendframework/zend-feed": "2.12.0", + "zendframework/zend-stdlib": "3.2.1" + } +} diff --git a/composer/Metapackage/DevDependencies/composer.json b/composer/Metapackage/DevDependencies/composer.json new file mode 100644 index 0000000000000000000000000000000000000000..586a4e830924d831b52c7f275f6e642d41ab4be7 --- /dev/null +++ b/composer/Metapackage/DevDependencies/composer.json @@ -0,0 +1,30 @@ +{ + "name": "drupal/dev-dependencies", + "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", + "conflict": { + "webflo/drupal-core-require-dev": "*" + }, + "require": { + "behat/mink": "1.8.0 | 1.7.1.1 | 1.7.x-dev", + "behat/mink-goutte-driver": "^1.2", + "behat/mink-selenium2-driver": "1.4.0 | 1.3.1.1 | 1.3.x-dev", + "composer/composer": "^1.8", + "drupal/coder": "^8.3.2", + "jcalderonzumba/gastonjs": "^1.0.2", + "jcalderonzumba/mink-phantomjs-driver": "^0.3.1", + "justinrainbow/json-schema": "^5.2", + "mikey179/vfsstream": "^1.2", + "phpspec/prophecy": "^1.7", + "phpunit/phpunit": "^6.5 || ^7", + "symfony/browser-kit": "^4.4", + "symfony/css-selector": "^4.4", + "symfony/debug": "^4.4", + "symfony/dom-crawler": "^4.4", + "symfony/filesystem": "^4.4", + "symfony/finder": "^4.4", + "symfony/lock": "^4.4", + "symfony/phpunit-bridge": "^4.4" + } +} diff --git a/composer/Metapackage/PinnedDevDependencies/composer.json b/composer/Metapackage/PinnedDevDependencies/composer.json new file mode 100644 index 0000000000000000000000000000000000000000..fb040b49f4a215f8f64edb4ff766dd6472e3856d --- /dev/null +++ b/composer/Metapackage/PinnedDevDependencies/composer.json @@ -0,0 +1,65 @@ +{ + "name": "drupal/pinned-dev-dependencies", + "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", + "conflict": { + "webflo/drupal-core-require-dev": "*" + }, + "require": { + "drupal/core": "self.version", + "behat/mink": "1.8.0 | 1.7.1.1 | 1.7.x-dev", + "behat/mink-browserkit-driver": "1.3.3", + "behat/mink-goutte-driver": "v1.2.1", + "behat/mink-selenium2-driver": "1.4.0 | 1.3.1.1 | 1.3.x-dev", + "composer/ca-bundle": "1.2.4", + "composer/composer": "1.9.0", + "composer/spdx-licenses": "1.5.2", + "composer/xdebug-handler": "1.3.3", + "doctrine/instantiator": "1.0.5", + "drupal/coder": "8.3.6", + "fabpot/goutte": "v3.2.3", + "instaclick/php-webdriver": "1.4.6", + "jcalderonzumba/gastonjs": "v1.0.2", + "jcalderonzumba/mink-phantomjs-driver": "v0.3.2", + "justinrainbow/json-schema": "5.2.8", + "mikey179/vfsstream": "v1.6.7", + "myclabs/deep-copy": "1.7.0", + "phar-io/manifest": "1.0.1", + "phar-io/version": "1.0.1", + "phpdocumentor/reflection-common": "1.0.1", + "phpdocumentor/reflection-docblock": "4.3.2", + "phpdocumentor/type-resolver": "0.5.1", + "phpspec/prophecy": "1.9.0", + "phpunit/php-code-coverage": "5.3.2", + "phpunit/php-file-iterator": "1.4.5", + "phpunit/php-text-template": "1.2.1", + "phpunit/php-timer": "1.0.9", + "phpunit/php-token-stream": "2.0.2", + "phpunit/phpunit": "6.5.14", + "phpunit/phpunit-mock-objects": "5.0.10", + "sebastian/code-unit-reverse-lookup": "1.0.1", + "sebastian/comparator": "2.1.3", + "sebastian/diff": "2.0.1", + "sebastian/environment": "3.1.0", + "sebastian/exporter": "3.1.2", + "sebastian/global-state": "2.0.0", + "sebastian/object-enumerator": "3.0.3", + "sebastian/object-reflector": "1.1.1", + "sebastian/recursion-context": "3.0.0", + "sebastian/resource-operations": "1.0.0", + "sebastian/version": "2.0.1", + "seld/jsonlint": "1.7.1", + "seld/phar-utils": "1.0.1", + "squizlabs/php_codesniffer": "3.5.0", + "symfony/browser-kit": "4.4.x-dev", + "symfony/css-selector": "4.4.x-dev", + "symfony/dom-crawler": "4.4.x-dev", + "symfony/filesystem": "4.4.x-dev", + "symfony/finder": "4.4.x-dev", + "symfony/lock": "4.4.x-dev", + "symfony/phpunit-bridge": "4.4.x-dev", + "theseer/tokenizer": "1.1.3", + "webmozart/assert": "1.5.0" + } +} diff --git a/composer/Metapackage/README.txt b/composer/Metapackage/README.txt new file mode 100644 index 0000000000000000000000000000000000000000..440e89e0a97be23c9ca7d5e5d223588e3eab7524 --- /dev/null +++ b/composer/Metapackage/README.txt @@ -0,0 +1,66 @@ +# Drupal Metapackages + +A metapackage is a Composer package that contains only a composer.json, and +has no other content. In other words, the purpose of a metapackage is to +provide dependencies, not to provide code or data. + + +## Metapackages Provided by Drupal Core + +Drupal Core provides three metapackages that serve different purposes. + + - drupal/core-recommended: This project pins to the exact version of each + dependency used in drupal/core. It also requires drupal/core, so + drupal/core-recommended should be used INSTEAD OF drupal/core. See usage + diagram below. This relationship makes it easier for Composer to update + a Drupal project. + + - drupal/dev-dependencies: This project provides the same version constraints + as Drupal uses for testing. It is useful for projects that either wish to + run some of the Drupal tests directly, or for projects that may wish to use + the same components that Drupal does for testing. + + - drupal/pinned-dev-dependencies: This project should be used INSTEAD OF + drupal/dev-dependencies in instances where a project wishes to pin to the + exact version of each testing dependency used in Drupal. This in general + should not be necessary. + +Note that a project that uses both drupal/core-recommended and +drupal/pinned-dev-dependencies must update them both at the same time, e.g.: + + composer update drupal/core-recommended drupal/pinned-dev-dependencies --with-updates + +Composer may have trouble with the update if one of these projects is listed +on the command line without the other. Running composer update without any +parameters should also work, because in this instance every dependency is +updated. + + +## Metapackage Usage in Template Projects + +The relationship between the metapackages drupal/core-recommended and +drupal/dev-dependencies and the project (subtree split) drupal/core, as +used in the drupal/recommended-project is shown below: + ++----------------------------+ +| drupal/recommended-project | ++----------------------------+ + | + +--"require": + | | + | | +-------------------------+ +-------------+ + | +-->| drupal/core-recommended |-->| drupal/core | + | +-------------------------+ +-------------+ + | + +--"require-dev": + | + | +-------------------------+ + +-->| drupal/dev-dependencies | + +-------------------------+ + +If a user does not wish to pin their Drupal project's dependencies to the same +versions used in drupal/core, then they should replace drupal/core-recommended +with drupal/core in their "require" section. + +If a user does not need the testing dependencies in their Drupal project, then +they may simply remove drupal/dev-dependencies from the "require-dev" section. diff --git a/core/lib/Drupal/Core/Composer/Composer.php b/core/lib/Drupal/Core/Composer/Composer.php index 627972c21c991f0d2d04ff9d854e2e7cda983e24..453a2485f6f3b9de591e7b70a2b81331377fb9a0 100644 --- a/core/lib/Drupal/Core/Composer/Composer.php +++ b/core/lib/Drupal/Core/Composer/Composer.php @@ -2,10 +2,8 @@ namespace Drupal\Core\Composer; -use Composer\Composer as ComposerApp; use Composer\Installer\PackageEvent; use Composer\Script\Event; -use Composer\Semver\Comparator; use Composer\Semver\Constraint\Constraint; use Composer\Util\ProcessExecutor; use Drupal\Component\FileSecurity\FileSecurity; @@ -96,20 +94,10 @@ class Composer { 'zendframework/zend-stdlib' => ['doc'], ]; - /** - * Ensure that the minimum required version of Composer is running. - * Throw an exception if Composer is too old. - */ - public static function ensureComposerVersion() { - $composerVersion = method_exists(ComposerApp::class, 'getVersion') ? - ComposerApp::getVersion() : ComposerApp::VERSION; - if (Comparator::lessThan($composerVersion, '1.9.0')) { - throw new \RuntimeException("Drupal core development requires Composer 1.9.0, but Composer $composerVersion is installed. Please run 'composer self-update'."); - } - } - /** * Add vendor classes to Composer's static classmap. + * + * @param \Composer\Script\Event $event */ public static function preAutoloadDump(Event $event) { // Get the configured vendor directory. diff --git a/core/tests/Drupal/Tests/Composer/ComposerTest.php b/core/tests/Drupal/Tests/Composer/ComposerTest.php new file mode 100644 index 0000000000000000000000000000000000000000..7728187888e3976163bb14a90aec216d08382e72 --- /dev/null +++ b/core/tests/Drupal/Tests/Composer/ComposerTest.php @@ -0,0 +1,47 @@ +<?php + +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() { + try { + $this->assertNull(Composer::ensureComposerVersion()); + } + catch (\RuntimeException $e) { + $this->assertRegExp('/Drupal core development requires Composer 1.9.0, but Composer /', $e->getMessage()); + } + } + + /** + * Verify that Composer::ensureBehatDriverVersions() detects a good version. + * + * @covers::ensureBehatDriverVersions + */ + public function testEnsureBehatDriverVersions() { + // First call 'ensureBehatDriverVersions' test directly using Drupal's + // composer.lock. It should not fail. + chdir($this->root); + $this->assertNull(Composer::ensureBehatDriverVersions()); + + // Next, call 'ensureBehatDriverVersions' again, this time using a fixture + // with a known-bad version number. + $this->expectException(\RuntimeException::class); + $this->expectExceptionMessageRegExp('#^Drupal requires behat/mink-selenium2-driver:1.3.x-dev#'); + chdir(__DIR__ . '/fixtures/ensureBehatDriverVersionsFixture'); + $this->assertNull(Composer::ensureBehatDriverVersions()); + } + +} diff --git a/core/tests/Drupal/Tests/Composer/Generator/BuilderTest.php b/core/tests/Drupal/Tests/Composer/Generator/BuilderTest.php new file mode 100644 index 0000000000000000000000000000000000000000..385b6a996f4e1085edbd985b6e14612fa043912b --- /dev/null +++ b/core/tests/Drupal/Tests/Composer/Generator/BuilderTest.php @@ -0,0 +1,98 @@ +<?php + +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; + +/** + * Test DrupalCoreRecommendedBuilder + * + * @group Metapackage + */ +class BuilderTest extends TestCase { + + /** + * Test data for testBuilder + */ + public function builderTestData() { + return [ + [ + DrupalCoreRecommendedBuilder::class, + [ + 'name' => 'drupal/core-recommended', + 'type' => 'metapackage', + 'description' => 'Locked core dependencies; require this project INSTEAD OF drupal/core.', + 'license' => 'GPL-2.0-or-later', + 'require' => + [ + 'drupal/core' => 'self.version', + 'symfony/polyfill-ctype' => 'v1.12.0', + 'symfony/yaml' => 'v3.4.32', + ], + 'conflict' => + [ + 'webflo/drupal-core-strict' => '*', + ], + ], + ], + + [ + DrupalDevDependenciesBuilder::class, + [ + 'name' => 'drupal/dev-dependencies', + '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.0 | 1.7.1.1 | 1.7.x-dev', + ], + 'conflict' => + [ + 'webflo/drupal-core-require-dev' => '*', + ], + ], + ], + + [ + DrupalPinnedDevDependenciesBuilder::class, + [ + 'name' => 'drupal/pinned-dev-dependencies', + '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' => 'self.version', + 'behat/mink' => '1.8.0 | 1.7.1.1 | 1.7.x-dev', + 'symfony/css-selector' => 'v4.3.5', + ], + 'conflict' => + [ + 'webflo/drupal-core-require-dev' => '*', + ], + ], + ], + + ]; + } + + /** + * Test all of the various kinds of builders. + * + * @dataProvider builderTestData + */ + public function testBuilder($builderClass, $expected) { + $fixtures = new Fixtures(); + $drupalCoreInfo = $fixtures->drupalCoreComposerFixture(); + + $builder = new $builderClass($drupalCoreInfo); + $generatedJson = $builder->getPackage(); + + $this->assertEquals($expected, $generatedJson); + } + +} diff --git a/core/tests/Drupal/Tests/Composer/Generator/Fixtures.php b/core/tests/Drupal/Tests/Composer/Generator/Fixtures.php new file mode 100644 index 0000000000000000000000000000000000000000..eccac2c12b30ba4bf3583aa12b1b90083f4003ac --- /dev/null +++ b/core/tests/Drupal/Tests/Composer/Generator/Fixtures.php @@ -0,0 +1,109 @@ +<?php + +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() { + return [ + 'name' => 'drupal/project-fixture', + 'description' => 'A fixture for testing the metapackage generator.', + 'type' => 'project', + 'license' => 'GPL-2.0-or-later', + 'require' => + [ + 'php' => '>=7.0.8', + 'symfony/yaml' => '~3.4.5', + ], + 'require-dev' => + [ + 'behat/mink' => '1.7.x-dev', + ], + ]; + } + + /** + * Data for a composer.lock fixture. + * + * @return array + * composer.lock fixture data. + */ + protected function composerLock() { + 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' => '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' => 'dev-master', + 'source' => + [ + 'type' => 'git', + 'url' => 'https://github.com/minkphp/Mink.git', + 'reference' => 'a534fe7dac9525e8e10ca68e737c3d7e5058ec83', + ], + ], + [ + 'name' => 'symfony/css-selector', + 'version' => 'v4.3.5', + 'source' => + [ + 'type' => 'git', + 'url' => 'https://github.com/symfony/css-selector.git', + 'reference' => 'f4b3ff6a549d9ed28b2b0ecd1781bf67cf220ee9', + ], + ], + ], + ]; + } + +} diff --git a/core/tests/Drupal/Tests/Composer/Generator/MetapackageUpdateTest.php b/core/tests/Drupal/Tests/Composer/Generator/MetapackageUpdateTest.php new file mode 100644 index 0000000000000000000000000000000000000000..aee83f0c682b123f89594ecbe3ff0747259a8310 --- /dev/null +++ b/core/tests/Drupal/Tests/Composer/Generator/MetapackageUpdateTest.php @@ -0,0 +1,85 @@ +<?php + +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 { + + /** + * Test data for testUpdated + */ + public function updatedTestData() { + return [ + [ + DrupalCoreRecommendedBuilder::class, + 'composer/Metapackage/CoreRecommended', + ], + [ + DrupalDevDependenciesBuilder::class, + 'composer/Metapackage/DevDependencies', + ], + [ + DrupalPinnedDevDependenciesBuilder::class, + 'composer/Metapackage/PinnedDevDependencies', + ], + ]; + } + + /** + * Test 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) { + // Create a DrupalCoreComposer for the System Under Test (current repo) + $repositoryRoot = dirname(dirname(dirname(dirname(dirname(dirname(__DIR__)))))); + $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); + } + +} diff --git a/core/tests/Drupal/Tests/Composer/fixtures/ensureBehatDriverVersionsFixture/composer.lock b/core/tests/Drupal/Tests/Composer/fixtures/ensureBehatDriverVersionsFixture/composer.lock new file mode 100644 index 0000000000000000000000000000000000000000..bcf6d8a30393f78dd416a27bec590b48b5c4f29d --- /dev/null +++ b/core/tests/Drupal/Tests/Composer/fixtures/ensureBehatDriverVersionsFixture/composer.lock @@ -0,0 +1,17 @@ +{ + "_readme": [ + "This file is a fixture used to test Drupal." + ], + "content-hash": "da9910627bab73a256b39ceda83d7167", + "packages-dev": [ + { + "name": "behat/mink-selenium2-driver", + "version": "dev-master", + "source": { + "type": "git", + "url": "https://github.com/minkphp/MinkSelenium2Driver.git", + "reference": "0a09c4341621fca937a726827611b20ce3e2c259" + } + } + ] +} diff --git a/core/tests/Drupal/Tests/Core/Composer/ComposerTest.php b/core/tests/Drupal/Tests/Core/Composer/ComposerTest.php deleted file mode 100644 index 906b45d4e525957be9653ca6b8ddbf0cd378f282..0000000000000000000000000000000000000000 --- a/core/tests/Drupal/Tests/Core/Composer/ComposerTest.php +++ /dev/null @@ -1,28 +0,0 @@ -<?php - -namespace Drupal\Tests\Core\Composer; - -use Drupal\Core\Composer\Composer; -use Drupal\Tests\UnitTestCase; - -/** - * @coversDefaultClass \Drupal\Core\Composer\Composer - * @group Composer - */ -class ComposerTest extends UnitTestCase { - - /** - * Verify that Composer::ensureComposerVersion() doesn't break. - * - * @covers::ensureComposerVersion - */ - public function testEnsureComposerVersion() { - try { - $this->assertNull(Composer::ensureComposerVersion()); - } - catch (\RuntimeException $e) { - $this->assertRegExp('/Drupal core development requires Composer 1.9.0, but Composer /', $e->getMessage()); - } - } - -}