jenkins-bot has submitted this change and it was merged. (
https://gerrit.wikimedia.org/r/386473 )
Change subject: Revert "xkill - lazy track labels/sitelinks/claims"
......................................................................
Revert "xkill - lazy track labels/sitelinks/claims"
See ticket for details… we're not actually ready for this.
This reverts commit e471b9c82cd9ee71ef66a5d11fdca606b39200be.
Change-Id: I11676ed977e4bd91e99c58e746a27d0ea40d7482
---
M client/config/WikibaseClient.default.php
M client/includes/DataAccess/Scribunto/EntityAccessor.php
M client/includes/DataAccess/Scribunto/Scribunto_LuaWikibaseEntityLibrary.php
M client/includes/DataAccess/Scribunto/Scribunto_LuaWikibaseLibrary.php
M client/includes/DataAccess/Scribunto/WikibaseLuaEntityBindings.php
M client/includes/DataAccess/Scribunto/mw.wikibase.entity.lua
M client/tests/phpunit/includes/DataAccess/Scribunto/EntityAccessorTest.php
M
client/tests/phpunit/includes/DataAccess/Scribunto/Scribunto_LuaWikibaseEntityLibraryTest.php
M
client/tests/phpunit/includes/DataAccess/Scribunto/Scribunto_LuaWikibaseLibraryTest.php
M docs/options.wiki
10 files changed, 43 insertions(+), 256 deletions(-)
Approvals:
Hoo man: Looks good to me, approved
jenkins-bot: Verified
diff --git a/client/config/WikibaseClient.default.php
b/client/config/WikibaseClient.default.php
index 312edac..c8943de 100644
--- a/client/config/WikibaseClient.default.php
+++ b/client/config/WikibaseClient.default.php
@@ -83,8 +83,6 @@
'disabledUsageAspects' => [],
- 'fineGrainedLuaTracking' => true,
-
// The type of object cache to use. Use CACHE_XXX constants.
// This is both a repo and client setting, and should be set to
the same value in
// repo and clients for multiwiki setups.
diff --git a/client/includes/DataAccess/Scribunto/EntityAccessor.php
b/client/includes/DataAccess/Scribunto/EntityAccessor.php
index 20c4957..ee878fc 100644
--- a/client/includes/DataAccess/Scribunto/EntityAccessor.php
+++ b/client/includes/DataAccess/Scribunto/EntityAccessor.php
@@ -69,24 +69,6 @@
*/
private $termsLanguages;
- /**
- * @var bool
- */
- private $fineGrainedLuaTracking;
-
- /**
- * @param EntityIdParser $entityIdParser
- * @param EntityLookup $entityLookup
- * @param UsageAccumulator $usageAccumulator
- * @param Serializer $entitySerializer
- * @param Serializer $statementSerializer
- * @param PropertyDataTypeLookup $dataTypeLookup
- * @param LanguageFallbackChain $fallbackChain
- * @param Language $language
- * @param ContentLanguages $termsLanguages
- * @param bool $fineGrainedLuaTracking Whether to track each used aspect
- * separately in Lua or just track an all usage.
- */
public function __construct(
EntityIdParser $entityIdParser,
EntityLookup $entityLookup,
@@ -96,8 +78,7 @@
PropertyDataTypeLookup $dataTypeLookup,
LanguageFallbackChain $fallbackChain,
Language $language,
- ContentLanguages $termsLanguages,
- $fineGrainedLuaTracking
+ ContentLanguages $termsLanguages
) {
$this->entityIdParser = $entityIdParser;
$this->entityLookup = $entityLookup;
@@ -108,7 +89,6 @@
$this->fallbackChain = $fallbackChain;
$this->language = $language;
$this->termsLanguages = $termsLanguages;
- $this->fineGrainedLuaTracking = $fineGrainedLuaTracking;
}
/**
@@ -141,9 +121,8 @@
$entityId = $this->entityIdParser->parse( $prefixedEntityId );
- if ( !$this->fineGrainedLuaTracking ) {
- $this->usageAccumulator->addAllUsage( $entityId );
- }
+ $this->usageAccumulator->addAllUsage( $entityId );
+
try {
$entityObject = $this->entityLookup->getEntity(
$entityId );
} catch ( RevisionedUnresolvedRedirectException $ex ) {
diff --git
a/client/includes/DataAccess/Scribunto/Scribunto_LuaWikibaseEntityLibrary.php
b/client/includes/DataAccess/Scribunto/Scribunto_LuaWikibaseEntityLibrary.php
index 55d01f8..a2b2c94 100644
---
a/client/includes/DataAccess/Scribunto/Scribunto_LuaWikibaseEntityLibrary.php
+++
b/client/includes/DataAccess/Scribunto/Scribunto_LuaWikibaseEntityLibrary.php
@@ -135,44 +135,6 @@
}
/**
- * Add a label usage (called once specific labels are accessed).
- *
- * @param string $entityId The Entity from which the labels were
accessed.
- * @param string $langCode Language code of the labels accessed.
- */
- public function addLabelUsage( $entityId, $langCode ) {
- $this->getImplementation()->addLabelUsage( $entityId, $langCode
);
- }
-
- /**
- * Add a description usage (called once specific descriptions are
accessed).
- *
- * @param string $entityId The Entity from which the descriptions were
accessed.
- * @param string $langCode Language code of the descriptions accessed.
- */
- public function addDescriptionUsage( $entityId, $langCode ) {
- $this->getImplementation()->addDescriptionUsage( $entityId,
$langCode );
- }
-
- /**
- * Add a sitelinks usage (called once specific sitelinks are accessed).
- *
- * @param string $entityId The Entity from which the sitelinks were
accessed.
- */
- public function addSiteLinksUsage( $entityId ) {
- $this->getImplementation()->addSiteLinksUsage( $entityId );
- }
-
- /**
- * Add an other usage (called once an otherwise not covered aspect is
used).
- *
- * @param string $entityId The Entity from which something was accessed.
- */
- public function addOtherUsage( $entityId ) {
- $this->getImplementation()->addOtherUsage( $entityId );
- }
-
- /**
* Register mw.wikibase.entity.lua library
*
* @return array
@@ -187,29 +149,11 @@
'formatStatements' => [ $this, 'formatStatements' ],
'formatPropertyValues' => [ $this,
'formatPropertyValues' ],
'addStatementUsage' => [ $this, 'addStatementUsage' ],
- 'addLabelUsage' => [ $this, 'addLabelUsage' ],
- 'addDescriptionUsage' => [ $this, 'addDescriptionUsage'
],
- 'addSiteLinksUsage' => [ $this, 'addSiteLinksUsage' ],
- 'addOtherUsage' => [ $this, 'addOtherUsage' ],
- 'getSetting' => [ $this, 'getSetting' ],
];
return $this->getEngine()->registerInterface(
__DIR__ . '/mw.wikibase.entity.lua', $lib, []
);
- }
-
- /**
- * Wrapper for getSetting
- *
- * @param string $setting
- *
- * @return array
- */
- public function getSetting( $setting ) {
- $this->checkType( 'setting', 1, $setting, 'string' );
- $settings = WikibaseClient::getDefaultInstance()->getSettings();
- return [ $settings->getSetting( $setting ) ];
}
/**
diff --git
a/client/includes/DataAccess/Scribunto/Scribunto_LuaWikibaseLibrary.php
b/client/includes/DataAccess/Scribunto/Scribunto_LuaWikibaseLibrary.php
index 84824bc..4290d37 100644
--- a/client/includes/DataAccess/Scribunto/Scribunto_LuaWikibaseLibrary.php
+++ b/client/includes/DataAccess/Scribunto/Scribunto_LuaWikibaseLibrary.php
@@ -200,7 +200,7 @@
private function newEntityAccessor() {
$wikibaseClient = WikibaseClient::getDefaultInstance();
- $settings = $wikibaseClient->getSettings();
+
return new EntityAccessor(
$this->getEntityIdParser(),
$wikibaseClient->getRestrictedEntityLookup(),
@@ -210,8 +210,7 @@
$wikibaseClient->getPropertyDataTypeLookup(),
$this->getLanguageFallbackChain(),
$this->getLanguage(),
- $wikibaseClient->getTermsLanguages(),
- $settings->getSetting( 'fineGrainedLuaTracking' )
+ $wikibaseClient->getTermsLanguages()
);
}
diff --git a/client/includes/DataAccess/Scribunto/WikibaseLuaEntityBindings.php
b/client/includes/DataAccess/Scribunto/WikibaseLuaEntityBindings.php
index 306a3ff..a2715ca 100644
--- a/client/includes/DataAccess/Scribunto/WikibaseLuaEntityBindings.php
+++ b/client/includes/DataAccess/Scribunto/WikibaseLuaEntityBindings.php
@@ -123,48 +123,6 @@
}
/**
- * Add a label usage (called once specific labels are accessed).
- *
- * @param string $entityId The Entity from which the labels were
accessed.
- * @param string $langCode Language code the labels accessed.
- */
- public function addLabelUsage( $entityId, $langCode ) {
- $entityId = $this->entityIdParser->parse( $entityId );
- $this->usageAccumulator->addLabelUsage( $entityId, $langCode );
- }
-
- /**
- * Add a description usage (called once specific descriptions are
accessed).
- *
- * @param string $entityId The Entity from which the descriptions were
accessed.
- * @param string $langCode Language code the descriptions accessed.
- */
- public function addDescriptionUsage( $entityId, $langCode ) {
- $entityId = $this->entityIdParser->parse( $entityId );
- $this->usageAccumulator->addDescriptionUsage( $entityId,
$langCode );
- }
-
- /**
- * Add a other usage.
- *
- * @param string $entityId The Entity from which something was accessed.
- */
- public function addOtherUsage( $entityId ) {
- $entityId = $this->entityIdParser->parse( $entityId );
- $this->usageAccumulator->addOtherUsage( $entityId );
- }
-
- /**
- * Add a sitelink usage (called once any sitelink is accessed).
- *
- * @param string $entityId The Entity from which the sitelinks were
accessed.
- */
- public function addSiteLinksUsage( $entityId ) {
- $entityId = $this->entityIdParser->parse( $entityId );
- $this->usageAccumulator->addSiteLinksUsage( $entityId );
- }
-
- /**
* Get global site ID (e.g. "enwiki")
* This is basically a helper function.
* @TODO: Make this part of mw.site in the Scribunto extension.
diff --git a/client/includes/DataAccess/Scribunto/mw.wikibase.entity.lua
b/client/includes/DataAccess/Scribunto/mw.wikibase.entity.lua
index d67c7e7..989a572 100644
--- a/client/includes/DataAccess/Scribunto/mw.wikibase.entity.lua
+++ b/client/includes/DataAccess/Scribunto/mw.wikibase.entity.lua
@@ -33,76 +33,45 @@
return type( propertyId ) == 'string' and propertyId:match(
'^P[1-9]%d*$' )
end
--- Log access to claims of entity
---
--- @param {string} entityId
--- @param {string} propertyId
-local addStatementUsage = function( entityId, propertyId )
- if isValidPropertyId( propertyId ) then
- -- Only attempt to track the usage if we have a valid property
id.
- php.addStatementUsage( entityId, propertyId )
- end
-end
-
--- Function to mask an entity's subtables in order to log access
+-- Function to mask an entity's claims table in order to log access
+-- to individual claims of an entity.
-- Code for logging based on: http://www.lua.org/pil/13.4.4.html
--
-- @param {table} entity
--- @param {string} tableName
--- @param {function} usageFunc
-local maskEntityTable = function( entity, tableName, usageFunc )
- if entity[tableName] == nil then
- return
+local maskClaimsTable = function( entity )
+ if entity.claims == nil then
+ return entity
end
- local actualEntityTable = entity[tableName]
- entity[tableName] = {}
+ local actualEntityClaims = entity.claims
+ entity.claims = {}
- local pseudoTableMetatable = {}
- pseudoTableMetatable.__index = function( emptyTable, key )
- usageFunc( entity.id, key )
- return actualEntityTable[key]
- end
-
- pseudoTableMetatable.__newindex = function( emptyTable, key, data )
- error( 'Entity cannot be modified', 2 )
- end
-
- local logNext = function( emptyTable, key )
- local k, v = next( actualEntityTable, key )
- if k ~= nil then
- usageFunc( entity.id, k )
+ local pseudoClaimsMetatable = {}
+ pseudoClaimsMetatable.__index = function( emptyTable, propertyId )
+ if isValidPropertyId( propertyId ) then
+ -- Only attempt to track the usage if we have a valid
property id.
+ php.addStatementUsage( entity.id, propertyId )
end
- return k, v
+
+ return actualEntityClaims[propertyId]
end
- pseudoTableMetatable.__pairs = function( emptyTable )
+ pseudoClaimsMetatable.__newindex = function( emptyTable, propertyId,
data )
+ error( 'Entity cannot be modified' )
+ end
+
+ local logNext = function( emptyTable, propertyId )
+ if isValidPropertyId( propertyId ) then
+ php.addStatementUsage( entity.id, propertyId )
+ end
+ return next( actualEntityClaims, propertyId )
+ end
+
+ pseudoClaimsMetatable.__pairs = function( emptyTable )
return logNext, {}, nil
end
- setmetatable( entity[tableName], pseudoTableMetatable )
-end
-
-local noUsageTracking = function()
-end
-
--- Function to mask an entity's subtables in order to log access and prevent
modifications
---
--- @param {table} entity
--- @param {bool} fineGrainedTracking
-local maskEntityTables = function ( entity, fineGrainedTracking )
- if fineGrainedTracking then
- maskEntityTable( entity, 'claims', addStatementUsage )
- maskEntityTable( entity, 'labels', php.addLabelUsage )
- maskEntityTable( entity, 'sitelinks', php.addSiteLinksUsage )
- maskEntityTable( entity, 'descriptions',
php.addDescriptionUsage )
- maskEntityTable( entity, 'aliases', php.addOtherUsage )
- else
- maskEntityTable( entity, 'claims', noUsageTracking )
- maskEntityTable( entity, 'labels', noUsageTracking )
- maskEntityTable( entity, 'sitelinks', noUsageTracking )
- maskEntityTable( entity, 'descriptions', noUsageTracking )
- maskEntityTable( entity, 'aliases', noUsageTracking )
- end
+ setmetatable( entity.claims, pseudoClaimsMetatable )
+ return entity
end
-- Create new entity object from given data
@@ -122,10 +91,9 @@
error( 'mw.wikibase.entity must not be constructed using legacy
data' )
end
- local entity = data
- maskEntityTables( entity, php.getSetting( 'fineGrainedLuaTracking' ) )
-
+ local entity = maskClaimsTable( data )
setmetatable( entity, metatable )
+
return entity
end
diff --git
a/client/tests/phpunit/includes/DataAccess/Scribunto/EntityAccessorTest.php
b/client/tests/phpunit/includes/DataAccess/Scribunto/EntityAccessorTest.php
index c03ca70..fc8db6a 100644
--- a/client/tests/phpunit/includes/DataAccess/Scribunto/EntityAccessorTest.php
+++ b/client/tests/phpunit/includes/DataAccess/Scribunto/EntityAccessorTest.php
@@ -47,8 +47,7 @@
private function getEntityAccessor(
EntityLookup $entityLookup = null,
UsageAccumulator $usageAccumulator = null,
- $langCode = 'en',
- $fineGrainedTracking = true
+ $langCode = 'en'
) {
$language = new Language( $langCode );
$serializerFactory = new SerializerFactory(
@@ -78,8 +77,7 @@
$propertyDataTypeLookup,
$fallbackChain,
$language,
- new StaticContentLanguages( [ 'de', $langCode, 'es',
'ja' ] ),
- $fineGrainedTracking
+ new StaticContentLanguages( [ 'de', $langCode, 'es',
'ja' ] )
);
}
@@ -105,24 +103,18 @@
}
}
- /**
- * @testWith [true]
- * [false]
- */
- public function testGetEntity_usage( $fineGrainedTracking ) {
+ public function testGetEntity_usage() {
$item = $this->getItem();
$itemId = $item->getId();
$entityLookup = new MockRepository();
$usages = new HashUsageAccumulator();
- $entityAccessor = $this->getEntityAccessor( $entityLookup,
$usages, 'en', $fineGrainedTracking );
+ $entityAccessor = $this->getEntityAccessor( $entityLookup,
$usages );
$entityAccessor->getEntity( $itemId->getSerialization() );
- // Only access to specific labels/claims/etc will result in
actual usage
- $this->assertEquals(
- $this->hasUsage( $usages->getUsages(), $item->getId(),
EntityUsage::ALL_USAGE ),
- !$fineGrainedTracking
+ $this->assertTrue(
+ $this->hasUsage( $usages->getUsages(), $item->getId(),
EntityUsage::ALL_USAGE ), 'all usage'
);
}
diff --git
a/client/tests/phpunit/includes/DataAccess/Scribunto/Scribunto_LuaWikibaseEntityLibraryTest.php
b/client/tests/phpunit/includes/DataAccess/Scribunto/Scribunto_LuaWikibaseEntityLibraryTest.php
index dbf4964..c5fcc83 100644
---
a/client/tests/phpunit/includes/DataAccess/Scribunto/Scribunto_LuaWikibaseEntityLibraryTest.php
+++
b/client/tests/phpunit/includes/DataAccess/Scribunto/Scribunto_LuaWikibaseEntityLibraryTest.php
@@ -218,36 +218,6 @@
$this->assertSame( $allowDataAccessInUserLanguage, $cacheSplit
);
}
- public function testAddLabelUsage() {
- $luaWikibaseLibrary = $this->newScribuntoLuaWikibaseLibrary();
- $luaWikibaseLibrary->addLabelUsage( 'Q32488', 'he' );
- $usages =
$luaWikibaseLibrary->getUsageAccumulator()->getUsages();
-
- $this->assertArrayHasKey( 'Q32488#L.he', $usages );
- }
-
- public function testAddDescriptionUsage() {
- $luaWikibaseLibrary = $this->newScribuntoLuaWikibaseLibrary();
- $luaWikibaseLibrary->addDescriptionUsage( 'Q32488', 'he' );
- $usages =
$luaWikibaseLibrary->getUsageAccumulator()->getUsages();
-
- $this->assertArrayHasKey( 'Q32488#D.he', $usages );
- }
-
- public function testAddSitelinksUsage() {
- $luaWikibaseLibrary = $this->newScribuntoLuaWikibaseLibrary();
- $luaWikibaseLibrary->addSiteLinksUsage( 'Q32488' );
- $usages =
$luaWikibaseLibrary->getUsageAccumulator()->getUsages();
- $this->assertArrayHasKey( 'Q32488#S', $usages );
- }
-
- public function testAddOtherUsage() {
- $luaWikibaseLibrary = $this->newScribuntoLuaWikibaseLibrary();
- $luaWikibaseLibrary->addOtherUsage( 'Q32488' );
- $usages =
$luaWikibaseLibrary->getUsageAccumulator()->getUsages();
- $this->assertArrayHasKey( 'Q32488#O', $usages );
- }
-
/**
* @param bool &$cacheSplit Will become true when the ParserCache has
been split
* @param Language|null $userLang The user's language
diff --git
a/client/tests/phpunit/includes/DataAccess/Scribunto/Scribunto_LuaWikibaseLibraryTest.php
b/client/tests/phpunit/includes/DataAccess/Scribunto/Scribunto_LuaWikibaseLibraryTest.php
index bb4b99a..423268d 100644
---
a/client/tests/phpunit/includes/DataAccess/Scribunto/Scribunto_LuaWikibaseLibraryTest.php
+++
b/client/tests/phpunit/includes/DataAccess/Scribunto/Scribunto_LuaWikibaseLibraryTest.php
@@ -70,13 +70,6 @@
];
}
- public function fineGrainedLuaTrackingProvider() {
- return [
- [ true, [ 'Q885588#L', 'Q885588#T' ] ],
- [ false, [ 'Q32488#X', 'Q885588#L', 'Q885588#T' ] ],
- ];
- }
-
public function testConstructor() {
$engine = $this->getEngine();
$luaWikibaseLibrary = new Scribunto_LuaWikibaseLibrary( $engine
);
@@ -285,12 +278,8 @@
$this->assertSame( $allowDataAccessInUserLanguage, $cacheSplit
);
}
- /**
- * @dataProvider fineGrainedLuaTrackingProvider
- */
- public function testRenderSnak_languageFallback( $fineGrainedTracking,
$expectedUsage ) {
+ public function testRenderSnak_languageFallback() {
$this->setAllowDataAccessInUserLanguage( true );
- $this->setFineGrainedLuaTracking( $fineGrainedTracking );
$cacheSplit = false;
$lang = Language::factory( 'ku' );
@@ -305,8 +294,7 @@
// All languages in the fallback chain from 'ku' to 'ku-latn'
count as "used".
$usage =
$luaWikibaseLibrary->getUsageAccumulator()->getUsages();
-
- $this->assertSame( $expectedUsage, array_keys( $usage ) );
+ $this->assertSame( [ 'Q32488#X', 'Q885588#L', 'Q885588#T' ],
array_keys( $usage ) );
$this->assertSame( true, $cacheSplit );
}
@@ -503,14 +491,6 @@
private function setAllowDataAccessInUserLanguage( $value ) {
$settings = WikibaseClient::getDefaultInstance()->getSettings();
$settings->setSetting( 'allowDataAccessInUserLanguage', $value
);
- }
-
- /**
- * @param bool $value
- */
- private function setFineGrainedLuaTracking( $value ) {
- $settings = WikibaseClient::getDefaultInstance()->getSettings();
- $settings->setSetting( 'fineGrainedLuaTracking', $value );
}
}
diff --git a/docs/options.wiki b/docs/options.wiki
index bbfc83b..47dc767 100644
--- a/docs/options.wiki
+++ b/docs/options.wiki
@@ -116,7 +116,6 @@
;sendEchoNotification: If true, allows users on the client wiki to get a
notification when a page they created is connected to a repo item. This
requires the Echo extension.
;echoIcon: If <code>sendEchoNotification</code> is set to <code>true</code>,
you can also provide what icon the user will see. The correct syntax is <code>[
'url' => '...' ]</code> or <code>[ 'path' => '...' ]</code> where
<code>path</code> is relative to <code>$wgExtensionAssetsPath</code>. Defaults
to <code>false</code> which means that there will be the default Echo icon.
;disabledUsageAspects: Array of usage aspects that should not be saved in the
<code>wbc_entity_usage</code> table. This supports aspect codes (like "T", "L"
or "X"), but not full aspect keys (like "L.de"). For example <code>[ 'D', 'C'
]</code> can be used to disable description and statement usages. Also a
replacement usage type can be given in the form of <code>[
'usage-type-to-replace' => 'replacement' ]</code>.
-;fineGrainedLuaTracking: Enable fine grained tracking on entities accessed
through Lua in client. No all (X) usage will be recorded, but each aspect will
be recorded individually based on actual usage.
;wikiPageUpdaterDbBatchSize: DEPRECATED. If set, acts as a default for
purgeCacheBatchSize and recentChangesBatchSize.
;purgeCacheBatchSize: Number of pages to process in each HTMLCacheUpdateJob, a
job used to send client wikis notifications about relevant changes to entities.
Higher value mean fewer jobs but longer run-time per job. Defaults to
wikiPageUpdaterDbBatchSize (for backwards compatibility) or MediaWiki core's
$wgUpdateRowsPerJob (which currently defaults to 300).
;recentChangesBatchSize: Number of <code>recentchanges</code> table rows to
create in each InjectRCRecordsJob, a job used to send client wikis
notifications about relevant changes to entities. Higher value mean fewer jobs
but longer run-time per job. Defaults to wikiPageUpdaterDbBatchSize (for
backwards compatibility) or MediaWiki core's $wgUpdateRowsPerJob (which
currently defaults to 300).
--
To view, visit https://gerrit.wikimedia.org/r/386473
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I11676ed977e4bd91e99c58e746a27d0ea40d7482
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Wikibase
Gerrit-Branch: master
Gerrit-Owner: Hoo man <[email protected]>
Gerrit-Reviewer: Anomie <[email protected]>
Gerrit-Reviewer: Daniel Kinzler <[email protected]>
Gerrit-Reviewer: Eranroz <[email protected]>
Gerrit-Reviewer: Hoo man <[email protected]>
Gerrit-Reviewer: Jackmcbarn <[email protected]>
Gerrit-Reviewer: Ladsgroup <[email protected]>
Gerrit-Reviewer: Matěj Suchánek <[email protected]>
Gerrit-Reviewer: Thiemo Mättig (WMDE) <[email protected]>
Gerrit-Reviewer: Tim Starling <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits