diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..35450e2 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: # Replace with a single Patreon username +open_collective: smw +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: ['https://www.semantic-mediawiki.org/wiki/Sponsorship'] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..7dca5c8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,58 @@ +name: CI + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + workflow_dispatch: + +jobs: + + test: + + runs-on: ubuntu-22.04 + continue-on-error: ${{ matrix.experimental }} + + strategy: + matrix: + include: + - mediawiki_version: '1.39' + smw_version: dev-master + php_version: 8.1 + database_type: mysql + database_image: "mariadb:10" + coverage: false + experimental: false + + env: + MW_VERSION: ${{ matrix.mediawiki_version }} + SMW_VERSION: ${{ matrix.smw_version }} + PHP_VERSION: ${{ matrix.php_version }} + DB_TYPE: ${{ matrix.database_type }} + DB_IMAGE: ${{ matrix.database_image }} + + + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Update submodules + run: git submodule update --init --remote + + - name: Run tests + run: make ci + if: matrix.coverage == false + + - name: Run tests with coverage + run: make ci-coverage + if: matrix.coverage == true + + - name: Upload code coverage + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: coverage/php/coverage.xml + if: matrix.coverage == true diff --git a/.gitignore b/.gitignore index e674fc0..b8f1c96 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,22 @@ -\#*# -.#* -.svn +!.* *~ *.kate-swp .*.swp -.idea + +.idea/ + +.envrc +.phpunit.result.cache + +composer.lock +composer.phar + +npm-debug.log vendor/ extensions/ -composer.lock \ No newline at end of file +node_modules/ +conf/ +.DS_Store +.env +coverage \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..2d846d0 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "build"] + path = build + url = https://github.com/gesinn-it-pub/docker-compose-ci.git diff --git a/.travis.install.sh b/.travis.install.sh deleted file mode 100644 index 956a818..0000000 --- a/.travis.install.sh +++ /dev/null @@ -1,69 +0,0 @@ -#! /bin/bash - -set -x - -originalDirectory=$(pwd) - -cd .. - -wget https://github.com/wikimedia/mediawiki/archive/$MW.tar.gz -tar -zxf $MW.tar.gz -mv mediawiki-$MW phase3 - -cd phase3 - -composer install --prefer-source - -if [ "$DB" == "postgres" ] -then - psql -c 'create database its_a_mw;' -U postgres - php maintenance/install.php --dbtype $DBTYPE --dbuser postgres --dbname its_a_mw --pass nyan TravisWiki admin --scriptpath /TravisWiki -else - mysql -e 'create database its_a_mw;' - php maintenance/install.php --dbtype $DBTYPE --dbuser root --dbname its_a_mw --dbpath $(pwd) --pass nyan TravisWiki admin --scriptpath /TravisWiki -fi - -cd extensions - -cp -r $originalDirectory SemanticWatchlist - -cd SemanticWatchlist -composer install --prefer-source - -cd ../.. - -if [ ! -z $SMW ] -then - composer require "mediawiki/semantic-media-wiki=$SMW" --prefer-source -fi - -cat <> composer.local.json -{ - "extra": { - "merge-plugin": { - "merge-dev": true, - "include": [ - "extensions/*/composer.json" - ] - } - } -} -EOT - -composer install --prefer-source - -echo 'require_once( __DIR__ . "/extensions/SemanticWatchlist/SemanticWatchlist.php" );' >> LocalSettings.php - -if [ ! -z $SMW ] -then - echo 'wfLoadExtension( "SemanticMediaWiki" );' >> LocalSettings.php -fi - -echo 'error_reporting(E_ALL| E_STRICT);' >> LocalSettings.php -echo 'ini_set("display_errors", 1);' >> LocalSettings.php -echo '$wgShowExceptionDetails = true;' >> LocalSettings.php -echo '$wgShowDBErrorBacktrace = true;' >> LocalSettings.php -echo '$wgDevelopmentWarnings = true;' >> LocalSettings.php -echo "putenv( 'MW_INSTALL_PATH=$(pwd)' );" >> LocalSettings.php - -php maintenance/update.php --quick diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 51e009b..0000000 --- a/.travis.yml +++ /dev/null @@ -1,28 +0,0 @@ -language: php - -jobs: - include: - - env: DBTYPE=mysql; MW=1.31.6; SMW=3.1.2 - php: 7.2 - - env: DBTYPE=mysql; MW=1.27.0; SMW=2.5.4; TYPE=coverage - php: 7.0 - - env: DBTYPE=sqlite; MW=1.28.2; SMW=2.5.4 - php: 7.0 - - env: DBTYPE=mysql; MW=1.34.0; SMW=dev-master - php: 7.4 - -install: - - travis_retry composer self-update - - bash .travis.install.sh - -script: ../phase3/tests/phpunit/phpunit.php -c ../phase3/extensions/SemanticWatchlist/phpunit.xml.dist - -after_success: - - if [[ "$TYPE" != "coverage" ]]; then exit 0; fi - - ../phase3/tests/phpunit/phpunit.php -c ../phase3/extensions/SemanticWatchlist/phpunit.xml.dist --coverage-clover coverage.clover - - wget https://scrutinizer-ci.com/ocular.phar - - php ocular.phar code-coverage:upload --format=php-clover coverage.clover - -cache: - directories: - - $HOME/.composer/cache diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b37d41b --- /dev/null +++ b/Makefile @@ -0,0 +1,32 @@ +-include .env +export + +# setup for docker-compose-ci build directory +# delete "build" directory to update docker-compose-ci + +ifeq (,$(wildcard ./build/)) + $(shell git submodule update --init --remote) +endif + +EXTENSION=SemanticResultFormats + +# docker images +MW_VERSION?=1.39 +PHP_VERSION?=8.1 +DB_TYPE?=mysql +DB_IMAGE?="mariadb:10" + +# extensions +SMW_VERSION?=5.2.0 + +# composer +# Enables "composer update" inside of extension +COMPOSER_EXT?=true + +# nodejs +# Enables node.js related tests and "npm install" +# NODE_JS?=true + +# check for build dir and git submodule init if it does not exist +include build/Makefile + diff --git a/build b/build new file mode 160000 index 0000000..10d5746 --- /dev/null +++ b/build @@ -0,0 +1 @@ +Subproject commit 10d57463ef3332f79d6b0e763ca8c5d2c4860e16 diff --git a/composer.json b/composer.json index 6ccb6b7..ba07545 100644 --- a/composer.json +++ b/composer.json @@ -25,7 +25,7 @@ "source": "https://github.com/SemanticMediaWiki/SemanticWatchlist" }, "require": { - "php": ">=7.3", + "php": ">=7.4", "composer/installers": "1.*,>=1.0.1" }, "extra": { @@ -33,15 +33,16 @@ "dev-master": "1.3.x-dev" } }, - "autoload": { - "psr-4": { - "SWL\\": "src/" - } - }, "config": { - "process-timeout": 0 + "process-timeout": 0, + "allow-plugins": { + "composer/installers": true + } }, "scripts": { + "test": [ + "@phpunit" + ], "phpunit": "php ../../tests/phpunit/phpunit.php -c phpunit.xml.dist" } } diff --git a/extension.json b/extension.json index 189a38f..fd1f686 100644 --- a/extension.json +++ b/extension.json @@ -13,7 +13,7 @@ "license-name": "GPL-3.0-or-later", "type": "semantic", "requires": { - "MediaWiki": ">= 1.35" + "MediaWiki": ">= 1.39" }, "MessagesDirs": { "SemanticWatchlist": [ @@ -26,11 +26,6 @@ "AutoloadNamespaces": { "SWL\\": "src/" }, - "Hooks": { - }, - "AutoloadClasses": { - "SWL": "src/" - }, "callback": "SWL\\SemanticWatchlist::initExtension", "ExtensionFunctions": [ "SWL\\SemanticWatchlist::onExtensionFunction" diff --git a/src/MediaWiki/Hooks/SkinTemplateNavigationUniversal.php b/src/MediaWiki/Hooks/SkinTemplateNavigationUniversal.php index 2a4550f..c2a4f48 100644 --- a/src/MediaWiki/Hooks/SkinTemplateNavigationUniversal.php +++ b/src/MediaWiki/Hooks/SkinTemplateNavigationUniversal.php @@ -8,7 +8,7 @@ /** * Called after the navigation links have been set up, before they are shown. - * https://secure.wikimedia.org/wikipedia/mediawiki/wiki/Manual:Hooks/SkinTemplateNavigation::Universal + * https://www.mediawiki.org/wiki/Manual:Hooks/SkinTemplateNavigation::Universal * * @ingroup SWL * diff --git a/tests/phpunit/Unit/HookRegistryTest.php b/tests/phpunit/Unit/HookRegistryTest.php index 5ea4304..a84a10f 100644 --- a/tests/phpunit/Unit/HookRegistryTest.php +++ b/tests/phpunit/Unit/HookRegistryTest.php @@ -15,13 +15,13 @@ * * @author mwjames */ -class HookRegistryTest extends \PHPUnit_Framework_TestCase { +class HookRegistryTest extends \PHPUnit\Framework\TestCase { public function testCanConstruct() { $this->assertInstanceOf( '\SWL\HookRegistry', - new HookRegistry( array() ) + new HookRegistry( [] ) ); } @@ -39,14 +39,14 @@ public function testRegister() { ->disableOriginalConstructor() ->getMock(); - $configuration = array( + $configuration = [ 'egSWLEnableTopLink' => false, 'egSWLEnableEmailNotify' => false, 'egSwlSqlDatabaseSchemaPath' => '../foo', 'wgLang' => $language - ); + ]; - $wgHooks = array(); + $wgHooks = []; $instance = new HookRegistry( $configuration ); $instance->register( $wgHooks ); @@ -74,56 +74,56 @@ private function doTestPersonalUrls( $wgHooks, $user ) { ->method( 'getUser' ) ->will( $this->returnValue( $user ) ); - $personal_urls = array(); + $personal_urls = []; $this->assertThatHookIsExcutable( $wgHooks, 'PersonalUrls', - array( &$personal_urls, $title, $skinTemplate ) + [ &$personal_urls, $title, $skinTemplate ] ); } private function doTestUserSaveOptions( $wgHooks, $user ) { - $options = array(); + $options = []; $this->assertThatHookIsExcutable( $wgHooks, 'UserSaveOptions', - array( $user, &$options ) + [ $user, &$options ] ); } private function doTestLoadExtensionSchemaUpdates( $wgHooks ) { - $databaseBase = $this->getMockBuilder( '\DatabaseBase' ) + $database = $this->getMockBuilder( '\Database' ) ->disableOriginalConstructor() ->getMockForAbstractClass(); $databaseUpdater = $this->getMockBuilder( '\DatabaseUpdater' ) ->disableOriginalConstructor() - ->setMethods( array( 'getDB' ) ) + ->setMethods( [ 'getDB' ] ) ->getMockForAbstractClass(); $databaseUpdater->expects( $this->any() ) ->method( 'getDB' ) - ->will( $this->returnValue( $databaseBase ) ); + ->will( $this->returnValue( $database ) ); $this->assertThatHookIsExcutable( $wgHooks, 'LoadExtensionSchemaUpdates', - array( $databaseUpdater ) + [ $databaseUpdater ] ); } private function doTestGetPreferences( $wgHooks, $user ) { - $preferences = array(); + $preferences = []; $this->assertThatHookIsExcutable( $wgHooks, 'GetPreferences', - array( $user, &$preferences ) + [ $user, &$preferences ] ); } @@ -141,11 +141,11 @@ public function doTestStoreUpdate( $wgHooks ) { $semanticData->expects( $this->any() ) ->method( 'getPropertyValues' ) - ->will( $this->returnValue( array() ) ); + ->will( $this->returnValue( [] ) ); $semanticData->expects( $this->any() ) ->method( 'getProperties' ) - ->will( $this->returnValue( array() ) ); + ->will( $this->returnValue( [] ) ); $store = $this->getMockBuilder( '\SMW\Store' ) ->disableOriginalConstructor() @@ -158,7 +158,7 @@ public function doTestStoreUpdate( $wgHooks ) { $this->assertThatHookIsExcutable( $wgHooks, 'SMWStore::updateDataBefore', - array( $store, $semanticData ) + [ $store, $semanticData ] ); } diff --git a/tests/phpunit/Unit/MediaWiki/Hooks/GetPreferencesTest.php b/tests/phpunit/Unit/MediaWiki/Hooks/GetPreferencesTest.php index 81af101..8428bc2 100644 --- a/tests/phpunit/Unit/MediaWiki/Hooks/GetPreferencesTest.php +++ b/tests/phpunit/Unit/MediaWiki/Hooks/GetPreferencesTest.php @@ -2,6 +2,7 @@ namespace SWL\Tests\MediaWiki\Hooks; +use MediaWiki\MediaWikiServices; use SWL\MediaWiki\Hooks\GetPreferences; use SMW\DIProperty; @@ -18,7 +19,7 @@ * * @author mwjames */ -class GetPreferencesTest extends \PHPUnit_Framework_TestCase { +class GetPreferencesTest extends \PHPUnit\Framework\TestCase { public function testCanConstruct() { @@ -30,25 +31,29 @@ public function testCanConstruct() { ->disableOriginalConstructor() ->getMock(); - $preferences = array(); + $preferences = []; + + $namespaceInfo = MediaWikiServices::getInstance()->getNamespaceInfo(); $this->assertInstanceOf( '\SWL\MediaWiki\Hooks\GetPreferences', - new GetPreferences( $user, $language, $preferences ) + new GetPreferences( $user, $language, $preferences, $namespaceInfo ) ); } public function testExecuteOnEnabledEmailNotifyPreference() { - $swlGroup = array(); - $preferences = array(); + $swlGroup = []; + $preferences = []; - $configuration = array( + $configuration = [ 'egSWLEnableEmailNotify' => true, 'egSWLEnableTopLink' => false - ); + ]; - $instance = $this->acquireInstance( $configuration, $swlGroup, $preferences ); + $namespaceInfo = MediaWikiServices::getInstance()->getNamespaceInfo(); + + $instance = $this->acquireInstance( $configuration, $swlGroup, $preferences, $namespaceInfo ); $this->assertTrue( $instance->execute() ); $this->assertCount( 1, $preferences ); @@ -56,15 +61,17 @@ public function testExecuteOnEnabledEmailNotifyPreference() { public function testExecuteOnEnabledTopLinkPreference() { - $swlGroup = array(); - $preferences = array(); + $swlGroup = []; + $preferences = []; - $configuration = array( + $configuration = [ 'egSWLEnableEmailNotify' => false, 'egSWLEnableTopLink' => true - ); + ]; - $instance = $this->acquireInstance( $configuration, $swlGroup, $preferences ); + $namespaceInfo = MediaWikiServices::getInstance()->getNamespaceInfo(); + + $instance = $this->acquireInstance( $configuration, $swlGroup, $preferences, $namespaceInfo ); $this->assertTrue( $instance->execute() ); $this->assertCount( 1, $preferences ); @@ -78,11 +85,11 @@ public function testExecuteOnSingleCategoryGroupPreference() { $swlGroup->expects( $this->once() ) ->method( 'getProperties' ) - ->will( $this->returnValue( array( 'FooProperty' ) ) ); + ->will( $this->returnValue( [ 'FooProperty' ] ) ); $swlGroup->expects( $this->exactly( 2 ) ) ->method( 'getCategories' ) - ->will( $this->returnValue( array( 'FooCategory' ) ) ); + ->will( $this->returnValue( [ 'FooCategory' ] ) ); $swlGroup->expects( $this->once() ) ->method( 'getId' ) @@ -92,20 +99,22 @@ public function testExecuteOnSingleCategoryGroupPreference() { ->method( 'getName' ) ->will( $this->returnValue( 'Foo' ) ); - $preferences = array(); + $preferences = []; - $configuration = array( + $configuration = [ 'egSWLEnableEmailNotify' => false, 'egSWLEnableTopLink' => false - ); + ]; + + $namespaceInfo = MediaWikiServices::getInstance()->getNamespaceInfo(); - $instance = $this->acquireInstance( $configuration, array( $swlGroup ), $preferences ); + $instance = $this->acquireInstance( $configuration, [ $swlGroup ], $preferences, $namespaceInfo ); $this->assertTrue( $instance->execute() ); $this->assertCount( 1, $preferences ); } - protected function acquireInstance( $configuration, $swlGroup, &$preferences ) { + protected function acquireInstance( $configuration, $swlGroup, &$preference, $namespaceInfo ) { $user = $this->getMockBuilder( 'User' ) ->disableOriginalConstructor() @@ -120,8 +129,8 @@ protected function acquireInstance( $configuration, $swlGroup, &$preferences ) { ->will( $this->returnValue( 'en' ) ); $instance = $this->getMockBuilder( '\SWL\MediaWiki\Hooks\GetPreferences' ) - ->setConstructorArgs( array( $user, $language, &$preferences ) ) - ->setMethods( array( 'getAllSwlGroups' ) ) + ->setConstructorArgs( [ $user, $language, &$preference, $namespaceInfo ] ) + ->setMethods( [ 'getAllSwlGroups' ] ) ->getMock(); $instance->expects( $this->once() ) diff --git a/tests/phpunit/Unit/MediaWiki/Hooks/PersonalUrlsTest.php b/tests/phpunit/Unit/MediaWiki/Hooks/SkinTemplateNavigationUniversalTest.php similarity index 58% rename from tests/phpunit/Unit/MediaWiki/Hooks/PersonalUrlsTest.php rename to tests/phpunit/Unit/MediaWiki/Hooks/SkinTemplateNavigationUniversalTest.php index 05c4f5b..e274dd9 100644 --- a/tests/phpunit/Unit/MediaWiki/Hooks/PersonalUrlsTest.php +++ b/tests/phpunit/Unit/MediaWiki/Hooks/SkinTemplateNavigationUniversalTest.php @@ -2,12 +2,12 @@ namespace SWL\Tests\MediaWiki\Hooks; -use SWL\MediaWiki\Hooks\PersonalUrls; - +use MediaWiki\MediaWikiServices; +use SWL\MediaWiki\Hooks\SkinTemplateNavigationUniversal; use Title; /** - * @covers \SWL\MediaWiki\Hooks\PersonalUrls + * @covers \SWL\MediaWiki\Hooks\SkinTemplateNavigationUniversal * * @ingroup Test * @@ -19,11 +19,11 @@ * * @author mwjames */ -class PersonalUrlsTest extends \PHPUnit_Framework_TestCase { +class SkinTemplateNavigationUniversalTest extends \PHPUnit\Framework\TestCase { public function testCanConstruct() { - $personalUrls = array(); + $personalUrls = []; $title = $this->getMockBuilder( 'Title' ) ->disableOriginalConstructor() @@ -33,16 +33,18 @@ public function testCanConstruct() { ->disableOriginalConstructor() ->getMock(); + $userOptionsManager = MediaWikiServices::getInstance()->getUserOptionsManager(); + $this->assertInstanceOf( - '\SWL\MediaWiki\Hooks\PersonalUrls', - new PersonalUrls( $personalUrls, $title, $user ) + '\SWL\MediaWiki\Hooks\SkinTemplateNavigationUniversal', + new SkinTemplateNavigationUniversal( $personalUrls, $title, $user, $userOptionsManager ) ); } public function testExecuteOnEnabledTopLink() { - $configuration = array( 'egSWLEnableTopLink' => true ); - $personalUrls = array( 'watchlist' => true ); + $configuration = [ 'egSWLEnableTopLink' => true ]; + $personalUrls = [ 'watchlist' => true ]; $title = Title::newFromText( __METHOD__ ); @@ -59,7 +61,9 @@ public function testExecuteOnEnabledTopLink() { ->with( $this->equalTo( 'swl_watchlisttoplink' ) ) ->will( $this->returnValue( true ) ); - $instance = new PersonalUrls( $personalUrls, $title, $user ); + $userOptionsManager = MediaWikiServices::getInstance()->getUserOptionsManager(); + + $instance = new SkinTemplateNavigationUniversal( $personalUrls, $title, $user, $userOptionsManager ); $instance->setConfiguration( $configuration ); $this->assertTrue( $instance->execute() ); @@ -68,8 +72,8 @@ public function testExecuteOnEnabledTopLink() { public function testExecuteOnDisabledTopLink() { - $configuration = array( 'egSWLEnableTopLink' => false ); - $personalUrls = array(); + $configuration = [ 'egSWLEnableTopLink' => false ]; + $personalUrls = []; $title = Title::newFromText( __METHOD__ ); @@ -77,7 +81,9 @@ public function testExecuteOnDisabledTopLink() { ->disableOriginalConstructor() ->getMock(); - $instance = new PersonalUrls( $personalUrls, $title, $user ); + $userOptionsManager = MediaWikiServices::getInstance()->getUserOptionsManager(); + + $instance = new SkinTemplateNavigationUniversal( $personalUrls, $title, $user, $userOptionsManager ); $instance->setConfiguration( $configuration ); $this->assertTrue( $instance->execute() ); @@ -86,8 +92,8 @@ public function testExecuteOnDisabledTopLink() { public function testExecuteOnLoggedOutUser() { - $configuration = array( 'egSWLEnableTopLink' => true ); - $personalUrls = array(); + $configuration = [ 'egSWLEnableTopLink' => true ]; + $personalUrls = []; $title = Title::newFromText( __METHOD__ ); @@ -99,7 +105,9 @@ public function testExecuteOnLoggedOutUser() { ->method( 'isLoggedIn' ) ->will( $this->returnValue( false ) ); - $instance = new PersonalUrls( $personalUrls, $title, $user ); + $userOptionsManager = MediaWikiServices::getInstance()->getUserOptionsManager(); + + $instance = new SkinTemplateNavigationUniversal( $personalUrls, $title, $user, $userOptionsManager ); $instance->setConfiguration( $configuration ); $this->assertTrue( $instance->execute() );