From bbe1190aa38185aa8b79bf7e898f732034366e05 Mon Sep 17 00:00:00 2001 From: Joe Latessa Date: Wed, 1 Apr 2026 15:21:44 -0400 Subject: [PATCH 1/2] use git hooks to run format checks --- .githooks/pre-commit | 6 ++++ CONTRIBUTING.md | 20 +++++++++++ bin/codebase-format-helper.bash | 14 +++----- bin/format-staged-files.sh | 64 +++++++++++++++++++++++++++++++++ bin/setup-hooks.sh | 30 ++++++++++++++++ 5 files changed, 124 insertions(+), 10 deletions(-) create mode 100755 .githooks/pre-commit create mode 100755 bin/format-staged-files.sh create mode 100755 bin/setup-hooks.sh diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 00000000..5010f84c --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -euo pipefail + +repo_root="$(git rev-parse --show-toplevel)" +"${repo_root}/bin/format-staged-files.sh" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f17d1828..f5056209 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -38,6 +38,26 @@ Tips for git management are found on the corresponding [wiki page](https://githu Tips for code formatting are found on the corresponding [wiki page](https://github.com/JETSCAPE/X-SCAPE/wiki/Doc.Policy.CodeFormatting). +### Optional Local git Hooks + +Enable a local formatter hook that runs on staged files before commit. +This is useful for catching formatting issues early, but remains optional. + +Setup: +``` +./bin/setup-hooks.sh +``` + +Notes: +- The setup-hooks script only needs to be run once per clone. +- The hook formats CMake files and C++ files in `src/` and `examples/`. +- The hook only checks staged files. +- Requires `clang-format` (v14) and `cmake-format` (v0.6.13) on PATH. + - Ubuntu / Debian: `sudo apt install clang-format-14 cmake-format` + - Package manager commands for other distributions may differ. +- Skip hooks for one commit with `git commit --no-verify`. +- To disable permanently, unset hooks with `git config --unset core.hooksPath`. + ## Unit Tests Please also see the [Unit Tests](https://github.com/JETSCAPE/X-SCAPE/wiki/Doc.Policy.UnitTests) page for details about writing unit tests to accompany your code contributions. diff --git a/bin/codebase-format-helper.bash b/bin/codebase-format-helper.bash index 322031a6..4943b3d1 100755 --- a/bin/codebase-format-helper.bash +++ b/bin/codebase-format-helper.bash @@ -123,17 +123,11 @@ function look_for_files_to_format() ) elif [[ ${language} = 'CMake' ]]; then FILES_TO_FORMAT=( - "${base_dir}"/**/CMakeLists.txt - "${base_dir}"/**/*.cmake + "${base_dir}"/CMakeLists.txt + "${base_dir}"/{src,examples}/**/CMakeLists.txt + "${base_dir}"/{src,examples}/**/*.cmake + "${base_dir}"/cmakemodules/**/*.cmake ) - for index in "${!FILES_TO_FORMAT[@]}"; do - if [[ ${FILES_TO_FORMAT[index]} =~ ^${base_dir}/3rdparty/(Cuba[^/]*/|CMakeLists.txt$) ]]; then - continue - elif [[ ${FILES_TO_FORMAT[index]} =~ ^${base_dir}/(3rdparty|build[^/]*)/ ]]; then - unset -v 'FILES_TO_FORMAT[index]' - fi - done - FILES_TO_FORMAT=("${FILES_TO_FORMAT[@]}") fi } diff --git a/bin/format-staged-files.sh b/bin/format-staged-files.sh new file mode 100755 index 00000000..971d005f --- /dev/null +++ b/bin/format-staged-files.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash + +set -euo pipefail + +if ! command -v clang-format >/dev/null 2>&1 || ! command -v cmake-format >/dev/null 2>&1; then + cat >&2 <<'EOF' +Formatter tools not found. Install them: + Ubuntu/Debian: sudo apt install clang-format-14 cmake-format +EOF + exit 1 +fi + +repo_root="$(git rev-parse --show-toplevel)" +cd "${repo_root}" + +mapfile -t staged_files < <(git diff --cached --name-only --diff-filter=ACMR 2>/dev/null || true) +if [[ ${#staged_files[@]} -eq 0 ]]; then + exit 0 +fi + +cpp_ext='(h|hpp|c|cc|cpp)$' +cmake_re='(^|/)CMakeLists\.txt$|\.cmake$' + +selected_files=() +for f in "${staged_files[@]}"; do + # Skip build folder and external packages + if [[ "${f}" == build/* || "${f}" == external_packages/* ]]; then + continue + fi + + # Include files matching CMakeLists.txt or .cmake + if [[ "${f}" =~ ${cmake_re} ]]; then + selected_files+=("${f}") + continue + fi + + # Include source files from src/ and examples/ + if [[ "${f}" =~ \.${cpp_ext} ]] && [[ "${f}" == src/* || "${f}" == examples/* ]]; then + selected_files+=("${f}") + fi +done + +if [[ ${#selected_files[@]} -eq 0 ]]; then + exit 0 +fi + +# format the selected files +for f in "${selected_files[@]}"; do + if [[ "${f}" =~ ${cmake_re} ]]; then + cmake-format -i "${f}" + else + clang-format -i -style=file "${f}" + fi +done + +# restage if changed +if ! git diff --quiet -- "${selected_files[@]}"; then + git add -- "${selected_files[@]}" + cat >&2 <<'EOF' +Formatting hook changed and restaged files. +EOF +fi + +exit 0 diff --git a/bin/setup-hooks.sh b/bin/setup-hooks.sh new file mode 100755 index 00000000..194506a0 --- /dev/null +++ b/bin/setup-hooks.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +set -euo pipefail + +if [[ ! -d .git ]]; then + echo "Error: Run this script from the repository's root directory." >&2 + exit 1 +fi + +if [[ ! -x .githooks/pre-commit ]]; then + echo "Error: Expected hook .githooks/pre-commit not found." >&2 + exit 1 +fi + +git config core.hooksPath .githooks +echo "Installed optional formatting hook." + +if ! command -v clang-format >/dev/null 2>&1 || ! command -v cmake-format >/dev/null 2>&1; then + cat >&2 <<'EOF' +Warning: Formatter utilities not found. Install them with your package manager: + Ubuntu / Debian: + sudo apt install clang-format-14 cmake-format + Package manager commands for other distributions may differ. + After installing the formatter utilities, re-run this setup script. +EOF + exit 1 +fi + +echo "clang-format and cmake-format are installed." + From 6cc27807a7d6cfde6d133f1d792f68bb997b78a2 Mon Sep 17 00:00:00 2001 From: Joe Latessa Date: Wed, 1 Apr 2026 22:32:39 -0400 Subject: [PATCH 2/2] update docs with option to install formatters with pip3 --- CONTRIBUTING.md | 2 ++ bin/setup-hooks.sh | 2 ++ 2 files changed, 4 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f5056209..947aee87 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -55,6 +55,8 @@ Notes: - Requires `clang-format` (v14) and `cmake-format` (v0.6.13) on PATH. - Ubuntu / Debian: `sudo apt install clang-format-14 cmake-format` - Package manager commands for other distributions may differ. + - `pip3 install clang-format==14.0.6 cmakelang` can be used. + - If using pip3, add the pip bin directory to the PATH, e.g. `export PATH="$HOME/.local/bin:$PATH"`. - Skip hooks for one commit with `git commit --no-verify`. - To disable permanently, unset hooks with `git config --unset core.hooksPath`. diff --git a/bin/setup-hooks.sh b/bin/setup-hooks.sh index 194506a0..3f7b6322 100755 --- a/bin/setup-hooks.sh +++ b/bin/setup-hooks.sh @@ -21,6 +21,8 @@ Warning: Formatter utilities not found. Install them with your package manager: Ubuntu / Debian: sudo apt install clang-format-14 cmake-format Package manager commands for other distributions may differ. + pip3 install clang-format==14.0.6 cmakelang can be used. + If using pip3, add the pip bin directory to the PATH, e.g. export PATH="$HOME/.local/bin:$PATH". After installing the formatter utilities, re-run this setup script. EOF exit 1