Adamw has uploaded a new change for review.
https://gerrit.wikimedia.org/r/61274
Change subject: Cleanup
......................................................................
Cleanup
Branch name (not ID) appears in page history.
Add stubs for ConflictResolution.
Move towards MediaWiki coding standards.
Basic tests.
TODO:
* I noticed too late that the Save Draft stuff is a redundant subset of
Extension:SaveDraft. I haven't removed the code here because it's a
gamble that the other extension will be pushed through to general acceptance.
Change-Id: I90452da7c5a4aa94224b7fc6ee3bbc0678d0e273
---
M Nonlinear.hooks.php
M Nonlinear.i18n.php
M Nonlinear.php
D Nonlinear.setup.php
A includes/Branch.php
A includes/ConflictResolution.php
D includes/branch.php
D includes/branch_store.php
R modules/historyPage/historyPage.css
R modules/historyPage/historyPage.js
M schema/install.sql
A tests/BranchTest.php
A tests/ConflictResolutionTest.php
A tests/NonlinearTests.hooks.php
14 files changed, 387 insertions(+), 148 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Nonlinear
refs/changes/74/61274/1
diff --git a/Nonlinear.hooks.php b/Nonlinear.hooks.php
index 7714412..148afe4 100644
--- a/Nonlinear.hooks.php
+++ b/Nonlinear.hooks.php
@@ -1,51 +1,90 @@
-<?php
+<?php namespace Nonlinear;
-namespace Nonlinear;
-
-class Hook
+class Hooks
{
- static function onLoadExtensionSchemaUpdates(\DatabaseUpdater $du)
- {
- MediawikiBranchStore::addSchemaUpdates($du);
- return true;
- }
+ static function onAlternateEdit( $page ) {
+ global $wgRequest;
- static function onPageHistoryLineEnding($pager, $row, &$summary,
$classes)
- {
- $summary = \Xml::wrapClass($row->branch_id, "branch-label") .
$summary;
- return true;
- }
-
- static function onRevisionInsertComplete($revision, $data, $flags)
- {
- try {
- $parent_branch = new Branch(array(
- 'rev_id' => $revision->getParentId()
- ));
- }
- catch (\MWException $ex) {
- //pass
- }
-
- //XXX if branch is still master...
- //XXX check article branching mode
-
- if ($parent_branch) {
- $parent_branch->adopt_revision($revision->getId());
+ if ( $wgRequest->getVal( 'wpDraft' ) ) {
+ $page->getTitle();
}
return true;
}
- static function onGetQueryInfo($pager, &$queryInfo)
- {
- MediawikiBranchStore::alterPageHistoryQuery($queryInfo);
+ static function onShowEditFormInitial( &$page, &$out ) {
+ global $wgRequest;
+
+ if ( $wgRequest->getVal( 'wpDraft' ) ) {
+ $out->addHtml(
+ \Html::rawElement( 'div', array( 'class' =>
'mw-warning' ),
+ "FOOooo" . "<p>When your changes are
ready for review, click the \"Send for review\" button. Resume editing by
visiting your " . \Linker::link( \SpecialPage::getTitleFor( "Drafts" ),
"drafts" ) . " page."
+ )
+ );
+ /*
+ $page->save = false;
+ $page->diff = true;
+ return false;
+ */
+ }
return true;
}
- //TODO take a less-global hit
- static function addUi($page, $skin)
- {
- $page->addModules('ext.nonlinear.ui');
+ static function onEditPageBeforeEditButtons( &$page, &$buttons,
&$tabindex ) {
+ // TODO: core hook to check "will otherwise go live" condition.
If not, then override the "save" functionality by branching
+ /*
+ if ( is_callable( '\\FlaggablePageView::singleton' ) ) {
+ $view = FlaggablePageView::singleton();
+ }
+ */
+
+ $button_desc = array(
+ 'id' => 'wpDraft',
+ 'name' => 'wpDraft',
+ 'type' => 'submit',
+ 'tabindex' => ++$tabindex,
+ 'value' => wfMessage( 'nonlinear-savedraft' )->text(),
+ 'accesskey' => wfMessage(
'nonlinear-savedraft-accesskey' )->text(),
+ 'title' => wfMessage( 'nonlinear-savedraft-tooltip'
)->text() . ' [' . wfMessage( 'nonlinear-savedraft-accesskey' )->text() . ']',
+ );
+ $buttons['draft'] = \Xml::element( 'input', $button_desc, '' );
+
+ return true;
+ }
+
+ static function onGetQueryInfo( $pager, &$queryInfo ) {
+ BranchStore::alterPageHistoryQuery( $queryInfo );
+ return true;
+ }
+
+ static function onPageHistoryLineEnding( $pager, $row, &$summary,
$classes ) {
+ $summary = \Xml::wrapClass( $row->branch_name, "branch-label" )
. $summary;
+ return true;
+ }
+
+ static function onRevisionInsertComplete( $revision, $data, $flags ) {
+ $parentRevision = \Revision::newFromId(
$revision->getParentId() );
+ if ( $parentRevision ) {
+ $parentBranch = Branch::find( $parentRevision );
+
+ //XXX check article branching mode
+
+ if ( $parentBranch ) {
+ $parentBranch->adopt( $revision );
+ }
+ }
+ return true;
+ }
+
+ static function addUi( $page, $skin ) {
+ if ( $page->getRequest()->getVal( 'action' ) === 'history' ) {
+ $page->addModules( 'ext.nonlinear.historyPage.ui' );
+ }
+ return true;
+ }
+
+ static function onLoadExtensionSchemaUpdates( \DatabaseUpdater $du ) {
+ $du->addExtensionUpdate( array( 'addTable',
+ 'nonlinear_branch', __DIR__ . "/schema/install.sql",
true ) );
return true;
}
}
diff --git a/Nonlinear.i18n.php b/Nonlinear.i18n.php
index 6022520..a57bf49 100644
--- a/Nonlinear.i18n.php
+++ b/Nonlinear.i18n.php
@@ -11,6 +11,10 @@
$messages['en'] = array(
'nonlinear-branch-not-found' => 'Unable to find branch',
'nonlinear-desc' => 'Helps manage page revision history, providing an
interface to fork and merge graphs',
+
+ 'nonlinear-savedraft' => 'Save draft',
+ 'nonlinear-savedraft-tooltip' => 'Save your changes to a sandbox
location',
+ 'nonlinear-savedraft-accesskey' => 'd',
);
/** Message documentation (Message documentation)
@@ -19,6 +23,10 @@
$messages['qqq'] = array(
'nonlinear-branch-not-found' => 'Displayed when a branch id does not
correspond to an existing database record.',
'nonlinear-desc' =>
'{{desc|name=Nonlinear|url=http://www.mediawiki.org/wiki/Extension:Nonlinear}}',
+
+ 'nonlinear-savedraft' => 'Button label for the "Save draft" feature,
displayed on the Edit page',
+ 'nonlinear-savedraft-tooltip' => 'Tooltip help for the "Save draft"
button',
+ 'nonlinear-savedraft-accesskey' => 'Hotkey for saving a draft',
);
/** Asturian (asturianu)
diff --git a/Nonlinear.php b/Nonlinear.php
index d42d12d..9c957ba 100644
--- a/Nonlinear.php
+++ b/Nonlinear.php
@@ -16,40 +16,54 @@
'descriptionmsg' => 'nonlinear-desc',
);
-$wgHooks['BeforePageDisplay'][] = 'Nonlinear\Hook::addUi';
-$wgHooks['LoadExtensionSchemaUpdates'][] = array('Nonlinear\Hook');
+$wgHooks['BeforePageDisplay'][] = 'Nonlinear\Hooks::addUi';
+$wgHooks['LoadExtensionSchemaUpdates'][] =
'Nonlinear\Hooks::onLoadExtensionSchemaUpdates';
-$wgHooks['RevisionInsertComplete'][] =
array('Nonlinear\Hook::onRevisionInsertComplete');
+$wgHooks['RevisionInsertComplete'][] =
'Nonlinear\Hooks::onRevisionInsertComplete';
-#$wgHooks['PageHistoryBeforeList'][] =
array('Nonlinear\Hook::alterPageHistory');
-$wgHooks['PageHistoryPager::getQueryInfo'][] =
array('Nonlinear\Hook::onGetQueryInfo');
-$wgHooks['PageHistoryLineEnding'][] =
array('Nonlinear\Hook::onPageHistoryLineEnding');
+$wgHooks['PageHistoryPager::getQueryInfo'][] =
'Nonlinear\Hooks::onGetQueryInfo';
+$wgHooks['PageHistoryLineEnding'][] =
'Nonlinear\Hooks::onPageHistoryLineEnding';
+
+// Disable "Save Draft" stuff for now
+if ( false ) {
+ $wgHooks['AlternateEdit'][] = 'Nonlinear\Hooks::onAlternateEdit';
+ $wgHooks['EditPageBeforeEditButtons'][] =
'Nonlinear\Hooks::onEditPageBeforeEditButtons';
+ $wgHooks['EditPage::showEditForm:initial'][] =
'Nonlinear\Hooks::onShowEditFormInitial';
+}
+
+$wgHooks['UnitTestsList'][] = 'Nonlinear\Tests\Hooks::onUnitTestsList';
-$ext_dir = dirname( __FILE__ );
+$ext_dir = __DIR__ . "/";
-$wgExtensionMessagesFiles['Nonlinear'] = $ext_dir . '/Nonlinear.i18n.php';
+$wgExtensionMessagesFiles['Nonlinear'] = $ext_dir . 'Nonlinear.i18n.php';
-$includes = $ext_dir . "/includes/";
+$includes = $ext_dir . "includes/";
+$tests = $ext_dir . "tests/";
$wgAutoloadClasses += array(
- 'Nonlinear\Hook' => $ext_dir . "/Nonlinear.hooks.php",
- 'Nonlinear\Branch' => $includes . "branch.php",
- 'Nonlinear\MediawikiBranchStore' => $includes . "branch_store.php",
+ 'Nonlinear\Hooks' => $ext_dir . "Nonlinear.hooks.php",
+
+ 'Nonlinear\Branch' => $includes . "Branch.php",
+ 'Nonlinear\BranchRevisionStore' => $includes . "Branch.php",
+ 'Nonlinear\BranchStore' => $includes . "Branch.php",
+ 'Nonlinear\ConflictResolution' => $includes . "ConflictResolution.php",
+
+ 'Nonlinear\Tests\Hooks' => $tests . "NonlinearTests.hooks.php",
);
$wgResourceModules += array(
- 'ext.nonlinear.ui' => array(
- 'localBasePath' => $ext_dir . '/modules',
- 'remoteExtPath' => 'Nonlinear/modules',
+ 'ext.nonlinear.historyPage.ui' => array(
+ 'localBasePath' => $ext_dir . "modules/historyPage",
+ 'remoteExtPath' => "Nonlinear/modules/historyPage",
'group' => 'ext.nonlinear',
- 'scripts' => 'ext.nonlinear.ui.js',
- 'styles' => 'ext.nonlinear.ui.css',
- 'messages' => array(
- ),
- 'dependencies' => array(
- 'mediawiki.util',
- 'jquery.client',
- ),
- ),
+ 'scripts' => 'historyPage.js',
+ 'styles' => 'historyPage.css',
+ 'messages' => array(
+ ),
+ 'dependencies' => array(
+ 'mediawiki.util',
+ 'jquery.client',
+ ),
+ ),
);
diff --git a/Nonlinear.setup.php b/Nonlinear.setup.php
deleted file mode 100644
index a4abe2d..0000000
--- a/Nonlinear.setup.php
+++ /dev/null
@@ -1,2 +0,0 @@
-<?php
-
diff --git a/includes/Branch.php b/includes/Branch.php
new file mode 100644
index 0000000..79d72d6
--- /dev/null
+++ b/includes/Branch.php
@@ -0,0 +1,130 @@
+<?php namespace Nonlinear;
+
+/**
+ * Tracks article revisions when they diverge from the main history
+ *
+ *
+ * We mark every revision on the branch, to reduce the cost of searches. Only
+ * the parent revision needs to be checked.
+ */
+class Branch
+{
+ protected $id;
+
+ // Restrict to internal factory apis
+ protected function __construct( $id ) {
+ $this->id = $id;
+ }
+
+ function getName() {
+ //FIXME: this is lame, we will be killed by replag. Just keep
track
+ // of fields in the object.
+ return BranchStore::getName( $this->id );
+ }
+
+ /**
+ * Search for
+ * @return Branch or null if not found
+ */
+ static function find( \Revision $rev ) {
+ $branchId = BranchRevisionStore::findByRev( $rev->getId() );
+ if ( $branchId ) {
+ return new Branch( $branchId );
+ }
+ return null;
+ }
+
+ /**
+ * Mark the first revision to diverge
+ *
+ * @return Branch newly created branch
+ */
+ static function create( \Revision $rev, $name = null ) {
+ $branchId = BranchStore::createBranch( $name );
+
+ $branch = new Branch( $branchId );
+ $branch->adopt( $rev );
+
+ return $branch;
+ }
+
+ function adopt( \Revision $rev ) {
+ //FIXME: this is a tricky operation re: permissions. We
+ // would rather set during revision create, to reuse all the
+ // same checks. Also, there might be a race condition where the
+ // revision is temporarily on trunk.
+ BranchRevisionStore::setRevBranch( $rev->getId(), $this->id );
+ }
+}
+
+/**
+ * DB implementation of a branch
+ */
+class BranchStore {
+ static function createBranch( $name = null ) {
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->insert(
+ 'nonlinear_branch',
+ array(
+ 'branch_name' => $name,
+ )
+ );
+ return $dbw->insertId();
+ }
+
+ static function alterPageHistoryQuery( &$queryInfo ) {
+ $queryInfo['tables'][] = 'nonlinear_branch_revision';
+ $queryInfo['tables'][] = 'nonlinear_branch';
+ $queryInfo['fields'][] = 'branch_id';
+ $queryInfo['fields'][] = 'branch_name';
+ $queryInfo['join_conds']['nonlinear_branch_revision'] = array(
+ 'LEFT JOIN',
+ 'br_rev_id = rev_id'
+ );
+ $queryInfo['join_conds']['nonlinear_branch'] = array(
+ 'LEFT JOIN',
+ 'br_branch_id = branch_id'
+ );
+
+ #TODO: per-user branch filter conditions
+ }
+
+ static function getName( $branchId ) {
+ $dbw = wfGetDB( DB_SLAVE );
+ return $dbw->selectField(
+ 'nonlinear_branch',
+ 'branch_name',
+ array('branch_id' => $branchId),
+ __METHOD__
+ );
+ }
+}
+
+/**
+ * DB implementation of a branch-revision link
+ */
+class BranchRevisionStore {
+ static function findByRev( $rev_id ) {
+ $dbw = wfGetDB( DB_SLAVE );
+ return $dbw->selectField(
+ 'nonlinear_branch_revision',
+ 'br_branch_id',
+ array('br_rev_id' => $rev_id),
+ __METHOD__
+ );
+ }
+
+ static function setRevBranch( $rev_id, $branch_id ) {
+ $dbw = wfGetDB( DB_MASTER );
+ $dbw->insert(
+ 'nonlinear_branch_revision',
+ array(
+ 'br_rev_id' => $rev_id,
+ 'br_branch_id' => $branch_id,
+ )
+ );
+ }
+
+ static function findOrphanedRevisions( $page_id ) {
+ }
+}
diff --git a/includes/ConflictResolution.php b/includes/ConflictResolution.php
new file mode 100644
index 0000000..f265826
--- /dev/null
+++ b/includes/ConflictResolution.php
@@ -0,0 +1,29 @@
+<?php namespace Nonlinear;
+
+/**
+ * We encourage the resolution of branches back into trunk by maintaining
+ * a conflict resolution workflow.
+ */
+class ConflictResolution {
+ function __construct( Branch $branch, \User $user ) {
+ }
+
+ function addComment( $comment, $position = null ) {
+ }
+
+ function markAsResolved() {
+ //TODO
+ }
+
+ function markAsRejected() {
+ }
+
+ function reopen() {
+ }
+
+ function tag( $tagName ) {
+ }
+
+ function untag( $tagName ) {
+ }
+}
diff --git a/includes/branch.php b/includes/branch.php
deleted file mode 100644
index fc472e5..0000000
--- a/includes/branch.php
+++ /dev/null
@@ -1,29 +0,0 @@
-<?php
-
-namespace Nonlinear;
-
-/**
- * Interface to a branch.
- */
-class Branch
-{
- function __construct($params)
- {
- $this->store = new MediawikiBranchStore();
-
- if (!empty($params['rev_id'])) {
- $this->id =
$this->store->find_by_rev_id($params['rev_id']);
- }
-
- if (empty($this->id)) {
- throw new \MWException('Unable to find branch');
- }
- }
-
- function adopt_revision($rev_id)
- {
- //XXX this is a tricky operation re: permissions. We
- // would rather set during revision create.
- $this->store->set_revision_branch($rev_id, $this->id);
- }
-}
diff --git a/includes/branch_store.php b/includes/branch_store.php
deleted file mode 100644
index 0caa3e9..0000000
--- a/includes/branch_store.php
+++ /dev/null
@@ -1,50 +0,0 @@
-<?php
-
-namespace Nonlinear;
-
-/**
- * Implementation of branch store, saved in the mediawiki database.
- */
-class MediawikiBranchStore
-{
- function find_by_rev_id($rev_id)
- {
- $dbw = wfGetDB( DB_SLAVE );
- return $dbw->selectField(
- 'branch',
- 'branch_id',
- array('branch_rev_id' => $rev_id),
- __METHOD__
- );
- }
-
- function set_revision_branch($rev_id, $branch_id)
- {
- $dbw = wfGetDB( DB_MASTER );
- $dbw->insert(
- 'branch',
- array(
- 'branch_rev_id' => $rev_id,
- 'branch_id' => $branch_id,
- )
- );
- }
-
- static function addSchemaUpdates(\DatabaseUpdater $du)
- {
- $base = dirname(__FILE__);
- $du->addExtensionUpdate( array( 'addTable',
- 'branch', "$base/../schema/install.sql", true ) );
- }
-
- static function alterPageHistoryQuery(&$queryInfo)
- {
- $queryInfo['tables'][] = 'branch';
- $queryInfo['fields'][] = 'branch_id';
- #XXX per-user branch filter conds
- $queryInfo['join_conds']['branch'] = array(
- 'LEFT JOIN',
- 'branch_rev_id = rev_id'
- );
- }
-}
diff --git a/modules/ext.nonlinear.ui.css b/modules/historyPage/historyPage.css
similarity index 100%
rename from modules/ext.nonlinear.ui.css
rename to modules/historyPage/historyPage.css
diff --git a/modules/ext.nonlinear.ui.js b/modules/historyPage/historyPage.js
similarity index 100%
rename from modules/ext.nonlinear.ui.js
rename to modules/historyPage/historyPage.js
diff --git a/schema/install.sql b/schema/install.sql
index 55f8ee5..b227330 100644
--- a/schema/install.sql
+++ b/schema/install.sql
@@ -1,7 +1,28 @@
-CREATE TABLE IF NOT EXISTS /*_*/branch (
- branch_id integer unsigned NOT NULL,
- -- Foreign key to revision.revision.id
- branch_rev_id integer unsigned NOT NULL
+-- Description of a branch
+CREATE TABLE /*_*/nonlinear_branch (
+ branch_id integer unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
+
+ branch_name varchar(255) DEFAULT NULL
) /*$wgDBTableOptions*/;
-CREATE INDEX /*i*/branch_rev_id ON /*_*/branch (branch_rev_id);
+-- Link a revision to a branch
+CREATE TABLE /*_*/nonlinear_branch_revision (
+ br_id integer unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
+
+ -- Foreign key to nonlinear_branch.branch_id
+ br_branch_id integer unsigned NOT NULL,
+
+ -- Foreign key to revision.rev_id
+ br_rev_id integer unsigned NOT NULL
+) /*$wgDBTableOptions*/;
+CREATE INDEX /*i*/br_branch_id ON /*_*/nonlinear_branch_revision
(br_branch_id);
+CREATE INDEX /*i*/br_rev_id ON /*_*/nonlinear_branch_revision (br_rev_id);
+
+-- Conflict resolution work queue
+CREATE TABLE /*_*/nonlinear_conflict_resolution (
+ cr_id integer unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT,
+
+ -- Foreign key to nonlinear_branch.branch_id
+ cr_branch_id integer unsigned NOT NULL
+) /*$wgDBTableOptions*/;
+CREATE INDEX /*i*/cr_branch_id ON /*_*/nonlinear_conflict_resolution
(cr_branch_id);
diff --git a/tests/BranchTest.php b/tests/BranchTest.php
new file mode 100644
index 0000000..ec0117b
--- /dev/null
+++ b/tests/BranchTest.php
@@ -0,0 +1,65 @@
+<?php
+
+use Nonlinear\Branch;
+use Nonlinear\BranchRevisionStore;
+use Nonlinear\BranchStore;
+
+/**
+ * @group Database
+ * @group medium
+ */
+class BranchTest extends MediaWikiTestCase {
+ protected $page;
+ protected $trunkRevision;
+ protected $iterationMarker = 1;
+
+ function setUp() {
+ parent::setUp();
+
+ $title = Title::newFromText( "aTitle",
$this->getDefaultWikitextNS() );
+ $this->page = new WikiPage( $title );
+
+ $this->trunkRevision = $this->doEdit();
+ }
+
+ function tearDown() {
+ if ( $this->page->exists() ) {
+ $this->page->doDeleteArticle( "test done" );
+ }
+
+ parent::tearDown();
+ }
+
+ protected function doEdit() {
+ $text = "aContent version " . $this->iterationMarker++;
+ $content = ContentHandler::makeContent( $text,
$this->page->getTitle() );
+ $status = $this->page->doEditContent( $content, "testing" );
+
+ $this->assertTrue( $status->isGood() );
+
+ return $this->page->getRevision();
+ }
+
+ function testCreateBranch() {
+ $rev = $this->doEdit();
+
+ $name = "abranchname";
+ $branch = Branch::create( $rev, $name );
+
+ $this->assertEquals( $name, $branch->getName() );
+ $this->assertNotNull( BranchRevisionStore::findByRev(
$rev->getId() ) );
+ }
+
+ function testFindBranch() {
+ $rev = $this->doEdit();
+
+ $name = "abranchname2";
+ $branch = Branch::create( $rev, $name );
+
+ $this->assertNull( Branch::find( $this->trunkRevision ) );
+
+ $foundBranch = Branch::find( $rev );
+ $this->assertNotNull( $foundBranch );
+ $this->assertEquals( $name, $foundBranch->getName() );
+ }
+}
diff --git a/tests/ConflictResolutionTest.php b/tests/ConflictResolutionTest.php
new file mode 100644
index 0000000..4815dc1
--- /dev/null
+++ b/tests/ConflictResolutionTest.php
@@ -0,0 +1,4 @@
+<?php
+
+class ConflictResolutionTest extends MediaWikiTestCase {
+}
diff --git a/tests/NonlinearTests.hooks.php b/tests/NonlinearTests.hooks.php
new file mode 100644
index 0000000..b439761
--- /dev/null
+++ b/tests/NonlinearTests.hooks.php
@@ -0,0 +1,10 @@
+<?php namespace Nonlinear\Tests;
+
+class Hooks {
+ static function onUnitTestsList( &$files ) {
+ $files[] = __DIR__ . 'BranchTest.php';
+ $files[] = __DIR__ . 'ConflictResolutionTest.php';
+
+ return true;
+ }
+}
--
To view, visit https://gerrit.wikimedia.org/r/61274
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I90452da7c5a4aa94224b7fc6ee3bbc0678d0e273
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Nonlinear
Gerrit-Branch: master
Gerrit-Owner: Adamw <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits