Paladox has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/184689

Change subject: Add SkinCredits
......................................................................

Add SkinCredits

* This adds SkinCredits for skins. It replaces ExtensionCredits for skins.

* There is backword compatibility so that authors have time to change there 
extension to use the new SkinCredits. With SkinCredits it deprecates skin in 
ExtensionTypes and Deprecates the use of ExtensionCredits for skins. 
SkinCredits also gets more information in skin simler to what the extension 
shows just that it is for skins.

Note this has been tested.

Change-Id: Ica0a9eccad7644460a3c63b184c09126303f25d2
---
M includes/DefaultSettings.php
M includes/api/ApiQuerySiteinfo.php
M includes/specials/SpecialVersion.php
3 files changed, 447 insertions(+), 12 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core 
refs/changes/89/184689/1

diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php
index ee462d8..de92165 100644
--- a/includes/DefaultSettings.php
+++ b/includes/DefaultSettings.php
@@ -6355,6 +6355,60 @@
 $wgExtensionCredits = array();
 
 /**
+ * An array of information about installed skins keyed by their type.
+ *
+ * All but 'name', 'path' and 'author' can be omitted.
+ *
+ * @code
+ * $wgSkinCredits[$type][] = array(
+ *     'path' => __FILE__,
+ *     'name' => 'Example skin',
+ *     'namemsg' => 'exampleskin-name',
+ *     'author' => array(
+ *         'Foo Barstein',
+ *     ),
+ *     'version' => '1.9.0',
+ *     'url' => 'http://example.org/example-skin/',
+ *     'descriptionmsg' => 'exampleskin-desc',
+ *     'license-name' => 'GPL-2.0',
+ * );
+ * @endcode
+ *
+ * The extensions are listed on Special:Version. This page also looks for a 
file
+ * named COPYING or LICENSE (optional .txt extension) and provides a link to
+ * view said file. When the 'license-name' key is specified, this file is
+ * interpreted as wikitext.
+ *
+ * - $type: One of 'skin', 
+ *    or any additional types as specified through the
+ *    SkinTypes hook as used in SpecialVersion::getSkinTypes().
+ *
+ * - name: Name of skin as an inline string instead of localizable message.
+ *    Do not omit this even if 'namemsg' is provided, as it is used to override
+ *    the path Special:Version uses to find skin's license info, and is
+ *    required for backwards-compatibility with MediaWiki 1.23 and older.
+ *
+ * - namemsg (since MW 1.24): A message key for a message containing the
+ *    skin's name, if the name is localizable. (For example, skin names
+ *    usually are.)
+ *
+ * - author: A string or an array of strings. Authors can be linked using
+ *    the regular wikitext link syntax. To have an internationalized version of
+ *    "and others" show, add an element "...". This element can also be linked,
+ *    for instance "[http://example ...]".
+ *
+ * - descriptionmsg: A message key or an an array with message key and 
parameters:
+ *    `'descriptionmsg' => 'exampleskin-desc',`
+ *
+ * - description: Description of skin as an inline string instead of
+ *    localizable message (omit in favour of 'descriptionmsg').
+ *
+ * - license-name: Short name of the license (used as label for the link), such
+ *   as "GPL-2.0" or "MIT" (https://spdx.org/licenses/ for a list of 
identifiers).
+ */
+$wgSkinCredits = array();
+
+/**
  * Authentication plugin.
  * @var $wgAuth AuthPlugin
  */
diff --git a/includes/api/ApiQuerySiteinfo.php 
b/includes/api/ApiQuerySiteinfo.php
index f373021..138dd68 100644
--- a/includes/api/ApiQuerySiteinfo.php
+++ b/includes/api/ApiQuerySiteinfo.php
@@ -690,11 +690,107 @@
                return $this->getResult()->addValue( 'query', $property, $data 
);
        }
 
