1
|
|
|
<?php |
2
|
|
|
/* |
3
|
|
|
* This file is part of the Magallanes package. |
4
|
|
|
* |
5
|
|
|
* (c) Andrés Montañez <[email protected]> |
6
|
|
|
* |
7
|
|
|
* For the full copyright and license information, please view the LICENSE |
8
|
|
|
* file that was distributed with this source code. |
9
|
|
|
*/ |
10
|
|
|
|
11
|
|
|
namespace Mage\Command\BuiltIn\Releases; |
12
|
|
|
|
13
|
|
|
use Mage\Task\TaskFactory; |
14
|
|
|
use Mage\Runtime\Exception\RuntimeException; |
15
|
|
|
use Symfony\Component\Process\Process; |
16
|
|
|
use Symfony\Component\Console\Input\InputInterface; |
17
|
|
|
use Symfony\Component\Console\Input\InputArgument; |
18
|
|
|
use Symfony\Component\Console\Output\OutputInterface; |
19
|
|
|
use Mage\Command\BuiltIn\DeployCommand; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* Command for Rolling Back a Releases |
23
|
|
|
* |
24
|
|
|
* @author Andrés Montañez <[email protected]> |
25
|
|
|
*/ |
26
|
|
|
class RollbackCommand extends DeployCommand |
27
|
|
|
{ |
28
|
|
|
/** |
29
|
|
|
* @var int |
30
|
|
|
*/ |
31
|
|
|
protected $statusCode = 0; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* Configure the Command |
35
|
|
|
*/ |
36
|
|
|
protected function configure() |
37
|
|
|
{ |
38
|
|
|
$this |
39
|
|
|
->setName('releases:rollback') |
40
|
|
|
->setDescription('Rollback to a release on an environment') |
41
|
|
|
->addArgument('environment', InputArgument::REQUIRED, 'Name of the environment to deploy to') |
42
|
|
|
->addArgument('release', InputArgument::REQUIRED, 'The ID or the Index of the release to rollback to') |
43
|
|
|
; |
44
|
|
|
} |
45
|
|
|
|
46
|
|
|
/** |
47
|
|
|
* Execute the Command |
48
|
|
|
* |
49
|
|
|
* @param InputInterface $input |
50
|
|
|
* @param OutputInterface $output |
51
|
|
|
* @return int|mixed |
52
|
|
|
*/ |
53
|
|
|
protected function execute(InputInterface $input, OutputInterface $output) |
54
|
|
|
{ |
55
|
|
|
$this->requireConfig(); |
56
|
|
|
|
57
|
|
|
$output->writeln('Starting <fg=blue>Magallanes</>'); |
58
|
|
|
$output->writeln(''); |
59
|
|
|
|
60
|
|
|
try { |
61
|
|
|
$this->runtime->setEnvironment($input->getArgument('environment')); |
|
|
|
|
62
|
|
|
|
63
|
|
|
$strategy = $this->runtime->guessStrategy(); |
64
|
|
|
$this->taskFactory = new TaskFactory($this->runtime); |
65
|
|
|
|
66
|
|
|
if (!$this->runtime->getEnvOption('releases', false)) { |
67
|
|
|
throw new RuntimeException('Releases are not enabled', 70); |
68
|
|
|
} |
69
|
|
|
|
70
|
|
|
$releaseToRollback = $input->getArgument('release'); |
71
|
|
|
if (($releaseId = $this->checkReleaseAvailability($releaseToRollback)) === false) { |
|
|
|
|
72
|
|
|
throw new RuntimeException(sprintf('Release "%s" is not available on all hosts', $releaseToRollback), 72); |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
$this->runtime->setReleaseId($releaseId)->setRollback(true); |
76
|
|
|
|
77
|
|
|
$output->writeln(sprintf(' Environment: <fg=green>%s</>', $this->runtime->getEnvironment())); |
78
|
|
|
$this->log(sprintf('Environment: %s', $this->runtime->getEnvironment())); |
79
|
|
|
|
80
|
|
|
$output->writeln(sprintf(' Rollback to Release Id: <fg=green>%s</>', $this->runtime->getReleaseId())); |
81
|
|
|
$this->log(sprintf('Release ID: %s', $this->runtime->getReleaseId())); |
82
|
|
|
|
83
|
|
View Code Duplication |
if ($this->runtime->getConfigOption('log_file', false)) { |
|
|
|
|
84
|
|
|
$output->writeln(sprintf(' Logfile: <fg=green>%s</>', $this->runtime->getConfigOption('log_file'))); |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
$output->writeln(sprintf(' Strategy: <fg=green>%s</>', $strategy->getName())); |
88
|
|
|
|
89
|
|
|
$output->writeln(''); |
90
|
|
|
$this->runDeployment($output, $strategy); |
91
|
|
|
} catch (RuntimeException $exception) { |
92
|
|
|
$output->writeln(sprintf('<error>%s</error>', $exception->getMessage())); |
93
|
|
|
$this->statusCode = $exception->getCode(); |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
$output->writeln('Finished <fg=blue>Magallanes</>'); |
97
|
|
|
|
98
|
|
|
return $this->statusCode; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* Check if the provided Release ID is available in all hosts |
103
|
|
|
* |
104
|
|
|
* @param string $releaseToRollback Release ID |
105
|
|
|
* @return bool |
106
|
|
|
*/ |
107
|
|
|
protected function checkReleaseAvailability($releaseToRollback) |
108
|
|
|
{ |
109
|
|
|
$hosts = $this->runtime->getEnvOption('hosts'); |
110
|
|
|
$hostPath = rtrim($this->runtime->getEnvOption('host_path'), '/'); |
111
|
|
|
|
112
|
|
|
$availableInHosts = 0; |
113
|
|
|
foreach ($hosts as $host) { |
114
|
|
|
$releases = []; |
115
|
|
|
$this->runtime->setWorkingHost($host); |
116
|
|
|
|
117
|
|
|
// Get List of Releases |
118
|
|
|
$cmdListReleases = sprintf('ls -1 %s/releases', $hostPath); |
119
|
|
|
|
120
|
|
|
/** @var Process $process */ |
121
|
|
|
$process = $this->runtime->runRemoteCommand($cmdListReleases, false); |
122
|
|
|
if ($process->isSuccessful()) { |
123
|
|
|
$releases = explode(PHP_EOL, trim($process->getOutput())); |
124
|
|
|
rsort($releases); |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
if (in_array($releaseToRollback, $releases)) { |
128
|
|
|
$availableInHosts++; |
129
|
|
|
} |
130
|
|
|
|
131
|
|
|
$this->runtime->setWorkingHost(null); |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
if ($availableInHosts === count($hosts)) { |
135
|
|
|
return $releaseToRollback; |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
return false; |
139
|
|
|
} |
140
|
|
|
} |
141
|
|
|
|
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.