# *************************************************************************** # * Copyright (c) 2023 0penBrain * # * * # * This program is free software; you can redistribute it and/or modify * # * it under the terms of the GNU Lesser General Public License (LGPL) * # * as published by the Free Software Foundation; either version 2 of * # * the License, or (at your option) any later version. * # * for detail see the LICENCE text file. * # * * # * This program is distributed in the hope that it will be useful, * # * but WITHOUT ANY WARRANTY; without even the implied warranty of * # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * # * GNU Library General Public License for more details. * # * * # * You should have received a copy of the GNU Library General Public * # * License along with this program; if not, write to the Free Software * # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * # * USA * # * * # *************************************************************************** # This is the lint workflow for CI of FreeCAD name: Lint on: workflow_call: inputs: artifactBasename: type: string required: true changedFiles: type: string required: true changedCppFiles: type: string required: true changedPythonFiles: type: string required: true checkLineendings: default: true type: boolean required: false lineendingsFailSilent: default: true type: boolean required: false checkWhitespace: default: true type: boolean required: false whitespaceFailSilent: default: true type: boolean required: false checkTabs: default: true type: boolean required: false tabsFailSilent: default: true type: boolean required: false checkQtConnections: default: true type: boolean required: false qtConnectionsFailSilent: default: true type: boolean required: false checkCpplint: default: true type: boolean required: false cpplintFilters: default: -build/c++11,-build/header_guard,-build/include,-build/include_alpha,-build/include_order,-build/include_subdir,-build/include_what_you_use,-build/namespaces,-legal/copyright,-readability/braces,-readability-braces-around-statements,-readability/casting,-readability/namespace,-readability/todo,-runtime/indentation_namespace,-runtime/int,-runtime/references,-whitespace/blank_line,-whitespace/braces,-whitespace/comma,-whitespace/comments,-whitespace/end_of_line,-whitespace/indent,-whitespace/line_length,-whitespace/newline,-whitespace/operators,-whitespace/parens,-whitespace/semicolon,-whitespace/tab,-whitespace/todo type: string required: false cpplintLineLength: default: 120 type: string required: false cpplintFailSilent: default: true type: boolean required: false checkPylint: default: true type: boolean required: false pylintDisable: default: disable=C0302 type: string required: false pylintFailtSilent: default: true type: boolean required: false checkBlack: default: true type: boolean required: false blackFailSilent: default: true type: boolean required: false checkClangFormat: default: false type: boolean required: false clangStyle: default: file # for .clang-format file type: string required: false clangFormatFailSilent: default: true type: boolean required: false checkSpelling: default: true type: boolean required: false listIgnoredMisspelling: default: .github/codespellignore type: string required: false spellingIgnore: default: ./.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/ type: string required: false codespellFailSilent: default: true type: boolean required: false checkClangTidy: default: true type: boolean required: false clangTidyChecks: default: # empty to use the .clang-tidy file type: string required: false clangTidyFailSilent: default: true # warnings or notes will never fail the CI, only errors type: boolean required: false checkClazy: # for the Message codes see: https://invent.kde.org/sdk/clazy#list-of-checks default: true type: boolean required: false clazyChecks: default: level1 type: string required: false clazyFailSilent: default: true # warnings or notes will never fail the CI, only errors type: boolean required: false checkClazyQT6: default: true type: boolean required: false clazyQT6Checks: default: 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 type: string required: false QT6Branch: # branch to check for QT6 Porting default: master type: string required: false clazyQT6FailSilent: default: true # warnings or notes will never fail the CI, only errors type: boolean required: false outputs: reportFile: value: ${{ jobs.Lint.outputs.reportFile }} jobs: Lint: if: inputs.changedFiles != '' runs-on: ubuntu-latest env: logdir: /tmp/logs/ fixesdir: /tmp/fixes/ reportdir: /tmp/report/ reportfilename: ${{ inputs.artifactBasename }}-report.md defaults: run: shell: bash outputs: reportFile: ${{ steps.Init.outputs.reportFile }} steps: - name: Check out code uses: actions/checkout@v3 - name: Make needed directories, files and initializations id: Init run: | mkdir -p ${{ env.logdir }} mkdir -p ${{ env.fixesdir }} mkdir -p ${{ env.reportdir }} echo "reportFile=${{ env.reportfilename }}" >> $GITHUB_OUTPUT - name: Check for non Unix line ending if: inputs.checkLineendings && always() run: | lineendings=0 for file in ${{ inputs.changedFiles }} do # Check for DOS or MAC line endings if [[ $(file -b $file) =~ "with CR" ]] then echo "::warning file=$file::File has non Unix line endings" | tee -a ${{ env.logdir }}lineendings.log ((lineendings=lineendings+1)) fi done echo "Found $lineendings line ending errors" # Write the report if [ $lineendings -gt 0 ] then echo "
:information_source: Found $lineendings problems with line endings" >> ${{env.reportdir}}${{ env.reportfilename }} echo "" >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} cat ${{ env.logdir }}lineendings.log >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} echo "
" >> ${{env.reportdir}}${{ env.reportfilename }} else echo ":heavy_check_mark: No line ending problem found " >> ${{env.reportdir}}${{ env.reportfilename }} fi echo "" >> ${{env.reportdir}}${{ env.reportfilename }} # Exit the step with appropriate code if [ $lineendings -gt 0 ] && [ ${{ inputs.lineendingsFailSilent }} != true ] then exit 1 else exit 0 fi - name: Check for trailing whitespaces if: inputs.checkWhitespace && always() run: | whitespaceErrors=0 exclude="*[.md]" for file in ${{ inputs.changedFiles }} do # Check for trailing whitespaces grep -nIHE --exclude="$exclude" " $" $file | sed 's/$/<-- trailing whitespace/' >> ${{ env.logdir }}whitespace.log || true done # Write the Log to the console with the Problem Matchers 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" # Write the report if [ $whitespaceErrors -gt 0 ] then echo "
:information_source: Found $whitespaceErrors trailing whitespace" >> ${{env.reportdir}}${{ env.reportfilename }} echo "" >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} cat ${{ env.logdir }}whitespace.log >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} echo "
" >> ${{env.reportdir}}${{ env.reportfilename }} else echo ":heavy_check_mark: No trailing whitespace found " >> ${{env.reportdir}}${{ env.reportfilename }} fi echo "" >> ${{env.reportdir}}${{ env.reportfilename }} # Exit the step with appropriate code if [ $whitespaceErrors -gt 0 ] && [ ${{ inputs.whitespaceFailSilent }} != true ] then exit 1 else exit 0 fi - name: Check for Tab usage if: inputs.checkTabs && always() run: | tabErrors=0 exclude="*[.md]" # Check for Tab usage for file in ${{ steps.changed-files.outputs.all_changed_files }} do grep -nIHE --exclude="$exclude" $'\t' $file | sed 's/$/ <-- contains tab/' >> ${{ env.logdir }}tab.log || true done # Write the Log to the console with the Problem Matchers 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" # Write the report if [ $tabErrors -gt 0 ]; then echo "
:information_source: Found $tabErrors tabs, better to use spaces" >> ${{env.reportdir}}${{ env.reportfilename }} echo "" >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} cat ${{ env.logdir }}tab.log >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} echo "
" >> ${{env.reportdir}}${{ env.reportfilename }} else echo ":heavy_check_mark: No tabs found" >> ${{env.reportdir}}${{ env.reportfilename }} fi echo "" >> ${{env.reportdir}}${{ env.reportfilename }} # Exit the step with appropriate code if [ $tabErrors -gt 0 ] && [ ${{ inputs.tabsFailSilent }} != true ] then exit 1 else exit 0 fi - name: Check old Qt string-based connections (https://wiki.qt.io/New_Signal_Slot_Syntax) if: inputs.checkQtConnections && inputs.changedCppFiles != '' && always() run: | qtconnectionSyntax=0 exclude="*[.md,.log,.ts,.git]" # Check all files for QT string-based connections for file in ${{ inputs.changedFiles }} #TODO does this makes sense in Python files ? do grep -nIHE --exclude="$exclude" $' SIGNAL| SLOT' $file | sed 's/$/ <--Consider using Functor-Based Connections/' >> ${{ env.logdir }}qtConnections.log || true #TODO seems to trigger false positives done # Write the Log to the console with the Problem Matchers if [ -f ${{ env.logdir }}qtConnections.log ]; then echo "::add-matcher::${{ runner.workspace }}/FreeCAD/.github/problemMatcher/grepMatcherWarning.json" cat ${{ env.logdir }}qtConnections.log echo "::remove-matcher owner=grepMatcher-warning::" qtconnectionSyntax=$(wc -l < ${{ env.logdir }}qtConnections.log) fi echo "Found $qtconnectionSyntax QT string-based connections" # Write the report if [ $qtconnectionSyntax -gt 0 ]; then echo "
:information_source: Found $qtconnectionSyntax QT string-based connections :arrow_right: consider using QT functor-Based Connections" >> ${{env.reportdir}}${{ env.reportfilename }} echo "" >> ${{env.reportdir}}${{ env.reportfilename }} # documentation link echo "For more information see: https://wiki.qt.io/New_Signal_Slot_Syntax or https://github.com/FreeCAD/FreeCAD/issues/6166" >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} cat ${{ env.logdir }}qtConnections.log >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} echo "
" >> ${{env.reportdir}}${{ env.reportfilename }} else echo ":heavy_check_mark: No string-based connections found " >> ${{env.reportdir}}${{ env.reportfilename }} fi echo "" >> ${{env.reportdir}}${{ env.reportfilename }} # Exit the step with appropriate code if [ $qtconnectionSyntax -gt 0 ] && [ ${{ inputs.qtConnectionsFailSilent }} != true ] then exit 1 else exit 0 fi - name: Cpplint if: inputs.checkCpplint && inputs.changedCppFiles != '' && always() run: | cpplintErrors=0 pip install cpplint # Run cpplint for file in ${{ inputs.changedCppFiles }} do cpplint --filter=${{ inputs.cpplintFilters }} --linelength=${{ inputs.cpplintLineLength }} $file &>> ${{ env.logdir }}cpplint.log || true done # If cpplint has run successfully, write the Log to the console with the Problem Matchers if [ ${{ 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 -nIHE "\[[0-9]\]$" ${{ env.logdir }}cpplint.log | wc -l ) || true fi echo "Found $cpplintErrors cpplint errors" # Write the report if [ $cpplintErrors -gt 0 ] then echo "
:warning: CppLint found $cpplintErrors errors / warnings" >> ${{env.reportdir}}${{ env.reportfilename }} else echo "
:heavy_check_mark: No cpplint errors found " >> ${{env.reportdir}}${{ env.reportfilename }} fi echo "" >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} cat ${{ env.logdir }}cpplint.log >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} echo "
" >> ${{env.reportdir}}${{ env.reportfilename }} echo "" >> ${{env.reportdir}}${{ env.reportfilename }} # Exit the step with appropriate code if [ $cpplintErrors -gt 0 ] && [ ${{ inputs.cpplintFailSilent }} != true ] then exit 1 else exit 0 fi - name: Pylint if: inputs.checkPylint && inputs.changedPythonFiles != '' && always() run: | set +e pylintErrors=0 pylintWarnings=0 pylintRefactorings=0 pylintConventions=0 pip install pylint # List enabled pylint checks pylint --list-msgs-enabled > ${{ env.logdir }}pylint-enabled-checks.log # Run pylint on all python files pylint --disable=${{ inputs.pylintDisable }} ${{ inputs.changedPythonFiles }} > ${{ env.logdir }}pylint.log exitCode=$? # If pylint has run successfully, write the Log to the console with the Problem Matchers 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 echo "Found $pylintErrors errors, $pylintWarnings warnings, $pylintRefactorings refactorings, $pylintConventions conventions" # Write the report if [ $pylintErrors -gt 0 ] then echo "
:fire: Pylint found :fire: $pylintErrors errors, :warning: $pylintWarnings warnings, :construction: $pylintRefactorings refactorings and :pencil2: $pylintConventions conventions" >> ${{env.reportdir}}${{ env.reportfilename }} elif [ $pylintWarnings -gt 0 ] then echo "
:warning: Pylint found :warning: $pylintWarnings warnings, :construction: $pylintRefactorings refactorings and :pencil2: $pylintConventions conventions" >> ${{env.reportdir}}${{ env.reportfilename }} elif [ $pylintRefactorings -gt 0 ] then echo "
:construction: Pylint found :construction: $pylintRefactorings refactorings and :pencil2: $pylintConventions conventions" >> ${{env.reportdir}}${{ env.reportfilename }} elif [ $pylintConventions -gt 0 ] then echo "
:pencil2: Pylint found :pencil2: $pylintConventions conventions" >> ${{env.reportdir}}${{ env.reportfilename }} else echo "
:heavy_check_mark: No pylint errors found " >> ${{env.reportdir}}${{ env.reportfilename }} fi echo "" >> ${{env.reportdir}}${{ env.reportfilename }} # List enabled checks in the report echo "
:information_source: Enabled checks" >> ${{env.reportdir}}${{ env.reportfilename }} echo "" >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} cat ${{ env.logdir }}pylint-enabled-checks.log >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} echo "
" >> ${{env.reportdir}}${{ env.reportfilename }} echo "" >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} cat ${{ env.logdir }}pylint.log >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} echo "
" >> ${{env.reportdir}}${{ env.reportfilename }} echo "" >> ${{env.reportdir}}${{ env.reportfilename }} # Exit the step with appropriate code if [ $pylintErrors -gt 0 ] && [ ${{ inputs.pylintFailSilent }} != true ] then exit $exitCode else echo "Pylint exited with code $exitCode, but we are ignoring it" exit 0 fi - name: Black (Python) if: inputs.checkBlack && inputs.changedPythonFiles != '' && always() run: | set +e blackReformats=0 blackFails=0 pip install black black --check ${{ inputs.changedPythonFiles }} &> ${{ env.logdir }}black.log exitCode=$? # If black has run successfully, write the Log to the console with the Problem Matchers 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 echo "Found $blackReformats files would be reformatted and $blackFails files would fail to reformat" # Write the report if [ $blackReformats -gt 0 ] || [ $blackFails -gt 0 ] #FIXME purpose of testing $blackFails as we don't use it then then echo "
:pencil2: Black would reformat $blackReformats files" >> ${{env.reportdir}}${{ env.reportfilename }} else echo "
:heavy_check_mark: Black would reformat no file" >> ${{env.reportdir}}${{ env.reportfilename }} fi echo "" >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} cat ${{ env.logdir }}black.log >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} echo "
" >> ${{env.reportdir}}${{ env.reportfilename }} echo "" >> ${{env.reportdir}}${{ env.reportfilename }} # Exit the step with appropriate code if [ $exitCode -gt 0 ] && [ ${{ inputs.blackFailSilent }} != true ] then exit $exitCode else echo "Black exited with code $exitCode, but we are ignoring it" exit 0 fi - name: Clang-format if: inputs.checkClangFormat && inputs.changedCppFiles != '' && always() run: | clangFormatErrors=0 # Run clang-format on all cpp files clang-format --dry-run --ferror-limit=1 --verbose --style=${{ inputs.clangStyle }} ${{ inputs.changedCppFiles }} &>> ${{ env.logdir }}clang-format.log || true # If clang-format has run successfully, write the Log to the console with the Problem Matchers 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 -nIHE "\[-Wclang-format-violations]$" ${{ env.logdir }}clang-format.log | wc -l ) || true fi echo "Found $clangFormatErrors clang-format errors" # Write the report if [ $clangFormatErrors -gt 0 ] then echo "
:pencil2: Clang-format would reformat $clangFormatErrors files" >> ${{env.reportdir}}${{ env.reportfilename }} else echo "
:heavy_check_mark: Clang-format would reformat no file " >> ${{env.reportdir}}${{ env.reportfilename }} fi echo "" >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} cat ${{ env.logdir }}clang-format.log >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} echo "
" >> ${{env.reportdir}}${{ env.reportfilename }} echo "" >> ${{env.reportdir}}${{ env.reportfilename }} # Exit the step with appropriate code if [ $clangFormatErrors -gt 0 ] && [ ${{ inputs.clangFormatFailSilent }} != true ] then exit 1 else exit 0 fi - name: Codespell if: inputs.checkSpelling && 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 ${{ inputs.listIgnoredMisspelling }} --skip ${{ inputs.spellingIgnore }} -D dictionary.txt ${{ inputs.changedFiles }} >& ${{ env.logdir }}codespell.log ) || true # If codespell has run successfully, write the Log to the console with the Problem Matchers 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 echo "Found $misspellings misspellings" # Write the report if [ $misspellings -gt 0 ] then echo "
:pencil2: Codespell found $misspellings misspellings" >> ${{env.reportdir}}${{ env.reportfilename }} else echo "
:heavy_check_mark: Codespell found no misspellings" >> ${{env.reportdir}}${{ env.reportfilename }} fi echo "" >> ${{env.reportdir}}${{ env.reportfilename }} echo "To ignore false positives, append the word to the [.github/codespellignore](https://github.com/FreeCAD/FreeCAD/blob/master/.github/codespellignore) file (lowercase)" >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} cat ${{ env.logdir }}codespell.log >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} echo "
" >> ${{env.reportdir}}${{ env.reportfilename }} echo "" >> ${{env.reportdir}}${{ env.reportfilename }} # Exit the step with appropriate code if [ $misspellings -gt 0 ] && [ ${{ inputs.codespellFailSilent }} != true ]; then exit 1 else exit 0 fi - name: Clang-tidy if: inputs.checkClangTidy && inputs.changedCppFiles != '' && always() run: | set +e clangTidyErrors=0 clangTidyWarnings=0 clangTidyNotes=0 sudo apt-get install -y --no-install-recommends clang-tidy #TODO: check where this "clang-tidy.yaml" goes ; shall this be put in the fixes ? clang-tidy --quiet --format-style=${{ inputs.clangStyle }} --export-fixes=clang-tidy.yaml -checks=${{ inputs.clangTidyChecks }} -p build/ --explain-config &>> ${{ env.logdir }}clang-tidy-enabled-checks.log # Run clang-tidy on all cpp files clang-tidy --quiet --format-style=${{ inputs.clangStyle }} --export-fixes=clang-tidy.yaml -checks=${{ inputs.clangTidyChecks }} -p build/ ${{ inputs.changedCppFiles }} &>> ${{ env.logdir }}clang-tidy.log exitCode=$? # If clang-tidy has run successfully, write the Log to the console with the Problem Matchers 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 -nIHE "^(.+):([0-9]+):([0-9]+): error: .+$" ${{ env.logdir }}clang-tidy.log | wc -l ) || true clangTidyWarnings=$(grep -nIHE "^(.+):([0-9]+):([0-9]+): warning: .+$" ${{ env.logdir }}clang-tidy.log | wc -l ) || true clangTidyNotes=$(grep -nIHE "^(.+):([0-9]+):([0-9]+): note: .+$" ${{ env.logdir }}clang-tidy.log | wc -l ) || true fi echo "Found $clangTidyErrors errors, $clangTidyWarnings warnings, $clangTidyNotes notes" # Write the report if [ $clangTidyErrors -gt 0 ] then echo "
:fire: Clang-Tidy found :fire: $clangTidyErrors errors, :warning: $clangTidyWarnings warnings and :pencil2: $clangTidyNotes notes" >> ${{env.reportdir}}${{ env.reportfilename }} elif [ $clangTidyWarnings -gt 0 ] then echo "
:warning: Clang-Tidy found :warning: $clangTidyWarnings warnings and :pencil2: $clangTidyNotes notes" >> ${{env.reportdir}}${{ env.reportfilename }} elif [ $clangTidyNotes -gt 0 ] then echo "
:pencil2: Clang-Tidy found :pencil2: $clangTidyNotes notes" >> ${{env.reportdir}}${{ env.reportfilename }} else echo "
:heavy_check_mark: Clang-Tidy found no errors, warnings or notes" >> ${{env.reportdir}}${{ env.reportfilename }} fi echo "" >> ${{env.reportdir}}${{ env.reportfilename }} # List enabled checks in the report echo "
:information_source: Enabled checks" >> ${{env.reportdir}}${{ env.reportfilename }} echo "" >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} cat ${{ env.logdir }}clang-tidy-enabled-checks.log >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} echo "
" >> ${{env.reportdir}}${{ env.reportfilename }} echo "" >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} cat ${{ env.logdir }}clang-tidy.log >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} echo "
" >> ${{env.reportdir}}${{ env.reportfilename }} echo "" >> ${{env.reportdir}}${{ env.reportfilename }} # Exit the step with appropriate code if [ $clangTidyErrors -gt 0 ] && [ ${{ inputs.clangTidyFailSilent }} != true ] then exit $exitCode else echo "Clang-tidy exited with code $exitCode, but we are ignoring it" exit 0 fi - name: Clazy if: inputs.checkClazy && inputs.changedCppFiles != '' && always() run: | clazyErrors=0 clazyWarnings=0 clazyNotes=0 sudo apt-get install -y --no-install-recommends clazy #TODO: check where this "clazy.yaml" goes ; shall this be put in the fixes ? # Run clazy on all cpp files clazy-standalone --export-fixes=clazy.yaml -checks=${{ inputs.clazyChecks }} -p build/ ${{ inputs.changedCppFiles }} &>> ${{ env.logdir }}clazy.log || true # If clazy has run successfully, write the Log to the console with the Problem Matchers 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 -nIHE "^(.+):([0-9]+):([0-9]+): error: .+$" ${{ env.logdir }}clazy.log | wc -l ) || true clazyWarnings=$(grep -nIHE "^(.+):([0-9]+):([0-9]+): warning: .+$" ${{ env.logdir }}clazy.log | wc -l ) || true clazyNotes=$(grep -nIHE "^(.+):([0-9]+):([0-9]+): note: .+$" ${{ env.logdir }}clazy.log | wc -l ) || true fi echo "Found $clazyErrors errors, $clazyWarnings warnings, $clazyNotes notes" # Write the report if [ "$clazyErrors" -gt 0 ] then echo "
:fire: Clazy found :fire: $clazyErrors errors, :warning: $clazyWarnings warnings and :pencil2: $clazyNotes notes" >> ${{env.reportdir}}${{ env.reportfilename }} elif [ "$clazyWarnings" -gt 0 ] then echo "
:warning: Clazy found :warning: $clazyWarnings warnings and :pencil2: $clazyNotes notes" >> ${{env.reportdir}}${{ env.reportfilename }} elif [ "$clazyNotes" -gt 0 ] then echo "
:pencil2: Clazy found :pencil2: $clazyNotes notes" >> ${{env.reportdir}}${{ env.reportfilename }} else echo "
:heavy_check_mark: Clazy found no errors, warnings or notes" >> ${{env.reportdir}}${{ env.reportfilename }} fi echo "" >> ${{env.reportdir}}${{ env.reportfilename }} echo "[List of checks](https://github.com/KDE/clazy#list-of-checks), [This explains some of the clazy warnings](https://www.kdab.com/uncovering-32-qt-best-practices-compile-time-clazy/) " >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} cat ${{ env.logdir }}clazy.log >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} echo "
" >> ${{env.reportdir}}${{ env.reportfilename }} echo "" >> ${{env.reportdir}}${{ env.reportfilename }} # Exit the step with appropriate code if [ "$clazyErrors" -gt 0 ] && [ ${{ inputs.clazyFailSilent }} != true ] then exit 1 else exit 0 fi - name: Clazy-QT6 if: inputs.checkClazyQT6 && inputs.changedCppFiles != '' && github.ref == inputs.QT6Branch && always() run: | clazyQT6Errors=0 clazyQT6Warnings=0 clazyQT6Notes=0 sudo apt-get install -y --no-install-recommends clazy #TODO: check where this "clazyQT6.yaml" goes ; shall this be put in the fixes ? # Run clazy checks for Qt6 on all cpp files clazy-standalone --export-fixes=clazyQT6.yaml -checks=${{ inputs.clazyQT6Checks }} -p build/ ${{ inputs.changedCppFiles }} &>> ${{ env.logdir }}clazyQT6.log || true # If clazy has run successfully, write the Log to the console with the Problem Matchers 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 -nIHE "^(.+):([0-9]+):([0-9]+): error: .+$" ${{ env.logdir }}clazyQT6.log | wc -l ) || true clazyQT6Warnings=$(grep -nIHE "^(.+):([0-9]+):([0-9]+): warning: .+$" ${{ env.logdir }}clazyQT6.log | wc -l ) || true clazyQT6Notes=$(grep -nIHE "^(.+):([0-9]+):([0-9]+): note: .+$" ${{ env.logdir }}clazyQT6.log | wc -l ) || true fi echo "Found $clazyQT6Errors errors, $clazyQT6Warnings warnings, $clazyQT6Notes notes" # Write the 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.reportdir}}${{ env.reportfilename }} elif [ "$clazyQT6Warnings" -gt 0 ] then echo "
:warning: Clazy found :warning: $clazyQT6Warnings warnings and :pencil2: $clazyQT6Notes notes for porting to QT6" >> ${{env.reportdir}}${{ env.reportfilename }} elif [ "$clazyNotes" -gt 0 ] then echo "
:pencil2: Clazy found :pencil2: $clazyQT6Notes notes for porting to QT6" >> ${{env.reportdir}}${{ env.reportfilename }} else echo "
:heavy_check_mark: Clazy found no errors, warnings or notes for porting to QT6" >> ${{env.reportdir}}${{ env.reportfilename }} fi echo "" >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} cat ${{ env.logdir }}clazyQT6.log >> ${{env.reportdir}}${{ env.reportfilename }} echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} echo "
" >> ${{env.reportdir}}${{ env.reportfilename }} echo "" >> ${{env.reportdir}}${{ env.reportfilename }} # Exit the step with appropriate code if [ "$clazyQT6Errors" -gt 0 ] && [ ${{ inputs.clazyQT6FailSilent }} != true ]; then exit 1 else exit 0 fi - name: Upload logs and fixes if: always() uses: actions/upload-artifact@v3 with: name: ${{ inputs.artifactBasename }}-Logs path: | ${{ env.logdir }} ${{ env.fixesdir }} - name: Upload report if: always() uses: actions/upload-artifact@v3 with: name: ${{ env.reportfilename }} path: | ${{env.reportdir}}${{ env.reportfilename }}