diff --git a/.github/problemMatcher/blackWarning.json b/.github/problemMatcher/blackWarning.json
new file mode 100644
index 0000000000..2d48de1576
--- /dev/null
+++ b/.github/problemMatcher/blackWarning.json
@@ -0,0 +1,15 @@
+{
+ "problemMatcher": [
+ {
+ "owner": "black-warning",
+ "severity": "warning",
+ "pattern": [
+ {
+ "regexp": "^(would reformat (.*))$",
+ "file": 2,
+ "message": 1
+ }
+ ]
+ }
+ ]
+}
diff --git a/.github/problemMatcher/clang.json b/.github/problemMatcher/clang.json
new file mode 100644
index 0000000000..b8a1185427
--- /dev/null
+++ b/.github/problemMatcher/clang.json
@@ -0,0 +1,17 @@
+{
+ "problemMatcher": [
+ {
+ "owner": "clang",
+ "pattern": [
+ {
+ "regexp": "^(.+):([0-9]+):([0-9]+): (error|warning|note): (.+)$",
+ "file": 1,
+ "line": 2,
+ "column": 3,
+ "severity": 4,
+ "message": 5
+ }
+ ]
+ }
+ ]
+}
diff --git a/.github/problemMatcher/codespell.json b/.github/problemMatcher/codespell.json
new file mode 100644
index 0000000000..e8f4f8381f
--- /dev/null
+++ b/.github/problemMatcher/codespell.json
@@ -0,0 +1,16 @@
+{
+ "problemMatcher": [
+ {
+ "owner": "codespell-matcher",
+ "severity": "warning",
+ "pattern": [
+ {
+ "regexp": "^(.+):(\\d+):\\s+(.+)$",
+ "file": 1,
+ "line": 2,
+ "message": 3
+ }
+ ]
+ }
+ ]
+}
diff --git a/.github/problemMatcher/cpplint.json b/.github/problemMatcher/cpplint.json
new file mode 100644
index 0000000000..79efedb0f1
--- /dev/null
+++ b/.github/problemMatcher/cpplint.json
@@ -0,0 +1,16 @@
+{
+ "problemMatcher": [
+ {
+ "owner": "cpplint",
+ "severity": "warning",
+ "pattern": [
+ {
+ "regexp": "^(.+):([0-9]+): (.+)$",
+ "file": 1,
+ "line": 2,
+ "message": 3
+ }
+ ]
+ }
+ ]
+}
diff --git a/.github/problemMatcher/grepMatcherWarning.json b/.github/problemMatcher/grepMatcherWarning.json
new file mode 100644
index 0000000000..49671d4253
--- /dev/null
+++ b/.github/problemMatcher/grepMatcherWarning.json
@@ -0,0 +1,16 @@
+{
+ "problemMatcher": [
+ {
+ "owner": "grepMatcher-warning",
+ "severity": "warning",
+ "pattern": [
+ {
+ "regexp": "^(.+):([0-9]+):(.+)$",
+ "file": 1,
+ "line": 2,
+ "message": 3
+ }
+ ]
+ }
+ ]
+}
diff --git a/.github/problemMatcher/pylintError.json b/.github/problemMatcher/pylintError.json
new file mode 100644
index 0000000000..8c5f73fbf5
--- /dev/null
+++ b/.github/problemMatcher/pylintError.json
@@ -0,0 +1,18 @@
+{
+ "problemMatcher": [
+ {
+ "owner": "pylint-error",
+ "severity": "error",
+ "pattern": [
+ {
+ "regexp": "^(.+?):([0-9]+):([0-9]+): ([([E|F][0-9]+): (.*)$",
+ "file": 1,
+ "line": 2,
+ "column": 3,
+ "code": 4,
+ "message": 5
+ }
+ ]
+ }
+ ]
+}
diff --git a/.github/problemMatcher/pylintWarning.json b/.github/problemMatcher/pylintWarning.json
new file mode 100644
index 0000000000..6a453f1d43
--- /dev/null
+++ b/.github/problemMatcher/pylintWarning.json
@@ -0,0 +1,18 @@
+{
+ "problemMatcher": [
+ {
+ "owner": "pylint-warning",
+ "severity": "warning",
+ "pattern": [
+ {
+ "regexp": "^(.+?):([0-9]+):([0-9]+): ([^E|F][0-9]+): (.*)$",
+ "file": 1,
+ "line": 2,
+ "column": 3,
+ "code": 4,
+ "message": 5
+ }
+ ]
+ }
+ ]
+}
diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml
new file mode 100644
index 0000000000..133eafb55f
--- /dev/null
+++ b/.github/workflows/checks.yml
@@ -0,0 +1,796 @@
+name: CI
+on:
+ pull_request:
+
+permissions:
+ pull-requests: write
+
+
+env:
+ logdir: logs/
+ fixesdir: fixes/
+
+ checkWhitespace: true
+ whitespaceFailSilent: true
+
+ checkTabs: true
+ tabsFailSilent: true
+
+ checkQtconnections: true
+ qtconnectionSyntaxFailSilent: true
+
+ checkCpplint: true
+ cpplintFilters: -build/header_guard,-readability/braces,-whitespace
+ cpplintLineLength: 120
+ cpplintFailSilent: true
+
+ checkPylint: true
+ pylintDisable: E0401,C0301,C0103,R0801,W0125
+ # for the Message codes see: https://pylint.pycqa.org/en/latest/user_guide/messages/index.html
+ # E0401: Unable to import '*' (import-error)
+ # C0103: Function name "*" doesn't conform to snake_case naming style (invalid-name)
+ # C0301: Line too long (118/100) (line-too-long)
+ # C0115: Missing class docstring (missing-class-docstring)
+ # C0116: Missing function or method docstring (missing-function-docstring)
+ # C0411: standard import "import *" should be placed before "import *" (wrong-import-order)
+ # R0801: Similar lines in 2 files --> not useful for us because not all files will be checked
+ # W0125: Using a conditional statement with a constant value (using-constant-test) --> often used for testing/debugging purposes in the Path module
+ pylintFailSilent: false
+
+ checkBlack: true
+ blackFailSilent: true
+
+ checkClangFormat: true
+ clangStyle: file #for .clang-format file
+ clangFormatFailSilent: true
+
+ checkSpelling: true
+ listIgnoredMisspelling: .github/codespellignore
+ skip: ./.git,*.po,*.ts,*.svg,./ChangeLog.txt,./src/3rdParty,./src/Mod/Assembly/App/opendcm,./src/CXX,./src/zipios++,./src/Base/swig*,./src/Mod/Robot/App/kdl_cp,./src/Mod/Import/App/SCL,./src/WindowsInstaller,./src/Doc/FreeCAD.uml,./build/
+ codespellFailSilent: false
+
+ checkClangTidy: true
+ clangTidyChecks: boost-*,bugprone-*,performance-*,readability-*,portability-*,modernize-*,clang-analyzer-*,cppcoreguidelines-*,concurrency-*
+ clangTidyFailSilent: false
+
+ checkClazy: true
+ clazyChecks: level1 # https://invent.kde.org/sdk/clazy#list-of-checks
+ clazyFailSilent: false
+
+ checkClazyQT6: true
+ clazyQT6Checks: qt6-deprecated-api-fixes,qt6-header-fixes,qt6-qhash-signature,qt6-fwd-fixes,missing-qobject-macro # for QT6 Porting https://invent.kde.org/sdk/clazy#list-of-checks
+ QT6Branch: master # branch to check for QT6 Porting
+ clazyQT6FailSilent: false
+
+ reportStepSummary: true
+ reportPRComment: false
+
+jobs:
+ checks:
+ name: Checks
+ runs-on: ubuntu-22.04
+ steps:
+ - uses: actions/checkout@v3
+ with:
+ fetch-depth: 2
+
+ - name: Install dependencies
+ id: install-dependencies
+ run: |
+ sudo apt-get update -qq
+
+ # apt-get install all the dependencies
+ # TODO: script to install all the dependencies (tools/build/ubuntu.sh) not working
+ # chmod +x tools/build/ubuntu.sh
+ # sudo ./tools/build/ubuntu.sh
+
+ sudo apt-get install -y --no-install-recommends \
+ python3-dev \
+ python3-matplotlib \
+ python3-pivy \
+ python3-ply \
+ python3-pyside2.qtcore \
+ python3-pyside2.qtgui \
+ python3-pyside2.qtsvg \
+ python3-pyside2.qtwidgets \
+ python3-pyside2.qtnetwork \
+ python3-markdown \
+ python3-git \
+ libboost-date-time-dev \
+ libboost-dev \
+ libboost-filesystem-dev \
+ libboost-graph-dev \
+ libboost-iostreams-dev \
+ libboost-program-options-dev \
+ libboost-python-dev \
+ libboost-regex-dev \
+ libboost-serialization-dev \
+ libboost-thread-dev \
+ libxerces-c-dev \
+ libocct-data-exchange-dev \
+ libocct-ocaf-dev \
+ libocct-visualization-dev \
+ occt-draw \
+ libvtk7-dev \
+ swig \
+ libcoin-dev \
+ libeigen3-dev \
+ libgts-bin \
+ libgts-dev \
+ libkdtree++-dev \
+ libmedc-dev \
+ libopencv-dev \
+ libproj-dev \
+ libpyside2-dev \
+ pyside2-tools \
+ pyqt5-dev-tools \
+ libqt5opengl5-dev \
+ libqt5svg5-dev \
+ libqt5webkit5-dev \
+ libqt5x11extras5-dev \
+ libqt5xmlpatterns5-dev \
+ qtbase5-dev \
+ qttools5-dev \
+ libx11-dev \
+ libzipios++-dev \
+ doxygen \
+ graphviz \
+ libnglib-dev \
+ netgen \
+ netgen-headers \
+ libmetis-dev \
+ libspnav-dev \
+ libshiboken2-dev \
+ shiboken2 \
+ imagemagick
+
+ - name: make Log and Fixes directory
+ run: |
+ mkdir -p ${{ env.logdir }}
+ mkdir -p ${{ env.fixesdir }}
+
+ - name: Job summary Header
+ id: header
+ run: |
+ echo '# Check Results: :rocket:' >> ${{ env.logdir }}checkReport.md
+
+ - name: Get changed files
+ id: changed-files
+ uses: tj-actions/changed-files@v12.2
+
+ - name: List all changed Files
+ id: list-changed-files
+ run: |
+ echo ":clipboard: Changed Files:
" >> ${{ env.logdir }}checkReport.md
+ echo "" >> ${{ env.logdir }}checkReport.md
+ echo '``` shell' >> ${{ env.logdir }}checkReport.md
+ for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
+ echo "$file" >> ${{ env.logdir }}checkReport.md
+ done
+ echo '```' >> ${{ env.logdir }}checkReport.md
+ echo ' ' >> ${{ env.logdir }}checkReport.md
+ echo "" >> ${{ env.logdir }}checkReport.md
+
+ - name: Harmonize Line endings
+ id: harmonize-line-endings
+ shell: bash
+ run: |
+ for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
+ if [ -f "$file" ]; then
+ echo "Harmonizing line endings in $file"
+ sed -i 's/\r//g' $file
+ fi
+ done
+
+ - name: filter files by extensions
+ id: files-by-extensions
+ shell: bash
+ run: |
+ changed_files=$( echo ${{ steps.changed-files.outputs.all_changed_files }} )
+
+ py=$(grep -oE '\S*?\.(py|py3)' <<< $changed_files | tr '\n' ' ') || true # grep returns non-zero exit code if no match is found
+ cpp=$(grep -oE '\S*?\.(c|c++|cc|cpp|cu|cuh|cxx|h|h++|hh|hpp|hxx)' <<< $changed_files | tr '\n' ' ') || true
+ echo "::set-output name=python_files::$py"
+ echo "::set-output name=cpp_files::$cpp"
+
+ - name: Tests Header
+ if: always()
+ id: tests-header
+ run: |
+ echo '### Tests:' >> ${{ env.logdir }}checkReport.md
+
+ - name: Trailing whitespaces
+ shell: bash
+ if: env.checkWhitespace == 'true' && always()
+ run: |
+ whitespaceErrors="0"
+ exclude="*[.md]"
+
+ for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
+ # check for whitespaces
+ grep -rnIHE --exclude="$exclude" " $" $file | sed 's/$/<-- trailing whitespace/' >> ${{ env.logdir }}whitespace.log || true
+ done
+
+ if [ -f ${{ env.logdir }}whitespace.log ]; then
+ echo "::add-matcher::${{ runner.workspace }}/FreeCAD/.github/problemMatcher/grepMatcherWarning.json"
+ cat ${{ env.logdir }}whitespace.log
+ echo "::remove-matcher owner=grepMatcher-warning::"
+
+ whitespaceErrors=$(wc -l < ${{ env.logdir }}whitespace.log)
+ fi
+
+ echo "Found $whitespaceErrors whitespace errors"
+
+ echo "whitespaceErrors=$whitespaceErrors" >> $GITHUB_ENV
+
+ if [ "$whitespaceErrors" -gt 0 ]; then
+ # Write the report
+ echo ":information_source: Found $whitespaceErrors trailing whitespace
" >> ${{ env.logdir }}checkReport.md
+ echo "" >> ${{ env.logdir }}checkReport.md
+ echo '```' >> ${{ env.logdir }}checkReport.md
+ head -n 500 ${{ env.logdir }}whitespace.log >> ${{ env.logdir }}checkReport.md
+ echo '```' >> ${{ env.logdir }}checkReport.md
+ echo " ">> ${{ env.logdir }}checkReport.md
+ else
+ echo ":heavy_check_mark: No trailing whitespace found " >> ${{ env.logdir }}checkReport.md
+ fi
+ echo "" >> ${{ env.logdir }}checkReport.md
+
+ if [ "$whitespaceErrors" -gt 0 ] && [ ${{ env.whitespaceFailSilent }} != true ]; then
+ exit 1
+ else
+ exit 0
+ fi
+
+ - name: Tabs
+ shell: bash
+ if: env.checkTabs == 'true' && always()
+ run: |
+ tabErrors="0"
+ exclude="*[.md]"
+
+ # check for tabs
+ for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
+ grep -rnIHE --exclude="$exclude" $'\t' $file | sed 's/$/ <-- contains tab/' >> ${{ env.logdir }}tab.log || true
+ done
+
+ # Parse the log
+ if [ -f ${{ env.logdir }}tab.log ]; then
+ echo "::add-matcher::${{ runner.workspace }}/FreeCAD/.github/problemMatcher/grepMatcherWarning.json"
+ cat ${{ env.logdir }}tab.log
+ echo "::remove-matcher owner=grepMatcher-warning::"
+
+ tabErrors=$(wc -l < ${{ env.logdir }}tab.log)
+ fi
+
+ echo "Found $tabErrors tab errors"
+
+ echo "tabErrors=$tabErrors" >> $GITHUB_ENV
+
+ if [ "$tabErrors" -gt 0 ]; then
+ echo ":information_source: Found $tabErrors tabs, better to use spaces
" >> ${{ env.logdir }}checkReport.md
+ echo "" >> ${{ env.logdir }}checkReport.md
+ echo '```' >> ${{ env.logdir }}checkReport.md
+ head -n 500 ${{ env.logdir }}tab.log >> ${{ env.logdir }}checkReport.md
+ echo '```' >> ${{ env.logdir }}checkReport.md
+ echo " ">> ${{ env.logdir }}checkReport.md
+ else
+ echo ":heavy_check_mark: No tabs found" >> ${{ env.logdir }}checkReport.md
+ fi
+ echo "" >> ${{ env.logdir }}checkReport.md
+
+ if [ "$tabErrors" -gt 0 ] && [ ${{ env.tabsFailSilent }} != true ]; then
+ exit 1
+ else
+ exit 0
+ fi
+
+ - name: QT - old string-based connections (https://wiki.qt.io/New_Signal_Slot_Syntax)
+ shell: bash
+ if: env.checkQtconnections == 'true' && steps.files-by-extensions.outputs.cpp_files != '' && always()
+ run: |
+ qtconnectionSyntax="0"
+ exclude="*[.md,.log,.ts,.git]"
+
+ # check all files for QT string-based connections
+ for file in ${{ steps.changed-files.outputs.all_changed_files }}; do
+ grep -rnIHE --exclude="$exclude" $' SIGNAL| SLOT' $file | sed 's,$, <--Consider using Functor-Based Connections,' >> ${{ env.logdir }}stringSyntax.log || true
+ done
+
+ # Parse the log file
+ if [ -f ${{ env.logdir }}stringSyntax.log ]; then
+ echo "::add-matcher::${{ runner.workspace }}/FreeCAD/.github/problemMatcher/grepMatcherWarning.json"
+ cat ${{ env.logdir }}stringSyntax.log
+ echo "::remove-matcher owner=grepMatcher-warning::"
+
+ qtconnectionSyntax=$(wc -l < ${{ env.logdir }}stringSyntax.log)
+ fi
+
+ # Pass Variables to GitHub Env
+ echo "qtconnectionSyntax=$qtconnectionSyntax" >> $GITHUB_ENV
+
+ echo "Found $qtconnectionSyntax QT string-based connections"
+
+ # Step-Report
+ if [ "$qtconnectionSyntax" -gt 0 ]; then
+ echo ":information_source: Found $qtconnectionSyntax QT string-based connections :arrow_right: consider using QT functor-Based Connections
" >> ${{ env.logdir }}checkReport.md
+ echo "" >> ${{ env.logdir }}checkReport.md
+ # documentation link
+ echo "For more information see: https://wiki.qt.io/New_Signal_Slot_Syntax or https://github.com/FreeCAD/FreeCAD/issues/6166" >> ${{ env.logdir }}checkReport.md
+ echo '```' >> ${{ env.logdir }}checkReport.md
+ head -n 500 ${{ env.logdir }}stringSyntax.log >> ${{ env.logdir }}checkReport.md
+ echo '```' >> ${{ env.logdir }}checkReport.md
+ echo " ">> ${{ env.logdir }}checkReport.md
+ else
+ echo ":heavy_check_mark: No string-based connections found " >> ${{ env.logdir }}checkReport.md
+ fi
+ echo "" >> ${{ env.logdir }}checkReport.md
+
+ if [ "$qtconnectionSyntax" -gt 0 ] && [ ${{ env.qtconnectionSyntaxFailSilent }} != true ]; then
+ exit 1
+ else
+ exit 0
+ fi
+
+ - name: Cpplint
+ shell: bash
+ if: env.checkCpplint == 'true' && steps.files-by-extensions.outputs.cpp_files != '' && always()
+ run: |
+ cpplintErrors="0"
+ #filters="--filter=-build/header_guard,-readability/braces,-whitespace"
+ #linelength="--linelength=120"
+
+ pip install cpplint
+
+ # run cpplint
+ for file in ${{ steps.files-by-extensions.outputs.cpp_files }}; do
+ cpplint --filter=${{ env.cpplintFilters }} --linelength=${{ env.cpplintLineLength }} $file &>> ${{ env.logdir }}cpplint.log || true
+ done
+
+ # if cpplint has run successfully parse the output
+ if [ -f ${{ env.logdir }}cpplint.log ]; then
+ echo "::add-matcher::${{ runner.workspace }}/FreeCAD/.github/problemMatcher/cpplint.json"
+ cat ${{ env.logdir }}cpplint.log
+ echo "::remove-matcher owner=cpplint::"
+
+ cpplintErrors=$(grep -rnIHE "\[[0-9]\]$" ${{ env.logdir }}cpplint.log | wc -l ) || true
+ fi
+
+ # Pass Variables to GitHub Env
+ echo "cpplintErrors=$cpplintErrors" >> $GITHUB_ENV
+
+ echo "Found $cpplintErrors cpplint errors"
+
+ # Step-Report
+ if [ "$cpplintErrors" -gt 0 ]; then
+ echo ":warning: CppLint found $cpplintErrors errors / warnings
" >> ${{ env.logdir }}checkReport.md
+ else
+ echo ":heavy_check_mark: No cpplint errors found
" >> ${{ env.logdir }}checkReport.md
+ fi
+
+ echo "" >> ${{ env.logdir }}checkReport.md
+ echo '```' >> ${{ env.logdir }}checkReport.md
+ head -n 500 ${{ env.logdir }}cpplint.log >> ${{ env.logdir }}checkReport.md
+ echo '```' >> ${{ env.logdir }}checkReport.md
+ echo " ">> ${{ env.logdir }}checkReport.md
+ echo "" >> ${{ env.logdir }}checkReport.md
+
+ if [ "$cpplintErrors" -gt 0 ] && [ ${{ env.cpplintFailSilent }} != true ]; then
+ exit 1
+ else
+ exit 0
+ fi
+
+ - name: Pylint
+ shell: bash
+ if: env.checkPylint == 'true' && steps.files-by-extensions.outputs.python_files != '' && always()
+ run: |
+ pylintErrors="0"
+
+ pip install pylint
+
+ pylintErrors="0"
+ pylintWarnings="0"
+ pylintRefactorings="0"
+ pylintConventions="0"
+
+ # Run pylint on all python files
+ pylint --exit-zero --reports y --disable=${{ env.pylintDisable }} ${{ steps.files-by-extensions.outputs.python_files }} > ${{ env.logdir }}pylint.log
+
+ # if pylint has run successfully, then parse the output
+ if [ -f ${{ env.logdir }}pylint.log ]; then
+ echo "::add-matcher::${{ runner.workspace }}/FreeCAD/.github/problemMatcher/pylintError.json"
+ echo "::add-matcher::${{ runner.workspace }}/FreeCAD/.github/problemMatcher/pylintWarning.json"
+ cat ${{ env.logdir }}pylint.log
+ echo "::remove-matcher owner=pylint-error::"
+ echo "::remove-matcher owner=pylint-warning::"
+
+ pylintErrors=$( grep -oP '(?<=error \|)\d+' ${{ env.logdir }}pylint.log) || true # grep returns 0 if no match is found
+ pylintWarnings=$( grep -oP '(?<=warning \|)\d+' ${{ env.logdir }}pylint.log) || true
+ pylintRefactorings=$( grep -oP '(?<=refactor \|)\d+' ${{ env.logdir }}pylint.log) || true
+ pylintConventions=$( grep -oP '(?<=convention \|)\d+' ${{ env.logdir }}pylint.log) || true
+ fi
+
+ # Pass Variables to GitHub Env
+ echo "pylintErrors=$pylintErrors" >> $GITHUB_ENV
+ echo "pylintWarnings=$pylintWarnings" >> $GITHUB_ENV
+ echo "pylintRefactorings=$pylintRefactorings" >> $GITHUB_ENV
+ echo "pylintConventions=$pylintConventions" >> $GITHUB_ENV
+
+ echo "Found $pylintErrors errors, $pylintWarnings warnings, $pylintRefactorings refactorings, $pylintConventions conventions"
+
+ #Step-summary
+ if [ "$pylintErrors" -gt 0 ]; then
+ echo ":fire: Pylint found :fire: $pylintErrors errors, :warning: $pylintWarnings warnings, :construction: $pylintRefactorings refactorings and :pencil2: $pylintConventions conventions
" >> ${{ env.logdir }}checkReport.md
+ elif [ "$pylintWarnings" -gt 0 ]; then
+ echo ":warning: Pylint found :warning: $pylintWarnings warnings, :construction: $pylintRefactorings refactorings and :pencil2: $pylintConventions conventions
" >> ${{ env.logdir }}checkReport.md
+ elif [ "$pylintRefactorings" -gt 0 ]; then
+ echo ":construction: Pylint found :construction: $pylintRefactorings refactorings and :pencil2: $pylintConventions conventions
" >> ${{ env.logdir }}checkReport.md
+ elif [ "$pylintConventions" -gt 0 ]; then
+ echo ":pencil2: Pylint found :pencil2: $pylintConventions conventions
" >> ${{ env.logdir }}checkReport.md
+ else
+ echo ":heavy_check_mark: No pylint errors found
" >> ${{ env.logdir }}checkReport.md
+ fi
+
+ echo "" >> ${{ env.logdir }}checkReport.md
+ echo '```' >> ${{ env.logdir }}checkReport.md
+ head -n 500 ${{ env.logdir }}pylint.log >> ${{ env.logdir }}checkReport.md
+ echo '```' >> ${{ env.logdir }}checkReport.md
+ echo " ">> ${{ env.logdir }}checkReport.md
+ echo "" >> ${{ env.logdir }}checkReport.md
+
+ # Error the step if pylint has found errors
+ if [ "$pylintErrors" -gt 0 ] && [ ${{ env.pylintFailSilent }} != true ]; then
+ exit 1
+ else
+ exit 0
+ fi
+
+ - name: Black (Python)
+ shell: bash
+ if: env.checkBlack == 'true' && steps.files-by-extensions.outputs.python_files != '' && always()
+ run: |
+
+ pip install black
+
+ blackReformats="0"
+ blackFails="0"
+
+ black --check ${{ steps.files-by-extensions.outputs.python_files }} &> ${{ env.logdir }}black.log || true
+
+ # if black has run successfully, then parse the output
+ if [ -f ${{ env.logdir }}black.log ]; then
+ echo "::add-matcher::${{ runner.workspace }}/FreeCAD/.github/problemMatcher/blackWarning.json"
+ cat ${{ env.logdir }}black.log
+ echo "::remove-matcher owner=black-warning::"
+
+ blackReformats=$( grep -oP '\d+(?= fil.+ would be reformatted)' ${{ env.logdir }}black.log) || true # grep returns 0 if no match is found
+ blackFails=$( grep -oP '\d+(?= fil.+ would fail to reformat)' ${{ env.logdir }}black.log) || true
+ fi
+
+ # Pass Variables to GitHub Env
+ echo "blackReformats=$blackReformats" >> $GITHUB_ENV
+ echo "blackFails=$blackFails" >> $GITHUB_ENV
+
+ echo "Found $blackReformats files would be reformatted and $blackFails files would fail to reformat"
+
+ #Step-summary
+ if [ "$blackReformats" -gt 0 ] || [ "$blackFails" -gt 0 ] ; then
+ echo ":pencil2: Black would reformat $blackReformats files
" >> ${{ env.logdir }}checkReport.md
+ else
+ echo ":heavy_check_mark: Black would reformat no file
" >> ${{ env.logdir }}checkReport.md
+ fi
+
+ echo "" >> ${{ env.logdir }}checkReport.md
+ echo '```' >> ${{ env.logdir }}checkReport.md
+ head -n 500 ${{ env.logdir }}black.log >> ${{ env.logdir }}checkReport.md
+ echo '```' >> ${{ env.logdir }}checkReport.md
+ echo " ">> ${{ env.logdir }}checkReport.md
+ echo "" >> ${{ env.logdir }}checkReport.md
+
+ if [ "$blackReformats" -gt 0 ] && [ ${{ env.blackFailSilent }} != true ]; then
+ exit 1
+ else
+ exit 0
+ fi
+
+ - name: Clang-format
+ shell: bash
+ if: env.checkClangFormat == 'true' && steps.files-by-extensions.outputs.cpp_files != '' && always()
+ run: |
+ clangFormatErrors="0"
+
+ # run clang-format on all cpp files
+ clang-format --dry-run --ferror-limit=1 --verbose --style=${{ env.clangStyle }} ${{ steps.files-by-extensions.outputs.cpp_files }} &>> ${{ env.logdir }}clang-format.log || true
+
+ # if cpplint has run successfully parse the output
+ if [ -f ${{ env.logdir }}clang-format.log ]; then
+ echo "::add-matcher::${{ runner.workspace }}/FreeCAD/.github/problemMatcher/clang.json"
+ cat ${{ env.logdir }}clang-format.log
+ echo "::remove-matcher owner=clang::"
+
+ clangFormatErrors=$(grep -rnIHE "\[-Wclang-format-violations]$" ${{ env.logdir }}clang-format.log | wc -l ) || true
+ fi
+
+ # Pass Variables to GitHub Env
+ echo "clangFormatErrors=$clangFormatErrors" >> $GITHUB_ENV
+
+ echo "Found $clangFormatErrors clang-format errors"
+
+ # Report
+
+ if [ "$clangFormatErrors" -gt 0 ]; then
+ echo ":pencil2: Clang-format would reformat $clangFormatErrors files
" >> ${{ env.logdir }}checkReport.md
+ else
+ echo ":heavy_check_mark: Clang-format would reformat no file
" >> ${{ env.logdir }}checkReport.md
+ fi
+
+ echo "" >> ${{ env.logdir }}checkReport.md
+ echo '```' >> ${{ env.logdir }}checkReport.md
+ head -n 500 ${{ env.logdir }}clang-format.log >> ${{ env.logdir }}checkReport.md
+ echo '```' >> ${{ env.logdir }}checkReport.md
+ echo " ">> ${{ env.logdir }}checkReport.md
+ echo "" >> ${{ env.logdir }}checkReport.md
+
+ if [ "$clangFormatErrors" -gt 0 ] && [ ${{ env.clangFormatFailSilent }} != true ]; then
+ exit 1
+ else
+ exit 0
+ fi
+
+ - name: Codespell
+ shell: bash
+ if: env.checkSpelling == 'true' && always()
+ run: |
+ pip install codespell
+
+ wget https://raw.githubusercontent.com/codespell-project/codespell/master/codespell_lib/data/dictionary.txt
+ #wget https://raw.githubusercontent.com/codespell-project/codespell/master/codespell_lib/data/dictionary_rare.txt
+
+ #misspellings=$( codespell --quiet-level 3 --summary --count --ignore-words ${{ env.listIgnoredMisspelling }} --skip ${{ env.skip }} -D dictionary.txt -D dictionary_rare.txt ${{ steps.changed-files.outputs.all_changed_files }} 2>&1 > ${{ env.logdir }}codespell.log ) || true
+ misspellings=$( codespell --quiet-level 3 --summary --count --ignore-words ${{ env.listIgnoredMisspelling }} --skip ${{ env.skip }} -D dictionary.txt ${{ steps.changed-files.outputs.all_changed_files }} 2>&1 > ${{ env.logdir }}codespell.log ) || true
+
+ # if codespell has run successfully, then parse the output
+ if [ -f ${{ env.logdir }}codespell.log ]; then
+ echo "::add-matcher::${{ runner.workspace }}/FreeCAD/.github/problemMatcher/codespell.json"
+ cat ${{ env.logdir }}codespell.log
+ echo "::remove-matcher owner=codespell::"
+ fi
+
+ # Pass Variables to GitHub Env
+ echo "CodespellMisspellings=$misspellings" >> $GITHUB_ENV
+
+ echo "Found $misspellings misspellings"
+
+ #Step-summary
+ if [ "$misspellings" -gt 0 ]; then
+ echo ":pencil2: Codespell found $misspellings misspellings
" >> ${{ env.logdir }}checkReport.md
+ else
+ echo ":heavy_check_mark: Codespell found no misspellings
" >> ${{ env.logdir }}checkReport.md
+ fi
+
+ echo "" >> ${{ env.logdir }}checkReport.md
+ # documentation link
+ echo "To ignore false positives, append the word to the [.github/codespellignore](https://github.com/FreeCAD/FreeCAD/blob/c38e88c61b8926f725215da88940025c94be1daa/.github/codespellignore) file (lowercase)" >> ${{ env.logdir }}checkReport.md
+ echo '```' >> ${{ env.logdir }}checkReport.md
+ head -n 500 ${{ env.logdir }}codespell.log >> ${{ env.logdir }}checkReport.md
+ echo '```' >> ${{ env.logdir }}checkReport.md
+ echo " ">> ${{ env.logdir }}checkReport.md
+ echo "" >> ${{ env.logdir }}checkReport.md
+
+ # Error the step if pylint has found errors
+ if [ "$misspellings" -gt 0 ] && [ ${{ env.codespellFailSilent }} != true ]; then
+ exit 1
+ else
+ exit 0
+ fi
+
+ - name: CMake Configure
+ if: env.checkClangTidy == 'true' && steps.files-by-extensions.outputs.cpp_files != '' && always()
+ run: |
+ cmake -DCMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE -B build/ > ${{ env.logdir }}Cmake.log
+ cat ${{ env.logdir }}Cmake.log
+
+ - name: Clang-tidy
+ shell: bash
+ if: env.checkClangTidy == 'true' && steps.files-by-extensions.outputs.cpp_files != '' && always()
+ run: |
+ clangTidyErrors="0"
+ clangTidyWarnings="0"
+ clangTidyNotes="0"
+
+ sudo apt-get install clang-tidy
+
+ clang-tidy --quiet --format-style=${{ env.clangStyle }} --export-fixes=${{ env.fixesdir }}clang-tidy.yaml -checks=${{ env.clangTidyChecks }} -p build/ ${{ steps.files-by-extensions.outputs.cpp_files }} &>> ${{ env.logdir }}clang-tidy.log || true
+
+ # if clang-tidy has run successfully parse the output
+ if [ -f ${{ env.logdir }}clang-tidy.log ]; then
+ echo "::add-matcher::${{ runner.workspace }}/FreeCAD/.github/problemMatcher/clang.json"
+ cat ${{ env.logdir }}clang-tidy.log
+ echo "::remove-matcher owner=clang::"
+
+ clangTidyErrors=$(grep -rnIHE "^(.+):([0-9]+):([0-9]+): error: .+$" ${{ env.logdir }}clang-tidy.log | wc -l ) || true
+ clangTidyWarnings=$(grep -rnIHE "^(.+):([0-9]+):([0-9]+): warning: .+$" ${{ env.logdir }}clang-tidy.log | wc -l ) || true
+ clangTidyNotes=$(grep -rnIHE "^(.+):([0-9]+):([0-9]+): note: .+$" ${{ env.logdir }}clang-tidy.log | wc -l ) || true
+ fi
+
+ # Pass Variables to GitHub Env
+ echo "clangTidyErrors=$clangTidyErrors" >> $GITHUB_ENV
+ echo "clangTidyWarnings=$clangTidyWarnings" >> $GITHUB_ENV
+ echo "clangTidyNotes=$clangTidyNotes" >> $GITHUB_ENV
+
+ echo "Found $clangTidyErrors errors, $clangTidyWarnings warnings, $clangTidyNotes notes"
+
+ # Step-Report
+ if [ "$clangTidyErrors" -gt 0 ]; then
+ echo ":fire: Clang-Tidy found :fire: $clangTidyErrors errors, :warning: $clangTidyWarnings warnings and :pencil2: $clangTidyNotes notes
" >> ${{ env.logdir }}checkReport.md
+ elif [ "$clangTidyWarnings" -gt 0 ]; then
+ echo ":warning: Clang-Tidy found :warning: $clangTidyWarnings warnings and :pencil2: $clangTidyNotes notes
" >> ${{ env.logdir }}checkReport.md
+ elif [ "$clangTidyNotes" -gt 0 ]; then
+ echo ":pencil2: Clang-Tidy found :pencil2: $clangTidyNotes notes
" >> ${{ env.logdir }}checkReport.md
+ else
+ echo ":heavy_check_mark: Clang-Tidy found no errors, warnings or notes
" >> ${{ env.logdir }}checkReport.md
+ fi
+
+ echo "" >> ${{ env.logdir }}checkReport.md
+ echo '```' >> ${{ env.logdir }}checkReport.md
+ head -n 500 ${{ env.logdir }}clang-tidy.log >> ${{ env.logdir }}checkReport.md
+ echo '```' >> ${{ env.logdir }}checkReport.md
+ echo " ">> ${{ env.logdir }}checkReport.md
+ echo "" >> ${{ env.logdir }}checkReport.md
+
+ # Error the step if pylint has found errors
+ if [ "$clangTidyErrors" -gt 0 ] && [ ${{ env.clangTidyFailSilent }} != true ]; then
+ exit 1
+ else
+ exit 0
+ fi
+
+ - name: Clazy
+ shell: bash
+ if: env.checkClazy == 'true' && steps.files-by-extensions.outputs.cpp_files != '' && always()
+ run: |
+ clazyErrors="0"
+ clazyWarnings="0"
+ clazyNotes="0"
+
+ sudo apt-get install clazy
+
+ clazy-standalone --export-fixes=${{ env.fixesdir }}clazy.yaml -checks=${{ env.clazyChecks }} -p build/ ${{ steps.files-by-extensions.outputs.cpp_files }} &>> ${{ env.logdir }}clazy.log || true
+
+ # if Clazy has run successfully parse the output
+ if [ -f ${{ env.logdir }}clazy.log ]; then
+ echo "::add-matcher::${{ runner.workspace }}/FreeCAD/.github/problemMatcher/clang.json"
+ cat ${{ env.logdir }}clazy.log
+ echo "::remove-matcher owner=clang::"
+
+ clazyErrors=$(grep -rnIHE "^(.+):([0-9]+):([0-9]+): error: .+$" ${{ env.logdir }}clazy.log | wc -l ) || true
+ clazyWarnings=$(grep -rnIHE "^(.+):([0-9]+):([0-9]+): warning: .+$" ${{ env.logdir }}clazy.log | wc -l ) || true
+ clazyNotes=$(grep -rnIHE "^(.+):([0-9]+):([0-9]+): note: .+$" ${{ env.logdir }}clazy.log | wc -l ) || true
+ fi
+
+ # Pass Variables to GitHub Env
+ echo "clazyErrors=$clazyErrors" >> $GITHUB_ENV
+ echo "clazyWarnings=$clazyWarnings" >> $GITHUB_ENV
+ echo "clazyNotes=$clazyNotes" >> $GITHUB_ENV
+
+ echo "Found $clazyErrors errors, $clazyWarnings warnings, $clazyNotes notes"
+
+ # Step-Report
+ if [ "$clazyErrors" -gt 0 ]; then
+ echo ":fire: Clazy found :fire: $clazyErrors errors, :warning: $clazyWarnings warnings and :pencil2: $clazyNotes notes
" >> ${{ env.logdir }}checkReport.md
+ elif [ "$clazyWarnings" -gt 0 ]; then
+ echo ":warning: Clazy found :warning: $clazyWarnings warnings and :pencil2: $clazyNotes notes
" >> ${{ env.logdir }}checkReport.md
+ elif [ "$clazyNotes" -gt 0 ]; then
+ echo ":pencil2: Clazy found :pencil2: $clazyNotes notes
" >> ${{ env.logdir }}checkReport.md
+ else
+ echo ":heavy_check_mark: Clazy found no errors, warnings or notes
" >> ${{ env.logdir }}checkReport.md
+ fi
+
+ echo "" >> ${{ env.logdir }}checkReport.md
+ echo '```' >> ${{ env.logdir }}checkReport.md
+ head -n 500 ${{ env.logdir }}clazy.log >> ${{ env.logdir }}checkReport.md
+ echo '```' >> ${{ env.logdir }}checkReport.md
+ echo " ">> ${{ env.logdir }}checkReport.md
+ echo "" >> ${{ env.logdir }}checkReport.md
+
+ # Error the step if pylint has found errors
+ if [ "$clazyErrors" -gt 0 ] && [ ${{ env.clazyFailSilent }} != true ]; then
+ exit 1
+ else
+ exit 0
+ fi
+
+ - name: Clazy-QT6
+ shell: bash
+ if: env.checkClazyQT6 == 'true' && steps.files-by-extensions.outputs.cpp_files != '' && github.base_ref == env.QT6Branch && always()
+ run: |
+ clazyQT6Errors="0"
+ clazyQT6Warnings="0"
+ clazyQT6Notes="0"
+
+ sudo apt-get install clazy
+
+ # clazy checks for qt6 porting
+ clazy-standalone --export-fixes=${{ env.fixesdir }}clazyQT6.yaml -checks=${{ env.clazyQT6Checks }} -p build/ ${{ steps.files-by-extensions.outputs.cpp_files }} &>> ${{ env.logdir }}clazyQT6.log || true
+
+
+ # if Clazy has run successfully parse the output
+ if [ -f ${{ env.logdir }}clazyQT6.log ]; then
+ echo "::add-matcher::${{ runner.workspace }}/FreeCAD/.github/problemMatcher/clang.json"
+ cat ${{ env.logdir }}clazyQT6.log
+ echo "::remove-matcher owner=clang::"
+
+ clazyQT6Errors=$(grep -rnIHE "^(.+):([0-9]+):([0-9]+): error: .+$" ${{ env.logdir }}clazyQT6.log | wc -l ) || true
+ clazyQT6Warnings=$(grep -rnIHE "^(.+):([0-9]+):([0-9]+): warning: .+$" ${{ env.logdir }}clazyQT6.log | wc -l ) || true
+ clazyQT6Notes=$(grep -rnIHE "^(.+):([0-9]+):([0-9]+): note: .+$" ${{ env.logdir }}clazyQT6.log | wc -l ) || true
+ fi
+
+ # Pass Variables to GitHub Env
+ echo "clazyQT6Errors=$clazyQT6Errors" >> $GITHUB_ENV
+ echo "clazyQT6Warnings=$clazyQT6Warnings" >> $GITHUB_ENV
+ echo "clazyQT6Notes=$clazyQT6Notes" >> $GITHUB_ENV
+
+ echo "Found $clazyQT6Errors errors, $clazyQT6Warnings warnings, $clazyQT6Notes notes"
+
+ # Step-Report
+ if [ "$clazyQT6Errors" -gt 0 ]; then
+ echo ":fire: Clazy found :fire: $clazyQT6Errors errors, :warning: $clazyQT6Warnings warnings and :pencil2: $clazyQT6Notes notes for porting to QT6
" >> ${{ env.logdir }}checkReport.md
+ elif [ "$clazyQT6Warnings" -gt 0 ]; then
+ echo ":warning: Clazy found :warning: $clazyQT6Warnings warnings and :pencil2: $clazyQT6Notes notes for porting to QT6
" >> ${{ env.logdir }}checkReport.md
+ elif [ "$clazyNotes" -gt 0 ]; then
+ echo ":pencil2: Clazy found :pencil2: $clazyQT6Notes notes for porting to QT6
" >> ${{ env.logdir }}checkReport.md
+ else
+ echo ":heavy_check_mark: Clazy found no errors, warnings or notes for porting to QT6
" >> ${{ env.logdir }}checkReport.md
+ fi
+
+ echo "" >> ${{ env.logdir }}checkReport.md
+ echo '```' >> ${{ env.logdir }}checkReport.md
+ head -n 500 ${{ env.logdir }}clazyQT6.log >> ${{ env.logdir }}checkReport.md
+ echo '```' >> ${{ env.logdir }}checkReport.md
+ echo " ">> ${{ env.logdir }}checkReport.md
+ echo "" >> ${{ env.logdir }}checkReport.md
+
+ # Error the step if pylint has found errors
+ if [ "$clazyQT6Errors" -gt 0 ] && [ ${{ env.clazyQT6FailSilent }} != true ]; then
+ exit 1
+ else
+ exit 0
+ fi
+
+ - name: Zip Logs
+ if: always()
+ run: |
+ zip -r ${{ env.logdir }}logs.zip ${{ env.logdir }}
+
+ - name: Upload Logs
+ if: always()
+ uses: actions/upload-artifact@v3
+ with:
+ name: Logs
+ path: ${{ env.logdir }}logs.zip
+
+ - name: Zip Fixes
+ if: always()
+ run: |
+ zip -r ${{ env.fixesdir }}fixes.zip ${{ env.fixesdir }}
+
+ - name: Upload Fixes
+ if: always()
+ uses: actions/upload-artifact@v3
+ with:
+ name: Fixes
+ path: ${{ env.fixesdir }}fixes.zip
+
+ - name: Post Report to GITHUB_STEP_SUMMARY
+ if: env.reportStepSummary == 'true' && always()
+ id: post-report-to-github-step-summary
+ run: |
+ cat ${{ env.logdir }}checkReport.md > $GITHUB_STEP_SUMMARY
+
+ - name: Create Pull request comment
+ if: env.reportPRComment == 'true' && always()
+ uses: marocchino/sticky-pull-request-comment@v2
+ with:
+ header: Check results
+ path: ${{ env.logdir }}checkReport.md