[GH-574] ci: Configure and integrate clang-format

git-clang-format ensures that all *new* code being submitted adheres to
the format dictated by clang-format.

The code style is based on LLVM (the creator of clang-format), but with
4 instead of 2 spaces indent width and a maximum of 120 instead of 80
characters per line in order to blend in well with existing code.

Please note:
- The er-coap-13 code gets exempt, as at some point, we probably want to
  to interact with whatever upstream there might be. For those files,
  just do what existing code does (which varies every few lines).
- Default is clang-format-10, which is available in the Ubuntu 20.04
  GitHub runner.
This commit is contained in:
Reto Schneider 2021-04-02 21:20:32 +02:00
parent c9cb48fc28
commit f623e8c0a5
6 changed files with 122 additions and 0 deletions

5
.clang-format Normal file
View File

@ -0,0 +1,5 @@
---
Language: Cpp
BasedOnStyle: LLVM
IndentWidth: 4
ColumnLimit: 120

1
.git-blame-ignore-revs Normal file
View File

@ -0,0 +1 @@
# This file contains all commits which are purely cosmetics

View File

@ -20,3 +20,22 @@ jobs:
- name: Check commits with gitlint
run: |
tools/ci/run_ci.sh --branch-target origin/${{ github.base_ref }} --run-gitlint
check-clang-format:
name: Run clang-format
runs-on: ubuntu-20.04
steps:
- name: Checkout code including full history
uses: actions/checkout@v2
with:
fetch-depth: 0
- name: Install clang-format
run: |
sudo apt update
sudo apt -qy --no-install-recommends install clang-format-10
- name: Check commits with clang-format
run: |
tools/ci/run_ci.sh --branch-target origin/${{ github.base_ref }} --run-clang-format

View File

