RunCommand   A
last analyzed

Complexity

Total Complexity 14

Size/Duplication

Total Lines 146
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 14

Test Coverage

Coverage 0%

Importance

Changes 2
Bugs 1 Features 1
Metric Value
wmc 14
c 2
b 1
f 1
lcom 1
cbo 14
dl 0
loc 146
ccs 0
cts 70
cp 0
rs 10

6 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
A configure() 0 6 1
B execute() 0 62 7
A setMaxBuilds() 0 4 1
A setDaemon() 0 4 1
B validateRunningBuilds() 0 30 3
1
<?php
2
/**
3
 * PHPCI - Continuous Integration for PHP.
4
 *
5
 * @copyright    Copyright 2014, Block 8 Limited.
6
 * @license      https://github.com/Block8/PHPCI/blob/master/LICENSE.md
7
 *
8
 * @link         https://www.phptesting.org/
9
 */
10
11
namespace PHPCI\Command;
12
13
use b8\Config;
14
use Monolog\Logger;
15
use PHPCI\Helper\Lang;
16
use PHPCI\Logging\BuildDBLogHandler;
17
use PHPCI\Logging\LoggedBuildContextTidier;
18
use PHPCI\Logging\OutputLogHandler;
19
use Symfony\Component\Console\Command\Command;
20
use Symfony\Component\Console\Input\InputInterface;
21
use Symfony\Component\Console\Output\OutputInterface;
22
use b8\Store\Factory;
23
use PHPCI\Builder;
24
use PHPCI\BuildFactory;
25
use PHPCI\Model\Build;
26
27
/**
28
 * Run console command - Runs any pending builds.
29
 *
30
 * @author       Dan Cryer <[email protected]>
31
 */
32
class RunCommand extends Command
33
{
34
    /**
35
     * @var OutputInterface
36
     */
37
    protected $output;
38
39
    /**
40
     * @var Logger
41
     */
42
    protected $logger;
43
44
    /**
45
     * @var int
46
     */
47
    protected $maxBuilds = 100;
48
49
    /**
50
     * @var bool
51
     */
52
    protected $isFromDaemon = false;
53
54
    /**
55
     * @param \Monolog\Logger $logger
56
     * @param string          $name
57
     */
58
    public function __construct(Logger $logger, $name = null)
59
    {
60
        parent::__construct($name);
61
        $this->logger = $logger;
62
    }
63
64
    protected function configure()
65
    {
66
        $this
67
            ->setName('phpci:run-builds')
68
            ->setDescription(Lang::get('run_all_pending'));
69
    }
70
71
    /**
72
     * Pulls all pending builds from the database and runs them.
73
     */
74
    protected function execute(InputInterface $input, OutputInterface $output)
75
    {
76
        $this->output = $output;
77
78
        // For verbose mode we want to output all informational and above
79
        // messages to the symphony output interface.
80
        if ($input->hasOption('verbose') && $input->getOption('verbose')) {
81
            $this->logger->pushHandler(
82
                new OutputLogHandler($this->output, Logger::INFO)
83
            );
84
        }
85
86
        $running = $this->validateRunningBuilds();
87
88
        $this->logger->pushProcessor(new LoggedBuildContextTidier());
89
        $this->logger->addInfo(Lang::get('finding_builds'));
90
        $store = Factory::getStore('Build');
91
        $result = $store->getByStatus(0, $this->maxBuilds);
92
        $this->logger->addInfo(Lang::get('found_n_builds', count($result['items'])));
93
94
        $builds = 0;
95
96
        while (count($result['items'])) {
97
            $build = array_shift($result['items']);
98
            $build = BuildFactory::getBuild($build);
99
100
            // Skip build (for now) if there's already a build running in that project:
101
            if (!$this->isFromDaemon && in_array($build->getProjectId(), $running)) {
102
                $this->logger->addInfo(Lang::get('skipping_build', $build->getId()));
103
                $result['items'][] = $build;
104
105
                // Re-run build validator:
106
                $running = $this->validateRunningBuilds();
107
                continue;
108
            }
109
110
            ++$builds;
111
112
            try {
113
                // Logging relevant to this build should be stored
114
                // against the build itself.
115
                $buildDbLog = new BuildDBLogHandler($build, Logger::INFO);
116
                $this->logger->pushHandler($buildDbLog);
117
118
                $builder = new Builder($build, $this->logger);
119
                $builder->execute();
120
121
                // After execution we no longer want to record the information
122
                // back to this specific build so the handler should be removed.
123
                $this->logger->popHandler($buildDbLog);
0 ignored issues
show
Unused Code introduced by
The call to Logger::popHandler() has too many arguments starting with $buildDbLog.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
124
            } catch (\Exception $ex) {
125
                $build->setStatus(Build::STATUS_FAILED);
126
                $build->setFinished(new \DateTime());
127
                $build->setLog($build->getLog().PHP_EOL.PHP_EOL.$ex->getMessage());
128
                $store->save($build);
129
            }
130
        }
131
132
        $this->logger->addInfo(Lang::get('finished_processing_builds'));
133
134
        return $builds;
135
    }
136
137
    public function setMaxBuilds($numBuilds)
138
    {
139
        $this->maxBuilds = (int) $numBuilds;
140
    }
141
142
    public function setDaemon($fromDaemon)
143
    {
144
        $this->isFromDaemon = (bool) $fromDaemon;
145
    }
146
147
    protected function validateRunningBuilds()
148
    {
149
        /** @var \PHPCI\Store\BuildStore $store */
150
        $store = Factory::getStore('Build');
151
        $running = $store->getByStatus(1);
152
        $rtn = array();
153
154
        $timeout = Config::getInstance()->get('phpci.build.failed_after', 1800);
155
156
        foreach ($running['items'] as $build) {
157
            /** @var \PHPCI\Model\Build $build */
158
            $build = BuildFactory::getBuild($build);
159
160
            $now = time();
161
            $start = $build->getStarted()->getTimestamp();
162
163
            if (($now - $start) > $timeout) {
164
                $this->logger->addInfo(Lang::get('marked_as_failed', $build->getId()));
165
                $build->setStatus(Build::STATUS_FAILED);
166
                $build->setFinished(new \DateTime());
167
                $store->save($build);
168
                $build->removeBuildDirectory();
169
                continue;
170
            }
171
172
            $rtn[$build->getProjectId()] = true;
173
        }
174
175
        return $rtn;
176
    }
177
}
178