Skip to content

Commit cb4bdb4

Browse files
authored
add upgrade command (#5882)
This adds the `backpack:upgrade` command. It is a framework for us to build interactive upgrade guides that will ease out the life of our developers. At the moment is has the steps for v6->v7 upgrade.
1 parent d3a2ba4 commit cb4bdb4

23 files changed

+3866
-0
lines changed

src/BackpackServiceProvider.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class BackpackServiceProvider extends ServiceProvider
2828
app\Console\Commands\CreateUser::class,
2929
app\Console\Commands\PublishBackpackMiddleware::class,
3030
app\Console\Commands\PublishView::class,
31+
app\Console\Commands\Upgrade\UpgradeCommand::class,
3132
app\Console\Commands\Addons\RequireDevTools::class,
3233
app\Console\Commands\Addons\RequireEditableColumns::class,
3334
app\Console\Commands\Addons\RequirePro::class,
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace Backpack\CRUD\app\Console\Commands\Upgrade\Concerns;
4+
5+
trait ExtractsFirstInteger
6+
{
7+
/**
8+
* Extract the first integer occurrence from the given string.
9+
*/
10+
protected function extractFirstInteger(string $value): ?int
11+
{
12+
if (preg_match('/(\d+)/', $value, $matches)) {
13+
return (int) $matches[1];
14+
}
15+
16+
return null;
17+
}
18+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
namespace Backpack\CRUD\app\Console\Commands\Upgrade\Concerns;
4+
5+
use Backpack\CRUD\app\Console\Commands\Upgrade\UpgradeContext;
6+
7+
/**
8+
* @mixin \Backpack\CRUD\app\Console\Commands\Upgrade\Step
9+
*/
10+
trait InteractsWithCrudControllers
11+
{
12+
/**
13+
* Filter a list of file paths.
14+
*/
15+
protected function filterCrudControllerPaths(array $paths, ?callable $contentsValidator = null): array
16+
{
17+
if (empty($paths)) {
18+
return [];
19+
}
20+
21+
$filtered = [];
22+
23+
foreach ($paths as $path) {
24+
if (! $this->isCrudControllerPath($path)) {
25+
continue;
26+
}
27+
28+
$contents = $this->context()->readFile($path);
29+
30+
if ($contents === null) {
31+
continue;
32+
}
33+
34+
if ($contentsValidator !== null && $contentsValidator($contents, $path) !== true) {
35+
continue;
36+
}
37+
38+
$filtered[] = $path;
39+
}
40+
41+
return $filtered;
42+
}
43+
44+
protected function isCrudControllerPath(string $path): bool
45+
{
46+
return str_contains($path, 'CrudController');
47+
}
48+
49+
abstract protected function context(): UpgradeContext;
50+
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
<?php
2+
3+
namespace Backpack\CRUD\app\Console\Commands\Upgrade;
4+
5+
use Backpack\CRUD\app\Console\Commands\Upgrade\Concerns\ExtractsFirstInteger;
6+
7+
abstract class Step
8+
{
9+
use ExtractsFirstInteger;
10+
11+
public function __construct(protected UpgradeContext $context)
12+
{
13+
}
14+
15+
abstract public function title(): string;
16+
17+
public function description(): ?string
18+
{
19+
return null;
20+
}
21+
22+
abstract public function run(): StepResult;
23+
24+
protected function context(): UpgradeContext
25+
{
26+
return $this->context;
27+
}
28+
29+
public function canFix(StepResult $result): bool
30+
{
31+
return false;
32+
}
33+
34+
public function fixMessage(StepResult $result): string
35+
{
36+
return 'Apply automatic fix?';
37+
}
38+
39+
public function fix(StepResult $result): StepResult
40+
{
41+
return StepResult::skipped('No automatic fix available.');
42+
}
43+
44+
/**
45+
* Provide optional choices for automatic fixes. When empty, a yes/no confirmation is shown.
46+
*
47+
* @return array<int|string, mixed>
48+
*/
49+
public function fixOptions(StepResult $result): array
50+
{
51+
return [];
52+
}
53+
54+
public function selectFixOption(?string $option): void
55+
{
56+
}
57+
58+
public function isBlocking(): bool
59+
{
60+
return false;
61+
}
62+
63+
/**
64+
* Build a preview of items with an optional formatter and overflow message.
65+
*
66+
* @param array<int, mixed> $items
67+
* @param callable|null $formatter
68+
* @return array<int, string>
69+
*/
70+
protected function previewList(
71+
array $items,
72+
int $limit = 10,
73+
?callable $formatter = null,
74+
?string $overflowMessage = null
75+
): array {
76+
if (empty($items)) {
77+
return [];
78+
}
79+
80+
$formatter ??= static fn ($item): string => '- '.(string) $item;
81+
$preview = array_slice($items, 0, $limit);
82+
$details = array_map($formatter, $preview);
83+
84+
$remaining = count($items) - count($preview);
85+
86+
if ($remaining > 0) {
87+
$details[] = sprintf($overflowMessage ?? '... %d more item(s) omitted.', $remaining);
88+
}
89+
90+
return $details;
91+
}
92+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
<?php
2+
3+
namespace Backpack\CRUD\app\Console\Commands\Upgrade;
4+
5+
class StepResult
6+
{
7+
public function __construct(
8+
public readonly StepStatus $status,
9+
public readonly string $summary,
10+
public readonly array $details = [],
11+
public readonly array $context = []
12+
) {
13+
}
14+
15+
public static function success(string $summary, array $details = [], array $context = []): self
16+
{
17+
return new self(StepStatus::Passed, $summary, $details, $context);
18+
}
19+
20+
public static function warning(string $summary, array $details = [], array $context = []): self
21+
{
22+
return new self(StepStatus::Warning, $summary, $details, $context);
23+
}
24+
25+
public static function failure(string $summary, array $details = [], array $context = []): self
26+
{
27+
return new self(StepStatus::Failed, $summary, $details, $context);
28+
}
29+
30+
public static function skipped(string $summary, array $details = [], array $context = []): self
31+
{
32+
return new self(StepStatus::Skipped, $summary, $details, $context);
33+
}
34+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php
2+
3+
namespace Backpack\CRUD\app\Console\Commands\Upgrade;
4+
5+
enum StepStatus: string
6+
{
7+
case Passed = 'passed';
8+
case Warning = 'warning';
9+
case Failed = 'failed';
10+
case Skipped = 'skipped';
11+
12+
public function label(): string
13+
{
14+
return match ($this) {
15+
self::Passed => 'done',
16+
self::Warning => 'warn',
17+
self::Failed => 'fail',
18+
self::Skipped => 'skip',
19+
};
20+
}
21+
22+
public function color(): string
23+
{
24+
return match ($this) {
25+
self::Passed => 'green',
26+
self::Warning => 'yellow',
27+
self::Failed => 'red',
28+
self::Skipped => 'gray',
29+
};
30+
}
31+
32+
public function isFailure(): bool
33+
{
34+
return $this === self::Failed;
35+
}
36+
37+
public function isWarning(): bool
38+
{
39+
return $this === self::Warning;
40+
}
41+
}

0 commit comments

Comments
 (0)