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.
Passed
Push — master ( b3cd52...71bd8a )
by Anton
02:19
created

functions.php ➔ roles()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
cc 1
nc 1
nop 1
dl 0
loc 4
ccs 0
cts 1
cp 0
crap 2
rs 10
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\Exception\Exception;
11
use Deployer\Exception\GracefulShutdownException;
12
use Deployer\Exception\RunException;
13
use Deployer\Host\FileLoader;
14
use Deployer\Host\Host;
15
use Deployer\Host\Localhost;
16
use Deployer\Host\Range;
17
use Deployer\Support\Proxy;
18
use Deployer\Task\Context;
19
use Deployer\Task\GroupTask;
20
use Deployer\Task\Task as T;
21
use Symfony\Component\Console\Exception\MissingInputException;
22
use Symfony\Component\Console\Helper\QuestionHelper;
23
use Symfony\Component\Console\Input\InputInterface;
24
use Symfony\Component\Console\Input\InputOption;
25
use Symfony\Component\Console\Output\OutputInterface;
26
use Symfony\Component\Console\Question\ChoiceQuestion;
27
use Symfony\Component\Console\Question\ConfirmationQuestion;
28
use Symfony\Component\Console\Question\Question;
29
use function Deployer\Support\array_to_string;
30
31
/**
32
 * @param string|array ...$hostname
33
 * @return Host|Host[]|Proxy
34
 */
35
function host(...$hostname)
36
{
37 1
    $deployer = Deployer::get();
38 1
    $aliases = Range::expand($hostname);
39
40 1
    foreach ($aliases as $alias) {
41 1
        if ($deployer->hosts->has($alias)) {
42
            $host = $deployer->hosts->get($alias);
43
            throw new \InvalidArgumentException(
44
                "Host \"{$host->tag()}\" already exists.\n" .
45
                "If you want to override configuration options, get host with <fg=yellow>getHost</> function.\n" .
46
                "\n" .
47
                "    <fg=yellow>getHost</>(<fg=green>'{$alias}'</>);" .
48
                "\n"
49
            );
50
        }
51
    }
52
53 1
    if (count($aliases) === 1) {
54 1
        $host = new Host($aliases[0]);
55 1
        $deployer->hosts->set($aliases[0], $host);
56 1
        return $host;
57
    } else {
58
        $hosts = array_map(function ($hostname) use ($deployer) {
59 1
            $host = new Host($hostname);
60 1
            $deployer->hosts->set($hostname, $host);
61 1
            return $host;
62 1
        }, $aliases);
63 1
        return new Proxy($hosts);
64
    }
65
}
66
67
/**
68
 * Get host by host alias.
69
 *
70
 * @param string $alias
71
 * @return Host
72
 */
73
function getHost(string $alias) {
74 1
    return Deployer::get()->hosts->get($alias);
75
}
76
77
/**
78
 * Get current host.
79
 *
80
 * @return Host
81
 */
82
function currentHost()
83
{
84
    return Context::get()->getHost();
85
}
86
87
/**
88
 * @param array ...$hostnames
89
 * @return Localhost|Localhost[]|Proxy
90
 */
91
function localhost(...$hostnames)
92
{
93 2
    $deployer = Deployer::get();
94 2
    $hostnames = Range::expand($hostnames);
95
96 2
    if (count($hostnames) <= 1) {
97 2
        $host = count($hostnames) === 1 ? new Localhost($hostnames[0]) : new Localhost();
98 2
        $deployer->hosts->set($host->alias(), $host);
99 2
        return $host;
100
    } else {
101
        $hosts = array_map(function ($hostname) use ($deployer) {
102
            $host = new Localhost($hostname);
103
            $deployer->hosts->set($host->alias(), $host);
104
            return $host;
105
        }, $hostnames);
106
        return new Proxy($hosts);
107
    }
108
}
109
110
/**
111
 * Load list of hosts from file
112
 *
113
 * @param string $file
114
 * @return Proxy
115
 */
116
function inventory($file)
117
{
118
    $deployer = Deployer::get();
119
    $fileLoader = new FileLoader();
120
    $fileLoader->load($file);
121
122
    $hosts = $fileLoader->getHosts();
123
    foreach ($hosts as $host) {
124
        $deployer->hosts->set($host->alias(), $host);
125
    }
126
127
    return new Proxy($hosts);
128
}
129
130
/**
131
 * Set task description.
132
 *
133
 * @param string $title
134
 * @return string
135
 */
