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

keradus / PHP-CS-Fixer / 16428450756

21 Jul 2025 06:19PM UTC coverage: 94.756% (-0.002%) from 94.758%
16428450756

push

github

web-flow
fix: always reach 100% of checked files (#8861)

4 of 4 new or added lines in 1 file covered. (100.0%)

111 existing lines in 19 files now uncovered.

28186 of 29746 relevant lines covered (94.76%)

45.93 hits per line

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

84.06
/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
    protected function configure(): void
65
    {
66
        $this
60✔
67
            ->setAliases(['selfupdate'])
60✔
68
            ->setDefinition(
60✔
69
                [
60✔
70
                    new InputOption('--force', '-f', InputOption::VALUE_NONE, 'Force update to next major version if available.'),
60✔
71
                ]
60✔
72
            )
60✔
73
            ->setHelp(
60✔
74
                <<<'EOT'
60✔
75
                    The <info>%command.name%</info> command replace your php-cs-fixer.phar by the
76
                    latest version released on:
77
                    <comment>https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/releases</comment>
78

79
                    <info>$ php php-cs-fixer.phar %command.name%</info>
80

81
                    EOT
60✔
82
            )
60✔
83
        ;
60✔
84
    }
85

86
    protected function execute(InputInterface $input, OutputInterface $output): int
87
    {
88
        if ($output instanceof ConsoleOutputInterface) {
58✔
UNCOV
89
            $stdErr = $output->getErrorOutput();
×
UNCOV
90
            $stdErr->writeln(Application::getAboutWithRuntime(true));
×
91
        }
92

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

96
            return 1;
6✔
97
        }
98

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

103
        try {
104
            $latestVersion = $this->versionChecker->getLatestVersion();
52✔
105
            $latestVersionOfCurrentMajor = $this->versionChecker->getLatestVersionOfMajor($currentMajor);
40✔
106
        } catch (\Exception $exception) {
18✔
107
            $output->writeln(\sprintf(
18✔
108
                '<error>Unable to determine newest version: %s</error>',
18✔
109
                $exception->getMessage()
18✔
110
            ));
18✔
111

112
            return 1;
18✔
113
        }
114

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

118
            return 0;
20✔
119
        }
120

121
        $remoteTag = $latestVersion;
14✔
122

123
        if (
124
            0 !== $this->versionChecker->compareVersions($latestVersionOfCurrentMajor, $latestVersion)
14✔
125
            && true !== $input->getOption('force')
14✔
126
        ) {
127
            $output->writeln(\sprintf('<info>A new major version of PHP CS Fixer is available</info> (<comment>%s</comment>)', $latestVersion));
4✔
128
            $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✔
129
            $output->writeln('<info>If you are ready to upgrade run this command with</info> <comment>-f</comment>');
4✔
130
            $output->writeln('<info>Checking for new minor/patch version...</info>');
4✔
131

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

135
                return 0;
2✔
136
            }
137

138
            $remoteTag = $latestVersionOfCurrentMajor;
2✔
139
        }
140

141
        $localFilename = $_SERVER['argv'][0];
12✔
142
        $realPath = realpath($localFilename);
12✔
143
        if (false !== $realPath) {
12✔
UNCOV
144
            $localFilename = $realPath;
×
145
        }
146

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

UNCOV
150
            return 1;
×
151
        }
152

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

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

UNCOV
159
            return 1;
×
160
        }
161

162
        chmod($tempFilename, 0777 & ~umask());
12✔
163

164
        $pharInvalidityReason = $this->pharChecker->checkFileValidity($tempFilename);
12✔
165
        if (null !== $pharInvalidityReason) {
12✔
UNCOV
166
            unlink($tempFilename);
×
167
            $output->writeln(\sprintf('<error>The download of</error> %s <error>is corrupt (%s).</error>', $remoteTag, $pharInvalidityReason));
×
UNCOV
168
            $output->writeln('<error>Please re-run the "self-update" command to try again.</error>');
×
169

UNCOV
170
            return 1;
×
171
        }
172

173
        rename($tempFilename, $localFilename);
12✔
174

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

177
        return 0;
12✔
178
    }
179
}
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