diff --git a/Dockerfile b/Dockerfile index aadcf20..354c85c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,21 +1,26 @@ # This Dockerfile can be used to create a Docker image/container # that runs the unit tests on the LinkTitles extension. -FROM mediawiki:1.34 -MAINTAINER Daniel Kraus (https://www.bovender.de) -RUN apt update -yqq && \ - apt install -yqq \ - php7.0-sqlite \ +FROM mediawiki:1.35 +LABEL "MAINTAINER" Daniel Kraus (https://www.bovender.de) +RUN apt-get update -yqq && \ + apt-get install -yqq \ + php7.3-sqlite \ sqlite3 \ unzip \ zip -RUN curl https://raw.githubusercontent.com/composer/getcomposer.org/cb19f2aa3aeaa2006c0cd69a7ef011eb31463067/web/installer -s | php -- --quiet -RUN php composer.phar install + +WORKDIR /var/www/html +ADD install-composer.sh install-composer.sh +RUN chmod +x install-composer.sh +RUN ./install-composer.sh COPY . /var/www/html/extensions/LinkTitles/ RUN mkdir /data && chown www-data /data +RUN php composer.phar update + WORKDIR /var/www/html/maintenance -RUN php install.php --pass admin --dbtype sqlite --extensions LinkTitles Tests admin +RUN php install.php --pass linktitles --dbtype sqlite --extensions LinkTitles Tests admin WORKDIR /var/www/html/tests/phpunit CMD ["php", "phpunit.php", "--group", "bovender"] diff --git a/NEWS.md b/NEWS.md index 65ec9e8..7a9da2f 100644 --- a/NEWS.md +++ b/NEWS.md @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 For changes prior to version 6.0.0, please see [`NEWS.old`](news.old). +## [7.0.0][] - 2020-12-23 + +### Changed + +- The minimum required version of MediaWiki is now 1.32. + +### Fixed + +- Fixed compatibility with MediaWiki version 1.35. + ## [6.0.0][] - 2019-12-31 ### Changed @@ -21,4 +31,5 @@ For changes prior to version 6.0.0, please see [`NEWS.old`](news.old). constant (DB_SLAVE was renamed to DB_REPLICA). NOTE that the minimum required version of MediaWiki is now 1.28 (which is an obsolete version). +[7.0.0]: https://github.com/bovender/LinkTitles/releases/tag/v7.0.0 [6.0.0]: https://github.com/bovender/LinkTitles/releases/tag/v6.0.0 diff --git a/README.md b/README.md index 8df11b0..2f45823 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -LinkTitles -========== +# LinkTitles [MediaWiki extension](https://www.mediawiki.org/wiki/Extension:LinkTitles) that automatically adds links to words that match titles of existing pages. @@ -7,9 +6,7 @@ automatically adds links to words that match titles of existing pages. Minimum requirement: MediaWiki 1.28. Source code documentation can be found at the [Github project pages](https://bovender.github.io/LinkTitles). - -Table of contents ------------------ +## Table of contents 1. [Oveview](#overview) - [Versions](#versions) @@ -43,9 +40,7 @@ Table of contents - [Testing](#testing) 7. [License](#license) - -Overview --------- +## Overview The **LinkTitles** extension automatically adds links to existing page titles that occur on a given page. This will automatically cross-reference your wiki @@ -65,7 +60,6 @@ original content will not be modified. once. Batch processing can either be started from a special page, or from the server's command line (see [below](#batch-processing)). - ### Versions This extension is [semantically versioned](http://semver.org). In short, this @@ -92,9 +86,7 @@ Version | Date | Major changes || For more details, click the 'Details' links, see the `NEWS.md` file in the repository for a user-friendly changelog, or study the commit messages. - -Installation ------------- +## Installation To obtain the extension, you can either download a compressed archive from the [Github releases page](https://github.com/bovender/LinkTitles/releases): Choose @@ -115,9 +107,7 @@ Do not forget to adjust the [configuration](#configuration) to your needs. If your MediaWiki version is really old (1.24 and older), you need to use a [different mechanism](https://www.mediawiki.org/wiki/Manual:Extensions#Installing_an_extension). - -Important note for MediaWiki versions 1.32 and newer ----------------------------------------------------- +## Important note for MediaWiki versions 1.32 and newer **Links can no longer be automatically added when a page is saved with MediaWiki versions 1.32 and newer.** This is because MediaWiki changed the @@ -138,8 +128,7 @@ A workaround is to set up a cron job for the command-line tool, e.g. [T222413]: https://phabricator.wikimedia.org/T222413 [467308]: https://gerrit.wikimedia.org/r/467308 -Usage ------ +## Usage ### Editing a page @@ -248,9 +237,7 @@ See all available options with: php linktitles-cli.php -h - -Configuration -------------- +## Configuration To change the configuration, set the variables in your `LocalSettings.php` file. The code lines below show the default values of the configuration variables. @@ -300,10 +287,9 @@ dummy pages for variants of page titles with different cases. Smart mode is enabled by default. You can disable it to increase performance of the extension. - ### Dealing with custom namespaces - $wgLinkTitlesSourceNamespace = []; + $wgLinkTitlesSourceNamespaces = []; Specifies additional namespaces for pages that should be processed by the LinkTitles extension. If this is an empty array (or anything else that PHP @@ -329,7 +315,7 @@ no links at all because there are no target namespaces at all. #### Example: Default configuration - $wgLinkTitlesSourceNamespace = []; + $wgLinkTitlesSourceNamespaces = []; $wgLinkTitlesTargetNamespaces = []; $wgLinkTitlesSamenamespace = true; @@ -338,7 +324,7 @@ namespace only (i.e., the same namespace that the source page is in). #### Example: Custom namespace only - $wgLinkTitlesSourceNamespace = [ NS_MY_NAMESPACE]; + $wgLinkTitlesSourceNamespaces = [ NS_MY_NAMESPACE]; $wgLinkTitlesTargetNamespaces = []; $wgLinkTitlesSamenamespace = true; @@ -348,7 +334,7 @@ is in). #### Example: Link to `NS_MAIN` only - $wgLinkTitlesSourceNamespace = [ NS_MY_NAMESPACE]; + $wgLinkTitlesSourceNamespaces = [ NS_MY_NAMESPACE]; $wgLinkTitlesTargetNamespaces = [ NS_MAIN ]; $wgLinkTitlesSamenamespace = false; @@ -459,18 +445,14 @@ The `LinkTitles:Special` page performs batch processing of pages by repeatedly calling itself. This happens to prevent timeouts on your server. The default reload interval is 1 second. +## Development -Development ------------ - -If you wish to contribute, please issue pull requests against the `develop` -branch, as I roughly follow Vincent Driessen's advice on [A successful Git -branching model](http://nvie.com/git-model) (knowing that there are -[alternative workflows](http://scottchacon.com/2011/08/31/github-flow.html)). - -The `master` branch contains stable releases only, so it is safe to pull the -master branch if you want to install the extension for your own Wiki. - +As of December 2020, there is only one major branch where all development takes +place. I used to follow Vincent Driessen's advice on [A successful Git +branching model](http://nvie.com/git-model), but this did not work out for me +after all. Pull requests from other developers were usually issued against the +`master` branch, and the constant switching between the `develop` and the `master` +branches was prone to cause a mess. ### Contributors @@ -480,8 +462,7 @@ master branch if you want to install the extension for your own Wiki. - @tetsuya-zama, bug fix - @yoshida3669, namespace-related bug fixes - Caleb Mingle (@dentafrice), bug fix -- @paladox, bug fixes - +- @paladox, bug fixes and compatilibity fixes ### Testing @@ -489,6 +470,20 @@ Starting from version 5, LinkTitles finally comes with phpunit tests. The code is not 100% covered yet. If you find something does not work as expected, let me know and I will try to add unit tests and fix it. +#### Testing with Docker + +If you have [Docker](https://www.docker.com) available, simply to this: + + docker build -t bovender/linktitles . + docker run -it --rm bovender/linktitles # repeat as necessary + +Or: + + make build-test-container + make test # repeat as necessary + +#### The Olde Way + Here's how I set up the testing environment. This may not be the canonical way to do it. Basic information on testing MediaWiki can be found [here](https://www.mediawiki.org/wiki/Manual:PHP_unit_testing). @@ -547,9 +542,7 @@ use Ubuntu). If you linked just the LinkTitles extension in step 5, only this extension will be tested. - -License -------- +## License Copyright 2012-2020 Daniel Kraus (GitHub: @bovender) diff --git a/extension.json b/extension.json index a158071..d23825f 100644 --- a/extension.json +++ b/extension.json @@ -15,7 +15,7 @@ "license-name": "GPL-2.0+", "descriptionmsg": "linktitles-desc", "requires": { - "MediaWiki": ">= 1.28.0" + "MediaWiki": ">= 1.32.0" }, "config": { "LinkTitlesParseOnEdit": true, diff --git a/includes/Source.php b/includes/Source.php index 95df48e..c7a1b25 100644 --- a/includes/Source.php +++ b/includes/Source.php @@ -23,6 +23,8 @@ */ namespace LinkTitles; +use MediaWiki\MediaWikiServices; + /** * Represents a page that is a potential link target. */ @@ -149,7 +151,7 @@ class Source { * @return boolean True if the page contains the __NOAUTOLINKS__ magic word. */ public function hasNoAutolinksMagicWord() { - return \MediaWiki\MediaWikiServices::getInstance()->getMagicWordFactory()->get( 'MAG_LINKTITLES_NOAUTOLINKS' )->match( $this->getText() ); + return MediaWikiServices::getInstance()->getMagicWordFactory()->get( 'MAG_LINKTITLES_NOAUTOLINKS' )->match( $this->getText() ); } /** diff --git a/includes/Target.php b/includes/Target.php index 9ccd603..d22c084 100644 --- a/includes/Target.php +++ b/includes/Target.php @@ -210,7 +210,7 @@ class Target { // page does indeed contain this magic word, return the page title // as-is (unlinked). if ( $this->config->enableNoTargetMagicWord ) { - if ( $this->getContent()->matchMagicWord( \MediaWiki\MediaWikiServices::getInstance()->getMagicWordFactory()->get('MAG_LINKTITLES_NOTARGET') ) ) { + if ( $this->getContent()->matchMagicWord( \MediaWiki\MediaWikiServices::getInstance()->getMagicWordFactory()->get( 'MAG_LINKTITLES_NOTARGET' ) ) ) { return false; } }; diff --git a/install-composer.sh b/install-composer.sh new file mode 100644 index 0000000..9aa0c1f --- /dev/null +++ b/install-composer.sh @@ -0,0 +1,22 @@ +#!/bin/sh + +# This is a slightly modified version of the installer script published at +# https://getcomposer.org/doc/faqs/how-to-install-composer-programmatically.md +# It does not depend on `wget` and uses `curl` instead. + +EXPECTED_CHECKSUM="$(curl -q https://composer.github.io/installer.sig)" +php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" +ACTUAL_CHECKSUM="$(php -r "echo hash_file('sha384', 'composer-setup.php');")" + +if [ "$EXPECTED_CHECKSUM" != "$ACTUAL_CHECKSUM" ] +then + >&2 echo 'ERROR: Invalid installer checksum' + rm composer-setup.php + exit 1 +fi + +# May need to remove the explicit pinning of version 1 in the future +php composer-setup.php --quiet --1 +RESULT=$? +rm composer-setup.php +exit $RESULT diff --git a/tests/phpunit/LinkerTest.php b/tests/phpunit/LinkerTest.php index 31ce2ca..b084861 100644 --- a/tests/phpunit/LinkerTest.php +++ b/tests/phpunit/LinkerTest.php @@ -37,7 +37,8 @@ class LinkTitlesLinkerTest extends LinkTitles\TestCase { protected $title; - protected function setUp() { + protected function setUp(): void + { parent::setUp(); // call last to have the Targets object invalidated after inserting the page } @@ -315,13 +316,13 @@ class LinkTitlesLinkerTest extends LinkTitles\TestCase { // Reset namespace caches. // See https://stackoverflow.com/q/45974979/270712 - MWNamespace::getCanonicalNamespaces( true ); + \MWNamespace::getCanonicalNamespaces(true); global $wgContLang; $wgContLang->resetNamespaces(); $this->assertTrue( MWNamespace::exists( $ns ), "The namespace with id $ns should exist!" ); $this->insertPage( "in custom namespace", 'This is a page in a custom namespace', $ns ); - LinKTitles\Targets::invalidate(); + LinkTitles\Targets::invalidate(); $linker = new LinkTitles\Linker( $config ); $source = LinkTitles\Source::createFromTitleAndText( $this->title, $input, $config ); $result = $linker->linkContent( $source ); diff --git a/tests/phpunit/SplitterTest.php b/tests/phpunit/SplitterTest.php index 28f3348..02252e7 100644 --- a/tests/phpunit/SplitterTest.php +++ b/tests/phpunit/SplitterTest.php @@ -1,4 +1,5 @@ ('bovender') * @@ -25,78 +26,81 @@ * * @group bovender */ -class SplitterTest extends MediaWikiTestCase { +class SplitterTest extends \MediaWikiTestCase +{ /** * @dataProvider provideSplitData */ - public function testSplit( $skipTemplates, $parseHeadings, $input, $expectedOutput ) { + public function testSplit($skipTemplates, $parseHeadings, $input, $expectedOutput) + { $config = new LinkTitles\Config(); $config->skipTemplates = $skipTemplates; $config->parseHeadings = $parseHeadings; LinkTitles\Splitter::invalidate(); - $splitter = LinkTitles\Splitter::singleton( $config ); - $this->assertSame( $skipTemplates, $splitter->config->skipTemplates, 'Splitter has incorrect skipTemplates config'); - $this->assertSame( $parseHeadings, $splitter->config->parseHeadings, 'Splitter has incorrect parseHeadings config'); - $this->assertSame( $expectedOutput, $splitter->split( $input ) ); + $splitter = LinkTitles\Splitter::singleton($config); + $this->assertSame($skipTemplates, $splitter->config->skipTemplates, 'Splitter has incorrect skipTemplates config'); + $this->assertSame($parseHeadings, $splitter->config->parseHeadings, 'Splitter has incorrect parseHeadings config'); + $this->assertSame($expectedOutput, $splitter->split($input)); } // TODO: Add more examples. - public static function provideSplitData() { + public static function provideSplitData() + { return [ [ true, // skipTemplates false, // parseHeadings 'this may be linked [[this may not be linked]]', - [ 'this may be linked ', '[[this may not be linked]]', '' ] + ['this may be linked ', '[[this may not be linked]]', ''] ], [ true, // skipTemplates false, // parseHeadings 'this may be linked this may not be linked', - [ 'this may be linked ', 'this may not be linked', '' ] + ['this may be linked ', 'this may not be linked', ''] ], [ true, // skipTemplates false, // parseHeadings 'With skipTemplates = true, this may be linked {{mytemplate|param=link target}}', - [ 'With skipTemplates = true, this may be linked ', '{{mytemplate|param=link target}}', '' ] + ['With skipTemplates = true, this may be linked ', '{{mytemplate|param=link target}}', ''] ], [ false, // skipTemplates false, // parseHeadings 'With skipTemplates = false, this may be linked {{mytemplate|param=link target}}', - [ 'With skipTemplates = false, this may be linked ', '{{mytemplate|param=', 'link target}}' ] + ['With skipTemplates = false, this may be linked ', '{{mytemplate|param=', 'link target}}'] ], [ true, // skipTemplates false, // parseHeadings 'With skipTemplates = true, this may be linked {{mytemplate|param={{transcluded}}}}', - [ 'With skipTemplates = true, this may be linked ', '{{mytemplate|param={{transcluded}}}}', '' ] + ['With skipTemplates = true, this may be linked ', '{{mytemplate|param={{transcluded}}}}', ''] ], [ true, // skipTemplates true, // parseHeadings "With parseHeadings = true,\n==a heading may be linked==\n", - [ "With parseHeadings = true,\n==a heading may be linked==\n" ] + ["With parseHeadings = true,\n==a heading may be linked==\n"] ], [ true, // skipTemplates false, // parseHeadings // no trailing newline in the following string because it would be swallowed "With parseHeadings = false,\n==a heading may not be linked==", - [ "With parseHeadings = false,\n", "==a heading may not be linked==", '' ] + ["With parseHeadings = false,\n", "==a heading may not be linked==", ''] ], [ true, // skipTemplates true, // parseHeadings "With parseHeadings = true,\n==a heading with spans may be linked==\n", - [ "With parseHeadings = true,\n==", "", "a heading with spans may be linked", "", "==\n" ] + ["With parseHeadings = true,\n==", "", "a heading with spans may be linked", "", "==\n"] ], [ true, // skipTemplates true, // parseHeadings "With parseHeadings = true,\n==
a heading with divs may be linked
==\n", - [ "With parseHeadings = true,\n==", "
", "a heading with divs may be linked", "
", "==\n" ] + ["With parseHeadings = true,\n==", "
", "a heading with divs may be linked", "
", "==\n"] ], // Improperly formatted headings cannot be dealt with appropriately for now // [ @@ -109,7 +113,7 @@ class SplitterTest extends MediaWikiTestCase { true, // skipTemplates true, // parseHeadings "Text in noautolinks tagshould be excluded", - [ "Text ", "in noautolinks tag", "should be excluded" ] + ["Text ", "in noautolinks tag", "should be excluded"] ], ]; } diff --git a/tests/phpunit/TargetTest.php b/tests/phpunit/TargetTest.php index 8b3a282..cd35a20 100644 --- a/tests/phpunit/TargetTest.php +++ b/tests/phpunit/TargetTest.php @@ -1,4 +1,5 @@ ('bovender') * @@ -23,39 +24,44 @@ /** * @group bovender */ -class TargetTest extends MediaWikiTestCase { +class TargetTest extends \MediaWikiTestCase +{ /** * @dataProvider provideStartOnly */ - public function testTargetWordStartOnly( $enabled, $delimiter ) { + public function testTargetWordStartOnly($enabled, $delimiter) + { $config = new LinkTitles\Config(); $config->wordStartOnly = $enabled; - $target = new LinKTitles\Target( NS_MAIN, 'test page', $config ); - $this->assertSame( $delimiter, $target->wordStart ); + $target = new LinKTitles\Target(NS_MAIN, 'test page', $config); + $this->assertSame($delimiter, $target->wordStart); } - public static function provideStartOnly() { + public static function provideStartOnly() + { return [ - [ true, '(?wordEndOnly = $enabled; - $target = new LinKTitles\Target( NS_MAIN, 'test page', $config ); - $this->assertSame( $delimiter, $target->wordEnd ); + $target = new LinKTitles\Target(NS_MAIN, 'test page', $config); + $this->assertSame($delimiter, $target->wordEnd); } - public static function provideEndOnly() { + public static function provideEndOnly() + { return [ - [ true, '(?!\pL|\pN)' ], - [ false, '' ] + [true, '(?!\pL|\pN)'], + [false, ''] ]; } } diff --git a/tests/phpunit/TestCase.php b/tests/phpunit/TestCase.php index e41fbde..cadf370 100644 --- a/tests/phpunit/TestCase.php +++ b/tests/phpunit/TestCase.php @@ -22,11 +22,13 @@ namespace LinkTitles; abstract class TestCase extends \MediaWikiTestCase { - protected function setUp() { + protected function setUp(): void + { parent::setUp(); } - protected function tearDown() { + protected function tearDown(): void + { parent::tearDown(); }