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 — add-update-command ( 52996a...7d33d9 )
by Pedro
14:43
created

UpgradeCommand::handle()   C

Complexity

Conditions 13
Paths 40

Size

Total Lines 97
Code Lines 54

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 13
eloc 54
nc 40
nop 0
dl 0
loc 97
rs 6.6166
c 1
b 0
f 1

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
namespace Backpack\CRUD\app\Console\Commands\Upgrade;
4
5
use Backpack\CRUD\app\Console\Commands\Traits\PrettyCommandOutput;
6
use Illuminate\Console\Command;
7
use RuntimeException;
8
9
class UpgradeCommand extends Command
10
{
11
    use PrettyCommandOutput;
0 ignored issues
show
introduced by
The trait Backpack\CRUD\app\Consol...its\PrettyCommandOutput requires some properties which are not provided by Backpack\CRUD\app\Consol...\Upgrade\UpgradeCommand: $progressBar, $statusColor, $status
Loading history...
12
13
    protected $signature = 'backpack:upgrade
14
                                {version=7 : Target Backpack version to prepare for.}
15
                                {--stop-on-failure : Stop executing once a step fails.}
16
                                {--format=cli : Output format (cli, json).}
17
                                {--debug : Show debug information for executed processes.}';
18
19
    protected $description = 'Run opinionated upgrade checks to help you move between Backpack major versions.';
20
21
    public function handle(): int
22
    {
23
        $format = $this->outputFormat();
24
25
        if (! in_array($format, ['cli', 'json'], true)) {
26
            $this->errorBlock(sprintf('Unknown output format "%s". Supported formats: cli, json.', $format));
27
28
            return Command::INVALID;
29
        }
30
31
        $version = (string) $this->argument('version');
32
        $majorVersion = $this->extractMajorVersion($version);
33
34
        try {
35
            $config = $this->resolveConfigForMajor($majorVersion);
36
        } catch (RuntimeException $exception) {
37
            $this->errorBlock($exception->getMessage());
38
39
            return Command::INVALID;
40
        }
41
42
        $stepClasses = $config->steps();
43
            if (empty($stepClasses)) {
44
            $this->errorBlock("No automated checks registered for Backpack v{$majorVersion}.");
45
46
            return Command::INVALID;
47
        }
48
49
            $context = new UpgradeContext($majorVersion, addons: $config->addons());
50
51
        $this->infoBlock("Backpack v{$majorVersion} upgrade assistant", 'upgrade');
52
53
        $results = [];
54
55
        foreach ($stepClasses as $stepClass) {
56
            /** @var Step $step */
57
            $step = new $stepClass($context);
58
59
            $this->progressBlock($step->title());
60
61
            try {
62
                $result = $step->run();
63
            } catch (\Throwable $exception) {
64
                $result = StepResult::failure(
65
                    $exception->getMessage(),
66
                    [
67
                        'Step: '.$stepClass,
68
                    ]
69
                );
70
            }
71
72
            $this->closeProgressBlock(strtoupper($result->status->label()), $result->status->color());
73
74
            $this->printResultDetails($result);
75
76
            if ($this->shouldOfferFix($step, $result)) {
77
                $question = trim($step->fixMessage($result));
78
                $question = $question !== '' ? $question : 'Apply automatic fix?';
79
                $applyFix = $this->confirm('  '.$question, false);
80
81
                if ($applyFix) {
82
                    $this->progressBlock('Applying automatic fix');
83
                    $fixResult = $step->fix($result);
84
                    $this->closeProgressBlock(strtoupper($fixResult->status->label()), $fixResult->status->color());
85
                    $this->printResultDetails($fixResult);
86
87
                    if (! $fixResult->status->isFailure()) {
88
                        $this->progressBlock('Re-running '.$step->title());
89
90
                        try {
91
                            $result = $step->run();
92
                        } catch (\Throwable $exception) {
93
                            $result = StepResult::failure(
94
                                $exception->getMessage(),
95
                                [
96
                                    'Step: '.$stepClass,
97
                                ]
98
                            );
99
                        }
100
101
                        $this->closeProgressBlock(strtoupper($result->status->label()), $result->status->color());
102
                        $this->printResultDetails($result);
103
                    }
104
                }
105
            }
106
107
            $results[] = [
108
                'step' => $stepClass,
109
                'result' => $result,
110
            ];
111
112
            if ($this->option('stop-on-failure') && $result->status->isFailure()) {
113
                break;
114
            }
115
        }
116
117
        return $this->outputSummary($majorVersion, $results);
118
    }
119
120
    protected function outputSummary(string $majorVersion, array $results): int
121
    {
122
        $format = $this->outputFormat();
123
124
        $hasFailure = collect($results)->contains(function ($entry) {
0 ignored issues
show
Bug introduced by
$results 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

124
        $hasFailure = collect(/** @scrutinizer ignore-type */ $results)->contains(function ($entry) {
Loading history...
125
            /** @var StepResult $result */
126
            $result = $entry['result'];
127
128
            return $result->status->isFailure();
129
        });
130
131
        $warnings = collect($results)->filter(function ($entry) {
132
            /** @var StepResult $result */
133
            $result = $entry['result'];
134
135
            return $result->status === StepStatus::Warning;
136
        });
137
138
        if ($format === 'json') {
139
            $payload = [
140
                'version' => $majorVersion,
141
                'results' => collect($results)->map(function ($entry) {
142
                    /** @var StepResult $result */
143
                    $result = $entry['result'];
144
145
                    return [
146
                        'step' => $entry['step'],
147
                        'status' => $result->status->value,
148
                        'summary' => $result->summary,
149
                        'details' => $result->details,
150
                    ];
151
                })->values()->all(),
152
            ];
153
154
            $this->newLine();
155
            $this->line(json_encode($payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
156
157
            return $hasFailure ? Command::FAILURE : Command::SUCCESS;
158
        }
159
160
        $this->newLine();
161
        $this->infoBlock('Summary', 'done');
162
163
        $this->note(sprintf('Checked %d upgrade steps.', count($results)), 'gray');
164
165
        if ($hasFailure) {
166
            $this->note('At least one step reported a failure. Review the messages above before continuing.', 'red', 'red');
167
        }
168
169
        if ($warnings->isNotEmpty()) {
170
            $this->note(sprintf('%d step(s) reported warnings.', $warnings->count()), 'yellow', 'yellow');
171
        }
172
173
        if (! $hasFailure && $warnings->isEmpty()) {
174
            $this->note('All checks passed, you are ready to continue with the manual steps from the upgrade guide.', 'green', 'green');
175
        }
176
177
        $this->newLine();
178
179
        return $hasFailure ? Command::FAILURE : Command::SUCCESS;
180
    }
181
182
    protected function printResultDetails(StepResult $result): void
183
    {
184
        $color = match ($result->status) {
185
            StepStatus::Passed => 'green',
186
            StepStatus::Warning => 'yellow',
187
            StepStatus::Failed => 'red',
188
            StepStatus::Skipped => 'gray',
189
        };
190
191
        if ($result->summary !== '') {
192
            $this->note($result->summary, $color, $color);
193
        }
194
195
        foreach ($result->details as $detail) {
196
            $this->note($detail, 'gray');
197
        }
198
199
        $this->newLine();
200
    }
201
202
    protected function shouldOfferFix(Step $step, StepResult $result): bool
203
    {
204
        if ($this->outputFormat() === 'json') {
205
            return false;
206
        }
207
208
        if (! $this->input->isInteractive()) {
209
            return false;
210
        }
211
212
        if (! in_array($result->status, [StepStatus::Warning, StepStatus::Failed], true)) {
213
            return false;
214
        }
215
216
        return $step->canFix($result);
217
    }
218
219
    protected function outputFormat(): string
220
    {
221
        $format = strtolower((string) $this->option('format'));
222
223
        return $format !== '' ? $format : 'cli';
224
    }
225
226
    protected function resolveConfigForMajor(string $majorVersion): UpgradeConfigInterface
227
    {
228
        $configProviderClass = sprintf('%s\\v%s\\UpgradeCommandConfig', __NAMESPACE__, $majorVersion);
229
230
        if (! class_exists($configProviderClass)) {
231
            throw new RuntimeException(sprintf(
232
                'Missing upgrade config provider for Backpack v%s. Please create %s.',
233
                $majorVersion,
234
                $configProviderClass
235
            ));
236
        }
237
238
        $provider = $this->laravel
239
            ? $this->laravel->make($configProviderClass)
240
            : new $configProviderClass();
241
242
        if (! $provider instanceof UpgradeConfigInterface) {
243
            throw new RuntimeException(sprintf(
244
                'Upgrade config provider [%s] must implement %s.',
245
                $configProviderClass,
246
                UpgradeConfigInterface::class
247
            ));
248
        }
249
250
        $steps = $provider->steps();
251
252
        if (! is_array($steps)) {
0 ignored issues
show
introduced by
The condition is_array($steps) is always true.
Loading history...
253
            throw new RuntimeException(sprintf(
254
                'Upgrade config provider [%s] must return an array of step class names.',
255
                $configProviderClass
256
            ));
257
        }
258
259
        return $provider;
260
    }
261
262
    protected function extractMajorVersion(string $version): string
263
    {
264
        if (preg_match('/^(\d+)/', $version, $matches)) {
265
            return $matches[1];
266
        }
267
268
        return $version;
269
    }
270
}
271