Tim Starling has uploaded a new change for review. ( https://gerrit.wikimedia.org/r/347315 )
Change subject: [WIP] A service for read-only mode ...................................................................... [WIP] A service for read-only mode Change-Id: I9bbee946c10742526d3423208efd68cb3cc5a7ee --- M autoload.php M includes/GlobalFunctions.php M includes/MediaWikiServices.php A includes/ReadOnlyMode.php M includes/ServiceWiring.php M includes/WatchedItemStore.php M includes/db/MWLBFactory.php M maintenance/rebuildFileCache.php M maintenance/rebuildImages.php M tests/phpunit/includes/GlobalFunctions/GlobalTest.php A tests/phpunit/includes/ReadOnlyModeTest.php M tests/phpunit/includes/auth/AuthManagerTest.php 12 files changed, 360 insertions(+), 82 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core refs/changes/15/347315/1 diff --git a/autoload.php b/autoload.php index 3816485..d4b8b2c 100644 --- a/autoload.php +++ b/autoload.php @@ -1159,6 +1159,7 @@ 'RawAction' => __DIR__ . '/includes/actions/RawAction.php', 'RawMessage' => __DIR__ . '/includes/Message.php', 'ReadOnlyError' => __DIR__ . '/includes/exception/ReadOnlyError.php', + 'ReadOnlyMode' => __DIR__ . '/includes/ReadOnlyMode.php', 'ReassignEdits' => __DIR__ . '/maintenance/reassignEdits.php', 'RebuildAll' => __DIR__ . '/maintenance/rebuildall.php', 'RebuildFileCache' => __DIR__ . '/maintenance/rebuildFileCache.php', diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index 3747c23..7eb7193 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -1272,7 +1272,8 @@ * @return bool */ function wfReadOnly() { - return wfReadOnlyReason() !== false; + return \MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode() + ->isReadOnly(); } /** @@ -1284,19 +1285,8 @@ * @return string|bool String when in read-only mode; false otherwise */ function wfReadOnlyReason() { - $readOnly = wfConfiguredReadOnlyReason(); - if ( $readOnly !== false ) { - return $readOnly; - } - - static $lbReadOnly = null; - if ( $lbReadOnly === null ) { - // Callers use this method to be aware that data presented to a user - // may be very stale and thus allowing submissions can be problematic. - $lbReadOnly = wfGetLB()->getReadOnlyReason(); - } - - return $lbReadOnly; + return \MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode() + ->getReason(); } /** @@ -1306,18 +1296,8 @@ * @since 1.27 */ function wfConfiguredReadOnlyReason() { - global $wgReadOnly, $wgReadOnlyFile; - - if ( $wgReadOnly === null ) { - // Set $wgReadOnly for faster access next time - if ( is_file( $wgReadOnlyFile ) && filesize( $wgReadOnlyFile ) > 0 ) { - $wgReadOnly = file_get_contents( $wgReadOnlyFile ); - } else { - $wgReadOnly = false; - } - } - - return $wgReadOnly; + return \MediaWiki\MediaWikiServices::getInstance()->getConfiguredReadOnlyMode() + ->getReason(); } /** diff --git a/includes/MediaWikiServices.php b/includes/MediaWikiServices.php index e44fefe..5e6bf8f 100644 --- a/includes/MediaWikiServices.php +++ b/includes/MediaWikiServices.php @@ -656,6 +656,22 @@ return $this->getService( 'VirtualRESTServiceClient' ); } + /** + * @since 1.29 + * @return ReadOnlyMode + */ + public function getConfiguredReadOnlyMode() { + return $this->getService( 'ConfiguredReadOnlyMode' ); + } + + /** + * @since 1.29 + * @return ReadOnlyMode + */ + public function getReadOnlyMode() { + return $this->getService( 'ReadOnlyMode' ); + } + /////////////////////////////////////////////////////////////////////////// // NOTE: When adding a service getter here, don't forget to add a test // case for it in MediaWikiServicesTest::provideGetters() and in diff --git a/includes/ReadOnlyMode.php b/includes/ReadOnlyMode.php new file mode 100644 index 0000000..820a946 --- /dev/null +++ b/includes/ReadOnlyMode.php @@ -0,0 +1,85 @@ +<?php + +/** + * A service class for fetching the wiki's current read-only mode. + * To obtain an instance, use MediaWikiServices::getReadOnlyMode(). + * + * @since 1.29 + */ +class ReadOnlyMode { + private $config; + private $loadBalancers = []; + private $reason = null; + + public function __construct( Config $config ) { + $this->config = $config; + } + + public function addLoadBalancer( \Wikimedia\Rdbms\LoadBalancer $loadBalancer ) { + $this->loadBalancers[] = $loadBalancer; + } + + /** + * Check whether the wiki is in read-only mode. + * + * @return bool + */ + public function isReadOnly() { + return $this->getReason() !== false; + } + + /** + * Check if the site is in read-only mode and return the message if so + * + * This checks the configuration and registered DB load balancers for + * read-only mode. This may result in DB connection being made. + * + * @return string|bool String when in read-only mode; false otherwise + */ + public function getReason() { + $readOnly = $this->getConfiguredReason(); + if ( $readOnly !== false ) { + return $readOnly; + } + foreach ( $this->loadBalancers as $lb ) { + $lbReadOnly = $lb->getReadOnlyReason(); + if ( $lbReadOnly !== false && $lbReadOnly !== null ) { + return $lbReadOnly; + } + } + return false; + } + + /** + * Get the value of $wgReadOnly or the contents of $wgReadOnlyFile. + * + * Use MediaWikiServices::getConfiguredReadOnlyMode()->getReason() for + * public access to this. + * + * @return string|bool String when in read-only mode; false otherwise + */ + private function getConfiguredReason() { + if ( $this->reason === null ) { + // Cache for faster access next time + $this->reason = $this->config->get( 'ReadOnly' ); + + if ( $this->reason === null ) { + $readOnlyFile = $this->config->get( 'ReadOnlyFile' ); + if ( is_file( $readOnlyFile ) && filesize( $readOnlyFile ) > 0 ) { + $this->reason = file_get_contents( $readOnlyFile ); + } else { + $this->reason = false; + } + } + } + return $this->reason; + } + + /** + * Set the read-only mode, which will apply for the remainder of the + * request or until a service reset. + */ + public function setReason( $msg ) { + $this->reason = $msg; + } +} diff --git a/includes/ServiceWiring.php b/includes/ServiceWiring.php index ce82702..18d8ec9 100644 --- a/includes/ServiceWiring.php +++ b/includes/ServiceWiring.php @@ -48,7 +48,8 @@ $lbConf = MWLBFactory::applyDefaultConfig( $mainConfig->get( 'LBFactoryConf' ), - $mainConfig + $mainConfig, + $services->getConfiguredReadOnlyMode() ); $class = MWLBFactory::getLBFactoryClass( $lbConf ); @@ -155,7 +156,8 @@ 'WatchedItemStore' => function( MediaWikiServices $services ) { $store = new WatchedItemStore( $services->getDBLoadBalancer(), - new HashBagOStuff( [ 'maxKeys' => 100 ] ) + new HashBagOStuff( [ 'maxKeys' => 100 ] ), + $services->getReadOnlyMode() ); $store->setStatsdDataFactory( $services->getStatsdDataFactory() ); return $store; @@ -404,6 +406,16 @@ return $vrsClient; }, + 'ConfiguredReadOnlyMode' => function( MediaWikiServices $services ) { + return new ReadOnlyMode( $services->getMainConfig() ); + }, + + 'ReadOnlyMode' => function( MediaWikiServices $services ) { + $readOnlyMode = new ReadOnlyMode( $services->getMainConfig() ); + $readOnlyMode->addLoadBalancer( $services->getDBLoadBalancer() ); + return $readOnlyMode; + }, + /////////////////////////////////////////////////////////////////////////// // NOTE: When adding a service here, don't forget to add a getter function // in the MediaWikiServices class. The convenience getter should just call diff --git a/includes/WatchedItemStore.php b/includes/WatchedItemStore.php index 70fdbf1..3bf2d3a 100644 --- a/includes/WatchedItemStore.php +++ b/includes/WatchedItemStore.php @@ -30,6 +30,11 @@ private $loadBalancer; /** + * @var ReadOnlyMode + */ + private $readOnlyMode; + + /** * @var HashBagOStuff */ private $cache; @@ -60,13 +65,16 @@ /** * @param LoadBalancer $loadBalancer * @param HashBagOStuff $cache + * @param ReadOnlyMode $readOnlyMode */ public function __construct( LoadBalancer $loadBalancer, - HashBagOStuff $cache + HashBagOStuff $cache, + ReadOnlyMode $readOnlyMode ) { $this->loadBalancer = $loadBalancer; $this->cache = $cache; + $this->readOnlyMode = $readOnlyMode; $this->stats = new NullStatsdDataFactory(); $this->deferredUpdatesAddCallableUpdateCallback = [ 'DeferredUpdates', 'addCallableUpdate' ]; $this->revisionGetTimestampFromIdCallback = [ 'Revision', 'getTimestampFromId' ]; @@ -595,7 +603,7 @@ * @return bool success */ public function addWatchBatchForUser( User $user, array $targets ) { - if ( $this->loadBalancer->getReadOnlyReason() !== false ) { + if ( $this->readOnlyMode->isReadOnly() ) { return false; } // Only loggedin user can have a watchlist @@ -653,7 +661,7 @@ */ public function removeWatch( User $user, LinkTarget $target ) { // Only logged in user can have a watchlist - if ( $this->loadBalancer->getReadOnlyReason() !== false || $user->isAnon() ) { + if ( $this->readOnlyMode->isReadOnly() || $user->isAnon() ) { return false; } @@ -784,7 +792,7 @@ */ public function resetNotificationTimestamp( User $user, Title $title, $force = '', $oldid = 0 ) { // Only loggedin user can have a watchlist - if ( $this->loadBalancer->getReadOnlyReason() !== false || $user->isAnon() ) { + if ( $this->readOnlyMode->isReadOnly() || $user->isAnon() ) { return false; } diff --git a/includes/db/MWLBFactory.php b/includes/db/MWLBFactory.php index fe063f2..3bc730d 100644 --- a/includes/db/MWLBFactory.php +++ b/includes/db/MWLBFactory.php @@ -33,9 +33,12 @@ /** * @param array $lbConf Config for LBFactory::__construct() * @param Config $mainConfig Main config object from MediaWikiServices + * @param ReadOnlyMode $readOnlyMode * @return array */ - public static function applyDefaultConfig( array $lbConf, Config $mainConfig ) { + public static function applyDefaultConfig( array $lbConf, Config $mainConfig, + ReadOnlyMode $readOnlyMode + ) { global $wgCommandLineMode; static $typesWithSchema = [ 'postgres', 'msssql' ]; @@ -55,8 +58,7 @@ 'errorLogger' => [ MWExceptionHandler::class, 'logException' ], 'cliMode' => $wgCommandLineMode, 'hostname' => wfHostname(), - // TODO: replace the global wfConfiguredReadOnlyReason() with a service. - 'readOnlyReason' => wfConfiguredReadOnlyReason(), + 'readOnlyReason' => $readOnlyMode->getReason(), ]; // When making changes here, remember to also specify MediaWiki-specific options diff --git a/maintenance/rebuildFileCache.php b/maintenance/rebuildFileCache.php index 3520279..04ac967 100644 --- a/maintenance/rebuildFileCache.php +++ b/maintenance/rebuildFileCache.php @@ -41,7 +41,7 @@ } public function finalSetup() { - global $wgDebugToolbar, $wgUseFileCache, $wgReadOnly; + global $wgDebugToolbar, $wgUseFileCache; $this->enabled = $wgUseFileCache; // Script will handle capturing output and saving it itself @@ -50,7 +50,8 @@ // Has to be done before Setup.php initialize MWDebug $wgDebugToolbar = false; // Avoid DB writes (like enotif/counters) - $wgReadOnly = 'Building cache'; // avoid DB writes (like enotif/counters) + MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode() + ->setReason( 'Building cache' ); parent::finalSetup(); } diff --git a/maintenance/rebuildImages.php b/maintenance/rebuildImages.php index 966864e..109350c 100644 --- a/maintenance/rebuildImages.php +++ b/maintenance/rebuildImages.php @@ -63,7 +63,8 @@ $this->dbw = $this->getDB( DB_MASTER ); $this->dryrun = $this->hasOption( 'dry-run' ); if ( $this->dryrun ) { - $GLOBALS['wgReadOnly'] = 'Dry run mode, image upgrades are suppressed'; + MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode() + ->setReason( 'Dry run mode, image upgrades are suppressed' ); } if ( $this->hasOption( 'missing' ) ) { diff --git a/tests/phpunit/includes/GlobalFunctions/GlobalTest.php b/tests/phpunit/includes/GlobalFunctions/GlobalTest.php index 2206fbd..16e944a 100644 --- a/tests/phpunit/includes/GlobalFunctions/GlobalTest.php +++ b/tests/phpunit/includes/GlobalFunctions/GlobalTest.php @@ -8,11 +8,7 @@ protected function setUp() { parent::setUp(); - $readOnlyFile = $this->getNewTempFile(); - unlink( $readOnlyFile ); - $this->setMwGlobals( [ - 'wgReadOnlyFile' => $readOnlyFile, 'wgUrlProtocols' => [ 'http://', 'https://', @@ -99,38 +95,6 @@ . "%E0%B0%B5%E0%B0%BE%E0%B0%A1%E0%B1%81%E0%B0%95%E0%B0%B0%E0%B0%BF_" . "%E0%B0%AE%E0%B0%BE%E0%B0%B0%E0%B1%8D%E0%B0%97%E0%B0%A6%E0%B0%B0" . "%E0%B1%8D%E0%B0%B6%E0%B0%A8%E0%B0%BF" ) ); - } - - /** - * @covers ::wfReadOnly - */ - public function testReadOnlyEmpty() { - global $wgReadOnly; - $wgReadOnly = null; - - $this->assertFalse( wfReadOnly() ); - $this->assertFalse( wfReadOnly() ); - } - - /** - * @covers ::wfReadOnly - */ - public function testReadOnlySet() { - global $wgReadOnly, $wgReadOnlyFile; - - $f = fopen( $wgReadOnlyFile, "wt" ); - fwrite( $f, 'Message' ); - fclose( $f ); - $wgReadOnly = null; # Check on $wgReadOnlyFile - - $this->assertTrue( wfReadOnly() ); - $this->assertTrue( wfReadOnly() ); # Check cached - - unlink( $wgReadOnlyFile ); - $wgReadOnly = null; # Clean cache - - $this->assertFalse( wfReadOnly() ); - $this->assertFalse( wfReadOnly() ); } public static function provideArrayToCGI() { diff --git a/tests/phpunit/includes/ReadOnlyModeTest.php b/tests/phpunit/includes/ReadOnlyModeTest.php new file mode 100644 index 0000000..d13c5c6 --- /dev/null +++ b/tests/phpunit/includes/ReadOnlyModeTest.php @@ -0,0 +1,204 @@ +<?php + +use MediaWiki\MediaWikiServices; + +/** + * @group Database + * @covers ReadOnlyMode + */ +class ReadOnlyModeTest extends MediaWikiTestCase { + public function provider() { + $rawTests = [ + 'None of anything' => [ + 'confMessage' => null, + 'hasFileName' => false, + 'fileContents' => false, + 'lbMessage' => false, + 'expectedState' => false, + 'expectedMessage' => false, + 'expectedConfMessage' => false + ], + 'File missing' => [ + 'confMessage' => null, + 'hasFileName' => true, + 'fileContents' => false, + 'lbMessage' => false, + 'expectedState' => false, + 'expectedMessage' => false, + 'expectedConfMessage' => false + ], + 'File empty' => [ + 'confMessage' => null, + 'hasFileName' => true, + 'fileContents' => '', + 'lbMessage' => false, + 'expectedState' => false, + 'expectedMessage' => false, + 'expectedConfMessage' => false + ], + 'File has message' => [ + 'confMessage' => null, + 'hasFileName' => true, + 'fileContents' => 'Message', + 'lbMessage' => false, + 'expectedState' => true, + 'expectedMessage' => 'Message', + 'expectedConfMessage' => 'Message', + ], + 'Conf has message' => [ + 'confMessage' => 'Message', + 'hasFileName' => false, + 'fileContents' => false, + 'lbMessage' => false, + 'expectedState' => true, + 'expectedMessage' => 'Message', + 'expectedConfMessage' => 'Message' + ], + "Conf=false means don't check the file" => [ + 'confMessage' => false, + 'hasFileName' => true, + 'fileContents' => 'Message', + 'lbMessage' => false, + 'expectedState' => false, + 'expectedMessage' => false, + 'expectedConfMessage' => false, + ], + 'LB has message' => [ + 'confMessage' => null, + 'hasFileName' => false, + 'fileContents' => false, + 'lbMessage' => 'Message', + 'expectedState' => true, + 'expectedMessage' => 'Message', + 'expectedConfMessage' => false + ], + 'All three have a message: conf wins' => [ + 'confMessage' => 'conf', + 'hasFileName' => true, + 'fileContents' => 'file', + 'lbMessage' => 'lb', + 'expectedState' => true, + 'expectedMessage' => 'conf', + 'expectedConfMessage' => 'conf' + ] + ]; + $cookedTests = []; + foreach ( $rawTests as $desc => $test ) { + $cookedTests[$desc] = [ $test ]; + } + return $cookedTests; + } + + private function createMode( $params, $makeLB ) { + $config = new HashConfig( [ + 'ReadOnly' => $params['confMessage'], + 'ReadOnlyFile' => $this->createFile( $params ), + ] ); + + $rom = new ReadOnlyMode( $config ); + + if ( $makeLB ) { + $lb = $this->createLB( $params ); + $rom->addLoadBalancer( $lb ); + } + return $rom; + } + + private function createLB( $params ) { + $lb = $this->getMockBuilder( \Wikimedia\Rdbms\LoadBalancer::class ) + ->disableOriginalConstructor() + ->getMock(); + $lb->expects( $this->any() )->method( 'getReadOnlyReason' ) + ->willReturn( $params['lbMessage'] ); + return $lb; + } + + private function createFile( $params ) { + if ( $params['hasFileName'] ) { + $fileName = $this->getNewTempFile(); + + if ( $params['fileContents'] === false ) { + unlink( $fileName ); + } else { + file_put_contents( $fileName, $params['fileContents'] ); + } + } else { + $fileName = null; + } + return $fileName; + } + + private function createServices( $params, $makeLB ) { + $services = MediaWikiServices::getInstance(); + $oldConfig = $services->getMainConfig(); + $myConfig = new MultiConfig( [ + new HashConfig( [ + 'ReadOnly' => $params['confMessage'], + 'ReadOnlyFile' => $this->createFile( $params ), + ] ), + $oldConfig + ] ); + $bootstrap = new HashConfig( [ + 'ConfigRegistry' => [ + 'main' => function () use ( $myConfig ) { + return $myConfig; + }, + ] + ] ); + $newServices = new MediaWikiServices( $bootstrap ); + $newServices->loadWiringFiles( $oldConfig->get( 'ServiceWiringFiles' ) ); + if ( $makeLB ) { + $newServices->redefineService( 'DBLoadBalancer', function () use ( $params ) { + return $this->createLB( $params ); + } ); + } + return $newServices; + } + + /** + * @dataProvider provider + */ + public function testWithLB( $params ) { + $rom = $this->createMode( $params, true ); + $this->assertSame( $params['expectedMessage'], $rom->getReason() ); + $this->assertSame( $params['expectedState'], $rom->isReadOnly() ); + } + + /** + * @dataProvider provider + */ + public function testWithoutLB( $params ) { + $rom = $this->createMode( $params, false ); + $this->assertSame( $params['expectedConfMessage'], $rom->getReason() ); + } + + /** + * @dataProvider provider + */ + public function testWiringWithLB( $params ) { + $rom = $this->createServices( $params, true )->getReadOnlyMode(); + $this->assertSame( $params['expectedMessage'], $rom->getReason() ); + $this->assertSame( $params['expectedState'], $rom->isReadOnly() ); + } + + /** + * @dataProvider provider + */ + public function testWiringWithoutLB( $params ) { + $rom = $this->createServices( $params, false )->getConfiguredReadOnlyMode(); + $this->assertSame( $params['expectedConfMessage'], $rom->getReason() ); + } + + public function testSetReadOnlyReason() { + $rom = $this->createMode( + [ + 'confMessage' => 'conf', + 'hasFileName' => false, + 'fileContents' => false, + 'lbMessage' => 'lb' + ], + true ); + $rom->setReason( 'override' ); + $this->assertSame( 'override', $rom->getReason() ); + } +} diff --git a/tests/phpunit/includes/auth/AuthManagerTest.php b/tests/phpunit/includes/auth/AuthManagerTest.php index 5c268f8..802e4ae 100644 --- a/tests/phpunit/includes/auth/AuthManagerTest.php +++ b/tests/phpunit/includes/auth/AuthManagerTest.php @@ -1404,12 +1404,13 @@ $this->manager->checkAccountCreatePermissions( new \User ) ); - $this->setMwGlobals( [ 'wgReadOnly' => 'Because' ] ); + $readOnlyMode = \MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode(); + $readOnlyMode->setReason( 'Because' ); $this->assertEquals( \Status::newFatal( 'readonlytext', 'Because' ), $this->manager->checkAccountCreatePermissions( new \User ) ); - $this->setMwGlobals( [ 'wgReadOnly' => false ] ); + $readOnlyMode->setReason( false ); $wgGroupPermissions['*']['createaccount'] = false; $status = $this->manager->checkAccountCreatePermissions( new \User ); @@ -1597,7 +1598,8 @@ $this->assertSame( AuthenticationResponse::FAIL, $ret->status ); $this->assertSame( 'noname', $ret->message->getKey() ); - $this->setMwGlobals( [ 'wgReadOnly' => 'Because' ] ); + $readOnlyMode = \MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode(); + $readOnlyMode->setReason( 'Because' ); $this->hook( 'LocalUserCreated', $this->never() ); $userReq->username = self::usernameForCreation(); $ret = $this->manager->beginAccountCreation( $creator, [ $userReq ], 'http://localhost/' ); @@ -1605,7 +1607,7 @@ $this->assertSame( AuthenticationResponse::FAIL, $ret->status ); $this->assertSame( 'readonlytext', $ret->message->getKey() ); $this->assertSame( [ 'Because' ], $ret->message->getParams() ); - $this->setMwGlobals( [ 'wgReadOnly' => false ] ); + $readOnlyMode->setReason( false ); $this->hook( 'LocalUserCreated', $this->never() ); $userReq->username = self::usernameForCreation(); @@ -1770,14 +1772,15 @@ $this->request->getSession()->setSecret( 'AuthManager::accountCreationState', [ 'username' => $creator->getName() ] + $session ); - $this->setMwGlobals( [ 'wgReadOnly' => 'Because' ] ); + $readOnlyMode = \MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode(); + $readOnlyMode->setReason( 'Because' ); $this->hook( 'LocalUserCreated', $this->never() ); $ret = $this->manager->continueAccountCreation( [] ); $this->unhook( 'LocalUserCreated' ); $this->assertSame( AuthenticationResponse::FAIL, $ret->status ); $this->assertSame( 'readonlytext', $ret->message->getKey() ); $this->assertSame( [ 'Because' ], $ret->message->getParams() ); - $this->setMwGlobals( [ 'wgReadOnly' => false ] ); + $readOnlyMode->setReason( false ); $this->request->getSession()->setSecret( 'AuthManager::accountCreationState', [ 'username' => $creator->getName() ] + $session ); @@ -2468,7 +2471,8 @@ // Wiki is read-only $session->clear(); - $this->setMwGlobals( [ 'wgReadOnly' => 'Because' ] ); + $readOnlyMode = \MediaWiki\MediaWikiServices::getInstance()->getReadOnlyMode(); + $readOnlyMode->setReason( 'Because' ); $user = \User::newFromName( $username ); $this->hook( 'LocalUserCreated', $this->never() ); $ret = $this->manager->autoCreateUser( $user, AuthManager::AUTOCREATE_SOURCE_SESSION, true ); @@ -2481,7 +2485,7 @@ [ LogLevel::DEBUG, 'denied by wfReadOnly(): {reason}' ], ], $logger->getBuffer() ); $logger->clearBuffer(); - $this->setMwGlobals( [ 'wgReadOnly' => false ] ); + $readOnlyMode->setReason( false ); // Session blacklisted $session->clear(); -- To view, visit https://gerrit.wikimedia.org/r/347315 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I9bbee946c10742526d3423208efd68cb3cc5a7ee Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/core Gerrit-Branch: master Gerrit-Owner: Tim Starling <tstarl...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits