Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,22 @@ repos:
rev: v2.4.1
hooks:
- id: codespell
args: [-w, --config, ./.github/coding-convention-tool/tools/.codespell/.codespellrc]
args: [-w, --config, /action/tools/.codespell/.codespellrc]
- repo: https://github.com/pocc/pre-commit-hooks
rev: v1.3.5
hooks:
- id: uncrustify
args: [-c, ./uncrustify/uncrustify.cfg, -lC, --no-backup, --replace]
args:
[
-c,
/action/tools/uncrustify/uncrustify.cfg,
-lC,
--no-backup,
--replace,
]
- id: clang-tidy
args:
- --config-file=./.clang-tidy
- --config-file=/action/tools/.clang-tidy
- --use-color
- --extra-arg=-I/inc
- --header-filter:'^((?!test).)*$'
Expand Down
32 changes: 32 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
FROM ubuntu:22.04

ENV DEBIAN_FRONTEND=noninteractive

# Install dependencies
RUN apt-get update && apt-get install -y --no-install-recommends \
python3 python3-pip python3-venv \
binutils ca-certificates git cmake make gcc g++ libc6-dev \
clang-tidy \
&& rm -rf /var/lib/apt/lists/* && \
python3 -m pip install --no-cache-dir --upgrade pip && \
python3 -m pip install --no-cache-dir pre-commit

# Build uncrustify 0.64
WORKDIR /tmp
RUN git clone -b uncrustify-0.64 --single-branch https://github.com/uncrustify/uncrustify.git uncrustify && \
cd uncrustify && \
mkdir build && cd build && \
cmake -D CMAKE_INSTALL_PREFIX=/usr/local -D CMAKE_BUILD_TYPE=RelWithDebInfo ../ && \
make -j "$(nproc)" && \
make install && \
cd /tmp && rm -rf uncrustify

# Set up Action resources
WORKDIR /action
COPY .pre-commit-config.yaml /action/
COPY tools /action/tools
COPY entrypoint.sh /entrypoint.sh

RUN chmod +x /entrypoint.sh

ENTRYPOINT ["/entrypoint.sh"]
167 changes: 56 additions & 111 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,133 +1,78 @@
# Coding Convention Tool
This is a code formatter tool that helps ensure consistent coding style and detects common issues in source code files. It integrates with [pre-commit](https://pre-commit.com/), allowing you to automate code formatting and checks as part of your development workflow.
# Code Convention Tool

## Features

- Automatically fixes end-of-file issues.
- Removes trailing whitespace from lines.
- Identifies and suggests fixes for common spelling errors using [codespell](https://github.com/codespell-project/codespell).
- Formats code according to specified [Uncrustify](https://github.com/uncrustify/uncrustify) rules base on [Silabs's coding standard](https://github.com/SiliconLabsSoftware/agreements-and-guidelines/blob/main/coding_standard.md)
- Checks for identifiers naming style mismatch of function, definition, struct, variable using [clang-tidy](https://releases.llvm.org/14.0.0/tools/clang/tools/extra/docs/clang-tidy/index.htmlextensible)

## Project Structure

* **tools**:
* **.codespell**
* **exclude-file.txt**: Contains lines to be excluded from Codespell checks.
* **ignore-words.txt**: Contains words to be ignored by Codespell to avoid false positives.
* **uncrustify.cfg**: Configuration file for Uncrustify, specifying the coding style and formatting rules.
* **.clang-tidy**: Configuration file for clang-tidy, specifying checks and options for static analysis.

* **.pre-commit-config.yaml**: Configuration file for pre-commit, defining the hooks and their settings to be run before commits.
## Installation
### Ubuntu
Recommended operating system: WSL, Ubuntu 22.04.

Ensure Python3 is installed on your system. Then, install pre-commit clang-format clang-tidy cppcheck by running:
```
$ pip install pre-commit
$ sudo apt install uncrustify clang-tidy cppcheck
```

Recommended version:
- Codespell 2.2.4
- Uncrustify 0.64.0 // Silabs specific uncrustify.cfg support only this version
- Clang tidy 14.0.0
Docker-based code formatting and static analysis. Identical checks in CI and locally.

### Windows
## Features
- **Uncrustify v0.64** - Formatting ([Silabs Style](https://github.com/SiliconLabsSoftware/agreements-and-guidelines/blob/main/coding_standard.md))
- **Clang-Tidy** - Naming conventions & common errors
- **Codespell** - Spell checking
- **Patch** - Generates patch for automated corrections

TBD
## How It Works

This composite action uses Docker to isolate tool dependencies from your repository:

### Exclude Folder
1. **Your workflow** checks out your code to `${{ github.workspace }}`
2. **Action downloads** config files automatically from this repo
3. **Docker image built** with pre-commit, uncrustify, clang-tidy, codespell
4. **Container mounts** your repo as `/src` (read-write volume)
5. **Pre-commit runs** checks against your code, modifying files in-place
6. **Results saved** to your workspace: `CodingConventionTool.txt`, `code-fix.patch`

When using this tool, you may want to skip some folders. You can specify folders to exclude from formatting and checks by replacing the exclude regex pattern with the folders you want to skip.
**Security for Internal Repos:**
- Use `runs-on: [self-hosted, ...]` to keep proprietary code on-premises
- All processing is local; no code transmitted externally
- Only action config files (public tools) are downloaded

Here's how you can exclude folders ```build``` and ```gecko_sdk_xxx```using regex patterns in [.pre-commit-config.yaml](./.pre-commit-config.yaml) file:
## Usage

### GitHub Actions
```yaml
exclude: .*/build/.*|.*/gecko_sdk.*/.*
- name: Checkout
uses: actions/checkout@v4

