From c51dcea6347b06eddcbc9d34bc1e09ee6225da0f Mon Sep 17 00:00:00 2001 From: Thomas Hauschild <7961978+Morgy93@users.noreply.github.com> Date: Sat, 4 Jul 2026 20:16:37 +0200 Subject: [PATCH 1/4] feat: enhance static analysis and command checks --- .github/workflows/static-analysis.yml | 4 +++- mago.toml | 4 ++++ src/Console/Command/AbstractCommand.php | 4 ++-- src/Console/Command/System/CheckCommand.php | 8 ++++++-- src/Console/Command/Theme/BuildCommand.php | 1 + src/Console/Command/Theme/CleanCommand.php | 13 +++++++++---- src/Console/Command/Theme/TokensCommand.php | 2 +- src/Service/StandardThemeBuilder.php | 12 +++++++++--- 8 files changed, 35 insertions(+), 13 deletions(-) diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index 1c17adfb..b07338bb 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -207,7 +207,9 @@ jobs: # graph. Only the module source is analyzed; phtml templates and the # Magento-idiomatic `mixed-*` codes are filtered via mago.toml. The Mago # binary and config come from the separate module checkout (its - # require-dev isn't part of the artifact). + # require-dev isn't part of the artifact). mago.toml sets + # `minimum-fail-level = "note"`, so any finding (including warnings and + # help messages) fails this job — green means a completely clean report. - name: Mago analyze working-directory: magento2 run: | diff --git a/mago.toml b/mago.toml index d4826339..63b32821 100644 --- a/mago.toml +++ b/mago.toml @@ -16,6 +16,10 @@ inline-empty-constructor-braces = false inline-empty-classlike-braces = false [analyzer] +# Fail on every reported finding (notes, help, warnings, errors) — not just +# errors. Keeps `ddev mago analyze` and the CI job red until the report is +# completely clean instead of silently passing with warnings. +minimum-fail-level = "note" # phtml templates rely on variables ($block, $escaper, $secureRenderer, …) that # Magento's template engine injects into the render scope at runtime. A static # analyzer cannot know them, so every template would report "undefined variable" diff --git a/src/Console/Command/AbstractCommand.php b/src/Console/Command/AbstractCommand.php index 8175676d..34e5f706 100644 --- a/src/Console/Command/AbstractCommand.php +++ b/src/Console/Command/AbstractCommand.php @@ -209,8 +209,8 @@ protected function isInteractiveTerminal(OutputInterface $output): bool return false; } - // Check if STDIN is available - if (!defined('STDIN') || !is_resource(STDIN)) { + // Check if STDIN is available (undefined outside the CLI SAPI) + if (!defined('STDIN')) { return false; } diff --git a/src/Console/Command/System/CheckCommand.php b/src/Console/Command/System/CheckCommand.php index c304aaa7..a80e7ea1 100644 --- a/src/Console/Command/System/CheckCommand.php +++ b/src/Console/Command/System/CheckCommand.php @@ -235,6 +235,7 @@ private function getMysqlVersionViaClient(): ?string } if ($output !== '') { + $matches = []; preg_match('/Distrib ([0-9.]+)/', $output, $matches); return isset($matches[1]) ? $matches[1] : null; } @@ -279,6 +280,7 @@ private function getComposerVersion(): string return 'Not installed'; } + $matches = []; preg_match('/Composer version ([^ ]+)/', $output, $matches); return isset($matches[1]) ? $matches[1] : 'Unknown'; } @@ -316,6 +318,7 @@ private function getGitVersion(): string return 'Not installed'; } + $matches = []; preg_match('/git version (.+)/', $output, $matches); return isset($matches[1]) ? $matches[1] : 'Unknown'; } @@ -780,8 +783,9 @@ private function getValueFromEnvironmentService($objectManager, string $name): ? try { $environmentService = $objectManager->get(\Magento\Framework\App\EnvironmentInterface::class); $method = 'get' . str_replace(' ', '', ucwords(str_replace('_', ' ', strtolower($name)))); - if (is_object($environmentService) && method_exists($environmentService, $method)) { - $value = $environmentService->$method(); + $getter = [$environmentService, $method]; + if (is_callable($getter)) { + $value = $getter(); if ($value !== null) { return (string) $value; } diff --git a/src/Console/Command/Theme/BuildCommand.php b/src/Console/Command/Theme/BuildCommand.php index b97122ed..b33a3acf 100644 --- a/src/Console/Command/Theme/BuildCommand.php +++ b/src/Console/Command/Theme/BuildCommand.php @@ -375,6 +375,7 @@ private function displayBuildSummary(SymfonyStyle $io, array $successList, float $themeName = $parts[0]; $details = $parts[1]; // Color the builder name in magenta + $matches = []; if (preg_match('/(using\s+)([^\s]+)(\s+builder)/', $details, $matches)) { $details = str_replace( $matches[0], diff --git a/src/Console/Command/Theme/CleanCommand.php b/src/Console/Command/Theme/CleanCommand.php index 293d12a4..4738840e 100644 --- a/src/Console/Command/Theme/CleanCommand.php +++ b/src/Console/Command/Theme/CleanCommand.php @@ -21,6 +21,13 @@ */ class CleanCommand extends AbstractCommand { + /** + * Tracks whether the theme-independent directories were already cleaned in this run. + * + * @var bool + */ + private bool $globalCleaned = false; + /** * @param ThemeCleaner $themeCleaner * @param ThemeList $themeList @@ -329,17 +336,15 @@ private function displayThemeHeader(string $themeName, int $currentTheme, int $t */ private function cleanThemeDirectories(string $themeName, bool $dryRun): int { - static $globalCleaned = false; - $cleaned = 0; $cleaned += $this->themeCleaner->cleanViewPreprocessed($themeName, $this->io, $dryRun, true); $cleaned += $this->themeCleaner->cleanPubStatic($themeName, $this->io, $dryRun, true); - if (!$globalCleaned) { + if (!$this->globalCleaned) { $cleaned += $this->themeCleaner->cleanPageCache($this->io, $dryRun, true); $cleaned += $this->themeCleaner->cleanVarTmp($this->io, $dryRun, true); $cleaned += $this->themeCleaner->cleanGenerated($this->io, $dryRun, true); - $globalCleaned = true; + $this->globalCleaned = true; } return $cleaned; } diff --git a/src/Console/Command/Theme/TokensCommand.php b/src/Console/Command/Theme/TokensCommand.php index a00bdd36..42573320 100644 --- a/src/Console/Command/Theme/TokensCommand.php +++ b/src/Console/Command/Theme/TokensCommand.php @@ -258,7 +258,7 @@ private function handleOutputFile(string $tailwindPath, string $themePath, strin */ private function copyToVarGenerated(string $sourceFilePath, string $themeCode): string { - $currentDir = getcwd(); + $currentDir = getcwd() ?: '.'; $varGeneratedPath = $currentDir . '/var/generated/hyva-token/' . str_replace('/', '/', $themeCode); if (!$this->fileDriver->isDirectory($varGeneratedPath)) { diff --git a/src/Service/StandardThemeBuilder.php b/src/Service/StandardThemeBuilder.php index 36e3c305..ba6b83cd 100644 --- a/src/Service/StandardThemeBuilder.php +++ b/src/Service/StandardThemeBuilder.php @@ -9,6 +9,13 @@ class StandardThemeBuilder { + /** + * Tracks whether the global Grunt tasks were already executed in this build process. + * + * @var bool + */ + private bool $gruntTasksRun = false; + /** * Create a standard theme builder. * @@ -47,13 +54,12 @@ public function build( $successList[] = "$themeCode: Dependencies checked"; // Run Grunt tasks (only once per build process) - static $gruntTasksRun = false; - if (!$gruntTasksRun) { + if (!$this->gruntTasksRun) { if (!$this->gruntTaskRunner->runTasks($io, $output, $isVerbose)) { return false; } $successList[] = 'Global: Grunt tasks executed'; - $gruntTasksRun = true; + $this->gruntTasksRun = true; } // Deploy static content From 4047de3819e5561a30bcdd2ec81498cbb48f84d6 Mon Sep 17 00:00:00 2001 From: Thomas Hauschild <7961978+Morgy93@users.noreply.github.com> Date: Sat, 4 Jul 2026 20:16:47 +0200 Subject: [PATCH 2/4] feat: improve mago analyze logging and configuration --- .ddev/commands/web/mago | 9 ++++++++- .github/workflows/static-analysis.yml | 7 +++++++ mago.toml | 4 ++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/.ddev/commands/web/mago b/.ddev/commands/web/mago index 52781f34..ecd7e815 100755 --- a/.ddev/commands/web/mago +++ b/.ddev/commands/web/mago @@ -28,7 +28,14 @@ if [[ ${1-} == "analyze" ]]; then target="${1}" shift fi - exec vendor/bin/mago --workspace magento --config mago.toml analyze "${target}" "$@" + # `paths = ["src"]` from mago.toml has no match under the magento workspace, + # which logs a harmless "Failed to walk" warning; symbols come from + # `includes = ["vendor"]`. Log only real errors — findings and the exit code + # are unaffected. Override with e.g. MAGO_LOG=warn when debugging. + export MAGO_LOG="${MAGO_LOG:-error}" + vendor/bin/mago --workspace magento --config mago.toml analyze "${target}" "$@" + echo "mago analyze: no issues found." + exit 0 fi vendor/bin/mago "$@" diff --git a/.github/workflows/static-analysis.yml b/.github/workflows/static-analysis.yml index b07338bb..a56d483a 100644 --- a/.github/workflows/static-analysis.yml +++ b/.github/workflows/static-analysis.yml @@ -212,6 +212,13 @@ jobs: # help messages) fails this job — green means a completely clean report. - name: Mago analyze working-directory: magento2 + env: + # `paths = ["src"]` from mago.toml has no match under this workspace + # (module source is analyzed via the vendor copy), which logs a + # harmless "Failed to walk" warning. Log only real errors — findings + # and the exit code are unaffected. Raise to `warn` when debugging + # incomplete-analysis problems (e.g. vendor files that fail to parse). + MAGO_LOG: error run: | ../mageforge/vendor/bin/mago \ --config ../mageforge/mago.toml \ diff --git a/mago.toml b/mago.toml index 63b32821..f67584df 100644 --- a/mago.toml +++ b/mago.toml @@ -7,6 +7,10 @@ php-version = "8.3" paths = ["src"] includes = ["vendor"] extensions = ["php", "phtml"] +# .trunk contains symlinks into the developer's host cache (~/.cache/trunk) +# that are dangling inside the ddev container and would log walk warnings. +# The astock phpcs-psr2-stock dir ships legacy sniffs with real parse errors. +excludes = ["**/.trunk/**", "**/astock/stock-api-libphp/libs/phpcs-psr2-stock/**"] [parser] enable-short-tags = false From 4b008041798879ba11f9223861d34e7872efaabd Mon Sep 17 00:00:00 2001 From: Thomas Hauschild <7961978+Morgy93@users.noreply.github.com> Date: Sat, 4 Jul 2026 20:20:02 +0200 Subject: [PATCH 3/4] fix: format file --- mago.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/mago.toml b/mago.toml index f67584df..434bd7a6 100644 --- a/mago.toml +++ b/mago.toml @@ -10,7 +10,10 @@ extensions = ["php", "phtml"] # .trunk contains symlinks into the developer's host cache (~/.cache/trunk) # that are dangling inside the ddev container and would log walk warnings. # The astock phpcs-psr2-stock dir ships legacy sniffs with real parse errors. -excludes = ["**/.trunk/**", "**/astock/stock-api-libphp/libs/phpcs-psr2-stock/**"] +excludes = [ + "**/.trunk/**", + "**/astock/stock-api-libphp/libs/phpcs-psr2-stock/**", +] [parser] enable-short-tags = false From 820aec3ee8bd14fcf64688aee785120b6bcedb43 Mon Sep 17 00:00:00 2001 From: Thomas Hauschild <7961978+Morgy93@users.noreply.github.com> Date: Sat, 4 Jul 2026 20:24:27 +0200 Subject: [PATCH 4/4] fix: improve logging for mago analyze command --- .ddev/commands/web/mago | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.ddev/commands/web/mago b/.ddev/commands/web/mago index ecd7e815..80d5dfea 100755 --- a/.ddev/commands/web/mago +++ b/.ddev/commands/web/mago @@ -34,7 +34,12 @@ if [[ ${1-} == "analyze" ]]; then # are unaffected. Override with e.g. MAGO_LOG=warn when debugging. export MAGO_LOG="${MAGO_LOG:-error}" vendor/bin/mago --workspace magento --config mago.toml analyze "${target}" "$@" - echo "mago analyze: no issues found." + # At MAGO_LOG=error mago suppresses its own (stderr) "No issues found" log + # line, so a clean run would be fully silent. Note success on stderr — same + # stream mago logs to — keeping stdout machine-readable (json/github/…). + echo "mago analyze: no issues found." >&2 + # set -e aborts above on findings; exit here so a successful analyze does + # not fall through to the plain `mago "$@"` invocation below. exit 0 fi