Completed
Push — master ( b77c5c...4fbeac )
by Jeroen
10s
created

Conveyor::boot()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2.0185

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 5
cts 6
cp 0.8333
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 5
nc 2
nop 1
crap 2.0185
1
<?php
2
3
/*
4
 * This file is part of the Conveyor package.
5
 *
6
 * (c) Jeroen Fiege <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace Webcreate\Conveyor;
13
14
use Symfony\Component\Config\FileLocator;
15
use Symfony\Component\DependencyInjection\Container;
16
use Symfony\Component\DependencyInjection\ContainerBuilder;
17
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
18
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
19
use Symfony\Component\Filesystem\Filesystem;
20
use Webcreate\Conveyor\DependencyInjection\Compiler\ParameterCompilerPass;
21
use Webcreate\Conveyor\DependencyInjection\Compiler\StrategyCompilerPass;
22
use Webcreate\Conveyor\DependencyInjection\Compiler\TaskCompilerPass;
23
use Webcreate\Conveyor\DependencyInjection\Compiler\TransporterCompilerPass;
24
use Webcreate\Conveyor\DependencyInjection\TransporterAwareInterface;
25
use Webcreate\Conveyor\Event\StageEvent;
26
use Webcreate\Conveyor\Event\StageEvents;
27
use Webcreate\Conveyor\Exception\EmptyChangesetException;
28
use Webcreate\Conveyor\Factory\StrategyFactory;
29
use Webcreate\Conveyor\IO\IOInterface;
30
use Webcreate\Conveyor\IO\NullIO;
31
use Webcreate\Conveyor\Repository\Repository;
32
use Webcreate\Conveyor\Repository\Version;
33
use Webcreate\Conveyor\Stage\Manager\StageManager;
34
use Webcreate\Conveyor\Strategy\StrategyInterface;
35
use Webcreate\Conveyor\Task\TaskRunner;
36
use Webcreate\Conveyor\Transporter\AbstractTransporter;
37
use Webcreate\Conveyor\Transporter\TransactionalTransporterInterface;
38
use Webcreate\Conveyor\Util\FilePath;
39
40
class Conveyor
0 ignored issues
show
Complexity introduced by
This class has a complexity of 69 which exceeds the configured maximum of 50.

The class complexity is the sum of the complexity of all methods. A very high value is usually an indication that your class does not follow the single reponsibility principle and does more than one job.

Some resources for further reading:

You can also find more detailed suggestions for refactoring in the “Code” section of your repository.

Loading history...
Complexity introduced by
The class Conveyor has a coupling between objects value of 42. Consider to reduce the number of dependencies under 13.
Loading history...
41
{
42
    /**
43
     * @var Container
44
     */
45
    protected $container;
46
    protected $booted;
47
    protected $strategy;
48
    protected $configFile;
49
50 3
    public function boot(IOInterface $io)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $io. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
51
    {
52 3
        if (true === $this->booted) {
53
            return;
54
        }
55
56 3
        $this->container = $this->buildContainer($io);
57
58 3
        $this->booted = true;
59 3
    }
60
61 1
    public function getContainer()
62
    {
63 1
        return $this->container;
64
    }
65
66
    /**
67
     * @return \Webcreate\Conveyor\Config\YamlConfig
68
     */
69
    public function getConfig()
70
    {
71
        return $this->container->get('config');
72
    }
73
74
    /**
75
     * @return \Webcreate\Conveyor\Repository\Repository
76
     */
77 1
    public function getRepository()
78
    {
79 1
        return $this->container->get('repository');
80
    }
81
82
    /**
83
     * @return \Webcreate\Conveyor\Builder\Builder
84
     */
85
    public function getBuilder()
86
    {
87
        return $this->container->get('builder');
88
    }
89
90
    /**
91
     * @param  string              $target name of the target to get the transporter for
92
     * @return AbstractTransporter
93
     */
94
    public function getTransporter($target)
95
    {
96
        $factory = $this->container->get('transporter.factory');
97
98
        $config = $this->getConfig()->getConfig();
99
100
        $options = $config['targets'][$target]['transport'];
101
102
        return $factory->get($options['type'], $options);
103
    }
