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 |
||
32 | class DeployCommand extends AbstractCommand |
||
33 | { |
||
34 | /** |
||
35 | * @var TaskFactory |
||
36 | */ |
||
37 | protected $taskFactory; |
||
38 | |||
39 | /** |
||
40 | * Configure the Command |
||
41 | */ |
||
42 | protected function configure() |
||
43 | { |
||
44 | $this |
||
45 | ->setName('deploy') |
||
46 | ->setDescription('Deploy code to hosts') |
||
47 | ->addArgument('environment', InputArgument::REQUIRED, 'Name of the environment to deploy to') |
||
48 | ->addOption('branch', null, InputOption::VALUE_REQUIRED, 'Force to switch to a branch other than the one defined', false) |
||
49 | ; |
||
50 | } |
||
51 | |||
52 | /** |
||
53 | * Execute the Command |
||
54 | * |
||
55 | * @param InputInterface $input |
||
56 | * @param OutputInterface $output |
||
57 | * @return integer |
||
58 | */ |
||
59 | protected function execute(InputInterface $input, OutputInterface $output) |
||
60 | { |
||
61 | $this->requireConfig(); |
||
62 | |||
63 | $output->writeln('Starting <fg=blue>Magallanes</>'); |
||
64 | $output->writeln(''); |
||
65 | |||
66 | try { |
||
67 | $this->runtime->setEnvironment($input->getArgument('environment')); |
||
|
|||
68 | |||
69 | $strategy = $this->runtime->guessStrategy(); |
||
70 | $this->taskFactory = new TaskFactory($this->runtime); |
||
71 | |||
72 | $output->writeln(sprintf(' Environment: <fg=green>%s</>', $this->runtime->getEnvironment())); |
||
73 | $this->log(sprintf('Environment: %s', $this->runtime->getEnvironment())); |
||
74 | |||
75 | if ($this->runtime->getEnvOption('releases', false)) { |
||
76 | $this->runtime->generateReleaseId(); |
||
77 | $output->writeln(sprintf(' Release ID: <fg=green>%s</>', $this->runtime->getReleaseId())); |
||
78 | $this->log(sprintf('Release ID: %s', $this->runtime->getReleaseId())); |
||
79 | } |
||
80 | |||
81 | View Code Duplication | if ($this->runtime->getConfigOption('log_file', false)) { |
|
82 | $output->writeln(sprintf(' Logfile: <fg=green>%s</>', $this->runtime->getConfigOption('log_file'))); |
||
83 | } |
||
84 | |||
85 | $output->writeln(sprintf(' Strategy: <fg=green>%s</>', $strategy->getName())); |
||
86 | |||
87 | if ($input->getOption('branch') !== false) { |
||
88 | $this->runtime->setEnvOption('branch', $input->getOption('branch')); |
||
89 | } |
||
90 | |||
91 | if ($this->runtime->getEnvOption('branch', false)) { |
||
92 | $output->writeln(sprintf(' Branch: <fg=green>%s</>', $this->runtime->getEnvOption('branch'))); |
||
93 | } |
||
94 | |||
95 | $output->writeln(''); |
||
96 | $this->runDeployment($output, $strategy); |
||
97 | } catch (RuntimeException $exception) { |
||
98 | $output->writeln(''); |
||
99 | $output->writeln(sprintf('<error>%s</error>', $exception->getMessage())); |
||
100 | $output->writeln(''); |
||
101 | $this->statusCode = 7; |
||
102 | } |
||
103 | |||
104 | $output->writeln('Finished <fg=blue>Magallanes</>'); |
||
105 | |||
106 | return $this->statusCode; |
||
107 | } |
||
108 | |||
109 | /** |
||
110 | * Run the Deployment Process |
||
111 | * |
||
112 | * @param OutputInterface $output |
||
113 | * @param StrategyInterface $strategy |
||
114 | * @throws RuntimeException |
||
115 | */ |
||
116 | protected function runDeployment(OutputInterface $output, StrategyInterface $strategy) |
||
117 | { |
||
118 | // Run "Pre Deploy" Tasks |
||
119 | $this->runtime->setStage(Runtime::PRE_DEPLOY); |
||
120 | if (!$this->runTasks($output, $strategy->getPreDeployTasks())) { |
||
121 | throw $this->getException(); |
||
122 | } |
||
123 | |||
124 | // Run "On Deploy" Tasks |
||
125 | $this->runtime->setStage(Runtime::ON_DEPLOY); |
||
126 | $this->runOnHosts($output, $strategy->getOnDeployTasks()); |
||
127 | |||
128 | // Run "On Release" Tasks |
||
129 | $this->runtime->setStage(Runtime::ON_RELEASE); |
||
130 | $this->runOnHosts($output, $strategy->getOnReleaseTasks()); |
||
131 | |||
132 | // Run "Post Release" Tasks |
||
133 | $this->runtime->setStage(Runtime::POST_RELEASE); |
||
134 | $this->runOnHosts($output, $strategy->getPostReleaseTasks()); |
||
135 | |||
136 | // Run "Post Deploy" Tasks |
||
137 | $this->runtime->setStage(Runtime::POST_DEPLOY); |
||
138 | if (!$this->runTasks($output, $strategy->getPostDeployTasks())) { |
||
139 | throw $this->getException(); |
||
140 | } |
||
141 | } |
||
142 | |||
143 | protected function runOnHosts(OutputInterface $output, $tasks) |
||
164 | |||
165 | /** |
||
166 | * Runs all the tasks |
||
167 | * |
||
168 | * @param OutputInterface $output |
||
169 | * @param $tasks |
||
170 | * @return bool |
||
171 | * @throws RuntimeException |
||
172 | */ |
||
173 | protected function runTasks(OutputInterface $output, $tasks) |
||
174 | { |
||
175 | if (count($tasks) == 0) { |
||
176 | $output->writeln(sprintf(' No tasks defined for <fg=black;options=bold>%s</> stage', $this->getStageName())); |
||
177 | $output->writeln(''); |
||
178 | return true; |
||
179 | } |
||
180 | |||
181 | if ($this->runtime->getHostName() !== null) { |
||
182 | $output->writeln(sprintf(' Starting <fg=black;options=bold>%s</> tasks on host <fg=black;options=bold>%s</>:', $this->getStageName(), $this->runtime->getHostName())); |
||
183 | } else { |
||
184 | $output->writeln(sprintf(' Starting <fg=black;options=bold>%s</> tasks:', $this->getStageName())); |
||
185 | } |
||
186 | |||
187 | $totalTasks = count($tasks); |
||
188 | $succeededTasks = 0; |
||
189 | |||
190 | foreach ($tasks as $taskName) { |
||
191 | /** @var AbstractTask $task */ |
||
192 | $task = $this->taskFactory->get($taskName); |
||
193 | $output->write(sprintf(' Running <fg=magenta>%s</> ... ', $task->getDescription())); |
||
194 | $this->log(sprintf('Running task %s (%s)', $task->getDescription(), $task->getName())); |
||
195 | |||
196 | if ($this->runtime->inRollback() && !$task instanceof ExecuteOnRollbackInterface) { |
||
197 | $succeededTasks++; |
||
198 | $output->writeln('<fg=yellow>SKIPPED</>'); |
||
199 | $this->log(sprintf('Task %s (%s) finished with SKIPPED, it was in a Rollback', $task->getDescription(), $task->getName())); |
||
200 | } else { |
||
201 | try { |
||
202 | if ($task->execute()) { |
||
203 | $succeededTasks++; |
||
204 | $output->writeln('<fg=green>OK</>'); |
||
205 | $this->log(sprintf('Task %s (%s) finished with OK', $task->getDescription(), $task->getName())); |
||
206 | } else { |
||
207 | $output->writeln('<fg=red>FAIL</>'); |
||
208 | $this->statusCode = 180; |
||
209 | $this->log(sprintf('Task %s (%s) finished with FAIL', $task->getDescription(), $task->getName())); |
||
210 | } |
||
211 | } catch (SkipException $exception) { |
||
212 | $succeededTasks++; |
||
213 | $output->writeln('<fg=yellow>SKIPPED</>'); |
||
214 | $this->log(sprintf('Task %s (%s) finished with SKIPPED, thrown SkipException', $task->getDescription(), $task->getName())); |
||
215 | } catch (ErrorException $exception) { |
||
216 | $output->writeln(sprintf('<fg=red>ERROR</> [%s]', $exception->getTrimmedMessage())); |
||
217 | $this->log(sprintf('Task %s (%s) finished with FAIL, with Error "%s"', $task->getDescription(), $task->getName(), $exception->getMessage())); |
||
218 | $this->statusCode = 190; |
||
219 | } |
||
220 | } |
||
221 | |||
222 | if ($this->statusCode !== 0) { |
||
223 | break; |
||
224 | } |
||
225 | } |
||
226 | |||
227 | $alertColor = 'red'; |
||
228 | if ($succeededTasks == $totalTasks) { |
||
229 | $alertColor = 'green'; |
||
230 | } |
||
231 | |||
232 | $output->writeln(sprintf(' Finished <fg=%s>%d/%d</> tasks for <fg=black;options=bold>%s</>.', $alertColor, $succeededTasks, $totalTasks, $this->getStageName())); |
||
233 | $output->writeln(''); |
||
234 | |||
235 | return ($succeededTasks == $totalTasks); |
||
236 | } |
||
237 | |||
238 | /** |
||
239 | * Exception for halting the the current process |
||
240 | */ |
||
241 | protected function getException() |
||
245 | } |
||
246 |
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.