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 ( 09a43c...4f79d5 )
by Anton
03:00
created

functions.php ➔ desc()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 1
dl 0
loc 10
ccs 4
cts 4
cp 1
crap 2
rs 9.9332
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 ...$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
 * @param string ...$hostnames
69
 * @return Localhost|Localhost[]|Proxy
70
 */
71
function localhost(...$hostnames)
72
{
73 7
    $deployer = Deployer::get();
74 7
    $hostnames = Range::expand($hostnames);
75
76 7
    if (count($hostnames) <= 1) {
77 7
        $host = count($hostnames) === 1 ? new Localhost($hostnames[0]) : new Localhost();
78 7
        $deployer->hosts->set($host->alias(), $host);
79 7
        return $host;
80
    } else {
81
        $hosts = array_map(function ($hostname) use ($deployer) {
82
            $host = new Localhost($hostname);
83
            $deployer->hosts->set($host->alias(), $host);
84
            return $host;
85
        }, $hostnames);
86
        return new Proxy($hosts);
87
    }
88
}
89
90
/**
91
 * Get host by host alias.
92
 *
93
 * @param string $alias
94
 * @return Host
95
 */
96
function getHost(string $alias)
97
{
98 1
    return Deployer::get()->hosts->get($alias);
99
}
100
101
/**
102
 * Get current host.
103
 *
104
 * @return Host
105
 */
106
function currentHost()
107
{
108 5
    return Context::get()->getHost();
109
}
110
111
112
/**
113
 * Load list of hosts from file
114
 *
115
 * @param string $file
116
 * @return Proxy
117
 */
118
function inventory($file)
119
{
120
    $deployer = Deployer::get();
121
    $fileLoader = new FileLoader();
122
    $fileLoader->load($file);
123
124
    $hosts = $fileLoader->getHosts();
125
    foreach ($hosts as $host) {
126
        $deployer->hosts->set($host->alias(), $host);
127
    }
128
129
    return new Proxy($hosts);
130
}
131
132
/**
133
 * Set task description.
134
 *
135
 * @param string $title
136
 * @return string
137
 */
138
function desc($title = null)
139
{
140 16
    static $store = null;
141
142 16
    if ($title === null) {
143 16
        return $store;
144
    } else {
145 6
        return $store = $title;
146
    }
147
}
148
149
/**
150
 * Define a new task and save to tasks list.
151
 *
152
 * Alternatively get a defined task.
153
 *
154
 * @param string $name Name of current task.
155
 * @param callable|array|string|null $body Callable task, array of other tasks names or nothing to get a defined tasks
156
 * @return Task\Task
157
 */
158
function task($name, $body = null)
159
{
160 16
    $deployer = Deployer::get();
161
162 16
    if (empty($body)) {
163 1
        return $deployer->tasks->get($name);
164
    }
165
166 16
    if (is_callable($body)) {
167 16
        $task = new T($name, $body);
168 7
    } elseif (is_array($body)) {
169 7
        $task = new GroupTask($name, $body);
170
    } else {
171
        throw new \InvalidArgumentException('Task should be a closure or array of other tasks.');
172
    }
173
174 16
    $task->saveSourceLocation();
175 16
    $deployer->tasks->set($name, $task);
176
177 16
    if (!empty(desc())) {
178 6
        $task->desc(desc());
179 6
        desc(''); // Clear title.
180
    }
181
182 16
    return $task;
183
}
184
185
/**
186
 * Call that task before specified task runs.
187
 *
188
 * @param string $it The task before $that should be run.
189
 * @param string $that The task to be run.
190
 */
191
function before($it, $that)
192
{
193 1
    $deployer = Deployer::get();
194 1
    $beforeTask = $deployer->tasks->get($it);
195
196 1
    $beforeTask->addBefore($that);
197 1
}
198
199
/**
200
 * Call that task after specified task runs.
201
 *
202
 * @param string $it The task after $that should be run.
203
 * @param string $that The task to be run.
204
 */
205
function after($it, $that)
206
{
207 1
    $deployer = Deployer::get();
208 1
    $afterTask = $deployer->tasks->get($it);
209
210 1
    $afterTask->addAfter($that);
211 1
}
212
213
/**
214
 * Setup which task run on failure of first.
215
 *
216
 * @param string $it The task which need to fail so $that should be run.
217
 * @param string $that The task to be run.
218
 */
219
function fail($it, $that)
220
{
221 6
    $deployer = Deployer::get();
222 6
    $deployer->fail->set($it, $that);
223 6
}
224
225
/**
226
 * Add users options.
227
 *
228
 * @param string $name The option name
229
 * @param string|array|null $shortcut The shortcuts, can be null, a string of shortcuts delimited by | or an array of shortcuts
230
 * @param int|null $mode The option mode: One of the VALUE_* constants
231
 * @param string $description A description text
232
 * @param string|string[]|int|bool|null $default The default value (must be null for self::VALUE_NONE)
233
 */