104
105
    /**
106
     * @return \Webcreate\Conveyor\IO\IOInterface
107
     */
108 1
    public function getIO()
109
    {
110 1
        return $this->container->get('io');
111
    }
112
113
    /**
114
     * @param  null|AbstractTransporter $transporter
115
     * @return StrategyInterface
116
     */
117
    public function getStrategy($transporter = null)
118
    {
119
        /** @var StrategyFactory $factory */
120
        $factory = $this->container->get('strategy.factory');
121
        $config = $this->getConfig()->getConfig();
122
        $dispatcher = $this->container->get('dispatcher');
123
124
        if (null === $this->strategy) {
125
            $options = $config['deploy']['strategy'];
126
127
            $strategy = $factory->get($options['type'], $options);
128
129
            if ($strategy instanceof TransporterAwareInterface) {
130
                $strategy->setTransporter($transporter);
131
            }
132
133
            if ($strategy instanceof EventSubscriberInterface) {
134
                $dispatcher->addSubscriber($strategy);
135
            }
136
137
            $this->strategy = $strategy;
138
        }
139
140
        return $this->strategy;
141
    }
142
143
    /**
144
     * Create a conveyor file
145
     *
146
     * @param  string  $filename
147
     * @return boolean
148
     */
149 1
    public function init($filename = null)
150
    {
151 1
        if (null === $filename) {
152 1
            $filename = $this->container->getParameter('conveyor.configfile');
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $filename. This often makes code more readable.
Loading history...
153
        }
154
155 1
        if (file_exists($filename)) {
156
            $this->getIO()->write(sprintf('<error>%s already exists.</error>', $filename));
157
158
            return false;
159
        } else {
160 1
            $this->getIO()->write(sprintf('Writing <info>%s</info>', $filename));
161 1
            file_put_contents($filename, file_get_contents(__DIR__ . '/Resources/conveyor.yml'));
162
        }
163
164 1
        return true;
165
    }
166
167
    /**
168
     * Validate conveyor file
169
     *
170
     * @throws \Symfony\Component\Config\Definition\Exception\InvalidConfigurationException
171
     * @return boolean
172
     */
173
    public function validate()
174
    {
175
        $config = $this->getConfig();
176
        $config->getConfig();
177
178
        return true;
179
    }
180
181
    /**
182
     * Returns available versions
183
     *
184
     * @return Version[]
185
     */
186 1
    public function getVersions()
187
    {
188 1
        return $this->getRepository()->getVersions();
189
    }
190
191
    /**
192
     * Retrieve the status for each target
193
     *
194
     * @param  null|string $target when given only get the status for a single target
195
     * @return array
196
     */
197
    public function status($target = null)
