jenkins-bot has submitted this change and it was merged.

Change subject: Update Wikidata - add usage tracking job
......................................................................


Update Wikidata - add usage tracking job

Change-Id: Ic377cad074a2fb53954f7db320b558b2ebc90098
---
M composer.lock
M extensions/Wikibase/.jscsrc
M extensions/Wikibase/client/WikibaseClient.php
M extensions/Wikibase/client/includes/Hooks/DataUpdateHookHandlers.php
M extensions/Wikibase/client/includes/Usage/EntityUsage.php
A extensions/Wikibase/client/includes/store/AddUsagesForPageJob.php
M extensions/Wikibase/client/includes/store/ClientStore.php
M extensions/Wikibase/client/includes/store/sql/DirectSqlStore.php
M extensions/Wikibase/client/tests/phpunit/MockClientStore.php
M 
extensions/Wikibase/client/tests/phpunit/includes/Hooks/DataUpdateHookHandlersTest.php
M extensions/Wikibase/client/tests/phpunit/includes/Usage/EntityUsageTest.php
A 
extensions/Wikibase/client/tests/phpunit/includes/store/AddUsagesForPageJobTest.php
M extensions/Wikibase/package.json
M 
extensions/Wikibase/view/resources/jquery/wikibase/jquery.wikibase.labelview.js
M 
extensions/Wikibase/view/tests/qunit/jquery/wikibase/jquery.wikibase.entitytermsforlanguageview.tests.js
M 
extensions/Wikibase/view/tests/qunit/jquery/wikibase/jquery.wikibase.labelview.tests.js
M vendor/composer/autoload_classmap.php
M vendor/composer/installed.json
18 files changed, 618 insertions(+), 151 deletions(-)

Approvals:
  Aude: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/composer.lock b/composer.lock
index 052b834..b9eb7f6 100644
--- a/composer.lock
+++ b/composer.lock
@@ -862,7 +862,7 @@
             "version": "dev-master",
             "source": {
                 "type": "git",
-                "url": "g...@github.com:wmde/Wikidata.org.git",
+                "url": "https://github.com/wmde/Wikidata.org.git";,
                 "reference": "9029d28d8aaeb65cd1338865183740b4be445fa5"
             },
             "dist": {
@@ -1276,7 +1276,7 @@
             "support": {
                 "issues": 
"https://phabricator.wikimedia.org/project/profile/989/";
             },
-            "time": "2015-06-30 17:53:04"
+            "time": "2015-06-30 13:02:17"
         },
         {
             "name": "wikibase/serialization-javascript",
@@ -1325,7 +1325,7 @@
             "source": {
                 "type": "git",
                 "url": 
"https://gerrit.wikimedia.org/r/p/mediawiki/extensions/Wikibase.git";,
-                "reference": "c81228d60966244c1f2db8623191a2ea28cbfe81"
+                "reference": "b73bc168435a1214956543d94ccfc00e8902a566"
             },
             "require": {
                 "data-values/common": "~0.2.0",
@@ -1403,14 +1403,14 @@
                 "issues": "https://phabricator.wikimedia.org/";,
                 "irc": "irc://irc.freenode.net/wikidata"
             },
-            "time": "2015-07-27 19:36:55"
+            "time": "2015-07-29 02:00:56"
         },
         {
             "name": "wikibase/wikimedia-badges",
             "version": "dev-master",
             "source": {
                 "type": "git",
-                "url": "g...@github.com:wmde/WikimediaBadges.git",
+                "url": "https://github.com/wmde/WikimediaBadges.git";,
                 "reference": "5cb28488f7791302cf6b835610f132b0b05915cf"
             },
             "dist": {
diff --git a/extensions/Wikibase/.jscsrc b/extensions/Wikibase/.jscsrc
index f66f6bd..312c030 100644
--- a/extensions/Wikibase/.jscsrc
+++ b/extensions/Wikibase/.jscsrc
@@ -3,12 +3,26 @@
        "preset": "wikimedia",
 
        // ----
-       // Rules from wikimedia preset we don't follow
+       // Rules from wikimedia preset we don't yet? follow
 
        "validateIndentation": null,
        "requireMultipleVarDecl": null,
        "disallowDanglingUnderscores": null,
-       "requireSpacesInsideArrayBrackets": null,
+       "requireSpacesInsideBrackets": null,
+       "requireVarDeclFirst": null,
+       "jsDoc": {
+               // what we don't yet follow is commented out
+               //"checkAnnotations": "jsduck5",
+               //"checkParamNames": true,
+               "requireParamTypes": true,
+               "checkRedundantParams": true,
+               //"checkReturnTypes": true,
+               "checkRedundantReturns": true,
+               //"requireReturnTypes": true,
+               //"checkTypes": "capitalizedNativeCase",
+               "checkRedundantAccess": true
+               //"requireNewlineAfterDescription": true
+       },
 
        // ----
        // Own rules
@@ -24,5 +38,5 @@
                "else"
        ],
 
-       "excludeFiles": [ "node_modules/**", "vendor/**" ]
+       "excludeFiles": [ "node_modules/**", "vendor/**", "extensions/**" ]
 }
diff --git a/extensions/Wikibase/client/WikibaseClient.php 
b/extensions/Wikibase/client/WikibaseClient.php
index 6fb840c..9a9ae33 100644
--- a/extensions/Wikibase/client/WikibaseClient.php
+++ b/extensions/Wikibase/client/WikibaseClient.php
@@ -67,6 +67,7 @@
        global $wgExtensionCredits, $wgExtensionMessagesFiles, $wgHooks;
        global $wgAPIMetaModules, $wgAPIPropModules, $wgSpecialPages, 
$wgResourceModules;
        global $wgWBClientSettings, $wgRecentChangesFlags, $wgMessagesDirs;