@ -61,6 +61,37 @@ Several compilation switches are used:
Depending on your platform, you need to define LWM2M_BIG_ENDIAN or LWM2M_LITTLE_ENDIAN.
LWM2M_CLIENT_MODE and LWM2M_SERVER_MODE can be defined at the same time.
## Development
### Dependencies and Tools
- Mandatory:
- Compiler: GCC and/or Clang
- Optional (but strongly recommended):
- Build system generator: CMake 3.13+
- Version control system: Git (and a GitHub account)
- Git commit message linter: gitlint
- Build system: ninja
- C code formatting: clang-format, version 10
- Unit testing: CUnit
On Ubuntu 20.04, used in CI, the dependencies can be installed as such:
- `apt install build-essential clang-format clang-format-10 clang-tools-10 cmake gcovr git libcunit1-dev ninja-build python3-pip`
- `pip3 install gitlint`
### Code formatting
New code must be formatted with [clang-format](https://clang.llvm.org/docs/ClangFormat.html).
The style is based on the LLVM style, but with 4 instead of 2 spaces indentation and allowing for 120 instead of 80
characters per line.
To check if your code matches the expected style, the following commands are helpful:
- `git clang-format-10 --diff`: Show what needs to be changed to match the expected code style
- `git clang-format-10`: Apply all needed changes directly
- `git clang-format-10 --commit master`: Fix code style for all changes since master
If existing code gets reformatted, this must be done in a separate commit. Its commit id has to be added to the file
`.git-blame-ignore-revs` and committed in yet another commit.
## Examples

View File

@ -0,0 +1,4 @@
---
DisableFormat: true
SortIncludes: false
...

View File

@ -24,6 +24,7 @@ OPT_BRANCH_SOURCE=
OPT_BRANCH_TARGET=master
OPT_C_EXTENSIONS=""
OPT_C_STANDARD=""
OPT_CLANG_FORMAT="clang-format-10"
OPT_SANITIZER=""
OPT_SCAN_BUILD=""
OPT_SONARQUBE=""
@ -31,8 +32,10 @@ OPT_TEST_COVERAGE_REPORT=""
OPT_VERBOSE=0
OPT_WRAPPER_CMD=""
RUN_BUILD=0
RUN_CLANG_FORMAT=0
RUN_CLEAN=0
RUN_GITLINT=0
RUN_GIT_BLAME_IGNORE=0
RUN_TESTS=0
HELP_MSG="usage: ${SCRIPT_NAME} <OPTIONS>...
@ -49,6 +52,8 @@ Options:
(ENABLE: ON or OFF)
--c-standard VERSION Explicitly specify C VERSION to be used
(VERSION: 99, 11)
--clang-format BINARY Set specific clang-format binary
(BINARY: defaults to ${OPT_CLANG_FORMAT})
--sanitizer TYPE Enable sanitizer
(TYPE: address leak thread undefined)
--scan-build BINARY Enable Clang code analyzer using specified
@ -64,6 +69,8 @@ Options:
Available steps (executed by --all):
--run-gitlint Check git commits with gitlint
--run-clang-format Check code formatting with clang-format
--run-git-blame-ignore Validate .git-blame-ignore-revs
--run-clean Remove all build artifacts
--run-build Build all targets
--run-tests Build and execute tests
@ -76,6 +83,27 @@ function usage() {
exit "${exit_code}"
}
function run_clang_format() {
local patch_file
patch_file="$(mktemp -t clang-format-patch.XXX)"
# shellcheck disable=SC2064
trap "{ rm -f -- '${patch_file}'; }" EXIT TERM INT
"git-${OPT_CLANG_FORMAT}" --diff "${OPT_BRANCH_TARGET}" 2>&1 |
{ grep -v \
-e 'no modified files to format' \
-e 'clang-format did not modify any files' || true;
} > "${patch_file}"
if [ -s "${patch_file}" ]; then
cat "${patch_file}"
exit 1
fi
echo "No code formatting errors found"
}
function run_clean() {
rm -rf build-wakaama
}
@ -86,6 +114,15 @@ function run_gitlint() {
gitlint --commits "${commits}"
}
function run_git_blame_ignore() {
for commit in $(grep -E '^[A-Za-z0-9]{40}$' .git-blame-ignore-revs); do
if ! git merge-base --is-ancestor "${commit}" HEAD; then
echo ".git-blame-ignore-revs: Commit ${commit} is not an ancestor."
exit
fi
done
}
function run_build() {
# Existing directory needed by SonarQube build-wrapper
mkdir -p build-wakaama
@ -153,10 +190,13 @@ if ! PARSED_OPTS=$(getopt -o vah \
-l branch-target: \
-l c-extensions: \
-l c-standard: \
-l clang-format: \
-l help \
-l run-build \
-l run-clang-format \
-l run-clean \
-l run-gitlint \
-l run-git-blame-ignore \
-l run-tests \
-l sanitizer: \
-l scan-build: \
@ -188,6 +228,14 @@ while true; do
OPT_C_STANDARD=$2
shift 2
;;
--clang-format)
OPT_CLANG_FORMAT=$2
shift 2
;;
--run-clang-format)
RUN_CLANG_FORMAT=1
shift
;;
--run-clean)
RUN_CLEAN=1
shift
@ -200,6 +248,10 @@ while true; do
RUN_GITLINT=1
shift
;;
--run-git-blame-ignore)
RUN_GIT_BLAME_IGNORE=1
shift
;;
--run-tests)
RUN_TESTS=1
shift
@ -233,8 +285,10 @@ while true; do
shift
;;
-a|--all)
RUN_CLANG_FORMAT=1
RUN_CLEAN=1
RUN_GITLINT=1
RUN_GIT_BLAME_IGNORE=1
RUN_BUILD=1
RUN_TESTS=1
shift
@ -296,6 +350,14 @@ if [ "${RUN_GITLINT}" -eq 1 ]; then
run_gitlint
fi
if [ "${RUN_CLANG_FORMAT}" -eq 1 ]; then
run_clang_format
fi
if [ "${RUN_GIT_BLAME_IGNORE}" -eq 1 ]; then
run_git_blame_ignore
fi
if [ "${RUN_CLEAN}" -eq 1 ]; then
run_clean
fi