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

UpgradeContext::targetVersion()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 1
c 1
b 0
f 1
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php
2
3
namespace Backpack\CRUD\app\Console\Commands\Upgrade;
4
5
use Composer\InstalledVersions;
6
use Illuminate\Filesystem\Filesystem;
7
use Illuminate\Support\Arr;
8
9
class UpgradeContext
10
{
11
    protected Filesystem $files;
12
13
    protected string $basePath;
14
15
    protected array $composerJson = [];
16
17
    protected array $searchCache = [];
18
19
    protected array $fileCache = [];
20
21
    protected array $defaultScanDirectories = [
22
        'app',
23
        'config',
24
        'resources/views',
25
        'resources/lang',
26
        'routes',
27
        'database/factories',
28
        'database/seeders',
29
    ];
30
31
    protected array $searchableExtensions = ['php'];
32
33
    protected array $addons = [];
34
35
    public function __construct(
36
        protected readonly string $targetVersion,
37
        ?Filesystem $filesystem = null,
38
        ?string $basePath = null,
39
        array $addons = []
40
    ) {
41
        $this->files = $filesystem ?? new Filesystem();
42
        $this->basePath = $this->normalizePath($basePath ?? $this->defaultBasePath());
43
        $this->addons = $addons;
44
    }
45
46
    public function targetVersion(): string
47
    {
48
        return $this->targetVersion;
49
    }
50
51
    public function addons(): array
52
    {
53
        return $this->addons;
54
    }
55
56
    public function basePath(string $path = ''): string
57
    {
58
        $path = ltrim($path, '/\\');
59
60
        return $this->normalizePath($this->basePath.($path !== '' ? '/'.$path : ''));
61
    }
62
63
    public function fileExists(string $relativePath): bool
64
    {
65
        return $this->files->exists($this->basePath($relativePath));
66
    }
67
68
    public function readFile(string $relativePath): ?string
69
    {
70
        if (isset($this->fileCache[$relativePath])) {
71
            return $this->fileCache[$relativePath];
72
        }
73
74
        $fullPath = $this->basePath($relativePath);
75
76
        if (! $this->files->exists($fullPath)) {
77
            return null;
78
        }
79
80
        try {
81
            return $this->fileCache[$relativePath] = $this->files->get($fullPath);
82
        } catch (\Throwable $exception) {
83
            return null;
84
        }
85
    }
86
87
    public function composerJson(): array
88
    {
89
        if (! empty($this->composerJson)) {
90
            return $this->composerJson;
91
        }
92
93
        $content = $this->readFile('composer.json');
94
95
        if (! $content) {
96
            return $this->composerJson = [];
97
        }
98
99
        return $this->composerJson = json_decode($content, true) ?? [];
100
    }
101
102
    public function composerRequirement(string $package): ?string
103
    {
104
        $composer = $this->composerJson();
105
106
        return Arr::get($composer, "require.$package") ?? Arr::get($composer, "require-dev.$package");
107
    }
108
109
    public function composerRequirementSection(string $package): ?string
110
    {
111
        $composer = $this->composerJson();
112
113
        if (array_key_exists($package, $composer['require'] ?? [])) {
114
            return 'require';
115
        }
116
117
        if (array_key_exists($package, $composer['require-dev'] ?? [])) {
118
            return 'require-dev';
119
        }
120
121
        return null;
122
    }
123
124
    public function hasComposerPackage(string $package): bool
125
    {
126
        return $this->composerRequirement($package) !== null;
127
    }
128
129
    public function composerMinimumStability(): ?string
130
    {
131
        $composer = $this->composerJson();
132
133
        return $composer['minimum-stability'] ?? null;
134
    }
135
136
    public function installedPackageVersion(string $package): ?string
137
    {
138
        if (! InstalledVersions::isInstalled($package)) {
139
            return null;
140
        }
141
142
        return InstalledVersions::getVersion($package) ?? InstalledVersions::getPrettyVersion($package);
143
    }
144
145
    public function installedPackagePrettyVersion(string $package): ?string
146
    {
147
        if (! InstalledVersions::isInstalled($package)) {
148
            return null;
149
        }
150
151
        return InstalledVersions::getPrettyVersion($package);
152
    }
153
154
    public function packageMajorVersion(string $package): ?int
155
    {
156
        $pretty = $this->installedPackagePrettyVersion($package);
157
158
        if (! $pretty) {
159
            return null;
160
        }
161
162
        if (preg_match('/(\d+)/', $pretty, $matches)) {
163
            return (int) $matches[1];
164
        }
165
166
        return null;
167
    }
168
169
    public function searchTokens(array $tokens, ?array $directories = null): array
170
    {
171
        sort($tokens);
172
173
        $directories = $directories ?? $this->defaultScanDirectories;
174
175
        $cacheKey = md5(json_encode([$tokens, $directories]));
176
177
        if (isset($this->searchCache[$cacheKey])) {
178
            return $this->searchCache[$cacheKey];
179
        }
180
181
        $results = array_fill_keys($tokens, []);
182
183
        foreach ($directories as $directory) {
184
            $absoluteDirectory = $this->resolvePath($directory);
185
186
            if (! $this->files->isDirectory($absoluteDirectory)) {
187
                continue;
188
            }
189
190
            foreach ($this->files->allFiles($absoluteDirectory) as $file) {
191
                $path = $file->getRealPath();
192
193
                if ($path === false) {
194
                    continue;
195
                }
196
197
                if ($this->shouldSkipFile($file->getFilename())) {
198
                    continue;
199
                }
200
201
                try {
202
                    $contents = $this->files->get($path);
203
                } catch (\Throwable $exception) {
204
                    continue;
205
                }
206
207
                foreach ($tokens as $token) {
208
                    if (str_contains($contents, $token)) {
209
                        $results[$token][] = $this->relativePath($path);
210
                    }
211
                }
212
            }
213
        }
214
215
        foreach ($results as $token => $paths) {
216
            $results[$token] = array_values(array_unique($paths));
217
        }
218
219
        return $this->searchCache[$cacheKey] = $results;
220
    }
221
222
    public function defaultScanDirectories(): array
223
    {
224
        return $this->defaultScanDirectories;
225
    }
226
227
    public function writeFile(string $relativePath, string $contents): bool
228
    {
229
        $fullPath = $this->basePath($relativePath);
230
231
        try {
232
            $this->files->ensureDirectoryExists(dirname($fullPath));
233
            $this->files->put($fullPath, $contents);
234
            $this->fileCache[$relativePath] = $contents;
235
236
            if ($relativePath === 'composer.json') {
237
                $this->composerJson = json_decode($contents, true) ?? [];
238
            }
239
240
            return true;
241
        } catch (\Throwable $exception) {
242
            return false;
243
        }
244
    }
245
246
    public function deleteFile(string $relativePath): bool
247
    {
248
        $fullPath = $this->basePath($relativePath);
249
250
        try {
251
            if (! $this->files->exists($fullPath)) {
252
                return true;
253
            }
254
255
            $this->files->delete($fullPath);
256
            unset($this->fileCache[$relativePath]);
257
258
            if ($relativePath === 'composer.json') {
259
                $this->composerJson = [];
260
            }
261
262
            return true;
263
        } catch (\Throwable $exception) {
264
            return false;
265
        }
266
    }
267
268
    public function updateComposerJson(callable $callback): bool
269
    {
270
        $composer = $this->composerJson();
271
272
        $updatedComposer = $composer;
273
274
        $callback($updatedComposer);
275
276
        if ($updatedComposer === $composer) {
277
            return true;
278
        }
279
280
        $encoded = json_encode($updatedComposer, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
281
282
        if ($encoded === false) {
283
            return false;
284
        }
285
286
        return $this->writeFile('composer.json', $encoded.PHP_EOL);
287
    }
288
289
    public function relativePath(string $absolutePath): string
290
    {
291
        $normalized = $this->normalizePath($absolutePath);
292
293
        if (str_starts_with($normalized, $this->basePath.'/')) {
294
            return substr($normalized, strlen($this->basePath) + 1);
295
        }
296
297
        return $normalized;
298
    }
299
300
    protected function resolvePath(string $path): string
301
    {
302
        if ($this->files->isDirectory($path) || $this->files->exists($path)) {
303
            return $this->normalizePath($path);
304
        }
305
306
        return $this->basePath($path);
307
    }
308
309
    protected function shouldSkipFile(string $filename): bool
310
    {
311
        $extension = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
0 ignored issues
show
Bug introduced by
It seems like pathinfo($filename, Back...ade\PATHINFO_EXTENSION) can also be of type array; however, parameter $string of strtolower() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

311
        $extension = strtolower(/** @scrutinizer ignore-type */ pathinfo($filename, PATHINFO_EXTENSION));
Loading history...
312
313
        if (! in_array($extension, $this->searchableExtensions, true)) {
314
            return true;
315
        }
316
317
        return false;
318
    }
319
320
    protected function normalizePath(string $path): string
321
    {
322
        $path = str_replace(['\\', '//'], '/', $path);
323
324
        return rtrim($path, '/');
325
    }
326
327
    protected function defaultBasePath(): string
328
    {
329
        return $this->normalizePath(base_path());
330
    }
331
}
332