7 declare(strict_types=1);
14 Updates
Magento with 2.3 requirements that can
't be done by `composer update` or `bin/magento setup:upgrade`. 15 Run this script after upgrading to PHP 7.1/7.2 and before running `composer update` or `bin/magento setup:upgrade`. 18 - Require new version of the metapackage 19 - Update "require-dev" section 20 - Add "Zend\\Mvc\\Controller\\": "setup/src/Zend/Mvc/Controller/" to composer.json "autoload":"psr-4" section 21 - Update Magento/Updater if it's installed
22 - Update
name, version, and description fields in the root composer.json
24 Usage: php -f
$_scriptName -- --root=
'</path/to/magento/root/>' [--composer=
'</path/to/composer/executable>']
25 [--edition=
'<community|enterprise>'] [--repo=
'<composer_repo_url>'] [--version=
'<version_constraint>']
29 --root=
'</path/to/magento/root/>' 30 Path to the
Magento installation root directory
33 --composer=
'</path/to/composer/executable>' 34 Path to the composer executable
35 - Default: The composer found in the system PATH
37 --edition=
'<community|enterprise>' 38 Target
Magento edition
for the update. Open Source =
'community', Commerce =
'enterprise' 39 - Default: The edition currently required in composer.json
41 --repo=
'<composer_repo_url>' 42 The
Magento repository url to use to pull the
new packages
43 - Default: The
Magento repository configured in composer.json
45 --version=
'<version_constraint>' 46 A composer version constraint
for allowable 2.3 packages. Versions other than 2.3 are not handled by
this script
48 - Default: The latest 2.3 version available in the
Magento repository
69 if (isset(
$opts[
'help'])) {
75 if (version_compare(PHP_VERSION,
'7.1',
'<') || version_compare(PHP_VERSION,
'7.3',
'>=')) {
76 preg_match(
'/^\d+\.\d+\.\d+/',PHP_VERSION, $matches);
77 $phpVersion = $matches[0];
78 throw new Exception(
"Invalid PHP version '$phpVersion'. Magento 2.3 requires PHP 7.1 or 7.2");
84 throw new BadMethodCallException(
'Existing Magento root directory must be supplied with --root');
90 throw new InvalidArgumentException(
"Supplied Magento root directory '$rootDir' does not contain composer.json");
96 foreach (array_keys(
$composerData[
'require']) as $requiredPackage) {
103 throw new InvalidArgumentException(
"No Magento metapackage found in $composerFile");
107 if (!empty(
$opts[
'edition'])) {
113 throw new InvalidArgumentException(
"Only 'community' and 'enterprise' editions allowed; '$edition' given");
118 throw new InvalidArgumentException(
"'$composerExec' is not a composer executable");
122 exec(
"command -v $composerExec", $out, $composerFailed);
123 if ($composerFailed) {
125 $message =
'Composer executable is not available in the system PATH';
128 $message =
"Invalid composer executable '$composerExec'";
130 throw new InvalidArgumentException(
$message);
140 $project =
"magento/project-$edition-edition";
146 if (!empty(
$opts[
'repo'])) {
151 if (strpos(strtolower(
$label),
'mage') !==
false || strpos(
$repo[
'url'],
'.mage') !==
false) {
157 throw new InvalidArgumentException(
'No Magento repository urls found in composer.json');
166 output(
"**** Searching for a matching version of $project ****");
171 output(
"\\nChecking $repoUrl");
173 runComposer(
"create-project --repository=$repoUrl $projectConstraint $tempDir --no-install");
180 if (strpos(
$version,
'2.3.') !== 0) {
181 throw new InvalidArgumentException(
"Bad 2.3 version constraint '$constraint'; version $version found");
185 output(
"\\n**** Found compatible $project version: $version ****");
190 catch (Exception $e) {
192 output(
"Failed to find a valid 2.3 $project package on $repoUrl",
WARN);
198 if (isset($exception)) {
202 output(
"\\n**** Executing Updates ****");
205 output(
"\\nBacking up $composerFile to $composerBackup");
211 $repoLabels = array_map(
'strtolower',array_keys(
$composerData[
'repositories']));
212 $newLabel =
'magento';
213 if (in_array($newLabel, $repoLabels)) {
214 $count = count($repoLabels);
216 if (!in_array(
"$newLabel-$i", $repoLabels)) {
217 $newLabel =
"$newLabel-$i";
222 output(
"\\nAdding $repo to composer repositories under label '$newLabel'");
223 runComposer(
"config repositories.$newLabel composer $repo");
226 output(
"\\nUpdating Magento metapackage requirement to $metapackage=$version");
229 runComposer(
'remove magento/product-community-edition --no-update');
232 runComposer(
"require $metapackage=$version --no-update");
234 output(
'\nUpdating "require-dev" section of composer.json');
236 'phpunit/phpunit:~6.2.0 ' .
237 'friendsofphp/php-cs-fixer:~2.10.1 ' .
238 'lusitanian/oauth:~0.8.10 ' .
239 'pdepend/pdepend:2.5.2 ' .
240 'sebastian/phpcpd:~3.0.0 ' .
241 'squizlabs/php_codesniffer:3.2.2 --no-update');
243 runComposer(
'remove --dev sjparkinson/static-review fabpot/php-cs-fixer --no-update');
245 output(
'\nAdding "Zend\\\\Mvc\\\\Controller\\\\": "setup/src/Zend/Mvc/Controller/" to "autoload": "psr-4"');
246 $composerData[
'autoload'][
'psr-4'][
'Zend\\Mvc\\Controller\\'] =
'setup/src/Zend/Mvc/Controller/';
248 if (preg_match(
'/^magento\/project\-(community|enterprise)\-edition$/',
$composerData[
'name'])) {
249 output(
'\nUpdating project name, version, and description');
261 output(
"\\nBacking up Magento/Updater directory $updateDir to $updateBackup");
263 output(
'\nUpdating Magento/Updater');
270 output(
"\\n**** Script Complete! $composerFile updated to Magento version $version ****");
272 output(
'Repository authentication failures occurred!',
WARN);
273 output(
' * Failed authentication could result in incorrect package versions',
WARN);
274 output(
' * To resolve, add credentials for the repositories to auth.json',
WARN);
277 }
catch (Exception $e) {
278 if ($e->getPrevious()) {
279 $e = $e->getPrevious();
284 output(
'Script failed! See usage information with --help',
ERROR);
287 output(
"Resetting $composerFile backup");
291 if (isset($updateBackup) && file_exists($updateBackup)) {
292 output(
"Resetting $updateDir backup");
296 if (isset($tempDir) && file_exists($tempDir)) {
297 output(
'Removing temporary project directory');
301 catch (Exception $e2) {
303 output(
'Backup restoration or directory cleanup failed',
ERROR);
306 exit($e->getCode() == 0 ? 1 : $e->getCode());
317 $unique =
"$dir/$filename";
318 if (file_exists($unique)) {
319 $unique = tempnam($dir,
"$filename.");
335 $command =
"$composerExec $command --no-interaction";
336 output(
" Running command:\\n $command");
337 exec(
"$command 2>&1", $lines, $exitCode);
338 $output =
' ' . join(
'\n ', $lines);
343 if (0 !== $exitCode) {
344 $output =
"Error encountered running command:\\n $command\\n$output";
345 throw new RuntimeException(
$output, $exitCode);
349 if (strpos(
$output,
'URL required authentication.') !==
false) {
350 preg_match(
"/'(https?:\/\/)?(?<url>[^\/']+)(\/[^']*)?' URL required authentication/",
$output, $matches);
351 $authUrl = $matches[
'url'];
353 output(
"Repository authentication failed; make sure '$authUrl' exists in auth.json",
WARN);
366 if (!file_exists(
$path)) {
370 $files = array_diff(scandir(
$path), array(
'..',
'.'));
371 foreach (
$files as $file) {
379 if (file_exists(
$path)) {
380 throw new Exception(
"Failed to delete $path");
392 $string = str_replace(
'\n', PHP_EOL, $string);
397 else if ($level ==
WARN) {
400 else if ($level ==
ERROR) {
403 $string =
"$label$string";
405 if ($level ==
WARN) {
409 error_log(PHP_EOL . $string);
412 echo $string . PHP_EOL;
output($string, $level=INFO, $label='')
if($edition !=='community' && $edition !=='enterprise') $composerExec
elseif(isset( $params[ 'redirect_parent']))
exec($command, array &$output=null, &$return_var=null)
if(!file_exists($composerFile)) $composerData
if(count($authFailed) > 0) catch(Exception $e) findUnusedFilename($dir, $filename)
defined('MTF_BOOT_FILE')||define('MTF_BOOT_FILE' __FILE__
foreach(array_keys($composerData['require']) as $requiredPackage) if(empty($edition)) if(!empty($opts['edition'])) $edition
foreach($appDirs as $dir) $files