Skip to content

Commit 6294a6c

Browse files
authored
Refactor compatibility checker (#256)
* refactor: rename include-vendor option to include-core in compatibility check command * feat: add validation for conflicting options in compatibility check command * feat: add --exclude-vendor option to compatibility check command * refactor: rename hasIncompatibilities to hasIssues in compatibility check logic * feat: enhance compatibility check with verbose output and add isHyvaAware determination logic * refactor: rename exclude-vendor option to include-vendor in compatibility check command
1 parent 5ada2dc commit 6294a6c

8 files changed

Lines changed: 170 additions & 43 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ All notable changes to this project will be documented in this file.
488488
- Scans Magento modules for Hyvä theme compatibility issues
489489
- Detects RequireJS, Knockout.js, jQuery, and UI Components usage
490490
- Interactive menu with Laravel Prompts for scan options
491-
- Options: `--show-all`, `--third-party-only`, `--include-vendor`, `--detailed`
491+
- Options: `--show-all`, `--third-party-only`, `--include-core`, `--include-vendor`, `--detailed`
492492
- Color-coded output (✓ Compatible, ⚠ Warnings, ✗ Incompatible)
493493
- Detailed file-level issues with line numbers
494494
- Exit code 1 for critical issues, 0 for success

docs/commands_reference.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,8 @@ bin/magento hyva:check
245245

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

251252
**Output:** Displays a table with compatibility status per module.

src/Console/Command/Hyva/CompatibilityCheckCommand.php

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class CompatibilityCheckCommand extends AbstractCommand
2828
{
2929
private const OPTION_SHOW_ALL = 'show-all';
3030
private const OPTION_THIRD_PARTY_ONLY = 'third-party-only';
31+
private const OPTION_INCLUDE_CORE = 'include-core';
3132
private const OPTION_INCLUDE_VENDOR = 'include-vendor';
3233
private const OPTION_DETAILED = 'detailed';
3334

@@ -71,11 +72,17 @@ protected function configure(): void
7172
'Check only third-party modules (exclude Magento_* modules)',
7273
)
7374
->addOption(
74-
self::OPTION_INCLUDE_VENDOR,
75+
self::OPTION_INCLUDE_CORE,
7576
null,
7677
InputOption::VALUE_NONE,
7778
'Include Magento core modules (default: third-party modules only)',
7879
)
80+
->addOption(
81+
self::OPTION_INCLUDE_VENDOR,
82+
null,
83+
InputOption::VALUE_NONE,
84+
'Include modules installed in the vendor directory (default: excluded)',
85+
)
7986
->addOption(
8087
self::OPTION_DETAILED,
8188
'd',
@@ -93,10 +100,18 @@ protected function configure(): void
93100
*/
94101
protected function executeCommand(InputInterface $input, OutputInterface $output): int
95102
{
103+
// Validate conflicting options early
104+
if ($input->getOption(self::OPTION_THIRD_PARTY_ONLY) && $input->getOption(self::OPTION_INCLUDE_CORE)) {
105+
$this->io->error('The options --third-party-only and --include-core cannot be used together.');
106+
107+
return Cli::RETURN_FAILURE;
108+
}
109+
96110
// Check if we're in interactive mode (no options provided)
97111
$hasOptions =
98112
(bool) $input->getOption(self::OPTION_SHOW_ALL)
99113
|| (bool) $input->getOption(self::OPTION_THIRD_PARTY_ONLY)
114+
|| (bool) $input->getOption(self::OPTION_INCLUDE_CORE)
100115
|| (bool) $input->getOption(self::OPTION_INCLUDE_VENDOR)
101116
|| (bool) $input->getOption(self::OPTION_DETAILED);
102117

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

136+
if ($this->isVerbose($output)) {
137+
$this->io->info('Running in interactive mode');
138+
}
139+
121140
// Set environment variables for Laravel Prompts
122141
$this->setPromptEnvironment();
123142

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

161181
// Show selected configuration
162182
$this->io->newLine();
@@ -168,15 +188,22 @@ private function runInteractiveMode(InputInterface $input, OutputInterface $outp
168188
} else {
169189
$config[] = 'Show modules with issues';
170190
}
171-
$config[] = $includeVendor ? 'Include Magento core' : 'Third-party modules only';
191+
$config[] = $includeCore ? 'Include Magento core' : 'Third-party modules only';
172192
if ($detailed) {
173193
$config[] = 'Detailed issues';
174194
}
175195
$this->io->comment('Configuration: ' . implode(', ', $config));
176196
$this->io->newLine();
177197

178198
// Run scan with selected options
179-
return $this->runScan($showAll, $thirdPartyOnly, $includeVendor, $detailed, $incompatibleOnly);
199+
return $this->runScan(
200+
$showAll,
201+
$thirdPartyOnly,
202+
$includeCore,
203+
$includeVendor,
204+
$detailed,
205+
$incompatibleOnly,
206+
);
180207
} catch (\Throwable $e) {
181208
$this->io->error('Interactive mode failed: ' . $e->getMessage());
182209
$this->io->info('Falling back to default scan (third-party modules only)...');
@@ -199,19 +226,32 @@ private function runDirectMode(InputInterface $input, OutputInterface $output):
199226
{
200227
$showAll = (bool) $input->getOption(self::OPTION_SHOW_ALL);
201228
$thirdPartyOnly = (bool) $input->getOption(self::OPTION_THIRD_PARTY_ONLY);
229+
$includeCore = (bool) $input->getOption(self::OPTION_INCLUDE_CORE);
202230
$includeVendor = (bool) $input->getOption(self::OPTION_INCLUDE_VENDOR);
203231
$detailed = (bool) $input->getOption(self::OPTION_DETAILED);
204232

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

207-
return $this->runScan($showAll, $thirdPartyOnly, $includeVendor, $detailed, false);
235+
if ($this->isVerbose($output)) {
236+
$this->io->info(sprintf(
237+
'Direct mode: showAll=%s, thirdPartyOnly=%s, includeCore=%s, includeVendor=%s, detailed=%s',
238+
$showAll ? 'true' : 'false',
239+
$thirdPartyOnly ? 'true' : 'false',
240+
$includeCore ? 'true' : 'false',
241+
$includeVendor ? 'true' : 'false',
242+
$detailed ? 'true' : 'false',
243+
));
244+
}
245+
246+
return $this->runScan($showAll, $thirdPartyOnly, $includeCore, $includeVendor, $detailed, false);
208247
}
209248

210249
/**
211250
* Run the actual compatibility scan
212251
*
213252
* @param bool $showAll
214253
* @param bool $thirdPartyOnly
254+
* @param bool $includeCore
215255
* @param bool $includeVendor
216256
* @param bool $detailed
217257
* @param bool $incompatibleOnly
@@ -220,19 +260,19 @@ private function runDirectMode(InputInterface $input, OutputInterface $output):
220260
private function runScan(
221261
bool $showAll,
222262
bool $thirdPartyOnly,
263+
bool $includeCore,
223264
bool $includeVendor,
224265
bool $detailed,
225266
bool $incompatibleOnly,
226267
): int {
227268
// Determine filter logic:
228-
// - thirdPartyOnly: Only scan non-Magento_* modules (default behavior)
229-
// - includeVendor: Also scan Magento_* core modules
230-
// - excludeVendor: Whether to exclude vendor/ directory (always false for now)
231-
$scanThirdPartyOnly = !$includeVendor;
232-
$excludeVendor = false;
269+
// - thirdPartyOnly: Only scan non-Magento_* modules
270+
// - includeCore: Also scan Magento_* core modules
271+
// - includeVendor: Whether to include modules installed in vendor/
272+
$scanThirdPartyOnly = $thirdPartyOnly || !$includeCore;
233273

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

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

246286
// Display detailed issues if requested
247-
if ($detailed && $results['hasIncompatibilities']) {
287+
if ($detailed && $results['hasIssues']) {
248288
$this->displayDetailedIssues($results);
249289
}
250290

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

254294
// Display recommendations if there are issues
255-
if ($results['hasIncompatibilities']) {
295+
if ($results['hasIssues']) {
256296
$this->displayRecommendations();
257297
}
258298

src/Service/Hyva/CompatibilityChecker.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
* @phpstan-type CheckResults array{
3535
* modules: array<string, ModuleEntry>,
3636
* summary: CheckSummary,
37-
* hasIncompatibilities: bool
37+
* hasIssues: bool
3838
* }
3939
*/
4040
class CompatibilityChecker
@@ -57,7 +57,7 @@ public function __construct(
5757
* @param bool $thirdPartyOnly Whether to scan only third-party modules (excludes Magento_* modules)
5858
* @param bool $excludeVendor Whether to exclude modules from the vendor/ directory
5959
* @return array<string, mixed> Results with structure: ['modules' => [], 'summary' => [],
60-
* 'hasIncompatibilities' => bool]
60+
* 'hasIssues' => bool]
6161
* @phpstan-return CheckResults
6262
*/
6363
public function check(
@@ -78,7 +78,7 @@ public function check(
7878
'criticalIssues' => 0,
7979
'warningIssues' => 0,
8080
],
81-
'hasIncompatibilities' => false,
81+
'hasIssues' => false,
8282
];
8383

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

124124
// Warnings alone still trigger the detail/recommendation display
125125
if ($hasWarnings) {
126-
$results['hasIncompatibilities'] = true;
126+
$results['hasIssues'] = true;
127127
}
128128

129129
if ($moduleInfo['isHyvaAware']) {

src/Service/Hyva/ModuleScanner.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,13 +174,33 @@ public function getModuleInfo(string $modulePath): array
174174
return [
175175
'name' => is_string($composerData['name'] ?? null) ? $composerData['name'] : 'Unknown',
176176
'version' => is_string($composerData['version'] ?? null) ? $composerData['version'] : 'Unknown',
177-
'isHyvaAware' => $this->isHyvaCompatibilityPackage($composerData),
177+
'isHyvaAware' => $this->isHyvaAware($modulePath, $composerData),
178178
];
179179
} catch (\Throwable $e) {
180180
return ['name' => 'Unknown', 'version' => 'Unknown', 'isHyvaAware' => false];
181181
}
182182
}
183183

184+
/**
185+
* Determine whether a module is Hyvä-aware.
186+
*
187+
* A module is considered Hyvä-aware when it either declares a Hyvä dependency,
188+
* is a Hyvä compatibility package, or ships a hyva-themes.json config.
189+
*
190+
* @param string $modulePath
191+
* @param array $composerData
192+
* @phpstan-param array<string, mixed> $composerData
193+
* @return bool
194+
*/
195+
private function isHyvaAware(string $modulePath, array $composerData): bool
196+
{
197+
if ($this->isHyvaCompatibilityPackage($composerData)) {
198+
return true;
199+
}
200+
201+
return $this->fileDriver->isExists($modulePath . '/hyva-themes.json');
202+
}
203+
184204
/**
185205
* Get basename without using basename().
186206
*

0 commit comments

Comments
 (0)