Skip to content

GH-119: Add module-scoped phpunit GrumPHP task#121

Open
hkirsman wants to merge 24 commits intomainfrom
feature/119-Optimize-GrumPHP-phpunit-to-run-only-affected-modules
Open

GH-119: Add module-scoped phpunit GrumPHP task#121
hkirsman wants to merge 24 commits intomainfrom
feature/119-Optimize-GrumPHP-phpunit-to-run-only-affected-modules

Conversation

@hkirsman
Copy link
Collaborator

@hkirsman hkirsman commented Mar 16, 2026

Overview

This pull request introduces a new GrumPHP task, phpunit_drupal_modules, designed to run PHPUnit tests only for affected custom Drupal modules. The implementation includes the task logic, service registration, configuration, and comprehensive tests. This addition enhances the efficiency of the test process by targeting only changed modules and integrates seamlessly with the existing GrumPHP workflow.

New GrumPHP Task: phpunit_drupal_modules

  • Added PhpUnitDrupalModulesTask class to run PHPUnit for changed Drupal custom modules, with logic to detect affected modules, check for test directories, and execute tests per module. Includes options for specifying module roots, config files, and test suites.
  • Registered the new task as a service in services.yaml and added its configuration schema to tasks.yml, supporting custom ignore patterns, extensions, and module roots. [1] [2]
  • Implemented the corresponding extension loader for GrumPHP (PhpUnitDrupalModulesExtensionLoader).
  • Integrated the new task and extension loader into the GrumPHP configuration (grumphp.yml). [1] [2]

Testing and Validation

  • Added a comprehensive PHPUnit test class for PhpUnitDrupalModulesTask, covering argument construction, skipping logic, and per-module execution with early failure.

Example output:

 ✗ git commit
GrumPHP detected a pre-commit command.
GrumPHP is sniffing your code!

Running tasks with priority 0!
==============================

Running task 1/1: phpunit_drupal_modules... 


phpunit_drupal_modules: NOTE: affected modules without tests:
  - web/modules/custom/my_no_tests_module

phpunit_drupal_modules: running tests for modules:
  - web/modules/custom/my_module
  - web/modules/custom/my_module2 

Testing

  1. Install this update
    composer require wunderio/code-quality:dev-feature/119-Optimize-GrumPHP-phpunit-to-run-only-affected-modules --dev --with-all-dependencies

  2. Add the new task to your grumphp.yml:

grumphp:
  tasks:
    phpunit_drupal_modules: ~
  1. Make sure you're using ddev to run the hooks:
    3.1 Add this to grumphp.yml:
grumphp:
  git_hook_variables:
    EXEC_GRUMPHP_COMMAND: ddev php

and append to extensions section

  extensions:
    - Wunderio\GrumPHP\Task\PhpUnitDrupalModules\PhpUnitDrupalModulesExtensionLoader

3.2 Re-init hooks:

ddev grumphp git:init
  1. Edit file in custom module that has tests:

  2. Try to commit, tests should run only in that module

- introduced PhpUnitModules GrumPHP task that discovers affected custom modules from the current context
- wired PhpUnitModules task to run phpunit via ddev only for changed custom modules
- added task configuration defaults (paths, ignore patterns, extensions) to tasks.yml

Refs: src/Task/PhpUnitModules/PhpUnitModulesTask.php, src/Task/PhpUnitModules/PhpUnitModulesExtensionLoader.php, src/Task/PhpUnitModules/services.yaml, src/Task/tasks.yml
- renamed and refined the custom phpunit task to PhpUnitDrupalModules to clearly target Drupal custom modules
- registered the new PhpUnitDrupalModules task and extension in default code-quality grumphp configuration
- wired PhpUnitDrupalModules task into task configuration with sensible defaults for custom module paths and ignore patterns

Refs: config/grumphp.yml, src/Task/PhpUnitDrupalModules/PhpUnitDrupalModulesTask.php, src/Task/PhpUnitDrupalModules/PhpUnitDrupalModulesExtensionLoader.php, src/Task/PhpUnitDrupalModules/services.yaml, src/Task/tasks.yml
- Ensure PhpUnitDrupalModules task cleanly skips when no matching module paths are found
- Run phpunit directly instead of via ddev wrapper when executing affected module tests
Refs: src/Task/PhpUnitDrupalModules/PhpUnitDrupalModulesTask.php
- Allow PhpUnitDrupalModules task to accept a config_file option matching the core phpunit task
- Pass the configured phpunit XML file via -c when running tests for affected custom modules