136
function desc($title = null)
137
{
138 10
    static $store = null;
139
140 10
    if ($title === null) {
141 10
        return $store;
142
    } else {
143
        return $store = $title;
144
    }
145
}
146
147
/**
148
 * Define a new task and save to tasks list.
149
 *
150
 * Alternatively get a defined task.
151
 *
152
 * @param string $name Name of current task.
153
 * @param callable|array|string|null $body Callable task, array of other tasks names or nothing to get a defined tasks
154
 * @return Task\Task
155
 */
156
function task($name, $body = null)
157
{
158 10
    $deployer = Deployer::get();
159
160 10
    if (empty($body)) {
161 1
        return $deployer->tasks->get($name);
162
    }
163
164 10
    if (is_callable($body)) {
165 10
        $task = new T($name, $body);
166 1
    } elseif (is_array($body)) {
167 1
        $task = new GroupTask($name, $body);
168
    } else {
169
        throw new \InvalidArgumentException('Task should be a closure or array of other tasks.');
170
    }
171
172 10
    $task->saveSourceLocation();
173 10
    $deployer->tasks->set($name, $task);
174
175 10
    if (!empty(desc())) {
176
        $task->desc(desc());
177
        desc(''); // Clear title.
178
    }
179
180 10
    return $task;
181
}
182
183
/**
184
 * Call that task before specified task runs.
185
 *
186
 * @param string $it The task before $that should be run.
187
 * @param string $that The task to be run.
188
 */
189
function before($it, $that)
190
{
191 1
    $deployer = Deployer::get();
192 1
    $beforeTask = $deployer->tasks->get($it);
193
194 1
    $beforeTask->addBefore($that);
195 1
}
196
197
/**
198
 * Call that task after specified task runs.
199
 *
200
 * @param string $it The task after $that should be run.
201
 * @param string $that The task to be run.
202
 */
203
function after($it, $that)
204
{
205 1
    $deployer = Deployer::get();
206 1
    $afterTask = $deployer->tasks->get($it);
207
208 1
    $afterTask->addAfter($that);
209 1
}
210
211
/**
212
 * Setup which task run on failure of first.
213
 *
214
 * @param string $it The task which need to fail so $that should be run.
215
 * @param string $that The task to be run.
216
 */
217
function fail($it, $that)
218
{
219
    $deployer = Deployer::get();
220
    $deployer->fail->set($it, $that);
221
}
222
223
/**
224
 * Add users options.
225
 *
226
 * @param string $name The option name
227
 * @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
228
 * @param int|null $mode The option mode: One of the VALUE_* constants
229
 * @param string $description A description text
230
 * @param string|string[]|int|bool|null $default The default value (must be null for self::VALUE_NONE)
231
 */
232
function option($name, $shortcut = null, $mode = null, $description = '', $default = null)
233
{
234
    Deployer::get()->inputDefinition->addOption(
235
        new InputOption($name, $shortcut, $mode, $description, $default)
236
    );
237
}
238
239
/**
240
 * Change the current working directory.
241
 *
242
 * @param string $path
243
 */
244
function cd($path)
245
{
246
    set('working_path', parse($path));
247
}
248
249
/**
250
 * Execute a callback within a specific directory and revert back to the initial working directory.
251
 *
252
 * @param string $path
253
 * @param callable $callback
254
 */
255
function within($path, $callback)
256
{
257
    $lastWorkingPath = get('working_path', '');
258
    try {
259
        set('working_path', parse($path));
260
        $callback();
261
    } finally {
262
        set('working_path', $lastWorkingPath);
263
    }
264
}
265
266
/**
267
 * Run command.
268
 *
269
 * @param string $command
270
 * @param array $options
271
 * @return string
272
 */
