diff --git a/.github/workflows/CI_master.yml b/.github/workflows/CI_master.yml new file mode 100644 index 0000000000..41f24e5c50 --- /dev/null +++ b/.github/workflows/CI_master.yml @@ -0,0 +1,66 @@ +# *************************************************************************** +# * 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 master workflow for CI of FreeCAD. +# It (only) aims at properly organizing the sub-workflows. + +name: FreeCAD master CI + +on: [workflow_dispatch, push, pull_request] + +concurrency: + group: FC-CI-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +jobs: + + Prepare: + uses: ./.github/workflows/sub_prepare.yml + with: + artifactBasename: Prepare-${{ github.run_id }} + + Build2004: + needs: [Prepare] + uses: ./.github/workflows/sub_buildUbuntu2004.yml + with: + artifactBasename: Build2004-${{ github.run_id }} + + Build2204: + needs: [Prepare] + uses: ./.github/workflows/sub_buildUbuntu2204.yml + with: + artifactBasename: Build2204-${{ github.run_id }} + + Lint: + needs: [Prepare] + uses: ./.github/workflows/sub_lint.yml + with: + artifactBasename: Lint-${{ github.run_id }} + changedFiles: ${{ needs.Prepare.outputs.changedFiles }} + changedCppFiles: ${{ needs.Prepare.outputs.changedCppFiles }} + changedPythonFiles: ${{ needs.Prepare.outputs.changedPythonFiles }} + + WrapUp: + needs: [Prepare, Build2004, Build2204, Lint] + if: always() + uses: ./.github/workflows/sub_wrapup.yml + with: + previousSteps: ${{ toJSON(needs) }} diff --git a/.github/workflows/actions/linux/generateCacheKey/action.yml b/.github/workflows/actions/linux/generateCacheKey/action.yml new file mode 100644 index 0000000000..6b8b8e058d --- /dev/null +++ b/.github/workflows/actions/linux/generateCacheKey/action.yml @@ -0,0 +1,42 @@ +# *************************************************************************** +# * 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 * +# * * +# *************************************************************************** + +name: generateCacheKey +description: "Linux: generates a cache key taking into account distro and compiler" + +inputs: + compiler: + description: "Binary name/path of compiler to be used" + required: true +outputs: + cacheKey: + description: "Cache key with distro and compiler version" + value: ${{ steps.generateCacheKey.outputs.cacheKey }} + +runs: + using: "composite" + steps: + - id: generateCacheKey + shell: bash + run: | + cacheKey=$(lsb_release -ds | tr -d ' ')-$( basename ${{ inputs.compiler }})$(${{ inputs.compiler }} -dumpfullversion -dumpversion) + echo "Generated cache key : $cacheKey" + echo "cacheKey=$cacheKey" >> $GITHUB_OUTPUT diff --git a/.github/workflows/actions/runTests/action.yml b/.github/workflows/actions/runTests/action.yml new file mode 100644 index 0000000000..ba8205eb99 --- /dev/null +++ b/.github/workflows/actions/runTests/action.yml @@ -0,0 +1,64 @@ +# *************************************************************************** +# * 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 * +# * * +# *************************************************************************** + +name: generateCacheKey +description: "Linux: run unit tests, generate log and report" + +inputs: + testDescription: + description: "Test description text, will be used on report" + required: true + testCommand: + description: "Test command to be ran" + required: true + logFile: + description: "Path for log file" + required: true + reportFile: + description: "Path for report file" + required: true + +runs: + using: "composite" + steps: + - name: Run tests + id: runTests + shell: bash + run: | + stdbuf -oL -eL ${{ inputs.testCommand }} |& sed -E '/[[:blank:]]*\([[:digit:]]{1,3} %\)[[:blank:]]*/d' | tee ${{ inputs.logFile }} + - name: Write report + shell: bash + if: always() + run: | + if [ ${{ steps.runTests.outcome }} == 'success' ] + then + echo "
:heavy_check_mark: ${{ inputs.testDescription }} succeeded" >> ${{ inputs.reportFile}} + else + echo "
:fire: ${{ inputs.testDescription }} failed" >> ${{ inputs.reportFile}} + fi + echo "" >> ${{ inputs.reportFile}} + echo "Below is presented only the 20 last lines of the test log" >> ${{ inputs.reportFile}} + echo "" >> ${{ inputs.reportFile}} + echo '```' >> ${{ inputs.reportFile}} + cat ${{ inputs.logFile }} | tail -n 20 >> ${{ inputs.reportFile}} + echo '```' >> ${{ inputs.reportFile}} + echo "
">> ${{ inputs.reportFile}} + echo "" >> ${{ inputs.reportFile}} diff --git a/.github/workflows/sub_buildUbuntu2004.yml b/.github/workflows/sub_buildUbuntu2004.yml new file mode 100644 index 0000000000..140e95ae84 --- /dev/null +++ b/.github/workflows/sub_buildUbuntu2004.yml @@ -0,0 +1,306 @@ +# *************************************************************************** +# * 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 a build and test workflow for CI of FreeCAD. +# This workflow aims at building and testing FreeCAD on Ubuntu 20.04 using GCC. + +name: Build Ubuntu 20.04 + +on: + workflow_call: + inputs: + artifactBasename: + type: string + required: true + testOnBuildDir: + default: false + type: boolean + required: false + allowedToFail: + default: false + type: boolean + required: false + outputs: + reportFile: + value: ${{ jobs.Build.outputs.reportFile }} + +jobs: + + Build: + runs-on: ubuntu-20.04 + continue-on-error: ${{ inputs.allowedToFail }} + env: + CCACHE_DIR: ${{ github.workspace }}/ccache + CCACHE_CONFIGPATH: ${{ github.workspace }}/ccache/config + CCACHE_MAXSIZE: 1G + CCACHE_COMPILERCHECK: "%compiler% -dumpfullversion -dumpversion" # default:mtime + CCACHE_COMPRESS: true + CCACHE_COMPRESSLEVEL: 1 + CC: /usr/bin/gcc + CXX: /usr/bin/g++ + #CC: /usr/bin/clang + #CXX: /usr/bin/clang++ + builddir: ${{ github.workspace }}/build/ + logdir: /tmp/logs/ + reportdir: /tmp/report/ + reportfilename: ${{ inputs.artifactBasename }}-report.md + defaults: + run: + shell: bash + outputs: + reportFile: ${{ steps.Init.outputs.reportFile }} + + steps: + - name: Checking out source code + uses: actions/checkout@v3 + - name: Install FreeCAD dependencies + run: | + sudo apt-get update -qq + sudo apt-get install -y --no-install-recommends \ + doxygen \ + graphviz \ + imagemagick \ + 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 \ + libcoin-dev \ + libeigen3-dev \ + libgts-bin \ + libgts-dev \ + libkdtree++-dev \ + libmedc-dev \ + libocct-data-exchange-dev \ + libocct-ocaf-dev \ + libocct-visualization-dev \ + libopencv-dev \ + libproj-dev \ + libpyside2-dev \ + libqt5opengl5-dev \ + libqt5svg5-dev \ + libqt5x11extras5-dev \ + libqt5xmlpatterns5-dev \ + libshiboken2-dev \ + libspnav-dev \ + libvtk7-dev \ + libx11-dev \ + libxerces-c-dev \ + libzipios++-dev \ + netgen \ + netgen-headers \ + occt-draw \ + pyqt5-dev-tools \ + pyside2-tools \ + python3-dev \ + python3-git \ + python3-markdown \ + python3-matplotlib \ + python3-packaging \ + python3-pivy \ + python3-ply \ + python3-pyside2.qtcore \ + python3-pyside2.qtgui \ + python3-pyside2.qtnetwork \ + python3-pyside2.qtsvg \ + python3-pyside2.qtwebengine \ + python3-pyside2.qtwebenginecore \ + python3-pyside2.qtwebenginewidgets \ + python3-pyside2.qtwebchannel \ + python3-pyside2.qtwidgets \ + qtbase5-dev \ + qttools5-dev \ + qtwebengine5-dev \ + shiboken2 \ + swig \ + ccache \ + xvfb + - name: Make needed directories, files and initializations + id: Init + run: | + mkdir -p ${{ env.CCACHE_DIR }} + mkdir -p ${{ env.CCACHE_CONFIGPATH }} + mkdir -p ${{ env.builddir }} + mkdir -p ${{ env.logdir }} + mkdir -p ${{ env.reportdir }} + echo "reportFile=${{ env.reportfilename }}" >> $GITHUB_OUTPUT + - name: Generate cache key + id: genCacheKey + uses: ./.github/workflows/actions/linux/generateCacheKey + with: + compiler: ${{ env.CXX }} + - name: Restore Compiler Cache + uses: pat-s/always-upload-cache@v3 + with: + path: ${{ env.CCACHE_DIR }} + key: FC-${{ steps.genCacheKey.outputs.cacheKey }}-${{ github.ref }}-${{ github.run_id }} + restore-keys: | + FC-${{ steps.genCacheKey.outputs.cacheKey }}-${{ github.ref }}- + FC-${{ steps.genCacheKey.outputs.cacheKey }}- + - name: Print CCache statistics before build, reset stats and print config + run: | + ccache -s + ccache -z + ccache -p + - name: CMake Configure + run: | + set +e + cmake \ + -D CMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE \ + -B ${{ env.builddir }} > ${{ env.logdir }}Cmake.log 2> ${{ env.logdir }}CmakeErrors.log + exitCode=$? + # Write the configure report + if [ $exitCode -eq 0 ] + then + echo "
:heavy_check_mark: CMake configure succeeded" >> ${{env.reportdir}}${{ env.reportfilename }} + else + echo "
:fire: CMake configure failed" >> ${{env.reportdir}}${{ env.reportfilename }} + fi + echo "" >> ${{env.reportdir}}${{ env.reportfilename }} + echo "Configure Error Log (stderr output):" >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + cat ${{ env.logdir }}CmakeErrors.log >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + echo "Configure Log (stdout output):" >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + tail -n 60 ${{ env.logdir }}Cmake.log >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + echo "
">> ${{env.reportdir}}${{ env.reportfilename }} + echo "" >> ${{env.reportdir}}${{ env.reportfilename }} + # Print the Log to the console + cat ${{ env.logdir }}CmakeErrors.log + echo "::group::Configure Log" + cat ${{ env.logdir }}Cmake.log + echo "::endgroup::" + # Exit the step with the exit code of the configure + exit $exitCode + - name: CMake Build + run: | + set +e + cmake --build ${{ env.builddir}} -j$(nproc) > ${{ env.logdir }}Build.log 2> ${{ env.logdir }}BuildErrors.log + exitCode=$? + # Write the build report + if [ $exitCode -eq 0 ] + then + echo "
:heavy_check_mark: CMake build succeeded" >> ${{env.reportdir}}${{ env.reportfilename }} + else + echo "
:fire: CMake build failed" >> ${{env.reportdir}}${{ env.reportfilename }} + fi + echo "" >> ${{env.reportdir}}${{ env.reportfilename }} + echo "Build Error Log (stderr output):" >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + cat ${{ env.logdir }}BuildErrors.log >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + echo "Build Log (stdout output trimmed to the last 100 Lines):" >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + tail -n 50 ${{ env.logdir }}Build.log >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + echo "
">> ${{env.reportdir}}${{ env.reportfilename }} + echo "" >> ${{env.reportdir}}${{ env.reportfilename }} + # Print the Log to the console + cat ${{ env.logdir }}BuildErrors.log + echo "::group::Build Log" + cat ${{ env.logdir }}Build.log + echo "::endgroup::" + # Exit the step with the exit code of the build + exit $exitCode + - name: Print ccache statistics after Build + run: | + ccache -s + - name: FreeCAD CLI tests on build dir + if: inputs.testOnBuildDir + uses: ./.github/workflows/actions/runTests + with: + testDescription: "CLI tests on build dir" + testCommand: ${{ env.builddir }}bin/FreeCADCmd -t 0 + logFile: ${{ env.logdir }}TestCLIBuild.log + reportFile: ${{env.reportdir}}${{ env.reportfilename }} + - name: FreeCAD GUI tests on build dir + if: inputs.testOnBuildDir + uses: ./.github/workflows/actions/runTests + with: + testDescription: "GUI tests on build dir" + testCommand: xvfb-run ${{ env.builddir }}/bin/FreeCAD -t 0 + logFile: ${{ env.logdir }}TestGUIBuild.log + reportFile: ${{env.reportdir}}${{ env.reportfilename }} + - name: CMake Install + run: | + set +e + sudo cmake --install ${{ env.builddir }} >> ${{ env.logdir }}Install.log 2>> ${{ env.logdir }}InstallErrors.log + exitCode=$? + # Write the install report + if [ $exitCode -eq 0 ] + then + echo "
:heavy_check_mark: CMake install succeeded" >> ${{env.reportdir}}${{ env.reportfilename }} + else + echo "
:fire: CMake install failed" >> ${{env.reportdir}}${{ env.reportfilename }} + fi + echo "" >> ${{env.reportdir}}${{ env.reportfilename }} + echo "Install Error Log (stderr output):" >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + cat ${{ env.logdir }}InstallErrors.log >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + echo "Install Error Log (stdout output trimmed to the last 100 Lines):" >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + tail -n 100 ${{ env.logdir }}Install.log >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + echo "
">> ${{env.reportdir}}${{ env.reportfilename }} + echo "" >> ${{env.reportdir}}${{ env.reportfilename }} + # Print the Log to the console + cat ${{ env.logdir }}InstallErrors.log + echo "::group::Install Log" + cat ${{ env.logdir }}Install.log + echo "::endgroup::" + # Exit the step with the exit code of the install + exit $exitCode + - name: FreeCAD CLI tests on install + uses: ./.github/workflows/actions/runTests + with: + testDescription: "CLI tests on install" + testCommand: FreeCADCmd -t 0 + logFile: ${{ env.logdir }}TestCLIInstall.log + reportFile: ${{env.reportdir}}${{ env.reportfilename }} + - name: FreeCAD GUI tests on install + uses: ./.github/workflows/actions/runTests + with: + testDescription: "GUI tests on install" + testCommand: xvfb-run FreeCAD -t 0 + logFile: ${{ env.logdir }}TestGUIInstall.log + reportFile: ${{env.reportdir}}${{ env.reportfilename }} + - name: Upload logs + if: always() + uses: actions/upload-artifact@v3 + with: + name: ${{ inputs.artifactBasename }}-Logs + path: | + ${{ env.logdir }} + - name: Upload report + if: always() + uses: actions/upload-artifact@v3 + with: + name: ${{ env.reportfilename }} + path: | + ${{env.reportdir}}${{ env.reportfilename }} diff --git a/.github/workflows/sub_buildUbuntu2204.yml b/.github/workflows/sub_buildUbuntu2204.yml new file mode 100644 index 0000000000..5b15e0642e --- /dev/null +++ b/.github/workflows/sub_buildUbuntu2204.yml @@ -0,0 +1,315 @@ +# *************************************************************************** +# * 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 a build and test workflow for CI of FreeCAD. +# This workflow aims at building and testing FreeCAD on Ubuntu 22.04 using Clang. + +name: Build Ubuntu 22.04 +on: + workflow_call: + inputs: + artifactBasename: + type: string + required: true + testOnBuildDir: + default: false + type: boolean + required: false + allowedToFail: + default: false + type: boolean + required: false + outputs: + reportFile: + value: ${{ jobs.Build.outputs.reportFile }} + +jobs: + Build: + runs-on: ubuntu-22.04 + continue-on-error: ${{ inputs.allowedToFail }} + env: + CCACHE_DIR: ${{ github.workspace }}/ccache + CCACHE_CONFIGPATH: ${{ github.workspace }}/ccache/config + CCACHE_MAXSIZE: 1G + CCACHE_COMPILERCHECK: "%compiler% -dumpfullversion -dumpversion" # default:mtime + CCACHE_COMPRESS: true + CCACHE_COMPRESSLEVEL: 1 + #CC: /usr/bin/gcc + #CXX: /usr/bin/g++ + CC: /usr/bin/clang + CXX: /usr/bin/clang++ + builddir: ${{ github.workspace }}/build/ + logdir: /tmp/logs/ + reportdir: /tmp/report/ + reportfilename: ${{ inputs.artifactBasename }}-report.md + defaults: + run: + shell: bash + outputs: + reportFile: ${{ steps.Init.outputs.reportFile }} + + steps: + - name: Checking out source code + uses: actions/checkout@v3 + - name: Install FreeCAD dependencies + run: | + sudo apt-get update -qq + sudo apt-get install -y --no-install-recommends \ + doxygen \ + graphviz \ + imagemagick \ + 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 \ + libcoin-dev \ + libeigen3-dev \ + libgts-bin \ + libgts-dev \ + libkdtree++-dev \ + libmedc-dev \ + libocct-data-exchange-dev \ + libocct-ocaf-dev \ + libocct-visualization-dev \ + libopencv-dev \ + libproj-dev \ + libpyside2-dev \ + libqt5opengl5-dev \ + libqt5svg5-dev \ + libqt5x11extras5-dev \ + libqt5xmlpatterns5-dev \ + libshiboken2-dev \ + libspnav-dev \ + libvtk7-dev \ + libx11-dev \ + libxerces-c-dev \ + libzipios++-dev \ + netgen \ + netgen-headers \ + occt-draw \ + pyqt5-dev-tools \ + pyside2-tools \ + python3-dev \ + python3-git \ + python3-markdown \ + python3-matplotlib \ + python3-packaging \ + python3-pivy \ + python3-ply \ + python3-pyside2.qtcore \ + python3-pyside2.qtgui \ + python3-pyside2.qtnetwork \ + python3-pyside2.qtsvg \ + python3-pyside2.qtwebengine \ + python3-pyside2.qtwebenginecore \ + python3-pyside2.qtwebenginewidgets \ + python3-pyside2.qtwebchannel \ + python3-pyside2.qtwidgets \ + qtbase5-dev \ + qttools5-dev \ + qtwebengine5-dev \ + shiboken2 \ + swig \ + ccache \ + xvfb + - name: Install Pivy version compatible with Python 3.10 + run: | + sudo apt-get purge python3-pivy + cd /tmp/ + git clone --depth 1 --branch 0.6.8 https://github.com/coin3d/pivy.git + cd pivy + mkdir build + cd build + cmake .. + make -j$(nproc) + sudo make install + - name: Make needed directories, files and initializations + id: Init + run: | + mkdir -p ${{ env.CCACHE_DIR }} + mkdir -p ${{ env.CCACHE_CONFIGPATH }} + mkdir -p ${{ env.builddir }} + mkdir -p ${{ env.logdir }} + mkdir -p ${{ env.reportdir }} + echo "reportFile=${{ env.reportfilename }}" >> $GITHUB_OUTPUT + - name: Generate cache key + id: genCacheKey + uses: ./.github/workflows/actions/linux/generateCacheKey + with: + compiler: ${{ env.CXX }} + - name: Restore Compiler Cache + uses: pat-s/always-upload-cache@v3 + with: + path: ${{ env.CCACHE_DIR }} + key: FC-${{ steps.genCacheKey.outputs.cacheKey }}-${{ github.ref }}-${{ github.run_id }} + restore-keys: | + FC-${{ steps.genCacheKey.outputs.cacheKey }}-${{ github.ref }}- + FC-${{ steps.genCacheKey.outputs.cacheKey }}- + - name: Print CCache statistics before build, reset stats and print config + run: | + ccache -s + ccache -z + ccache -p + - name: CMake Configure + run: | + set +e + cmake \ + -D CMAKE_EXPORT_COMPILE_COMMANDS:BOOL=TRUE \ + -B ${{ env.builddir }} > ${{ env.logdir }}Cmake.log 2> ${{ env.logdir }}CmakeErrors.log + exitCode=$? + # Write the configure report + if [ $exitCode -eq 0 ] + then + echo "
:heavy_check_mark: CMake configure succeeded" >> ${{env.reportdir}}${{ env.reportfilename }} + else + echo "
:fire: CMake configure failed" >> ${{env.reportdir}}${{ env.reportfilename }} + fi + echo "" >> ${{env.reportdir}}${{ env.reportfilename }} + echo "Configure Error Log (stderr output):" >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + cat ${{ env.logdir }}CmakeErrors.log >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + echo "Configure Log (stdout output):" >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + tail -n 60 ${{ env.logdir }}Cmake.log >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + echo "
">> ${{env.reportdir}}${{ env.reportfilename }} + echo "" >> ${{env.reportdir}}${{ env.reportfilename }} + # Print the Log to the console + cat ${{ env.logdir }}CmakeErrors.log + echo "::group::Configure Log" + cat ${{ env.logdir }}Cmake.log + echo "::endgroup::" + # Exit the step with the exit code of the configure + exit $exitCode + - name: CMake Build + run: | + set +e + cmake --build ${{ env.builddir}} -j$(nproc) > ${{ env.logdir }}Build.log 2> ${{ env.logdir }}BuildErrors.log + exitCode=$? + # Write the build report + if [ $exitCode -eq 0 ] + then + echo "
:heavy_check_mark: CMake build succeeded" >> ${{env.reportdir}}${{ env.reportfilename }} + else + echo "
:fire: CMake build failed" >> ${{env.reportdir}}${{ env.reportfilename }} + fi + echo "" >> ${{env.reportdir}}${{ env.reportfilename }} + echo "Build Error Log (stderr output):" >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + cat ${{ env.logdir }}BuildErrors.log >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + echo "Build Log (stdout output trimmed to the last 100 Lines):" >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + tail -n 50 ${{ env.logdir }}Build.log >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + echo "
">> ${{env.reportdir}}${{ env.reportfilename }} + echo "" >> ${{env.reportdir}}${{ env.reportfilename }} + # Print the Log to the console + cat ${{ env.logdir }}BuildErrors.log + echo "::group::Build Log" + cat ${{ env.logdir }}Build.log + echo "::endgroup::" + # Exit the step with the exit code of the build + exit $exitCode + - name: Print ccache statistics after Build + run: | + ccache -s + - name: FreeCAD CLI tests on build dir + if: inputs.testOnBuildDir + uses: ./.github/workflows/actions/runTests + with: + testDescription: "CLI tests on build dir" + testCommand: ${{ env.builddir }}bin/FreeCADCmd -t 0 + logFile: ${{ env.logdir }}TestCLIBuild.log + reportFile: ${{env.reportdir}}${{ env.reportfilename }} + - name: FreeCAD GUI tests on build dir + if: inputs.testOnBuildDir + uses: ./.github/workflows/actions/runTests + with: + testDescription: "GUI tests on build dir" + testCommand: xvfb-run ${{ env.builddir }}/bin/FreeCAD -t 0 + logFile: ${{ env.logdir }}TestGUIBuild.log + reportFile: ${{env.reportdir}}${{ env.reportfilename }} + - name: CMake Install + run: | + set +e + sudo cmake --install ${{ env.builddir }} >> ${{ env.logdir }}Install.log 2>> ${{ env.logdir }}InstallErrors.log + exitCode=$? + # Write the install report + if [ $exitCode -eq 0 ] + then + echo "
:heavy_check_mark: CMake install succeeded" >> ${{env.reportdir}}${{ env.reportfilename }} + else + echo "
:fire: CMake install failed" >> ${{env.reportdir}}${{ env.reportfilename }} + fi + echo "" >> ${{env.reportdir}}${{ env.reportfilename }} + echo "Install Error Log (stderr output):" >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + cat ${{ env.logdir }}InstallErrors.log >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + echo "Install Error Log (stdout output trimmed to the last 100 Lines):" >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + tail -n 100 ${{ env.logdir }}Install.log >> ${{env.reportdir}}${{ env.reportfilename }} + echo '```' >> ${{env.reportdir}}${{ env.reportfilename }} + echo "
">> ${{env.reportdir}}${{ env.reportfilename }} + echo "" >> ${{env.reportdir}}${{ env.reportfilename }} + # Print the Log to the console + cat ${{ env.logdir }}InstallErrors.log + echo "::group::Install Log" + cat ${{ env.logdir }}Install.log + echo "::endgroup::" + # Exit the step with the exit code of the install + exit $exitCode + - name: FreeCAD CLI tests on install + uses: ./.github/workflows/actions/runTests + with: + testDescription: "CLI tests on install" + testCommand: FreeCADCmd -t 0 + logFile: ${{ env.logdir }}TestCLIInstall.log + reportFile: ${{env.reportdir}}${{ env.reportfilename }} + - name: FreeCAD GUI tests on install + uses: ./.github/workflows/actions/runTests + with: + testDescription: "GUI tests on install" + testCommand: xvfb-run FreeCAD -t 0 + logFile: ${{ env.logdir }}TestGUIInstall.log + reportFile: ${{env.reportdir}}${{ env.reportfilename }} + - name: Upload logs + if: always() + uses: actions/upload-artifact@v3 + with: + name: ${{ inputs.artifactBasename }}-Logs + path: | + ${{ env.logdir }} + - name: Upload report + if: always() + uses: actions/upload-artifact@v3 + with: + name: ${{ env.reportfilename }} + path: | + ${{env.reportdir}}${{ env.reportfilename }} diff --git a/.github/workflows/sub_lint.yml b/.github/workflows/sub_lint.yml new file mode 100644 index 0000000000..b8687dbd2e --- /dev/null +++ b/.github/workflows/sub_lint.yml @@ -0,0 +1,739 @@ +# *************************************************************************** +# * 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: false + 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 }} diff --git a/.github/workflows/sub_prepare.yml b/.github/workflows/sub_prepare.yml new file mode 100644 index 0000000000..c6772d3ca9 --- /dev/null +++ b/.github/workflows/sub_prepare.yml @@ -0,0 +1,165 @@ +# *************************************************************************** +# * 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 pre-check workflow for CI of FreeCAD. +# It aims at running some basic checks about the workflow run ... +# ... and gathering some data needed for the next steps. + +name: Prepare + +on: + workflow_call: + inputs: + artifactBasename: + type: string + required: true + failOnOldRebase: + default: false + type: boolean + required: false + maxRebaseHours: + default: "48" + type: string + required: false + outputs: + reportFile: + value: ${{ jobs.Prepare.outputs.reportFile }} + changedFiles: + value: ${{ jobs.Prepare.outputs.changedFiles }} + changedPythonFiles: + value: ${{ jobs.Prepare.outputs.changedPythonFiles }} + changedCppFiles: + value: ${{ jobs.Prepare.outputs.changedCppFiles }} + +jobs: + + Prepare: + env: + isPR: ${{ github.event_name == 'pull_request' }} + isPush: ${{ github.event_name == 'push' }} + logdir: /tmp/logs/ + reportdir: /tmp/report/ + reportfilename: ${{ inputs.artifactBasename }}-report.md + runs-on: ubuntu-latest + defaults: + run: + shell: bash + outputs: + reportFile: ${{ steps.Init.outputs.reportFile }} + changedFiles: ${{ steps.Output.outputs.changedFiles }} + changedPythonFiles: ${{ steps.Output.outputs.changedPythonFiles }} + changedCppFiles: ${{ steps.Output.outputs.changedCppFiles }} + + steps: + - name: Make needed directories, files and initializations + id: Init + run: | + mkdir -p ${{ env.logdir }} + mkdir -p ${{ env.reportdir }} + commitCnt=0 + touch ${{ env.logdir }}changedFiles.lst ${{ env.logdir }}changedCppFiles.lst ${{ env.logdir }}changedPythonFiles.lst + echo "reportFile=${{ env.reportfilename }}" >> $GITHUB_OUTPUT + - name: Determine base and head SHA in case of PR + if: env.isPR == 'true' + run: | + baseSha=${{ github.event.pull_request.base.sha }} + headSha=${{ github.event.pull_request.head.sha }} + echo "baseSha=$baseSha" >> $GITHUB_ENV + echo "headSha=$headSha" >> $GITHUB_ENV + echo "This CI run is performed on a Pull Request" | tee -a ${{env.reportdir}}${{ env.reportfilename }} + echo "Base SHA is $baseSha, Head SHA is $headSha" | tee -a ${{env.reportdir}}${{ env.reportfilename }} + - name: Check if PR has been recently rebased + if: env.isPR == 'true' + run: | + baseDate=$(curl -H "Accept: application/vnd.github+json" -H "authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" $GITHUB_API_URL/repos/$GITHUB_REPOSITORY/commits/$baseSha | jq -r '.commit.committer.date') + dateDiff=$(( ( $(date +%s) - $(date -d $baseDate +%s) ) / 3600 )) + echo "Pull request is based on a $dateDiff hour-old commit" | tee -a ${{env.reportdir}}${{ env.reportfilename }} + # Exit the step with appropriate code + if [ $dateDiff -gt ${{ inputs.maxRebaseHours }} ] + then + echo -n ":warning: Pull request should be rebased" | tee -a ${{env.reportdir}}${{ env.reportfilename }} + if ${{ inputs.failOnOldRebase }} + then + echo "" | tee -a ${{env.reportdir}}${{ env.reportfilename }} + exit 1 + else + echo " ... but it is ignored by setting" | tee -a ${{env.reportdir}}${{ env.reportfilename }} + fi + fi + - name: Determine base and head SHA in case of push + if: env.isPush == 'true' + run: | + baseSha=${{ github.event.before }} + headSha=${{ github.event.after }} + echo "headSha=$headSha" >> $GITHUB_ENV + if [ $baseSha -eq 0 ] + then + echo "This CI run is performed on a Push that created a new branch : files changed will be ignored" | tee -a ${{env.reportdir}}${{ env.reportfilename }} + echo "Head SHA is $headSha" | tee -a ${{env.reportdir}}${{ env.reportfilename }} + echo "isPush='false'" >> $GITHUB_ENV + else + echo "This CI run is performed on a Push" | tee -a ${{env.reportdir}}${{ env.reportfilename }} + echo "Base SHA is $baseSha, Head SHA is $headSha" | tee -a ${{env.reportdir}}${{ env.reportfilename }} + echo "baseSha=$baseSha" >> $GITHUB_ENV + fi + - name: Get compare between head and base + if: env.isPR == 'true' || env.isPush == 'true' + run: | + echo "$GITHUB_API_URL/repos/$GITHUB_REPOSITORY/compare/$baseSha...$headSha" + curl -H "Accept: application/vnd.github+json" -H "authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" $GITHUB_API_URL/repos/$GITHUB_REPOSITORY/compare/$baseSha...$headSha > ${{ env.logdir }}compare.json + - name: Get number of commits in the changeset + if: env.isPR == 'true' || env.isPush == 'true' + run: | + commitCnt=$(jq -re '.ahead_by' ${{ env.logdir }}compare.json) + echo "Changeset is composed of $commitCnt commit(s)" | tee -a ${{env.reportdir}}${{ env.reportfilename }} + - name: Get files modified in changeset #TODO check what happens with deleted file in the subsequent process + if: env.isPR == 'true' || env.isPush == 'true' + run: | + jq '.files[] | if .status != "removed" then .filename else empty end' ${{ env.logdir }}compare.json > ${{ env.logdir }}changedFiles.lst + grep -E '\.(py|py3)"' ${{ env.logdir }}changedFiles.lst > ${{ env.logdir }}changedPythonFiles.lst || true + grep -E '\.(c|c\+\+|cc|cpp|cu|cuh|cxx|h|h\+\+|hh|hpp|hxx)"' ${{ env.logdir }}changedFiles.lst > ${{ env.logdir }}changedCppFiles.lst || true + # Write the report + echo "::group::Modified files in changeset (removed files are ignored) :" ; cat ${{ env.logdir }}changedFiles.lst ; echo "::endgroup::" + echo "
Modified files (removed files are ignored):" >> ${{env.reportdir}}${{ env.reportfilename }} + cat ${{ env.logdir }}changedFiles.lst >> ${{env.reportdir}}${{ env.reportfilename }} + echo "
" >> ${{env.reportdir}}${{ env.reportfilename }} + echo "" >> ${{env.reportdir}}${{ env.reportfilename }} + - name: Transmitting outputs + id: Output + run: | + echo "changedFiles=$(cat ${{ env.logdir }}changedFiles.lst | tr '\n' ' ')" >> $GITHUB_OUTPUT + echo "changedPythonFiles=$(cat ${{ env.logdir }}changedPythonFiles.lst | tr '\n' ' ')" >> $GITHUB_OUTPUT + echo "changedCppFiles=$(cat ${{ env.logdir }}changedCppFiles.lst | tr '\n' ' ')" >> $GITHUB_OUTPUT + echo "" >> $GITHUB_OUTPUT + - name: Upload logs + if: always() + uses: actions/upload-artifact@v3 + with: + name: ${{ inputs.artifactBasename }}-Logs + path: | + ${{ env.logdir }} + - name: Upload report + if: always() + uses: actions/upload-artifact@v3 + with: + name: ${{ env.reportfilename }} + path: | + ${{env.reportdir}}${{ env.reportfilename }} diff --git a/.github/workflows/sub_wrapup.yml b/.github/workflows/sub_wrapup.yml new file mode 100644 index 0000000000..6d2083c4aa --- /dev/null +++ b/.github/workflows/sub_wrapup.yml @@ -0,0 +1,114 @@ +# *************************************************************************** +# * 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 a generic wrapup workflow that only aims at gathering reports and ... +# ... presenting them as a unified summary +# +# It expects steps to be summarized to be presented a JSON input formatted ... +# ... as the "needs" context of Github : +# https://docs.github.com/en/actions/learn-github-actions/contexts#needs-context +# In addition to standard "result", each step shall have a string entry in "outputs" ... +# ... named "reportFile" containing the name of the corresponding report. The ... +# ... report file shall be available in an artifact with the same name. + +name: WrapUp +on: + workflow_call: + inputs: + previousSteps: + type: string + required: true + +jobs: + + WrapUp: + runs-on: ubuntu-latest + env: + artifactsDownloadDir: /tmp/artifacts/ + defaults: + run: + shell: bash + + steps: + - name: Make needed directories, files and initializations + run: | + mkdir -p ${{ env.artifactsDownloadDir }} + - name: Download artifacts + uses: actions/download-artifact@v3 + with: + path: ${{ env.artifactsDownloadDir }} + - name: Save input data to file + run: | + cat > data << EOD + ${{ inputs.previousSteps }} + EOD + - name: Compute the report + run: | + echo "usedArtifacts<> $GITHUB_ENV + for step in $(jq -r "keys_unsorted | .[]" data) + do + echo "Processing step $step" + result=$(jq -r ".$step.result" data) + icon=":heavy_check_mark:" + if [ $result == 'failure' ] + then + icon=":x:" + elif [ $result == 'cancelled' ] + then + icon=":no_entry_sign:" + elif [ $result == 'skipped' ] + then + icon=":white_check_mark:" + fi + echo "### $icon $step step" >> report.md + if [ $result == 'skipped' ] + then + echo "Step was skipped, no report was generated" | tee -a report.md + continue + elif [ $result == 'cancelled' ] + then + echo "Step was cancelled when executing, report may be incomplete" | tee -a report.md + fi + report=$(jq -r ".$step.outputs.reportFile" data) + if [ $report ] + then + echo "Report for step $step is $report" + echo "$report" >> $GITHUB_ENV + if [ $(find ${{ env.artifactsDownloadDir }} -type f -name $report | wc -l) -eq 1 ] + then + find ${{ env.artifactsDownloadDir }} -type f -name $report -exec cat {} \; >> report.md + else + echo "No or several files found for report $report, not printing" | tee -a report.md + echo "Below files found :" + find ${{ env.artifactsDownloadDir }} -type f -name $report + fi + else + echo "Report file was not set by step $step" | tee -a report.md + fi + echo "" >> report.md + done + echo "EOD" >> $GITHUB_ENV + cat report.md >> $GITHUB_STEP_SUMMARY + - name: Delete used artifacts + uses: geekyeggo/delete-artifact@v2 + with: + name: | + ${{ env.usedArtifacts }}