+       global $wgJobClasses;
 
        $wgExtensionCredits['wikibase'][] = array(
                'path' => __DIR__,
@@ -121,6 +122,9 @@
        // extension hooks
        $wgHooks['WikibaseDeleteData'][] = 
'\Wikibase\ClientHooks::onWikibaseDeleteData';
 
+       // job classes
+       $wgJobClasses['wikibase-addUsagesForPage'] = 
'Wikibase\Client\Store\AddUsagesForPageJob';
+
        // api modules
        $wgAPIMetaModules['wikibase'] = array(
                'class' => 'Wikibase\ApiClientInfo',
diff --git 
a/extensions/Wikibase/client/includes/Hooks/DataUpdateHookHandlers.php 
b/extensions/Wikibase/client/includes/Hooks/DataUpdateHookHandlers.php
index 8b12966..6776f65 100644
--- a/extensions/Wikibase/client/includes/Hooks/DataUpdateHookHandlers.php
+++ b/extensions/Wikibase/client/includes/Hooks/DataUpdateHookHandlers.php
@@ -3,6 +3,8 @@
 namespace Wikibase\Client\Hooks;
 
 use Content;
+use EnqueueJob;
+use JobQueueGroup;
 use LinksUpdate;
 use ManualLogEntry;
 use ParserCache;
@@ -10,6 +12,7 @@
 use ParserOutput;
 use Title;
 use User;
+use Wikibase\Client\Store\AddUsagesForPageJob;
 use Wikibase\Client\Store\UsageUpdater;
 use Wikibase\Client\Usage\ParserOutputUsageAccumulator;
 use Wikibase\Client\WikibaseClient;
@@ -34,19 +37,15 @@
         */
        private $usageUpdater;
 
+       /**
+        * @var JobQueueGroup
+        */
+       private $jobScheduler;
+
        public static function newFromGlobalState() {
-               $wikibaseClient = WikibaseClient::getDefaultInstance();
-               $settings = $wikibaseClient->getSettings();
-
-               $usageUpdater = new UsageUpdater(
-                       $settings->getSetting( 'siteGlobalID' ),
-                       $wikibaseClient->getStore()->getUsageTracker(),
-                       $wikibaseClient->getStore()->getUsageLookup(),
-                       $wikibaseClient->getStore()->getSubscriptionManager()
-               );
-
                return new DataUpdateHookHandlers(
-                       $usageUpdater
+                       
WikibaseClient::getDefaultInstance()->getStore()->getUsageUpdater(),
+                       JobQueueGroup::singleton()
                );
        }
 
@@ -113,9 +112,11 @@
        }
 
        public function __construct(
-               UsageUpdater $usageUpdater
+               UsageUpdater $usageUpdater,
+               JobQueueGroup $jobScheduler
        ) {
                $this->usageUpdater = $usageUpdater;
+               $this->jobScheduler = $jobScheduler;
        }
 
        /**
@@ -160,7 +161,7 @@
         * Implemented to update usage tracking information via UsageUpdater.
         *
         * @param ParserOutput $parserOutput
-        * @param $title $title
+        * @param Title $title
         */
        public function doParserCacheSaveComplete( ParserOutput $parserOutput, 
Title $title ) {
                $usageAcc = new ParserOutputUsageAccumulator( $parserOutput );
@@ -169,13 +170,24 @@
                // These timestamps should usually be the same, but asking 
$title may cause a database query.
                $touched = $parserOutput->getTimestamp() ?: 
$title->getTouched();
 
+               if ( count( $usageAcc->getUsages() ) === 0 ) {
+                       // no usages, bail out
+                       return;
+               }
+
                // Add or touch any usages present in the new rendering.
                // This allows us to track usages in each user language 
separately, for multilingual sites.
-               $this->usageUpdater->addUsagesForPage(
-                       $title->getArticleId(),
-                       $usageAcc->getUsages(),
-                       $touched
-               );
+
+               // NOTE: Since parser cache updates may be triggered by page 
views (in a new language),
+               // schedule the usage updates in the job queue, to avoid 
writing to the database
+               // during a GET request.
+
+               //TODO: Before posting a job, check slave database. If no 
changes are needed, skip update.
+
+               $addUsagesForPageJob = AddUsagesForPageJob::newSpec( $title, 
$usageAcc->getUsages(), $touched );
+               $enqueueJob = EnqueueJob::newFromLocalJobs( 
$addUsagesForPageJob );
+
+               $this->jobScheduler->lazyPush( $enqueueJob );
        }
 
        /**
diff --git a/extensions/Wikibase/client/includes/Usage/EntityUsage.php 
b/extensions/Wikibase/client/includes/Usage/EntityUsage.php
index 5876d7a..864efce 100644
--- a/extensions/Wikibase/client/includes/Usage/EntityUsage.php
+++ b/extensions/Wikibase/client/includes/Usage/EntityUsage.php
@@ -146,6 +146,17 @@
        }
 
        /**
+        * @return array array( 'entityId' => $entityId, 'aspect' => $aspect, 
'modifier' => $modifier )
+        */
+       public function asArray() {
+               return array(
+                       'entityId' => $this->entityId->getSerialization(),
+                       'aspect' => $this->aspect,
+                       'modifier' => $this->modifier
+               );
+       }
+
+       /**
         * @param string $aspectKey
         *
         * @return string One of the EntityUsage::..._USAGE constants with the 
modifier split off.
diff --git a/extensions/Wikibase/client/includes/store/AddUsagesForPageJob.php 
b/extensions/Wikibase/client/includes/store/AddUsagesForPageJob.php
new file mode 100644
index 0000000..335fd3e
--- /dev/null
+++ b/extensions/Wikibase/client/includes/store/AddUsagesForPageJob.php
@@ -0,0 +1,153 @@
+<?php
+
+namespace Wikibase\Client\Store;
+
+use Job;
+use JobSpecification;
+use Title;
+use Wikibase\Client\Usage\EntityUsage;
+use Wikibase\Client\WikibaseClient;
+use Wikibase\DataModel\Entity\EntityIdParser;
+use Wikimedia\Assert\Assert;
+
+/**
+ * Job for scheduled invocation of UsageUpdater::addUsagesForPage
+ *
+ * @license GPL 2+
+ * @author Daniel Kinzler
+ */
+class AddUsagesForPageJob extends Job {
+
+       /**
+        * @var integer
+        */
+       private $pageId;
+
+       /**
+        * @var EntityUsage[]
+        */
+       private $usages;
+
+       /**
+        * @var string timestamp
+        */
+       private $touched;
+
+       /**
+        * @var UsageUpdater
+        */
+       private $usageUpdater;
+
+       /**
+        * @var EntityIdParser $idParser
+        */
+       private $idParser;
+
+       /**
+        * Spec constructor, for creating JobSpecifications to be pushed to the 
job queue.
+        *
+        * @param Title $title
+        * @param EntityUsage[] $usages
+        * @param string $touched
+        *
+        * @return JobSpecification
+        */
+       public static function newSpec( Title $title, array $usages, $touched ) 
{
+               // NOTE: Map EntityUsage objects to scalar arrays, for JSON 
serialization in the job queue.
+               $usages = array_map( function ( EntityUsage $usage ) {
+                       return $usage->asArray();
+               }, $usages );
+
+               $jobParams = array(
+                       'pageId' => $title->getArticleId(),
+                       'usages' => $usages,
+                       'touched' => $touched
+               );
+
+               return new JobSpecification(
+                       'wikibase-addUsagesForPage',
+                       $jobParams,
+                       array( 'removeDuplicates' => true ),
+                       $title
+               );
+       }
+
+       /**
+        * @param Title $title
+        * @param array $params
+        */
+       public function __construct( Title $title, array $params ) {
+               parent::__construct( 'wikibase-addUsagesForPage', $title, 
$params );
+
+               Assert::parameter(
+                       isset( $params['pageId'] ) && is_int( $params['pageId'] 
) && $params['pageId'] > 0,
+                       '$params["pageId"]',
+                       'must be a positive integer' );
+
+               Assert::parameter(
+                       isset( $params['usages'] ) && is_array( 
$params['usages'] ) && !empty( $params['usages'] ),
+                       '$params["usages"]',
+                       'must be a non-empty array' );
+
+               Assert::parameter(
+                       isset( $params['touched'] ) && is_string( 
$params['touched'] ) && $params['touched'] !== '',
+                       '$params["touched"]',
+                       'must be a timestamp string' );
+
+               Assert::parameterElementType(
+                       'array',
+                       $params['usages'],
+                       '$params["usages"]' );
+
+               $this->pageId = $params['pageId'];
+               $this->usages = $params['usages'];
+               $this->touched = $params['touched'];
+
+               $usageUpdater = 
WikibaseClient::getDefaultInstance()->getStore()->getUsageUpdater();
+               $idParser = 
WikibaseClient::getDefaultInstance()->getEntityIdParser();
+               $this->overrideServices( $usageUpdater, $idParser );
+       }
+
+       /**
+        * Service override for testing
+        *
+        * @param UsageUpdater $usageUpdater
+        * @param EntityIdParser $idParser
+        */
+       public function overrideServices( UsageUpdater $usageUpdater, 
EntityIdParser $idParser ) {
+               $this->usageUpdater = $usageUpdater;
+               $this->idParser = $idParser;
+       }
+
+       /**
+        * @return EntityUsage[]
+        */
+       private function getUsages() {
+               // Turn serialized usage info into EntityUsage objects
+               $idParser = $this->idParser;
+               $usages = array_map( function ( array $usageArray ) use ( 
$idParser ) {
+                       // This is the inverse of EntityUsage::asArray()
+                       return new EntityUsage(
+                               $idParser->parse( $usageArray['entityId'] ),
+                               $usageArray['aspect'],
+                               $usageArray['modifier']
+                       );
+               }, $this->usages );
+
+               return $usages;
+       }
+
+       /**
+        * Call UsageUpdater::addUsagesForPage
+        *
+        * @return bool Success
+        */
+       public function run() {
+               $this->usageUpdater->addUsagesForPage(
+                       $this->pageId,
+                       $this->getUsages(),
+                       $this->touched
+               );
+       }
+
+}
diff --git a/extensions/Wikibase/client/includes/store/ClientStore.php 
b/extensions/Wikibase/client/includes/store/ClientStore.php
index 66b381a..51d052f 100644
--- a/extensions/Wikibase/client/includes/store/ClientStore.php
+++ b/extensions/Wikibase/client/includes/store/ClientStore.php
@@ -3,6 +3,7 @@
 namespace Wikibase;
 
 use MWException;
+use Wikibase\Client\Store\UsageUpdater;
 use Wikibase\Client\Usage\SubscriptionManager;
 use Wikibase\Client\Usage\UsageLookup;
 use Wikibase\Client\Usage\UsageTracker;
@@ -125,4 +126,11 @@
         */
        public function getEntityPrefetcher();
 
+       /**
+        * @since 0.5
+        *
+        * @return UsageUpdater
+        */
+       public function getUsageUpdater();
+
 }
