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

keradus / PHP-CS-Fixer / 24023665044

02 Apr 2026 09:33PM UTC coverage: 93.056% (+0.1%) from 92.938%
24023665044

push

github

web-flow
chore: add tests for `BracesPositionFixer` (#9522)

29548 of 31753 relevant lines covered (93.06%)

43.98 hits per line

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

83.33
/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
 * @no-named-arguments Parameter names are not covered by the backward compatibility promise.
38
 */
39
#[AsCommand(name: 'self-update', description: 'Update php-cs-fixer.phar to the latest stable version.')]
40
final class SelfUpdateCommand extends Command
41
{
42
    private NewVersionCheckerInterface $versionChecker;
43

44
    private ToolInfoInterface $toolInfo;
45

46
    private PharCheckerInterface $pharChecker;
47

48
    public function __construct(
49
        NewVersionCheckerInterface $versionChecker,
50
        ToolInfoInterface $toolInfo,
51
        PharCheckerInterface $pharChecker
52
    ) {
53
        parent::__construct('self-update');
60✔
54
        $this->setDescription('Update php-cs-fixer.phar to the latest stable version.');
60✔
55

56
        $this->versionChecker = $versionChecker;
60✔
57
        $this->toolInfo = $toolInfo;
60✔
58
        $this->pharChecker = $pharChecker;
60✔
59
    }
60

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

73
            <info>$ php php-cs-fixer.phar %command.name%</info>
74

75
            EOT;
76
    }
77

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

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

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

100
            return 1;
6✔
101
        }
102

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

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

116
            return 1;
18✔
117
        }
118

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

122
            return 0;
20✔
123
        }
124

125
        $remoteTag = $latestVersion;
14✔
126

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

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

139
                return 0;
2✔
140
            }
141

142
            $remoteTag = $latestVersionOfCurrentMajor;
2✔
143
        }
144

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

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

154
            return 1;
×
155
        }
156

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

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

163
            return 1;
×
164
        }
165

166
        chmod($tempFilename, 0777 & ~umask());
12✔
167

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

174
            return 1;
×
175
        }
176

177
        rename($tempFilename, $localFilename);
12✔
178

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

181
        return 0;
12✔
182
    }
183
}
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