Issue #3087626 by greg.1.anderson, Mixologic, jibran, Mile23, alexpott, xjm: Convert drupal/core-recommended & c. into a subtree split

merge-requests/64/head
Alex Pott 2019-10-25 10:05:29 +01:00
parent d5fc5da747
commit 55580b707d
No known key found for this signature in database
GPG Key ID: 31905460D4A69276
22 changed files with 1232 additions and 68 deletions

View File

@ -70,11 +70,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 --"
},

48
composer.lock generated
View File

@ -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.",
@ -3563,16 +3563,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": {
@ -3599,15 +3599,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",
@ -3620,7 +3620,7 @@
"testing",
"webdriver"
],
"time": "2018-10-10T12:39:06+00:00"
"time": "2019-09-02T09:46:54+00:00"
},
{
"name": "composer/ca-bundle",
@ -4421,18 +4421,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",
@ -4791,8 +4791,8 @@
"authors": [
{
"name": "Sebastian Bergmann",
"role": "lead",
"email": "sebastian@phpunit.de"
"email": "sebastian@phpunit.de",
"role": "lead"
}
],
"description": "Simple template engine.",
@ -5595,8 +5595,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",

81
composer/Composer.php Normal file
View File

@ -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);
}
}

View File

@ -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",
],
];
}
}

View File

@ -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" => "*",
],
];
}
}

View File

@ -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;
}
}

View File

@ -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",
],
];
}
}

View File

@ -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();
}

View File

@ -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";
}
}

View File

@ -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

View File

@ -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) : [];
}
}

View File

@ -0,0 +1,62 @@
{
"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.3.0",
"paragonie/random_compat": "v9.99.99",
"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": "1.4.1",
"symfony/class-loader": "v3.4.32",
"symfony/console": "v3.4.32",
"symfony/debug": "v3.4.32",
"symfony/dependency-injection": "v3.4.32",
"symfony/event-dispatcher": "v3.4.32",
"symfony/http-foundation": "v3.4.32",
"symfony/http-kernel": "v3.4.32",
"symfony/polyfill-ctype": "v1.12.0",
"symfony/polyfill-iconv": "v1.12.0",
"symfony/polyfill-mbstring": "v1.12.0",
"symfony/polyfill-php70": "v1.12.0",
"symfony/process": "v3.4.32",
"symfony/psr-http-message-bridge": "v1.1.2",
"symfony/routing": "v3.4.32",
"symfony/serializer": "v3.4.32",
"symfony/translation": "v3.4.32",
"symfony/validator": "v3.4.32",
"symfony/yaml": "v3.4.32",
"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"
}
}

View File

@ -0,0 +1,29 @@
{
"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": "^3.4.0",
"symfony/css-selector": "^3.4.0",
"symfony/debug": "^3.4.0",
"symfony/filesystem": "~3.4.0",
"symfony/finder": "~3.4.0",
"symfony/lock": "~3.4.0",
"symfony/phpunit-bridge": "^3.4.3"
}
}

View File

@ -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": "v3.4.32",
"symfony/css-selector": "v3.4.32",
"symfony/dom-crawler": "v3.4.32",
"symfony/filesystem": "v3.4.32",
"symfony/finder": "v3.4.32",
"symfony/lock": "v3.4.32",
"symfony/phpunit-bridge": "v3.4.32",
"theseer/tokenizer": "1.1.3",
"webmozart/assert": "1.5.0"
}
}

View File

@ -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.

View File

@ -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.

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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',
],
],
],
];
}
}

View File

@ -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);
}
}

View File

@ -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"
}
}
]
}

View File

@ -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());
}
}
}