diff --git a/extensions/Wikibase/client/includes/store/sql/DirectSqlStore.php 
b/extensions/Wikibase/client/includes/store/sql/DirectSqlStore.php
index dc4f311..80d42cf 100644
--- a/extensions/Wikibase/client/includes/store/sql/DirectSqlStore.php
+++ b/extensions/Wikibase/client/includes/store/sql/DirectSqlStore.php
@@ -7,6 +7,7 @@
 use Wikibase\Client\Store\Sql\ConsistentReadConnectionManager;
 use Wikibase\Client\Store\Sql\PagePropsEntityIdLookup;
 use Wikibase\Client\Store\TitleFactory;
+use Wikibase\Client\Store\UsageUpdater;
 use Wikibase\Client\Usage\NullSubscriptionManager;
 use Wikibase\Client\Usage\NullUsageTracker;
 use Wikibase\Client\Usage\SiteLinkUsageLookup;
@@ -464,4 +465,16 @@
                return $this->entityPrefetcher;
        }
 
+       /**
+        * @return UsageUpdater
+        */
+       public function getUsageUpdater() {
+               return new UsageUpdater(
+                       $this->siteId,
+                       $this->getUsageTracker(),
+                       $this->getUsageLookup(),
+                       $this->getSubscriptionManager()
+               );
+       }
+
 }
diff --git a/extensions/Wikibase/client/tests/phpunit/MockClientStore.php 
b/extensions/Wikibase/client/tests/phpunit/MockClientStore.php
index 1cef882..edf4f11 100644
--- a/extensions/Wikibase/client/tests/phpunit/MockClientStore.php
+++ b/extensions/Wikibase/client/tests/phpunit/MockClientStore.php
@@ -3,9 +3,13 @@
 namespace Wikibase\Test;
 
 use Wikibase\ChangesTable;
+use Wikibase\Client\Store\UsageUpdater;
 use Wikibase\Client\Usage\NullSubscriptionManager;
 use Wikibase\Client\Usage\NullUsageTracker;
 use Wikibase\ClientStore;
+use Wikibase\Lib\Store\EntityLookup;
+use Wikibase\Lib\Store\EntityPrefetcher;
+use Wikibase\Lib\Store\EntityRevisionLookup;
 use Wikibase\Lib\Store\NullEntityPrefetcher;
 use Wikibase\PropertyInfoStore;
 use Wikibase\Store\EntityIdLookup;
