DeployRunCommand::setDeployDefinitionFileFinder()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 1
dl 0
loc 3
ccs 0
cts 3
cp 0
crap 2
rs 10
1
<?php
2
3
namespace Deployee\Plugins\Deploy\Commands;
4
5
use Composer\Autoload\ClassLoader;
6
use Deployee\Components\Container\ContainerInterface;
7
use Deployee\Plugins\Deploy\Definitions\Deploy\DeployFactory;
8
use Deployee\Plugins\Deploy\Definitions\Deploy\DeployDefinitionInterface;
9
use Deployee\Plugins\Deploy\Definitions\Tasks\TaskDefinitionInterface;
10
use Deployee\Plugins\Deploy\Dispatcher\DispatcherFinder;
11
use Deployee\Plugins\Deploy\Dispatcher\DispatchResult;
12
use Deployee\Plugins\Deploy\Dispatcher\DispatchResultInterface;
13
use Deployee\Plugins\Deploy\Events\FindExecutableDefinitionFilesEvent;
14
use Deployee\Plugins\Deploy\Events\PostRunDeploy;
15
use Deployee\Plugins\Deploy\Events\PreDispatchTaskEvent;
16
use Deployee\Plugins\Deploy\Events\PreRunDeployEvent;
17
use Deployee\Plugins\Deploy\Exception\FailedException;
18
use Deployee\Plugins\Deploy\Finder\DeployDefinitionFileFinder;
19
use Deployee\Plugins\Deploy\Events\PreDispatchDeploymentEvent;
20
use Deployee\Plugins\Deploy\Events\PostDispatchDeploymentEvent;
21
use Deployee\Plugins\Deploy\Events\PostDispatchTaskEvent;
22
use Symfony\Component\Console\Command\Command;
23
use Symfony\Component\Console\Input\InputInterface;
24
use Symfony\Component\Console\Output\OutputInterface;
25
use Symfony\Component\EventDispatcher\EventDispatcher;
26
27
class DeployRunCommand extends Command
28
{
29
    /**
30
     * @var ContainerInterface
31
     */
32
    private $container;
33
34
    /**
35
     * @var DispatcherFinder
36
     */
37
    private $dispatcherFinder;
38
39
    /**
40
     * @var DeployFactory
41
     */
42
    private $deployFactory;
43
44
    /**
45
     * @var EventDispatcher
46
     */
47
    private $eventDispatcher;
48
49
    /**
50
     * @var DeployDefinitionFileFinder
51
     */
52
    private $deployDefinitionFileFinder;
53
54
    /**
55
     * @param ContainerInterface $container
56
     */
57
    public function setContainer(ContainerInterface $container)
58
    {
59
        $this->container = $container;
60
    }
61
62
    /**
63
     * @param DispatcherFinder $dispatcherFinder
64
     */
65
    public function setDispatcherFinder(DispatcherFinder $dispatcherFinder)
66
    {
67
        $this->dispatcherFinder = $dispatcherFinder;
68
    }
69
70
    /**
71
     * @param DeployFactory $deployFactory
72
     */
73
    public function setDeployFactory(DeployFactory $deployFactory)
74
    {
75
        $this->deployFactory = $deployFactory;
76
    }
77
78
    /**
79
     * @param EventDispatcher $eventDispatcher
80
     */
81
    public function setEventDispatcher(EventDispatcher $eventDispatcher)
82
    {
83
        $this->eventDispatcher = $eventDispatcher;
84
    }
85
86
    /**
87
     * @param DeployDefinitionFileFinder $deployDefinitionFileFinder
88
     */
89
    public function setDeployDefinitionFileFinder(DeployDefinitionFileFinder $deployDefinitionFileFinder)
90
    {
91
        $this->deployDefinitionFileFinder = $deployDefinitionFileFinder;
92
    }
93
94
    /**
95
     * @inheritdoc
96
     */
97
    public function configure()
98
    {
99
        parent::configure();
100
        $this->setName('deploy:run');
101
    }
102
103
    /**
104
     * @param InputInterface $input
105
     * @param OutputInterface $output
106
     * @return int|void|null
107
     * @throws \ReflectionException
108
     */
109
    protected function execute(InputInterface $input, OutputInterface $output)
110
    {
111
        $this->eventDispatcher->dispatch(PreRunDeployEvent::class, new PreRunDeployEvent($input));
112
113
        $definitions = $this->getExecutableDefinitions($input, $output);
114
        $output->writeln(sprintf('Executing %s definitions', count($definitions)));
115
        $success = true;
116
        $exitCode = 0;
117
118
        foreach($definitions as $definitionClass){
119
            if(!class_exists($definitionClass) || !in_array(DeployDefinitionInterface::class, class_implements($definitionClass), false)){
120
                $output->write(sprintf(
121
                    'WARNING: Skipping definition %s since it does not implement %s',
122
                    $definitionClass,
123
                    DeployDefinitionInterface::class
124
                ));
125
                continue;
126
            }
127
128
            $output->writeln(sprintf('Execute definition %s', $definitionClass), OutputInterface::VERBOSITY_VERBOSE);
129
            $deployDefinition = $this->deployFactory->createDeploy($definitionClass);
130
            $event = new PreDispatchDeploymentEvent($deployDefinition);
131
            $this->eventDispatcher->dispatch(PreDispatchDeploymentEvent::class, $event);
132
133
            try {
134
                if (($exitCode = $this->runDeploymentDefinition($deployDefinition, $output)) !== 0) {
135
                    throw new FailedException(sprintf('Failed to execute definition %s', $definitionClass));
136
                }
137
138
                $output->writeln(sprintf('Finished executing definition %s', $definitionClass), OutputInterface::VERBOSITY_DEBUG);
139
            }
140
            catch(\Exception $e){
141
                $output->writeln(sprintf('ERROR (%s): %s', get_class($e), $e->getMessage()));
142
                $success = false;
143
                $exitCode = 5;
144
            }
145
            finally {
146
                $this->eventDispatcher->dispatch(
147
                    PostDispatchDeploymentEvent::class,
148
                    new PostDispatchDeploymentEvent($deployDefinition, $success)
149
                );
150
            }
151
152
            if($success === false){
153
                break;
154
            }
155
        }
156
157
        $this->eventDispatcher->dispatch(PostRunDeploy::class, new PostRunDeploy($success));
158
159
        exit($exitCode);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
160
    }
161
162
    /**
163
     * @param DeployDefinitionInterface $deployDefinition
164
     * @param OutputInterface $output
165
     * @return int
166
     * @throws \Deployee\Plugins\Deploy\Exception\DispatcherException
167
     */
168
    private function runDeploymentDefinition(DeployDefinitionInterface $deployDefinition, OutputInterface $output): int
169
    {
170
        $return = 0;
171
        $deployDefinition->define();
172
173
        foreach($deployDefinition->getTaskDefinitions()->toArray() as $taskDefinition){
174
            $output->writeln(
175
                sprintf('Executing %s => %s', get_class($deployDefinition), get_class($taskDefinition)),
176
                OutputInterface::VERBOSITY_DEBUG
177
            );
178
179
            $result = $this->runTaskDefinition($taskDefinition, $output);
180
181
            if($result->getExitCode() > 0){
182
                $return = $result->getExitCode();
183
                break;
184
            }
185
        }
186
187
        return $return;
188
    }
189
190
    /**
191
     * @param TaskDefinitionInterface $taskDefinition
192
     * @param OutputInterface $output
193
     * @return DispatchResultInterface
194
     * @throws \Deployee\Plugins\Deploy\Exception\DispatcherException
195
     */
196
    private function runTaskDefinition(TaskDefinitionInterface $taskDefinition, OutputInterface $output): DispatchResultInterface{
197
198
        $event = new PreDispatchTaskEvent($taskDefinition);
199
        $this->eventDispatcher->dispatch(PreDispatchTaskEvent::class, $event);
200
201
        if($event->isPreventDispatch() === true){
202
            return new DispatchResult(0, 'Skipped execution of task definition', '');
203
        }
204
205
        $finder = new DispatcherFinder($this->container);
206
        $dispatcher = $finder->findTaskDispatcherByDefinition($taskDefinition);
207
        $result = $dispatcher->dispatch($taskDefinition);
208
209
        if($result->getExitCode() > 0){
210
            $output->write(
211
                sprintf(
212
                    "Error while executing task (%s)" . PHP_EOL . "Output: %s" . PHP_EOL . "Error output: %s",
213
                    $result->getExitCode(),
214
                    $result->getOutput(),
215
                    $result->getErrorOutput()
216
                )
217
            );
218
        }
219
220
        if($result->getOutput()) {
221
            $output->writeln($result->getOutput(), OutputInterface::VERBOSITY_VERBOSE);
222
        }
223
224
        $this->eventDispatcher->dispatch(PostDispatchTaskEvent::class, new PostDispatchTaskEvent($taskDefinition, $result));
225
226
        return $result;
227
    }
228
229
    /**
230
     * @param InputInterface $input
231
     * @param OutputInterface $output
232
     * @return \ArrayObject
233
     */
234
    private function getExecutableDefinitions(InputInterface $input, OutputInterface $output): \ArrayObject
235
    {
236
        /* @var ClassLoader $classLoader */
237
        $classLoader = require('vendor/autoload.php');
238
        $definitionFileCollection = $this->deployDefinitionFileFinder->find();
239
        $classLoader->addClassMap($definitionFileCollection->getArrayCopy());
240
241
        $event = new FindExecutableDefinitionFilesEvent(
242
            new \ArrayObject(array_keys($definitionFileCollection->getArrayCopy())),
243
            $input,
244
            $output
245
        );
246
247
        $this->eventDispatcher->dispatch(FindExecutableDefinitionFilesEvent::class, $event);
248
249
        return $event->getDefinitionFileCollection();
250
    }
251
}