Skip to content
Open
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
71aedca
Test also with MW 44
JeroenDeDauw Jul 3, 2025
26cce25
Use new class paths
JeroenDeDauw Jul 3, 2025
df37c59
Localisation updates from https://translatewiki.net.
translatewiki Jul 24, 2025
e85048f
Localisation updates from https://translatewiki.net.
translatewiki Jul 31, 2025
33300cc
Localisation updates from https://translatewiki.net.
translatewiki Aug 11, 2025
1ff9144
Localisation updates from https://translatewiki.net.
translatewiki Aug 14, 2025
51c460d
Localisation updates from https://translatewiki.net.
translatewiki Aug 18, 2025
c670288
add concurrency group to avoid duplicate runs for the same ref.
freephile Dec 10, 2025
7aa9268
Use act to test locally before commit
freephile Dec 10, 2025
9117772
ensure that extensions: mbstring, intl, pdo_sqlite, php-ast are avai…
freephile Dec 11, 2025
0d66497
change CSS class order for new Codex Html::errorBox() output
freephile Dec 11, 2025
bc4927d
add guard against missing command
freephile Dec 11, 2025
5d4ec00
make command messaging dynamic like others
freephile Dec 11, 2025
80bfb0b
comment more clearly what is ignored
freephile Dec 11, 2025
3f7482c
update parser tests for 1.43 and 1.44
freephile Dec 11, 2025
c41cdd2
Skip Psalm on PHP 8.4 until we can upgrade psalm to 5.x
freephile Dec 11, 2025
4ee24c1
Add better file-level comments
freephile Dec 15, 2025
76d4676
Replace usage of ParserOutput#getText
freephile Dec 15, 2025
a9d53a9
Replace usage of ParserOutput#getText
freephile Dec 15, 2025
07b0db2
remove trailing whitespace
freephile Dec 15, 2025
b7868a4
remove dead fallback code
freephile Dec 15, 2025
9efe8a2
Do not extend TestCase
freephile Dec 15, 2025
1dc19de
better cache key name
freephile Dec 15, 2025
a63aa76
mark as phony
freephile Dec 15, 2025
bed3485
use explicit conditions
freephile Dec 15, 2025
b1e386c
simplify assertSame to use $parserOutput
freephile Dec 16, 2025
4d962d1
use parser pipeline in assertion tests
freephile Dec 16, 2025
852e97d
Apply suggestion from @Copilot
freephile Mar 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 99 additions & 50 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ on:
push:
pull_request:

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: true

jobs:
test:
name: "PHPUnit: MW ${{ matrix.mw }}, PHP ${{ matrix.php }}"
Expand All @@ -13,21 +17,12 @@ jobs:
fail-fast: false
matrix:
include:
- mw: 'REL1_39'
php: 8.1
experimental: false
- mw: 'REL1_40'
php: 8.1
experimental: false
- mw: 'REL1_41'
php: 8.2
experimental: false
- mw: 'REL1_42'
php: 8.2
experimental: false
- mw: 'REL1_43'
php: 8.3
experimental: false
- mw: 'REL1_44'
php: 8.4
experimental: false
- mw: 'master'
php: 8.4
experimental: true
Expand All @@ -43,7 +38,7 @@ jobs:
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: mbstring, intl
extensions: mbstring, intl, pdo_sqlite, php-ast
tools: composer

- name: Cache MediaWiki
Expand All @@ -54,49 +49,80 @@ jobs:
mediawiki
!mediawiki/extensions/
!mediawiki/vendor/
key: mw_${{ matrix.mw }}-php${{ matrix.php }}
key: mw_${{ matrix.mw }}-php${{ matrix.php }}-${{ runner.os }}
restore-keys: |
mw_${{ matrix.mw }}-php${{ matrix.php }}-
mw_${{ matrix.mw }}-

- name: Cache Composer cache
- name: Cache composer cache
id: cache-composer
uses: actions/cache@v4
with:
path: ~/.composer/cache
key: composer-php${{ matrix.php }}
path: ~/.cache/composer
key: composer-${{ matrix.php }}-${{ hashFiles('**/composer.lock') }}
restore-keys: |
composer-${{ matrix.php }}-