198
    {
199
        $config         = $this->getConfig()->getConfig();
200
        $targets        = (null !== $target) ? array($target) : array_keys($config['targets']);
201
        $repository     = $this->getRepository();
202
        $remoteInfoFile = $this->container->getParameter('conveyor.remoteinfofile');
203
204
        $retval = array();
205
206
        foreach ($targets as $target) {
207
            $this->assertTargetExists($target, $config);
0 ignored issues
show
Bug introduced by
It seems like $config defined by $this->getConfig()->getConfig() on line 199 can also be of type null; however, Webcreate\Conveyor\Conveyor::assertTargetExists() does only seem to accept array, 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...
208
        }
209
210
        foreach ($targets as $target) {
211
            $transporter = $this->getTransporter($target);
212
            $strategy    = $this->getStrategy($transporter);
213
214
            $context = new Context();
215
            $context
216
                ->setTarget($target)
217
                ->setStrategy($strategy)
218
            ;
219
220
            try {
221
                $versionFile = FilePath::join(
222
                    $transporter->getPath(),
223
                    $strategy->getCurrentReleasePath(),
224
                    $remoteInfoFile
225
                );
226
227
                $isDeployed = $transporter->exists($versionFile);
228
229
                if ($isDeployed) {
230
                    $manager = new StageManager($context, $this->container->get('dispatcher'));
231
                    $manager->addStage('get.remote.version', new Stage\RetrieveRemoteVersionInfoStage($transporter, $repository, new NullIO(), $remoteInfoFile, array('getRemoteVersion')));
232
                    $manager->execute();
233
234
                    // @todo don't compare to master branch, compare to the remote version's ancestor
235
                    $localVersion = $repository->getVersion(sprintf('dev-%s', $repository->getMasterBranch()));
236
                    $remoteVersion = $context->getRemoteVersion();
237
238
                    $compare = $repository->versionCompare($localVersion, $remoteVersion);
239
240
                    $changelog = array();
241
242
                    if (1 === $compare) {
243
                        $changelog = $repository->changelog($remoteVersion, $localVersion);
244
                    } elseif (-1 === $compare) {
245
                        $changelog = $repository->changelog($localVersion, $remoteVersion);
246
                    }
247
248
                    $retval[$target] = array(
249
                        'remoteVersion' => $context->getRemoteVersion(),
250
                        'localVersion'  => $localVersion,
251
                        'changelog'     => $changelog,
252
                        'compare'       => $compare,
253
                    );
254
                } else {
255
                    $retval[$target] = false;
256
                }
257
            } catch (\Exception $e) {
258
                $retval[$target] = array(
259
                    'error' => $e,
260
                );
261
            }
262
        }
263
264
        return $retval;
265
    }
266
267
    /**
268
     * Builds version for target
269
     *
270
     * @param string         $target
271
     * @param Version|string $version
272
     */
273
    public function build($target, $version)
274
    {
275
        if (is_string($version)) {
276
            $version = $this->getRepository()->getVersion($version);
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $version. This often makes code more readable.
Loading history...
277
        }
278
279
        $this->assertTargetExists($target, $this->getConfig()->getConfig());
0 ignored issues
show
Bug introduced by
It seems like $this->getConfig()->getConfig() targeting Webcreate\Conveyor\Config\YamlConfig::getConfig() can also be of type null; however, Webcreate\Conveyor\Conveyor::assertTargetExists() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
280
281
        $this->setConfigParametersForTarget($target);
282
        $this->setConfigParametersForVcs($this->getRepository(), $version);
283
284
        $builder = $this->getBuilder();
285
        $io      = $this->getIO();
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $io. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
286
287
        $context = new Context();
288
        $context
289
            ->setBuilddir($builder->getBuildDir())
290
            ->setVersion($version)
291
            ->setTarget($target)
292
        ;
293
294
        $manager = new StageManager($context, $this->container->get('dispatcher'));
295
        $manager
296
            ->addStage('build', new Stage\BuildStage($builder, $io))
297
            ->execute()
298
        ;
299
    }
300
301
    /**
302
     * Deploys version to target
303
     *
304
     * @param string $target
305
     * @param string $version
306
     * @param array  $options
307
     */
308 View Code Duplication
    public function deploy($target, $version, array $options = array())
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
309
    {
310
        $this->assertTargetOrGroupExists($target, $this->getConfig()->getConfig());
0 ignored issues
show
Bug introduced by
It seems like $this->getConfig()->getConfig() targeting Webcreate\Conveyor\Config\YamlConfig::getConfig() can also be of type null; however, Webcreate\Conveyor\Conve...rtTargetOrGroupExists() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
311
312
        if ($this->isTargetGroup($target)) {
313
            $targets = $this->getTargetsForGroup($target);
314
        } else {
315
            $targets = array($target);
316
        }
317
318
        foreach ($targets as $target) {
319
            $this->getIO()->setPrefix(sprintf('[%s] ', $target));
320
321
            $this->doDeploy($target, $version, $options);
322
323
            $this->getIO()->setPrefix(null);
324
        }
325
    }
326
327
    /**
328
     * Simulates a deploy
329
     *
330
     * @param string $target
331
     * @param string $version
332
     * @param array  $options
333
     */
334 View Code Duplication
    public function simulate($target, $version, array $options = array())
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
335
    {
336
        $this->assertTargetOrGroupExists($target, $this->getConfig()->getConfig());
0 ignored issues
show
Bug introduced by
It seems like $this->getConfig()->getConfig() targeting Webcreate\Conveyor\Config\YamlConfig::getConfig() can also be of type null; however, Webcreate\Conveyor\Conve...rtTargetOrGroupExists() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
337
338
        if ($this->isTargetGroup($target)) {
339
            $targets = $this->getTargetsForGroup($target);
340
        } else {
341
            $targets = array($target);
342
        }
343
344
        foreach ($targets as $target) {
345
            $this->getIO()->setPrefix(sprintf('[%s] ', $target));
346
347
            $this->doSimulate($target, $version, $options);
348
349
            $this->getIO()->setPrefix(null);
350
        }
351
    }
352
353
    public function undeploy($target, array $options = array())
0 ignored issues
show
Unused Code introduced by
The parameter $options is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
354
    {
355
        $this->assertTargetExists($target, $this->getConfig()->getConfig());
0 ignored issues
show
Bug introduced by
It seems like $this->getConfig()->getConfig() targeting Webcreate\Conveyor\Config\YamlConfig::getConfig() can also be of type null; however, Webcreate\Conveyor\Conveyor::assertTargetExists() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
356
357
        $this->setConfigParametersForTarget($target);
358
        $this->setConfigParametersForVcs($this->getRepository(), new Version());
359
360
        /** @var \Webcreate\Conveyor\Task\TaskRunner $trUndeploy */
361
        $transporter = $this->getTransporter($target);
362
        $io          = $this->getIO();
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $io. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
363
        $trUndeploy  = $this->container->get('undeploy.taskrunner');
364
        $strategy    = $this->getStrategy($transporter);
365
366
        $trUndeploy->setTransporter($transporter);
367
368
        $context = new Context();
369
        $context
370
            ->setTarget($target)
371
            ->setStrategy($strategy)
372
            ->setVersion(new Version())
373
        ;
374
375
        $manager = new StageManager($context, $this->container->get('dispatcher'));
376
        $manager
377
            ->addStage('undeploy', new Stage\UndeployStage($trUndeploy, $transporter, $io))
378
            ->execute()
379
        ;
380
    }
381
382
    /**
383
     * Performs a diff with the target
384
     *
385
     * @param string $target
386
     * @param string $version
387
     */
388
    public function diff($target, $version)
389
    {
390
        $version = $this->getRepository()->getVersion($version);
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $version. This often makes code more readable.
Loading history...
391
392
        $this->assertTargetExists($target, $this->getConfig()->getConfig());
0 ignored issues
show
Bug introduced by
It seems like $this->getConfig()->getConfig() targeting Webcreate\Conveyor\Config\YamlConfig::getConfig() can also be of type null; however, Webcreate\Conveyor\Conveyor::assertTargetExists() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
393
394
        $transporter    = $this->getTransporter($target);
395
        $repository     = $this->getRepository();
396
        $io             = $this->getIO();
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $io. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
397
        $remoteInfoFile = $this->container->getParameter('conveyor.remoteinfofile');
398
        $strategy       = $this->getStrategy($transporter);
399
400
        $context = new Context();
401
        $context
402
            ->setVersion($version)
403
            ->setTarget($target)
404
            ->setStrategy($strategy)
405
        ;
406
407
        $manager = new StageManager($context, $this->container->get('dispatcher'));
408
        $manager
409
            ->addStage('get.remote.version', new Stage\RetrieveRemoteVersionInfoStage($transporter, $repository, $io, $remoteInfoFile, array('getRemoteVersion')))
410
            ->addStage('diff',               new Stage\DiffStage($repository, $io))
0 ignored issues
show
Coding Style introduced by
Expected 1 space instead of 15 after comma in function call.
Loading history...
411
            ->execute()
412
        ;
413
    }
414
415
    /**
416
     * @return array
417
     */
418
    protected function getTargetGroups()
419
    {
420
        $config = $this->getConfig()->getConfig();
421
422
        $groups = array();
423 View Code Duplication
        foreach ($config['targets'] as $targetName => $targetConfig) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
424
            foreach ($targetConfig['groups'] as $group) {
425
                $groups[$group][] = $targetName;
426
            }
427
        }
428
429
        return $groups;
430
    }
431
432
    /**
433
     * @param string $target
434
     * @return bool
435
     */
436
    protected function isTargetGroup($target)
437
    {
438
        $groups = $this->getTargetGroups();
439
440
        return array_key_exists($target, $groups);
441
    }
442
443
    /**
444
     * @param string $group
445
     * @return array
446
     */
447
    protected function getTargetsForGroup($group)
448
    {
449
        if (!$this->isTargetGroup($group)) {
450
            throw new \InvalidArgumentException(
451
                sprintf(
452
                    '"%s" is not a valid target group, valid groups are: %s',
453
                    $group,
454
                    implode(', ', array_keys($this->getTargetGroups()))
455
                )
456
            );
457
        }
458
459
        $groups = $this->getTargetGroups();
460
461
        return $groups[$group];
462
    }
463
464
    /**
465
     * Deploys version to target
466
     *
467
     * @param string $target
468
     * @param string $version
469
     * @param array  $options
470
     */
471
    protected function doDeploy($target, $version, array $options = array())
472
    {
473
        $version = $this->getRepository()->getVersion($version);
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $version. This often makes code more readable.
Loading history...
474
475
        $options += array(
476
            'full_deploy'       => false,
477
            'deploy_after_only' => false,
478
            'force'             => false,
479
        );
480
481
        $this->assertTargetExists($target, $this->getConfig()->getConfig());
0 ignored issues
show
Bug introduced by
It seems like $this->getConfig()->getConfig() targeting Webcreate\Conveyor\Config\YamlConfig::getConfig() can also be of type null; however, Webcreate\Conveyor\Conveyor::assertTargetExists() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
482
483
        $this->setConfigParametersForTarget($target);
484
        $this->setConfigParametersForVcs($this->getRepository(), $version);
485
486
        $config         = $this->getConfig()->getConfig();
487
        $derived        = $config['build']['derived'];
488
        $transporter    = $this->getTransporter($target);
489
        $builder        = $this->getBuilder();
490
        $repository     = $this->getRepository();
491
        $io             = $this->getIO();
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $io. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
492
        $dispatcher     = $this->container->get('dispatcher');
493
        $trDeployBefore = $this->container->get('deploy.taskrunner.before');
494
        /** @var $trDeployAfter TaskRunner */
495
        $trDeployAfter  = $this->container->get('deploy.taskrunner.after');
496
        $trDeployFinal  = $this->container->get('deploy.taskrunner.final');
497
        $remoteInfoFile = $this->container->getParameter('conveyor.remoteinfofile');
498
        $strategy       = $this->getStrategy($transporter);
499
500
        // @todo I don't like how the transporter is set here
501
        $trDeployBefore->setTransporter($transporter);
502
        $trDeployAfter->setTransporter($transporter);
503
        $trDeployFinal->setTransporter($transporter);
504
505
        $context = new Context();
506
        $context
507
            ->setFullDeploy($options['full_deploy'])
508
            ->setForce($options['force'])
509
            ->setBuilddir($builder->getBuildDir())
510
            ->setVersion($version)
511
            ->setTarget($target)
512
            ->setStrategy($strategy)
513
        ;
514
515
        if ($transporter instanceof TransactionalTransporterInterface) {
516
            $transporter->begin();
517
        }
518
519
        $manager = new StageManager($context, $dispatcher);
520
        $manager
521
            ->addStage('validate.remote',    new Stage\ValidateRemoteStage($transporter, $io, $remoteInfoFile))
0 ignored issues
show
Coding Style introduced by
Expected 1 space instead of 4 after comma in function call.
Loading history...
522
            ->addStage('get.remote.version', new Stage\RetrieveRemoteVersionInfoStage($transporter, $repository, $io, $remoteInfoFile))
523
            ->addStage('build',              new Stage\BuildStage($builder, $io))
0 ignored issues
show
Coding Style introduced by
Expected 1 space instead of 14 after comma in function call.
Loading history...
524
            ->addStage('filelist',           new Stage\BuildFilelistStage($repository, $derived))
0 ignored issues
show
Coding Style introduced by
Expected 1 space instead of 11 after comma in function call.
Loading history...
525
            ->addStage('deploy.before',      new Stage\DeployBeforeStage($trDeployBefore, $io))
0 ignored issues
show
Coding Style introduced by
Expected 1 space instead of 6 after comma in function call.
Loading history...
526
            ->addStage('transfer',           new Stage\TransferStage($transporter, $io))
0 ignored issues
show
Coding Style introduced by
Expected 1 space instead of 11 after comma in function call.
Loading history...
527
            ->addStage('set.remote.version', new Stage\WriteRemoteInfoFileStage($transporter, $remoteInfoFile, $io))
528
            ->addStage('deploy.after',       new Stage\DeployAfterStage($trDeployAfter, $io))
0 ignored issues
show
Coding Style introduced by
Expected 1 space instead of 7 after comma in function call.
Loading history...
529
            ->addStage('deploy.final',       new Stage\DeployFinalStage($trDeployFinal, $io))
0 ignored issues
show
Coding Style introduced by
Expected 1 space instead of 7 after comma in function call.
Loading history...
530
        ;
531
532 View Code Duplication
        if ($transporter instanceof TransactionalTransporterInterface) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
533
            $dispatcher->addListener(
534
                StageEvents::STAGE_PRE_EXECUTE,
535
                function (StageEvent $event) use ($transporter) {
536
                    if ('deploy.after' === $event->getStageName()) {
537
                        $transporter->commit();
538
                    }
539
                }
540
            );
541
        }
542
543
        $runnableStages = array();
544
        if (true === $options['deploy_after_only']) {
545
            $runnableStages = array('deploy.after');
546
        }
547
548
        try {
549
            $result = $manager->execute($runnableStages);
550
        } catch (EmptyChangesetException $e) {
551
            $this->getIO()->write('Nothing to deploy: no files have been changed or removed. Use --full to deploy anyway.', true);
552
553
            $result = true; // trigger a cleanup
554
        }
555
556 View Code Duplication
        if ($result === true) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
557
            // cleanup
558
            $builddir = $this->getBuilder()->getBuildDir();
559
            if (is_dir($builddir)) {
560
                $filesystem = new Filesystem();
561
                $filesystem->remove($builddir);
562
            }
563
        }
564
    }
565
566
    /**
567
     * Simulates a deploy
568
     *
569
     * @param string $target
570
     * @param string $version
571
     * @param array  $options
572
     */
573
    protected function doSimulate($target, $version, array $options = array())
574
    {
575
        $version = $this->getRepository()->getVersion($version);
0 ignored issues
show
Coding Style introduced by
Consider using a different name than the parameter $version. This often makes code more readable.
Loading history...
576
577
        $options += array(
578
            'full_deploy' => false,
579
            'force'       => false,
580
        );
581
582
        $this->assertTargetExists($target, $this->getConfig()->getConfig());
0 ignored issues
show
Bug introduced by
It seems like $this->getConfig()->getConfig() targeting Webcreate\Conveyor\Config\YamlConfig::getConfig() can also be of type null; however, Webcreate\Conveyor\Conveyor::assertTargetExists() does only seem to accept array, maybe add an additional type check?

This check looks at variables that are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
583
584
        $this->setConfigParametersForTarget($target);
585
        $this->setConfigParametersForVcs($this->getRepository(), $version);
586
587
        $transporter = $this->getTransporter($target);
588
        $readOnlyTransporter = $this->container->get('transporter.readonly');
589
        $readOnlyTransporter->setInnerTransporter($transporter);
590
591
        $config         = $this->getConfig()->getConfig();
592
        $derived        = $config['build']['derived'];
593
        $builder        = $this->getBuilder();
594
        $repository     = $this->getRepository();
595
        $io             = $this->getIO();
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $io. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
596
        $dispatcher     = $this->container->get('dispatcher');
597
        $trDeployBefore = $this->container->get('deploy.taskrunner.before');
598
        $trDeployAfter  = $this->container->get('deploy.taskrunner.after');
599
        $trDeployFinal  = $this->container->get('deploy.taskrunner.final');
600
        $remoteInfoFile = $this->container->getParameter('conveyor.remoteinfofile');
601
        $strategy       = $this->getStrategy($readOnlyTransporter);
602
603
        $trDeployBefore->setTransporter($readOnlyTransporter);
604
        $trDeployAfter->setTransporter($readOnlyTransporter);
605
        $trDeployFinal->setTransporter($readOnlyTransporter);
606
607
        $context = new Context();
608
        $context
609
            ->setFullDeploy($options['full_deploy'])
610
            ->setForce($options['force'])
611
            ->setSimulate(true)
612
            ->setBuilddir($this->getBuilder()->getBuildDir())
613
            ->setVersion($version)
614
            ->setTarget($target)
615
            ->setStrategy($strategy)
616
        ;
617
618
        if ($transporter instanceof TransactionalTransporterInterface) {
619
            $transporter->begin();
620
        }
621
622
        $manager = new StageManager($context, $dispatcher);
623
        $manager
624
            ->addStage('validate.remote',    new Stage\ValidateRemoteStage($readOnlyTransporter, $io, $remoteInfoFile))
0 ignored issues
show
Coding Style introduced by
Expected 1 space instead of 4 after comma in function call.
Loading history...
625
            ->addStage('get.remote.version', new Stage\RetrieveRemoteVersionInfoStage($readOnlyTransporter, $repository, $io, $remoteInfoFile))
626
            ->addStage('build',              new Stage\BuildStage($builder, $io))
0 ignored issues
show
Coding Style introduced by
Expected 1 space instead of 14 after comma in function call.
Loading history...
627
            ->addStage('filelist',           new Stage\BuildFilelistStage($repository, $derived))
0 ignored issues
show
Coding Style introduced by
Expected 1 space instead of 11 after comma in function call.
Loading history...
628
            ->addStage('deploy.before',      new Stage\DeployBeforeStage($trDeployBefore, $io))
0 ignored issues
show
Coding Style introduced by
Expected 1 space instead of 6 after comma in function call.
Loading history...
629
            ->addStage('transfer',           new Stage\TransferStage($readOnlyTransporter, $io))
0 ignored issues
show
Coding Style introduced by
Expected 1 space instead of 11 after comma in function call.
Loading history...
630
            ->addStage('set.remote.version', new Stage\WriteRemoteInfoFileStage($readOnlyTransporter, $remoteInfoFile, $io))
631
            ->addStage('deploy.after',       new Stage\DeployAfterStage($trDeployAfter, $io))
0 ignored issues
show
Coding Style introduced by
Expected 1 space instead of 7 after comma in function call.
Loading history...
632
            ->addStage('deploy.final',       new Stage\DeployFinalStage($trDeployFinal, $io))
0 ignored issues
show
Coding Style introduced by
Expected 1 space instead of 7 after comma in function call.
Loading history...
633
        ;
634
635 View Code Duplication
        if ($transporter instanceof TransactionalTransporterInterface) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
636
            $dispatcher->addListener(
637
                StageEvents::STAGE_PRE_EXECUTE,
638
                function (StageEvent $event) use ($transporter) {
639
                    if ('deploy.after' === $event->getStageName()) {
640
                        $transporter->commit();
641
                    }
642
                }
643
            );
644
        }
645
646
        try {
647
            $result = $manager->execute();
648
        } catch (EmptyChangesetException $e) {
649
            $this->getIO()->write('Nothing to deploy: no files have been changed or removed. Use --full to deploy anyway.', true);
650
651
            $result = true; // trigger a cleanup
652
        }
653
654 View Code Duplication
        if ($result === true) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
655
            // cleanup
656
            $builddir = $this->getBuilder()->getBuildDir();
657
            if (is_dir($builddir)) {
658
                $filesystem = new Filesystem();
659
                $filesystem->remove($builddir);
660
            }
661
        }
662
    }
663
664
    /**
665
     * @param  IOInterface                          $io
666
     * @return ContainerBuilder
667
     * @throws \Exception|\InvalidArgumentException
668
     */
669 3
    protected function buildContainer(IOInterface $io)
0 ignored issues
show
Comprehensibility introduced by
Avoid variables with short names like $io. Configured minimum length is 3.

Short variable names may make your code harder to understand. Variable names should be self-descriptive. This check looks for variable names who are shorter than a configured minimum.

Loading history...
670
    {
671 3
        $container = new ContainerBuilder();
672 3
        $loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/Resources/config'));
673 3
        $loader->load('parameters.yml');
674 3
        $loader->load('services.yml');
675 3
        $loader->load('tasks.yml');
676 3
        $loader->load('transporters.yml');
677 3
        $loader->load('strategies.yml');
678
679 3
        $container->set('io', $io);
680
681 3
        $container->addCompilerPass(new TaskCompilerPass());
682 3
        $container->addCompilerPass(new TransporterCompilerPass());
683 3
        $container->addCompilerPass(new StrategyCompilerPass());
684 3
        $container->addCompilerPass(new ParameterCompilerPass());
685
686
        // set custom config file if it is set
687 3
        if ($this->configFile) {
688
            $container->setParameter('conveyor.configfile', $this->configFile);
689
        }
690
691
        try {
692 3
            $container->compile();
693 2
        } catch (\InvalidArgumentException $e) {
694
            // Ignore an InvalidArgumentException for YamlConfig,
695
            // otherwise init() would not be possible
696 2
            if ('YamlConfig.php' !== basename($e->getFile())) {
697
                throw $e;
698
            }
699
        }
700
701 3
        return $container;
702
    }
