From mediawiki.org

Thanks for contributing to XTools! This guide gives a high-level walkthrough of everything you need to contribute to XTools in a local environment.


Running a development server[edit]

  • Clone the repository: git clone https://github.com/x-tools/xtools.git && cd xtools
  • Run composer install and answer all the prompts. See /Configuration for documentation on each config parameter.
  • If you're working on JavaScript or CSS, compile assets with ./node_modules/.bin/encore dev --watch
    • Before submitting your pull request, be sure to use production instead of dev and without the watch flag.
  • Launch Symfony's built-in server: symfony serve
  • Assuming the configuration was done correctly and as desired, you should be up and running at http://localhost:8000

The Simple Counter is the simplest tool and should work as soon as you set up XTools. Test it by going to http://localhost:8000/sc and put in Jimbo Wales as the Username and en.wikipedia.org as the Wiki. After submitting you should quickly get results.

The development server does not cache application or session data; any changes you make are visible after refreshing the page. However when you modify things in .env or otherwise aren't seeing changes you're making, you may need to clear the cache with symfony console cache:clear.

Assets are generated with Symfony Encore.

The logs are in var/logs/dev.log. If things are acting up unexpectedly, you might try clearing the cache or restarting the server.

Developing against Toolforge replicas[edit]

First make sure you have a Wikimedia developer account and access to Toolforge. Then you can set up the necessary tunnels and a shell session with:

ssh -L 4711:s1.web.db.svc.wikimedia.cloud:3306 -L 4712:s2.web.db.svc.wikimedia.cloud:3306 -L 4713:s3.web.db.svc.wikimedia.cloud:3306 -L 4714:s4.web.db.svc.wikimedia.cloud:3306 -L 4715:s5.web.db.svc.wikimedia.cloud:3306 -L 4716:s6.web.db.svc.wikimedia.cloud:3306 -L 4717:s7.web.db.svc.wikimedia.cloud:3306 -L 4718:s8.web.db.svc.wikimedia.cloud:3306 -L 4720:tools.db.svc.eqiad.wmflabs:3306 username@login.toolforge.org

Replace username with your Toolforge Unix shell username. Note our tunnel has to connect to each database slice. The ports used here should match up with the corresponding options in your .env, like so:


Change the your-* bits to your own values, which you can find in your replica.my.cnf file in the home directory of your account on Toolforge.


XTools should probably take advantage of Doctrine's built-in caching mechanism, but it doesn't. Instead it is done in a somewhat manual fashion. This is only done in Repository classes, using this pattern:

public function doSomething($input)
    $cacheKey = $this->getCacheKey(func_get_args(), 'something');
    if ($this->cache->hasItem($cacheKey)) {
        return $this->cache->getItem($cacheKey)->get();
    $results = 'results of big query';
    return $this->setCache($cacheKey, $results);

The cache key can be anything, so long as it is unique to the specific method. A third parameter can be passed to setCache to set the TTL, using the same syntax from the DateInterval class (e.g. P1D is one day, PT1H is one hour).

The above methods are just wrappers around a PSR-6 implementation, intended to reduce the repetition of similar lines of code. You can, of course, retrieve the underlying CacheItemPoolInterface whenever you want, preferably through dependency injection, but it can also be accessed via the container with $container->get('cache.app').

Style guidelines[edit]

  • It's called "XTools", with two capital letters.
  • XTools conforms to PSR2 and Slevomat coding standards; use ./vendor/bin/phpcs -s -p . to check your code.
  • Routes must begin with the tool name, i.e. EditCounterYearCounts
  • Version numbers follow Semantic Versioning guidelines.


Tests are located in the tests/ directory, and match the src/ directory structure. They are built with PHPUnit. Repositories only handle fetching data and do not need to be tested. Controllers also interact with the database, and while tests are most welcomed for these, they will not run on the continuous integration server (GitHub Actions or Scrutinizer) due to limitations.

There are also tests for linting, phpDoc blocks, and file permissions.

Use composer test to run the full suite, or ./vendor/bin/phpunit tests/ to run just the unit tests.


Releases are made by tagging commits in the master branch. Before tagging a new release:

  • Update the version number in app/config/version.yml
  • Check the copyright year in README.md
  • Update RELEASE_NOTES.md with any notable new information for the end user.

Then tag the release (follow the Semantic Versioning guidelines, and annotate the tag with the above release notes) and push it to GitHub.

Lastly, update the version and updated parameters at XTools.

Additional help[edit]