- uses: actions/checkout@v4
- name: Checkout (EarlyCopy)
uses: actions/checkout@v4
with:
path: EarlyCopy

- name: Install MediaWiki
if: steps.cache-mediawiki.outputs.cache-hit != 'true'
working-directory: ~
working-directory: ${{ github.workspace }}
run: bash EarlyCopy/.github/workflows/installMediaWiki.sh ${{ matrix.mw }} ExternalContent

- uses: actions/checkout@v4
- name: Checkout extension into MediaWiki tree
uses: actions/checkout@v4
with:
path: mediawiki/extensions/ExternalContent

- name: Composer allow-plugins
run: composer config --no-plugins allow-plugins.composer/installers true

- run: composer update
- name: Composer update (extension + deps)
run: composer update --no-progress --no-interaction --prefer-dist --optimize-autoloader

- name: Run update.php
run: php maintenance/update.php --quick

- name: Run PHPUnit
run: php tests/phpunit/phpunit.php -c extensions/ExternalContent/
- name: Run PHPUnit (junit)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not sure about Junit. We are not consuming it anywhere in the CI pipeline, so it is not needed here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how the code coverage pipeline works, but the --log-junit option to PHPUnit produces a JUnit compatible log file which can be ingested by more coverage analysis tools.

continue-on-error: true

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should fail the CI pipeline if PHPUnit doesn't pass. This sliences the error.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have to come back to look at this in more detail to understand what I did but I believe the intention to "not fail" was simply to make coverage non-blocking... while test failures are blocking. In any case, project policies and preferences are to be respected.

run: php tests/phpunit/phpunit.php -c extensions/ExternalContent/ --log-junit tests/junit.xml

- name: Run PHPUnit with code coverage
run: php tests/phpunit/phpunit.php -c extensions/ExternalContent/ --coverage-clover coverage.xml
- name: Upload PHPUnit JUnit result
uses: actions/upload-artifact@v4
with:
name: phpunit-junit-${{ matrix.mw }}-php${{ matrix.php }}
path: tests/junit.xml
Comment thread
freephile marked this conversation as resolved.
Outdated

- name: Run PHPUnit with code coverage (master only)
if: matrix.mw == 'master'
run: php tests/phpunit/phpunit.php -c extensions/ExternalContent/ --coverage-clover coverage.xml

