diff --git a/.clang-format b/.clang-format new file mode 100644 index 000000000..44397b42f --- /dev/null +++ b/.clang-format @@ -0,0 +1,4 @@ +BasedOnStyle: Google +IndentWidth: 4 +AccessModifierOffset: -4 +SortIncludes: false # FIXME: https://github.com/4jcraft/4jcraft/issues/225 \ No newline at end of file diff --git a/.github/scripts/check-clang-format.sh b/.github/scripts/check-clang-format.sh new file mode 100644 index 000000000..3efb79fe5 --- /dev/null +++ b/.github/scripts/check-clang-format.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash + +set -euo pipefail + +formatter="${CLANG_FORMAT_BIN:-clang-format-19}" +base_ref="${1:-}" +head_ref="${2:-HEAD}" + +if [[ -z "$base_ref" ]]; then + if git rev-parse --verify HEAD^ >/dev/null 2>&1; then + base_ref="$(git rev-parse HEAD^)" + else + echo "No comparison base available; skipping clang-format check." + exit 0 + fi +fi + +diff_output="$( + git diff --name-only --diff-filter=ACMR "$base_ref" "$head_ref" -- \ + '*.c' '*.cc' '*.cpp' '*.cxx' '*.h' '*.hh' '*.hpp' '*.hxx' '*.inl' +)" + +if [[ -z "$diff_output" ]]; then + echo "No changed C/C++ files to check." + exit 0 +fi + +mapfile -t files <<<"$diff_output" + +echo "Checking formatting for changed files:" +printf ' %s\n' "${files[@]}" + +"$formatter" --version +"$formatter" --dry-run --Werror "${files[@]}" \ No newline at end of file diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml new file mode 100644 index 000000000..a125848e6 --- /dev/null +++ b/.github/workflows/clang-format.yml @@ -0,0 +1,69 @@ +name: Clang Format + +on: + push: + paths: + - '**.cpp' + - '**.h' + - '**.c' + - '**.cc' + - '**.cxx' + - '**.hh' + - '**.hpp' + - '**.hxx' + - '**.inl' + - '.clang-format' + - '.github/workflows/clang-format.yml' + - '.github/scripts/check-clang-format.sh' + pull_request: + paths: + - '**.cpp' + - '**.h' + - '**.c' + - '**.cc' + - '**.cxx' + - '**.hh' + - '**.hpp' + - '**.hxx' + - '**.inl' + - '.clang-format' + - '.github/workflows/clang-format.yml' + - '.github/scripts/check-clang-format.sh' + +jobs: + clang-format: + runs-on: ubuntu-24.04 + concurrency: + group: clang-format-${{ github.ref }} + cancel-in-progress: true + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Install clang-format + run: | + sudo apt-get update + sudo apt-get install -y clang-format-19 + + - name: Check changed files + env: + CLANG_FORMAT_BIN: clang-format-19 + EVENT_NAME: ${{ github.event_name }} + PR_BASE_REF: ${{ github.event.pull_request.base.ref }} + PR_BASE_SHA: ${{ github.event.pull_request.base.sha }} + BEFORE_SHA: ${{ github.event.before }} + CURRENT_SHA: ${{ github.sha }} + run: | + set -euo pipefail + + BASE_SHA="" + if [ "$EVENT_NAME" = "pull_request" ]; then + git fetch --no-tags origin "$PR_BASE_REF" --depth=1 + BASE_SHA="$(git merge-base "origin/$PR_BASE_REF" "$CURRENT_SHA")" + elif [ -n "$BEFORE_SHA" ] && [ "$BEFORE_SHA" != "0000000000000000000000000000000000000000" ]; then + BASE_SHA="$BEFORE_SHA" + fi + + bash ./.github/scripts/check-clang-format.sh "$BASE_SHA" "$CURRENT_SHA" \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8f6de058d..7c2dcf001 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,7 +32,9 @@ Commit names should clearly describe what was changed in the commit. [Convention ### Keep code clean and readable. -At this time, we do not have a style guide or rules for how code should be formatted. In general, code should be readable and try to match the styling and conventions of whatever is around it. +Code formatting is defined by the repository's [`.clang-format`](./.clang-format) file. If you are touching C or C++ source, format the files you changed before opening or updating a pull request. + +CI checks formatting on changed C and C++ files, so local formatting mismatches will fail the relevant workflow. ### Avoid changing in-game behavior.