234
function option($name, $shortcut = null, $mode = null, $description = '', $default = null)
235
{
236 6
    Deployer::get()->inputDefinition->addOption(
237 6
        new InputOption($name, $shortcut, $mode, $description, $default)
238
    );
239 6
}
240
241
/**
242
 * Change the current working directory.
243
 *
244
 * @param string $path
245
 */
246
function cd($path)
247
{
248 1
    set('working_path', parse($path));
249 1
}
250
251
/**
252
 * Execute a callback within a specific directory and revert back to the initial working directory.
253
 *
254
 * @param string $path
255
 * @param callable $callback
256
 */
257
function within($path, $callback)
258
{
259
    $lastWorkingPath = get('working_path', '');
260
    try {
261
        set('working_path', parse($path));
262
        $callback();
263
    } finally {
264
        set('working_path', $lastWorkingPath);
265
    }
266
}
267
268
/**
269
 * Run command.
270
 *
271
 * @param string $command
272
 * @param array $options
273
 * @return string
274
 */
275
function run($command, $options = [])
276
{
277
    $run = function ($command, $options) {
278 4
        $host = Context::get()->getHost();
279
280 4
        $command = parse($command);
281 4
        $workingPath = get('working_path', '');
282
283 4
        if (!empty($workingPath)) {
284 1
            $command = "cd $workingPath && ($command)";
285
        }
286
287 4
        $env = get('env', []) + ($options['env'] ?? []);
288 4
        if (!empty($env)) {
289
            $env = array_to_string($env);
290
            $command = "export $env; $command";
291
        }
292
293 4
        if ($host instanceof Localhost) {
294 4
            $process = Deployer::get()->processRunner;
295 4
            $output = $process->run($host, $command, $options);
296
        } else {
297
            $client = Deployer::get()->sshClient;
298
            $output = $client->run($host, $command, $options);
299
        }
300
301 4
        return rtrim($output);
302 4
    };
303
304 4
    if (preg_match('/^sudo\b/', $command)) {
305
        try {
306
            return $run($command, $options);
307
        } catch (RunException $exception) {
308
            $askpass = get('sudo_askpass', '/tmp/dep_sudo_pass');
309
            $password = get('sudo_pass', false);
310
            if ($password === false) {
311
                writeln("<fg=green;options=bold>run</> $command");
312
                $password = askHiddenResponse('Password:');
313
            }
314
            $run("echo -e '#!/bin/sh\necho \"%secret%\"' > $askpass", array_merge($options, ['secret' => $password]));
315
            $run("chmod a+x $askpass", $options);
316
            $run(sprintf('export SUDO_ASKPASS=%s; %s', $askpass, preg_replace('/^sudo\b/', 'sudo -A', $command)), $options);
317
            $run("rm $askpass", $options);
318
        }
319
    } else {
320 4
        return $run($command, $options);
321
    }
322
}
323
324
325
/**
326
 * Execute commands on local machine
327
 *
328
 * @param string $command Command to run locally.
329
 * @param array $options
330
 * @return string Output of command.
331
 */
332
function runLocally($command, $options = [])
333
{
334 5
    $process = Deployer::get()->processRunner;
335 5
    $command = parse($command);
336
337 5
    $env = get('env', []) + ($options['env'] ?? []);
338 5
    if (!empty($env)) {
339
        $env = array_to_string($env);
340
        $command = "export $env; $command";
341
    }
342
343 5
    $output = $process->run(new Localhost(), $command, $options);
344
345 5
    return rtrim($output);
346
}
347
348
/**
349
 * Run test command.
350
 * Example:
351
 *
352
 *     test('[ -d {{release_path}} ]')
353
 *
354
 * @param string $command
355
 * @return bool
356
 */
357
function test($command)
358
{
359 4
    return run("if $command; then echo 'true'; fi") === 'true';
360
}
361
362
/**
363
 * Run test command locally.
364
 * Example:
365
 *
366
 *     testLocally('[ -d {{local_release_path}} ]')
367
 *
368
 * @param string $command
369
 * @return bool
370
 */
371
function testLocally($command)
372
{
373
    return runLocally("if $command; then echo 'true'; fi") === 'true';
374
}
375
376
/**
377
 * Iterate other hosts, allowing to call run func in callback.
378
 *
379
 * @experimental
380
 * @param Host|Host[] $hosts
381
 * @param callable $callback
382
 */
