Skip to content
Snippets Groups Projects
Commit ad016236 authored by Ted Bowman's avatar Ted Bowman
Browse files

Issue #3335908 by tedbow, Wim Leers: The 'fake_site' fixture cannot be using...

Issue #3335908 by tedbow, Wim Leers: The 'fake_site' fixture cannot be using with `composer show` because the packages are not installed
parent 9bfc8ace
No related branches found
No related tags found
No related merge requests found
Showing
with 424 additions and 65 deletions
......@@ -32,20 +32,22 @@
"Composer\\Config::disableProcessTimeout",
"scripts/phpunit.sh"
],
"core-convert": "Drupal\\automatic_updates\\CoreCovert\\Converter::doConvert"
"core-convert": "Drupal\\automatic_updates\\Development\\Converter::doConvert",
"create-site-fixture": "\\Drupal\\automatic_updates\\Development\\ComposerFixtureCreator::createFixture"
},
"scripts-descriptions": {
"phpcbf": "Automatically fixes standards violations where possible.",
"phpcs": "Checks code for standards compliance.",
"test": "Runs PHPUnit tests.",
"core-convert": "Converts this module to a core merge request. Excepts 2 arguments. 1) The core clone directory. 2) The core merge request branch."
"core-convert": "Converts this module to a core merge request. Excepts 2 arguments. 1) The core clone directory. 2) The core merge request branch.",
"create-site-fixture": "Recreates the 'fake_site' fixture needed for testing"
},
"require-dev": {
"colinodell/psr-testlogger": "^1"
},
"autoload": {
"psr-4": {
"Drupal\\automatic_updates\\CoreCovert\\": "scripts/src"
"Drupal\\automatic_updates\\Development\\": "scripts/src"
}
}
}
{
"version": "1.2.4",
"require": {
"drupal/core-recommended": "9.8.0"
"drupal/core-recommended": "9.8.0",
"drupal/core": "9.8.0"
},
"require-dev": {
"drupal/core-dev": "^9"
......@@ -16,5 +18,38 @@
"bar": 134,
"foo-bar": null
}
},
"repositories": {
"packagist.org": false,
"drupal/core-recommended": {
"type": "path",
"version": "9.8.0",
"url": "../path_repos/drupal--core-recommended",
"options": {
"symlink": false
}
},
"drupal/core-dev": {
"type": "path",
"version": "9.8.0",
"url": "../path_repos/drupal--core-dev",
"options": {
"symlink": false
}
},
"drupal/core": {
"type": "path",
"version": "9.8.0",
"url": "../path_repos/drupal--core",
"options": {
"symlink": false
}
}
},
"minimum-stability": "stable",
"config": {
"allow-plugins": {
"drupal/core-composer-scaffold": false
}
}
}
{}
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "e9b347834f96b988de85d370a723d3bf",
"packages": [
{
"name": "drupal/core",
"version": "9.8.0",
"dist": {
"type": "path",
"url": "../path_repos/drupal--core",
"reference": "5aeab06c3087477e20e617328f2fa9f3ed18373d"
},
"type": "drupal-core",
"extra": {
"_readme": [
"The 'drupal-scaffold' section below is needed because 'Drupal\\automatic_updates\\Validator\\ScaffoldFilePermissionsValidator'",
"uses this section to determine which files to check. The actual composer.json file for drupal/core will have more files listed",
"but this limited list is used in '\\Drupal\\Tests\\automatic_updates\\Kernel\\StatusCheck\\ScaffoldFilePermissionsValidatorTest'",
"to ensure the section is source of the file list."
],
"drupal-scaffold": {
"file-mapping": {
"[web-root]/sites/default/default.settings.php": "",
"[web-root]/sites/default/default.services.yml": ""
}
}
},
"transport-options": {
"symlink": false,
"relative": true
}
},
{
"name": "drupal/core-recommended",
"version": "9.8.0",
"dist": {
"type": "path",
"url": "../path_repos/drupal--core-recommended",
"reference": "c9babad9851edc2b7b4b43c778bc30db09f14946"
},
"type": "project",
"transport-options": {
"symlink": false,
"relative": true
}
}
],
"packages-dev": [
{
"name": "drupal/core-dev",
"version": "9.8.0",
"dist": {
"type": "path",
"url": "../path_repos/drupal--core-dev",
"reference": "6a8d7df3a5650a5d3bce6e478114064b176f7104"
},
"type": "package",
"transport-options": {
"symlink": false,
"relative": true
}
}
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.3.0"
}
{
"packages": [
{
"name": "drupal/core",
"version": "9.8.0",
"type": "drupal-core",
"extra": {
"drupal-scaffold": {
"file-mapping": {
"[web-root]/sites/default/default.settings.php": "",
"[web-root]/sites/default/default.services.yml": ""
}
"packages": [
{
"name": "drupal/core",
"version": "9.8.0",
"version_normalized": "9.8.0.0",
"dist": {
"type": "path",
"url": "../path_repos/drupal--core",
"reference": "5aeab06c3087477e20e617328f2fa9f3ed18373d"
},
"type": "drupal-core",
"extra": {
"_readme": [
"The 'drupal-scaffold' section below is needed because 'Drupal\\automatic_updates\\Validator\\ScaffoldFilePermissionsValidator'",
"uses this section to determine which files to check. The actual composer.json file for drupal/core will have more files listed",
"but this limited list is used in '\\Drupal\\Tests\\automatic_updates\\Kernel\\StatusCheck\\ScaffoldFilePermissionsValidatorTest'",
"to ensure the section is source of the file list."
],
"drupal-scaffold": {
"file-mapping": {
"[web-root]/sites/default/default.settings.php": "",
"[web-root]/sites/default/default.services.yml": ""
}
}
},
"installation-source": "dist",
"transport-options": {
"symlink": false,
"relative": true
},
"install-path": "../drupal/core"
},
{
"name": "drupal/core-dev",
"version": "9.8.0",
"version_normalized": "9.8.0.0",
"dist": {
"type": "path",
"url": "../path_repos/drupal--core-dev",
"reference": "6a8d7df3a5650a5d3bce6e478114064b176f7104"
},
"type": "package",
"installation-source": "dist",
"transport-options": {
"symlink": false,
"relative": true
},
"install-path": "../drupal/core-dev"
},
{
"name": "drupal/core-recommended",
"version": "9.8.0",
"version_normalized": "9.8.0.0",
"dist": {
"type": "path",
"url": "../path_repos/drupal--core-recommended",
"reference": "c9babad9851edc2b7b4b43c778bc30db09f14946"
},
"type": "project",
"installation-source": "dist",
"transport-options": {
"symlink": false,
"relative": true
},
"install-path": "../drupal/core-recommended"
}
}
},
{
"name": "drupal/core-recommended",
"version": "9.8.0",
"type": "drupal-core"
},
{
"name": "drupal/core-dev",
"version": "9.8.0",
"type": "drupal-core"
}
],
"dev-package-names": []
],
"dev": true,
"dev-package-names": [
"drupal/core-dev"
]
}
......@@ -4,23 +4,53 @@
* @file
*/
// Composer Utility needs the versions key to be present.
return [
'root' => [
'name' => '__root__',
'pretty_version' => '1.2.4',
'version' => '1.2.4.0',
'reference' => NULL,
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => [],
'dev' => TRUE,
],
'versions' => [
'drupal/core' => [
'name' => 'drupal/core',
'version' => '9.8.0',
'type' => 'drupal-core',
'__root__' => [
'pretty_version' => '1.2.4',
'version' => '1.2.4.0',
'reference' => NULL,
'type' => 'library',
'install_path' => __DIR__ . '/../../',
'aliases' => [],
'dev_requirement' => FALSE,
],
'drupal/core-recommended' => [
'name' => 'drupal/core-recommended',
'version' => '9.8.0',
'drupal/core' => [
'pretty_version' => '9.8.0',
'version' => '9.8.0.0',
'reference' => '5aeab06c3087477e20e617328f2fa9f3ed18373d',
'type' => 'drupal-core',
'install_path' => __DIR__ . '/../drupal/core',
'aliases' => [],
'dev_requirement' => FALSE,
],
'drupal/core-dev' => [
'name' => 'drupal/core-dev',
'version' => '9.8.0',
'type' => 'drupal-core',
'pretty_version' => '9.8.0',
'version' => '9.8.0.0',
'reference' => '6a8d7df3a5650a5d3bce6e478114064b176f7104',
'type' => 'package',
'install_path' => __DIR__ . '/../drupal/core-dev',
'aliases' => [],
'dev_requirement' => TRUE,
],
'drupal/core-recommended' => [
'pretty_version' => '9.8.0',
'version' => '9.8.0.0',
'reference' => 'c9babad9851edc2b7b4b43c778bc30db09f14946',
'type' => 'project',
'install_path' => __DIR__ . '/../drupal/core-recommended',
'aliases' => [],
'dev_requirement' => FALSE,
],
],
];
{"name":"drupal\/core-dev","type":"package","version":"9.8.0"}
\ No newline at end of file
{"name":"drupal/core-recommended","type":"project","version":"9.8.0"}
{
"name":"drupal/core",
"type":"drupal-core",
"version":"9.8.0",
"extra": {
"_readme": [
"The 'drupal-scaffold' section below is needed because 'Drupal\\automatic_updates\\Validator\\ScaffoldFilePermissionsValidator'",
"uses this section to determine which files to check. The actual composer.json file for drupal/core will have more files listed",
"but this limited list is used in '\\Drupal\\Tests\\automatic_updates\\Kernel\\StatusCheck\\ScaffoldFilePermissionsValidatorTest'",
"to ensure the section is source of the file list."
],
"drupal-scaffold": {
"file-mapping": {
"[web-root]/sites/default/default.settings.php": "",
"[web-root]/sites/default/default.services.yml": ""
}
}
}
}
{"name":"drupal\/core-dev","type":"package","version":"9.8.0"}
\ No newline at end of file
{"name":"drupal/core-recommended","type":"project","version":"9.8.0"}
{
"name":"drupal/core",
"type":"drupal-core",
"version":"9.8.0",
"extra": {
"_readme": [
"The 'drupal-scaffold' section below is needed because 'Drupal\\automatic_updates\\Validator\\ScaffoldFilePermissionsValidator'",
"uses this section to determine which files to check. The actual composer.json file for drupal/core will have more files listed",
"but this limited list is used in '\\Drupal\\Tests\\automatic_updates\\Kernel\\StatusCheck\\ScaffoldFilePermissionsValidatorTest'",
"to ensure this section determines the file list."
],
"drupal-scaffold": {
"file-mapping": {
"[web-root]/sites/default/default.settings.php": "",
"[web-root]/sites/default/default.services.yml": ""
}
}
}
}
......@@ -2,6 +2,7 @@
namespace Drupal\fixture_manipulator;
use Composer\Semver\VersionParser;
use Drupal\Component\Utility\NestedArray;
use Drupal\Core\Serialization\Yaml;
use Symfony\Component\Filesystem\Filesystem;
......@@ -190,6 +191,12 @@ class FixtureManipulator {
if ($package) {
$package = ['name' => $pretty_name] + $package;
$install_json_package = array_diff_key($package, array_flip(['install_path']));
// Composer will use 'version_normalized', if present, to determine the
// version number.
if (isset($install_json_package['version']) && !isset($install_json_package['version_normalized'])) {
$parser = new VersionParser();
$install_json_package['version_normalized'] = $parser->normalize($install_json_package['version']);
}
}
if (isset($position)) {
......
......@@ -6,6 +6,7 @@ namespace Drupal\Tests\package_manager\Kernel;
use Drupal\fixture_manipulator\ActiveFixtureManipulator;
use Drupal\package_manager\ComposerUtility;
use Symfony\Component\Process\Process;
/**
* Test that the 'fake-site' fixture is a valid starting point.
......@@ -113,4 +114,19 @@ class FakeSiteFixtureTest extends PackageManagerKernelTestBase {
return $packages;
}
/**
* Tests that Composer show command can be used on the fixture.
*/
public function testComposerShow(): void {
$process = new Process(['composer', 'show', '--format=json'], $this->container->get('package_manager.path_locator')->getProjectRoot());
$process->run();
if ($error = $process->getErrorOutput()) {
$this->fail('Process error: ' . $error);
}
$output = json_decode($process->getOutput(), TRUE);
$package_names = array_map(fn (array $package) => $package['name'], $output['installed']);
$this->assertTrue(asort($package_names));
$this->assertSame(['drupal/core', 'drupal/core-dev', 'drupal/core-recommended'], $package_names);
}
}
......@@ -30,27 +30,23 @@ class FixtureManipulatorTest extends PackageManagerKernelTestBase {
private \Exception $expectedTearDownException;
/**
* The existing packages in the fixture.
* The original 'installed.php' data before any manipulation.
*
* @var \string[][]
* @var array
*/
private array $existingCorePackages = [
'drupal/core' => [
'name' => 'drupal/core',
'version' => '9.8.0',
'type' => 'drupal-core',
],
'drupal/core-recommended' => [
'name' => 'drupal/core-recommended',
'version' => '9.8.0',
'type' => 'drupal-core',
],
'drupal/core-dev' => [
'name' => 'drupal/core-dev',
'version' => '9.8.0',
'type' => 'drupal-core',
],
];
private array $originalInstalledPhp;
/**
* Ensures the original fixture packages in 'installed.php' are unchanged.
*
* @param array $installed_php
* The current 'installed.php' data.
*/
private function assertOriginalFixturePackagesUnchanged(array $installed_php): void {
$original_package_names = array_keys($this->originalInstalledPhp);
$installed_php_core_packages = array_intersect_key($installed_php, array_flip($original_package_names));
$this->assertSame($this->originalInstalledPhp, $installed_php_core_packages);
}
/**
* {@inheritdoc}
......@@ -61,6 +57,8 @@ class FixtureManipulatorTest extends PackageManagerKernelTestBase {
$this->dir = $this->container->get('package_manager.path_locator')
->getProjectRoot();
[, $this->originalInstalledPhp] = $this->getData();
$manipulator = new ActiveFixtureManipulator();
$manipulator
->addPackage([
......@@ -157,9 +155,13 @@ class FixtureManipulatorTest extends PackageManagerKernelTestBase {
'name' => 'my/dev-package',
'version' => '2.1.0',
'type' => 'library',
'version_normalized' => '2.1.0.0',
],
];
$installed_php_expected_packages = $installed_json_expected_packages;
// Composer stores `version_normalized`in 'installed.json' but not
// 'installed.php'.
unset($installed_php_expected_packages['my/dev-package']['version_normalized']);
[$installed_json, $installed_php] = $this->getData();
$installed_json['packages'] = array_intersect_key($installed_json['packages'], $installed_json_expected_packages);
$this->assertSame($installed_json_expected_packages, $installed_json['packages']);
......@@ -169,7 +171,13 @@ class FixtureManipulatorTest extends PackageManagerKernelTestBase {
// have been prefixed with the __DIR__ constant, which should be interpreted
// when installed.php is loaded by the PHP runtime.
$installed_php_expected_packages['my/dev-package']['install_path'] = "$this->dir/vendor/composer/../relative/path";
$installed_php_expected_packages = $this->existingCorePackages + $installed_php_expected_packages;
// None of the operations should have changed the original packages.
$this->assertOriginalFixturePackagesUnchanged($installed_php);
// Remove the original packages since we have confirmed that they have not
// changed.
$installed_php = array_diff_key($installed_php, $this->originalInstalledPhp);
$this->assertSame($installed_php_expected_packages, $installed_php);
}
......@@ -241,6 +249,7 @@ class FixtureManipulatorTest extends PackageManagerKernelTestBase {
'my/dev-package' => [
'name' => 'my/dev-package',
'version' => '3.2.1',
'version_normalized' => '3.2.1.0',
'type' => 'library',
],
'my/other-package' => [
......@@ -249,6 +258,9 @@ class FixtureManipulatorTest extends PackageManagerKernelTestBase {
],
];
$installed_php_expected_packages = $install_json_expected_packages;
// Composer stores `version_normalized`in 'installed.json' but not
// 'installed.php'.
unset($installed_php_expected_packages['my/dev-package']['version_normalized']);
$installed_php_expected_packages['my/dev-package']['install_path'] = "$this->dir/vendor/composer/../relative/path";
[$installed_json, $installed_php] = $this->getData();
$installed_json['packages'] = array_intersect_key($installed_json['packages'], $install_json_expected_packages);
......@@ -256,8 +268,13 @@ class FixtureManipulatorTest extends PackageManagerKernelTestBase {
$this->assertContains('my/dev-package', $installed_json['dev-package-names']);
$this->assertNotContains('my/other-package', $installed_json['dev-package-names']);
$this->assertNotContains('my/package', $installed_json['dev-package-names']);
$installed_php_expected_packages = $this->existingCorePackages + $installed_php_expected_packages;
// @see ::testAddPackage()
// None of the operations should have changed the original packages.
$this->assertOriginalFixturePackagesUnchanged($installed_php);
// Remove the original packages since we have confirmed that they have not
// changed.
$installed_php = array_diff_key($installed_php, $this->originalInstalledPhp);
$this->assertSame($installed_php_expected_packages, $installed_php);
}
......
<?php
declare(strict_types = 1);
namespace Drupal\automatic_updates\Development;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Process\Exception\ProcessFailedException;
use Symfony\Component\Process\Process;
/**
* Creates the test fixture at 'package_manager/tests/fixtures/fake_site'.
*/
final class ComposerFixtureCreator {
const FIXTURE_PATH = __DIR__ . '/../../package_manager/tests/fixtures/fake_site';
/**
* Creates the fixture.
*/
public static function createFixture(): void {
$fs = new Filesystem();
$fs->remove(static::FIXTURE_PATH . "/composer.lock");
// Remove all the vendor folders but leave our 2 test files.
// @see \Drupal\Tests\package_manager\Kernel\PathExcluder\VendorHardeningExcluderTest
self::removeAllExcept(self::FIXTURE_PATH . "/vendor", ['.htaccess', 'web.config']);
static::doComposerInstall();
static::removeAllExcept(static::FIXTURE_PATH . '/vendor/composer', ['installed.json', 'installed.php']);
$fs->remove(static::FIXTURE_PATH . '/vendor/autoload.php');
$process = new Process(['composer', 'phpcbf'], __DIR__ . '/../..');
$process->run();
print "\nFixture created 🎉.";
}
/**
* Runs a Composer command at the fixture root.
*
* @param array $command
* The command to run as passed to
* \Symfony\Component\Process\Process::__construct.
*
* @return string
* The Composer command output.
*/
protected static function runComposerCommand(array $command): string {
array_unshift($command, 'composer');
$command[] = "--working-dir=" . static::FIXTURE_PATH;
$process = new Process($command);
$process->run();
if (!$process->isSuccessful()) {
throw new ProcessFailedException($process);
}
return $process->getOutput();
}
/**
* Removes all files in a directory except the ones specified.
*
* @param string $directory
* The directory path.
* @param string[] $files_to_keep
* The files to not delete.
*/
protected static function removeAllExcept(string $directory, array $files_to_keep): void {
if (!is_dir($directory)) {
throw new \LogicException("Expected directory $directory");
}
$paths_to_remove = glob("$directory/*");
$fs = new Filesystem();
foreach ($paths_to_remove as $path_to_remove) {
$base_name = basename($path_to_remove);
if (!in_array($base_name, $files_to_keep, TRUE)) {
$fs->remove($path_to_remove);
}
}
}
/**
* Runs `composer install`.
*/
protected static function doComposerInstall(): void {
// Disable Packagist entirely so that we don't test the Internet.
static::runComposerCommand(['config', 'repo.packagist.org', 'false']);
static::runComposerCommand(['install']);
}
}
......@@ -2,7 +2,7 @@
declare(strict_types = 1);
namespace Drupal\automatic_updates\CoreCovert;
namespace Drupal\automatic_updates\Development;
use Composer\Script\Event;
use Symfony\Component\Filesystem\Filesystem;
......
......@@ -196,7 +196,8 @@ final class VersionPolicyValidator implements EventSubscriberInterface {
$unknown_target = new \LogicException('The target version of Drupal core could not be determined.');
if (isset($package_versions)) {
$core_package_name = key($updater->getActiveComposer()->getCorePackages());
// Get the first non-dev core package.
$core_package_name = key(array_diff_key($updater->getActiveComposer()->getCorePackages(), ['drupal/core-dev' => '']));
if ($core_package_name && array_key_exists($core_package_name, $package_versions)) {
return $package_versions[$core_package_name];
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment