Skip to content

feat: add git pre-commit hook for automatic code formatting#23384

Merged
Artur- merged 16 commits intomainfrom
spotless-pre-commit-hook
Feb 18, 2026
Merged

feat: add git pre-commit hook for automatic code formatting#23384
Artur- merged 16 commits intomainfrom
spotless-pre-commit-hook

Conversation

@Artur-
Copy link
Member

@Artur- Artur- commented Jan 30, 2026

Adds a pre-commit hook that runs spotless:apply on staged files, eliminating the need to manually format code before commits.

  • scripts/git-hooks/pre-commit: the hook that formats staged files
  • scripts/install-git-hooks.sh: installs hooks, backs up existing ones
  • pom.xml: runs install script during Maven initialize phase

Existing pre-commit hooks are backed up to pre-commit.local and called after formatting completes.

Adds a pre-commit hook that runs spotless:apply on staged files,
eliminating the need to manually format code before commits.

- scripts/git-hooks/pre-commit: the hook that formats staged files
- scripts/install-git-hooks.sh: installs hooks, backs up existing ones
- pom.xml: runs install script during Maven initialize phase

Existing pre-commit hooks are backed up to pre-commit.local and
called after formatting completes.
- Run spotless:apply on whole project (multi-module compatible)
- Use POSIX-compatible commands only (works on Linux and Mac)
- Remove unnecessary variables and function abstractions
@Artur- Artur- force-pushed the spotless-pre-commit-hook branch from 33834c8 to 405ba20 Compare January 30, 2026 13:30
@github-actions
Copy link

github-actions bot commented Jan 30, 2026

Test Results

 1 356 files  ± 0   1 356 suites  ±0   1h 26m 30s ⏱️ + 2m 21s
 9 613 tests ± 0   9 546 ✅ ± 0  67 💤 ±0  0 ❌ ±0 
10 079 runs  +34  10 003 ✅ +33  76 💤 +1  0 ❌ ±0 

Results for commit 16c1767. ± Comparison against base commit 00710af.

♻️ This comment has been updated with latest results.

Copy link
Member

@heruan heruan left a comment

Choose a reason for hiding this comment

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

Should we adopt Husky rather than reinventing the wheel?

@Artur-
Copy link
Member Author

Artur- commented Jan 30, 2026

How would you integrate husky into the Maven build?

@heruan
Copy link
Member

heruan commented Jan 30, 2026

Still with exec-maven-plugin, but instead of the custom logic in install-git-hooks.sh it would just install Husky. With that we gain some more options like branch specific hooks or envs to enable/disable hooks.

@heruan
Copy link
Member

heruan commented Jan 30, 2026

The problem with this is that once it copies hooks into .git/hooks, when you change the branch the hooks are still there and they will fail if the current branch does not have spotless. So either we make the hook check the branch first, or we add some logic to skip the hook when we run in other branches.

@mcollovati
Copy link
Collaborator

I guess this solution would also not work for Windows users

@Artur-
Copy link
Member Author

Artur- commented Jan 30, 2026

Let's see how it would look with husky. It would assume you have node installed

Replace custom shell-based git hooks with Husky for better branch
switching support. The .husky/ directory is version-controlled so
hooks update automatically when switching branches without manual
reinstallation.
Use npx husky@9.1.7 directly instead of relying on package.json.
@Artur-
Copy link
Member Author

Artur- commented Jan 30, 2026

Looks quite a lot simpler now

@Artur- Artur- requested a review from heruan January 30, 2026 16:16
@Artur-
Copy link
Member Author

Artur- commented Jan 30, 2026

should also work on windows

Move Husky installation to a profile activated by the absence of
.husky/_, so it runs only once instead of on every Maven execution.
@Artur-
Copy link
Member Author

Artur- commented Feb 9, 2026

@claude review this

@heruan
Copy link
Member

heruan commented Feb 9, 2026

Works on macOS, anyone able to test it on Windows?

@Artur-
Copy link
Member Author

Artur- commented Feb 9, 2026

@caalador maybe

@caalador
Copy link
Contributor

Does work on windows also.

Copy link
Contributor

@caalador caalador left a comment

Choose a reason for hiding this comment

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

Else ok, but could have a mention in the README that one should run the install-git-hooks profile once for this to start working.

@Artur-
Copy link
Member Author

Artur- commented Feb 10, 2026

The whole point is that you should not need that

@caalador
Copy link
Contributor

Well just doing a commit without once running the profile did not work.

