GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Test Failed
Push — master ( 44f5f8...8d9d8e )
by Anton
02:15
created

Deployer::load()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 20

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4.3244

Importance

Changes 0
Metric Value
cc 4
nc 2
nop 1
dl 0
loc 20
ccs 8
cts 11
cp 0.7272
crap 4.3244
rs 9.6
c 0
b 0
f 0
1
<?php
2
/* (c) Anton Medvedev <[email protected]>
3
 *
4
 * For the full copyright and license information, please view the LICENSE
5
 * file that was distributed with this source code.
6
 */
7
8
namespace Deployer;
9
10
use Deployer\Collection\Collection;
11
use Deployer\Component\PharUpdate\Console\Command as PharUpdateCommand;
12
use Deployer\Component\PharUpdate\Console\Helper as PharUpdateHelper;
13
use Deployer\Component\ProcessRunner\Printer;
14
use Deployer\Component\ProcessRunner\ProcessRunner;
15
use Deployer\Component\Ssh\Client;
16
use Deployer\Configuration\Configuration;
17
use Deployer\Console\CommandEvent;
18
use Deployer\Console\DiceCommand;
19
use Deployer\Console\InitCommand;
20
use Deployer\Console\MainCommand;
21
use Deployer\Console\RunCommand;
22
use Deployer\Console\SshCommand;
23
use Deployer\Console\TreeCommand;
24
use Deployer\Console\WorkerCommand;
25
use Deployer\Executor\Messenger;
26
use Deployer\Executor\Master;
27
use Deployer\Executor\Server;
28
use Deployer\Logger\Handler\FileHandler;
29
use Deployer\Logger\Handler\NullHandler;
30
use Deployer\Logger\Logger;
31
use Deployer\Selector\Selector;
32
use Deployer\Task;
33
use Deployer\Utility\Httpie;
34
use Deployer\Utility\Reporter;
35
use Deployer\Utility\Rsync;
36
use Pimple\Container;
37
use Symfony\Component\Console;
38
use Symfony\Component\Console\Application;
39
use Symfony\Component\Console\Input\ArgvInput;
40
use Symfony\Component\Console\Input\InputDefinition;
41
use Symfony\Component\Console\Input\InputInterface;
42
use Symfony\Component\Console\Input\InputOption;
43
use Symfony\Component\Console\Output\ConsoleOutput;
44
use Symfony\Component\Console\Output\OutputInterface;
45
use Throwable;
46
47
/**
48
 * Deployer class represents DI container for configuring
49
 *
50
 * @property Application $console
51
 * @property InputInterface $input
52
 * @property OutputInterface $output
53
 * @property Task\TaskCollection|Task\Task[] $tasks
54
 * @property Host\HostCollection|Collection|Host\Host[] $hosts
55
 * @property Configuration $config
56
 * @property Rsync $rsync
57
 * @property Client $sshClient
58
 * @property ProcessRunner $processRunner
59
 * @property Task\ScriptManager $scriptManager
60
 * @property Selector $selector
61
 * @property Master $master
62
 * @property Messenger $messenger
63
 * @property Messenger $logger
64
 * @property Printer $pop
65
 * @property Collection $fail
66
 * @property InputDefinition $inputDefinition
67
 */
68
class Deployer extends Container
69
{
70
    /**
71
     * Global instance of deployer. It's can be accessed only after constructor call.
72
     * @var Deployer
73
     */
74
    private static $instance;
75
76 19
    public function __construct(Application $console)
77
    {
78 19
        parent::__construct();
79
80
        /******************************
81
         *           Console          *
82
         ******************************/
83
84 19
        $console->getDefinition()->addOption(
85 19
            new InputOption('--file', '-f', InputOption::VALUE_OPTIONAL, 'Specify Deployer file')
86
        );
87
88
        $this['console'] = function () use ($console) {
89 11
            return $console;
90
        };
91
        $this['input'] = function () {
92
            throw new \RuntimeException('Uninitialized "input" in Deployer container.');
93
        };
94
        $this['output'] = function () {
95
            throw new \RuntimeException('Uninitialized "output" in Deployer container.');
96
        };
97
        $this['inputDefinition'] = function () {
98 11
            return new InputDefinition();
99
        };
100
        $this['questionHelper'] = function () {
101 10
            return $this->getHelper('question');
102
        };
103
104
        /******************************
105
         *           Config           *
106
         ******************************/
107
108
        $this['config'] = function () {
109 19
            return new Configuration();
110
        };
111 19
        $this->config['shell'] = 'bash -s';
112 19
        $this->config['port'] = '';
113 19
        $this->config['config_file'] = '';
114 19
        $this->config['identity_file'] = '';
115 19
        $this->config['remote_user'] = '';
116 19
        $this->config['forward_agent'] = true;
117 19
        $this->config['ssh_multiplexing'] = true;
118
119
        /******************************
120
         *            Core            *
121
         ******************************/
122
123
        $this['pop'] = function ($c) {
124 12
            return new Printer($c['output']);
125
        };
126
        $this['sshClient'] = function ($c) {
127 10
            return new Client($c['output'], $c['pop'], $c['logger']);
128
        };
129
        $this['rsync'] = function ($c) {
130
            return new Rsync($c['pop'], $c['output']);
131
        };
132
        $this['processRunner'] = function ($c) {
133 11
            return new ProcessRunner($c['pop'], $c['logger']);
134
        };
135
        $this['tasks'] = function () {
136 19
            return new Task\TaskCollection();
137
        };
138
        $this['hosts'] = function () {
139 13
            return new Host\HostCollection();
140
        };
141
        $this['scriptManager'] = function ($c) {
142 12
            return new Task\ScriptManager($c['tasks']);
143
        };
144
        $this['selector'] = function ($c) {
145 9
            return new Selector($c['hosts']);
146
        };
147
        $this['fail'] = function () {
148 11
            return new Collection();
149
        };
150
        $this['messenger'] = function ($c) {
151 10
            return new Messenger($c['input'], $c['output']);
152
        };
153
        $this['server'] = function ($c) {
154 10
            return new Server(
155 10
                $c['input'],
156 10
                $c['output'],
157 10
                $c['questionHelper'],
158
            );
0 ignored issues
show
Bug introduced by
This code did not parse for me. Apparently, there is an error somewhere around this line:

Syntax error, unexpected ')'
Loading history...
159
        };
160
        $this['master'] = function ($c) {
161 10
            return new Master(
162 10
                $c['input'],
163 10
                $c['output'],
164 10
                $c['server'],
165 10
                $c['messenger'],
166 10
                $c['sshClient'],
167 10
                $c['config']
168
            );
169
        };
170
171
        /******************************
172
         *           Logger           *
173
         ******************************/
174
175
        $this['log_handler'] = function () {
176 12
            return !empty($this->config['log_file'])
177
                ? new FileHandler($this->config['log_file'])
178 12
                : new NullHandler();
179
        };
180
        $this['logger'] = function () {
181 12
            return new Logger($this['log_handler']);
182
        };
183
184 19
        self::$instance = $this;
185
186
        task('connect', function () {
187
            $this['sshClient']->connect(currentHost());
188 19
        })->desc('Connect to remote server');
189 19
    }
190
191
    /**
192
     * @return Deployer
193
     */
194 28
    public static function get()
195
    {
196 28
        return self::$instance;
197
    }
198
199
    /**
200
     * Init console application
201
     */
202 11
    public function init()
203
    {
204 11
        $this->addTaskCommands();
205 11
        $this->getConsole()->add(new WorkerCommand($this));
206 11
        $this->getConsole()->add(new DiceCommand());
207 11
        $this->getConsole()->add(new InitCommand());
208 11
        $this->getConsole()->add(new TreeCommand($this));
209 11
        $this->getConsole()->add(new SshCommand($this));
210 11
        $this->getConsole()->add(new RunCommand($this));
211 11
        if (self::isPharArchive()) {
212
            $selfUpdate = new PharUpdateCommand('self-update');
213
            $selfUpdate->setDescription('Updates deployer.phar to the latest version');
214
            $selfUpdate->setManifestUri('https://deployer.org/manifest.json');
215
            $this->getConsole()->add($selfUpdate);
216
            $this->getConsole()->getHelperSet()->set(new PharUpdateHelper());
217
        }
218 11
    }
219
220
    /**
221
     * Transform tasks to console commands.
222
     */
223 11
    public function addTaskCommands()
224
    {
225 11
        foreach ($this->tasks as $name => $task) {
226 11
            $command = new MainCommand($name, $task->getDescription(), $this);
227 11
            $command->setHidden($task->isHidden());
228
229 11
            $this->getConsole()->add($command);
230
        }
231 11
    }
232
233
    /**
234
     * @param string $name
235
     * @return mixed
236
     * @throws \InvalidArgumentException
237
     */
238 26
    public function __get($name)
239
    {
240 26
        if (isset($this[$name])) {
241 26
            return $this[$name];
242
        } else {
243
            throw new \InvalidArgumentException("Property \"$name\" does not exist.");
244
        }
245
    }
246
247
    /**
248
     * @param string $name
249
     * @param mixed $value
250
     */
251 10
    public function __set($name, $value)
252
    {
253 10
        $this[$name] = $value;
254 10
    }
255
256
    /**
257
     * @return Application
258
     */
259 11
    public function getConsole()
260
    {
261 11
        return $this['console'];
262
    }
263
264
    /**
265
     * @param string $name
266
     * @return Console\Helper\HelperInterface
267
     */
268 10
    public function getHelper($name)
269
    {
270 10
        return $this->getConsole()->getHelperSet()->get($name);
271
    }
272
273
    /**
274
     * Run Deployer
275
     *
276
     * @param string $version
277
     * @param string $deployFile
278
     */
279
    public static function run($version, $deployFile)
280
    {
281
        $input = new ArgvInput();
282
        $output = new ConsoleOutput();
283
284
        try {
285
            // Init Deployer
286
            $console = new Application('Deployer', $version);
287
            $deployer = new self($console);
288
289
            // Require deploy.php file
290
            self::load($deployFile);
291
292
            // Run Deployer
293
            $deployer->init();
294
            $console->run($input, $output);
295
296
        } catch (Throwable $exception) {
297
            self::printException($output, $exception);
298
        }
299
    }
300
301 11
    public static function load(string $deployFile)
302
    {
303 11
        if (is_readable($deployFile)) {
304
            // Prevent variable leak into deploy.php file
305
            call_user_func(function () use ($deployFile) {
306
                // Reorder autoload stack
307 11
                $originStack = spl_autoload_functions();
308
309 11
                require $deployFile;
310
311 11
                $newStack = spl_autoload_functions();
312 11
                if ($originStack[0] !== $newStack[0]) {
313
                    foreach (array_reverse($originStack) as $loader) {
314
                        spl_autoload_unregister($loader);
315
                        spl_autoload_register($loader, true, true);
316
                    }
317
                }
318 11
            });
319
        }
320 11
    }
321
322
    public static function printException(OutputInterface $output, Throwable $exception)
323
    {
324
        $class = get_class($exception);
325
        $file = basename($exception->getFile());
326
        $output->writeln([
327
            "<fg=white;bg=red> {$class} </> <comment>in {$file} on line {$exception->getLine()}:</>",
328
            "",
329
            implode("\n", array_map(function ($line) {
330
                return "  " . $line;
331
            }, explode("\n", $exception->getMessage()))),
332
            "",
333
        ]);
334
        if ($output->isDebug()) {
335
            $output->writeln($exception->getTraceAsString());
336
        }
337
    }
338
339
    public static function isWorker() {
340
        return Deployer::get()->config->has('master_url');
341
    }
342
343
    public static function proxyCallToMaster($func, ...$arguments) {
344
        return Httpie::get(get('master_url') . '/proxy')
345
            ->setopt(CURLOPT_TIMEOUT, 0) // no timeout
346
            ->body([
347
                'host' => currentHost()->getAlias(),
348
                'func' => $func,
349
                'arguments' => $arguments,
350
            ])
351
            ->getJson();
352
    }
353
354
    /**
355
     * Collect anonymous stats about Deployer usage for improving developer experience.
356
     * If you are not comfortable with this, you will always be able to disable this
357
     * by setting `allow_anonymous_stats` to false in your deploy.php file.
358
     *
359
     * @param CommandEvent $commandEvent
360
     * @codeCoverageIgnore
361
     */
362
    public function collectAnonymousStats(CommandEvent $commandEvent)
363
    {
364
        if ($this->config->has('allow_anonymous_stats') && $this->config['allow_anonymous_stats'] === false) {
365
            return;
366
        }
367
368
        $stats = [
369
            'status' => 'success',
370
            'command_name' => $commandEvent->getCommand()->getName(),
371
            'project_hash' => empty($this->config['repository']) ? null : sha1($this->config['repository']),
372
            'hosts_count' => $this->hosts->count(),
373
            'deployer_version' => $this->getConsole()->getVersion(),
374
            'deployer_phar' => self::isPharArchive(),
375
            'php_version' => phpversion(),
376
            'extension_pcntl' => extension_loaded('pcntl'),
377
            'extension_curl' => extension_loaded('curl'),
378
            'os' => defined('PHP_OS_FAMILY') ? PHP_OS_FAMILY : (stristr(PHP_OS, 'DAR') ? 'OSX' : (stristr(PHP_OS, 'WIN') ? 'WIN' : (stristr(PHP_OS, 'LINUX') ? 'LINUX' : PHP_OS))),
379
            'exception' => null,
380
        ];
381
382
        if ($commandEvent->getException() !== null) {
383
            $stats['status'] = 'error';
384
            $stats['exception'] = get_class($commandEvent->getException());
385
        }
386
387
        if ($stats['command_name'] === 'init') {
388
            $stats['allow_anonymous_stats'] = $GLOBALS['allow_anonymous_stats'] ?? false;
389
        }
390
391
        if (in_array($stats['command_name'], ['worker', 'list', 'help'], true)) {
392
            return;
393
        }
394
395
        Reporter::report($stats);
396
    }
397
398 11
    public static function isPharArchive()
399
    {
400 11
        return 'phar:' === substr(__FILE__, 0, 5);
401
    }
402
}
403