• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

keradus / PHP-CS-Fixer / 16999983712

15 Aug 2025 09:42PM UTC coverage: 94.75% (-0.09%) from 94.839%
16999983712

push

github

keradus
ci: more self-fixing checks on lowest/highest PHP

28263 of 29829 relevant lines covered (94.75%)

45.88 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.08
/src/Console/Command/SelfUpdateCommand.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of PHP CS Fixer.
7
 *
8
 * (c) Fabien Potencier <fabien@symfony.com>
9
 *     Dariusz Rumiński <dariusz.ruminski@gmail.com>
10
 *
11
 * This source file is subject to the MIT license that is bundled
12
 * with this source code in the file LICENSE.
13
 */
14

15
namespace PhpCsFixer\Console\Command;
16

17
use PhpCsFixer\Console\Application;
18
use PhpCsFixer\Console\SelfUpdate\NewVersionCheckerInterface;
19
use PhpCsFixer\PharCheckerInterface;
20
use PhpCsFixer\Preg;
21
use PhpCsFixer\ToolInfoInterface;
22
use Symfony\Component\Console\Attribute\AsCommand;
23
use Symfony\Component\Console\Command\Command;
24
use Symfony\Component\Console\Input\InputInterface;
25
use Symfony\Component\Console\Input\InputOption;
26
use Symfony\Component\Console\Output\ConsoleOutputInterface;
27
use Symfony\Component\Console\Output\OutputInterface;
28

29
/**
30
 * @author Igor Wiedler <igor@wiedler.ch>
31
 * @author Stephane PY <py.stephane1@gmail.com>
32
 * @author Grégoire Pineau <lyrixx@lyrixx.info>
33
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
34
 *
35
 * @internal
36
 */
