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
Pull Request — master (#1904)
by Anton
02:17
created

functions.php ➔ fail()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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