Merge "registration: Add development requirements to extension.json"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Wed, 22 May 2019 21:41:48 +0000 (21:41 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Wed, 22 May 2019 21:41:48 +0000 (21:41 +0000)
docs/extension.schema.v1.json
docs/extension.schema.v2.json
includes/registration/ExtensionProcessor.php
includes/registration/ExtensionRegistry.php
includes/registration/Processor.php
tests/phpunit/includes/registration/ExtensionProcessorTest.php

index 32946d3..cf02f2b 100644 (file)
                                }
                        }
                },
+               "dev-requires": {
+                       "type": "object",
+                       "description": "Indicates what dependencies are required for development purposes such as running tests. This syntax may be extended in the future.",
+                       "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."
+                                               },
+                                               "ability-shell": {
+                                                       "type": "boolean",
+                                                       "default": false,
+                                                       "description": "Whether this extension requires shell access."
+                                               }
+                                       },
+                                       "patternProperties": {
+                                               "^ext-": {
+                                                       "type": "string",
+                                                       "description": "Required PHP extension.",
+                                                       "enum": ["*"]
+                                               }
+                                       }
+                               },
+                               "extensions": {
+                                       "type": "object",
+                                       "description": "Set of version constraint strings against specific extensions."
+                               },
+                               "skins": {
+                                       "type": "object",
+                                       "description": "Set of version constraint strings against specific skins."
+                               }
+                       }
+               },
                "ResourceFileModulePaths": {
                        "type": "object",
                        "description": "Default paths to use for all ResourceLoader file modules",
index 42b34b7..f29f850 100644 (file)
                                }
                        }
                },
+               "dev-requires": {
+                       "type": "object",
+                       "description": "Indicates what dependencies are required for development purposes such as running tests. This syntax may be extended in the future.",
+                       "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."
+                                               },
+                                               "ability-shell": {
+                                                       "type": "boolean",
+                                                       "default": false,
+                                                       "description": "Whether this extension requires shell access."
+                                               }
+                                       },
+                                       "patternProperties": {
+                                               "^ext-": {
+                                                       "type": "string",
+                                                       "description": "Required PHP extension.",
+                                                       "enum": ["*"]
+                                               }
+                                       }
+                               },
+                               "extensions": {
+                                       "type": "object",
+                                       "description": "Set of version constraint strings against specific extensions."
+                               },
+                               "skins": {
+                                       "type": "object",
+                                       "description": "Set of version constraint strings against specific skins."
+                               }
+                       }
+               },
                "ResourceFileModulePaths": {
                        "type": "object",
                        "description": "Default paths to use for all ResourceLoader file modules",
index b474ddc..faaaece 100644 (file)
@@ -304,8 +304,76 @@ class ExtensionProcessor implements Processor {
                ];
        }
 
