From: jenkins-bot Date: Mon, 24 Sep 2018 05:43:18 +0000 (+0000) Subject: Merge "registration: Let extensions add PHP version requirements" X-Git-Tag: 1.34.0-rc.0~4014 X-Git-Url: http://git.cyclocoop.org/%7B%24admin_url%7Dcompta/comptes/journal.php?a=commitdiff_plain;h=0c045de899977975884aa93f3f4e2642dd175f83;hp=257edebf33b89180d754adbad44ed3be9eab0b71;p=lhc%2Fweb%2Fwiklou.git Merge "registration: Let extensions add PHP version requirements" --- diff --git a/docs/extension.schema.v1.json b/docs/extension.schema.v1.json index 0ff169c3c2..e6ec971e51 100644 --- a/docs/extension.schema.v1.json +++ b/docs/extension.schema.v1.json @@ -55,13 +55,24 @@ }, "requires": { "type": "object", - "description": "Indicates what versions of MediaWiki core or extensions are required. This syntax may be extended in the future, for example to check dependencies between other services.", + "description": "Indicates what versions of PHP, MediaWiki core or extensions are required. This syntax may be extended in the future, for example to check dependencies between other services.", "additionalProperties": false, "properties": { "MediaWiki": { "type": "string", "description": "Version constraint string against MediaWiki core." }, + "platform": { + "type": "object", + "description": "Indicates version constraints against platform services.", + "additionalProperties": false, + "properties": { + "php": { + "type": "string", + "description": "Version constraint string against PHP." + } + } + }, "extensions": { "type": "object", "description": "Set of version constraint strings against specific extensions." diff --git a/docs/extension.schema.v2.json b/docs/extension.schema.v2.json index 7de5ed5f9a..93bf0d908a 100644 --- a/docs/extension.schema.v2.json +++ b/docs/extension.schema.v2.json @@ -56,13 +56,24 @@ }, "requires": { "type": "object", - "description": "Indicates what versions of MediaWiki core or extensions are required. This syntax may be extended in the future, for example to check dependencies between other services.", + "description": "Indicates what versions of PHP, MediaWiki core or extensions are required. This syntax may be extended in the future, for example to check dependencies between other services.", "additionalProperties": false, "properties": { "MediaWiki": { "type": "string", "description": "Version constraint string against MediaWiki core." }, + "platform": { + "type": "object", + "description": "Indicates version constraints against platform services.", + "additionalProperties": false, + "properties": { + "php": { + "type": "string", + "description": "Version constraint string against PHP." + } + } + }, "extensions": { "type": "object", "description": "Set of version constraint strings against specific extensions." diff --git a/includes/registration/ExtensionDependencyError.php b/includes/registration/ExtensionDependencyError.php index d380d07761..dfd598541d 100644 --- a/includes/registration/ExtensionDependencyError.php +++ b/includes/registration/ExtensionDependencyError.php @@ -48,6 +48,11 @@ class ExtensionDependencyError extends Exception { */ public $incompatibleCore = false; + /** + * @var bool + */ + public $incompatiblePhp = false; + /** * @param array $errors Each error has a 'msg' and 'type' key at minimum */ @@ -59,6 +64,9 @@ class ExtensionDependencyError extends Exception { case 'incompatible-core': $this->incompatibleCore = true; break; + case 'incompatible-php': + $this->incompatiblePhp = true; + break; case 'missing-skins': $this->missingSkins[] = $info['missing']; break; diff --git a/includes/registration/ExtensionRegistry.php b/includes/registration/ExtensionRegistry.php index 1f8a27e60e..3138b37a04 100644 --- a/includes/registration/ExtensionRegistry.php +++ b/includes/registration/ExtensionRegistry.php @@ -213,7 +213,8 @@ class ExtensionRegistry { $autoloadNamespaces = []; $autoloaderPaths = []; $processor = new ExtensionProcessor(); - $versionChecker = new VersionChecker( $wgVersion ); + $phpVersion = PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION . '.' . PHP_RELEASE_VERSION; + $versionChecker = new VersionChecker( $wgVersion, $phpVersion ); $extDependencies = []; $incompatible = []; $warnings = false; diff --git a/includes/registration/VersionChecker.php b/includes/registration/VersionChecker.php index 1569e088b8..93b4a14301 100644 --- a/includes/registration/VersionChecker.php +++ b/includes/registration/VersionChecker.php @@ -35,6 +35,11 @@ class VersionChecker { */ private $coreVersion = false; + /** + * @var Constraint|bool representing PHP version + */ + private $phpVersion = false; + /** * @var array Loaded extensions */ @@ -48,9 +53,10 @@ class VersionChecker { /** * @param string $coreVersion Current version of core */ - public function __construct( $coreVersion ) { + public function __construct( $coreVersion, $phpVersion ) { $this->versionParser = new VersionParser(); $this->setCoreVersion( $coreVersion ); + $this->setPhpVersion( $phpVersion ); } /** @@ -82,6 +88,21 @@ class VersionChecker { } } + /** + * Set PHP version. + * + * @param string $phpVersion Current PHP version. Must be well-formed. + * @throws UnexpectedValueException + */ + private function setPhpVersion( $phpVersion ) { + // normalize to make this throw an exception if the version is invalid + $this->phpVersion = new Constraint( + '==', + $this->versionParser->normalize( $phpVersion ) + ); + $this->phpVersion->setPrettyString( $phpVersion ); + } + /** * Check all given dependencies if they are compatible with the named * installed extensions in the $credits array. @@ -90,6 +111,9 @@ class VersionChecker { * { * 'FooBar' => { * 'MediaWiki' => '>= 1.25.0', + * 'platform': { + * 'php': '>= 7.0.0' + * }, * 'extensions' => { * 'FooBaz' => '>= 1.25.0' * }, @@ -108,14 +132,47 @@ class VersionChecker { foreach ( $dependencies as $dependencyType => $values ) { switch ( $dependencyType ) { case ExtensionRegistry::MEDIAWIKI_CORE: - $mwError = $this->handleMediaWikiDependency( $values, $extension ); + $mwError = $this->handleDependency( + $this->coreVersion, + $values, + $extension + ); if ( $mwError !== false ) { $errors[] = [ - 'msg' => $mwError, + 'msg' => + "{$extension} is not compatible with the current MediaWiki " + . "core (version {$this->coreVersion->getPrettyString()}), " + . "it requires: $values." + , 'type' => 'incompatible-core', ]; } break; + case 'platform': + foreach ( $values as $dependency => $constraint ) { + if ( $dependency === 'php' ) { + $phpError = $this->handleDependency( + $this->phpVersion, + $constraint, + $extension + ); + if ( $phpError !== false ) { + $errors[] = [ + 'msg' => + "{$extension} is not compatible with the current PHP " + . "version {$this->phpVersion->getPrettyString()}), " + . "it requires: $constraint." + , + 'type' => 'incompatible-php', + ]; + } + } else { + // add other platform dependencies here + throw new UnexpectedValueException( 'Dependency type ' . $dependency . + ' unknown in ' . $extension ); + } + } + break; case 'extensions': case 'skins': foreach ( $values as $dependency => $constraint ) { @@ -138,29 +195,27 @@ class VersionChecker { } /** - * Handle a dependency to MediaWiki core. It will check, if a MediaWiki version constraint was - * set with self::setCoreVersion before this call (if not, it will return an empty array) and - * checks the version constraint given against it. + * Handle a simple dependency to MediaWiki core or PHP. See handleMediaWikiDependency and + * handlePhpDependency for details. * + * @param Constraint|bool $version The version installed * @param string $constraint The required version constraint for this dependency * @param string $checkedExt The Extension, which depends on this dependency - * @return bool|string false if no error, or a string with the message + * @return bool false if no error, true else */ - private function handleMediaWikiDependency( $constraint, $checkedExt ) { - if ( $this->coreVersion === false ) { - // Couldn't parse the core version, so we can't check anything + private function handleDependency( $version, $constraint, $checkedExt ) { + if ( $version === false ) { + // Couldn't parse the version, so we can't check anything return false; } // if the installed and required version are compatible, return an empty array if ( $this->versionParser->parseConstraints( $constraint ) - ->matches( $this->coreVersion ) ) { + ->matches( $version ) ) { return false; } - // otherwise mark this as incompatible. - return "{$checkedExt} is not compatible with the current " - . "MediaWiki core (version {$this->coreVersion->getPrettyString()}), it requires: " - . "$constraint."; + + return true; } /** diff --git a/tests/phpunit/includes/registration/ExtensionProcessorTest.php b/tests/phpunit/includes/registration/ExtensionProcessorTest.php index d9e091dc8d..71a3a4fa80 100644 --- a/tests/phpunit/includes/registration/ExtensionProcessorTest.php +++ b/tests/phpunit/includes/registration/ExtensionProcessorTest.php @@ -678,6 +678,9 @@ class ExtensionProcessorTest extends MediaWikiTestCase { $info = self::$default + [ 'requires' => [ 'MediaWiki' => '>= 1.25.0', + 'platform' => [ + 'php' => '>= 5.5.9' + ], 'extensions' => [ 'Bar' => '*' ] diff --git a/tests/phpunit/includes/registration/VersionCheckerTest.php b/tests/phpunit/includes/registration/VersionCheckerTest.php index b668a9adb0..20f97bf581 100644 --- a/tests/phpunit/includes/registration/VersionCheckerTest.php +++ b/tests/phpunit/includes/registration/VersionCheckerTest.php @@ -9,10 +9,10 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase { use PHPUnit4And6Compat; /** - * @dataProvider provideCheck + * @dataProvider provideMediaWikiCheck */ - public function testCheck( $coreVersion, $constraint, $expected ) { - $checker = new VersionChecker( $coreVersion ); + public function testMediaWikiCheck( $coreVersion, $constraint, $expected ) { + $checker = new VersionChecker( $coreVersion, '7.0.0' ); $this->assertEquals( $expected, !(bool)$checker->checkArray( [ 'FakeExtension' => [ 'MediaWiki' => $constraint, @@ -20,7 +20,7 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase { ] ) ); } - public static function provideCheck() { + public static function provideMediaWikiCheck() { return [ // [ $wgVersion, constraint, expected ] [ '1.25alpha', '>= 1.26', false ], @@ -44,11 +44,64 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase { ]; } + /** + * @dataProvider providePhpValidCheck + */ + public function testPhpValidCheck( $phpVersion, $constraint, $expected ) { + $checker = new VersionChecker( '1.0.0', $phpVersion ); + $this->assertEquals( $expected, !(bool)$checker->checkArray( [ + 'FakeExtension' => [ + 'platform' => [ + 'php' => $constraint, + ], + ], + ] ) ); + } + + public static function providePhpValidCheck() { + return [ + // [ phpVersion, constraint, expected ] + [ '7.0.23', '>= 7.0.0', true ], + [ '7.0.23', '^7.1.0', false ], + [ '7.0.23', '7.0.23', true ], + ]; + } + + /** + * @expectedException UnexpectedValueException + */ + public function testPhpInvalidConstraint() { + $checker = new VersionChecker( '1.0.0', '7.0.0' ); + $checker->checkArray( [ + 'FakeExtension' => [ + 'platform' => [ + 'php' => 'totallyinvalid', + ], + ], + ] ); + } + + /** + * @dataProvider providePhpInvalidVersion + * @expectedException UnexpectedValueException + */ + public function testPhpInvalidVersion( $phpVersion ) { + $checker = new VersionChecker( '1.0.0', $phpVersion ); + } + + public static function providePhpInvalidVersion() { + return [ + // [ phpVersion ] + [ '7.abc' ], + [ '5.a.x' ], + ]; + } + /** * @dataProvider provideType */ public function testType( $given, $expected ) { - $checker = new VersionChecker( '1.0.0' ); + $checker = new VersionChecker( '1.0.0', '7.0.0' ); $checker->setLoadedExtensionsAndSkins( [ 'FakeDependency' => [ 'version' => '1.0.0', @@ -150,7 +203,7 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase { * returns any error message. */ public function testInvalidConstraint() { - $checker = new VersionChecker( '1.0.0' ); + $checker = new VersionChecker( '1.0.0', '7.0.0' ); $checker->setLoadedExtensionsAndSkins( [ 'FakeDependency' => [ 'version' => 'not really valid', @@ -169,7 +222,7 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase { ], ] ) ); - $checker = new VersionChecker( '1.0.0' ); + $checker = new VersionChecker( '1.0.0', '7.0.0' ); $checker->setLoadedExtensionsAndSkins( [ 'FakeDependency' => [ 'version' => '1.24.3', @@ -184,24 +237,49 @@ class VersionCheckerTest extends PHPUnit\Framework\TestCase { ] ); } - /** - * T197478 - */ - public function testInvalidDependency() { - $checker = new VersionChecker( '1.0.0' ); - $this->setExpectedException( UnexpectedValueException::class, - 'Dependency type skin unknown in FakeExtension' ); - $this->assertEquals( [ + public function provideInvalidDependency() { + return [ [ - 'type' => 'invalid-version', - 'msg' => 'FakeDependency does not have a valid version string.', + [ + 'FakeExtension' => [ + 'platform' => [ + 'undefinedPlatformDependency' => '*', + ], + ], + ], + 'undefinedPlatformDependency', ], - ], $checker->checkArray( [ - 'FakeExtension' => [ - 'skin' => [ - 'FakeSkin' => '*', + [ + [ + 'FakeExtension' => [ + 'undefinedDependencyType' => '*', + ], ], + 'undefinedDependencyType', ], - ] ) ); + // T197478 + [ + [ + 'FakeExtension' => [ + 'skin' => [ + 'FakeSkin' => '*', + ], + ], + ], + 'skin', + ], + ]; + } + + /** + * @dataProvider provideInvalidDependency + */ + public function testInvalidDependency( $depencency, $type ) { + $checker = new VersionChecker( '1.0.0', '7.0.0' ); + $this->setExpectedException( + UnexpectedValueException::class, + "Dependency type $type unknown in FakeExtension" + ); + $checker->checkArray( $depencency ); } }