Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.43% covered (success)
96.43%
27 / 28
75.00% covered (warning)
75.00%
3 / 4
CRAP
0.00% covered (danger)
0.00%
0 / 1
SelfUpdateCommand
96.43% covered (success)
96.43%
27 / 28
75.00% covered (warning)
75.00%
3 / 4
6
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getCommandNames
88.89% covered (warning)
88.89%
8 / 9
0.00% covered (danger)
0.00%
0 / 1
2.01
 configure
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
 execute
100.00% covered (success)
100.00%
13 / 13
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3declare(strict_types=1);
4
5/**
6 * Fast Forward Development Tools for PHP projects.
7 *
8 * This file is part of fast-forward/dev-tools project.
9 *
10 * @author   Felipe SayĆ£o Lobato Abreu <github@mentordosnerds.com>
11 * @license  https://opensource.org/licenses/MIT MIT License
12 *
13 * @see      https://github.com/php-fast-forward/
14 * @see      https://github.com/php-fast-forward/dev-tools
15 * @see      https://github.com/php-fast-forward/dev-tools/issues
16 * @see      https://php-fast-forward.github.io/dev-tools/
17 * @see      https://datatracker.ietf.org/doc/html/rfc2119
18 */
19
20namespace FastForward\DevTools\Console\Command;
21
22use FastForward\DevTools\Console\Command\Traits\LogsCommandResults;
23use FastForward\DevTools\Reflection\ClassReflection;
24use FastForward\DevTools\SelfUpdate\SelfUpdateRunnerInterface;
25use FastForward\DevTools\SelfUpdate\SelfUpdateScopeResolverInterface;
26use Symfony\Component\Console\Attribute\AsCommand;
27use Symfony\Component\Console\Command\Command;
28use Symfony\Component\Console\Input\InputInterface;
29use Symfony\Component\Console\Output\OutputInterface;
30
31/**
32 * Updates the installed DevTools package through Composer.
33 */
34#[AsCommand(
35    name: 'dev-tools:self-update',
36    description: 'Updates the installed fast-forward/dev-tools package.',
37    aliases: ['self-update', 'selfupdate'],
38)]
39 class SelfUpdateCommand extends Command
40{
41    use LogsCommandResults;
42
43    /**
44     * @param SelfUpdateRunnerInterface $selfUpdateRunner the runner that executes Composer's update command
45     * @param SelfUpdateScopeResolverInterface $scopeResolver resolves whether the active binary is globally installed
46     */
47    public function __construct(
48        private  SelfUpdateRunnerInterface $selfUpdateRunner,
49        private  SelfUpdateScopeResolverInterface $scopeResolver,
50    ) {
51        parent::__construct();
52    }
53
54    /**
55     * Returns the command name and aliases declared through AsCommand.
56     *
57     * @return list<string>
58     */
59    public static function getCommandNames(): array
60    {
61        static $commandNames = null;
62
63        if (null !== $commandNames) {
64            return $commandNames;
65        }
66
67        $arguments = ClassReflection::getAttributeArguments(self::class, AsCommand::class);
68        $commandNames = [$arguments['name'], ...$arguments['aliases']];
69
70        return $commandNames = array_values(array_filter(
71            $commandNames,
72            static fn(string $commandName): bool => '' !== $commandName,
73        ));
74    }
75
76    /**
77     * Configures the self-update command.
78     */
79    protected function configure(): void
80    {
81        $this->setHelp(
82            'This command updates fast-forward/dev-tools through Composer. When DevTools is running from'
83            . ' Composer global, the command updates that global installation automatically; otherwise it updates'
84            . ' the current project installation.'
85        );
86    }
87
88    /**
89     * Executes the Composer update flow.
90     *
91     * @param InputInterface $input the command input
92     * @param OutputInterface $output the command output
93     *
94     * @return int the command status code
95     */
96    protected function execute(InputInterface $input, OutputInterface $output): int
97    {
98        $global = $this->scopeResolver->isGlobalInstallation();
99
100        $this->log('Updating DevTools installation...', $input, [
101            'global' => $global,
102        ]);
103
104        $statusCode = $this->selfUpdateRunner->update($global, $output);
105
106        if (self::SUCCESS === $statusCode) {
107            return $this->success('DevTools self-update completed successfully.', $input, [
108                'global' => $global,
109            ]);
110        }
111
112        return $this->failure('DevTools self-update failed.', $input, [
113            'global' => $global,
114            'status_code' => $statusCode,
115        ]);
116    }
117}