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

  1. A GitHub repository containing your extension source.
  2. Extension.json and a composer.json that list mediawiki/semantic-media-wiki or the core version you target.
  3. 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-php action to get the correct PHP version and extensions.
  • Caches Composer dependencies for speed.
  • Clones the docker-compose-ci repository – the same harness used by the core and many extensions – and runs make ci to start a fresh MediaWiki instance.
  • Runs PHPUnit against the extension test suite defined in extension.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

  1. Run against multiple MediaWiki versions. Use a matrix strategy to test against REL1_35, REL1_39, and the latest master branch.
  2. Cache Docker layers. Add actions/cache@v3 for ~/.docker if you build custom images.
  3. 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.
  4. Use secrets for DB passwords and API keys. Store them in the repository’s Settings → Secrets → Actions and reference them as ${{ secrets.MY_SECRET }}.
  5. 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 to Packagist or 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!

Subscribe to MediaWiki Tips and Tricks

Don’t miss out on the latest articles. Sign up now to get access to the library of members-only articles.
jamie@example.com
Subscribe