From 87b177f2258b6d8c9f913bb5c681a7cfe75d5da7 Mon Sep 17 00:00:00 2001 From: AntonioCS Date: Sat, 3 Jan 2026 19:37:34 +0000 Subject: [PATCH] Add git staged files utility functions (v2.2.6) - Add core/util/git.mk with mb_staged_files and mb_run_on_staged functions - mb_staged_files: returns staged files, optionally filtered by extension - mb_run_on_staged: runs command only if staged files exist (single git call) - mb_git_available: checks git availability at load time - Graceful handling when git is not installed --- core/util.mk | 1 + core/util/git.mk | 63 ++++++++++++++++++++++++++++++++ tests/unit/core/util/git_test.mk | 49 +++++++++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 core/util/git.mk create mode 100644 tests/unit/core/util/git_test.mk diff --git a/core/util.mk b/core/util.mk index f91028e..63aa7c5 100644 --- a/core/util.mk +++ b/core/util.mk @@ -26,6 +26,7 @@ include $(mb_core_path)/util/os_detection.mk include $(mb_core_path)/util/cache.mk include $(mb_core_path)/util/colours.mk include $(mb_core_path)/util/debug.mk +include $(mb_core_path)/util/git.mk include $(mb_core_path)/util/variables.mk diff --git a/core/util/git.mk b/core/util/git.mk new file mode 100644 index 0000000..86e45a0 --- /dev/null +++ b/core/util/git.mk @@ -0,0 +1,63 @@ +##################################################################################### +# Project: MakeBind +# File: core/util/git.mk +# Description: Git utility functions for MakeBind +# Author: AntonioCS +# License: MIT License +##################################################################################### +ifndef __MB_CORE_UTIL_GIT_MK__ +__MB_CORE_UTIL_GIT_MK__ := 1 + +mb_debug_git ?= $(mb_debug) + +## Check if git is available (set once at load time) +## Note: Can't use mb_cmd_exists or mb_true here as they may not be defined yet +mb_git_available := $(shell command -v git >/dev/null 2>&1 && echo 1) + +## @function mb_staged_files +## @description Returns a space-separated list of staged files, optionally filtered by extension +## @arg 1: extension (optional) - File extension to filter (e.g., php, py, go). If empty, returns all staged files. +## @returns Space-separated list of staged files (paths relative to git root) +## @example $(call mb_staged_files,php) -> src/Foo.php src/Bar.php +## @example $(call mb_staged_files) -> all staged files +define mb_staged_files +$(strip + $(if $(mb_git_available), + $(eval $0_arg1_ext := $(if $(value 1),$(strip $1),)) + $(if $($0_arg1_ext), + $(shell git diff --cached --name-only --diff-filter=d 2>/dev/null | grep '\.$($0_arg1_ext)$$' || true), + $(shell git diff --cached --name-only --diff-filter=d 2>/dev/null) + ) + ) +) +endef + +## @function mb_run_on_staged +## @description Runs a command only if there are staged files. +## Optionally filters by extension. The staged files are appended to the command. +## @arg 1: extension (optional) - File extension to filter (e.g., php, py, go). If empty, matches all files. +## @arg 2: command (required) - Command to run (files will be appended) +## @example $(call mb_run_on_staged,php,vendor/bin/phpstan analyse) +## @example $(call mb_run_on_staged,,prettier --write) +define mb_run_on_staged +$(strip + $(if $(mb_git_available), + $(eval $0_arg1_ext := $(if $(value 1),$(strip $1),)) + $(eval $0_arg2_cmd := $(if $(value 2),$(strip $2),$(call mb_printf_error,$0: command required))) + $(eval $0_files := $(call mb_staged_files,$($0_arg1_ext))) + $(if $($0_files), + $(call mb_debug_print,Running: $($0_arg2_cmd) $($0_files),$(mb_debug_git)) + $($0_arg2_cmd) $($0_files) + , + $(if $($0_arg1_ext), + $(call mb_printf_info,No staged .$($0_arg1_ext) files), + $(call mb_printf_info,No staged files) + ) + ) + , + $(call mb_printf_info,git not available) + ) +) +endef + +endif # __MB_CORE_UTIL_GIT_MK__ diff --git a/tests/unit/core/util/git_test.mk b/tests/unit/core/util/git_test.mk new file mode 100644 index 0000000..9376cec --- /dev/null +++ b/tests/unit/core/util/git_test.mk @@ -0,0 +1,49 @@ +##################################################################################### +# Project: MakeBind +# File: tests/unit/core/util/git_test.mk +# Description: Tests for git utility functions +# Author: AntonioCS +# License: MIT License +##################################################################################### + +include $(mb_core_path)/util/variables.mk +include $(mb_core_path)/util/git.mk + +mb_debug_git := $(mb_off) + +## Test that mb_staged_files returns empty when no files are staged +define test_core_util_git_staged_files_empty_when_none + $(eval $@_result := $(call mb_staged_files,php)) + $(call mb_assert_empty,$($@_result),Expected empty result when no PHP files are staged) +endef + +## Test that mb_staged_files works with different extensions +define test_core_util_git_staged_files_different_extensions + $(eval $@_result_py := $(call mb_staged_files,py)) + $(eval $@_result_go := $(call mb_staged_files,go)) + $(eval $@_result_js := $(call mb_staged_files,js)) + $(call mb_assert_empty,$($@_result_py),Expected empty result for py) + $(call mb_assert_empty,$($@_result_go),Expected empty result for go) + $(call mb_assert_empty,$($@_result_js),Expected empty result for js) +endef + +## Test that mb_run_on_staged does not error when no files staged +## Note: This test verifies the function executes without error +## The actual command won't run since there are no staged files +define test_core_util_git_run_on_staged_no_files + $(eval $@_result := $(call mb_run_on_staged,php,echo "would run")) + $(call mb_assert,1,mb_run_on_staged should complete without error) +endef + +## Test that mb_staged_files works without extension (doesn't error) +## Note: Can't assert empty since tests may run with staged files +define test_core_util_git_staged_files_all_no_extension + $(eval $@_result := $(call mb_staged_files)) + $(call mb_assert,1,mb_staged_files without extension should complete without error) +endef + +## Test that mb_run_on_staged works without extension +define test_core_util_git_run_on_staged_all_no_extension + $(eval $@_result := $(call mb_run_on_staged,,echo "would run")) + $(call mb_assert,1,mb_run_on_staged without extension should complete without error) +endef