+
+
        public function appendSkins( $property ) {
                $data = array();
                $allowed = Skin::getAllowedSkins();
                $default = Skin::normalizeKey( 'default' );
+               foreach ( $this->getConfig()->get( 'SkinCredits' ) as $type => 
$skins ) {
+                       foreach ( $skins as $skin ) {
+                               $ret = array();
+                               $ret['type'] = $type;
+                               if ( isset( $skin['name'] ) ) {
+                                       $ret['name'] = $skin['name'];
+                               }
+                               if ( isset( $skin['namemsg'] ) ) {
+                                       $ret['namemsg'] = $skin['namemsg'];
+                               }
+                               if ( isset( $skin['description'] ) ) {
+                                       $ret['description'] = 
$skin['description'];
+                               }
+                               if ( isset( $skin['descriptionmsg'] ) ) {
+                                       // Can be a string or array( key, 
param1, param2, ... )
+                                       if ( is_array( $skin['descriptionmsg'] 
) ) {
+                                               $ret['descriptionmsg'] = 
$skin['descriptionmsg'][0];
+                                               $ret['descriptionmsgparams'] = 
array_slice( $skin['descriptionmsg'], 1 );
+                                               
$this->getResult()->setIndexedTagName( $ret['descriptionmsgparams'], 'param' );
+                                       } else {
+                                               $ret['descriptionmsg'] = 
$skin['descriptionmsg'];
+                                       }
+                               }
+                               if ( isset( $skin['author'] ) ) {
+                                       $ret['author'] = is_array( 
$skin['author'] ) ?
+                                               implode( ', ', $skin['author'] 
) : $skin['author'];
+                               }
+                               if ( isset( $skin['url'] ) ) {
+                                       $ret['url'] = $skin['url'];
+                               }
+                               if ( isset( $skin['version'] ) ) {
+                                       $ret['version'] = $skin['version'];
+                               } elseif ( isset( $skin['svn-revision'] ) &&
+                                       preg_match( 
'/\$(?:Rev|LastChangedRevision|Revision): *(\d+)/',
+                                               $skin['svn-revision'], $m )
+                               ) {
+                                       $ret['version'] = 'r' . $m[1];
+                               }
+                               if ( isset( $skin['path'] ) ) {
+                                       $skinPath = dirname( $skin['path'] );
+                                       $gitInfo = new GitInfo( $skinPath );
+                                       $vcsVersion = $gitInfo->getHeadSHA1();
+                                       if ( $vcsVersion !== false ) {
+                                               $ret['vcs-system'] = 'git';
+                                               $ret['vcs-version'] = 
$vcsVersion;
+                                               $ret['vcs-url'] = 
$gitInfo->getHeadViewUrl();
+                                               $vcsDate = 
$gitInfo->getHeadCommitDate();
+                                               if ( $vcsDate !== false ) {
+                                                       $ret['vcs-date'] = 
wfTimestamp( TS_ISO_8601, $vcsDate );
+                                               }
+                                       } else {
+                                               $svnInfo = 
SpecialVersion::getSvnInfo( $skinPath );
+                                               if ( $svnInfo !== false ) {
+                                                       $ret['vcs-system'] = 
'svn';
+                                                       $ret['vcs-version'] = 
$svnInfo['checkout-rev'];
+                                                       $ret['vcs-url'] = 
isset( $svnInfo['viewvc-url'] ) ? $svnInfo['viewvc-url'] : '';
+                                               }
+                                       }
+
+                                       if ( 
SpecialVersion::getExtLicenseFileName( $skinPath ) ) {
+                                               $ret['license-name'] = isset( 
$skin['license-name'] ) ? $skin['license-name'] : '';
+                                               $ret['license'] = 
SpecialPage::getTitleFor(
+                                                       'Version',
+                                                       "License/{$ext['name']}"
+                                               )->getLinkURL();
+                                       }
+
+                                       if ( 
SpecialVersion::getExtAuthorsFileName( $skinPath ) ) {
+                                               $ret['credits'] = 
SpecialPage::getTitleFor(
+                                                       'Version',
+                                                       "Credits/{$ext['name']}"
+                                               )->getLinkURL();
+                                       }
+                               }
+                               if ( !isset( $allowed[$name] ) ) {
+                                       $skin['unusable'] = '';
+                               }
+                       if ( $type === $default ) { 
+                               $ret['default'] = ''; 
+                       }
+                               $data[] = $ret;
+                       }
+               }
+
+               /*
+                * This is here for backward compatibility.
+                * This is deprecated since MediaWiki 1.25
+                * @deprecated since 1.25 Use SkinCredits
+                */
+               wfDeprecated( __METHOD__, '1.25' );
+        if ( is_callable( $GLOBALS['wgExtensionCredits']['skin'] ) ); {
+               echo $GLOBALS['wgExtensionCredits']['skin'];
+
                foreach ( Skin::getSkinNames() as $name => $displayName ) {
+
                        $msg = $this->msg( "skinname-{$name}" );
                        $code = $this->getParameter( 'inlanguagecode' );
                        if ( $code && Language::isValidCode( $code ) ) {
@@ -706,8 +802,8 @@
                                $displayName = $msg->text();
                        }
                        $skin = array( 'code' => $name );
-                       ApiResult::setContent( $skin, $displayName );
-                       if ( !isset( $allowed[$name] ) ) {
+                       ApiResult::setContent( $skin, $displayName ); 
+                       if ( !isset( $allowed[$name] ) ) { 
                                $skin['unusable'] = '';
                        }
                        if ( $name === $default ) {
@@ -715,6 +811,8 @@
                        }
                        $data[] = $skin;
                }
+       }
+
                $this->getResult()->setIndexedTagName( $data, 'skin' );
 
                return $this->getResult()->addValue( 'query', $property, $data 
);
diff --git a/includes/specials/SpecialVersion.php 
b/includes/specials/SpecialVersion.php
index 2aa629e..67e62b0 100644
--- a/includes/specials/SpecialVersion.php
+++ b/includes/specials/SpecialVersion.php
@@ -38,6 +38,8 @@
 
        protected static $extensionTypes = false;
 
+       protected static $skinTypes = false;
+
        protected static $viewvcUrls = array(
                'svn+ssh://svn.wikimedia.org/svnroot/mediawiki' => 
'http://svn.wikimedia.org/viewvc/mediawiki',
                'http://svn.wikimedia.org/svnroot/mediawiki' => 
'http://svn.wikimedia.org/viewvc/mediawiki',
@@ -53,7 +55,7 @@
         * @param string|null $par
         */
        public function execute( $par ) {
-               global $IP, $wgExtensionCredits;
+               global $IP, $wgExtensionCredits, $wgSkinCredits;
 
                $this->setHeaders();
                $this->outputHeader();
@@ -74,6 +76,15 @@
                                        }
                                }
                        }
