Skip to content

Commit 51b49cd

Browse files
Update docker-compose CI (#12)
1 parent 382aefc commit 51b49cd

17 files changed

+163
-108
lines changed

Diff for: .github/workflows/ci.yml

+23-8
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,42 @@ jobs:
1111

1212
test:
1313

14-
runs-on: ubuntu-20.04
14+
runs-on: ubuntu-22.04
1515
continue-on-error: ${{ matrix.experimental }}
1616

1717
strategy:
1818
matrix:
1919
include:
2020
- mediawiki_version: '1.35'
21-
chameleon_version: '4.1.0'
21+
php_version: 7.4
22+
chameleon_version: 4.2.1
23+
database_type: mysql
24+
database_image: "mysql:5.7"
2225
coverage: true
2326
experimental: false
24-
- mediawiki_version: '1.36'
25-
chameleon_version: dev-master
27+
- mediawiki_version: '1.39'
28+
php_version: 8.1
29+
chameleon_version: 4.2.1
30+
database_type: mysql
31+
database_image: "mysql:8"
2632
coverage: false
27-
experimental: true
33+
experimental: false
2834

2935
env:
3036
MW_VERSION: ${{ matrix.mediawiki_version }}
3137
CHAMELEON_VERSION: ${{ matrix.chameleon_version }}
38+
PHP_VERSION: ${{ matrix.php_version }}
39+
DB_TYPE: ${{ matrix.database_type }}
40+
DB_IMAGE: ${{ matrix.database_image }}
3241

3342
steps:
3443
- name: Checkout
35-
uses: actions/checkout@v3
44+
uses: actions/checkout@v4
45+
with:
46+
submodules: recursive
47+
48+
- name: Update submodules
49+
run: git submodule update --init --remote
3650

3751
- name: Run tests
3852
run: make ci
@@ -43,7 +57,8 @@ jobs:
4357
if: matrix.coverage == true
4458

4559
- name: Upload code coverage
46-
uses: codecov/codecov-action@v2
60+
uses: codecov/codecov-action@v4
4761
with:
48-
files: coverage/php/coverage.xml,coverage/js/clover.xml
62+
token: ${{ secrets.CODECOV_TOKEN }}
63+
files: coverage/php/coverage.xml
4964
if: matrix.coverage == true

Diff for: .gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "build"]
2+
path = build
3+
url = https://github.com/gesinn-it-pub/docker-compose-ci.git

Diff for: .phpcs.xml

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?xml version="1.0"?>
2+
<ruleset>
3+
<rule ref="./vendor/mediawiki/mediawiki-codesniffer/MediaWiki">
4+
<exclude name="MediaWiki.NamingConventions.ValidGlobalName.allowedPrefix" />
5+
<exclude name="MediaWiki.Commenting.MissingCovers.MissingCovers" />
6+
<exclude name="MediaWiki.Commenting.FunctionComment.MissingDocumentationPrivate" />
7+
<exclude name="MediaWiki.Commenting.FunctionComment.MissingDocumentationPublic" />
8+
</rule>
9+
<file>.</file>
10+
<arg name="bootstrap" value="./vendor/mediawiki/mediawiki-codesniffer/utils/bootstrap-ci.php"/>
11+
<arg name="extensions" value="php"/>
12+
<arg name="encoding" value="UTF-8"/>
13+
</ruleset>

Diff for: Makefile

+23-44
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,31 @@
1-
EXTENSION := ConfIDentSkin
2-
3-
MW_VERSION ?= 1.35
4-
CHAMELEON_VERSION ?= 4.1.0
5-
6-
EXTENSION_FOLDER := /var/www/html/extensions/${EXTENSION}
7-
COVERAGE_FOLDER := ${EXTENSION_FOLDER}/coverage
8-
PWD := $(shell bash -c "pwd -W 2>/dev/null || pwd")# this way it works on Windows and Linux
9-
IMAGE_NAME := confident-skin:test-${MW_VERSION}-${CHAMELEON_VERSION}
10-
DOCKER_RUN := docker run --rm -v ${PWD}/coverage:${COVERAGE_FOLDER} ${IMAGE_NAME}
11-
PHPUNIT := ${DOCKER_RUN} php tests/phpunit/phpunit.php --testdox -c ${EXTENSION_FOLDER}
12-
NPM := docker run --rm -v ${PWD}/coverage:${COVERAGE_FOLDER} -w ${EXTENSION_FOLDER} ${IMAGE_NAME} npm
1+
-include .env-39
2+
export
133