- name: Upload code coverage
run: bash <(curl -s https://codecov.io/bash)
- name: Upload code coverage (master only) securely
if: matrix.mw == 'master'
continue-on-error: true
uses: codecov/codecov-action@v4

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs a CODECOV_TOKEN. @malberts do we have one for this repo?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just omit for now? I don't want to deal with this now and getting compat fixed is still nice

with:
files: coverage.xml

- name: Run parser tests
run: php tests/parser/parserTests.php --file=extensions/ExternalContent/tests/parser/parserTests.txt
if: matrix.mw >= 'REL1_43'
- name: Upload coverage artifact (master only)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we already have Codecov report, should we upload the coverage artifact from the CI?

if: matrix.mw == 'master'
uses: actions/upload-artifact@v4
with:
name: coverage-${{ matrix.mw }}-php${{ matrix.php }}
path: coverage.xml
Comment on lines +109 to +116

Copilot AI Jan 28, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The path to the coverage.xml file may be incorrect. The file is written to 'coverage.xml' relative to the 'mediawiki' working directory (line 102), which means it's at 'mediawiki/coverage.xml' from the workspace root. The codecov-action and upload-artifact actions run from the workspace root, so the path should be 'mediawiki/coverage.xml' instead of 'coverage.xml'.

Copilot uses AI. Check for mistakes.

- name: Run parser tests (explicit targets)
if: matrix.mw >= 'REL1_43' || matrix.mw == 'master'
run: |
if [[ "${{ matrix.mw }}" == "REL1_43" ]]; then
php tests/parser/parserTests.php --file=extensions/ExternalContent/tests/parser/parserTests-mw143.txt
else
php tests/parser/parserTests.php --file=extensions/ExternalContent/tests/parser/parserTests.txt
fi

static-analysis:
name: "Static Analysis: MW ${{ matrix.mw }}, PHP ${{ matrix.php }}"
Expand All @@ -106,6 +132,8 @@ jobs:
include:
- mw: 'REL1_43'
php: '8.3'
- mw: 'REL1_44'
php: '8.4'

runs-on: ubuntu-latest

Expand All @@ -118,7 +146,7 @@ jobs:
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: mbstring
extensions: mbstring, intl, pdo_sqlite, php-ast
tools: composer, cs2pr

- name: Cache MediaWiki
Expand All @@ -129,24 +157,32 @@ jobs:
mediawiki
!mediawiki/extensions/
!mediawiki/vendor/
# Shared cache key across static-analysis and code-style jobs
# Safe to share because both jobs use the same MW core code
key: mw_static_analysis

@coderabbitai coderabbitai Bot Dec 11, 2025

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Cache key collision: static-analysis and code-style share the same MediaWiki cache.

Both jobs use key: mw_static_analysis, causing them to share a single cached MediaWiki installation. If their dependencies differ or if one job modifies the cache, it could corrupt the other job's environment.

Assign distinct cache keys:

  # In static-analysis job (line 161):
- key: mw_static_analysis
+ key: mw_static_analysis_php${{ matrix.php }}

  # In code-style job (line 231):
- key: mw_static_analysis
+ key: mw_code_style_php${{ matrix.php }}

Or if these jobs are truly identical and can safely share a cache, document this intention and add a comment explaining why the shared key is acceptable.

Also applies to: 231-231

🤖 Prompt for AI Agents
.github/workflows/ci.yml around line 161 (and also line 231): the
static-analysis and code-style jobs both use the identical cache key
`mw_static_analysis`, causing a cache collision; change each job to use a
distinct, descriptive cache key (for example include the job name or purpose and
optionally the OS/hash) such as `mw_static_analysis-${{ matrix.os
}}-static-analysis` and `mw_static_analysis-${{ matrix.os }}-code-style`, or if
sharing is intentional add a comment above both keys explaining why a shared
cache is safe and keep a single shared key.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adding a comment to indicate that a shared cache is intentional

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@freephile, thank you for addressing this! Adding a comment to document that the shared cache between static-analysis and code-style is intentional is exactly the right approach. This will help future maintainers understand that both jobs can safely use the same MediaWiki cache since they have identical requirements.

The comment will clarify that sharing key: mw_static_analysis is by design and prevent confusion down the road. 👍

restore-keys: |
mw_static_analysis
Comment on lines 132 to +164

Copilot AI Jan 28, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cache key 'mw_static_analysis' is shared across different MediaWiki versions (REL1_43 and REL1_44) in the matrix. This will cause cache conflicts where one version's MediaWiki installation may be used for the other version. The cache key should include the matrix.mw variable to differentiate between versions, for example: 'mw_static_analysis_${{ matrix.mw }}'.

Suggested change
key: mw_static_analysis
restore-keys: |
mw_static_analysis
key: mw_static_analysis_${{ matrix.mw }}
restore-keys: |
mw_static_analysis_${{ matrix.mw }}

Copilot uses AI. Check for mistakes.

- name: Cache Composer cache
- name: Cache composer cache
uses: actions/cache@v4
with:
path: ~/.composer/cache
key: composer_static_analysis
path: ~/.cache/composer
key: composer_static_analysis-${{ hashFiles('**/composer.lock') }}
restore-keys: |
composer_static_analysis-

- uses: actions/checkout@v4
- name: Checkout (EarlyCopy)
uses: actions/checkout@v4
with:
path: EarlyCopy

- name: Install MediaWiki
- name: Install MediaWiki (if needed)
if: steps.cache-mediawiki.outputs.cache-hit != 'true'
working-directory: ~
working-directory: ${{ github.workspace }}
run: bash EarlyCopy/.github/workflows/installMediaWiki.sh ${{ matrix.mw }} ExternalContent

- uses: actions/checkout@v4
- name: Checkout extension into MediaWiki tree
uses: actions/checkout@v4
with:
path: mediawiki/extensions/ExternalContent

Expand All @@ -159,9 +195,11 @@ jobs:
- name: PHPStan
run: php vendor/bin/phpstan analyse --error-format=checkstyle --no-progress | cs2pr

- run: php vendor/bin/psalm --shepherd --stats
if: true

- name: Psalm
# Skip Psalm on PHP 8.4 until we can upgrade psalm to 5.x
# MediaWiki core locks psalm to ^4.3
if: matrix.php != '8.4'
run: php vendor/bin/psalm --shepherd --stats

code-style:
name: "Code style: MW ${{ matrix.mw }}, PHP ${{ matrix.php }}"
Expand All @@ -171,6 +209,8 @@ jobs:
include:
- mw: 'REL1_43'
php: '8.3'
- mw: 'REL1_44'
php: '8.4'

runs-on: ubuntu-latest

Expand All @@ -183,7 +223,7 @@ jobs:
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: mbstring, intl, php-ast
extensions: mbstring, intl, pdo_sqlite, php-ast
tools: composer

- name: Cache MediaWiki
Expand All @@ -194,24 +234,32 @@ jobs:
mediawiki
!mediawiki/extensions/
!mediawiki/vendor/
# Shared cache key across static-analysis and code-style jobs
# Safe to share because both jobs use the same MW core code
key: mw_static_analysis
restore-keys: |
mw_static_analysis
Comment on lines 197 to +241

Copilot AI Jan 28, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cache key 'mw_static_analysis' is shared across different MediaWiki versions (REL1_43 and REL1_44) in the matrix. This will cause cache conflicts where one version's MediaWiki installation may be used for the other version. The cache key should include the matrix.mw variable to differentiate between versions, for example: 'mw_static_analysis_${{ matrix.mw }}'.

Suggested change
key: mw_static_analysis
restore-keys: |
mw_static_analysis
key: mw_static_analysis_${{ matrix.mw }}
restore-keys: |
mw_static_analysis_${{ matrix.mw }}

Copilot uses AI. Check for mistakes.

- name: Cache Composer cache
- name: Cache composer cache
uses: actions/cache@v4
with:
path: ~/.composer/cache
key: composer_static_analysis
path: ~/.cache/composer
key: composer_static_analysis-${{ hashFiles('**/composer.lock') }}
restore-keys: |
composer_static_analysis-

- uses: actions/checkout@v4
- name: Checkout (EarlyCopy)
uses: actions/checkout@v4
with:
path: EarlyCopy

- name: Install MediaWiki
- name: Install MediaWiki (if needed)
if: steps.cache-mediawiki.outputs.cache-hit != 'true'
working-directory: ~
working-directory: ${{ github.workspace }}
run: bash EarlyCopy/.github/workflows/installMediaWiki.sh ${{ matrix.mw }} ExternalContent

- uses: actions/checkout@v4
- name: Checkout extension into MediaWiki tree
uses: actions/checkout@v4
with:
path: mediawiki/extensions/ExternalContent

Expand All @@ -221,4 +269,5 @@ jobs:
- name: Composer install
run: composer install --no-progress --no-interaction --prefer-dist --optimize-autoloader

- run: vendor/bin/phpcs -p -s
- name: PHP CodeSniffer
run: vendor/bin/phpcs -p -s
8 changes: 7 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
.phpunit.result.cache
composer.lock
vendor/
vendor/

# Local CI/testing artifacts (act, generated directories, logs)
.actrc
*.log
mediawiki/
EarlyCopy/
3 changes: 3 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,6 @@ psalm:

parser:
php ../../tests/parser/parserTests.php --file=tests/parser/parserTests.txt

parser-mw143:
php ../../tests/parser/parserTests.php --file=tests/parser/parserTests-mw143.txt
17 changes: 13 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,18 +97,20 @@ Parameters: none

## Installation

Platform requirements:
Platform requirements of 4.x:

* [PHP] 8.0 or later (tested up to 8.3)
* [MediaWiki] 1.39 or later (tested up to 1.43 and master)
* [PHP] 8.0 or later (tested up to 8.4)
* [MediaWiki] 1.43 or later (tested up to 1.44 and master)

For older PHP or MediaWiki, use older versions of External Content.

The recommended way to install External Content is using [Composer] with
[MediaWiki's built-in support for Composer][Composer install].

On the commandline, go to your wikis root directory. Then run these two commands:

```shell script
COMPOSER=composer.local.json composer require --no-update professional-wiki/external-content:~3.0
COMPOSER=composer.local.json composer require --no-update professional-wiki/external-content:~4.0
```
```shell script
composer update professional-wiki/external-content --no-dev -o
Expand Down Expand Up @@ -244,6 +246,13 @@ Alternatively, you can execute commands from the MediaWiki root directory:

## Release notes

### Version 4.0.0 - 2025-07-04

* Raised minimum MediaWiki version from 1.39 to 1.43
* Added support for MediaWiki 1.44
* Fixed compatibility issue with the Network extension
* Translation updates

### Version 3.0.1 - 2025-04-06

* Fixed compatibility with MediaWiki 1.43 and above (IDatabase TypeError)
Expand Down
4 changes: 2 additions & 2 deletions extension.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "External Content",
"version": "3.0.1",
"version": "4.0.0",
"license-name": "GPL-2.0-or-later",

"author": [
Expand All @@ -13,7 +13,7 @@
"descriptionmsg": "external-content-desc",

"requires": {
"MediaWiki": ">= 1.39.0",
"MediaWiki": ">= 1.43.0",
"platform": {
"php": ">= 8.0"
}
Expand Down
19 changes: 19 additions & 0 deletions i18n/ce.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"@metadata": {
"authors": [
"Умар"
]
},
"external-content-desc": "Бакъо ло арахьара чулацам чубаккха, масала, «markdown» файлаш, хьан вики агӀонаш тӀехь",
"external-content-fetch-failed": "Файл схьаэца аьтто ца баьлла",
"external-content-domain-not-allowed": "Оцу доменера файлаш дӀахӀотто бакъо йац",
"external-content-extension-not-allowed": "Оцу форматан файлаш дӀахӀотто бакъо йац",
"external-content-url-missing-host": "URL чохь хост йац",
"external-content-url-missing-path": "URL-адрес чохь бац файлан некъ",
"external-content-url-not-bitbucket": "Bitbucket-ан нийса йоцу URL",
"external-content-url-missing-repository": "URL-адресехь йац репозиторин цӀе",
"external-content-tracking-category": "Арахьара чулацам болу агӀонаш",
"external-content-tracking-category-desc": "ХӀокху агӀонан тӀехь чубиллина арахьара чулацам бу",
"external-content-broken-tracking-category": "Боьхна арахьара чулацам болу агӀонаш",
"external-content-broken-tracking-category-desc": "ХӀокху агӀонна арахьара чулацам чубаккха аьтто ца баьлла"
}
12 changes: 11 additions & 1 deletion i18n/pt-br.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,15 @@
]
},
"external-content-desc": "Permite a incorporação de conteúdo externo, como arquivos markdown, em suas páginas wiki",
"external-content-extension-not-allowed": "Incorporar arquivos com esta extensão não é permitido"
"external-content-fetch-failed": "Não foi possível recuperar o arquivo",
"external-content-domain-not-allowed": "Não é permitido incorporar arquivos deste domínio.",
"external-content-extension-not-allowed": "Incorporar arquivos com esta extensão não é permitido",
"external-content-url-missing-host": "URL está sem host",
"external-content-url-missing-path": "URL está sem o caminho do arquivo",
"external-content-url-not-bitbucket": "Não é um URL de Bitbucket válido",
"external-content-url-missing-repository": "O URL tem em falta o nome do repositório",
"external-content-tracking-category": "Páginas com conteúdo externo",
"external-content-tracking-category-desc": "Esta página incorpora conteúdo externo",
"external-content-broken-tracking-category": "Páginas com conteúdo externo corrompido",
"external-content-broken-tracking-category-desc": "Esta página não conseguiu incorporar conteúdo externo"
}
Loading
Loading