Skip to content
Snippets Groups Projects

Issue #3316721: Add script to convert this module into a core merge request

Merged Issue #3316721: Add script to convert this module into a core merge request
2 unresolved threads
2 unresolved threads
2 files
+ 324
2
Compare changes
  • Side-by-side
  • Inline
Files
2
+ 316
0
<?php
namespace Drupal\automatic_updates\CoreCovert;
use Composer\Script\Event;
use Symfony\Component\Filesystem\Filesystem;
/**
* Converts the contrib module to core merge request.
*/
class Converter {
public static function doConvert(Event $event) {
$args = $event->getArguments();
if (count($args) !== 2) {
throw new \ArgumentCountError("This scripts 2 arguments, a directory that is a core clone and the branch.");
}
$core_dir = $args[0];
$core_branch = $args[1];
if (!is_dir($core_dir)) {
throw new \Exception("$core_dir is not a directory.");
}
$old_machine_name = 'automatic_updates';
$new_machine_name = 'auto_updates';
static::switchToBranches($core_dir, $core_branch);
$fs = new Filesystem();
$core_module_path = static::getCoreModulePath($core_dir);
$package_manager_core_path = $core_dir . "/core/modules/package_manager";
// Remove old module
$fs->remove($core_module_path);
$fs->remove($package_manager_core_path);
// Copy the contrib module to core.
$fs->mirror(__DIR__ . '/../..', $core_module_path );
// Remove unneeded
$removals = [
'package_manager/package_manager.install',
'automatic_updates_9_3_shim',
'automatic_updates_extensions',
'drupalci.yml',
'README.md',
'.git',
'pcre.ini',
'composer.json',
'.gitattributes',
'.gitignore',
'DEVELOPING.md',
'scripts',
];
$removals = array_map(function ($path) use ($core_module_path) { return "$core_module_path/$path"; }, $removals);
$fs->remove($removals);
// Replace in file names and contents.
$replacements = [
$old_machine_name => $new_machine_name,
'AutomaticUpdates' => 'AutoUpdates',
"core_version_requirement: ^9.3" => "package: Core\nversion: VERSION\nlifecycle: experimental",
];
foreach ($replacements as $search => $replace) {
static::renameFiles($search, $replace);
static::replaceContents($search, $replace);
}
static::removeLines();
$fs->rename("$core_module_path/package_manager", $core_dir . "/core/modules/package_manager");
static::addWordsToDictionary($core_dir, [
'syncer',
'syncers',
'unwritable',
]);
static::runCoreChecks($core_dir);
static::makeCommit($core_dir);
/**
* @todo Commit with the specific commit from contrib.
*/
print "\Done. Probably good but you should check before you push.";
}
private static function getContribDir() {
return __DIR__ . '/../..';
}
/**
* @param $core_dir
*
* @return string
*/
private static function getCoreModulePath(string $core_dir): string {
return $core_dir . '/core/modules/auto_updates';
}
/**
* Replaces a string in the contents of the module files.
*
* @param string $search
* @param string $replace
*/
private static function replaceContents(string $search, string $replace) {
$files = static::getDirContents(static::getCoreModulePath(), TRUE);
foreach ($files as $file) {
$filePath = $file->getRealPath();
file_put_contents($filePath,str_replace($search,$replace,file_get_contents($filePath)));
}
}
/**
* Renames the module files.
*
* @param string $old_pattern
* @param string $new_pattern
*/
private static function renameFiles(string $old_pattern, string $new_pattern) {
$files = static::getDirContents(static::getCoreModulePath());
// Keep a record of the files and directories to change.
// We will change all the files first so we don't change the location of any
// of the files in the middle.
// This probably won't work if we had nested folders with the pattern on 2
// folder levels but we don't.
$filesToChange = [];
$dirsToChange = [];
foreach ($files as $file) {
$fileName = $file->getFilename();
if ($fileName === '.') {
$fullPath = $file->getPath();
$parts = explode('/', $fullPath);
$name = array_pop($parts);
$path = "/" . implode('/', $parts);
}
else {
$name = $fileName;
$path = $file->getPath();
}
if (strpos($name, $old_pattern) !== FALSE) {
$new_filename = str_replace($old_pattern, $new_pattern, $name);
if ($file->isFile()) {
$filesToChange[$file->getRealPath()] = $file->getPath() . "/$new_filename";
}
else {
// Store directories by path depth.
$depth = count(explode('/', $path));
$dirsToChange[$depth][$file->getRealPath()] = "$path/$new_filename";
}
}
}
foreach ($filesToChange as $old => $new) {
(new Filesystem())->rename($old, $new);
}
// Rename directories starting with the most nested to avoid renaming
// parents directories first.
krsort($dirsToChange);
foreach ($dirsToChange as $dirs) {
foreach ($dirs as $old => $new) {
(new Filesystem())->rename($old, $new);
}
}
}
/**
* Gets the contents of a directory.
*
* @param string $path
* @param bool $excludeDirs
*
* @return \SplFileInfo[]
*/
private static function getDirContents(string $path, $excludeDirs = FALSE): array {
$rii = new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($path));
$files = array();
/** @var \SplFileInfo $file */
foreach ($rii as $file) {
if($excludeDirs && $file->isDir()) {
continue;
}
$files[] = $file;
}
return $files;
}
/**
* Ensures the git status is clean.
*
* @return bool
* @throws \Exception
*/
private static function ensureGitClean() {
$status_output = shell_exec('git status');
if (strpos($status_output, 'nothing to commit, working tree clean') === FALSE) {
throw new \Exception("git not clean: " .$status_output);
}
return TRUE;
}
/**
* Gets the current git branch.
*
* @return string
*/
private static function getCurrentBranch() {
return trim(shell_exec('git rev-parse --abbrev-ref HEAD'));
}
/**
* Switches to the branches we need.
*
* @param string $core_dir
* @param string $core_branch
* The core merge request branch.
*/
private static function switchToBranches(string $core_dir, string $core_branch) {
static::switchToBranch('8.x-2.x');
chdir($core_dir);
static::switchToBranch($core_branch);
}
/**
* Switches to a branches and makes sure it is clean.
*
* @param string $branch
*
* @throws \Exception
*/
private static function switchToBranch(string $branch) {
static::ensureGitClean();
shell_exec("git checkout $branch");
if ($branch !== static::getCurrentBranch()) {
throw new \Exception("could not check $branch");
}
}
private static function makeCommit(string $core_dir) {
chdir(self::getContribDir());
self::ensureGitClean();
$hash = trim(shell_exec('git rev-parse HEAD'));
$message = trim(shell_exec("git show -s --format='%s'"));
chdir($core_dir);
shell_exec('git add core');
shell_exec("git commit -m 'Contrib: $message - https://git.drupalcode.org/project/automatic_updates/-/commit/$hash'");
}
private static function addWordsToDictionary(string $core_dir, array $new_words) {
$dict_file = $core_dir . '/core/misc/cspell/dictionary.txt';
$contents = file_get_contents($dict_file);
$words = explode("\n", $contents);
$words = array_filter($words);
foreach ($new_words as $new_word) {
if (array_search($new_word, $words)) {
continue;
}
$words[] = $new_word;
}
asort($words);
file_put_contents($dict_file, implode("\n", $words));
}
private static function runCoreChecks(string $core_dir) {
chdir($core_dir);
$output = NULL;
$result = NULL;
system(' sh ./core/scripts/dev/commit-code-check.sh --branch 9.5.x', $result);
if ($result !== 0) {
print "😭commit-code-check.sh failed";
exit(1);
}
print "🎉 commit-code-check.sh passed!";
}
/**
* Removes lines from the module based on a starting and ending token
* These are lines that are not need in core at all.
*
* @throws \Exception
*/
private static function removeLines() {
$files = static::getDirContents(static::getCoreModulePath(), TRUE);
foreach ($files as $file) {
$filePath = $file->getRealPath();
$contents = file_get_contents($filePath);
$lines = explode("\n", $contents);
$skip = FALSE;
$newLines = [];
foreach ($lines as $line) {
if (strpos($line, '// BEGIN: DELETE FROM CORE MERGE REQUEST')) {
if ($skip) {
throw new \Exception("Already found begin");
}
$skip = TRUE;
}
if (!$skip) {
$newLines[] = $line;
}
if (strpos($line, '// END: DELETE FROM CORE MERGE REQUEST')) {
if (!$skip) {
throw new \Exception("Didn't find matching begin");
}
$skip = false;
}
}
if ($skip) {
throw new \Exception("Didn't find ending token");
}
file_put_contents($filePath, implode("\n", $newLines));
}
}
}
Loading