+                       foreach ( $wgSkinCredits as $group => $skins ) {
+                               foreach ( $skins as $skin ) {
+                                       if ( isset( $skin['name'] ) && ( 
$skin['name'] === $extName ) ) {
+                                               $extNode = &$skin;
+                                               break 2;
+                                       }
+                               }
+                       }
+
                        if ( !$extNode ) {
                                $out->setStatusCode( 404 );
                        }
@@ -288,6 +299,7 @@
         */
        public static function getVersionLinked() {
                global $wgVersion;
+               wfProfileIn( __METHOD__ );
 
                $gitVersion = self::getVersionLinkedGit();
                if ( $gitVersion ) {
@@ -392,6 +404,7 @@
                                'variable' => wfMessage( 'version-variables' 
)->text(),
                                'media' => wfMessage( 'version-mediahandlers' 
)->text(),
                                'antispam' => wfMessage( 'version-antispam' 
)->text(),
+                               /* @deprecated since 1.25 please use 
SkinCredits and then skin */
                                'skin' => wfMessage( 'version-skins' )->text(),
                                'api' => wfMessage( 'version-api' )->text(),
                                'other' => wfMessage( 'version-other' )->text(),
@@ -401,6 +414,28 @@
                }
 
                return self::$extensionTypes;
+       }
+
+       /**
+        * Returns an array with the base skin types.
+        * Type is stored as array key, the message as array value.
+        *
+        * TODO: ideally this would return all extension types.
+        *
+        * @since 1.25
+        *
+        * @return array
+        */
+       public static function getSkinTypes() {
+               if ( self::$skinTypes === false ) {
+                       self::$skinTypes = array(
+                               'skin' => wfMessage( 'version-skins' )->text(),
+                       );
+
+                       Hooks::run( 'SkinTypes', array( &self::$skinTypes ) );
+               }
+
+               return self::$skinTypes;
        }
 
        /**
@@ -419,6 +454,21 @@
        }
 
        /**
+        * Returns the internationalized name for an extension type.
+        *
+        * @since 1.25
+        *
+        * @param string $type
+        *
+        * @return string
+        */
+       public static function getSkinTypeName( $type ) {
+               $types = self::getSkinTypes();
+
+               return isset( $types[$type] ) ? $types[$type] : $types['other'];
+       }
+
+       /**
         * Generate wikitext showing the name, URL, author and description of 
each extension.
         *
         * @return string Wikitext
@@ -426,10 +476,7 @@
        public function getExtensionCredits() {
                global $wgExtensionCredits;
 
-               if (
-                       count( $wgExtensionCredits ) === 0 ||
-                       // Skins are displayed separately, see getSkinCredits()
-                       ( count( $wgExtensionCredits ) === 1 && isset( 
$wgExtensionCredits['skin'] ) )
+               if ( !count( $wgExtensionCredits ) 
                ) {
                        return '';
                }
@@ -473,15 +520,20 @@
        }
 
        /**
-        * Generate wikitext showing the name, URL, author and description of 
each skin.
+        * Generate wikitext showing the name, URL, author and description of 
each extension.
         *
         * @return string Wikitext
         */
        public function getSkinCredits() {
-               global $wgExtensionCredits;
-               if ( !isset( $wgExtensionCredits['skin'] ) || count( 
$wgExtensionCredits['skin'] ) === 0 ) {
+               global $wgSkinCredits;
+
+               if ( !count( $wgSkinCredits ) 
+               ) {
                        return '';
                }
+
+
+               $skinTypes = self::getSkinTypes();
 
                $out = Xml::element(
                                'h2',
@@ -491,7 +543,10 @@
                        Xml::openElement( 'table', array( 'class' => 'wikitable 
plainlinks', 'id' => 'sv-skin' ) );
 
                $this->firstExtOpened = false;
+
+               // We want the 'other' type to be last in the list.
                $out .= $this->getExtensionCategory( 'skin', null );
+               $out .= $this->getSkinCategory( 'skin', null);
 
                $out .= Xml::closeElement( 'table' );
 
@@ -636,6 +691,34 @@
        }
 
        /**
+        * Creates and returns the HTML for a single extension category.
+        *
+        * @since 1.17
+        *
+        * @param string $type
+        * @param string $message
+        *
+        * @return string
+        */
+       protected function getSkinCategory( $type, $message ) {
+               global $wgSkinCredits;
+
+               $out = '';
+
+               if ( array_key_exists( $type, $wgSkinCredits ) && count( 
$wgSkinCredits[$type] ) > 0 ) {
+                       $out .= $this->openExtType( $message, 'credits-' . 
$type );
+
+                       usort( $wgSkinCredits[$type], array( $this, 'compare' ) 
);
+
+                       foreach ( $wgSkinCredits[$type] as $skin ) {
+                               $out .= $this->getCreditsForSkin( $skin );
+                       }
+               }
+
+               return $out;
+       }
+
+       /**
         * Callback to sort extensions by type.
         * @param array $a
         * @param array $b
@@ -728,7 +811,7 @@
                        list( $vcsVersion, $vcsLink, $vcsDate ) = $cache->get( 
$memcKey );
 
                        if ( !$vcsVersion ) {
-                               wfDebug( "Getting VCS info for extension 
{$extension['name']}" );
+                               wfDebug( "Getting VCS info for extension 
$extensionName" );
                                $gitInfo = new GitInfo( $extensionPath );
                                $vcsVersion = $gitInfo->getHeadSHA1();
                                if ( $vcsVersion !== false ) {
@@ -744,7 +827,7 @@
                                }
                                $cache->set( $memcKey, array( $vcsVersion, 
$vcsLink, $vcsDate ), 60 * 60 * 24 );
                        } else {
-                               wfDebug( "Pulled VCS info for extension 
{$extension['name']} from cache" );
+                               wfDebug( "Pulled VCS info for extension 
$extensionName from cache" );
                        }
                }
 
@@ -852,6 +935,206 @@
        }
 
        /**
+        * Creates and formats a version line for a single extension.
+        *
+        * Information for five columns will be created. Parameters required in 
the
+        * $extension array for part rendering are indicated in ()
+        *  - The name of (name), and URL link to (url), the extension
+        *  - Official version number (version) and if available version 
control system
+        *    revision (path), link, and date
+        *  - If available the short name of the license (license-name) and a 
linke
+        *    to ((LICENSE)|(COPYING))(\.txt)? if it exists.
+        *  - Description of extension (descriptionmsg or description)
+        *  - List of authors (author) and link to a 
((AUTHORS)|(CREDITS))(\.txt)? file if it exists
+        *
+        * @param array $extension
+        *
+        * @return string Raw HTML
+        */
+       public function getCreditsForSkin( array $skin ) {
+               $out = $this->getOutput();
+
+               // We must obtain the information for all the bits and pieces!
+               // ... such as extension names and links
+               if ( isset( $skin['namemsg'] ) ) {
+                       // Localized name of extension
+                       $skinName = $this->msg( $skin['namemsg'] )->text();
+               } elseif ( isset( $skin['name'] ) ) {
+                       // Non localized version
+                       $skinName = $skin['name'];
+               } else {
+                       $skinName = $this->msg( 'version-no-skin-name' 
)->text();
+               }
+
+               if ( isset( $skin['url'] ) ) {
+                       $skinNameLink = Linker::makeExternalLink(
+                               $skin['url'],
+                               $skinName,
+                               true,
+                               '',
+                               array( 'class' => 'mw-version-mediawiki-name' )
+                       );
+               } else {
+                       $skinNameLink = $skinName;
+               }
+
+               // ... and the version information
+               // If the extension path is set we will check that directory 
for GIT and SVN
+               // metadata in an attempt to extract date and vcs commit 
metadata.
+               $canonicalVersion = '–';
+               $skinPath = null;
+               $vcsVersion = null;
+               $vcsLink = null;
+               $vcsDate = null;
+
+               if ( isset( $skin['version'] ) ) {
+                       $canonicalVersion = $out->parseInline( $skin['version'] 
);
+               }
+
+               if ( isset( $skin['path'] ) ) {
+                       global $IP;
+                       $skinPath = dirname( $skin['path'] );
+                       if ( $this->coreId == '' ) {
+                               wfDebug( 'Looking up core head id' );
+                               $coreHeadSHA1 = self::getGitHeadSha1( $IP );
+                               if ( $coreHeadSHA1 ) {
+                                       $this->coreId = $coreHeadSHA1;
+                               } else {
+                                       $svnInfo = self::getSvnInfo( $IP );
+                                       if ( $svnInfo !== false ) {
+                                               $this->coreId = 
$svnInfo['checkout-rev'];
+                                       }
+                               }
+                       }
+                       $cache = wfGetCache( CACHE_ANYTHING );
+                       $memcKey = wfMemcKey( 
'specialversion-skin-version-text', $skin['path'], $this->coreId );
+                       list( $vcsVersion, $vcsLink, $vcsDate ) = $cache->get( 
$memcKey );
+
+                       if ( !$vcsVersion ) {
+                               wfDebug( "Getting VCS info for skin $skinName" 
);
+                               $gitInfo = new GitInfo( $skinPath );
+                               $vcsVersion = $gitInfo->getHeadSHA1();
+                               if ( $vcsVersion !== false ) {
+                                       $vcsVersion = substr( $vcsVersion, 0, 7 
);
+                                       $vcsLink = $gitInfo->getHeadViewUrl();
+                                       $vcsDate = 
$gitInfo->getHeadCommitDate();
+                               } else {
+                                       $svnInfo = self::getSvnInfo( $skinPath 
);
+                                       if ( $svnInfo !== false ) {
+                                               $vcsVersion = $this->msg( 
'version-svn-revision', $svnInfo['checkout-rev'] )->text();
+                                               $vcsLink = isset( 
$svnInfo['viewvc-url'] ) ? $svnInfo['viewvc-url'] : '';
+                                       }
+                               }
+                               $cache->set( $memcKey, array( $vcsVersion, 
$vcsLink, $vcsDate ), 60 * 60 * 24 );
+                       } else {
+                               wfDebug( "Pulled VCS info for skin $skinName 
from cache" );
+                       }
+               }
+
+               $versionString = Html::rawElement(
+                       'span',
+                       array( 'class' => 'mw-version-skin-version' ),
+                       $canonicalVersion
+               );
+
+               if ( $vcsVersion ) {
+                       if ( $vcsLink ) {
+                               $vcsVerString = Linker::makeExternalLink(
+                                       $vcsLink,
+                                       $this->msg( 'version-version', 
$vcsVersion ),
+                                       true,
+                                       '',
+                                       array( 'class' => 
'mw-version-skin-vcs-version' )
+                               );
+                       } else {
+                               $vcsVerString = Html::element( 'span',
+                                       array( 'class' => 
'mw-version-skin-vcs-version' ),
+                                       "({$vcsVersion})"
+                               );
+                       }
+                       $versionString .= " {$vcsVerString}";
+
+                       if ( $vcsDate ) {
+                               $vcsTimeString = Html::element( 'span',
+                                       array( 'class' => 
'mw-version-skin-vcs-timestamp' ),
+                                       $this->getLanguage()->timeanddate( 
$vcsDate, true )
+                               );
+                               $versionString .= " {$vcsTimeString}";
+                       }
+                       $versionString = Html::rawElement( 'span',
+                               array( 'class' => 
'mw-version-skin-meta-version' ),
+                               $versionString
+                       );
+               }
+
+               // ... and license information; if a license file exists we
+               // will link to it
+               $licenseLink = '';
+               if ( isset( $skin['name'] ) ) {
+                       $licenseName = null;
+                       if ( isset( $skin['license-name'] ) ) {
+                               $licenseName = $out->parseInline( 
$skin['license-name'] );
+                       } elseif ( $this->getExtLicenseFileName( $extensionPath 
) ) {
+                               $licenseName = $this->msg( 
'version-ext-license' );
+                       }
+                       if ( $licenseName !== null ) {
+                               $licenseLink = Linker::link(
+                                       $this->getPageTitle( 'License/' . 
$skin['name'] ),
+                                       $licenseName,
+                                       array(
+                                               'class' => 
'mw-version-skin-license',
+                                               'dir' => 'auto',
+                                       )
+                               );
+                       }
+               }
+
+               // ... and generate the description; which can be a 
parameterized l10n message
+               // in the form array( <msgname>, <parameter>, <parameter>... ) 
or just a straight
+               // up string
+               if ( isset( $skin['descriptionmsg'] ) ) {
+                       // Localized description of extension
+                       $descriptionMsg = $skin['descriptionmsg'];
+
+                       if ( is_array( $descriptionMsg ) ) {
+                               $descriptionMsgKey = $descriptionMsg[0]; // Get 
the message key
+                               array_shift( $descriptionMsg ); // Shift out 
the message key to get the parameters only
+                               array_map( "htmlspecialchars", $descriptionMsg 
); // For sanity
+                               $description = $this->msg( $descriptionMsgKey, 
$descriptionMsg )->text();
+                       } else {
+                               $description = $this->msg( $descriptionMsg 
)->text();
+                       }
+               } elseif ( isset( $skin['description'] ) ) {
+                       // Non localized version
+                       $description = $skin['description'];
+               } else {
+                       $description = '';
+               }
+               $description = $out->parseInline( $description );
+
+               // ... now get the authors for this extension
+               $authors = isset( $skin['author'] ) ? $skin['author'] : array();
+               $authors = $this->listAuthors( $authors, $skin['name'], 
$skinPath );
+
+               // Finally! Create the table
+               $html = Html::openElement( 'tr', array(
+                               'class' => 'mw-version-skin',
+                               'id' => "mw-version-skin-{$skin['name']}"
+                       )
+               );
+
+               $html .= Html::rawElement( 'td', array(), $skinNameLink );
+               $html .= Html::rawElement( 'td', array(), $versionString );
+               $html .= Html::rawElement( 'td', array(), $licenseLink );
+               $html .= Html::rawElement( 'td', array( 'class' => 
'mw-version-skin-description' ), $description );
+               $html .= Html::rawElement( 'td', array( 'class' => 
'mw-version-skin-authors' ), $authors );
+
+               $html .= Html::closeElement( 'tr' );
+
+               return $html;
+       }
+
+       /**
         * Generate wikitext showing hooks in $wgHooks.
         *
         * @return string Wikitext

-- 
To view, visit https://gerrit.wikimedia.org/r/184689
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ica0a9eccad7644460a3c63b184c09126303f25d2
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Paladox <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to