37
#[AsCommand(name: 'self-update', description: 'Update php-cs-fixer.phar to the latest stable version.')]
38
final class SelfUpdateCommand extends Command
39
{
40
    /** @TODO PHP 8.0 - remove the property */
41
    protected static $defaultName = 'self-update';
42

43
    /** @TODO PHP 8.0 - remove the property */
44
    protected static $defaultDescription = 'Update php-cs-fixer.phar to the latest stable version.';
45

46
    private NewVersionCheckerInterface $versionChecker;
47

48
    private ToolInfoInterface $toolInfo;
49

50
    private PharCheckerInterface $pharChecker;
51

52
    public function __construct(
53
        NewVersionCheckerInterface $versionChecker,
54
        ToolInfoInterface $toolInfo,
55
        PharCheckerInterface $pharChecker
56
    ) {
57
        parent::__construct();
60✔
58

59
        $this->versionChecker = $versionChecker;
60✔
60
        $this->toolInfo = $toolInfo;
60✔
61
        $this->pharChecker = $pharChecker;
60✔
62
    }
63

64
    /**
65
     * {@inheritdoc}
66
     *
67
     * Override here to only generate the help copy when used.
68
     */
69
    public function getHelp(): string
70
    {
71
        return <<<'EOT'
72
            The <info>%command.name%</info> command replace your php-cs-fixer.phar by the
73
            latest version released on:
74
            <comment>https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/releases</comment>
75

76
            <info>$ php php-cs-fixer.phar %command.name%</info>
77

78
            EOT;
79
    }
80

81
    protected function configure(): void
82
    {
83
        $this
60✔
84
            ->setAliases(['selfupdate'])
60✔
85
            ->setDefinition(
60✔
86
                [
60✔
87
                    new InputOption('--force', '-f', InputOption::VALUE_NONE, 'Force update to next major version if available.'),
60✔
88
                ]
60✔
89
            )
60✔
90
        ;
60✔
91
    }
92

93
    protected function execute(InputInterface $input, OutputInterface $output): int
94
    {
95
        if ($output instanceof ConsoleOutputInterface) {
58✔
96
            $stdErr = $output->getErrorOutput();
×
97
            $stdErr->writeln(Application::getAboutWithRuntime(true));
×
98
        }
99

100
        if (!$this->toolInfo->isInstalledAsPhar()) {
58✔
101
            $output->writeln('<error>Self-update is available only for PHAR version.</error>');
6✔
102

103
            return 1;
6✔
104
        }
105

106
        $currentVersion = $this->getApplication()->getVersion();
52✔
107
        Preg::match('/^v?(?<major>\d+)\./', $currentVersion, $matches);
52✔
108
        $currentMajor = (int) $matches['major'];
52✔
109

110
        try {
111
            $latestVersion = $this->versionChecker->getLatestVersion();
52✔
112
            $latestVersionOfCurrentMajor = $this->versionChecker->getLatestVersionOfMajor($currentMajor);
40✔
113
        } catch (\Exception $exception) {
18✔
114
            $output->writeln(\sprintf(
18✔
115
                '<error>Unable to determine newest version: %s</error>',
18✔
116
                $exception->getMessage()
18✔
117
            ));
18✔
118

119
            return 1;
18✔
120
        }
121

122
        if (1 !== $this->versionChecker->compareVersions($latestVersion, $currentVersion)) {
34✔
123
            $output->writeln('<info>PHP CS Fixer is already up-to-date.</info>');
20✔
124

125
            return 0;
20✔
126
        }
127

128
        $remoteTag = $latestVersion;
14✔
129

130
        if (
131
            0 !== $this->versionChecker->compareVersions($latestVersionOfCurrentMajor, $latestVersion)
14✔
132
            && true !== $input->getOption('force')
14✔
133
        ) {
134
            $output->writeln(\sprintf('<info>A new major version of PHP CS Fixer is available</info> (<comment>%s</comment>)', $latestVersion));
4✔
135
            $output->writeln(\sprintf('<info>Before upgrading please read</info> https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/blob/%s/UPGRADE-v%s.md', $latestVersion, $currentMajor + 1));
4✔
136
            $output->writeln('<info>If you are ready to upgrade run this command with</info> <comment>-f</comment>');
4✔
137
            $output->writeln('<info>Checking for new minor/patch version...</info>');
4✔
138

139
            if (1 !== $this->versionChecker->compareVersions($latestVersionOfCurrentMajor, $currentVersion)) {
4✔
140
                $output->writeln('<info>No minor update for PHP CS Fixer.</info>');
2✔
141

142
                return 0;
2✔
143
            }
144

145
            $remoteTag = $latestVersionOfCurrentMajor;
2✔
146
        }
147

148
        $localFilename = $_SERVER['argv'][0];
12✔
149
        $realPath = realpath($localFilename);
12✔
150
        if (false !== $realPath) {
12✔
151
            $localFilename = $realPath;
×
152
        }
153

154
        if (!is_writable($localFilename)) {
12✔
155
            $output->writeln(\sprintf('<error>No permission to update</error> "%s" <error>file.</error>', $localFilename));
×
156

157
            return 1;
×
158
        }
159

160
        $tempFilename = \dirname($localFilename).'/'.basename($localFilename, '.phar').'-tmp.phar';
12✔
161
        $remoteFilename = $this->toolInfo->getPharDownloadUri($remoteTag);
12✔
162

163
        if (false === @copy($remoteFilename, $tempFilename)) {
12✔
164
            $output->writeln(\sprintf('<error>Unable to download new version</error> %s <error>from the server.</error>', $remoteTag));
×
165

166
            return 1;
×
167
        }
168

169
        chmod($tempFilename, 0777 & ~umask());
12✔
170

171
        $pharInvalidityReason = $this->pharChecker->checkFileValidity($tempFilename);
12✔
172
        if (null !== $pharInvalidityReason) {
12✔
173
            unlink($tempFilename);
×
174
            $output->writeln(\sprintf('<error>The download of</error> %s <error>is corrupt (%s).</error>', $remoteTag, $pharInvalidityReason));
×
175
            $output->writeln('<error>Please re-run the "self-update" command to try again.</error>');
×
176

177
            return 1;
×
178
        }
179

180
        rename($tempFilename, $localFilename);
12✔
181

182
        $output->writeln(\sprintf('<info>PHP CS Fixer updated</info> (<comment>%s</comment> -> <comment>%s</comment>)', $currentVersion, $remoteTag));
12✔
183

184
        return 0;
12✔
185
    }
186
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc