Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -488,7 +488,7 @@ All notable changes to this project will be documented in this file.
- Scans Magento modules for Hyvä theme compatibility issues
- Detects RequireJS, Knockout.js, jQuery, and UI Components usage
- Interactive menu with Laravel Prompts for scan options
- Options: `--show-all`, `--third-party-only`, `--include-vendor`, `--detailed`
- Options: `--show-all`, `--third-party-only`, `--include-core`, `--include-vendor`, `--detailed`
- Color-coded output (✓ Compatible, ⚠ Warnings, ✗ Incompatible)
- Detailed file-level issues with line numbers
- Exit code 1 for critical issues, 0 for success
Expand Down
3 changes: 2 additions & 1 deletion docs/commands_reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,8 @@ bin/magento hyva:check

- `-a, --show-all` — Show all modules including compatible ones.
- `-t, --third-party-only` — Check only third-party modules (exclude Magento\_\*).
- `--include-vendor` — Include Magento core modules in the check.
- `--include-core` — Include Magento core modules in the check.
- `--include-vendor` — Include modules installed in the vendor directory (default: excluded).
- `--detailed` — Show detailed compatibility information.

**Output:** Displays a table with compatibility status per module.
Expand Down
66 changes: 53 additions & 13 deletions src/Console/Command/Hyva/CompatibilityCheckCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class CompatibilityCheckCommand extends AbstractCommand
{
private const OPTION_SHOW_ALL = 'show-all';
private const OPTION_THIRD_PARTY_ONLY = 'third-party-only';
private const OPTION_INCLUDE_CORE = 'include-core';
private const OPTION_INCLUDE_VENDOR = 'include-vendor';
private const OPTION_DETAILED = 'detailed';

Expand Down Expand Up @@ -71,11 +72,17 @@ protected function configure(): void
'Check only third-party modules (exclude Magento_* modules)',
)
->addOption(
self::OPTION_INCLUDE_VENDOR,
self::OPTION_INCLUDE_CORE,
null,
InputOption::VALUE_NONE,
'Include Magento core modules (default: third-party modules only)',
)
->addOption(
self::OPTION_INCLUDE_VENDOR,
null,
InputOption::VALUE_NONE,
'Include modules installed in the vendor directory (default: excluded)',
)
->addOption(
self::OPTION_DETAILED,
'd',
Expand All @@ -93,10 +100,18 @@ protected function configure(): void
*/
protected function executeCommand(InputInterface $input, OutputInterface $output): int
{
// Validate conflicting options early
if ($input->getOption(self::OPTION_THIRD_PARTY_ONLY) && $input->getOption(self::OPTION_INCLUDE_CORE)) {
$this->io->error('The options --third-party-only and --include-core cannot be used together.');

return Cli::RETURN_FAILURE;
}

// Check if we're in interactive mode (no options provided)
$hasOptions =
(bool) $input->getOption(self::OPTION_SHOW_ALL)
|| (bool) $input->getOption(self::OPTION_THIRD_PARTY_ONLY)
|| (bool) $input->getOption(self::OPTION_INCLUDE_CORE)
|| (bool) $input->getOption(self::OPTION_INCLUDE_VENDOR)
|| (bool) $input->getOption(self::OPTION_DETAILED);

Expand All @@ -118,6 +133,10 @@ private function runInteractiveMode(InputInterface $input, OutputInterface $outp
{
$this->io->title('Hyvä Theme Compatibility Check');

if ($this->isVerbose($output)) {
$this->io->info('Running in interactive mode');
}

// Set environment variables for Laravel Prompts
$this->setPromptEnvironment();

Expand Down Expand Up @@ -155,8 +174,9 @@ private function runInteractiveMode(InputInterface $input, OutputInterface $outp
// Map selected options to flags
$showAll = $displayMode === self::DISPLAY_MODE_SHOW_ALL;
$incompatibleOnly = $displayMode === self::DISPLAY_MODE_INCOMPATIBLE_ONLY;
$includeVendor = $scope === self::SCOPE_ALL;
$includeCore = $scope === self::SCOPE_ALL;
$thirdPartyOnly = false; // Not needed in interactive mode
$includeVendor = false; // Vendor modules excluded by default in interactive mode

// Show selected configuration
$this->io->newLine();
Expand All @@ -168,15 +188,22 @@ private function runInteractiveMode(InputInterface $input, OutputInterface $outp
} else {
$config[] = 'Show modules with issues';
}
$config[] = $includeVendor ? 'Include Magento core' : 'Third-party modules only';
$config[] = $includeCore ? 'Include Magento core' : 'Third-party modules only';
if ($detailed) {
$config[] = 'Detailed issues';
}
$this->io->comment('Configuration: ' . implode(', ', $config));
$this->io->newLine();

// Run scan with selected options
return $this->runScan($showAll, $thirdPartyOnly, $includeVendor, $detailed, $incompatibleOnly);
return $this->runScan(
$showAll,
$thirdPartyOnly,
$includeCore,
$includeVendor,
$detailed,
$incompatibleOnly,
);
} catch (\Throwable $e) {
$this->io->error('Interactive mode failed: ' . $e->getMessage());
$this->io->info('Falling back to default scan (third-party modules only)...');
Expand All @@ -199,19 +226,32 @@ private function runDirectMode(InputInterface $input, OutputInterface $output):
{
$showAll = (bool) $input->getOption(self::OPTION_SHOW_ALL);
$thirdPartyOnly = (bool) $input->getOption(self::OPTION_THIRD_PARTY_ONLY);
$includeCore = (bool) $input->getOption(self::OPTION_INCLUDE_CORE);
$includeVendor = (bool) $input->getOption(self::OPTION_INCLUDE_VENDOR);
$detailed = (bool) $input->getOption(self::OPTION_DETAILED);
Comment on lines 227 to 231

$this->io->title('Hyvä Theme Compatibility Check');

return $this->runScan($showAll, $thirdPartyOnly, $includeVendor, $detailed, false);
if ($this->isVerbose($output)) {
$this->io->info(sprintf(
'Direct mode: showAll=%s, thirdPartyOnly=%s, includeCore=%s, includeVendor=%s, detailed=%s',
$showAll ? 'true' : 'false',
$thirdPartyOnly ? 'true' : 'false',
$includeCore ? 'true' : 'false',
$includeVendor ? 'true' : 'false',
$detailed ? 'true' : 'false',
));
}

return $this->runScan($showAll, $thirdPartyOnly, $includeCore, $includeVendor, $detailed, false);
}

/**
* Run the actual compatibility scan
*
* @param bool $showAll
* @param bool $thirdPartyOnly
* @param bool $includeCore
* @param bool $includeVendor
* @param bool $detailed
* @param bool $incompatibleOnly
Expand All @@ -220,19 +260,19 @@ private function runDirectMode(InputInterface $input, OutputInterface $output):
private function runScan(
bool $showAll,
bool $thirdPartyOnly,
bool $includeCore,
bool $includeVendor,
bool $detailed,
bool $incompatibleOnly,
): int {
// Determine filter logic:
// - thirdPartyOnly: Only scan non-Magento_* modules (default behavior)
// - includeVendor: Also scan Magento_* core modules
// - excludeVendor: Whether to exclude vendor/ directory (always false for now)
$scanThirdPartyOnly = !$includeVendor;
$excludeVendor = false;
// - thirdPartyOnly: Only scan non-Magento_* modules
// - includeCore: Also scan Magento_* core modules
// - includeVendor: Whether to include modules installed in vendor/
$scanThirdPartyOnly = $thirdPartyOnly || !$includeCore;

// Run the compatibility check
$results = $this->compatibilityChecker->check($this->io, $showAll, $scanThirdPartyOnly, $excludeVendor);
$results = $this->compatibilityChecker->check($this->io, $showAll, $scanThirdPartyOnly, !$includeVendor);

// Determine display mode:
// showAll = show all modules including compatible ones
Expand All @@ -244,15 +284,15 @@ private function runScan(
$this->displayResults($results, $displayShowAll);

// Display detailed issues if requested
if ($detailed && $results['hasIncompatibilities']) {
if ($detailed && $results['hasIssues']) {
$this->displayDetailedIssues($results);
}

// Display summary
$this->displaySummary($results['summary']);

// Display recommendations if there are issues
if ($results['hasIncompatibilities']) {
if ($results['hasIssues']) {
$this->displayRecommendations();
}

Expand Down
10 changes: 5 additions & 5 deletions src/Service/Hyva/CompatibilityChecker.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
* @phpstan-type CheckResults array{
* modules: array<string, ModuleEntry>,
* summary: CheckSummary,
* hasIncompatibilities: bool
* hasIssues: bool
* }
*/
class CompatibilityChecker
Expand All @@ -57,7 +57,7 @@ public function __construct(
* @param bool $thirdPartyOnly Whether to scan only third-party modules (excludes Magento_* modules)
* @param bool $excludeVendor Whether to exclude modules from the vendor/ directory
* @return array<string, mixed> Results with structure: ['modules' => [], 'summary' => [],
* 'hasIncompatibilities' => bool]
* 'hasIssues' => bool]
* @phpstan-return CheckResults
*/
public function check(
Expand All @@ -78,7 +78,7 @@ public function check(
'criticalIssues' => 0,
'warningIssues' => 0,
],
'hasIncompatibilities' => false,
'hasIssues' => false,
];

$io->text(sprintf('Scanning %d modules for Hyvä compatibility...', count($modules)));
Expand Down Expand Up @@ -118,12 +118,12 @@ public function check(
$results['summary']['compatible']++;
} else {
$results['summary']['incompatible']++;
$results['hasIncompatibilities'] = true;
$results['hasIssues'] = true;
}

// Warnings alone still trigger the detail/recommendation display
if ($hasWarnings) {
$results['hasIncompatibilities'] = true;
$results['hasIssues'] = true;
}

if ($moduleInfo['isHyvaAware']) {
Expand Down
22 changes: 21 additions & 1 deletion src/Service/Hyva/ModuleScanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -174,13 +174,33 @@ public function getModuleInfo(string $modulePath): array
return [
'name' => is_string($composerData['name'] ?? null) ? $composerData['name'] : 'Unknown',
'version' => is_string($composerData['version'] ?? null) ? $composerData['version'] : 'Unknown',
'isHyvaAware' => $this->isHyvaCompatibilityPackage($composerData),
'isHyvaAware' => $this->isHyvaAware($modulePath, $composerData),
];
} catch (\Throwable $e) {
return ['name' => 'Unknown', 'version' => 'Unknown', 'isHyvaAware' => false];
}
}

/**
* Determine whether a module is Hyvä-aware.
*
* A module is considered Hyvä-aware when it either declares a Hyvä dependency,
* is a Hyvä compatibility package, or ships a hyva-themes.json config.
*
* @param string $modulePath
* @param array $composerData
* @phpstan-param array<string, mixed> $composerData
* @return bool
*/
private function isHyvaAware(string $modulePath, array $composerData): bool
{
if ($this->isHyvaCompatibilityPackage($composerData)) {
return true;
}

return $this->fileDriver->isExists($modulePath . '/hyva-themes.json');
}

/**
* Get basename without using basename().
*
Expand Down
Loading
Loading