Passed
Push — master ( 8b5091...c51706 )
by Anton
01:50
created

TaskCommand   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 167
Duplicated Lines 4.19 %

Coupling/Cohesion

Components 1
Dependencies 9

Test Coverage

Coverage 90.63%

Importance

Changes 0
Metric Value
dl 7
loc 167
ccs 87
cts 96
cp 0.9063
rs 10
c 0
b 0
f 0
wmc 19
lcom 1
cbo 9

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 2
A configure() 0 50 1
C execute() 7 62 11
A parseOptions() 0 8 2
A castValueToPhpType() 0 11 3

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
/* (c) Anton Medvedev <[email protected]>
3
 *
4
 * For the full copyright and license information, please view the LICENSE
5
 * file that was distributed with this source code.
6
 */
7
8
namespace Deployer\Console;
9
10
use Deployer\Deployer;
11
use Deployer\Exception\Exception;
12
use Deployer\Exception\GracefulShutdownException;
13
use Deployer\Executor\ExecutorInterface;
14
use Symfony\Component\Console\Command\Command;
15
use Symfony\Component\Console\Input\InputArgument;
16
use Symfony\Component\Console\Input\InputInterface as Input;
17
use Symfony\Component\Console\Input\InputOption as Option;
18
use Symfony\Component\Console\Output\OutputInterface as Output;
19
20
class TaskCommand extends Command
21
{
22
    /**
23
     * @var Deployer
24
     */
25
    private $deployer;
26
27
    /**
28
     * @var ExecutorInterface
29
     */
30
    public $executor;
31
32
    /**
33
     * @param string $name
34
     * @param string $description
35
     * @param Deployer $deployer
36
     */
37 12
    public function __construct($name, $description, Deployer $deployer)
38
    {
39 12
        parent::__construct($name);
40 12
        if ($description) {
41 8
            $this->setDescription($description);
42
        }
43 12
        $this->deployer = $deployer;
44 12
    }
45
46
    /**
47
     * Configures the command
48
     */
49 12
    protected function configure()
50
    {
51 12
        $this->addArgument(
52 12
            'stage',
53 12
            InputArgument::OPTIONAL,
54 12
            'Stage or hostname'
55
        );
56 12
        $this->addOption(
57 12
            'parallel',
58 12
            'p',
59 12
            Option::VALUE_NONE,
60 12
            'Run tasks in parallel'
61
        );
62 12
        $this->addOption(
63 12
            'limit',
64 12
            'l',
65 12
            Option::VALUE_REQUIRED,
66 12
            'How many host to run in parallel?'
67
        );
68 12
        $this->addOption(
69 12
            'no-hooks',
70 12
            null,
71 12
            Option::VALUE_NONE,
72 12
            'Run task without after/before hooks'
73
        );
74 12
        $this->addOption(
75 12
            'log',
76 12
            null,
77 12
            Option::VALUE_REQUIRED,
78 12
            'Log to file'
79
        );
80 12
        $this->addOption(
81 12
            'roles',
82 12
            null,
83 12
            Option::VALUE_REQUIRED,
84 12
            'Roles to deploy'
85
        );
86 12
        $this->addOption(
87 12
            'hosts',
88 12
            null,
89 12
            Option::VALUE_REQUIRED,
90 12
            'Host to deploy, comma separated, supports ranges [:]'
91
        );
92 12
        $this->addOption(
93 12
            'option',
94 12
            'o',
95 12
            Option::VALUE_REQUIRED | Option::VALUE_IS_ARRAY,
96 12
            'Sets configuration option'
97
        );
98 12
    }
99
100
    /**
101
     * {@inheritdoc}
102
     */
103 11
    protected function execute(Input $input, Output $output)
104
    {
105 11
        $stage = $input->hasArgument('stage') ? $input->getArgument('stage') : null;
106 11
        $roles = $input->getOption('roles');
107 11
        $hosts = $input->getOption('hosts');
108 11
        $this->parseOptions($input->getOption('option'));
109
110 11
        $hooksEnabled = !$input->getOption('no-hooks');
111 11
        if (!empty($input->getOption('log'))) {
112
            $this->deployer->config['log_file'] = $input->getOption('log');
113
        }
114
115 11 View Code Duplication
        if (!empty($hosts)) {
116
            $hosts = $this->deployer->hostSelector->getByHostnames($hosts);
117 11
        } elseif (!empty($roles)) {
118
            $hosts = $this->deployer->hostSelector->getByRoles($roles);
119
        } else {
120 11
            $hosts = $this->deployer->hostSelector->getHosts($stage);
0 ignored issues
show
Bug introduced by Anton Medvedev
It seems like $stage defined by $input->hasArgument('sta...rgument('stage') : null on line 105 can also be of type array<integer,string> or null; however, Deployer\Host\HostSelector::getHosts() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
121
        }
122
123 11
        if (empty($hosts)) {
124
            throw new Exception('No host selected');
125
        }
126
127 11
        $tasks = $this->deployer->scriptManager->getTasks(
128 11
            $this->getName(),
129 11
            $hosts,
130 11
            $hooksEnabled
131
        );
132
133 11
        if (empty($tasks)) {
134
            throw new Exception('No task will be executed, because the selected hosts do not meet the conditions of the tasks');
135
        }
136
137 11
        if ($input->getOption('parallel')) {
138
            $executor = $this->deployer->parallelExecutor;
139
        } else {
140 11
            $executor = $this->deployer->seriesExecutor;
141
        }
142
143
        try {
144 11
            $executor->run($tasks, $hosts);
145 1
        } catch (\Throwable $exception) {
146 1
            $this->deployer->logger->log('['. get_class($exception) .'] '. $exception->getMessage());
147 1
            $this->deployer->logger->log($exception->getTraceAsString());
148
149 1
            if ($exception instanceof GracefulShutdownException) {
150
                throw $exception;
151
            } else {
152
                // Check if we have tasks to execute on failure
153 1
                if ($this->deployer['fail']->has($this->getName())) {
154 1
                    $taskName = $this->deployer['fail']->get($this->getName());
155 1
                    $tasks = $this->deployer->scriptManager->getTasks($taskName, $hosts, $hooksEnabled);
156
157 1
                    $executor->run($tasks, $hosts);
158
                }
159 1
                throw $exception;
160
            }
161
        }
162
163 10
        return 0;
164
    }
165
166 11
    private function parseOptions(array $options)
167
    {
168 11
        foreach ($options as $option) {
169 1
            list($name, $value) = explode('=', $option);
170 1
            $value = $this->castValueToPhpType($value);
171 1
            $this->deployer->config->set($name, $value);
172
        }
173 11
    }
174
175 1
    private function castValueToPhpType($value)
176
    {
177 1
        switch ($value) {
178 1
            case 'true':
179
                return true;
180 1
            case 'false':
181
                return false;
182
            default:
183 1
                return $value;
184
        }
185
    }
186
}
187