Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

Passed
Push — coverage-badge-dont-delete ( 988970...16f19c )
by
unknown
35:30 queued 20:29
created

Install::handle()   B

Complexity

Conditions 6
Paths 12

Size

Total Lines 66
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 6
eloc 38
c 1
b 0
f 0
nc 12
nop 0
dl 0
loc 66
rs 8.6897

How to fix   Long Method   

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
namespace Backpack\CRUD\app\Console\Commands;
4
5
use Backpack\CRUD\BackpackServiceProvider;
6
use Carbon\Carbon;
7
use Illuminate\Console\Command;
8
use Illuminate\Support\Facades\Hash;
9
use Illuminate\Support\Str;
10
use Symfony\Component\Console\Output\OutputInterface;
11
use Symfony\Component\Process\Process;
12
13
class Install extends Command
14
{
15
    use Traits\PrettyCommandOutput;
16
17
    protected $progressBar;
18
19
    /**
20
     * The name and signature of the console command.
21
     *
22
     * @var string
23
     */
24
    protected $signature = 'backpack:install
25
                                {--timeout=300} : How many seconds to allow each process to run.
26
                                {--debug} : Show process output or not. Useful for debugging.
27
                                {--skip-basset-check : Skip running "php artisan basset:check" at the end of the installation.}';
28
    /**
29
     * The console command description.
30
     *
31
     * @var string
32
     */
33
    protected $description = 'Install Backpack requirements on dev, publish files and create uploads directory.';
34
35
    /**
36
     * Addons variable.
37
     *
38
     * @var array
39
     */
40
    protected $addons = [
41
        Addons\RequirePro::class,
42
        Addons\RequireDevTools::class,
43
        Addons\RequireEditableColumns::class,
44
    ];
45
46
    /**
47
     * Themes variable.
48
     *
49
     * @var array
50
     */
51
    protected $themes = [
52
        Themes\RequireThemeTabler::class,
53
        Themes\RequireThemeCoreuiv4::class,
54
        Themes\RequireThemeCoreuiv2::class,
55
    ];
56
57
    /**
58
     * Execute the console command.
59
     *
60
     * @return mixed Command-line output
61
     */
62
    public function handle()
63
    {
64
        $this->infoBlock('Installing Backpack CRUD.', 'Step 1');
65
66
        // Publish files
67
        $this->progressBlock('Publishing configs, views, routes and assets');
68
        $this->executeArtisanProcess('vendor:publish', [
69
            '--provider' => BackpackServiceProvider::class,
70
            '--tag' => 'minimum',
71
        ]);
72
        $this->closeProgressBlock();
73
74
        // Create users table
75
        $this->progressBlock('Creating users table');
76
        $this->executeArtisanProcess('migrate', $this->option('no-interaction') ? ['--no-interaction' => true] : []);
77
        $this->closeProgressBlock();
78
79
        // Create CheckIfAdmin middleware
80
        $this->progressBlock('Creating CheckIfAdmin middleware');
81
        $this->executeArtisanProcess('backpack:publish-middleware');
82
        $this->closeProgressBlock();
83
84
        // Install Backpack Generators
85
        $this->progressBlock('Installing Generators');
86
        if (! file_exists('vendor/backpack/generators/composer.json')) {
87
            // only do this if Generators aren't already required
88
            $process = new Process(['composer', 'require', '--dev', 'backpack/generators']);
89
            $process->setTimeout(300);
90
            $process->run();
91
        }
92
        $this->closeProgressBlock();
93
94
        // Install Backpack Basset
95
        $this->progressBlock('Installing Basset');
96
        $this->executeArtisanProcess('basset:install --no-check --no-interaction');
97
        $this->closeProgressBlock();
98
99
        // Optional commands
100
        if (! $this->option('no-interaction')) {
101
            // Themes
102
            $this->installTheme();
103
104
            // Create users
105
            $this->createUsers();
106
107
            // Addons
108
            $this->installAddons();
109
        } elseif (! $this->isAnyThemeInstalled()) {
110
            // Install default theme
111
            $this->progressBlock('Installing default theme');
112
            $this->executeArtisanProcess('backpack:require:theme-tabler');
113
            $this->closeProgressBlock();
114
        }
115
116
        //execute basset checks
117
        if (! $this->option('skip-basset-check')) {
118
            $this->progressBlock('Running Basset checks');
119
            $this->executeArtisanProcess('basset:check');
120
            $this->closeProgressBlock();
121
        }
122
        // Done
123
        $url = Str::of(config('app.url'))->finish('/')->append('admin/');
124
        $this->infoBlock('Backpack installation complete.', 'done');
125
        $this->note("Go to <fg=blue>$url</> to access your new admin panel.");
126
        $this->note('You may need to run <fg=blue>php artisan serve</> to serve your Laravel project.');
127
        $this->newLine();
128
    }
129
130
    private function createUsers()
131
    {
132
        $userClass = config('backpack.base.user_model_fqn', 'App\Models\User');
133
        $userModel = new $userClass();
134
135
        $this->newLine();
136
        $this->infoBlock('Creating an admin.', 'Step 3');
137
        $this->note('Quickly jump in your admin panel, using the email & password you choose here.');
138
139
        // Test User Model DB Connection
140
        try {
141
            $userModel->getConnection()->getPdo();
142
        } catch (\Throwable $e) {
143
            $this->note('Error accessing the database, make sure the User Model has a valid DB connection.', 'red');
144
145
            return;
146
        }
147
148
        // Count current users
149
        $currentUsers = $userModel->count();
150
        $this->note(sprintf('Currently there %s in the <fg=blue>%s</> table.', trans_choice("{0} are <fg=blue>no users</>|{1} is <fg=blue>1 user</>|[2,*] are <fg=blue>$currentUsers users</>", $currentUsers), $userModel->getTable()));
151
152
        if ($currentUsers) {
153
            $this->note('Skipping creating an admin user.');
154
            $this->newLine();
155
156
            return;
157
        }
158
159
        $total = 0;
160
        while ($this->confirm(' Add '.($total ? 'another' : 'an').' admin user?')) {
161
            $name = $this->ask(' Name');
162
            $mail = $this->ask(" {$name}'s email");
163
            $pass = $this->secret(" {$name}'s password");
164
165
            try {
166
                $user = collect([
0 ignored issues
show
Bug introduced by
array('name' => $name, '...ades\Hash::make($pass)) of type array<string,mixed|string> is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

166
                $user = collect(/** @scrutinizer ignore-type */ [
Loading history...
167
                    'name' => $name,
168
                    'email' => $mail,
169
                    'password' => Hash::make($pass),
170
                ]);
171
172
                // Merge timestamps
173
                if ($userModel->timestamps) {
174
                    $user = $user->merge([
0 ignored issues
show
Bug introduced by
array('created_at' => Ca...> Carbon\Carbon::now()) of type array<string,Carbon\Carbon> is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $items of Illuminate\Support\Collection::merge(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

174
                    $user = $user->merge(/** @scrutinizer ignore-type */ [
Loading history...
175
                        'created_at' => Carbon::now(),
176
                        'updated_at' => Carbon::now(),
177
                    ]);
178
                }
179
180
                $userModel->insert($user->toArray());
181
182
                $this->deleteLines(12);
183
                $this->progressBlock('Adding admin user');
184
                $this->closeProgressBlock();
185
                $this->note($name);
186
                $this->note($mail);
187
188
                $total++;
189
            } catch (\Throwable$e) {
190
                $this->errorBlock($e->getMessage());
191
            }
192
        }
193
194
        $this->deleteLines(3);
195
196
        if (! $total) {
197
            $this->deleteLines();
198
            $this->note('Skipping creating an admin user.');
199
            $this->newLine();
200
        }
201
    }
202
203
    private function isEveryAddonInstalled()
204
    {
205
        return collect($this->addons)->every(function ($addon) {
0 ignored issues
show
Bug introduced by
$this->addons of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

205
        return collect(/** @scrutinizer ignore-type */ $this->addons)->every(function ($addon) {
Loading history...
206
            return file_exists($addon->path);
207
        });
208
    }
209
210
    private function updateAddonsStatus()
211
    {
212
        $this->addons = $this->addons->each(function (&$addon) {
213
            $isInstalled = file_exists($addon->path);
214
            $addon->status = $isInstalled ? 'installed' : 'not installed';
215
            $addon->statusColor = $isInstalled ? 'green' : 'yellow';
216
        });
217
    }
218
219
    private function installAddons()
220
    {
221
        // map the addons
222
        $this->addons = collect($this->addons)
0 ignored issues
show
Bug introduced by
$this->addons of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

222
        $this->addons = collect(/** @scrutinizer ignore-type */ $this->addons)
Loading history...
Documentation Bug introduced by
It seems like collect($this->addons)->...ion(...) { /* ... */ }) of type Illuminate\Support\Collection is incompatible with the declared type array of property $addons.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
223
            ->map(function ($class) {
224
                return (object) $class::$addon;
225
            });
226
227
        // set addons current status (installed / not installed)
228
        $this->updateAddonsStatus();
229
230
        // if all addons are installed do nothing
231
        if ($this->isEveryAddonInstalled()) {
232
            return;
233
        }
234
235
        $this->infoBlock('Installing premium Backpack add-ons:', 'Step 4');
236
        $this->note('Add tons of features and functionality to your admin panel, using our paid add-ons.');
237
        $this->note('For more information, payment and access please visit <fg=blue>https://backpackforlaravel.com/pricing</>');
238
        $this->newLine();
239
240
        // Calculate the printed line count
241
        $printedLines = $this->addons
242
            ->map(function ($e) {
243
                return count($e->description);
244
            })
245
            ->reduce(function ($sum, $item) {
246
                return $sum + $item + 2;
247
            }, 0);
0 ignored issues
show
Bug introduced by
0 of type integer is incompatible with the type Illuminate\Support\Traits\TReduceInitial expected by parameter $initial of Illuminate\Support\Collection::reduce(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

247
            }, /** @scrutinizer ignore-type */ 0);
Loading history...
248
249
        $total = 0;
250
        while (! $this->isEveryAddonInstalled()) {
251
            $input = (int) $this->listChoice('Would you like to install a premium Backpack add-on? <fg=gray>(enter an option number from above or press any other key to continue the installation)</>', $this->addons->toArray());
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->listChoice('Would...his->addons->toArray()) targeting Backpack\CRUD\app\Consol...s\Install::listChoice() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
252
253
            if ($input < 1 || $input > $this->addons->count()) {
254
                $this->deleteLines(3);
255
                break;
256
            }
257
258
            // Clear list
259
            $this->deleteLines($printedLines + 4 + ($total ? 2 : 0));
260
261
            try {
262
                $addon = $this->addons[$input - 1];
263
264
                // Install addon (low verbose level)
265
                $currentVerbosity = $this->output->getVerbosity();
266
                $this->output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
267
                $this->call($addon->command);
268
                $this->output->setVerbosity($currentVerbosity);
269
270
                // refresh list
271
                $this->updateAddonsStatus();
272
273
                $total++;
274
            } catch (\Throwable $e) {
275
                $this->errorBlock($e->getMessage());
276
            }
277
278
            $this->line('  ──────────', 'fg=gray');
279
            $this->newLine();
280
        }
281
    }
282
283
    private function isEveryThemeInstalled()
284
    {
285
        return $this->themes()->every(function ($theme) {
286
            return $theme->status == 'installed';
287
        });
288
    }
289
290
    private function isAnyThemeInstalled()
291
    {
292
        return $this->themes()->filter(function ($theme) {
293
            return $theme->status == 'installed';
294
        })->count() > 0;
295
    }
296
297
    private function installTheme()
298
    {
299
        // if all themes are installed do nothing
300
        if ($this->isEveryThemeInstalled()) {
301
            return;
302
        }
303
304
        $this->infoBlock('Installing a Theme.', 'Step 2');
305
        $this->note('Choose your admin UI, depending on your project and preferences.');
306
        $this->newLine();
307
308
        // Calculate the printed line count
309
        $printedLines = $this->themes()
310
            ->map(function ($e) {
311
                return count($e->description);
312
            })
313
            ->reduce(function ($sum, $item) {
314
                return $sum + $item + 2;
315
            }, 0);
0 ignored issues
show
Bug introduced by
0 of type integer is incompatible with the type Illuminate\Support\Traits\TReduceInitial expected by parameter $initial of Illuminate\Support\Collection::reduce(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

315
            }, /** @scrutinizer ignore-type */ 0);
Loading history...
316
317
        $total = 0;
318
        $input = (int) $this->listChoice('Which Backpack theme would you like to install? <fg=gray>(enter option number: 1, 2 or 3)</>', $this->themes()->toArray(), 1);
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->listChoice('Which...themes()->toArray(), 1) targeting Backpack\CRUD\app\Consol...s\Install::listChoice() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
319
320
        if ($input < 1 || $input > $this->themes()->count()) {
321
            $this->deleteLines(3);
322
            $this->note('Unknown theme. Using default theme value.');
323
            $this->newLine();
324
325
            $input = 1;
326
        }
327
328
        // Clear list
329
        $this->deleteLines($printedLines + 4 + ($total ? 2 : 0));
330
331
        try {
332
            $addon = $this->themes()[$input - 1];
333
334
            // Install addon (low verbose level)
335
            $currentVerbosity = $this->output->getVerbosity();
336
            $this->output->setVerbosity(OutputInterface::VERBOSITY_VERBOSE);
337
            $this->call($addon->command);
338
            $this->output->setVerbosity($currentVerbosity);
339
340
            $total++;
341
        } catch (\Throwable $e) {
342
            $this->errorBlock($e->getMessage());
343
        }
344
    }
345
346
    public function themes()
347
    {
348
        return collect($this->themes)
0 ignored issues
show
Bug introduced by
$this->themes of type array is incompatible with the type Illuminate\Contracts\Support\Arrayable expected by parameter $value of collect(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

348
        return collect(/** @scrutinizer ignore-type */ $this->themes)
Loading history...
349
            ->map(function ($class) {
350
                return (object) $class::$addon;
351
            })->each(function (&$theme) {
352
                $isInstalled = file_exists($theme->path);
353
                $theme->status = $isInstalled ? 'installed' : 'not installed';
354
                $theme->statusColor = $isInstalled ? 'green' : 'yellow';
355
            });
356
    }
357
}
358