Refs: src/Task/PhpUnitDrupalModules/PhpUnitDrupalModulesTask.php, src/Task/tasks.yml
- Allow PhpUnitDrupalModules task to accept a configurable testsuite name passed through to phpunit
- Extend task configuration schema to expose the new testsuite option
Refs: src/Task/PhpUnitDrupalModules/PhpUnitDrupalModulesTask.php, src/Task/tasks.yml
- Output the list of affected custom Drupal modules before executing the phpunit_drupal_modules task for better commit-time visibility
Refs: src/Task/PhpUnitDrupalModules/PhpUnitDrupalModulesTask.php
- Only run phpunit for custom modules that actually contain a tests directory
- Print affected modules one per line before executing the phpunit_drupal_modules task for clearer feedback
Refs: src/Task/PhpUnitDrupalModules/PhpUnitDrupalModulesTask.php
- Detect affected custom Drupal modules that lack a tests directory and list them explicitly in phpunit_drupal_modules output
- Keep actual phpunit execution limited to modules that do have tests, listed one per line for clarity
Refs: src/Task/PhpUnitDrupalModules/PhpUnitDrupalModulesTask.php
- Print a clear NOTE block listing affected custom modules that have no tests configured
- Keep a separate, well-spaced list of modules that will actually have phpunit tests run against them
Refs: src/Task/PhpUnitDrupalModules/PhpUnitDrupalModulesTask.php
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new GrumPHP task intended to run PHPUnit only for affected custom Drupal modules, reducing pre-commit runtime by scoping tests to changed modules that contain tests.

Changes:

  • Added a new phpunit_drupal_modules task entry and extension registration in GrumPHP config.
  • Introduced PhpUnitDrupalModulesTask + extension loader + Symfony service definition.
  • Added task configuration options (ignore patterns, extensions, run roots, phpunit config/testsuites).

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/Task/tasks.yml Adds configurable options for the new module-scoped PHPUnit task.
src/Task/PhpUnitDrupalModules/services.yaml Registers the new task as a Symfony service tagged for GrumPHP.
src/Task/PhpUnitDrupalModules/PhpUnitDrupalModulesTask.php Implements module detection and phpunit command argument building.
src/Task/PhpUnitDrupalModules/PhpUnitDrupalModulesExtensionLoader.php Adds an extension loader to import the task’s services file.
config/grumphp.yml Enables the new task and registers its extension loader.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

- refactor PhpUnitDrupalModulesTask to read module roots from configurable run_on option with default web/modules/custom
- support multiple configurable module root directories when collecting affected modules
Refs: src/Task/PhpUnitDrupalModules/PhpUnitDrupalModulesTask.php
- add PhpUnitDrupalModulesTaskTest to verify phpunit argument building with config_file and testsuite
- ensure module-only configuration builds arguments containing only affected module paths
Refs: tests/PhpUnitDrupalModules/PhpUnitDrupalModulesTaskTest.php
- replace array_map callbacks with explicit foreach loops when normalising module roots and formatting output
- keep behaviour and messaging identical while satisfying security audit sniffs
Refs: src/Task/PhpUnitDrupalModules/PhpUnitDrupalModulesTask.php
- Extract module root determination into `getModuleRoots()`
- Move module collection from paths into `collectModulesFromPaths()`
- Separate modules with and without tests into `splitModulesByTests()`
- Isolate output logic for modules without tests into `printModulesWithoutTests()`
- Isolate output logic for modules with tests into `printModulesWithTests()`
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a GrumPHP task to speed up local pre-commit checks by running PHPUnit only for impacted custom Drupal modules (and skipping modules without tests), instead of executing the full test suite on every commit.

Changes:

  • Registers a new GrumPHP task phpunit_drupal_modules and its extension loader.
  • Implements PhpUnitDrupalModulesTask to derive affected module roots from changed paths and run PHPUnit only for modules containing a tests/ directory.
  • Adds task configuration defaults/options in src/Task/tasks.yml and introduces unit tests for the argument builder.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