273
function run($command, $options = [])
274
{
275
    $run = function ($command, $options) {
276
        $host = Context::get()->getHost();
277
278
        $command = parse($command);
279
        $workingPath = get('working_path', '');
280
281
        if (!empty($workingPath)) {
282
            $command = "cd $workingPath && ($command)";
283
        }
284
285
        $env = get('env', []) + ($options['env'] ?? []);
286
        if (!empty($env)) {
287
            $env = array_to_string($env);
288
            $command = "export $env; $command";
289
        }
290
291
        if ($host instanceof Localhost) {
292
            $process = Deployer::get()->processRunner;
293
            $output = $process->run($host, $command, $options);
294
        } else {
295
            $client = Deployer::get()->sshClient;
296
            $output = $client->run($host, $command, $options);
297
        }
298
299
        return rtrim($output);
300
    };
301
302
    if (preg_match('/^sudo\b/', $command)) {
303
        try {
304
            return $run($command, $options);
305
        } catch (RunException $exception) {
306
            $askpass = get('sudo_askpass', '/tmp/dep_sudo_pass');
307
            $password = get('sudo_pass', false);
308
            if ($password === false) {
309
                writeln("<fg=green;options=bold>run</> $command");
310
                $password = askHiddenResponse('Password:');
311
            }
312
            $run("echo -e '#!/bin/sh\necho \"%secret%\"' > $askpass", array_merge($options, ['secret' => $password]));
313
            $run("chmod a+x $askpass", $options);
314
            $run(sprintf('export SUDO_ASKPASS=%s; %s', $askpass, preg_replace('/^sudo\b/', 'sudo -A', $command)), $options);
315
            $run("rm $askpass", $options);
316
        }
317
    } else {
318
        return $run($command, $options);
319
    }
320
}
321
322
323
/**
324
 * Execute commands on local machine
325
 *
326
 * @param string $command Command to run locally.
327
 * @param array $options
328
 * @return string Output of command.
329
 */
330
function runLocally($command, $options = [])
331
{
332 1
    $process = Deployer::get()->processRunner;
333 1
    $command = parse($command);
334
335 1
    $env = get('env', []) + ($options['env'] ?? []);
336 1
    if (!empty($env)) {
337
        $env = array_to_string($env);
338
        $command = "export $env; $command";
339
    }
340
341 1
    $output = $process->run(localhost(), $command, $options);
342
343 1
    return rtrim($output);
344
}
345
346
/**
347
 * Run test command.
348
 * Example:
349
 *
350
 *     test('[ -d {{release_path}} ]')
351
 *
352
 * @param string $command
353
 * @return bool
354
 */
355
function test($command)
356
{
357
    return run("if $command; then echo 'true'; fi") === 'true';
358
}
359
360
/**
361
 * Run test command locally.
362
 * Example:
363
 *
364
 *     testLocally('[ -d {{local_release_path}} ]')
365
 *
366
 * @param string $command
367
 * @return bool
368
 */
369
function testLocally($command)
370
{
371
    return runLocally("if $command; then echo 'true'; fi") === 'true';
372
}
373
374
/**
375
 * Iterate other hosts, allowing to call run func in callback.
376
 *
377
 * @experimental
378
 * @param Host|Host[] $hosts
379
 * @param callable $callback
380
 */
381
function on($hosts, callable $callback)
382
{
383
    $deployer = Deployer::get();
384
385
    if (!is_array($hosts) && !($hosts instanceof \Traversable)) {
386
        $hosts = [$hosts];
387
    }
388
389
    foreach ($hosts as $host) {
390
        if ($host instanceof Host) {
391
            $host->getConfig()->load();
392
            Context::push(new Context($host, input(), output()));
393
            try {
394
                $callback($host);
395
                $host->getConfig()->save();
396
            } catch (GracefulShutdownException $e) {
397
                $deployer->messenger->renderException($e, $host);
398
            } finally {
399
                Context::pop();
400
            }
401
        } else {
402
            throw new \InvalidArgumentException("Function on can iterate only on Host instances.");
403
        }
404
    }
405
}
406
407
/**
408
 * Run task
409
 *
410
 * @experimental
411
 * @param string $task
412
 */
413
function invoke($task)
414
{
415
    $hosts = [Context::get()->getHost()];
416
    $tasks = Deployer::get()->scriptManager->getTasks($task, $hosts);
0 ignored issues
show
Unused Code introduced by
The call to ScriptManager::getTasks() has too many arguments starting with $hosts.

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...
417
418
    $executor = Deployer::get()->seriesExecutor;
0 ignored issues
show
Bug introduced by
The property seriesExecutor does not seem to exist. Did you mean executor?

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
419
    $executor->run($tasks, $hosts);
420
}
421
422
/*
423
 * Upload file or directory to host.
424
 */
425 View Code Duplication
function upload(string $source, string $destination, $config = [])
0 ignored issues
show
Duplication introduced by
This function 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...
426
{
427
    $rsync = Deployer::get()->rsync;
428
    $host = currentHost();
429
    $source = parse($source);
430
    $destination = parse($destination);
431
432
    if ($host instanceof Localhost) {
433
        $rsync->call($host, $source, $destination, $config);
434
    } else {
435
        $rsync->call($host, $source, "{$host->hostname()}:$destination", $config);
436
    }
437
}
438
439
/*
440
 * Download file or directory from host
441
 */
442 View Code Duplication
function download(string $source, string $destination, $config = [])
0 ignored issues
show
Duplication introduced by
This function 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...
443
{
444
    $rsync = Deployer::get()->rsync;
445
    $host = currentHost();
446
    $source = parse($source);
447
    $destination = parse($destination);
448
449
    if ($host instanceof Localhost) {
450
        $rsync->call($host, $source, $destination, $config);
451
    } else {
452
        $rsync->call($host, "{$host->hostname()}:$source", $destination, $config);
453
    }
454
}
455
456
/**
457
 * Writes an info message.
458
 * @param string $message
459
 */
460
function info($message)
461
{
462
    output()->writeln("<fg=green;options=bold>info</> " . parse($message));
463
}
464
465
/**
466
 * Writes an warning message.
467
 * @param string $message
468
 */
469
function warning($message)
470
{
471
    writeln("<fg=yellow;options=bold>warning</> <comment>" . parse($message) . "</comment>");
472
}
473
474
/**
475
 * Writes a message to the output and adds a newline at the end.
476
 * @param string|array $message
477
 * @param int $options
478
 */
479
function writeln($message, $options = 0)
480
{
481
    $host = currentHost();
482
    output()->writeln("[{$host->tag()}] " . parse($message), $options);
483
}
484
485
/**
486
 * Writes a message to the output.
487
 * @param string $message
488
 * @param int $options
489
 */
490
function write($message, $options = 0)
491
{
492
    output()->write(parse($message), $options);
493
}
494
495
/**
496
 * Setup configuration option.
497
 *
498
 * @param string $name
499
 * @param mixed $value
500
 */
501 View Code Duplication
function set($name, $value)
0 ignored issues
show
Duplication introduced by
This function 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...
502
{
503
    if (!Context::has()) {
504
        Deployer::get()->config->set($name, $value);
505
    } else {
506
        Context::get()->getConfig()->set($name, $value);
507
    }
508
}
509
510
/**
511
 * Merge new config params to existing config array.
512
 *
513
 * @param string $name
514
 * @param array $array
515
 */
516 View Code Duplication
function add($name, $array)
0 ignored issues
show
Duplication introduced by
This function 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...
517
{
518
    if (!Context::has()) {
519
        Deployer::get()->config->add($name, $array);
520
    } else {
521
        Context::get()->getConfig()->add($name, $array);
522
    }
523
}
524
525
/**
526
 * Get configuration value.
527
 *
528
 * @param string $name
529
 * @param mixed|null $default
530
 * @return mixed
531
 */
532 View Code Duplication
function get($name, $default = null)
0 ignored issues
show
Duplication introduced by
This function 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...
533
{
534 1
    if (!Context::has()) {
535
        return Deployer::get()->config->get($name, $default);
536
    } else {
537 1
        return Context::get()->getConfig()->get($name, $default);
538
    }
539
}
540
541
/**
542
 * Check if there is such configuration option.
543
 *
544
 * @param string $name
545
 * @return boolean
546
 */
547 View Code Duplication
function has($name)
0 ignored issues
show
Duplication introduced by
This function 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...
548
{
549
    if (!Context::has()) {
550
        return Deployer::get()->config->has($name);
551
    } else {
552
        return Context::get()->getConfig()->has($name);
553
    }
554
}
555
556
/**
557
 * @param string $message
558
 * @param string|null $default
559
 * @param string[]|null $autocomplete
560
 * @return string
561
 */
562
function ask($message, $default = null, $autocomplete = null)
563
{
564
    Context::required(__FUNCTION__);
565
566
    if (output()->isQuiet()) {
567
        return $default;
568
    }
569
570
    /** @var QuestionHelper $helper */
571
    $helper = Deployer::get()->getHelper('question');
572
573
    $tag = currentHost()->tag();
574
    $message = "[$tag] <question>$message</question> " . (($default === null) ? "" : "(default: $default) ");
575
576
    $question = new Question($message, $default);
577
    if (!empty($autocomplete)) {
578
        $question->setAutocompleterValues($autocomplete);
579
    }
580
581
    try {
582
        return $helper->ask(input(), output(), $question);
583
    } catch (MissingInputException $exception) {
584
        throw new Exception("Failed to read input from stdin.\nMake sure what you are asking for input not from parallel task.", $exception->getCode(), $exception);
585
    }
586
}
587
588
/**
589
 * @param string $message
590
 * @param string[] $availableChoices
591
 * @param string|null $default
592
 * @param bool|false $multiselect
593
 * @return string|string[]
594
 */
595
function askChoice($message, array $availableChoices, $default = null, $multiselect = false)
596
{
597
    Context::required(__FUNCTION__);
598
599
    if (empty($availableChoices)) {
600
        throw new \InvalidArgumentException('Available choices should not be empty');
601
    }
602
603
    if ($default !== null && !array_key_exists($default, $availableChoices)) {
604
        throw new \InvalidArgumentException('Default choice is not available');
605
    }
606
607
    if (output()->isQuiet()) {
608
        if ($default === null) {
609
            $default = key($availableChoices);
610
        }
611
        return [$default => $availableChoices[$default]];
612
    }
613
614
    $helper = Deployer::get()->getHelper('question');
615
616
    $tag = currentHost()->tag();
617
    $message = "[$tag] <question>$message</question> " . (($default === null) ? "" : "(default: $default) ");
618
619
    $question = new ChoiceQuestion($message, $availableChoices, $default);
620
    $question->setMultiselect($multiselect);
621
622
    return $helper->ask(input(), output(), $question);
623
}
624
625
/**
626
 * @param string $message
627
 * @param bool $default
628
 * @return bool
629
 */
630
function askConfirmation($message, $default = false)
631
{
632
    Context::required(__FUNCTION__);
633
634
    if (output()->isQuiet()) {
635
        return $default;
636
    }
637
638
    $helper = Deployer::get()->getHelper('question');
639
640
    $yesOrNo = $default ? 'Y/n' : 'y/N';
641
    $tag = currentHost()->tag();
642
    $message = "[$tag] <question>$message</question> [$yesOrNo] ";
643
644
    $question = new ConfirmationQuestion($message, $default);
645
646
    return $helper->ask(input(), output(), $question);
647
}
648
649
/**
650
 * @param string $message
651
 * @return string
652
 */
653
function askHiddenResponse($message)
654
{
655
    Context::required(__FUNCTION__);
656
657
    if (output()->isQuiet()) {
658
        return '';
659
    }
660
661
    $helper = Deployer::get()->getHelper('question');
662
663
    $tag = currentHost()->tag();
664
    $message = "[$tag] <question>$message</question> ";
665
666
    $question = new Question($message);
667
    $question->setHidden(true);
668
    $question->setHiddenFallback(false);
669
670
    return $helper->ask(input(), output(), $question);
671
}
672
673
/**
674
 * @return InputInterface
675
 */
676
function input()
677
{
678
    return Context::get()->getInput();
679
}
680
681
682
/**
683
 * @return OutputInterface
684
 */
685
function output()
686
{
687
    return Context::get()->getOutput();
688
}
689
690
/**
691
 * Check if command exists
692
 *
693
 * @param string $command
694
 * @return bool
695
 */
696
function commandExist($command)
697
{
698
    return test("hash $command 2>/dev/null");
699
}
700
701
function commandSupportsOption($command, $option)
702
{
703
    return test("[[ $(man $command 2>&1 || $command -h 2>&1 || $command --help 2>&1) =~ '$option' ]]");
704
}
705
706
/**
707
 * Parse set values.
708
 *
709
 * @param string $value
710
 * @return string
711
 */
712
function parse($value)
713
{
714 1
    return Context::get()->getConfig()->parse($value);
715
}
716
717
function locateBinaryPath($name)
718
{
719
    $nameEscaped = escapeshellarg($name);
720
721
    // Try `command`, should cover all Bourne-like shells
722
    // Try `which`, should cover most other cases
723
    // Fallback to `type` command, if the rest fails
724
    $path = run("command -v $nameEscaped || which $nameEscaped || type -p $nameEscaped");
725
    if ($path) {
726
        // Deal with issue when `type -p` outputs something like `type -ap` in some implementations
727
        return trim(str_replace("$name is", "", $path));
728
    }
729
730
    throw new \RuntimeException("Can't locate [$nameEscaped] - neither of [command|which|type] commands are available");
731
}
732