Skip to content

Check plugins compatibility when upgrading to v4 #17280

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 24 commits into from
Aug 18, 2025
Merged
Changes from 3 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
236edaf
Add a command that checks plugins compatibility with v4
CharlieEtienne Aug 12, 2025
f631ae7
Fix class name
CharlieEtienne Aug 12, 2025
5a1d387
chore: fix code style
CharlieEtienne Aug 12, 2025
c7eee71
Fix missing import
CharlieEtienne Aug 12, 2025
7fbac9d
Refactor package compatibility check to use local composer.json inste…
CharlieEtienne Aug 12, 2025
4bb1c98
chore: fix code style
CharlieEtienne Aug 12, 2025
eb7412d
Add CheckPluginsCompatibilityWithV4 command to UpgradeServiceProvider
CharlieEtienne Aug 12, 2025
13b4ee5
properly exclude filament itself
CharlieEtienne Aug 12, 2025
4aa58f4
fix plugin compatibility check to not skip Filament packages
CharlieEtienne Aug 13, 2025
1aa0708
Update upgrade script
CharlieEtienne Aug 13, 2025
3043d96
chore: fix code style
CharlieEtienne Aug 13, 2025
2ae97eb
fix ci
CharlieEtienne Aug 13, 2025
b5052d3
Merge remote-tracking branch 'origin/patch-2' into patch-2
CharlieEtienne Aug 13, 2025
f82ab72
remove the separate command
CharlieEtienne Aug 14, 2025
ae4affc
Merge branch '4.x' into pr/17280
danharrin Aug 18, 2025
9a182c4
clean up
danharrin Aug 18, 2025
950d879
add PHP and Laravel version checks
danharrin Aug 18, 2025
4f840f1
start suggesting plugin requirement commands
danharrin Aug 18, 2025
d3e94a8
Update filament-v4
danharrin Aug 18, 2025
fe9b44e
check for any filament/* paclage
danharrin Aug 18, 2025
80c585b
Tailwind cmd
danharrin Aug 18, 2025
758807c
Update UpgradeTailwindToV4Command.php
danharrin Aug 18, 2025
db7d773
Update UpgradeTailwindToV4Command.php
danharrin Aug 18, 2025
8c071ef
Update UpgradeTailwindToV4Command.php
danharrin Aug 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
208 changes: 208 additions & 0 deletions packages/upgrade/src/Commands/CheckPluginsCompatibilityWithV4.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,208 @@
<?php

namespace Filament\Upgrade\Commands;

use Exception;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Http;

#[AsCommand(name: 'filament:check-plugins-compatibility-with-v4')]
class CheckPluginsCompatibilityWithV4 extends Command
{
/**
* The name and signature of the console command.
*/
protected $signature = 'filament:check-plugins-compatibility-with-v4';

/**
* The console command description.
*/
protected $description = 'Check if installed Filament plugins are compatible with Filament v4';

/**
* Execute the console command.
*/
public function handle(): int
{
$composerPath = base_path('composer.json');

if (! file_exists($composerPath)) {
$this->error('composer.json not found.');

return 1;
}

$composer = json_decode(file_get_contents($composerPath), true);
$dependencies = $composer['require'] ?? [];

$allPackages = collect($dependencies)->keys();

// Filter packages to only those that require filament/filament
$filamentPlugins = $allPackages->filter(function ($package) {
return $this->packageRequiresFilament($package);
});

$this->info('Found ' . $filamentPlugins->count() . ' packages that require filament/filament');

$results = [];

foreach ($filamentPlugins as $package) {
$compatibility = $this->checkFilamentV4Compatibility($package);
$versionDisplay = '–';

if ($compatibility !== null) {
$versionDisplay = $compatibility['version'];
if ($compatibility['isPrerelease']) {
$versionDisplay .= ' (prerelease)';
}
}

$results[] = [
'package' => $package,
'installed' => $dependencies[$package],
'compatible' => $compatibility ? '✅' : '❌',
'latest_v4_version' => $versionDisplay,
];
}

// Display result in a formatted table
$this->table(
['Package', 'Installed Version', 'Compatible with v4?', 'Latest Compatible v4 Version'],
$results
);

return 0;
}

/**
* Checks on Packagist whether the given package has any version compatible with Filament v4.
*
* @param string $package The full package name (e.g. vendor/package)
* @return array|null Array with version string and isPrerelease flag, or null if not found
*/
protected function checkFilamentV4Compatibility(string $package): ?array
{
// First check regular releases
$url = "https://repo.packagist.org/p2/{$package}.json";
$compatibleVersion = $this->checkPackageCompatibility($package, $url);

if ($compatibleVersion !== null) {
return [
'version' => $compatibleVersion,
'isPrerelease' => false,
];
}

// If no compatible version found, check dev versions
$devUrl = "https://repo.packagist.org/p2/{$package}~dev.json";
$compatibleVersion = $this->checkPackageCompatibility($package, $devUrl);

if ($compatibleVersion !== null) {
return [
'version' => $compatibleVersion,
'isPrerelease' => true,
];
}

return null;
}

/**
* Checks a specific package URL for Filament v4 compatibility
*
* @param string $package The full package name
* @param string $url The Packagist API URL to check
* @return string|null The compatible version string or null if not found
*/
protected function checkPackageCompatibility(string $package, string $url): ?string
{
try {
$response = Http::get($url);

if (! $response->ok()) {
return null;
}

$data = $response->json();
$versions = $data['packages'][$package] ?? [];

foreach ($versions as $version) {
$requires = $version['require'] ?? [];

if (isset($requires['filament/filament'])) {
$constraint = $requires['filament/filament'];

// Match common constraint patterns for v4
if (preg_match('/\^4\.|~4\.|>=4\./', $constraint)) {
return $version['version'];
}
}
}

} catch (Exception $e) {
$this->error("Error checking {$package} at {$url}: " . $e->getMessage());
}

return null;
}

/**
* Checks if a package requires filament/filament
*
* @param string $package The full package name
* @return bool True if the package requires filament/filament
*/
protected function packageRequiresFilament(string $package): bool
{
// Skip filament/filament itself
if ($package === 'filament/filament') {
return true;
}

// Skip filament/* packages as they're part of the Filament ecosystem
if (str_starts_with($package, 'filament/')) {
return true;
}

try {
// Check regular releases
$url = "https://repo.packagist.org/p2/{$package}.json";
$response = Http::get($url);

if ($response->ok()) {
$data = $response->json();
$versions = $data['packages'][$package] ?? [];

// Check all versions, not just the latest
foreach ($versions as $version) {
$requires = $version['require'] ?? [];

if (isset($requires['filament/filament'])) {
return true;
}
}
}

// If not found in regular releases, check dev versions
$devUrl = "https://repo.packagist.org/p2/{$package}~dev.json";
$devResponse = Http::get($devUrl);

if ($devResponse->ok()) {
$devData = $devResponse->json();
$devVersions = $devData['packages'][$package] ?? [];

foreach ($devVersions as $version) {
$requires = $version['require'] ?? [];

if (isset($requires['filament/filament'])) {
return true;
}
}
}
} catch (Exception $e) {
$this->error("Error checking if {$package} requires filament/filament: " . $e->getMessage());
}

return false;
}
}