@@ -181,4 +185,18 @@
                return new NullEntityPrefetcher();
        }
 
+       /**
+        * @since 0.5
+        *
+        * @return UsageUpdater
+        */
+       public function getUsageUpdater() {
+               return new UsageUpdater(
+                       'mock',
+                       $this->getUsageTracker(),
+                       $this->getUsageLookup(),
+                       $this->getSubscriptionManager()
+               );
+       }
+
 }
diff --git 
a/extensions/Wikibase/client/tests/phpunit/includes/Hooks/DataUpdateHookHandlersTest.php
 
b/extensions/Wikibase/client/tests/phpunit/includes/Hooks/DataUpdateHookHandlersTest.php
index 744489f..ac761a8 100644
--- 
a/extensions/Wikibase/client/tests/phpunit/includes/Hooks/DataUpdateHookHandlersTest.php
+++ 
b/extensions/Wikibase/client/tests/phpunit/includes/Hooks/DataUpdateHookHandlersTest.php
@@ -2,6 +2,8 @@
 
 namespace Wikibase\Client\Tests\Hooks;
 
+use JobQueueGroup;
+use JobSpecification;
 use ParserOutput;
 use Title;
 use Wikibase\Client\Hooks\DataUpdateHookHandlers;
@@ -26,13 +28,20 @@
 
        /**
         * @param Title $title
-        * @param EntityUsage[]|null $expectedUsages
+        * @param array $expectedUsages
         * @param string|null $touched
-        * @param bool $prune
+        * @param bool $prune whether pruneUsagesForPage() should be used
+        * @param bool $add whether addUsagesForPage() should be used
         *
         * @return UsageUpdater
         */
-       private function newUsageUpdater( Title $title, array $expectedUsages = 
null, $touched = null, $prune = true ) {
+       private function newUsageUpdater(
+               Title $title,
+               array $expectedUsages = null,
+               $touched = null,
+               $prune = true,
+               $add = true
+       ) {
                $usageUpdater = $this->getMockBuilder( 
'Wikibase\Client\Store\UsageUpdater' )
                        ->disableOriginalConstructor()
                        ->getMock();
@@ -47,7 +56,7 @@
                // greater timestamp.
                $touchedMatcher = $this->greaterThanOrEqual( $touched );
 
-               if ( $expectedUsages === null ) {
+               if ( $expectedUsages === null || !$add ) {
                        $usageUpdater->expects( $this->never() )
                                ->method( 'addUsagesForPage' );
                } else {
@@ -70,17 +79,87 @@
 
        /**
         * @param Title $title
+        * @param array|null $expectedUsages
+        * @param string|null $touched
+        * @param bool $useJobQueue whether we expect the job queue to be used
+        *
+        * @return JobQueueGroup
+        */
+       private function newJobScheduler(
+               Title $title,
+               array $expectedUsages = null,
+               $touched = null,
+               $useJobQueue = false
+       ) {
+               $jobScheduler = $this->getMockBuilder( 'JobQueueGroup' )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+
+               if ( empty( $expectedUsages ) || !$useJobQueue ) {
+                       $jobScheduler->expects( $this->never() )
+                               ->method( 'lazyPush' );
+               } else {
+                       $expectedUsageArray = array_map( function ( EntityUsage 
$usage ) {
+                               return $usage->asArray();
+                       }, $expectedUsages );
+
+                       $params = array(
+                               'jobsByWiki' => array(
+                                       wfWikiID() => array(
+                                               array(
+                                                       'type' => 
'wikibase-addUsagesForPage',
+                                                       'params' => array(
+                                                               'pageId' => 
$title->getArticleID(),
+                                                               'usages' => 
$expectedUsageArray,
+                                                               'touched' => 
$touched
+                                                       ),
+                                                       'opts' => array(
+                                                               
'removeDuplicates' => true
+                                                       ),
+                                                       'title' => array(
+                                                               'ns' => NS_MAIN,
+                                                               'key' => 
'Oxygen'
+                                                       )
+                                               )
+                                       )
+                               )
+                       );
+
+                       $jobScheduler->expects( $this->once() )
+                               ->method( 'lazyPush' )
+                               ->with( $this->callback( function ( $job ) use 
( $params ) {
+                                       
DataUpdateHookHandlersTest::assertEquals( 'enqueue', $job->getType() );
+                                       
DataUpdateHookHandlersTest::assertEquals( $params, $job->getParams() );
+                                       return true;
+                               } ) );
+
+               }
+
+               return $jobScheduler;
+       }
+
+       /**
+        * @param Title $title
         * @param EntityUsage[]|null $expectedUsages
         * @param string|null $touched timestamp
-        * @param bool $prune
+        * @param bool $prune whether pruneUsagesForPage() should be used
+        * @param bool $asyncAdd whether addUsagesForPage() should be called 
via the job queue
         *
         * @return DataUpdateHookHandlers
         */
-       private function newDataUpdateHookHandlers( Title $title, array 
$expectedUsages = null, $touched = null, $prune = true ) {
-               $usageUpdater = $this->newUsageUpdater( $title, 
$expectedUsages, $touched, $prune );
+       private function newDataUpdateHookHandlers(
+               Title $title,
+               array $expectedUsages = null,
+               $touched = null,
+               $prune = true,
+               $asyncAdd = false
+       ) {
+               $usageUpdater = $this->newUsageUpdater( $title, 
$expectedUsages, $touched, $prune, !$asyncAdd );
+               $jobScheduler = $this->newJobScheduler( $title, 
$expectedUsages, $touched, $asyncAdd );
 
                return new DataUpdateHookHandlers(
-                       $usageUpdater
+                       $usageUpdater,
+                       $jobScheduler
                );
        }
 
@@ -164,7 +243,7 @@
                $linksUpdate = $this->newLinksUpdate( $title, $usage, 
$timestamp );
 
                // Assertions are done by the UsageUpdater mock
-               $handler = $this->newDataUpdateHookHandlers( $title, $usage, 
$timestamp, true );
+               $handler = $this->newDataUpdateHookHandlers( $title, $usage, 
$timestamp, true, false );
                $handler->doLinksUpdateComplete( $linksUpdate );
        }
 
@@ -178,7 +257,7 @@
                $parserOutput = $this->newParserOutput( $usage, $timestamp );
 
                // Assertions are done by the UsageUpdater mock
-               $handler = $this->newDataUpdateHookHandlers( $title, $usage, 
$timestamp, false );
+               $handler = $this->newDataUpdateHookHandlers( $title, $usage, 
$timestamp, false, true );
                $handler->doParserCacheSaveComplete( $parserOutput, $title );
        }
 
@@ -188,7 +267,7 @@
                $timestamp = '20150505000000';
 
                // Assertions are done by the UsageUpdater mock
-               $handler = $this->newDataUpdateHookHandlers( $title, null, 
$timestamp, true );
+               $handler = $this->newDataUpdateHookHandlers( $title, null, 
$timestamp, true, false );
                $handler->doArticleDeleteComplete( $title->getNamespace(), 
$title->getArticleID(), $timestamp );
        }
 
diff --git 
a/extensions/Wikibase/client/tests/phpunit/includes/Usage/EntityUsageTest.php 
b/extensions/Wikibase/client/tests/phpunit/includes/Usage/EntityUsageTest.php
index 1a20b61..48f9bc6 100644
--- 
a/extensions/Wikibase/client/tests/phpunit/includes/Usage/EntityUsageTest.php
+++ 
b/extensions/Wikibase/client/tests/phpunit/includes/Usage/EntityUsageTest.php
@@ -55,6 +55,25 @@
                $this->assertEquals( "$aspect.$modifier", 
$usage->getAspectKey() );
        }
 
+       public function testAsArray() {
+               $id = new ItemId( 'Q7' );
+               $aspect = EntityUsage::LABEL_USAGE;
+               $modifier = 'ru';
+
+               $expected = array(
+                       'entityId' => $id->getSerialization(),
+                       'aspect' => $aspect,
+                       'modifier' => null
+               );
+
+               $usage = new EntityUsage( $id, $aspect );
+               $this->assertEquals( $expected, $usage->asArray() );
+
+               $expected['modifier'] = $modifier;
+               $usage = new EntityUsage( $id, $aspect, $modifier );
+               $this->assertEquals( $expected, $usage->asArray() );
+       }
+
        public function aspectKeyProvider() {
                return array(
                        array( 'L', array( 'L', null ) ),
diff --git 
a/extensions/Wikibase/client/tests/phpunit/includes/store/AddUsagesForPageJobTest.php
 
b/extensions/Wikibase/client/tests/phpunit/includes/store/AddUsagesForPageJobTest.php
new file mode 100644
index 0000000..cb15661
--- /dev/null
+++ 
b/extensions/Wikibase/client/tests/phpunit/includes/store/AddUsagesForPageJobTest.php
@@ -0,0 +1,144 @@
+<?php
+
+namespace Wikibase\Client\Test\Store;
+
+use Title;
+use Wikibase\Client\Store\AddUsagesForPageJob;
+use Wikibase\Client\Usage\EntityUsage;
+use Wikibase\DataModel\Entity\BasicEntityIdParser;
+use Wikibase\DataModel\Entity\ItemId;
+
+/**
+ * @covers Wikibase\Client\Store\AddUsagesForPageJob
+ *
+ * @group Wikibase
+ * @group WikibaseClient
+ * @group WikibaseUsageTracking
+ *
+ * @licence GNU GPL v2+
+ * @author Daniel Kinzler
+ */
+class AddUsagesForPageJobTest extends \PHPUnit_Framework_TestCase {
+
+       public function provideConstructor_failure() {
+               $pageId = 17;
+               $usageQ5X = new EntityUsage( new ItemId( 'Q5' ), 'X' );
+               $usages = array( $usageQ5X->asArray() );
+               $touched = '20150101000000';
+
+               return array(
+                       'empty' => array( array() ),
+
+                       '$pageId is missing' => array( array(
+                               'usages' => $usages,
+                               'touched' => $touched,
+                       ) ),
+                       '$pageId is not an int' => array( array(
+                               'pageId' => 'foo',
+                               'usages' => $usages,
+                               'touched' => $touched,
+                       ) ),
+                       '$pageId is zero' => array( array(
+                               'pageId' => 0,
+                               'usages' => $usages,
+                               'touched' => $touched,
+                       ) ),
+
+                       '$usages is missing' => array( array(
+                               'pageId' => $pageId,
+                               'touched' => $touched,
+                       ) ),
+                       '$usages is not an array' => array( array(
+                               'pageId' => $pageId,
+                               'usages' => 'xxx',
+                               'touched' => $touched,
+                       ) ),
+                       '$usages is empty' => array( array(
+                               'pageId' => $pageId,
+                               'usages' => array(),
+                               'touched' => $touched,
+                       ) ),
+                       '$usages contains crap' => array( array(
+                               'pageId' => $pageId,
+                               'usages' => array( 1, 2, 3 ),
+                               'touched' => $touched,
+                       ) ),
+
+                       '$touched is missing' => array( array(
+                               'pageId' => $pageId,
+                               'usages' => $usages,
+                       ) ),
+                       '$touched is not a string' => array( array(
+                               'pageId' => $pageId,
+                               'usages' => $usages,
+                               'touched' => 23,
+                       ) ),
+                       '$touched is empty' => array( array(
+                               'pageId' => $pageId,
+                               'usages' => $usages,
+                               'touched' => '',
+                       ) ),
+               );
+       }
+
+       /**
+        * @dataProvider provideConstructor_failure
+        * @param array $params
+        */
+       public function testConstructor_failure( $params ) {
+               $this->setExpectedException( 'InvalidArgumentException' );
+
+               $title = Title::makeTitle( NS_MAIN, 'Foo' );
+               new AddUsagesForPageJob( $title, $params );
+       }
+
+       public function testRun() {
+               $usageQ5X = new EntityUsage( new ItemId( 'Q5' ), 'X' );
+               $params = array(
+                       'pageId' => 17,
+                       'usages' => array( $usageQ5X->asArray() ),
+                       'touched' => '20150101000000',
+               );
+
+               $usageUpdater = $this->getMockBuilder( 
'Wikibase\Client\Store\UsageUpdater' )
+                       ->disableOriginalConstructor()
+                       ->getMock();
+
+               $usageUpdater->expects( $this->once() )
+                       ->method( 'addUsagesForPage' )
+                       ->with(
+                               $params['pageId'],
+                               array( $usageQ5X ),
+                               $params['touched']
+                       );
+
+               $title = Title::makeTitle( NS_MAIN, 'Foo' );
+               $job = new AddUsagesForPageJob( $title, $params );
+               $job->overrideServices( $usageUpdater, new 
BasicEntityIdParser() );
+
+               $job->run();
+       }
+
+       public function testNewSpec() {
+               $usageQ5X = new EntityUsage( new ItemId( 'Q5' ), 'X' );
+
+               $title = Title::makeTitle( NS_MAIN, 'Foo' );
+               $title->resetArticleID( 17 );
+
+               $touched = '20150101000000';
+               $usages = array( $usageQ5X );
+
+               $spec = AddUsagesForPageJob::newSpec( $title, $usages, $touched 
);
+
+               $params = array(
+                       'pageId' => $title->getArticleID(),
+                       'usages' => array( $usageQ5X->asArray() ),
+                       'touched' => '20150101000000',
+               );
+
+               $this->assertEquals( 'wikibase-addUsagesForPage', 
$spec->getType() );
+               $this->assertEquals( $title->getFullText(), 
$spec->getTitle()->getFullText() );
+               $this->assertEquals( $params, $spec->getParams() );
+       }
+
+}
diff --git a/extensions/Wikibase/package.json b/extensions/Wikibase/package.json
index 2e22208..43022cd 100644
--- a/extensions/Wikibase/package.json
+++ b/extensions/Wikibase/package.json
@@ -11,7 +11,7 @@
        "author": "The Wikidata team",
        "license": "GPL-2.0+",
        "devDependencies": {
-               "jscs": "",
+               "jscs": ">=2.0",
                "jshint": ""
        }
 }
diff --git 
a/extensions/Wikibase/view/resources/jquery/wikibase/jquery.wikibase.labelview.js
 
b/extensions/Wikibase/view/resources/jquery/wikibase/jquery.wikibase.labelview.js
index 3564a36..0715d96 100644
--- 
a/extensions/Wikibase/view/resources/jquery/wikibase/jquery.wikibase.labelview.js
+++ 
b/extensions/Wikibase/view/resources/jquery/wikibase/jquery.wikibase.labelview.js
@@ -38,7 +38,6 @@
                        $entityId: '.wikibase-labelview-entityid'
                },
                value: null,
-               inputNodeName: 'TEXTAREA',
                helpMessage: mw.msg( 'wikibase-label-input-help-message' ),
                entityId: null,
                showEntityId: false
@@ -55,7 +54,6 @@
                        !( this.options.value instanceof wb.datamodel.Term )
                        || !this.options.entityId
                        || !this.options.labelsChanger
-                       || this.options.inputNodeName !== 'INPUT' && 
this.options.inputNodeName !== 'TEXTAREA'
                ) {
                        throw new Error( 'Required option not specified 
properly' );
                }
@@ -144,7 +142,7 @@
                        return deferred.resolve().promise();
                }
 
