Skip to content
Snippets Groups Projects
Commit 2a305405 authored by Adam G-H's avatar Adam G-H
Browse files

Issue #3233138 by phenaproxima, tedbow, rkoller: If necessary update...

Issue #3233138 by phenaproxima, tedbow, rkoller: If necessary update drupal/core-composer-scaffold and drupal/core-project-message
parent a17ffd8d
No related branches found
No related tags found
1 merge request!60Issue #3233138: If necessary update drupal/core-composer-scaffold and drupal/core-project-message
......@@ -141,9 +141,10 @@ class Updater {
if (count($project_versions) !== 1 || !array_key_exists('drupal', $project_versions)) {
throw new \InvalidArgumentException("Currently only updates to Drupal core are supported.");
}
$packages = [
$this->getCorePackageName() => $project_versions['drupal'],
];
$packages = [];
foreach ($this->getCorePackageNames() as $package) {
$packages[$package] = $project_versions['drupal'];
}
$stage_key = $this->createActiveStage($packages);
/** @var \Drupal\automatic_updates\Event\PreStartEvent $event */
$event = $this->dispatchUpdateEvent(new PreStartEvent($packages), AutomaticUpdatesEvents::PRE_START);
......@@ -152,43 +153,60 @@ class Updater {
}
/**
* Determines the name of the core package in the project composer.json.
* Returns the names of the core packages in the project composer.json.
*
* This makes the following assumptions:
* - The vendor directory is next to the project composer.json.
* - The project composer.json contains a requirement for a core package.
* - That requirement is either for drupal/core or drupal/core-recommended.
* The following packages are considered core packages:
* - drupal/core;
* - drupal/core-recommended;
* - drupal/core-vendor-hardening;
* - drupal/core-composer-scaffold; and
* - drupal/core-project-message.
*
* @return string
* The name of the core package (either drupal/core or
* drupal/core-recommended).
* @return string[]
* The names of the core packages.
*
* @throws \RuntimeException
* If the project composer.json is not found.
* @throws \LogicException
* If the project composer.json does not contain one of the supported core
* packages.
* If the project composer.json does not contain drupal/core or
* drupal/core-recommended.
*
* @todo Move this to an update validator, or use a more robust method of
* detecting the core package.
* detecting the core packages.
*/
public function getCorePackageName(): string {
public function getCorePackageNames(): array {
$composer = realpath($this->pathLocator->getProjectRoot() . '/composer.json');
if (empty($composer) || !file_exists($composer)) {
throw new \RuntimeException("Could not find project-level composer.json");
}
$composer = file_get_contents($composer);
$composer = Json::decode($composer);
$data = file_get_contents($composer);
$data = Json::decode($data);
if (isset($composer['require']['drupal/core'])) {
return 'drupal/core';
}
elseif (isset($composer['require']['drupal/core-recommended'])) {
return 'drupal/core-recommended';
// @todo Find some way to either use a canonical list of packages that are
// part of core, or use heuristics to detect them in the lock file (e.g.,
// any package which starts with 'drupal/core-' and is a Composer plugin
// or metapackage).
$core_packages = ['drupal/core', 'drupal/core-recommended'];
$requirements = array_keys($data['require']);
// Ensure that either drupal/core or drupal/core-recommended are required
// by the project. If neither is, then core will not be updated, and we
// consider that an error condition.
$core_requirements = array_intersect($core_packages, $requirements);
if (empty($core_requirements)) {
throw new \LogicException("Drupal core does not appear to be required in $composer.");
}
throw new \LogicException("Could not determine the Drupal core package in the project-level composer.json.");
// Also detect core's Composer plugins, so they can be updated if needed.
$core_packages = array_merge($core_packages, [
'drupal/core-composer-scaffold',
'drupal/core-vendor-hardening',
'drupal/core-project-message',
]);
return array_intersect($core_packages, $requirements);
}
/**
......
......@@ -81,7 +81,10 @@ class ReadinessValidationManager {
$recommender = new UpdateRecommender();
$release = $recommender->getRecommendedRelease(TRUE);
if ($release) {
$package_versions = [$this->updater->getCorePackageName() => $release->getVersion()];
$core_packages = $this->updater->getCorePackageNames();
// Update all core packages to the same version.
$package_versions = array_fill(0, count($core_packages), $release->getVersion());
$package_versions = array_combine($core_packages, $package_versions);
}
else {
$package_versions = [];
......
......@@ -58,7 +58,10 @@ class UpdateVersionValidator implements EventSubscriberInterface {
*/
public function checkUpdateVersion(UpdateEvent $event): void {
$from_version = ExtensionVersion::createFromVersionString($this->getCoreVersion());
$core_package_name = $this->updater->getCorePackageName();
$core_package_names = $this->updater->getCorePackageNames();
// All the core packages will be updated to the same version, so it doesn't
// matter which specific package we're looking at.
$core_package_name = reset($core_package_names);
$to_version = ExtensionVersion::createFromVersionString($event->getPackageVersions()[$core_package_name]);
if ($from_version->getMajorVersion() !== $to_version->getMajorVersion()) {
......
......@@ -74,6 +74,14 @@ class CoreUpdateTest extends UpdateTestBase {
/**
* Returns composer.json changes that are needed to update core.
*
* This will clone the following packages into temporary directories:
* - drupal/core
* - drupal/core-recommended
* - drupal/core-project-message
* - drupal/core-composer-scaffold
* The cloned packages will be assigned the given version number, and the test
* site's composer.json will use the clones as path repositories.
*
* @param string $version
* The version of core we will be updating to.
*
......@@ -81,28 +89,47 @@ class CoreUpdateTest extends UpdateTestBase {
* The changes to merge into the test site's composer.json.
*/
protected function getConfigurationForUpdate(string $version): array {
$changes = [];
$repositories = [];
// Create a fake version of core with the given version number, and change
// its README so that we can actually be certain that we update to this
// fake version.
$core_dir = $this->copyPackage($this->getWebRoot() . '/core');
$this->setCoreVersion($core_dir, $version);
file_put_contents("$core_dir/README.txt", "Placeholder for Drupal core $version.");
$changes['repositories']['drupal/core'] = $this->createPathRepository($core_dir);
$dir = $this->copyPackage($this->getWebRoot() . '/core');
$this->setCoreVersion($dir, $version);
file_put_contents("$dir/README.txt", "Placeholder for Drupal core $version.");
$repositories['drupal/core'] = $this->createPathRepository($dir);
$drupal_root = $this->getDrupalRoot();
// Create a fake version of drupal/core-recommended which itself requires
// the fake version of core we just created.
$recommended_dir = $this->copyPackage($this->getDrupalRoot() . '/composer/Metapackage/CoreRecommended');
$this->alterPackage($recommended_dir, [
$dir = $this->copyPackage("$drupal_root/composer/Metapackage/CoreRecommended");
$this->alterPackage($dir, [
'require' => [
'drupal/core' => $version,
],
'version' => $version,
]);
$changes['repositories']['drupal/core-recommended'] = $this->createPathRepository($recommended_dir);
$repositories['drupal/core-recommended'] = $this->createPathRepository($dir);
// Create a fake version of drupal/core-project-message.
$dir = $this->copyPackage("$drupal_root/composer/Plugin/ProjectMessage");
$this->alterPackage($dir, ['version' => $version]);
$repositories['drupal/core-project-message'] = $this->createPathRepository($dir);
// Create a fake version of drupal/core-composer-scaffold.
$dir = $this->copyPackage("$drupal_root/composer/Plugin/Scaffold");
$this->alterPackage($dir, ['version' => $version]);
$repositories['drupal/core-composer-scaffold'] = $this->createPathRepository($dir);
// Create a fake version of drupal/core-vendor-hardening.
$dir = $this->copyPackage("$drupal_root/composer/Plugin/VendorHardening");
$this->alterPackage($dir, ['version' => $version]);
$repositories['drupal/core-vendor-hardening'] = $this->createPathRepository($dir);
return $changes;
return [
'repositories' => $repositories,
];
}
/**
......
......@@ -42,6 +42,12 @@ class UpdaterTest extends AutomaticUpdatesKernelTestBase {
$command = [
'require',
'drupal/core:9.8.1',
// These two plugins are in the root composer.json that ships with a
// git clone of Drupal core, so they will be included when determining
// which core packages to update.
// @see \Drupal\automatic_updates\Updater::getCorePackageNames()
'drupal/core-vendor-hardening:9.8.1',
'drupal/core-project-message:9.8.1',
'--update-with-all-dependencies',
];
$stager->stage($command, Argument::cetera())->shouldBeCalled();
......
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