- name: Code Convention Check
uses: SiliconLabsSoftware/devs-coding-convention-tool@main
with:
custom-ignore-words: "" # Optional
custom-exclude-file: "" # Optional
custom-pre-commit-config: "" # Optional
```

### Exclude File, Ignore Words for Codespell
**Outputs:** `CodingConventionTool.txt` (report), `code-fix.patch` (diff)

When using Codespell, you may encounter false positives or want to exclude specific files or directories from being checked. Codespell provides configuration options to handle these scenarios.
### Local Docker

Here's an example of a codespell configuration file [.codespellrc](tools/.codespell/.codespellrc)
**Quick Start** (from your repo root):
```bash
# Build image
git clone https://github.com/SiliconLabsSoftware/devs-coding-convention-tool.git /tmp/convention-tool
docker build -t convention-tool /tmp/convention-tool

# Run checks
docker run --rm -v "$(pwd):/src" convention-tool
```
ignore-words = ./tools/.codespell/ignore-words.txt
exclude-file = ./tools/.codespell/exclude-file.txt
check-filenames =
check-hidden =
count =
skip = .git,*.a,
```

Explanation of Configuration Options

* **[ignore-words](tools/.codespell/ignore-words.txt)** : This option points to a file containing words that should be ignored by Codespell. If you encounter a false positive, add the problematic word to ignore-words.txt. Ensure each word is in lowercase and on a new line.

Example ignore-words.txt:

```
the
foobar
**With Custom Config:**
```bash
docker run --rm \
-v "$(pwd):/src" \
-e CUSTOM_IGNORE_WORDS=".github/formatting_config/ignore-words.txt" \
-e CUSTOM_EXCLUDE_FILE=".github/formatting_config/exclude-file.txt" \
-e CUSTOM_PRE_COMMIT_CONFIG=".github/formatting_config/.pre-commit-config.yaml" \
convention-tool
```
* **[exclude-file](tools/.codespell/exclude-file.txt)** : This option points to a file containing lines that should be excluded from spell-checking. If a specific line in your code is causing a false positive, copy and paste the entire line into exclude-file.txt.

Example exclude-file.txt:
```
This is a sample line that should be excluded.
```
* **check-filenames**: Set this option to true if you want Codespell to check filenames for spelling errors. By default, this is empty (disabled).
Files modified in-place. Review: `git diff`

* **check-hidden**: Set this option to true if you want Codespell to check hidden files for spelling errors. By default, this is empty (disabled).
## Configuration

* **count**: Set this option to true if you want Codespell to display the number of occurrences of each misspelled word. By default, this is empty (disabled).

* **skip**: This option allows you to specify files or directories that Codespell should skip. You can list multiple entries separated by commas. For example, .git,*.a, will skip the .git directory and all files with the .a extension.

### Uncrustify

Automatic source code formatting follows [Silabs's coding standard](https://github.com/SiliconLabsSoftware/agreements-and-guidelines/blob/main/coding_standard.md)
The Uncrustify configuration file is located at [/tools/uncrustify/uncrustify.cfg](./tools/uncrustify/uncrustify.cfg).


### Clang-Tidy

**Checks for identifiers naming style mismatch**

Clang-Tidy supports checking casing types (UPPER_CASE/lower_case) and prefixes of Function, Struct, Enum, Global Constant.
You can modify the prefix in the file [.clang-tidy](./tools/.clang-tidy).

For example, config function with lower_case and prefix 'sl_'
```
- key: readability-identifier-naming.FunctionCase
value: lower_case
- key: readability-identifier-naming.FunctionPrefix
value: 'sl_'
```

**Adding Extra Arguments**

You may need to provide additional paths to header files or define macros for Clang-Tidy to ensure it correctly analyzes your code. This can be done using the ```--extra-arg``` option in the hook configuration.

To add extra arguments to the clang-tidy hook, modify the args section of the hook configuration in your .pre-commit-config.yaml file. Here's an example of how to add extra arguments:

```yaml
- repo: https://github.com/pocc/pre-commit-hooks
rev: v1.3.5
hooks:
- id: clang-tidy
args:
- --config-file=./tools/.clang-tidy
- --use-color
- --extra-arg=-I/inc/
- --extra-arg=-DMY_MACRO=1
```
In this example, we've added two extra arguments to Clang-Tidy:
Default rules embedded at build time:

```-I/inc/```: Specifies an include directory where Clang-Tidy will look for header files.
| Tool | Config Path | Customization |
| -------------- | --------------------------------- | ------------------------------------------ |
| **Uncrustify** | `tools/uncrustify/uncrustify.cfg` | Override via `custom-pre-commit-config` |
| **Clang-Tidy** | `tools/.clang-tidy` | Override via `custom-pre-commit-config` |
| **Codespell** | `tools/.codespell/` | Override via `custom-ignore-words/exclude` |

```-DMY_MACRO=1```: Defines a macro named MY_MACRO with the value 1 for use in the code analysis.
Use `custom-pre-commit-config` to provide your own `.pre-commit-config.yaml` for full control.
65 changes: 65 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
name: "Code Convention Check"
description: "Check code conventions using Docker container"

inputs:
custom-exclude-file:

Choose a reason for hiding this comment

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

This exclude file is the deceptive exclude file of the coding convention?
Because that is basically useless, would be much better to have an actual exclude with regex/glob.
(The other option is the custom pre-commit config which is not really nice.)

description: "Path to custom exclude file (relative to repo root)"
required: false
default: ""

custom-ignore-words:
description: "Path to custom ignore words file (relative to repo root)"
required: false
default: ""

custom-pre-commit-config:
description: "Path to custom pre-commit config file (relative to repo root)"
required: false
default: ""

runner-type:
description: "Runner type (deprecated, now runs in Docker)"
required: false
default: "auto"

runs:
using: "composite"
steps:
- name: Build Code Convention Docker Image
shell: bash
run: |
docker build -t coding-convention-tool:${{ github.sha }} ${{ github.action_path }}

- name: Run Code Convention Checks
shell: bash
run: |
docker run --rm \
-v "${{ github.workspace }}:/src" \
-e CUSTOM_EXCLUDE_FILE="${{ inputs.custom-exclude-file }}" \
-e CUSTOM_IGNORE_WORDS="${{ inputs.custom-ignore-words }}" \
-e CUSTOM_PRE_COMMIT_CONFIG="${{ inputs.custom-pre-commit-config }}" \
coding-convention-tool:${{ github.sha }}

- name: Upload Results
uses: actions/upload-artifact@v4
if: always()
with:
name: CodingConventionResult
path: ${{ github.workspace }}/CodingConventionTool.txt
retention-days: 3

- name: Upload Patch
uses: actions/upload-artifact@v4
if: always()
with:
name: code-fix.patch
path: ${{ github.workspace }}/code-fix.patch
retention-days: 3

- name: Check Results
shell: bash
run: |
if grep -iq "Failed" ${{ github.workspace }}/CodingConventionTool.txt; then
echo "Code convention check failed"
exit 1
fi
65 changes: 65 additions & 0 deletions entrypoint.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#!/bin/bash
set -e

SW_REPO_DIR="/src"
ACTION_REPO_DIR="/action"

# Set cache directories for pre-commit (non-root user needs writable location)
export HOME="$SW_REPO_DIR"
export XDG_CACHE_HOME="$SW_REPO_DIR/.cache"

cd "$SW_REPO_DIR" || exit 1

git config --system --add safe.directory "$SW_REPO_DIR" 2>/dev/null || \
git config --add safe.directory "$SW_REPO_DIR"

echo "=== Configuration Status ==="
echo "CUSTOM_EXCLUDE_FILE: ${CUSTOM_EXCLUDE_FILE:-<not set>}"
echo "CUSTOM_IGNORE_WORDS: ${CUSTOM_IGNORE_WORDS:-<not set>}"
echo "CUSTOM_PRE_COMMIT_CONFIG: ${CUSTOM_PRE_COMMIT_CONFIG:-<not set>}"
echo "==========================="

# Handle custom configuration

if [ -n "$CUSTOM_PRE_COMMIT_CONFIG" ]; then
if [ -f "$SW_REPO_DIR/$CUSTOM_PRE_COMMIT_CONFIG" ]; then
echo "Applying custom pre-commit config: $CUSTOM_PRE_COMMIT_CONFIG"
cp "$SW_REPO_DIR/$CUSTOM_PRE_COMMIT_CONFIG" "$ACTION_REPO_DIR/.pre-commit-config.yaml"
else
echo "Warning: Custom pre-commit config not found: $CUSTOM_PRE_COMMIT_CONFIG"
fi
fi

if [ -n "$CUSTOM_EXCLUDE_FILE" ]; then
if [ -f "$SW_REPO_DIR/$CUSTOM_EXCLUDE_FILE" ]; then
echo "Applying custom exclude file: $CUSTOM_EXCLUDE_FILE"
cp "$SW_REPO_DIR/$CUSTOM_EXCLUDE_FILE" "$ACTION_REPO_DIR/tools/.codespell/exclude-file.txt"
else
echo "Warning: Custom exclude file not found: $CUSTOM_EXCLUDE_FILE"
fi
fi

if [ -n "$CUSTOM_IGNORE_WORDS" ]; then
if [ -f "$SW_REPO_DIR/$CUSTOM_IGNORE_WORDS" ]; then
echo "Applying custom ignore words: $CUSTOM_IGNORE_WORDS"
cp "$SW_REPO_DIR/$CUSTOM_IGNORE_WORDS" "$ACTION_REPO_DIR/tools/.codespell/ignore-words.txt"
else
echo "Warning: Custom ignore words file not found: $CUSTOM_IGNORE_WORDS"
fi
fi

echo "Installing pre-commit hooks..."
pre-commit install-hooks --config /action/.pre-commit-config.yaml

echo "Running pre-commit..."
set +e
pre-commit run --config /action/.pre-commit-config.yaml --all-files 2>&1 | tee CodingConventionTool.txt
PC_EXIT=${PIPESTATUS[0]}
set -e

git diff > code-fix.patch || echo "No changes to patch."

if [ "$PC_EXIT" -ne 0 ]; then
echo "Pre-commit failed with exit code $PC_EXIT"
exit "$PC_EXIT"
fi
Loading