-               var $input = $( document.createElement( 
this.options.inputNodeName ) );
+               var $input = $( '<input />' );
 
                $input
                .addClass( this.widgetFullName + '-input' )
@@ -156,11 +154,6 @@
                )
                .attr( 'lang', languageCode )
                .attr( 'dir', $.util.getDirectionality( languageCode ) )
-               .on( 'keydown.' + this.widgetName, function( event ) {
-                       if( event.keyCode === $.ui.keyCode.ENTER ) {
-                               event.preventDefault();
-                       }
-               } )
                .on( 'eachchange.' + this.widgetName, function( event ) {
                        self._trigger( 'change' );
                } );
@@ -170,10 +163,7 @@
                }
 
                if( $.fn.inputautoexpand ) {
-                       $input.inputautoexpand( {
-                               expandHeight: true,
-                               suppressNewLine: true
-                       } );
+                       $input.inputautoexpand();
                }
 
                this.$text.empty().append( $input );
@@ -203,7 +193,7 @@
         */
        _afterStopEditing: function( dropValue ) {
                if( dropValue && this.options.value.getText() === '' ) {
-                       this.$text.children( '.' + this.widgetFullName + 
'-input' ).val( '' );
+                       this.$text.children( 'input' ).val( '' );
                }
                return PARENT.prototype._afterStopEditing.call( this, dropValue 
);
        },
@@ -237,7 +227,7 @@
                var response = PARENT.prototype._setOption.call( this, key, 
value );
 
                if( key === 'disabled' && this.isInEditMode() ) {
-                       this.$text.children( '.' + this.widgetFullName + 
'-input' ).prop( 'disabled', value );
+                       this.$text.children( 'input' ).prop( 'disabled', value 
);
                }
 
                return response;
@@ -261,7 +251,7 @@
 
                return new wb.datamodel.Term(
                        this.options.value.getLanguageCode(),
-                       $.trim( this.$text.children( '.' + this.widgetFullName 
+ '-input' ).val() )
+                       $.trim( this.$text.children( 'input' ).val() )
                );
        },
 
@@ -270,7 +260,7 @@
         */
        focus: function() {
                if( this.isInEditMode() ) {
-                       this.$text.children( '.' + this.widgetFullName + 
'-input' ).focus();
+                       this.$text.children( 'input' ).focus();
                } else {
                        this.element.focus();
                }
diff --git 
a/extensions/Wikibase/view/tests/qunit/jquery/wikibase/jquery.wikibase.entitytermsforlanguageview.tests.js
 
b/extensions/Wikibase/view/tests/qunit/jquery/wikibase/jquery.wikibase.entitytermsforlanguageview.tests.js
index 860f792..52be41b 100644
--- 
a/extensions/Wikibase/view/tests/qunit/jquery/wikibase/jquery.wikibase.entitytermsforlanguageview.tests.js
+++ 
b/extensions/Wikibase/view/tests/qunit/jquery/wikibase/jquery.wikibase.entitytermsforlanguageview.tests.js
@@ -196,7 +196,7 @@
        } );
 
        addToQueue( $queue, function() {
-               entitytermsforlanguageview.$label.find( 'input, textarea' 
).val( '' );
+               entitytermsforlanguageview.$label.find( 'input' ).val( '' );
                entitytermsforlanguageview.stopEditing();
        } );
 
@@ -224,14 +224,14 @@
                'Verified isInitialValue() returning true.'
        );
 
-       entitytermsforlanguageview.$label.find( 'input, textarea' ).val( 
'changed' );
+       entitytermsforlanguageview.$label.find( 'input' ).val( 'changed' );
 
        assert.ok(
                !entitytermsforlanguageview.isInitialValue(),
                'Verified isInitialValue() returning false after changing 
value.'
        );
 
