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
9 changes: 1 addition & 8 deletions .github/workflows/continuous_integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -924,11 +924,4 @@ jobs:
- uses: actions/checkout@v4

- name: Check for tabs
# Ensure that there are no tabs in source code.
# GREP returns 0 (true) if there are any matches, and
# we don't want any matches. If there are matches,
# print a helpful message, and make the test fail by using "false".
# The GREP command here checks for any tab characters in the the files
# that match the specified pattern. GREP does not pick up explicit tabs
# (e.g., literally a \t in a source file).
run: if grep --line-num --recursive --exclude-dir="*dependencies*" --exclude-dir="*snopt*" --include={CMakeLists.txt,*.cpp,*.c,*.h} -P "\t" . ; then echo "Tabs found in the lines shown above. See CONTRIBUTING.md about tabs."; false; fi
run: scripts/tools/check-tabs.sh
18 changes: 18 additions & 0 deletions .github/workflows/pr_static_analysis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: static-analysis

on:
pull_request:

jobs:
format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Fetch full history for branches

- name: Fetch the main branch
run: git fetch origin main:refs/remotes/origin/main

- name: Check code formatting with clang-format against main
run: scripts/tools/check-format.sh --branch remotes/origin/main
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ install
# OpenSim
err.log
out.log
logs/*.log
logs/*.dot
logs/*.svg

# Mac
.DS_Store
Expand Down
Empty file added logs/.gitkeep
Empty file.
139 changes: 139 additions & 0 deletions scripts/tools/check-format.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
#!/bin/bash
# Check the changed code against the clang-format code style for the repository.
# Uses a copy of https://github.com/llvm/llvm-project/blob/main/clang/tools/clang-format/git-clang-format
# located in the scripts directory to check the formatting of the diff against main.
# The script will exit with a 1 if a diff is detected and a 0 if it isn't.
# If a diff is detected, you should run the script to fix the issues locally and commit again.

# Disable exit on error so we can handle return codes manually
set +e

# === Argument Parsing ===

FIX=0
BASE_REF="main"
OPEN_SIM_BASE="."
TOOLS_DIR="./scripts/tools"
LOG_DIR="./logs"
POSITIONAL=()

# Parse optional --fix flag
while [[ $# -gt 0 ]]; do
case "$1" in
-f|--fix)
FIX=1
shift
;;
-b|--branch)
BASE_REF="$2"
shift 2
;;
-h|--help)
echo "Usage: $0 [OPTIONS] [<opensim-base-dir>] [<tools-dir>]

Options:
-f, --fix Automatically apply formatting fixes if issues are found.
-b, --branch <name> Set the git base branch to diff against. Default: main
-h, --help Show this help message.

Positional Arguments:
<opensim-base-dir> Path to the OpenSim base directory. Default: current directory
<tools-dir> Path to the tools directory containing git-clang-format.py. Default: ./scripts/tools

Examples:
$0
$0 -b develop
$0 --fix $OPEN_SIM_BASE $TOOLS_DIR
"
exit 0
;;
-*)
echo "Unknown option: $1"
exit 1
;;
*)
POSITIONAL+=("$1")
shift
;;
esac
done

# Restore positional arguments
set -- "${POSITIONAL[@]}"

# Assign positional arguments with defaults
if [ ${#POSITIONAL[@]} -gt 0 ]; then
OPEN_SIM_BASE="${POSITIONAL[0]}"
fi

if [ ${#POSITIONAL[@]} -gt 1 ]; then
TOOLS_DIR="${POSITIONAL[1]}"
fi

OPEN_SIM_BASE=$(realpath "$OPEN_SIM_BASE")
TOOLS_DIR=$(realpath "$TOOLS_DIR")

# Independent log directory (relative to current working directory)
LOG_FILE="$LOG_DIR/clang-format.log"
GIT_CLANG_FORMAT="$TOOLS_DIR/git-clang-format.py"

# Ensure git-clang-format.py exists
if [ ! -f "$GIT_CLANG_FORMAT" ]; then
echo "Error: git-clang-format.py not found at $GIT_CLANG_FORMAT"
exit 1
fi

# Create log directory if it doesn't exist
mkdir -p "$LOG_DIR"

# Clear or create the log file
: > "$LOG_FILE"

# Save current directory
ORIG_DIR=$(pwd)

# Change to OpenSim base directory
cd "$OPEN_SIM_BASE" || {
echo "Error: Failed to cd into $OPEN_SIM_BASE"
exit 1
}

# Run git-clang-format with logging (from OpenSim base dir)
"$GIT_CLANG_FORMAT" "$BASE_REF" --diff | tee -a "$ORIG_DIR/$LOG_FILE"
rc1=${PIPESTATUS[0]}

"$GIT_CLANG_FORMAT" "$BASE_REF" --diffstat | tee -a "$ORIG_DIR/$LOG_FILE"
rc2=${PIPESTATUS[0]}

# Combine exit codes
FORMAT_ERROR=$(( rc1 || rc2 ))

# If --fix is specified and formatting issues exist, apply the fix
if [ "$FORMAT_ERROR" -ne 0 ] && [ "$FIX" -eq 1 ]; then
echo | tee -a "$ORIG_DIR/$LOG_FILE"
echo "Applying automatic formatting fixes..." | tee -a "$ORIG_DIR/$LOG_FILE"
"$GIT_CLANG_FORMAT" "$BASE_REF" | tee -a "$ORIG_DIR/$LOG_FILE"
echo "Fixes applied. Please review and re-commit your changes." | tee -a "$ORIG_DIR/$LOG_FILE"
fi


# Return to original directory
cd "$ORIG_DIR"

# Final message
if [ "$FORMAT_ERROR" -ne 0 ]; then
if [ "$FIX" -eq 1 ]; then
echo "Fix mode enabled. Formatting was corrected." | tee -a "$LOG_FILE"
FORMAT_ERROR=0
else
echo | tee -a "$LOG_FILE"
echo "Formatting issues found! Run the following command to fix them:" | tee -a "$LOG_FILE"
echo | tee -a "$LOG_FILE"
echo " $0 --fix --branch \"$BASE_REF\" \"$OPEN_SIM_BASE\" \"$TOOLS_DIR\"" | tee -a "$LOG_FILE"
echo | tee -a "$LOG_FILE"
fi
else
echo "No formatting issues found." | tee -a "$LOG_FILE"
fi

exit $FORMAT_ERROR
50 changes: 50 additions & 0 deletions scripts/tools/check-tabs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/bin/bash
# Ensure that there are no tabs in source code.
# GREP returns 0 (true) if there are any matches, and
# we don't want any matches. If there are matches,
# print a helpful message, and make the test fail by using "false".
# The GREP command here checks for any tab characters in the the files
# that match the specified pattern. GREP does not pick up explicit tabs
# (e.g., literally a \t in a source file).


OPEN_SIM_BASE="."

if [[ "$1" == "-h" || "$1" == "--help" ]]; then
echo "Usage: $0 [<opensim-base-dir>]

Checks source files for tab characters.

Arguments:
<opensim-base-dir> Optional. Path to the OpenSim base directory. Default: current directory

Examples:
$0
$0 ./src/OpenSim
"
exit 0
fi
# Use the first argument if provided
if [ $# -ge 1 ]; then
OPEN_SIM_BASE="$1"
fi

OPEN_SIM_BASE=$(realpath "$OPEN_SIM_BASE") || {
echo "Error: '$1' is not a valid directory."
exit 1
}

if [ ! -d "$OPEN_SIM_BASE" ]; then
echo "Directory $OPEN_SIM_BASE does not exist."
exit 1
fi

# Search for tab characters in source files
if grep --line-number --recursive \
--exclude-dir="*dependencies*" \
--exclude-dir="*snopt*" \
--include={CMakeLists.txt,*.cpp,*.c,*.h} \
-P "\t" "$OPEN_SIM_BASE"; then
echo "Tabs found in the lines shown above. See CONTRIBUTING.md about tabs."
exit 1
fi
Loading
Loading