703
704
    /**
705
     * @param string $target
706
     */
707
    protected function setConfigParametersForTarget($target)
708
    {
709
        $this->getConfig()->setParameter('target', $target);
710
711
        $config = $this->getConfig()->getConfig();
712
713
        $transporterOptions = $config['targets'][$target]['transport'];
714
        foreach ($transporterOptions as $key => $value) {
715
            $this->getConfig()->setParameter('target.transport.' . $key, $value);
716
        }
717
    }
718
719
    /**
720
     * @param Repository $getRepository
721
     * @param Version $version
722
     */
723
    private function setConfigParametersForVcs(Repository $getRepository, Version $version)
724
    {
725
        $this->getConfig()->setParameter('vcs.url', $getRepository->getUrl());
726
        $this->getConfig()->setParameter('vcs.type', $getRepository->getType());
727
        $this->getConfig()->setParameter('vcs.build', $version->getBuild());
728
        $this->getConfig()->setParameter('vcs.build_short', substr($version->getBuild(), 0, 7));
729
        $this->getConfig()->setParameter('vcs.version', $version->getName());
730
    }
731
732
    /**
733
     * @param string $target
734
     * @param array $config
735
     * @return bool
736
     * @throws \InvalidArgumentException
737
     */
738
    protected function assertTargetExists($target, array $config)
739
    {
740
        if (!isset($config['targets'][$target])) {
741
            throw new \InvalidArgumentException(sprintf("Target '%s' does not exist, available targets are: %s.", $target, implode(", ", array_keys($config['targets']))));
742
        }
743
744
        return true;
745
    }
746
747
    /**
748
     * @param string $target
749
     * @param array $config
750
     * @return bool
751
     * @throws \InvalidArgumentException
752
     */
753
    protected function assertTargetOrGroupExists($target, array $config)
754
    {
755
        if (!isset($config['targets'][$target]) && !$this->isTargetGroup($target)) {
756
            $targets = array_keys($config['targets']);
757
            $groups = array_keys($this->getTargetGroups());
758
759
            throw new \InvalidArgumentException(sprintf("Target '%s' does not exist, available targets and groups are: %s.", $target, implode(", ", array_merge($targets, $groups))));
760
        }
761
762
        return true;
763
    }
764
765
    /**
766
     * Set a custom config file, is used for booting (compiling the di container)
767
     *
768
     * @param string $path
769
     */
770
    public function setConfigFile($path)
771
    {
772
        $this->configFile = $path;
773
    }
774
}
775