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 docs/commands.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ bin/magento mageforge:hyva:compatibility:check [options]
**Options**:

- `--show-all` / `-a` - Show all modules including compatible ones
- `--third-party-only` / `-t` - Check only third-party modules (exclude Magento\_\* modules)
- `--third-party-only` / `-t` - Check only third-party modules (exclude Magento_* modules)
- `--include-vendor` - Include Magento core modules in scan (default: third-party only)
- `--detailed` / `-d` - Show detailed file-level issues for incompatible modules

Expand Down
43 changes: 27 additions & 16 deletions src/Console/Command/Hyva/CompatibilityCheckCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,7 @@ private function runInteractiveMode(InputInterface $input, OutputInterface $outp
label: 'Select scan options',
options: [
'show-all' => 'Show all modules including compatible ones',
'incompatible-only' => 'Show only incompatible modules (default behavior)',
'include-vendor' => 'Include Magento core modules (default: third-party only)',
'include-vendor' => 'Include vendor modules (default: excluded)',
'detailed' => 'Show detailed file-level issues with line numbers',
],
default: [],
Expand All @@ -111,7 +110,6 @@ private function runInteractiveMode(InputInterface $input, OutputInterface $outp

// Apply selected options to input
$showAll = in_array('show-all', $selectedOptions);
$incompatibleOnly = in_array('incompatible-only', $selectedOptions);
$includeVendor = in_array('include-vendor', $selectedOptions);
$detailed = in_array('detailed', $selectedOptions);
$thirdPartyOnly = false; // Not needed in interactive mode
Expand All @@ -121,13 +119,11 @@ private function runInteractiveMode(InputInterface $input, OutputInterface $outp
$config = [];
if ($showAll) {
$config[] = 'Show all modules';
} elseif ($incompatibleOnly) {
$config[] = 'Show incompatible only';
} else {
$config[] = 'Show modules with issues';
}
if ($includeVendor) {
$config[] = 'Include Magento core';
$config[] = 'Include vendor modules';
} else {
$config[] = 'Third-party modules only';
}
Expand All @@ -137,8 +133,8 @@ private function runInteractiveMode(InputInterface $input, OutputInterface $outp
$this->io->comment('Configuration: ' . implode(', ', $config));
$this->io->newLine();

// Run scan with selected options (pass incompatibleOnly flag)
return $this->runScan($showAll, $thirdPartyOnly, $includeVendor, $detailed, $incompatibleOnly, $output);
// Run scan with selected options
return $this->runScan($showAll, $thirdPartyOnly, $includeVendor, $detailed, false, $output);
} catch (\Exception $e) {
$this->resetPromptEnvironment();
$this->io->error('Interactive mode failed: ' . $e->getMessage());
Expand Down Expand Up @@ -176,12 +172,11 @@ private function runScan(
): int {

// Determine filter logic for vendor and third-party modules:
// - excludeVendor controls whether to scan modules in the vendor/ directory
// - By default (no flags): scan third-party modules including those in vendor/
// - With --include-vendor: scan everything including Magento_* core modules
// - By default (no flags): scan third-party modules excluding those in vendor/
// - With --include-vendor: include vendor modules in the scan
// - With --third-party-only: explicitly scan only third-party modules
$scanThirdPartyOnly = $thirdPartyOnly || (!$includeVendor && !$thirdPartyOnly);
$excludeVendor = false; // Always include vendor for third-party scanning
$excludeVendor = !$includeVendor;

// Run the compatibility check
$results = $this->compatibilityChecker->check(
Expand Down Expand Up @@ -369,9 +364,25 @@ private function isInteractiveTerminal(OutputInterface $output): bool
}
}

// Additional check: try to detect if running in a proper TTY
$sttyOutput = shell_exec('stty -g 2>/dev/null');
return !empty($sttyOutput);
// Additional check: detect if running in a proper TTY using safer methods
if (\function_exists('stream_isatty') && \defined('STDIN')) {
try {
return \stream_isatty(\STDIN);
} catch (\Throwable $e) {
// Fall through to next check
}
}

if (\function_exists('posix_isatty') && \defined('STDIN')) {
try {
return \posix_isatty(\STDIN);
} catch (\Throwable $e) {
// Fall through to default
}
}

// Conservative default if no TTY-detection functions are available
return false;
}

/**
Expand Down Expand Up @@ -450,7 +461,7 @@ private function getServerVar(string $name): ?string
private function setEnvVar(string $name, string $value): void
{
$this->secureEnvStorage[$name] = $value;
putenv("$name=$value");
$_SERVER[$name] = $value;
}

/**
Expand Down
6 changes: 3 additions & 3 deletions src/Service/Hyva/IncompatibilityDetector.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class IncompatibilityDetector
'severity' => self::SEVERITY_WARNING,
],
[
'pattern' => '/(?:define|require)\s*\(\s*\[[^\]]*["\']mage\/[^"\']*["\']/',
'pattern' => '/(?:define|require)\s*\(\s*\[[^\]]*["\']mage\/[^"\']*["\']\s*[^\]]*\]/',
'description' => 'Magento RequireJS module reference',
'severity' => self::SEVERITY_CRITICAL,
],
Expand All @@ -65,7 +65,7 @@ class IncompatibilityDetector
'severity' => self::SEVERITY_CRITICAL,
],
[
'pattern' => '/<referenceBlock.*remove="true">/',
'pattern' => '/<referenceBlock\b[^>]*\bremove\s*=\s*"true"[^>]*>/s',
'description' => 'Block removal (review for Hyvä compatibility)',
'severity' => self::SEVERITY_WARNING,
],
Expand All @@ -82,7 +82,7 @@ class IncompatibilityDetector
'severity' => self::SEVERITY_CRITICAL,
],
[
'pattern' => '/\$\(.*\)\..*\(/',
'pattern' => '/\$\([^)]*\)\s*\.(on|click|ready|change|keyup|keydown|submit|ajax|each|css|hide|show|addClass|removeClass|toggleClass|append|prepend|html|text|val|attr|prop|data|trigger|find|parent|children)\s*\(/',
'description' => 'jQuery DOM manipulation',
'severity' => self::SEVERITY_WARNING,
],
Expand Down
42 changes: 16 additions & 26 deletions src/Service/Hyva/ModuleScanner.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,31 +107,7 @@ private function findRelevantFiles(string $directory): array
}

/**
* Check if module has Hyvä compatibility package based on composer data
*
* @param array $composerData Parsed composer.json data
*/
private function isHyvaCompatibilityPackage(array $composerData): bool
{
// Check if this IS a Hyvä compatibility package
$packageName = $composerData['name'] ?? '';
if (str_starts_with($packageName, 'hyva-themes/') && str_contains($packageName, '-compat')) {
return true;
}

// Check dependencies for Hyvä packages
$requires = $composerData['require'] ?? [];
foreach ($requires as $package => $version) {
if (str_starts_with($package, 'hyva-themes/')) {
return true;
}
}

return false;
}

/**
* Check if module has Hyvä compatibility package (public wrapper)
* Check if module has Hyvä compatibility package
*/
public function hasHyvaCompatibilityPackage(string $modulePath): bool
{
Expand All @@ -149,7 +125,21 @@ public function hasHyvaCompatibilityPackage(string $modulePath): bool
return false;
}

return $this->isHyvaCompatibilityPackage($composerData);
// Check if this IS a Hyvä compatibility package
$packageName = $composerData['name'] ?? '';
if (str_starts_with($packageName, 'hyva-themes/') && str_contains($packageName, '-compat')) {
return true;
}

// Check dependencies for Hyvä packages
$requires = $composerData['require'] ?? [];
foreach ($requires as $package => $version) {
if (str_starts_with($package, 'hyva-themes/')) {
return true;
}
}

return false;
} catch (\Exception $e) {
// Log error when debugging to help identify JSON or file read issues
if (getenv('MAGEFORGE_DEBUG')) {
Expand Down
36 changes: 3 additions & 33 deletions src/etc/di.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,6 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:framework:ObjectManager/etc/config.xsd"
>
<type name="Magento\Framework\Console\CommandList">
<arguments>
<argument
name="commands"
xsi:type="array"
>
<item name="mageforge_system_version"
xsi:type="object"
>
OpenForgeProject\MageForge\Console\Command\System\VersionCommand</item>
<item name="mageforge_system_check"
xsi:type="object"
>
OpenForgeProject\MageForge\Console\Command\System\CheckCommand</item>
<item name="mageforge_theme_list"
xsi:type="object"
>
OpenForgeProject\MageForge\Console\Command\Theme\ListCommand</item>
<item name="mageforge_theme_build"
xsi:type="object"
>
OpenForgeProject\MageForge\Console\Command\Theme\BuildCommand</item>
<item name="mageforge_theme_watch"
xsi:type="object"
>
OpenForgeProject\MageForge\Console\Command\Theme\WatchCommand</item>
<item name="mageforge_hyva_compatibility_check"
xsi:type="object"
>
OpenForgeProject\MageForge\Console\Command\Hyva\CompatibilityCheckCommand</item>
</argument>
</arguments>
</type>
<type name="Magento\Framework\Console\CommandList">
<arguments>
<argument
Expand All @@ -60,6 +27,9 @@
<item name="mageforge_static_clean"
xsi:type="object"
>OpenForgeProject\MageForge\Console\Command\Static\CleanCommand</item>
<item name="mageforge_hyva_compatibility_check"
xsi:type="object"
>OpenForgeProject\MageForge\Console\Command\Hyva\CompatibilityCheckCommand</item>
</argument>
</arguments>
</type>
Expand Down