From f2bb5b9d454af6f2c4bb58b7bf84ca9fb256a7a2 Mon Sep 17 00:00:00 2001 From: AntonioCS Date: Sun, 4 Jan 2026 10:16:32 +0000 Subject: [PATCH] Add phpstan and psalm modules for static analysis (v2.2.7) - PHPStan module: php/phpstan/analyse, php/phpstan/staged Config: phpstan_level, phpstan_memory_limit Runtime: phpstan_files=, phpstan_args= - Psalm module: php/psalm/analyse, php/psalm/staged Config: psalm_threads Runtime: psalm_files=, psalm_args= - Remove old php/phpstan and php/psalm targets from php module - Add tests for both modules (12 tests, 22 assertions) --- CHANGELOG.md | 19 ++++++ modules/php/php/php.mk | 14 ----- modules/php/phpstan/mod_config.mk | 17 ++++++ modules/php/phpstan/mod_info.mk | 6 ++ modules/php/phpstan/phpstan.mk | 49 ++++++++++++++++ modules/php/phpstan/phpstan_test.mk | 91 +++++++++++++++++++++++++++++ modules/php/psalm/mod_config.mk | 14 +++++ modules/php/psalm/mod_info.mk | 6 ++ modules/php/psalm/psalm.mk | 48 +++++++++++++++ modules/php/psalm/psalm_test.mk | 79 +++++++++++++++++++++++++ 10 files changed, 329 insertions(+), 14 deletions(-) create mode 100644 modules/php/phpstan/mod_config.mk create mode 100644 modules/php/phpstan/mod_info.mk create mode 100644 modules/php/phpstan/phpstan.mk create mode 100644 modules/php/phpstan/phpstan_test.mk create mode 100644 modules/php/psalm/mod_config.mk create mode 100644 modules/php/psalm/mod_info.mk create mode 100644 modules/php/psalm/psalm.mk create mode 100644 modules/php/psalm/psalm_test.mk diff --git a/CHANGELOG.md b/CHANGELOG.md index 7f79b88..b57d50b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ +## [2.2.7] - 2026-01-04 + +### Added +- **PHPStan module**: New standalone module for PHPStan static analysis + - `php/phpstan/analyse` - Run PHPStan analysis + - `php/phpstan/staged` - Run PHPStan on staged PHP files only + - Configuration options: `phpstan_level`, `phpstan_memory_limit` + - Runtime variables: `phpstan_files=` for paths, `phpstan_args=` for extra options + - Depends on `php` module +- **Psalm module**: New standalone module for Psalm static analysis + - `php/psalm/analyse` - Run Psalm analysis + - `php/psalm/staged` - Run Psalm on staged PHP files only + - Configuration options: `psalm_threads` + - Runtime variables: `psalm_files=` for paths, `psalm_args=` for extra options + - Depends on `php` module + +### Changed +- **PHP module**: Removed old `php/phpstan` and `php/psalm` targets (now in separate modules) + ## [2.2.6] - 2026-01-03 ### Added diff --git a/modules/php/php/php.mk b/modules/php/php/php.mk index 3e64d4c..9deb787 100644 --- a/modules/php/php/php.mk +++ b/modules/php/php/php.mk @@ -84,20 +84,6 @@ php/dc/logs: ## Show php container logs endif -php/phpstan: mb/info-$$@ := Running PHPStan -php/phpstan: ## Run PHPStan to phpstan.output - $(call php_invoke,$(phpstan_bin) analyse \ - --configuration=$(phpstan_config_file) \ - $(if $(phpstan_send_to_file),--error-format=github > $(phpstan_output_file)) \ - || true \ - ) - -php/psalm: ## Run Psalm to psalm.output - $(call php_invoke,$(psalm_bin) $(psalm_flags) \ - $(if $(psalm_send_to_file),> $(psalm_output_file)) \ - || true \ - ) - endif # __MB_MODULES_PHP_TARGETS__ endif # __MB_MODULES_PHP__ diff --git a/modules/php/phpstan/mod_config.mk b/modules/php/phpstan/mod_config.mk new file mode 100644 index 0000000..81d84fb --- /dev/null +++ b/modules/php/phpstan/mod_config.mk @@ -0,0 +1,17 @@ +## Path to PHPStan binary +phpstan_bin ?= vendor/bin/phpstan# + +## Path to phpstan configuration file +phpstan_config ?= phpstan.neon# + +## Analysis level (0-9, empty = use config file setting) +phpstan_level ?=# + +## Memory limit (e.g., 512M, 1G) +phpstan_memory_limit ?=# + +## If true, send output to file instead of stdout +phpstan_send_to_file ?= $(mb_true)# + +## Output file for phpstan results +phpstan_output_file ?= phpstan.output# diff --git a/modules/php/phpstan/mod_info.mk b/modules/php/phpstan/mod_info.mk new file mode 100644 index 0000000..119ffab --- /dev/null +++ b/modules/php/phpstan/mod_info.mk @@ -0,0 +1,6 @@ +mb_module_name := phpstan +mb_module_version := 1.0.0 +mb_module_description := PHPStan static analysis module for MakeBind +mb_module_author := AntonioCS +mb_module_license := MIT +mb_module_depends := php diff --git a/modules/php/phpstan/phpstan.mk b/modules/php/phpstan/phpstan.mk new file mode 100644 index 0000000..0b8099e --- /dev/null +++ b/modules/php/phpstan/phpstan.mk @@ -0,0 +1,49 @@ +##################################################################################### +# Project: MakeBind +# File: modules/php/phpstan/phpstan.mk +# Description: PHPStan static analysis module for MakeBind +# Author: AntonioCS +# License: MIT License +##################################################################################### +ifndef __MB_MODULES_PHP_PHPSTAN__ +__MB_MODULES_PHP_PHPSTAN__ := 1 + +## Internal function to build phpstan command arguments +## @returns Common arguments for phpstan +define phpstan_build_args +$(strip + $(eval $0_args :=) + $(eval + $0_args += $(if $(wildcard $(phpstan_config)),--configuration=$(phpstan_config)) + $0_args += $(if $(phpstan_level),--level=$(phpstan_level)) + $0_args += $(if $(phpstan_memory_limit),--memory-limit=$(phpstan_memory_limit)) + $0_args += $(if $(value phpstan_args),$(phpstan_args)) + $0_args += $(if $(value phpstan_files),$(phpstan_files)) + ) + $(strip $($0_args)) +) +endef + +## Skip target definitions when loaded dynamically (e.g., during test discovery) +ifndef __MB_TEST_DISCOVERY__ + +## Verify php module is loaded (check once at module level) +$(if $(value php_invoke),,$(error phpstan module requires php module - please add php module first)) + +php/phpstan/analyse: ## Run PHPStan analysis (phpstan_files= for paths, phpstan_args= for extra options) + $(eval $@_cmd := $(phpstan_bin) analyse $(call phpstan_build_args)) + $(if $(call mb_is_true,$(phpstan_send_to_file)),\ + $(eval $@_cmd += > $(phpstan_output_file) 2>&1 || true)\ + $(call mb_printf_info,Running phpstan and sending output to $(phpstan_output_file))\ + ) + $(call php_invoke,$($@_cmd)) + $(if $(call mb_is_true,$(phpstan_send_to_file)),\ + $(call mb_printf_info,Results saved to $(phpstan_output_file))\ + ) + +php/phpstan/staged: ## Run PHPStan on staged PHP files only + $(call mb_run_on_staged,php,$(call php_invoke,$(phpstan_bin) analyse)) + +endif # __MB_TEST_DISCOVERY__ + +endif # __MB_MODULES_PHP_PHPSTAN__ diff --git a/modules/php/phpstan/phpstan_test.mk b/modules/php/phpstan/phpstan_test.mk new file mode 100644 index 0000000..5fb4024 --- /dev/null +++ b/modules/php/phpstan/phpstan_test.mk @@ -0,0 +1,91 @@ +##################################################################################### +# Project: MakeBind +# File: modules/php/phpstan/phpstan_test.mk +# Description: Tests for the phpstan module +# Author: AntonioCS +# License: MIT License +##################################################################################### + +include $(mb_core_path)/util.mk +include $(mb_core_path)/functions.mk + +## Load config to define variables +include $(mb_modules_path)/php/phpstan/mod_config.mk + +###################################################################################### +# Configuration tests +###################################################################################### + +define test_modules_phpstan_config_defaults + $(call mb_assert_eq,vendor/bin/phpstan,$(phpstan_bin),phpstan_bin should default to vendor/bin/phpstan) + $(call mb_assert_eq,phpstan.neon,$(phpstan_config),phpstan_config should default to phpstan.neon) + $(call mb_assert_eq,$(mb_true),$(phpstan_send_to_file),phpstan_send_to_file should default to mb_true) + $(call mb_assert_eq,phpstan.output,$(phpstan_output_file),phpstan_output_file should default to phpstan.output) + $(call mb_assert_empty,$(phpstan_level),phpstan_level should be empty by default) + $(call mb_assert_empty,$(phpstan_memory_limit),phpstan_memory_limit should be empty by default) +endef + +###################################################################################### +# phpstan_build_args tests +###################################################################################### + +## Need to include the main module for function tests +include $(mb_modules_path)/php/phpstan/phpstan.mk + +define test_modules_phpstan_build_args_empty + $(eval phpstan_config := nonexistent.neon) + $(eval $0_result := $(call phpstan_build_args)) + $(call mb_assert_empty,$($0_result),Should return empty when no config and no options) + $(eval phpstan_config := phpstan.neon) +endef + +define test_modules_phpstan_build_args_with_level + $(eval phpstan_level := 8) + $(eval phpstan_config := nonexistent.neon) + $(eval $0_result := $(call phpstan_build_args)) + $(call mb_assert_eq,--level=8,$($0_result),Should include level option) + $(eval phpstan_level :=) + $(eval phpstan_config := phpstan.neon) +endef + +define test_modules_phpstan_build_args_with_memory_limit + $(eval phpstan_memory_limit := 512M) + $(eval phpstan_config := nonexistent.neon) + $(eval $0_result := $(call phpstan_build_args)) + $(call mb_assert_eq,--memory-limit=512M,$($0_result),Should include memory-limit option) + $(eval phpstan_memory_limit :=) + $(eval phpstan_config := phpstan.neon) +endef + +define test_modules_phpstan_build_args_with_files + $(eval phpstan_files := src/Controller/) + $(eval phpstan_config := nonexistent.neon) + $(eval $0_result := $(call phpstan_build_args)) + $(call mb_assert_eq,src/Controller/,$($0_result),phpstan_files should be included) + $(eval phpstan_files :=) + $(eval phpstan_config := phpstan.neon) +endef + +define test_modules_phpstan_build_args_runtime_args + $(eval phpstan_args := --no-progress --error-format=json) + $(eval phpstan_config := nonexistent.neon) + $(eval $0_result := $(call phpstan_build_args)) + $(call mb_assert_eq,--no-progress --error-format=json,$($0_result),Runtime phpstan_args should be included) + $(eval phpstan_args :=) + $(eval phpstan_config := phpstan.neon) +endef + +define test_modules_phpstan_build_args_all_options + $(eval phpstan_level := 5) + $(eval phpstan_memory_limit := 1G) + $(eval phpstan_args := --no-progress) + $(eval phpstan_files := src/) + $(eval phpstan_config := nonexistent.neon) + $(eval $0_result := $(call phpstan_build_args)) + $(call mb_assert_eq,--level=5 --memory-limit=1G --no-progress src/,$($0_result),All options should be combined) + $(eval phpstan_level :=) + $(eval phpstan_memory_limit :=) + $(eval phpstan_args :=) + $(eval phpstan_files :=) + $(eval phpstan_config := phpstan.neon) +endef diff --git a/modules/php/psalm/mod_config.mk b/modules/php/psalm/mod_config.mk new file mode 100644 index 0000000..53ce21e --- /dev/null +++ b/modules/php/psalm/mod_config.mk @@ -0,0 +1,14 @@ +## Path to Psalm binary +psalm_bin ?= vendor/bin/psalm# + +## Path to psalm configuration file +psalm_config ?= psalm.xml# + +## Number of threads to use (empty = use default) +psalm_threads ?=# + +## If true, send output to file instead of stdout +psalm_send_to_file ?= $(mb_true)# + +## Output file for psalm results +psalm_output_file ?= psalm.output# diff --git a/modules/php/psalm/mod_info.mk b/modules/php/psalm/mod_info.mk new file mode 100644 index 0000000..bb85af8 --- /dev/null +++ b/modules/php/psalm/mod_info.mk @@ -0,0 +1,6 @@ +mb_module_name := psalm +mb_module_version := 1.0.0 +mb_module_description := Psalm static analysis module for MakeBind +mb_module_author := AntonioCS +mb_module_license := MIT +mb_module_depends := php diff --git a/modules/php/psalm/psalm.mk b/modules/php/psalm/psalm.mk new file mode 100644 index 0000000..cd1099b --- /dev/null +++ b/modules/php/psalm/psalm.mk @@ -0,0 +1,48 @@ +##################################################################################### +# Project: MakeBind +# File: modules/php/psalm/psalm.mk +# Description: Psalm static analysis module for MakeBind +# Author: AntonioCS +# License: MIT License +##################################################################################### +ifndef __MB_MODULES_PHP_PSALM__ +__MB_MODULES_PHP_PSALM__ := 1 + +## Internal function to build psalm command arguments +## @returns Common arguments for psalm +define psalm_build_args +$(strip + $(eval $0_args :=) + $(eval + $0_args += $(if $(wildcard $(psalm_config)),--config=$(psalm_config)) + $0_args += $(if $(psalm_threads),--threads=$(psalm_threads)) + $0_args += $(if $(value psalm_args),$(psalm_args)) + $0_args += $(if $(value psalm_files),$(psalm_files)) + ) + $(strip $($0_args)) +) +endef + +## Skip target definitions when loaded dynamically (e.g., during test discovery) +ifndef __MB_TEST_DISCOVERY__ + +## Verify php module is loaded (check once at module level) +$(if $(value php_invoke),,$(error psalm module requires php module - please add php module first)) + +php/psalm/analyse: ## Run Psalm analysis (psalm_files= for paths, psalm_args= for extra options) + $(eval $@_cmd := $(psalm_bin) $(call psalm_build_args)) + $(if $(call mb_is_true,$(psalm_send_to_file)),\ + $(eval $@_cmd += > $(psalm_output_file) 2>&1 || true)\ + $(call mb_printf_info,Running psalm and sending output to $(psalm_output_file))\ + ) + $(call php_invoke,$($@_cmd)) + $(if $(call mb_is_true,$(psalm_send_to_file)),\ + $(call mb_printf_info,Results saved to $(psalm_output_file))\ + ) + +php/psalm/staged: ## Run Psalm on staged PHP files only + $(call mb_run_on_staged,php,$(call php_invoke,$(psalm_bin))) + +endif # __MB_TEST_DISCOVERY__ + +endif # __MB_MODULES_PHP_PSALM__ diff --git a/modules/php/psalm/psalm_test.mk b/modules/php/psalm/psalm_test.mk new file mode 100644 index 0000000..ae6092d --- /dev/null +++ b/modules/php/psalm/psalm_test.mk @@ -0,0 +1,79 @@ +##################################################################################### +# Project: MakeBind +# File: modules/php/psalm/psalm_test.mk +# Description: Tests for the psalm module +# Author: AntonioCS +# License: MIT License +##################################################################################### + +include $(mb_core_path)/util.mk +include $(mb_core_path)/functions.mk + +## Load config to define variables +include $(mb_modules_path)/php/psalm/mod_config.mk + +###################################################################################### +# Configuration tests +###################################################################################### + +define test_modules_psalm_config_defaults + $(call mb_assert_eq,vendor/bin/psalm,$(psalm_bin),psalm_bin should default to vendor/bin/psalm) + $(call mb_assert_eq,psalm.xml,$(psalm_config),psalm_config should default to psalm.xml) + $(call mb_assert_eq,$(mb_true),$(psalm_send_to_file),psalm_send_to_file should default to mb_true) + $(call mb_assert_eq,psalm.output,$(psalm_output_file),psalm_output_file should default to psalm.output) + $(call mb_assert_empty,$(psalm_threads),psalm_threads should be empty by default) +endef + +###################################################################################### +# psalm_build_args tests +###################################################################################### + +## Need to include the main module for function tests +include $(mb_modules_path)/php/psalm/psalm.mk + +define test_modules_psalm_build_args_empty + $(eval psalm_config := nonexistent.xml) + $(eval $0_result := $(call psalm_build_args)) + $(call mb_assert_empty,$($0_result),Should return empty when no config and no options) + $(eval psalm_config := psalm.xml) +endef + +define test_modules_psalm_build_args_with_threads + $(eval psalm_threads := 4) + $(eval psalm_config := nonexistent.xml) + $(eval $0_result := $(call psalm_build_args)) + $(call mb_assert_eq,--threads=4,$($0_result),Should include threads option) + $(eval psalm_threads :=) + $(eval psalm_config := psalm.xml) +endef + +define test_modules_psalm_build_args_with_files + $(eval psalm_files := src/Controller/) + $(eval psalm_config := nonexistent.xml) + $(eval $0_result := $(call psalm_build_args)) + $(call mb_assert_eq,src/Controller/,$($0_result),psalm_files should be included) + $(eval psalm_files :=) + $(eval psalm_config := psalm.xml) +endef + +define test_modules_psalm_build_args_runtime_args + $(eval psalm_args := --no-progress --output-format=json) + $(eval psalm_config := nonexistent.xml) + $(eval $0_result := $(call psalm_build_args)) + $(call mb_assert_eq,--no-progress --output-format=json,$($0_result),Runtime psalm_args should be included) + $(eval psalm_args :=) + $(eval psalm_config := psalm.xml) +endef + +define test_modules_psalm_build_args_all_options + $(eval psalm_threads := 8) + $(eval psalm_args := --no-cache) + $(eval psalm_files := src/) + $(eval psalm_config := nonexistent.xml) + $(eval $0_result := $(call psalm_build_args)) + $(call mb_assert_eq,--threads=8 --no-cache src/,$($0_result),All options should be combined) + $(eval psalm_threads :=) + $(eval psalm_args :=) + $(eval psalm_files :=) + $(eval psalm_config := psalm.xml) +endef