diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 000000000..f469020db --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,2 @@ +#!/bin/sh +exec "$(git rev-parse --show-toplevel)/.github/scripts/clang-format-check.sh" diff --git a/.github/scripts/clang-format-check.sh b/.github/scripts/clang-format-check.sh new file mode 100755 index 000000000..b042fc64f --- /dev/null +++ b/.github/scripts/clang-format-check.sh @@ -0,0 +1,70 @@ +#!/bin/sh +# +# Rejects changed lines that are not clang-format clean. Shared by the +# pre-commit hook and by CI so both judge identically. +# +# clang-format-check.sh staged changes (pre-commit) +# clang-format-check.sh changes since (CI) +# +# Only the changed lines are checked, so this does not demand a reformat +# of surrounding code that predates the style file. +# +# git-clang-format spawns a separate clang-format, defaulting to the +# unversioned one on PATH, so the wrapper and the binary are both pinned +# here. A mismatched pair fails outright. +# +# Bypass: +# git commit -n skips every hook +# SKIP_CLANG_FORMAT=1 git ... skips just this check +# + +[ -n "$SKIP_CLANG_FORMAT" ] && exit 0 + +ver=${CLANG_FORMAT_VERSION:-18} +bin="clang-format-$ver" +wrapper="git-clang-format-$ver" + +top=$(git rev-parse --show-toplevel 2>/dev/null) || exit 0 +[ -f "$top/.clang-format" ] || exit 0 + +# Skipping keeps a missing formatter from blocking commits. CI asserts the +# binaries are present in a separate step, so it cannot skip silently. +if ! command -v "$wrapper" >/dev/null 2>&1; then + echo "clang-format: $wrapper not found, skipping" >&2 + exit 0 +fi + +# git-clang-format needs a commit to diff against, so the very first +# commit in a repo cannot be checked. +git rev-parse --verify --quiet HEAD >/dev/null || exit 0 + +if [ -n "$1" ]; then + scope=$1 +else + scope=--staged +fi + +out=$("$wrapper" --binary "$bin" --diff -q "$scope" 2>&1) +ret=$? + +if [ $ret -eq 0 ]; then + exit 0 +fi + +if [ $ret -ne 1 ]; then + echo "$out" >&2 + echo "clang-format: $wrapper failed (exit $ret)" >&2 + exit $ret +fi + +echo "$out" +echo "" +echo "ERROR: changed lines are not clang-format clean." +echo "" +# Not "&& git add -u": the wrapper exits 1 when it reformats something. +echo "Fix with:" +echo " $wrapper --binary $bin $scope; git add -u" +echo "" +echo "Or bypass with:" +echo " SKIP_CLANG_FORMAT=1 git commit ..." +exit 1 diff --git a/.github/workflows/clang-format-check.yml b/.github/workflows/clang-format-check.yml index 77e65e32c..9626e0584 100644 --- a/.github/workflows/clang-format-check.yml +++ b/.github/workflows/clang-format-check.yml @@ -13,7 +13,7 @@ permissions: jobs: clang-format-check: - name: Check PR formatting with clang-format-15 + name: Check PR formatting with clang-format-18 runs-on: ubuntu-latest timeout-minutes: 5 @@ -23,9 +23,15 @@ jobs: with: fetch-depth: 0 # Need full history to compare with main branch - - name: Install clang-format-15 + - name: Verify clang-format-18 run: | - sudo apt-get install -y clang-format-15 + # 18 is preinstalled on ubuntu-latest. use it to avoid an update+install + command -v clang-format-18 >/dev/null || { + echo "clang-format-18 is missing from the runner image"; exit 1; } + command -v git-clang-format-18 >/dev/null || { + echo "git-clang-format-18 is missing from the runner image"; exit 1; } + clang-format-18 --version + clang-format --version || true - name: Fetch base branch env: @@ -35,44 +41,8 @@ jobs: - name: Check formatting env: - BASE_SHA: ${{ github.event.pull_request.base.sha }} BASE_REF: ${{ github.event.pull_request.base.ref }} run: | - echo "Running git-clang-format-15 to check for formatting issues..." echo "Comparing against base branch: $BASE_REF" - - # Create a temporary file for the diff and ensure cleanup - DIFF_FILE="$(mktemp)" - trap 'rm -f "$DIFF_FILE"' EXIT - - # Run git-clang-format against the PR base commit and capture status safely under set -e - if git-clang-format-15 "$BASE_REF" > "$DIFF_FILE"; then - status=0 - else - status=$? - fi - - if [ "$status" -eq 0 ]; then - echo "✅ Code is properly formatted!" - exit 0 - elif [ "$status" -eq 1 ]; then - echo "❌ Code formatting issues detected!" - echo "" - echo "The following changes would be made by clang-format-15:" - echo "==================================================" - cat "$DIFF_FILE" - echo "==================================================" - echo "" - echo "Please run the following command locally on your feature branch and commit the changes:" - echo " git-clang-format-15 $BASE_REF" - exit 0 - # TEMPORARY DISABLE DUE TO BUGS - #exit 1 - else - echo "❌ git-clang-format-15 failed with exit code $status" - echo "Output (if any):" - cat "$DIFF_FILE" - exit 0 - # TEMPORARY DISABLE DUE TO BUGS - #exit 1 - fi + # Same script the pre-commit hook runs, so local and CI agree. + .github/scripts/clang-format-check.sh "$BASE_REF" diff --git a/README.md b/README.md index 653da9105..971ddfbaa 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,13 @@ PKCS11 and AUTOSAR SHE. For a technical overview of wolfHSM and instructions on using wolfHSM in your application, please refer to the following resources. +## Formatting + +Enable the pre-commit clang-format check, once per clone: + + sudo apt-get install -y clang-format-18 + git config core.hooksPath .githooks + ## Resources - [wolfHSM Manual](https://www.wolfssl.com/documentation/manuals/wolfhsm/index.html)