383
function on($hosts, callable $callback)
384
{
385
    $deployer = Deployer::get();
386
387
    if (!is_array($hosts) && !($hosts instanceof \Traversable)) {
388
        $hosts = [$hosts];
389
    }
390
391
    foreach ($hosts as $host) {
392
        if ($host instanceof Host) {
393
            $host->getConfig()->load();
394
            Context::push(new Context($host, input(), output()));
395
            try {
396
                $callback($host);
397
                $host->getConfig()->save();
398
            } catch (GracefulShutdownException $e) {
399
                $deployer->messenger->renderException($e, $host);
400
            } finally {
401
                Context::pop();
402
            }
403
        } else {
404
            throw new \InvalidArgumentException("Function on can iterate only on Host instances.");
405
        }
406
    }
407
}
408
409
/**
410
 * Run task
411
 *
412
 * @experimental
413
 * @param string $task
414
 */
415
function invoke($task)
416
{
417
    $hosts = [Context::get()->getHost()];
418
    $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...
419
420
    $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...
421
    $executor->run($tasks, $hosts);
422
}
423
424
/*
425
 * Upload file or directory to host.
426
 */
427 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...
428
{
429
    $rsync = Deployer::get()->rsync;
430
    $host = currentHost();
431
    $source = parse($source);
432
    $destination = parse($destination);
433
434
    if ($host instanceof Localhost) {
435
        $rsync->call($host, $source, $destination, $config);
436
    } else {
437
        $rsync->call($host, $source, "{$host->hostname()}:$destination", $config);
438
    }
439
}
440
441
/*
442
 * Download file or directory from host
443
 */
444 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...
445
{
446
    $rsync = Deployer::get()->rsync;
447
    $host = currentHost();
448
    $source = parse($source);
449
    $destination = parse($destination);
450
451
    if ($host instanceof Localhost) {
452
        $rsync->call($host, $source, $destination, $config);
453
    } else {
454
        $rsync->call($host, "{$host->hostname()}:$source", $destination, $config);
455
    }
456
}
457
458
/**
459
 * Writes an info message.
460
 * @param string $message
461
 */
462
function info($message)
463
{
464 5
    output()->writeln("<fg=green;options=bold>info</> " . parse($message));
465 5
}
466
467
/**
468
 * Writes an warning message.
469
 * @param string $message
470
 */
471
function warning($message)
472
{
473
    writeln("<fg=yellow;options=bold>warning</> <comment>" . parse($message) . "</comment>");
474
}
475
476
/**
477
 * Writes a message to the output and adds a newline at the end.
478
 * @param string|array $message
479
 * @param int $options
480
 */
481
function writeln($message, $options = 0)
482
{
483
    $host = currentHost();
484
    output()->writeln("[{$host->tag()}] " . parse($message), $options);
485
}
486
487
/**
488
 * Writes a message to the output.
489
 * @param string $message
490
 * @param int $options
491
 */
492
function write($message, $options = 0)
493
{
494
    output()->write(parse($message), $options);
495
}
496
497
/**
498
 * Setup configuration option.
499
 *
500
 * @param string $name
501
 * @param mixed $value
502
 */
503 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...
504
{
505 6
    if (!Context::has()) {
506 6
        Deployer::get()->config->set($name, $value);
507
    } else {
508 1
        Context::get()->getConfig()->set($name, $value);
509
    }
510 6
}
511
512
/**
513
 * Merge new config params to existing config array.
514
 *
515
 * @param string $name
516
 * @param array $array
517
 */
518 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...
519
{
520
    if (!Context::has()) {
521
        Deployer::get()->config->add($name, $array);
522
    } else {
523
        Context::get()->getConfig()->add($name, $array);
524
    }
525
}
526
527
/**
528
 * Get configuration value.
529
 *
530
 * @param string $name
531
 * @param mixed|null $default
532
 * @return mixed
533
 */
534 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...
535
{
536 5
    if (!Context::has()) {
537
        return Deployer::get()->config->get($name, $default);
538
    } else {
539 5
        return Context::get()->getConfig()->get($name, $default);
540
    }
541
}
542
543
/**
544
 * Check if there is such configuration option.
545
 *
546
 * @param string $name
547
 * @return boolean
548
 */
549 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...
550
{
551 1
    if (!Context::has()) {
552
        return Deployer::get()->config->has($name);
553
    } else {
554 1
        return Context::get()->getConfig()->has($name);
555
    }
556
}
557
558
/**
559
 * @param string $message
560
 * @param string|null $default
561
 * @param string[]|null $autocomplete
562
 * @return string
563
 */
564
function ask($message, $default = null, $autocomplete = null)
565
{
566
    Context::required(__FUNCTION__);
567
568
    if (output()->isQuiet()) {
569
        return $default;
570
    }
571
572
    /** @var QuestionHelper $helper */
573
    $helper = Deployer::get()->getHelper('question');
574
575
    $tag = currentHost()->tag();
576
    $message = "[$tag] <question>$message</question> " . (($default === null) ? "" : "(default: $default) ");
577
578
    $question = new Question($message, $default);
579
    if (!empty($autocomplete)) {
580
        $question->setAutocompleterValues($autocomplete);
581
    }
582
583
    try {
584
        return $helper->ask(input(), output(), $question);
585
    } catch (MissingInputException $exception) {
586
        throw new Exception("Failed to read input from stdin.\nMake sure what you are asking for input not from parallel task.", $exception->getCode(), $exception);
587
    }
588
}
589
590
/**
591
 * @param string $message
592
 * @param string[] $availableChoices
593
 * @param string|null $default
594
 * @param bool|false $multiselect
595
 * @return string|string[]
596
 */
597
function askChoice($message, array $availableChoices, $default = null, $multiselect = false)
598
{
599
    Context::required(__FUNCTION__);
600
601
    if (empty($availableChoices)) {
602
        throw new \InvalidArgumentException('Available choices should not be empty');
603
    }
604
605
    if ($default !== null && !array_key_exists($default, $availableChoices)) {
606
        throw new \InvalidArgumentException('Default choice is not available');
607
    }
608
609
    if (output()->isQuiet()) {
610
        if ($default === null) {
611
            $default = key($availableChoices);
612
        }
613
        return [$default => $availableChoices[$default]];
614
    }
615
616
    $helper = Deployer::get()->getHelper('question');
617
618
    $tag = currentHost()->tag();
619
    $message = "[$tag] <question>$message</question> " . (($default === null) ? "" : "(default: $default) ");
620
621
    $question = new ChoiceQuestion($message, $availableChoices, $default);
622
    $question->setMultiselect($multiselect);
623
624
    return $helper->ask(input(), output(), $question);
625
}
626
627
/**
628
 * @param string $message
629
 * @param bool $default
630
 * @return bool
631
 */
632
function askConfirmation($message, $default = false)
633
{
634
    Context::required(__FUNCTION__);
635
636
    if (output()->isQuiet()) {
637
        return $default;
638
    }
639
640
    $helper = Deployer::get()->getHelper('question');
641
642
    $yesOrNo = $default ? 'Y/n' : 'y/N';
643
    $tag = currentHost()->tag();
644
    $message = "[$tag] <question>$message</question> [$yesOrNo] ";
645
646
    $question = new ConfirmationQuestion($message, $default);
647
648
    return $helper->ask(input(), output(), $question);
649
}
650
651
/**
652
 * @param string $message
653
 * @return string
654
 */
655
function askHiddenResponse($message)
656
{
657
    Context::required(__FUNCTION__);
658
659
    if (output()->isQuiet()) {
660
        return '';
661
    }
662
663
    $helper = Deployer::get()->getHelper('question');
664
665
    $tag = currentHost()->tag();
666
    $message = "[$tag] <question>$message</question> ";
667
668
    $question = new Question($message);
669
    $question->setHidden(true);
670
    $question->setHiddenFallback(false);
671
672
    return $helper->ask(input(), output(), $question);
673
}
674
675
/**
676
 * @return InputInterface
677
 */
678
function input()
679
{
680 4
    return Context::get()->getInput();
681
}
682
683
684
/**
685
 * @return OutputInterface
686
 */
687
function output()
688
{
689 5
    return Context::get()->getOutput();
690
}
691
692
/**
693
 * Check if command exists
694
 *
695
 * @param string $command
696
 * @return bool
697
 */
698
function commandExist($command)
699
{
700
    return test("hash $command 2>/dev/null");
701
}
702
703
function commandSupportsOption($command, $option)
704
{
705 1
    return test("[[ $(man $command 2>&1 || $command -h 2>&1 || $command --help 2>&1) =~ '$option' ]]");
706
}
707
708
/**
709
 * Parse set values.
710
 *
711
 * @param string $value
712
 * @return string
713
 */
714
function parse($value)
715
{
716 6
    return Context::get()->getConfig()->parse($value);
717
}
718
719
function locateBinaryPath($name)
720
{
721 1
    $nameEscaped = escapeshellarg($name);
722
723
    // Try `command`, should cover all Bourne-like shells
724
    // Try `which`, should cover most other cases
725
    // Fallback to `type` command, if the rest fails
726 1
    $path = run("command -v $nameEscaped || which $nameEscaped || type -p $nameEscaped");
727 1
    if ($path) {
728
        // Deal with issue when `type -p` outputs something like `type -ap` in some implementations
729 1
        return trim(str_replace("$name is", "", $path));
730
    }
731
732
    throw new \RuntimeException("Can't locate [$nameEscaped] - neither of [command|which|type] commands are available");
733
}
734