Skip to content
Snippets Groups Projects

Issue #3409491 add composer dependencies in conversion script

Files
2
@@ -5,6 +5,11 @@ declare(strict_types = 1);
@@ -5,6 +5,11 @@ declare(strict_types = 1);
namespace Drupal\automatic_updates\Development;
namespace Drupal\automatic_updates\Development;
use Composer\Script\Event;
use Composer\Script\Event;
 
use Symfony\Component\Console\Command\Command;
 
use Symfony\Component\Console\Input\InputArgument;
 
use Symfony\Component\Console\Input\InputInterface;
 
use Symfony\Component\Console\Input\InputOption;
 
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Filesystem\Filesystem;
/**
/**
@@ -20,9 +25,114 @@ use Symfony\Component\Filesystem\Filesystem;
@@ -20,9 +25,114 @@ use Symfony\Component\Filesystem\Filesystem;
*
*
* The core clone should already have the core merge request locally.
* The core clone should already have the core merge request locally.
*/
*/
class Converter {
class ConverterCommand extends Command {
private const RUN_CHECKS = TRUE;
private string $core_dir;
 
 
private string $core_branch;
 
 
private string $contrib_branch;
 
 
private bool $package_manager_only;
 
 
private string $core_target_branch;
 
 
private string $contrib_dir;
 
 
private bool $no_commit;
 
 
private bool $skipCoreChecks;
 
 
/**
 
* {@inheritdoc}
 
*/
 
protected function execute(InputInterface $input, OutputInterface $output) {
 
$this->core_dir = $input->getArgument('core_dir');
 
$this->core_branch = $input->getArgument('core_branch');
 
$this->contrib_branch = $input->getArgument('contrib_branch');
 
$this->package_manager_only = $input->getOption('package_manager_only');
 
$this->core_target_branch = $input->getOption('core_target_branch');
 
$this->contrib_dir = realpath(__DIR__ . '/../..');
 
$this->skipCoreChecks = $input->getOption('skip_core_checks');
 
$this->no_commit = $input->getOption('no_commit');
 
// Esnure core_dir is a directory.
 
if (!is_dir($this->core_dir)) {
 
throw new \Exception("$this->core_dir is not a directory.");
 
}
 
// Switch to core_target_branch to ensure it is clean.
 
chdir($this->core_dir);
 
static::switchToBranch($this->core_target_branch);
 
// Git pull to ensure we are up to date.
 
static::executeCommand('git pull');
 
// change back the previous directory.
 
chdir($this->contrib_dir);
 
// Ensure we are on the correct branches.
 
static::switchToBranches($this->core_dir, $this->core_branch, $this->contrib_branch);
 
// Switch to the core directory and checkout the files and folders that this
 
// conversion script will automatically update based on our composer.json
 
// file and our dictionary.txt file.
 
chdir($this->core_dir);
 
static::executeCommand("git checkout {$this->core_target_branch} -- composer.json");
 
static::executeCommand("git checkout {$this->core_target_branch} -- composer.lock");
 
static::executeCommand("git checkout {$this->core_target_branch} -- composer");
 
static::executeCommand("git checkout {$this->core_target_branch} -- core/composer.json");
 
static::executeCommand("git checkout {$this->core_target_branch} -- core/misc/cspell/dictionary.txt");
 
 
// Switch to the core directory and require all of the packages there are in
 
// this module's composer.json require section.
 
chdir('core');
 
$require_section = $this->getContribModuleComposerJsonSection('require');
 
// Hardcode symfony version to 6.4 for core.
 
$core_symfony_version_update = function ($package_name, $version): string {
 
if (str_starts_with($package_name, 'symfony/')) {
 
return '^6.4';
 
}
 
return $version;
 
};
 
foreach ($require_section as $package_name => $version) {
 
$version = $core_symfony_version_update($package_name, $version);
 
static::executeCommand("composer require $package_name:$version --no-update");
 
}
 
// Switch back to the parent directory.
 
chdir('..');
 
// Run composer update for just this packages.
 
static::executeCommand("composer update " . implode(' ', array_keys($require_section)));
 
 
$require_dev_section = $this->getContribModuleComposerJsonSection('require-dev');
 
foreach ($require_dev_section as $package_name => $version) {
 
$version = $core_symfony_version_update($package_name, $version);
 
static::executeCommand("composer require --dev $package_name:$version");
 
}
 
$this->doConvert();
 
return Command::SUCCESS;
 
}
 
 
/**
 
* Executes a command and throws an exception if it fails.
 
*
 
* @param string $cmd
 
* The command to execute.
 
*/
 
private static function executeCommand(string $cmd): void {
 
$result = NULL;
 
system($cmd, $result);
 
if ($result !== 0) {
 
throw new \Exception("Command failed: $cmd");
 
}
 
}
 
 
/**
 
* {@inheritdoc}
 
*/
 
protected function configure() {
 
$this->addArgument('core_dir', InputArgument::REQUIRED, 'The path to the root of Drupal Core');
 
$this->addArgument('core_branch', InputArgument::REQUIRED, 'The core merge request branch');
 
$this->addArgument('contrib_branch', InputArgument::OPTIONAL, 'The contrib branch to switch to', '3.0.x');
 
$this->addOption('package_manager_only', NULL, InputOption::VALUE_NONE, 'Only convert package manager');
 
$this->addOption('core_target_branch', NULL, InputOption::VALUE_REQUIRED, 'The core target branch', '11.x');
 
$this->addOption('skip_core_checks', NULL, InputOption::VALUE_NONE, 'Skip core checks');
 
$this->addOption('no_commit', NULL, InputOption::VALUE_NONE, 'Do not make commit');
 
}
/**
/**
* Prints message.
* Prints message.
@@ -36,36 +146,15 @@ class Converter {
@@ -36,36 +146,15 @@ class Converter {
/**
/**
* Converts the contrib module to core merge request.
* Converts the contrib module to core merge request.
*
* @param \Composer\Script\Event $event
* The Composer event.
*/
*/
public static function doConvert(Event $event): void {
private function doConvert(): void {
$args = $event->getArguments();
$count_arg = count($args);
if (!($count_arg === 3 || $count_arg === 4)) {
throw new \Exception("This scripts 3 required arguments: a directory that is a core clone and the branch and to convert either package_manager or automatic_updates.\nIt has 1 optional arguments: the branch of this module to use which defaults to 3.0.x");
}
$core_dir = $args[0];
$core_branch = $args[1];
if (!is_dir($core_dir)) {
throw new \Exception("$core_dir is not a directory.");
}
$package_manager_only = match($args[2]) {
'package_manager' => TRUE,
'automatic_updates' => FALSE,
default => throw new \UnexpectedValueException("The 3nd argument must be package_manager or automatic_updates"),
};
$contrib_branch = $count_arg === 3 ? '3.0.x' : $args[3];
$old_machine_name = 'automatic_updates';
$old_machine_name = 'automatic_updates';
$new_machine_name = 'auto_updates';
$new_machine_name = 'auto_updates';
static::switchToBranches($core_dir, $core_branch, $contrib_branch);
self::info('Switched branches');
self::info('Switched branches');
$fs = new Filesystem();
$fs = new Filesystem();
$core_module_path = static::getCoreModulePath($core_dir);
$core_module_path = static::getCoreModulePath($this->core_dir);
$package_manager_core_path = $core_dir . "/core/modules/package_manager";
$package_manager_core_path = $this->core_dir . "/core/modules/package_manager";
// Remove old module.
// Remove old module.
$fs->remove($core_module_path);
$fs->remove($core_module_path);
self::info('Removed old core module');
self::info('Removed old core module');
@@ -93,10 +182,10 @@ class Converter {
@@ -93,10 +182,10 @@ class Converter {
}
}
self::info('Replacements done.');
self::info('Replacements done.');
static::removeLines($core_dir);
static::removeLines($this->core_dir);
self::info('Remove unneeded lines');
self::info('Remove unneeded lines');
self::moveScripts($core_dir, $core_module_path, $package_manager_only);
self::moveScripts($this->core_dir, $core_module_path, $this->package_manager_only);
self::info('Moved scripts');
self::info('Moved scripts');
// Remove unneeded.
// Remove unneeded.
@@ -135,36 +224,39 @@ class Converter {
@@ -135,36 +224,39 @@ class Converter {
$fs->rename("$core_module_path/package_manager", $package_manager_core_path);
$fs->rename("$core_module_path/package_manager", $package_manager_core_path);
self::info('Move package manager');
self::info('Move package manager');
static::copyGenericTest($package_manager_core_path, $core_dir);
static::copyGenericTest($package_manager_core_path, $this->core_dir);
// Run phpcbf because removing code from merge request may result in unused
// Run phpcbf because removing code from merge request may result in unused
// use statements or multiple empty lines.
// use statements or multiple empty lines.
system("composer phpcbf $package_manager_core_path");
system("composer phpcbf $package_manager_core_path");
if ($package_manager_only) {
if ($this->package_manager_only) {
$fs->remove($core_module_path);
$fs->remove($core_module_path);
}
}
else {
else {
static::copyGenericTest($core_module_path, $core_dir);
static::copyGenericTest($core_module_path, $this->core_dir);
system("composer phpcbf $core_module_path");
system("composer phpcbf $core_module_path");
}
}
static::addWordsToDictionary($core_dir, self::getContribDir() . "/dictionary.txt");
static::addWordsToDictionary($this->core_dir, self::getContribDir() . "/dictionary.txt");
self::info("Added to dictionary");
self::info("Added to dictionary");
chdir($core_dir);
chdir($this->core_dir);
if (self::RUN_CHECKS) {
if ($this->skipCoreChecks) {
static::runCoreChecks($core_dir);
self::info('⚠️Skipped core checks');
self::info('Ran core checks');
}
}
else {
else {
self::info('⚠️Skipped core checks');
static::runCoreChecks($this->core_dir);
 
self::info('Ran core checks');
}
}
static::doMakeCommit($core_dir);
if (!$this->no_commit) {
self::info('Make commit');
static::doMakeCommit($this->core_dir);
self::info("Done. Probably good but you should check before you push. These are the files present in the contrib module absent in core:");
self::info('Make commit');
print shell_exec(sprintf("tree %s/package_manager > /tmp/contrib.txt && tree %s/core/modules/package_manager > /tmp/core.txt && diff /tmp/contrib.txt /tmp/core.txt", self::getContribDir(), $core_dir));
self::info("Done. Probably good but you should check before you push. These are the files present in the contrib module absent in core:");
self::info('(Run diff /tmp/contrib.txt /tmp/core.txt to see that with color.');
print shell_exec(sprintf("tree %s/package_manager > /tmp/contrib.txt && tree %s/core/modules/package_manager > /tmp/core.txt && diff /tmp/contrib.txt /tmp/core.txt", self::getContribDir(), $this->core_dir));
 
self::info('(Run diff /tmp/contrib.txt /tmp/core.txt to see that with color.');
 
}
 
}
}
/**
/**
@@ -344,7 +436,7 @@ class Converter {
@@ -344,7 +436,7 @@ class Converter {
static::ensureGitClean();
static::ensureGitClean();
shell_exec("git checkout $branch");
shell_exec("git checkout $branch");
if ($branch !== static::getCurrentBranch()) {
if ($branch !== static::getCurrentBranch()) {
throw new \Exception("could not check $branch");
throw new \Exception("could not checkout $branch");
}
}
}
}
@@ -546,4 +638,9 @@ class Converter {
@@ -546,4 +638,9 @@ class Converter {
static::replaceContents([new \SplFileInfo($new_test)], 'action', $module_name);
static::replaceContents([new \SplFileInfo($new_test)], 'action', $module_name);
}
}
 
private function getContribModuleComposerJsonSection(string $section): array {
 
$composer_json = json_decode(file_get_contents($this->contrib_dir . '/composer.json'), TRUE);
 
return $composer_json[$section];
 
}
 
}
}
Loading