-       public function getRequirements( array $info ) {
-               return $info['requires'] ?? [];
+       public function getRequirements( array $info, $includeDev ) {
+               // Quick shortcuts
+               if ( !$includeDev || !isset( $info['dev-requires'] ) ) {
+                       return $info['requires'] ?? [];
+               }
+
+               if ( !isset( $info['requires'] ) ) {
+                       return $info['dev-requires'] ?? [];
+               }
+
+               // OK, we actually have to merge everything
+               $merged = [];
+
+               // Helper that combines version requirements by
+               // picking the non-null if one is, or combines
+               // the two. Note that it is not possible for
+               // both inputs to be null.
+               $pick = function ( $a, $b ) {
+                       if ( $a === null ) {
+                               return $b;
+                       } elseif ( $b === null ) {
+                               return $a;
+                       } else {
+                               return "$a $b";
+                       }
+               };
+
+               $req = $info['requires'];
+               $dev = $info['dev-requires'];
+               if ( isset( $req['MediaWiki'] ) || isset( $dev['MediaWiki'] ) ) {
+                       $merged['MediaWiki'] = $pick(
+                               $req['MediaWiki'] ?? null,
+                               $dev['MediaWiki'] ?? null
+                       );
+               }
+
+               $platform = array_merge(
+                       array_keys( $req['platform'] ?? [] ),
+                       array_keys( $dev['platform'] ?? [] )
+               );
+               if ( $platform ) {
+                       foreach ( $platform as $pkey ) {
+                               if ( $pkey === 'php' ) {
+                                       $value = $pick(
+                                               $req['platform']['php'] ?? null,
+                                               $dev['platform']['php'] ?? null
+                                       );
+                               } else {
+                                       // Prefer dev value, but these should be constant
+                                       // anyways (ext-* and ability-*)
+                                       $value = $dev['platform'][$pkey] ?? $req['platform'][$pkey];
+                               }
+                               $merged['platform'][$pkey] = $value;
+                       }
+               }
+
+               foreach ( [ 'extensions', 'skins' ] as $thing ) {
+                       $things = array_merge(
+                               array_keys( $req[$thing] ?? [] ),
+                               array_keys( $dev[$thing] ?? [] )
+                       );
+                       foreach ( $things as $name ) {
+                               $merged[$thing][$name] = $pick(
+                                       $req[$thing][$name] ?? null,
+                                       $dev[$thing][$name] ?? null
+                               );
+                       }
+               }
+
+               return $merged;
        }
 
        protected function extractHooks( array $info ) {
index fb89731..768b488 100644 (file)
@@ -86,6 +86,13 @@ class ExtensionRegistry {
         */
        protected $testAttributes = [];
 
+       /**
+        * Whether to check dev-requires
+        *
+        * @var bool
+        */
+       protected $checkDev = false;
+
        /**
         * @var ExtensionRegistry
         */
@@ -103,6 +110,14 @@ class ExtensionRegistry {
                return self::$instance;
        }
 
+       /**
+        * @since 1.34
+        * @param bool $check
+        */
+       public function setCheckDevRequires( $check ) {
+               $this->checkDev = $check;
+       }
+
        /**
         * @param string $path Absolute path to the JSON file
         */
@@ -148,6 +163,7 @@ class ExtensionRegistry {
                        'registration' => self::CACHE_VERSION,
                        'mediawiki' => $wgVersion,
                        'abilities' => $this->getAbilities(),
+                       'checkDev' => $this->checkDev,
                ];
 
                // We use a try/catch because we don't want to fail here
@@ -295,7 +311,7 @@ class ExtensionRegistry {
                        }
 
                        // get all requirements/dependencies for this extension
-                       $requires = $processor->getRequirements( $info );
+                       $requires = $processor->getRequirements( $info, $this->checkDev );
 
                        // validate the information needed and add the requirements
                        if ( is_array( $requires ) && $requires && isset( $info['name'] ) ) {
index 68ba413..51cca36 100644 (file)
@@ -36,10 +36,11 @@ interface Processor {
         *
         * @since 1.26
         * @param array $info
+        * @param bool $includeDev
         * @return array Where keys are the name to have a constraint on,
         *              like 'MediaWiki'. Values are a constraint string like "1.26.1".
         */
-       public function getRequirements( array $info );
+       public function getRequirements( array $info, $includeDev );
 
        /**
         * Get the path for additional autoloaders, e.g. the one of Composer.
index d5a2b3a..cdd5c63 100644 (file)
@@ -717,11 +717,67 @@ class ExtensionProcessorTest extends MediaWikiTestCase {
                $processor = new ExtensionProcessor();
                $this->assertSame(
                        $info['requires'],
-                       $processor->getRequirements( $info )
+                       $processor->getRequirements( $info, false )
                );
                $this->assertSame(
                        [],
-                       $processor->getRequirements( [] )
+                       $processor->getRequirements( [], false )
+               );
+       }
+
+       public function testGetDevRequirements() {
+               $info = self::$default + [
+                       'dev-requires' => [
+                               'MediaWiki' => '>= 1.31.0',
+                               'platform' => [
+                                       'ext-foo' => '*',
+                               ],
+                               'skins' => [
+                                       'Baz' => '*',
+                               ],
+                               'extensions' => [
+                                       'Biz' => '*',
+                               ],
+                       ],
+               ];
+               $processor = new ExtensionProcessor();
+               $this->assertSame(
+                       $info['dev-requires'],
+                       $processor->getRequirements( $info, true )
+               );
+               // Set some standard requirements, so we can test merging
+               $info['requires'] = [
+                       'MediaWiki' => '>= 1.25.0',
+                       'platform' => [
+                               'php' => '>= 5.5.9'
+                       ],
+                       'extensions' => [
+                               'Bar' => '*'
+                       ]
+               ];
+               $this->assertSame(
+                       [
+                               'MediaWiki' => '>= 1.25.0 >= 1.31.0',
+                               'platform' => [
+                                       'php' => '>= 5.5.9',
+                                       'ext-foo' => '*',
+                               ],
+                               'extensions' => [
+                                       'Bar' => '*',
+                                       'Biz' => '*',
+                               ],
+                               'skins' => [
+                                       'Baz' => '*',
+                               ],
+                       ],
+                       $processor->getRequirements( $info, true )
+               );
+
+               // If there's no dev-requires, it just returns requires
+               unset( $info['dev-requires'] );
+               $this->assertSame(
+                       $info['requires'],
+                       $processor->getRequirements( $info, true )
                );
        }