14-
.PHONY: all
15-
all:
4+
# setup for docker-compose-ci build directory
5+
# delete "build" directory to update docker-compose-ci
166

17-
.PHONY: ci
18-
ci: build test
7+
ifeq (,$(wildcard ./build/))
8+
$(shell git submodule update --init --remote)
9+
endif
1910

20-
.PHONY: ci-coverage
21-
ci-coverage: build test-coverage
22-
23-
.PHONY: build
24-
build:
25-
docker build --tag ${IMAGE_NAME} \
26-
--build-arg=MW_VERSION=${MW_VERSION} \
27-
--build-arg=CHAMELEON_VERSION=${CHAMELEON_VERSION} \
28-
.
29-
30-
.PHONY: test
31-
test: phpunit npm-test
11+
EXTENSION := ConfIDentSkin
3212

33-
.PHONY: test-coverage
34-
test-coverage: phpunit-coverage npm-test-coverage
13+
# docker images
14+
MW_VERSION?=1.35
15+
PHP_VERSION?=7.4
16+
DB_TYPE?=sqlite
17+
DB_IMAGE?=""
3518

36-
.PHONY: phpunit
37-
phpunit:
38-
${PHPUNIT} ${EXTENSION_FOLDER}/tests/phpunit
19+
# extensions
20+
CHAMELEON_VERSION?=4.2.1
3921

40-
.PHONY:
41-
phpunit-coverage:
42-
${PHPUNIT} ${EXTENSION_FOLDER}/tests/phpunit \
43-
--coverage-html ${COVERAGE_FOLDER}/php \
44-
--coverage-clover ${COVERAGE_FOLDER}/php/coverage.xml
22+
# composer
23+
# Enables "composer update" inside of extension
24+
COMPOSER_EXT?=true
4525

46-
.PHONY: npm-test
47-
npm-test:
48-
${NPM} run test
26+
# nodejs
27+
# Enables node.js related tests and "npm install"
28+
NODE_JS?=true
4929

50-
.PHONY: npm-test-coverage
51-
npm-test-coverage:
52-
${NPM} run test-coverage
30+
# check for build dir and git submodule init if it does not exist
31+
include build/Makefile

Diff for: build

Submodule build added at d54a8ce

Diff for: composer.json

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"require-dev": {
3+
"mediawiki/mediawiki-codesniffer": "^39.0",
4+
"phpstan/phpstan": "^1.7",
5+
"vimeo/psalm": "^4.23"
6+
},
7+
"scripts": {
8+
"fix": [ "@phpcs-fix" ],
9+
"test": [ "@analyze", "@phpunit" ],
10+
"test-coverage": [ "@analyze", "@phpunit-coverage" ],
11+
"analyze": ["@phpcs", "@phpstan"],
12+
"phpcs": "phpcs -p -s src tests/phpunit",
13+
"phpcs-fix": "phpcbf src tests/phpunit",
14+
"psalm": "psalm --config=psalm.xml",
15+
"psalm-baseline": "psalm --config=psalm.xml --set-baseline=psalm-baseline.xml",
16+
"phpunit": "php ../../tests/phpunit/phpunit.php -c phpunit.xml.dist --testdox",
17+
"phpunit-coverage": "php ../../tests/phpunit/phpunit.php -c phpunit.xml.dist --testdox --coverage-text --coverage-html coverage/php --coverage-clover coverage/php/coverage.xml"
18+
}
19+
}

Diff for: phpunit.xml.dist

-3
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@
1515
<testsuite name="confident-skin-unit">
1616
<directory>tests/phpunit/Unit</directory>
1717
</testsuite>
18-
<testsuite name="confident-skin-integration">
19-
<directory>tests/phpunit/Integration</directory>
20-
</testsuite>
2118
</testsuites>
2219
<filter>
2320
<whitelist addUncoveredFilesFromWhitelist="true">

Diff for: src/Components/ConfidentVersions.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ public function getHtml(): string {
1313

1414
return $this->indent() . '<!-- versions -->' . $this->indent() .
1515
'<div id="confident-versions" class="' . $this->getClassString() . '" >' .
16-
$this->indent(1) .
16+
$this->indent( 1 ) .
1717
'<span class="openresearch-stack-version">OpenResearchStack: ' .
1818
$wgOpenResearchStackVersion . '</span>' . $this->indent() .
1919
'<span class="confident-version">Confident: ' .
20-
$wgConfidentVersion . '</span>' . $this->indent(-1) .
20+
$wgConfidentVersion . '</span>' . $this->indent( -1 ) .
2121
'</div>';
2222
}
2323
}

