Mattflaschen has uploaded a new change for review. https://gerrit.wikimedia.org/r/322223
Change subject: Add script to fix inconsistent state for board name ...................................................................... Add script to fix inconsistent state for board name This loops through all Flow boards (optionally with a namespace constraint). It checks the JSON workflow ID, loads the workflow from that, then checks that the Flow title matches the core (page table) title. You can optionally limit the number of boards modified in each run. There is also a dry run mode. Small supporting changes elsewhere, including renaming a parameter in another maintenance script to match. Bug: T148057 Change-Id: I6a1a410db0893049651fbbbd6f9b9f13360c34c3 --- M Hooks.php M includes/BoardMover.php M includes/WorkflowLoaderFactory.php A maintenance/FlowFixInconsistentBoards.php M maintenance/convertNamespaceFromWikitext.php 5 files changed, 146 insertions(+), 5 deletions(-) git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Flow refs/changes/23/322223/1 diff --git a/Hooks.php b/Hooks.php index 0ef70bd..072f17e 100644 --- a/Hooks.php +++ b/Hooks.php @@ -280,6 +280,9 @@ require_once __DIR__.'/maintenance/FlowPopulateRefId.php'; $updater->addPostDatabaseUpdateMaintenance( 'FlowPopulateRefId' ); + require_once __DIR__.'/maintenance/FlowFixInconsistentBoards.php'; + $updater->addPostDatabaseUpdateMaintenance( 'FlowFixInconsistentBoards' ); + /* * Add primary key, but only after we've made sure the newly added * column has been populated (otherwise they'd all be null values) diff --git a/includes/BoardMover.php b/includes/BoardMover.php index b0978a7..979408f 100644 --- a/includes/BoardMover.php +++ b/includes/BoardMover.php @@ -51,9 +51,8 @@ /** * Collects the workflow and header (if it exists) and puts them into the database. Does - * not commit yet. It is intended for begin to be called at the beginning of the - * transaction, move to be called for each move, and commit to be called at the end - * the core transaction, via a hook. + * not commit yet. It is intended for move to be called for each move, and commit + * to be called at the end the core transaction, via a hook. * * @param int $oldPageId Page ID before move/change * @param Title $newPage Page after move/change diff --git a/includes/WorkflowLoaderFactory.php b/includes/WorkflowLoaderFactory.php index 647ece0..fd52375 100644 --- a/includes/WorkflowLoaderFactory.php +++ b/includes/WorkflowLoaderFactory.php @@ -113,7 +113,7 @@ * @throws InvalidInputException * @throws UnknownWorkflowIdException */ - protected function loadWorkflowById( /* Title or false */ $title, $workflowId ) { + public function loadWorkflowById( /* Title or false */ $title, $workflowId ) { /** @var Workflow $workflow */ $workflow = $this->storage->getStorage( 'Workflow' )->get( $workflowId ); if ( !$workflow ) { diff --git a/maintenance/FlowFixInconsistentBoards.php b/maintenance/FlowFixInconsistentBoards.php new file mode 100644 index 0000000..885dc64 --- /dev/null +++ b/maintenance/FlowFixInconsistentBoards.php @@ -0,0 +1,139 @@ +<?php + +use Flow\Content\BoardContent; +use Flow\Container; +use Flow\Exception\UnknownWorkflowIdException; + +require_once ( getenv( 'MW_INSTALL_PATH' ) !== false + ? getenv( 'MW_INSTALL_PATH' ) . '/maintenance/Maintenance.php' + : dirname( __FILE__ ) . '/../../../maintenance/Maintenance.php' ); + +/** + * Changes Flow boards and their topics to be associated with their current title, based on the JSON content + * Fixes inconsistent bugs like T138310. + * + * There is a dry run available. + * + * @ingroup Maintenance + */ +class FlowFixInconsistentBoards extends LoggedUpdateMaintenance { + /** + * @var DbFactory $dbFactory + */ + protected $dbFactory; + + /** + * @var WorkflowLoaderFactory $workflowLoaderFactory + */ + protected $workflowLoaderFactory; + + public function __construct() { + parent::__construct(); + + $this->mDescription = 'Changes Flow boards and their topics to be associated with their current title, based on the JSON content. Must be run separately for each affected wiki.'; + + $this->addOption( 'dry-run', 'Only prints the board names, without changing anything.' ); + $this->addOption( 'namespaceName', 'Name of namespace to check, otherwise all', false, true ); + $this->addOption( 'limit', 'Limit of inconsistent pages to identify (and fix if not a dry run). Defaults to no limit', false, true ); + + $this->setBatchSize( 300 ); + } + + protected function getUpdateKey() { + return 'FlowFixInconsistentBoards:version1'; + } + + public function doDBUpdates() { + global $wgLang; + + $this->dbFactory = Container::get( 'db.factory' ); + $this->workflowLoaderFactory = Container::get( 'factory.loader.workflow' ); + + $this->boardMover = Container::get( 'board_mover' ); + + $dryRun = $this->hasOption( 'dry-run' ); + + $limit = $this->getOption( 'limit' ); + + $wikiDbw = $this->dbFactory->getWikiDB( DB_MASTER ); + + $iterator = new BatchRowIterator( $wikiDbw, 'page', 'page_id', $this->mBatchSize ); + $iterator->setFetchColumns( [ 'page_namespace', 'page_title', 'page_latest' ] ); + $iterator->addConditions( [ + 'page_content_model' => CONTENT_MODEL_FLOW_BOARD, + ] ); + + if ( $this->hasOption( 'namespaceName' ) ) { + $namespaceName = $this->getOption( 'namespaceName' ); + $namespaceId = $wgLang->getNsIndex( $namespaceName ); + + if ( !$namespaceId ) { + $this->error( "'$namespaceName' is not a valid namespace name" ); + return; + } + + if ( $namespaceId == NS_TOPIC ) { + $this->error( 'This script can not be run on the Flow topic namespace' ); + return; + } + + $iterator->addConditions( [ + 'page_namespace' => $namespaceId, + ] ); + } else { + $iterator->addConditions( [ + 'page_namespace != ' . NS_TOPIC, + ] ); + } + + $checkedCount = 0; + $inconsistentCount = 0; + foreach ( $iterator as $rows ) { + foreach ( $rows as $row ) { + $checkedCount++; + $coreTitle = Title::makeTitle( $row->page_namespace, $row->page_title ); + $revision = Revision::newFromId( $row->page_latest ); + $content = $revision->getContent( Revision::RAW ); + if ( !$content instanceof BoardContent ) { + $actualClass = get_class( $content ); + $this->error( "ERROR: '$coreTitle' content is a '$actualClass', but should be '" . BoardContent::class . "'." ); + continue; + } + $workflowId = $content->getWorkflowId(); + $workflowIdAlphadecimal = $workflowId->getAlphadecimal(); + try { + $workflow = $this->workflowLoaderFactory->loadWorkflowById( false, $workflowId ); + } catch ( UnknownWorkflowIdException $ex ) { + // This is a different error (a core page refers to + // a non-existent workflow), which this script can not fix. + $this->error( "ERROR: '$coreTitle' refers to workflow ID '$workflowIdAlphadecimal', which could not be found." ); + continue; + } + if ( !$workflow->matchesTitle( $coreTitle ) ) { + $workflowTitle = $workflow->getOwnerTitle(); + $this->output( "INCONSISTENT: Core title for '$workflowIdAlphadecimal' is '$coreTitle', but Flow title is '$workflowTitle'\n" ); + + if ( !$dryRun ) { + $this->boardMover->move( (int)$row->page_id, $coreTitle ); + $this->boardMover->commit(); + $this->output( "FIXED: Updated '$workflowIdAlphadecimal' to match core title, '$coreTitle'\n" ); + } + + $inconsistentCount++; + if ( $limit !== null && $inconsistentCount >= $limit ) { + break; + } + } + } + + $action = $dryRun ? 'Identified' : 'Fixed'; + $this->output( "Checked a total of $checkedCount Flow boards. $action a total of $inconsistentCount inconsistent boards.\n" ); + if ( $limit !== null && $inconsistentCount >= $limit ) { + break; + } + } + } +} + +$maintClass = 'FlowFixInconsistentBoards'; +require_once( RUN_MAINTENANCE_IF_MAIN ); diff --git a/maintenance/convertNamespaceFromWikitext.php b/maintenance/convertNamespaceFromWikitext.php index 064cd5f..303cee7 100644 --- a/maintenance/convertNamespaceFromWikitext.php +++ b/maintenance/convertNamespaceFromWikitext.php @@ -15,7 +15,7 @@ public function __construct() { parent::__construct(); $this->mDescription = "Converts a single namespace of wikitext talk pages to Flow"; - $this->addArg( 'namespace', 'Name of the namespace to convert' ); + $this->addArg( 'namespaceName', 'Name of the namespace to convert' ); $this->addOption( 'no-convert-templates', 'Comma-separated list of templates that indicate a page should not be converted', -- To view, visit https://gerrit.wikimedia.org/r/322223 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: newchange Gerrit-Change-Id: I6a1a410db0893049651fbbbd6f9b9f13360c34c3 Gerrit-PatchSet: 1 Gerrit-Project: mediawiki/extensions/Flow Gerrit-Branch: master Gerrit-Owner: Mattflaschen <mflasc...@wikimedia.org> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits