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.

InitCommand::execute()   F
last analyzed

Complexity

Conditions 10
Paths 1028

Size

Total Lines 123
Code Lines 59

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 10
eloc 59
c 0
b 0
f 0
nc 1028
nop 2
dl 0
loc 123
rs 3.6945

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
declare(strict_types=1);
4
5
/* (c) Anton Medvedev <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Deployer\Command;
12
13
use Symfony\Component\Console\Command\Command;
14
use Symfony\Component\Console\Input\InputInterface;
15
use Symfony\Component\Console\Input\InputOption;
16
use Symfony\Component\Console\Output\OutputInterface;
17
use Symfony\Component\Console\Style\SymfonyStyle;
18
use Symfony\Component\Process\Exception\RuntimeException;
19
use Symfony\Component\Process\PhpProcess;
20
use Symfony\Component\Process\Process;
21
22
class InitCommand extends Command
23
{
24
    use CommandCommon;
25
26
    protected function configure()
27
    {
28
        $this
29
            ->setName('init')
30
            ->setDescription('Initialize deployer in your project')
31
            ->addOption('path', 'p', InputOption::VALUE_OPTIONAL, 'Recipe path');
32
    }
33
34
    protected function execute(InputInterface $input, OutputInterface $output): int
35
    {
36
        if (getenv('COLORTERM') === 'truecolor') {
37
            $output->write(
38
                <<<EOF
39
                    ╭───────────────────────────────────────╮
40
                    │                                       │
41
                    │                                       │
42
                    │    \e[38;2;94;231;223m_\e[39m\e[38;2;95;231;226m_\e[39m\e[38;2;96;230;228m_\e[39m\e[38;2;96;229;230m_\e[39m          \e[38;2;97;226;230m_\e[39m                    │
43
                    │   \e[38;2;98;223;229m|\e[39m    \e[38;2;98;220;229m\\\e[39m \e[38;2;99;216;228m_\e[39m\e[38;2;100;213;228m_\e[39m\e[38;2;101;210;228m_\e[39m \e[38;2;101;208;227m_\e[39m\e[38;2;102;205;227m_\e[39m\e[38;2;103;202;227m_\e[39m\e[38;2;104;199;226m|\e[39m \e[38;2;104;196;226m|\e[39m\e[38;2;105;194;225m_\e[39m\e[38;2;106;191;225m_\e[39m\e[38;2;106;188;225m_\e[39m \e[38;2;107;186;224m_\e[39m \e[38;2;108;183;224m_\e[39m \e[38;2;109;181;224m_\e[39m\e[38;2;109;178;223m_\e[39m\e[38;2;110;176;223m_\e[39m \e[38;2;111;174;222m_\e[39m\e[38;2;111;171;222m_\e[39m\e[38;2;112;169;222m_\e[39m    │
44
                    │   \e[38;2;113;167;221m|\e[39m  \e[38;2;113;165;221m|\e[39m  \e[38;2;114;163;221m|\e[39m \e[38;2;115;160;220m-\e[39m\e[38;2;115;158;220m_\e[39m\e[38;2;116;156;219m|\e[39m \e[38;2;117;155;219m.\e[39m \e[38;2;117;153;219m|\e[39m \e[38;2;118;151;218m|\e[39m \e[38;2;119;149;218m.\e[39m \e[38;2;119;147;218m|\e[39m \e[38;2;120;145;217m|\e[39m \e[38;2;121;144;217m|\e[39m \e[38;2;121;142;216m-\e[39m\e[38;2;122;140;216m_\e[39m\e[38;2;123;139;216m|\e[39m  \e[38;2;123;137;215m_\e[39m\e[38;2;124;136;215m|\e[39m   │
45
                    │   \e[38;2;124;134;215m|\e[39m\e[38;2;125;133;214m_\e[39m\e[38;2;126;132;214m_\e[39m\e[38;2;126;130;214m_\e[39m\e[38;2;127;129;213m_\e[39m\e[38;2;127;128;213m/\e[39m\e[38;2;130;128;212m|\e[39m\e[38;2;132;129;212m_\e[39m\e[38;2;134;129;212m_\e[39m\e[38;2;137;130;211m_\e[39m\e[38;2;139;131;211m|\e[39m  \e[38;2;141;131;211m_\e[39m\e[38;2;143;132;210m|\e[39m\e[38;2;145;132;210m_\e[39m\e[38;2;147;133;209m|\e[39m\e[38;2;149;133;209m_\e[39m\e[38;2;151;134;209m_\e[39m\e[38;2;153;135;208m_\e[39m\e[38;2;155;135;208m|\e[39m\e[38;2;157;136;208m_\e[39m  \e[38;2;159;136;207m|\e[39m\e[38;2;161;137;207m_\e[39m\e[38;2;162;137;206m_\e[39m\e[38;2;164;138;206m_\e[39m\e[38;2;166;139;206m|\e[39m\e[38;2;167;139;205m_\e[39m\e[38;2;169;140;205m|\e[39m     │
46
                    │             \e[38;2;170;140;205m|\e[39m\e[38;2;172;141;204m_\e[39m\e[38;2;173;141;204m|\e[39m       \e[38;2;175;142;203m|\e[39m\e[38;2;176;142;203m_\e[39m\e[38;2;177;143;203m_\e[39m\e[38;2;179;143;202m_\e[39m\e[38;2;180;144;202m|\e[39m           │
47
                    │                                       │
48
                    │                                       │
49
                    ╰───────────────────────────────────────╯
50
51
                    EOF,
52
            );
53
        } else {
54
            $output->write(
55
                <<<EOF
56
                    ╭───────────────────────────────────────╮
57
                    │                                       │
58
                    │                                       │
59
                    │    ____          _                    │
60
                    │   |    \ ___ ___| |___ _ _ ___ ___    │
61
                    │   |  |  | -_| . | | . | | | -_|  _|   │
62
                    │   |____/|___|  _|_|___|_  |___|_|     │
63
                    │             |_|       |___|           │
64
                    │                                       │
65
                    │                                       │
66
                    ╰───────────────────────────────────────╯
67
68
                    EOF,
69
            );
70
        }
71
72
        $io = new SymfonyStyle($input, $output);
73
        $recipePath = $input->getOption('path');
74
75
        $language = $io->choice('Select recipe language', ['php', 'yaml'], 'php');
76
        if (empty($recipePath)) {
77
            $recipePath = "deploy.$language";
78
        }
79
80
        // Avoid accidentally override of existing file.
81
        if (file_exists($recipePath)) {
82
            $io->warning("$recipePath already exists");
83
            if (!$io->confirm("Do you want to override the existing file?", false)) {
84
                $io->block('👍🏻');
85
                exit(1);
0 ignored issues
show
Bug Best Practice introduced by
In this branch, the function will implicitly return null which is incompatible with the type-hinted return integer. Consider adding a return statement or allowing null as return value.

For hinted functions/methods where all return statements with the correct type are only reachable via conditions, ?null? gets implicitly returned which may be incompatible with the hinted type. Let?s take a look at an example:

interface ReturnsInt {
    public function returnsIntHinted(): int;
}

class MyClass implements ReturnsInt {
    public function returnsIntHinted(): int
    {
        if (foo()) {
            return 123;
        }
        // here: null is implicitly returned
    }
}
Loading history...
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
86
            }
87
        }
88
89
        // Template
90
        $template = $io->choice('Select project template', $this->recipes(), 'common');
91
92
        // Repo
93
        $default = '';
94
        try {
95
            $process = Process::fromShellCommandline('git remote get-url origin');
96
            $default = $process->mustRun()->getOutput();
97
            $default = trim($default);
98
        } catch (RuntimeException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
99
        }
100
        $repository = $io->ask('Repository', $default);
101
102
        // Guess host
103
        if (preg_match('/github.com:(?<org>[A-Za-z0-9_.\-]+)\//', $repository, $m)) {
104
            $org = $m['org'];
105
            $tempHostFile = tempnam(sys_get_temp_dir(), 'temp-host-file');
106
            $php = new PhpProcess(
107
                <<<EOF
108
                    <?php
109
                    \$ch = curl_init('https://api.github.com/orgs/$org');
110
                    curl_setopt(\$ch, CURLOPT_USERAGENT, 'Deployer');
111
                    curl_setopt(\$ch, CURLOPT_CUSTOMREQUEST, 'GET');
112
                    curl_setopt(\$ch, CURLOPT_RETURNTRANSFER, true);
113
                    curl_setopt(\$ch, CURLOPT_FOLLOWLOCATION, true);
114
                    curl_setopt(\$ch, CURLOPT_MAXREDIRS, 10);
115
                    curl_setopt(\$ch, CURLOPT_CONNECTTIMEOUT, 5);
116
                    curl_setopt(\$ch, CURLOPT_TIMEOUT, 5);
117
                    \$result = curl_exec(\$ch);
118
                    curl_close(\$ch);
119
                    \$json = json_decode(\$result);
120
                    \$host = parse_url(\$json->blog, PHP_URL_HOST);
121
                    file_put_contents('$tempHostFile', \$host);
122
                    EOF,
123
            );
124
            $php->start();
125
        }
126
127
        // Project
128
        $default = '';
129
        try {
130
            $process = Process::fromShellCommandline('basename "$PWD"');
131
            $default = $process->mustRun()->getOutput();
132
            $default = trim($default);
133
        } catch (RuntimeException $e) {
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
134
        }
135
        $project = $io->ask('Project name', $default);
136
137
        // Hosts
138
        $host = null;
139
        if (isset($tempHostFile)) {
140
            $host = file_get_contents($tempHostFile);
141
        }
142
        $hostsString = $io->ask('Hosts (comma separated)', $host);
143
        if ($hostsString !== null) {
144
            $hosts = explode(',', $hostsString);
145
        } else {
146
            $hosts = [];
147
        }
148
149
        file_put_contents($recipePath, $this->$language($template, $project, $repository, $hosts));
150
151
        $this->telemetry();
152
        $output->writeln(sprintf(
153
            '<info>Successfully created</info> <comment>%s</comment>',
154
            $recipePath,
155
        ));
156
        return 0;
157
    }
158
159
    private function php(string $template, string $project, string $repository, array $hosts): string
160
    {
161
        $h = "";
162
        foreach ($hosts as $host) {
163
            $h .= "host('{$host}')\n" .
164
                "    ->set('remote_user', 'deployer')\n" .
165
                "    ->set('deploy_path', '~/{$project}');\n";
166
        }
167
168
        return <<<PHP
169
            <?php
170
            namespace Deployer;
171
172
            require 'recipe/$template.php';
173
174
            // Config
175
176
            set('repository', '{$repository}');
177
178
            add('shared_files', []);
179
            add('shared_dirs', []);
180
            add('writable_dirs', []);
181
182
            // Hosts
183
184
            {$h}
185
            // Hooks
186
187
            after('deploy:failed', 'deploy:unlock');
188
189
            PHP;
190
    }
191
192
    private function yaml(string $template, string $project, string $repository, array $hosts): string
193
    {
194
        $h = "";
195
        foreach ($hosts as $host) {
196
            $h .= "  $host:\n" .
197
                "    remote_user: deployer\n" .
198
                "    deploy_path: '~/{$project}'\n";
199
        }
200
201
        $additionalConfigs = $this->getAdditionalConfigs($template);
202
203
        return <<<YAML
204
            import: 
205
              - recipe/$template.php
206
207
            config:
208
              repository: '$repository'
209
            $additionalConfigs
210
            hosts:
211
            $h
212
            tasks:
213
              build:
214
                - run: uptime  
215
216
            after:
217
              deploy:failed: deploy:unlock
218
219
            YAML;
220
    }
221
222
    private function getAdditionalConfigs(string $template): string
223
    {
224
        if ($template !== 'common') {
225
            return '';
226
        }
227
228
        return <<<YAML
229
              shared_files:
230
                - .env
231
              shared_dirs:
232
                - uploads
233
              writable_dirs:
234
                - uploads
235
              
236
            YAML;
237
    }
238
239
    private function recipes(): array
240
    {
241
        $recipes = [];
242
        $dir = new \DirectoryIterator(__DIR__ . '/../../recipe');
243
        foreach ($dir as $fileinfo) {
244
            if ($fileinfo->isDot()) {
245
                continue;
246
            }
247
            if ($fileinfo->isDir()) {
248
                continue;
249
            }
250
251
            $recipe = pathinfo($fileinfo->getFilename(), PATHINFO_FILENAME);
252
253
            if ($recipe === 'README') {
254
                continue;
255
            }
256
257
            $recipes[] = $recipe;
258
        }
259
260
        sort($recipes);
261
        return $recipes;
262
    }
263
}
264