Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
93.10% covered (success)
93.10%
27 / 29
50.00% covered (danger)
50.00%
2 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
CheckComposerLockUpToDate
93.10% covered (success)
93.10%
27 / 29
50.00% covered (danger)
50.00%
2 / 4
9.03
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 canExecuteWithoutLocalSettings
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getMwInstallPath
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 execute
95.83% covered (success)
95.83%
23 / 24
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3// @codeCoverageIgnoreStart
4require_once __DIR__ . '/Maintenance.php';
5// @codeCoverageIgnoreEnd
6
7use MediaWiki\Composer\LockFileChecker;
8use MediaWiki\Maintenance\Maintenance;
9use Wikimedia\Composer\ComposerJson;
10use Wikimedia\Composer\ComposerLock;
11
12/**
13 * Checks whether your composer-installed dependencies are up to date
14 *
15 * Composer creates a "composer.lock" file which specifies which versions are installed
16 * (via `composer install`). It has a hash, which can be compared to the value of
17 * the composer.json file to see if dependencies are up to date.
18 */
19class CheckComposerLockUpToDate extends Maintenance {
20    public function __construct() {
21        parent::__construct();
22        $this->addDescription(
23            'Checks whether your composer.lock file is up to date with the current composer.json' );
24    }
25
26    public function canExecuteWithoutLocalSettings(): bool {
27        return true;
28    }
29
30    /**
31     * @return string The value of the constant MW_INSTALL_PATH. This method mocked in phpunit tests.
32     */
33    protected function getMwInstallPath(): string {
34        return MW_INSTALL_PATH;
35    }
36
37    public function execute() {
38        $installPath = $this->getMwInstallPath();
39        $lockLocation = "$installPath/composer.lock";
40        $jsonLocation = "$installPath/composer.json";
41        if ( !file_exists( $lockLocation ) ) {
42            // Maybe they're using mediawiki/vendor?
43            $lockLocation = "$installPath/vendor/composer.lock";
44            if ( !file_exists( $lockLocation ) ) {
45                $this->fatalError(
46                    'Could not find composer.lock file. Have you run "composer install --no-dev"?'
47                );
48            }
49        }
50
51        $lock = new ComposerLock( $lockLocation );
52        $json = new ComposerJson( $jsonLocation );
53
54        // Check all the dependencies to see if any are old
55        $checker = new LockFileChecker( $json, $lock );
56        $errors = $checker->check();
57
58        // NOTE: This is used by TestSetup before MediaWikiServices is initialized and thus
59        //       may not rely on global singletons.
60        // NOTE: This is used by maintenance/update.php and thus may not rely on
61        //       database connections, including e.g. interface messages without useDatabase=false,
62        //       which would call MessageCache.
63        if ( $errors ) {
64            foreach ( $errors as $error ) {
65                $this->error( $error . "\n" );
66            }
67            $suggestedCommand = 'composer update';
68            if ( !defined( 'MW_PHPUNIT_TEST' ) ) {
69                $suggestedCommand .= ' --no-dev';
70            }
71            $this->fatalError(
72                'Error: your composer.lock file is not up to date. ' .
73                'Run "' . $suggestedCommand . '" to install newer dependencies'
74            );
75        } else {
76            // We couldn't find any out-of-date dependencies, so assume everything is ok!
77            $this->output( "Your composer.lock file is up to date with current dependencies!\n" );
78        }
79    }
80}
81
82// @codeCoverageIgnoreStart
83$maintClass = CheckComposerLockUpToDate::class;
84require_once RUN_MAINTENANCE_IF_MAIN;
85// @codeCoverageIgnoreEnd