@caalador
Copy link
Contributor

caalador commented Feb 10, 2026

Now it doesn't format at all when committing.
[edit] manually helps if you format the correct module.
[edit x2] after rerunning the maven install profile it seems to run spotless, but a commit takes ages as it goes through everything.

@heruan
Copy link
Member

heruan commented Feb 10, 2026

Adding <ratchetFrom>main</ratchetFrom> to Spotless plugin configuration might speed up a little by formatting only changed files.

@mcollovati
Copy link
Collaborator

Adding <ratchetFrom>main</ratchetFrom> to Spotless plugin configuration might speed up a little by formatting only changed files.

How does that work? Does it compare with local main or origin/main?
And what about the maintenance branches (for example, once we'll move main to 25.2)? Should the configuration be changed when branching out the maintenance branch?

@heruan
Copy link
Member

heruan commented Feb 10, 2026

How does that work? Does it compare with local main or origin/main?

With this it compares to local main, otherwise we should have <ratchetFrom>origin/main</ratchetFrom>.

And what about the maintenance branches (for example, once we'll move main to 25.2)? Should the configuration be changed when branching out the maintenance branch?

Right, and we will forget. Maybe the reference branch can be inferred with some git command?

@Artur-
Copy link
Member Author

Artur- commented Feb 12, 2026

When I try this on Windows in a virtual machine, it does activate the profile but it does not install the hook because on windows the command is npx.cmd and not npx

Edit: This does not sound correct either. Might be something wrong with the node installation

@Artur-
Copy link
Member Author

Artur- commented Feb 12, 2026

I had a broken Node installation. Now with a new Node 24, I see on the first mvn install that it runs install-git-hook, so it works automatically for me on Windows

@Artur-
Copy link
Member Author

Artur- commented Feb 12, 2026

Also mvn help:active-profiles -pl . shows

install-git-hooks

initially and no longer shows that after mvn install once the hooks has been installed

Husky runs hooks with `sh -e`, so grep returning 1 (no matches)
killed the script before reaching the empty-check guard. Also
removed GNU-only `xargs -r` flag for Windows compatibility.
@github-actions github-actions bot added +1.0.0 and removed +0.0.1 labels Feb 12, 2026
…mmit hook

Compute the merge-base between HEAD and the upstream tracking branch,
and pass it to Spotless via -Dspotless.ratchetFrom so only files
changed since the branch diverged are formatted. This avoids running
Spotless on the entire codebase on every commit. The property defaults
to empty so plain `mvn spotless:apply` still formats everything.
When HEAD is detached (e.g. during rebase), there is no upstream
tracking branch so @{u} fails. Exit gracefully and let the commit
proceed without formatting.
@Artur- Artur- requested review from heruan February 12, 2026 13:22
heruan
heruan previously approved these changes Feb 12, 2026
@Artur-
Copy link
Member Author

Artur- commented Feb 12, 2026

npm warn exec The following package was not found and will be installed: husky@9.1.7
npm warn exec The following package was not found and will be installed: husky@9.1.7
npm warn exec The following package was not found and will be installed: husky@9.1.7
npm warn exec The following package was not found and will be installed: husky@9.1.7
sh: 1: husky: Text file busy

Is this broken for parallel builds?

Use a lock directory (mkdir is atomic) to ensure only one process
runs npx husky in parallel Maven builds. Move the logic to a
dedicated script in scripts/.
@github-actions github-actions bot added +0.0.1 and removed +1.0.0 labels Feb 12, 2026
Copy link
Member

@heruan heruan left a comment

Choose a reason for hiding this comment

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

Added some comments from Claude. Starts feeling like this could have some unexpected site-effects, would it be performance or committing unwanted changes.

If we decide to go on and merge, I'd suggest to communicate this change and ask feedback.

- Fix installHusky.js lock cleanup: use finally block so the lock
  directory is always removed even if npx throws, preventing stuck locks
- Fix pre-commit partial staging: stash unstaged changes before
  formatting and restore after, so `git add -p` workflows are preserved
@sonarqubecloud
Copy link

Copy link
Member

@heruan heruan left a comment

Choose a reason for hiding this comment

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

LGTM now! I suggest to document this hook in CONTRIBUTING.md or where else appropriate.

@Artur- Artur- merged commit 43f4b9f into main Feb 18, 2026
31 checks passed
@Artur- Artur- deleted the spotless-pre-commit-hook branch February 18, 2026 07:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

Comments