-       entitytermsforlanguageview.$label.find( 'input, textarea' ).val( 'test 
label' );
+       entitytermsforlanguageview.$label.find( 'input' ).val( 'test label' );
 
        assert.ok(
                entitytermsforlanguageview.isInitialValue(),
diff --git 
a/extensions/Wikibase/view/tests/qunit/jquery/wikibase/jquery.wikibase.labelview.tests.js
 
b/extensions/Wikibase/view/tests/qunit/jquery/wikibase/jquery.wikibase.labelview.tests.js
index 0b3cf33..9ee4b1a 100644
--- 
a/extensions/Wikibase/view/tests/qunit/jquery/wikibase/jquery.wikibase.labelview.tests.js
+++ 
b/extensions/Wikibase/view/tests/qunit/jquery/wikibase/jquery.wikibase.labelview.tests.js
@@ -98,7 +98,7 @@
        labelview.startEditing();
 
        assert.ok(
-               labelview.$text.find( 'textarea' ).length === 1,
+               labelview.$text.find( 'input' ).length === 1,
                'Generated input element.'
        );
 
@@ -108,7 +108,7 @@
        labelview.stopEditing(); // should not trigger event
        labelview.startEditing();
 
-       labelview.$text.find( 'textarea' ).val( '' );
+       labelview.$text.find( 'input' ).val( '' );
 
        labelview.stopEditing();
 } );
@@ -124,14 +124,14 @@
                'Verified isInitialValue() returning true.'
        );
 
-       labelview.$text.find( 'textarea' ).val( 'changed' );
+       labelview.$text.find( 'input' ).val( 'changed' );
 
        assert.ok(
                !labelview.isInitialValue(),
                'Verified isInitialValue() returning false after changing 
value.'
        );
 
-       labelview.$text.find( 'textarea' ).val( 'test label' );
+       labelview.$text.find( 'input' ).val( 'test label' );
 
        assert.ok(
                labelview.isInitialValue(),
diff --git a/vendor/composer/autoload_classmap.php 
b/vendor/composer/autoload_classmap.php
index 25ace3b..7cf72f7 100644
--- a/vendor/composer/autoload_classmap.php
+++ b/vendor/composer/autoload_classmap.php
@@ -331,11 +331,13 @@
     'Wikibase\\Client\\RepoItemLinkGenerator' => $baseDir . 
'/extensions/Wikibase/client/includes/RepoItemLinkGenerator.php',
     'Wikibase\\Client\\RepoLinker' => $baseDir . 
'/extensions/Wikibase/client/includes/RepoLinker.php',
     'Wikibase\\Client\\Specials\\SpecialUnconnectedPages' => $baseDir . 
'/extensions/Wikibase/client/includes/specials/SpecialUnconnectedPages.php',
+    'Wikibase\\Client\\Store\\AddUsagesForPageJob' => $baseDir . 
'/extensions/Wikibase/client/includes/store/AddUsagesForPageJob.php',
     'Wikibase\\Client\\Store\\Sql\\BulkSubscriptionUpdater' => $baseDir . 
'/extensions/Wikibase/client/includes/store/sql/BulkSubscriptionUpdater.php',
     'Wikibase\\Client\\Store\\Sql\\ConsistentReadConnectionManager' => 
$baseDir . 
'/extensions/Wikibase/client/includes/store/sql/ConsistentReadConnectionManager.php',
     'Wikibase\\Client\\Store\\Sql\\PagePropsEntityIdLookup' => $baseDir . 
'/extensions/Wikibase/client/includes/store/sql/PagePropsEntityIdLookup.php',
     'Wikibase\\Client\\Store\\TitleFactory' => $baseDir . 
'/extensions/Wikibase/client/includes/store/TitleFactory.php',
     'Wikibase\\Client\\Store\\UsageUpdater' => $baseDir . 
'/extensions/Wikibase/client/includes/store/UsageUpdater.php',
+    'Wikibase\\Client\\Test\\Store\\AddUsagesForPageJobTest' => $baseDir . 
'/extensions/Wikibase/client/tests/phpunit/includes/store/AddUsagesForPageJobTest.php',
     'Wikibase\\Client\\Test\\Store\\UsageUpdaterTest' => $baseDir . 
'/extensions/Wikibase/client/tests/phpunit/includes/UsageUpdaterTest.php',
     'Wikibase\\Client\\Test\\Usage\\UsageTrackingIntegrationTest' => $baseDir 
. 
'/extensions/Wikibase/client/tests/phpunit/includes/Usage/UsageTrackingIntegrationTest.php',
     'Wikibase\\Client\\Tests\\Api\\ApiClientInfoTest' => $baseDir . 
'/extensions/Wikibase/client/tests/phpunit/includes/api/ApiClientInfoTest.php',
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index 8691f68..048eaa1 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -1159,100 +1159,12 @@
         ]
     },
     {
-        "name": "wikibase/wikibase",
-        "version": "dev-wmf/1.26wmf16",
-        "version_normalized": "dev-wmf/1.26wmf16",
-        "source": {
-            "type": "git",
-            "url": 
"https://gerrit.wikimedia.org/r/p/mediawiki/extensions/Wikibase.git";,
-            "reference": "c81228d60966244c1f2db8623191a2ea28cbfe81"
-        },
-        "require": {
-            "data-values/common": "~0.2.0",
-            "data-values/data-types": "~0.4.0",
-            "data-values/data-values": "~1.0.0",
-            "data-values/geo": "~1.0",
-            "data-values/interfaces": "^0.1.5",
-            "data-values/javascript": "~0.6.0|~0.7.0",
-            "data-values/number": "~0.5.0",
-            "data-values/serialization": "~1.0",
-            "data-values/time": "~0.8.0",
-            "data-values/validators": "~0.1.0",
-            "data-values/value-view": "~0.14.0",
-            "diff/diff": "~2.0|~1.0",
-            "php": ">=5.3.2",
-            "wikibase/data-model": "~3.0",
-            "wikibase/data-model-javascript": "^1.0.2",
-            "wikibase/data-model-serialization": "~1.7",
-            "wikibase/internal-serialization": "~1.4",
-            "wikibase/javascript-api": "~1.0",
-            "wikibase/serialization-javascript": "~2.0"
-        },
-        "conflict": {
-            "mediawiki/mediawiki": "<1.23"
-        },
-        "require-dev": {
-            "squizlabs/php_codesniffer": "~2.1"
-        },
-        "time": "2015-07-27 19:36:55",
-        "type": "mediawiki-extension",
-        "installation-source": "source",
-        "autoload": {
-            "classmap": [
-                "client/includes/",
-                "client/WikibaseClient.hooks.php",
-                "client/tests/phpunit/",
-                "lib/includes/",
-                "lib/WikibaseLib.hooks.php",
-                "lib/tests/phpunit/",
-                "repo/includes/",
-                "repo/maintenance/",
-                "repo/tests/phpunit/",
-                "repo/Wikibase.hooks.php"
-            ],
-            "psr-4": {
-                "Wikibase\\View\\": "view/src",
-                "Wikimedia\\Purtle\\": "purtle/src",
-                "Wikimedia\\Purtle\\Tests\\": "purtle/tests/phpunit"
-            }
-        },
-        "scripts": {
-            "test": [
-                "composer phpcs"
-            ],
-            "phpcs": [
-                "vendor/bin/phpcs -sp --standard=phpcs.xml --extensions=php 
--ignore=extensions/ValueView,vendor ."
-            ]
-        },
-        "license": [
-            "GPL-2.0+"
-        ],
-        "authors": [
-            {
-                "name": "The Wikidata team"
-            }
-        ],
-        "description": "Structured data repository for MediaWiki",
-        "homepage": "http://wikiba.se";,
-        "keywords": [
-            "wikibase",
-            "wikibaseclient",
-            "wikibaselib",
-            "wikibaserepo",
-            "wikidata"
-        ],
-        "support": {
-            "issues": "https://phabricator.wikimedia.org/";,
-            "irc": "irc://irc.freenode.net/wikidata"
-        }
-    },
-    {
         "name": "wikibase/wikimedia-badges",
         "version": "dev-master",
         "version_normalized": "9999999-dev",
         "source": {
             "type": "git",
-            "url": "g...@github.com:wmde/WikimediaBadges.git",
+            "url": "https://github.com/wmde/WikimediaBadges.git";,
             "reference": "5cb28488f7791302cf6b835610f132b0b05915cf"
         },
         "dist": {
@@ -1302,7 +1214,7 @@
         "version_normalized": "9999999-dev",
         "source": {
             "type": "git",
-            "url": "g...@github.com:wmde/Wikidata.org.git",
+            "url": "https://github.com/wmde/Wikidata.org.git";,
             "reference": "9029d28d8aaeb65cd1338865183740b4be445fa5"
         },
         "dist": {
@@ -1497,5 +1409,93 @@
             "wikibase",
             "wikidata"
         ]
+    },
+    {
+        "name": "wikibase/wikibase",
+        "version": "dev-wmf/1.26wmf16",
+        "version_normalized": "dev-wmf/1.26wmf16",
+        "source": {
+            "type": "git",
+            "url": 
"https://gerrit.wikimedia.org/r/p/mediawiki/extensions/Wikibase.git";,
+            "reference": "b73bc168435a1214956543d94ccfc00e8902a566"
+        },
+        "require": {
+            "data-values/common": "~0.2.0",
+            "data-values/data-types": "~0.4.0",
+            "data-values/data-values": "~1.0.0",
+            "data-values/geo": "~1.0",
+            "data-values/interfaces": "^0.1.5",
+            "data-values/javascript": "~0.6.0|~0.7.0",
+            "data-values/number": "~0.5.0",
+            "data-values/serialization": "~1.0",
+            "data-values/time": "~0.8.0",
+            "data-values/validators": "~0.1.0",
+            "data-values/value-view": "~0.14.0",
+            "diff/diff": "~2.0|~1.0",
+            "php": ">=5.3.2",
+            "wikibase/data-model": "~3.0",
+            "wikibase/data-model-javascript": "^1.0.2",
+            "wikibase/data-model-serialization": "~1.7",
+            "wikibase/internal-serialization": "~1.4",
+            "wikibase/javascript-api": "~1.0",
+            "wikibase/serialization-javascript": "~2.0"
+        },
+        "conflict": {
+            "mediawiki/mediawiki": "<1.23"
+        },
+        "require-dev": {
+            "squizlabs/php_codesniffer": "~2.1"
+        },
+        "time": "2015-07-28 17:31:42",
+        "type": "mediawiki-extension",
+        "installation-source": "source",
+        "autoload": {
+            "classmap": [
+                "client/includes/",
+                "client/WikibaseClient.hooks.php",
+                "client/tests/phpunit/",
+                "lib/includes/",
+                "lib/WikibaseLib.hooks.php",
+                "lib/tests/phpunit/",
+                "repo/includes/",
+                "repo/maintenance/",
+                "repo/tests/phpunit/",
+                "repo/Wikibase.hooks.php"
+            ],
+            "psr-4": {
+                "Wikibase\\View\\": "view/src",
+                "Wikimedia\\Purtle\\": "purtle/src",
+                "Wikimedia\\Purtle\\Tests\\": "purtle/tests/phpunit"
+            }
+        },
+        "scripts": {
+            "test": [
+                "composer phpcs"
+            ],
+            "phpcs": [
+                "vendor/bin/phpcs -sp --standard=phpcs.xml --extensions=php 
--ignore=extensions/ValueView,vendor ."
+            ]
+        },
+        "license": [
+            "GPL-2.0+"
+        ],
+        "authors": [
+            {
+                "name": "The Wikidata team"
+            }
+        ],
+        "description": "Structured data repository for MediaWiki",
+        "homepage": "http://wikiba.se";,
+        "keywords": [
+            "wikibase",
+            "wikibaseclient",
+            "wikibaselib",
+            "wikibaserepo",
+            "wikidata"
+        ],
+        "support": {
+            "issues": "https://phabricator.wikimedia.org/";,
+            "irc": "irc://irc.freenode.net/wikidata"
+        }
     }
 ]

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

Gerrit-MessageType: merged
Gerrit-Change-Id: Ic377cad074a2fb53954f7db320b558b2ebc90098
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Wikidata
Gerrit-Branch: wmf/1.26wmf16
Gerrit-Owner: Aude <aude.w...@gmail.com>
Gerrit-Reviewer: Addshore <addshorew...@gmail.com>
Gerrit-Reviewer: Aude <aude.w...@gmail.com>
Gerrit-Reviewer: Tobias Gritschacher <tobias.gritschac...@wikimedia.de>
Gerrit-Reviewer: jenkins-bot <>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to