How to Set Up CI/CD for MediaWiki Extensions GitHub Actions
Why CI/CD Matters for MediaWiki Extensions
MediaWiki powers some of the world’s largest wikis – Wikipedia, Wikimedia Commons, and countless community sites. Extensions add critical functionality, from visual editors to semantic querying. Because extensions are often shared across many installations, a reliable continuous integration / continuous deployment (CI/CD) pipeline is essential to keep code quality high, catch regressions early, and ship releases confidently.
Core Concepts
- GitHub Actions – the built‑in CI/CD engine on GitHub. It runs jobs in isolated containers or virtual machines, provides a secret store, and integrates tightly with pull‑requests and tags.
- MediaWiki test harness – MediaWiki ships a Docker‑Compose based test suite (
docker‑compose‑ci) used by many extensions (e.g., Semantic MediaWiki). It spins up a fresh MediaWiki core, a database, and any required services. - Extension.json – the modern manifest for MediaWiki extensions. Declaring dependencies here lets the test harness install the correct MediaWiki version automatically.
Prerequisites
- A GitHub repository containing your extension source.
- Extension.json and a
composer.jsonthat listmediawiki/semantic-media-wikior the core version you target. - Docker installed locally (for debugging) – the same images are used in the CI runners.
Step‑by‑step Workflow
The following example sets up a minimal CI pipeline that runs linting, PHP unit tests, and JavaScript tests on every push and pull‑request. It also creates a GitHub release when a tag matching v*.*.* is pushed.
1. Create .github/workflows/ci.yml
name: CI for MediaWiki Extension
on:
push:
branches: ["**"]
tags: ["v*.*.*"]
pull_request:
branches: ["**"]
jobs:
test:
runs-on: ubuntu-latest
services:
mariadb:
image: mariadb:10.11
env:
MYSQL_ROOT_PASSWORD: rootpw
MYSQL_DATABASE: wikidb
ports: ["3306:3306"]
options: >-
--health-cmd "mysqladmin ping --silent"
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Set up PHP
uses: shivammathur/setup-php@v2
with:
php-version: '8.2'
extensions: mbstring, intl, zip
ini-values: date.timezone=UTC
coverage: xdebug
- name: Cache Composer packages
uses: actions/cache@v3
with:
path: vendor
key: ${{ runner.os }}-composer-${{ hashFiles('composer.lock') }}
restore-keys: |
${{ runner.os }}-composer-
- name: Install dependencies
run: composer install --prefer-dist --no-progress --no-suggest
- name: Lint PHP files
run: composer phpcs
- name: Run PHP unit tests (MediaWiki test harness)
env:
DB_HOST: 127.0.0.1
DB_USER: root
DB_PASSWORD: rootpw
DB_NAME: wikidb
run: |
git clone https://gerrit.wikimedia.org/r/mediawiki/extensions/docker-compose-ci.git
cd docker-compose-ci
make ci
cd ..
php vendor/bin/phpunit --testsuite extension
- name: Set up Node
uses: actions/setup-node@v3
with:
node-version: '20'
cache: 'npm'
- name: Install JS dependencies
run: npm ci
- name: Lint JavaScript
run: npm run lint
- name: Run JavaScript tests
run: npm test
release:
needs: test
if: startsWith(github.ref, 'refs/tags/v')
runs-on: ubuntu-latest
permissions:
contents: write
packages: write
steps:
- name: Checkout tag
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
with:
tag_name: ${{ github.ref_name }}
name: "Release ${{ github.ref_name }}"
body: "Automated release generated by CI."
draft: false
prerelease: false
This workflow does a few important things:
- Spins up a MariaDB service for MediaWiki’s database.
- Uses the official
shivammathur/setup-phpaction to get the correct PHP version and extensions. - Caches Composer dependencies for speed.
- Clones the
docker-compose-cirepository – the same harness used by the core and many extensions – and runsmake cito start a fresh MediaWiki instance. - Runs PHPUnit against the
extensiontest suite defined inextension.json. - Runs Node‑based linting and tests for any front‑end code.
- Creates a GitHub release automatically when a version tag is pushed.
2. Add Linting Scripts to composer.json
{
"require-dev": {
"phpunit/phpunit": "^9",
"squizlabs/php_codesniffer": "^3.6"
},
"scripts": {
"phpcs": "phpcs --standard=PSR12 src/",
"test": "phpunit"
}
}
Make sure your extension follows the PSR‑12 coding standard – the MediaWiki core enforces this in its own CI.
3. Configure JavaScript Testing (optionalh3>
If your extension ships front‑end assets, add a package.json like:
{
"name": "my‑extension",
"scripts": {
"lint": "eslint src/",
"test": "jest"
},
"devDependencies": {
"eslint": "^8",
"jest": "^29"
}
}
Using the‑Provided setup-mediawiki Action
For simpler projects you can replace the manual docker‑compose‑ci steps with the community action lucaswerkmeister/setup-mediawiki. It installs MediaWiki core, optional skins, and extensions in a single step, exposing useful outputs such as api‑url and install‑directory. Example:
- uses: lucaswerkmeister/setup-mediawiki@v1
id: wiki
with:
version: REL1_43
extensions: |
MyExtension
admin-username: ci‑admin
admin-password: ${{ secrets.WIKI_ADMIN_PASS }}
- name: Run extension tests
run: |
cd ${{ steps.wiki.outputs.install-directory }}
php vendor/bin/phpunit --testsuitecode>This action is handy for quick smoke‑tests, documentation builds, or when your extension does not need a full Composer‑based MediaWiki installation.
Best Practices for MediaWiki Extension CI
Run against multiple MediaWiki versions. Use a matrix strategy to test against REL1_35, REL1_39, and the latest master branch.Cache Docker layers. Add actions/cache@v3 for ~/.docker if you build custom images.Separate linting from testing. Linting is fast and catches style issues early; keep it as a separate job so failures don’t block the heavy integration tests.Use secrets for DB passwords and API keys. Store them in the repository’s Settings → Secrets → Actions and reference them as ${{ secrets.MY_SECRET }}.Publish coverage reports. The actions/upload-artifact action can send coverage.xml to Codecov or a custom server.
Deploying the Extension to a Wiki
CI can also automate deployment. A common pattern is:
When a tag is pushed, the release job builds a Composer package (composer.json with type: mediawiki-extension).The package is uploaded toPackagistor a private Composer repository.Wikis that consume the extension update via composer update – optionally triggered by a webhook.
Alternatively, for Wikimedia‑hosted extensions you can push the built .tar.gz to the Gerrit repository and let the Wikimedia CI handle the rollout.
Full Example Repository
A working reference can be found in the LinkedWiki‑CI demo. It demonstrates:
Docker‑Compose CI harness.Matrix testing across MediaWiki releases.Automated OAuth consumer creation for API tests.Artifact upload of test reports.
Conclusion
Setting up CI/CD for MediaWiki extensions with GitHub Actions brings the same reliability that large Wikimedia projects enjoy. By leveraging the existing docker‑compose‑ci harness or the community setup-mediawiki action, you get a reproducible MediaWiki environment, fast feedback on code changes, and an automated release pipeline. Adopt the patterns above, tailor the matrix to the versions your users run, and your extension will stay healthy in the fast‑moving MediaWiki ecosystem.
Happy coding, and may your tests always pass!