Diff for: src/Components/MainContentWithSideBar.php

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ class MainContentWithSideBar extends Component {
1010
*/
1111
public function getHtml(): string {
1212
$mainContent = new MainContent(
13-
$this->getSkinTemplate(), $this->getDomElement(), $this->getIndent());
14-
return SideBarDecorator::for($mainContent)->getHtml();
13+
$this->getSkinTemplate(), $this->getDomElement(), $this->getIndent() );
14+
return SideBarDecorator::for( $mainContent )->getHtml();
1515
}
1616

1717
}

Diff for: src/Components/SideBarDecorator.php

+26-21
Original file line numberDiff line numberDiff line change
@@ -3,57 +3,62 @@
33
namespace Skins\Chameleon\Components;
44

55
use ConfIDentSkin\DomHelpers;
6-
use Skins\Chameleon\ChameleonTemplate;
76

87
class SideBarDecorator extends Component {
98

10-
public static function for(Component $component) {
11-
return new self($component);
9+
public static function for( Component $component ) {
10+
return new self( $component );
1211
}
1312

13+
/**
14+
* The component being decorated.
15+
*
16+
* @var Component
17+
*/
1418
private Component $decoratee;
1519

16-
public function __construct(Component $decoratee) {
20+
public function __construct( Component $decoratee ) {
1721
$this->decoratee = $decoratee;
18-
parent::__construct($decoratee->getSkinTemplate(), $decoratee->getDomElement(),
19-
$decoratee->getIndent());
22+
parent::__construct( $decoratee->getSkinTemplate(), $decoratee->getDomElement(),
23+
$decoratee->getIndent() );
2024
}
2125

2226
/**
2327
* @inheritDoc
2428
* @throws \MWException
2529
*/
2630
public function getHtml(): string {
27-
[$decorateeHtml, $sidebarHtml] =
31+
[ $decorateeHtml, $sidebarHtml ] =
2832
self::createSidebar( $this->decoratee->getHtml() );
2933

3034
return $this->indent() .
31-
'<div class="row">' . $this->indent(1) .
32-
($sidebarHtml != '' ?
33-
'<aside id="sidebar" class="col-12 col-lg-4 order-lg-2">' . $this->indent(1) .
34-
$sidebarHtml . $this->indent(-1) .
35+
'<div class="row">' . $this->indent( 1 ) .
36+
( $sidebarHtml != '' ?
37+
'<aside id="sidebar" class="col-12 col-lg-4 order-lg-2">' . $this->indent( 1 ) .
38+
$sidebarHtml . $this->indent( -1 ) .
3539
'</aside>' :
3640
''
3741
) . $this->indent() .
38-
'<div class="col">'. $this->indent(1) .
39-
$decorateeHtml . $this->indent(-1) .
40-
'</div>' . $this->indent(-1) .
42+
'<div class="col">' . $this->indent( 1 ) .
43+
$decorateeHtml . $this->indent( -1 ) .
44+
'</div>' . $this->indent( -1 ) .
4145
'</div>';
4246
}
4347

4448
private static function createSidebar( $mainHtml ) {
4549
$sidebarHtml = '';
46-
if (str_contains($mainHtml, 'sidebarItem')) {
47-
[$mainHtml, $sidebarHtml] =
48-
DomHelpers::cutElements($mainHtml, fn($n) => self::isSidebarElement($n));
50+
if ( str_contains( $mainHtml, 'sidebarItem' ) ) {
51+
[ $mainHtml, $sidebarHtml ] =
52+
DomHelpers::cutElements( $mainHtml, fn( $n ) => self::isSidebarElement( $n ) );
4953
}
50-
return [$mainHtml, $sidebarHtml];
54+
return [ $mainHtml, $sidebarHtml ];
5155
}
5256

5357
private static function isSidebarElement( $node ) {
54-
if (!$node->hasAttributes())
58+
if ( !$node->hasAttributes() ) {
5559
return false;
56-
$classes = explode(' ', $node->getAttribute('class'));
57-
return in_array('sidebarItem', $classes);
60+
}
61+
$classes = explode( ' ', $node->getAttribute( 'class' ) );
62+
return in_array( 'sidebarItem', $classes );
5863
}
5964
}

Diff for: src/DomHelpers.php

+6-5
Original file line numberDiff line numberDiff line change
@@ -12,28 +12,29 @@ public static function cutElements( string $source, callable $predicate
1212
$sourceNode = self::load( $source );
1313
$targetNode = self::load();
1414

15-
$toCut = iterator_to_array(self::filter( $sourceNode, $predicate ), false);
15+
$toCut = iterator_to_array( self::filter( $sourceNode, $predicate ), false );
1616
foreach ( $toCut as $cut ) {
17-
$cut->parentNode->removeChild($cut);
17+
$cut->parentNode->removeChild( $cut );
1818
self::append( $cut, $targetNode );
1919
}
2020

21-
return [self::save( $sourceNode ), self::save( $targetNode )];
21+
return [ self::save( $sourceNode ), self::save( $targetNode ) ];
2222
}
2323

2424
private static function filter( DOMNode $n, $predicate ): \Generator {
2525
if ( $predicate( $n ) ) {
2626
yield $n;
2727
} else {
28-
foreach ( $n->childNodes as $c )
28+
foreach ( $n->childNodes as $c ) {
2929
yield from self::filter( $c, $predicate );
30+
}
3031
}
3132
}
3233

3334
private static function load( string $source = null ): DOMNode {
3435
$source ??= '<body>';
3536
$doc = new DOMDocument();
36-
$doc->loadHTML('<?xml encoding="utf-8"?>' . $source, LIBXML_NOERROR);
37+
$doc->loadHTML( '<?xml encoding="utf-8"?>' . $source, LIBXML_NOERROR );
3738
return $doc->getElementsByTagName( 'body' )->item( 0 );
3839
}
3940

Diff for: src/Hooks.php

+7-3
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,26 @@
22

33
namespace ConfIDentSkin;
44

5-
use MediaWiki\Hook\BeforeInitializeHook;
65
use MediaWiki\Hook\BeforePageDisplayHook;
76
use MediaWiki\Hook\MediaWikiServicesHook;
8-
use MediaWiki\MediaWikiServices;
97

108
class Hooks implements MediaWikiServicesHook, BeforePageDisplayHook {
119

10+
/**
11+
* List of SCSS files used by the extension or skin.
12+
*
13+
* @var string[] List of SCSS file identifiers.
14+
*/
1215
private $scssFiles = [
1316
'extension-PageForms',
1417
'skin-ContentHeader',
1518
'skin-enableShowAllFieldsToggle',
1619
];
1720

1821
public function __construct( $scssFiles = null ) {
19-
if ($scssFiles !== null)
22+
if ( $scssFiles !== null ) {
2023
$this->scssFiles = $scssFiles;
24+
}
2125
}
2226

2327
/**

Diff for: tests/node-qunit/setup.js

+16-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
1+
const fs = require('fs');
2+
const path = require('path');
13
const resetDom = createDom();
2-
prepareMediaWiki();
34
const sinon = require('sinon');
45

6+
// Define paths for both versions
7+
const oojsJqueryPath = path.resolve(__dirname, '../../../../resources/lib/oojs/oojs.jquery.js');
8+
const oojsPath = path.resolve(__dirname, '../../../../resources/lib/oojs/oojs.js');
9+
510
QUnit.hooks.beforeEach(assert => {
611
sinon.assert.pass = message =>
712
assert.pushResult({ result: true, expected: true, actual: true, message });
813
sinon.assert.fail = message =>
914
assert.pushResult({ result: false, expected: true, actual: false, message });
1015
});
1116

17+
prepareMediaWiki();
18+
1219
QUnit.hooks.afterEach(() => {
1320
resetDom();
1421
sinon.restore();
@@ -41,7 +48,14 @@ function createDom() {
4148
* setup MediaWiki globals: OO, mw, ...
4249
*/
4350
function prepareMediaWiki() {
44-
global.OO = require('../../../../resources/lib/oojs/oojs.jquery.js');
51+
// Check if oojs.js exists (for MW 1.39+), otherwise use oojs.jquery.js (for MW 1.35)
52+
if (fs.existsSync(oojsPath)) {
53+
global.OO = require(oojsPath);
54+
} else if (fs.existsSync(oojsJqueryPath)) {
55+
global.OO = require(oojsJqueryPath);
56+
} else {
57+
throw new Error('Neither oojs.js nor oojs.jquery.js could be found.');
58+
}
4559
require('../../../../resources/lib/ooui/oojs-ui-core.js');
4660
require('../../../../resources/lib/ooui/oojs-ui-widgets.js');
4761
require('../../../../resources/lib/ooui/oojs-ui-wikimediaui');

0 commit comments

Comments
 (0)