config/grumphp.yml Enables the new task and registers its extension loader.
src/Task/PhpUnitDrupalModules/PhpUnitDrupalModulesExtensionLoader.php Adds an extension loader to import the task service definition.
src/Task/PhpUnitDrupalModules/services.yaml Registers the task service + GrumPHP task tag.
src/Task/PhpUnitDrupalModules/PhpUnitDrupalModulesTask.php Implements module detection, test presence checks, and PHPUnit invocation.
src/Task/tasks.yml Adds default options for the new task (roots, extensions, ignores, phpunit config/testsuites).
tests/PhpUnitDrupalModules/PhpUnitDrupalModulesTaskTest.php Adds unit tests for buildArguments().

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

- Execute phpunit once per affected custom Drupal module so each module’s tests run with the configured testsuite
- Keep clear output about modules with and without tests while stopping on the first failing module run
Refs: src/Task/PhpUnitDrupalModules/PhpUnitDrupalModulesTask.php
- Print a progress line after each affected Drupal module’s phpunit run, including index, total, module path, and OK/FAILED status
- Keep per-module execution behavior while maintaining early exit on the first failing module

Refs: src/Task/PhpUnitDrupalModules/PhpUnitDrupalModulesTask.php
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new GrumPHP task (phpunit_drupal_modules) to speed up pre-commit checks by running PHPUnit only for impacted custom Drupal modules (and skipping modules without tests).

Changes:

  • Introduces PhpUnitDrupalModulesTask to detect changed files under configured module roots and run PHPUnit per affected module that has a tests/ directory.
  • Registers the task via a new extension loader + Symfony service definition and enables it in config/grumphp.yml.
  • Adds PHPUnit tests for argument building and task run behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/Task/PhpUnitDrupalModules/PhpUnitDrupalModulesTask.php Implements module detection + per-module PHPUnit execution and user-facing output.
src/Task/PhpUnitDrupalModules/services.yaml Registers the task as a GrumPHP service/tag.
src/Task/PhpUnitDrupalModules/PhpUnitDrupalModulesExtensionLoader.php Loads the task’s service definition into GrumPHP.
src/Task/tasks.yml Defines configurable options for the new task.
config/grumphp.yml Enables the task and registers its extension loader.
tests/PhpUnitDrupalModules/PhpUnitDrupalModulesTaskTest.php Adds unit tests for argument building and run() behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

hkirsman and others added 3 commits March 17, 2026 15:48
- Introduce a configurable timeout option for the PhpUnitDrupalModules task and apply it per-module via Symfony Process
- Keep existing config_file and testsuite handling while improving progress output with per-module completion lines

Refs: src/Task/PhpUnitDrupalModules/PhpUnitDrupalModulesTask.php, src/Task/tasks.yml
- Add an end-to-end test that uses a temporary directory tree to verify module root detection from changed paths
- Assert that modules are correctly split into with-tests and without-tests based on presence of a tests/ directory
Refs: tests/PhpUnitDrupalModules/PhpUnitDrupalModulesTaskTest.php

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
…task

- Use the task’s actual name in all console messages instead of hardcoded strings
- Add a configurable timeout option for per-module phpunit runs and apply it via Symfony Process
- Print per-module completion lines with index, total, and OK/FAILED status to show progress during long test runs

Refs: src/Task/PhpUnitDrupalModules/PhpUnitDrupalModulesTask.php, src/Task/tasks.yml
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new GrumPHP task (phpunit_drupal_modules) to run PHPUnit only for affected custom Drupal modules, aiming to reduce pre-commit test runtime by scoping execution to changed modules.

Changes:

  • Introduces PhpUnitDrupalModulesTask to detect impacted modules, skip modules without tests, and run PHPUnit per affected module.
  • Registers the task via a new service definition and extension loader, and wires it into GrumPHP configuration and task schema.
  • Adds PHPUnit tests covering argument building and run behavior.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/Task/PhpUnitDrupalModules/PhpUnitDrupalModulesTask.php Implements module detection + per-module phpunit execution logic.
src/Task/PhpUnitDrupalModules/services.yaml Registers the task service and GrumPHP task tag.
src/Task/PhpUnitDrupalModules/PhpUnitDrupalModulesExtensionLoader.php Adds an extension loader to import the task’s services.
src/Task/tasks.yml Adds config schema/options for the new task.
config/grumphp.yml Enables the new task and extension in the default GrumPHP config.
tests/PhpUnitDrupalModules/PhpUnitDrupalModulesTaskTest.php Adds test coverage for argument building and task execution behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

- update phpunit task test to assert SKIPPED result code instead of relying on isPassed()

Refs: tests/PhpUnitDrupalModules/PhpUnitDrupalModulesTaskTest.php
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants