Detect which Maven module needs to be built

I would like GitLab to build only the module needed based on the commit.

The project is a Maven multimode project, with three modules:

  • Base contains base code, which is required by middle and top.
  • Middle contains code that is only needed by top.
  • Top contains the invocation of base and middle code.

Therefore:

  • If there is a code change in base, base, middle, and top need to be rebuilt.
  • If there is a code change in middle, middle and top need a code change, no base.
  • If there is a code change in top, only top needs to be rebuilt.

(This example is an illustrative example, with only 3 modules; please imagine many more modules, with more complex dependencies.)

Since I know where the code got changed, I can use the infamous:

mvn --projects {base, middle, top} --also-make clean install

I would pass in the appropriate module, since I know which code changed.

How to achieve this in GitLab, without hardcoding?

So far, I have tried hardcoding the possibilities, passing the module as a string argument. While this is working, it requires hardcoding the module, or passing the module via some kind of input variable.

Since GitLab knows which module was changed, how can we tell it to run the command with the module that has the code change? Some kind of:

mvn --projects gitlab-to-detect-changed-modules --also-make clean install

To make GitLab CI automatically detect which Maven modules were changed and build only the necessary modules without hardcoding, you can use GitLab’s built-in CI_COMMIT_SHA and Git diff tools to detect changes dynamically.

Basic Strategy

  1. Detect changed files using git diff between the current commit and the base commit (e.g., main or origin/main).
  2. Map changed files to their Maven modules.
  3. Build only the necessary modules using mvn --projects with --also-make.

Example .gitlab-ci.yml Approach

stages:
  - build

build:
  stage: build
  script:
    # Fetch base branch to compare
    - git fetch origin main
    # Get list of changed directories (assuming each module is in its own folder)
    - CHANGED_DIRS=$(git diff --name-only origin/main...HEAD | cut -d/ -f1 | sort -u)
    - echo "Changed directories: $CHANGED_DIRS"

    # Create a list of affected modules based on dependencies
    - MODULES=""
    - for dir in $CHANGED_DIRS; do
        if [ "$dir" = "base" ]; then
          MODULES="$MODULES,base,middle,top"
        elif [ "$dir" = "middle" ]; then
          MODULES="$MODULES,middle,top"
        elif [ "$dir" = "top" ]; then
          MODULES="$MODULES,top"
        fi
      done
    # Remove leading comma
    - MODULES=${MODULES#,}
    - echo "Building modules: $MODULES"

    # Run Maven build
    - mvn --projects $MODULES --also-make clean install

Notes

  • Adjust origin/main if your default branch is different.
  • Replace hardcoded logic with a dependency map if you have many modules. A separate script (e.g., Python or Bash) can help calculate affected modules based on real Maven dependencies.
  • You could also use tools like Moderne or JReleaser in more complex setups.

Result

With this setup, GitLab will:

  • Detect which module(s) changed
  • Determine the dependent modules
  • Build only what’s necessary

No need for hardcoded module lists or manual input!