name: Continuous Integration on: [push, pull_request] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: lint: name: Lint runs-on: ubuntu-22.04 steps: - name: Install run: sudo apt-get install -y clang-format - name: Checkout uses: actions/checkout@v4 - name: Symlinks run: find * -type l -printf "::error::%p is a symlink. This is forbidden by the Arduino Library Specification." -exec false {} + - name: Clang-format run: | find src/ extras/ -name '*.[ch]pp' | xargs clang-format -i --verbose --style=file git diff --exit-code - name: Check URLs run: | grep -hREo "(http|https)://[a-zA-Z0-9./?=_%:-]*" src/ | sort -u | while read -r URL do STATUS=$(curl -s -o /dev/null -I -w "%{http_code}" "$URL") [ "$STATUS" -ge 400 ] && echo "::warning title=HTTP $STATUS::$URL returned $STATUS" done || true gcc: name: GCC needs: lint runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: include: - gcc: "4.8" - gcc: "5" - gcc: "6" - gcc: "7" cxxflags: -fsanitize=leak -fno-sanitize-recover=all - gcc: "8" cxxflags: -fsanitize=undefined -fno-sanitize-recover=all - gcc: "9" cxxflags: -fsanitize=address -fno-sanitize-recover=all - gcc: "10" cxxflags: -funsigned-char # Issue #1715 - gcc: "11" - gcc: "12" steps: - name: Workaround for actions/runner-images#9491 run: sudo sysctl vm.mmap_rnd_bits=28 - name: Install run: | sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 40976EAF437D05B5 3B4FE6ACC0B21F32 sudo add-apt-repository -yn 'deb http://archive.ubuntu.com/ubuntu/ xenial main universe' sudo add-apt-repository -yn 'deb http://archive.ubuntu.com/ubuntu/ bionic main universe' sudo add-apt-repository -yn 'deb http://archive.ubuntu.com/ubuntu/ focal main universe' sudo apt-get update sudo apt-get install -y gcc-${{ matrix.gcc }} g++-${{ matrix.gcc }} timeout-minutes: 5 - name: Checkout uses: actions/checkout@v4 timeout-minutes: 1 - name: Configure run: cmake -DCMAKE_BUILD_TYPE=Debug . env: CC: gcc-${{ matrix.gcc }} CXX: g++-${{ matrix.gcc }} CXXFLAGS: ${{ matrix.cxxflags }} timeout-minutes: 1 - name: Build run: cmake --build . timeout-minutes: 10 - name: Test run: ctest --output-on-failure -C Debug . env: UBSAN_OPTIONS: print_stacktrace=1 timeout-minutes: 2 clang: name: Clang needs: lint strategy: fail-fast: false matrix: include: - clang: "3.9" runner: ubuntu-20.04 archive: bionic - clang: "4.0" runner: ubuntu-20.04 archive: bionic - clang: "5.0" runner: ubuntu-20.04 archive: bionic - clang: "6.0" runner: ubuntu-20.04 archive: bionic - clang: "7" runner: ubuntu-20.04 - clang: "8" cxxflags: -fsanitize=leak -fno-sanitize-recover=all runner: ubuntu-20.04 - clang: "9" cxxflags: -fsanitize=undefined -fno-sanitize-recover=all runner: ubuntu-20.04 - clang: "10" cxxflags: -fsanitize=address -fno-sanitize-recover=all runner: ubuntu-20.04 - clang: "11" runner: ubuntu-22.04 - clang: "12" runner: ubuntu-22.04 - clang: "13" runner: ubuntu-22.04 - clang: "14" runner: ubuntu-22.04 - clang: "15" runner: ubuntu-22.04 runs-on: ${{ matrix.runner }} steps: - name: Add archive repositories if: matrix.archive run: | sudo add-apt-repository -yn 'deb http://archive.ubuntu.com/ubuntu/ ${{ matrix.archive }} main' sudo add-apt-repository -yn 'deb http://archive.ubuntu.com/ubuntu/ ${{ matrix.archive }} universe' - name: Install Clang ${{ matrix.clang }} run: | sudo apt-get update sudo apt-get install -y clang-${{ matrix.clang }} - name: Install libc++ ${{ matrix.clang }} if: matrix.clang >= 11 run: sudo apt-get install -y libc++-${{ matrix.clang }}-dev libc++abi-${{ matrix.clang }}-dev - name: Install libunwind ${{ matrix.clang }} if: matrix.clang == 12 # dependency is missing in Ubuntu 22.04 run: sudo apt-get install -y libunwind-${{ matrix.clang }}-dev - name: Checkout uses: actions/checkout@v4 - name: Configure run: cmake -DCMAKE_BUILD_TYPE=Debug . env: CC: clang-${{ matrix.clang }} CXX: clang++-${{ matrix.clang }} CXXFLAGS: >- ${{ matrix.cxxflags }} ${{ matrix.clang < 11 && '-I/usr/lib/llvm-10/include/c++/v1/' || '' }} - name: Build run: cmake --build . - name: Test run: ctest --output-on-failure -C Debug . env: UBSAN_OPTIONS: print_stacktrace=1 conf_test: name: Test configuration on Linux needs: [gcc, clang] runs-on: ubuntu-20.04 steps: - name: Install run: | sudo apt-get update sudo apt-get install -y g++-multilib gcc-avr avr-libc - name: Checkout uses: actions/checkout@v4 - name: AVR run: avr-g++ -std=c++11 -Isrc extras/conf_test/avr.cpp - name: GCC 32-bit run: g++ -std=c++11 -m32 -Isrc extras/conf_test/x86.cpp - name: GCC 64-bit run: g++ -std=c++11 -m64 -Isrc extras/conf_test/x64.cpp - name: Clang 32-bit run: clang++ -std=c++11 -m32 -Isrc extras/conf_test/x86.cpp - name: Clang 64-bit run: clang++ -std=c++11 -m64 -Isrc extras/conf_test/x64.cpp conf_test_windows: name: Test configuration on Windows runs-on: windows-2019 needs: [gcc, clang] steps: - name: Checkout uses: actions/checkout@v4 - name: 32-bit run: | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars32.bat" cl /Isrc extras/conf_test/x86.cpp shell: cmd - name: 64-bit run: | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat" cl /Isrc extras/conf_test/x64.cpp shell: cmd xcode: name: XCode needs: clang runs-on: macos-13 strategy: fail-fast: false matrix: include: - xcode: "14.1" - xcode: "14.2" - xcode: "14.3.1" - xcode: "15.0.1" - xcode: "15.1" - xcode: "15.2" steps: - name: Checkout uses: actions/checkout@v4 - name: Select XCode version run: sudo xcode-select --switch /Applications/Xcode_${{ matrix.xcode }}.app - name: Configure run: cmake -DCMAKE_BUILD_TYPE=Debug . - name: Build run: cmake --build . - name: Test run: ctest --output-on-failure -C Debug . # DISABLED: Running on AppVeyor instead because it supports older versions of the compiler # msvc: # name: Visual Studio # strategy: # fail-fast: false # matrix: # include: # - os: windows-2016 # - os: windows-2019 # runs-on: ${{ matrix.os }} # steps: # - name: Checkout # uses: actions/checkout@v4 # - name: Configure # run: cmake -DCMAKE_BUILD_TYPE=Debug . # - name: Build # run: cmake --build . # - name: Test # run: ctest --output-on-failure -C Debug . arduino: name: Arduino needs: gcc strategy: fail-fast: false matrix: include: - core: arduino:avr board: arduino:avr:uno - core: arduino:samd board: arduino:samd:mkr1000 runs-on: ubuntu-20.04 steps: - name: Checkout uses: actions/checkout@v4 - name: Install arduino-cli run: curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | BINDIR=/usr/local/bin sh - name: Install core run: arduino-cli core install ${{ matrix.core }} - name: Install libraries run: arduino-cli lib install SD Ethernet - name: Build JsonConfigFile run: arduino-cli compile --library . --warnings all -b ${{ matrix.board }} "examples/JsonConfigFile/JsonConfigFile.ino" - name: Build JsonFilterExample run: arduino-cli compile --library . --warnings all -b ${{ matrix.board }} "examples/JsonFilterExample/JsonFilterExample.ino" - name: Build JsonGeneratorExample run: arduino-cli compile --library . --warnings all -b ${{ matrix.board }} "examples/JsonGeneratorExample/JsonGeneratorExample.ino" - name: Build JsonHttpClient run: arduino-cli compile --library . --warnings all -b ${{ matrix.board }} "examples/JsonHttpClient/JsonHttpClient.ino" - name: Build JsonParserExample run: arduino-cli compile --library . --warnings all -b ${{ matrix.board }} "examples/JsonParserExample/JsonParserExample.ino" - name: Build JsonServer run: arduino-cli compile --library . --warnings all -b ${{ matrix.board }} "examples/JsonServer/JsonServer.ino" - name: Build JsonUdpBeacon run: arduino-cli compile --library . --warnings all -b ${{ matrix.board }} "examples/JsonUdpBeacon/JsonUdpBeacon.ino" - name: Build MsgPackParser run: arduino-cli compile --library . --warnings all -b ${{ matrix.board }} "examples/MsgPackParser/MsgPackParser.ino" - name: Build ProgmemExample run: arduino-cli compile --library . --warnings all -b ${{ matrix.board }} "examples/ProgmemExample/ProgmemExample.ino" - name: Build StringExample run: arduino-cli compile --library . --warnings all -b ${{ matrix.board }} "examples/StringExample/StringExample.ino" platformio: name: PlatformIO needs: gcc runs-on: ubuntu-latest strategy: fail-fast: false matrix: include: - platform: atmelavr board: leonardo libraries: - SD - Ethernet conf_test: avr - platform: espressif8266 board: huzzah conf_test: esp8266 - platform: espressif32 board: esp32dev libraries: - Ethernet conf_test: esp8266 - platform: atmelsam board: mkr1000USB libraries: - SD - Ethernet conf_test: esp8266 - platform: teensy board: teensy31 conf_test: esp8266 - platform: ststm32 board: adafruit_feather_f405 libraries: - SD - Ethernet conf_test: esp8266 - platform: nordicnrf52 board: adafruit_feather_nrf52840 libraries: - SD - Ethernet conf_test: esp8266 steps: - name: Checkout uses: actions/checkout@v4 - name: Set up cache for pip uses: actions/cache@v4 with: path: ~/.cache/pip key: ${{ runner.os }}-pip - name: Set up Python 3.x uses: actions/setup-python@v5 with: python-version: "3.x" - name: Install PlatformIO run: pip install platformio - name: Install adafruit-nrfutil if: ${{ matrix.platform == 'nordicnrf52' }} run: pip install adafruit-nrfutil - name: Include Adafruit_TinyUSB.h # https://github.com/adafruit/Adafruit_nRF52_Arduino/issues/653 if: ${{ matrix.platform == 'nordicnrf52' }} run: find examples/ -name '*.ino' -exec sed -i 's/\(#include \)/\1\n#include /' {} + - name: Set up cache for platformio uses: actions/cache@v4 with: path: ~/.platformio key: ${{ runner.os }}-platformio-${{ matrix.platform }} - name: Install platform "${{ matrix.platform }}" run: platformio platform install ${{ matrix.platform }} - name: Install libraries if: ${{ matrix.libraries }} run: platformio lib install arduino-libraries/${{ join(matrix.libraries, ' arduino-libraries/') }} - name: Test configuration run: platformio ci "extras/conf_test/${{ matrix.conf_test }}.cpp" -l '.' -b ${{ matrix.board }} if: ${{ matrix.conf_test }} - name: Build JsonConfigFile run: platformio ci "examples/JsonConfigFile/JsonConfigFile.ino" -l '.' -b ${{ matrix.board }} - name: Build JsonFilterExample run: platformio ci "examples/JsonFilterExample/JsonFilterExample.ino" -l '.' -b ${{ matrix.board }} - name: Build JsonGeneratorExample run: platformio ci "examples/JsonGeneratorExample/JsonGeneratorExample.ino" -l '.' -b ${{ matrix.board }} - name: Build JsonHttpClient run: platformio ci "examples/JsonHttpClient/JsonHttpClient.ino" -l '.' -b ${{ matrix.board }} - name: Build JsonParserExample run: platformio ci "examples/JsonParserExample/JsonParserExample.ino" -l '.' -b ${{ matrix.board }} - name: Build JsonServer if: ${{ matrix.platform != 'espressif32' }} run: platformio ci "examples/JsonServer/JsonServer.ino" -l '.' -b ${{ matrix.board }} - name: Build JsonUdpBeacon run: platformio ci "examples/JsonUdpBeacon/JsonUdpBeacon.ino" -l '.' -b ${{ matrix.board }} - name: Build MsgPackParser run: platformio ci "examples/MsgPackParser/MsgPackParser.ino" -l '.' -b ${{ matrix.board }} - name: Build ProgmemExample run: platformio ci "examples/ProgmemExample/ProgmemExample.ino" -l '.' -b ${{ matrix.board }} - name: Build StringExample run: platformio ci "examples/StringExample/StringExample.ino" -l '.' -b ${{ matrix.board }} - name: PlatformIO prune if: ${{ always() }} run: platformio system prune -f particle: name: Particle needs: gcc runs-on: ubuntu-latest if: github.event_name == 'push' strategy: fail-fast: false matrix: include: - board: argon steps: - name: Checkout uses: actions/checkout@v4 - name: Install Particle CLI run: sudo npm install -g particle-cli - name: Login to Particle run: particle login -t "${{ secrets.PARTICLE_TOKEN }}" - name: Compile run: extras/ci/particle.sh ${{ matrix.board }} arm: name: GCC for ARM processor needs: gcc runs-on: ubuntu-20.04 steps: - name: Install run: | sudo apt-get update sudo apt-get install -y g++-arm-linux-gnueabihf - name: Checkout uses: actions/checkout@v4 - name: Configure run: cmake . env: CC: arm-linux-gnueabihf-gcc CXX: arm-linux-gnueabihf-g++ - name: Build run: cmake --build . coverage: needs: gcc name: Coverage runs-on: ubuntu-20.04 steps: - name: Install run: sudo apt-get install -y lcov ninja-build - name: Checkout uses: actions/checkout@v4 - name: Configure run: cmake -G Ninja -DCOVERAGE=true . - name: Build run: ninja - name: Test run: ctest --output-on-failure -LE 'WillFail|Fuzzing' -T test - name: lcov --capture run: lcov --capture --no-external --directory . --output-file coverage.info - name: lcov --remove run: lcov --remove coverage.info "$(pwd)/extras/*" --output-file coverage_filtered.info - name: genhtml run: mkdir coverage && genhtml coverage_filtered.info -o coverage -t ArduinoJson - name: Upload HTML report uses: actions/upload-artifact@v4 with: name: Coverage report path: coverage - name: Upload to Coveralls uses: coverallsapp/github-action@v2 with: github-token: ${{ secrets.GITHUB_TOKEN }} path-to-lcov: coverage_filtered.info valgrind: needs: gcc name: Valgrind runs-on: ubuntu-20.04 steps: - name: Install run: | sudo apt-get update sudo apt-get install -y valgrind ninja-build - name: Checkout uses: actions/checkout@v4 - name: Configure run: cmake -G Ninja -D MEMORYCHECK_COMMAND_OPTIONS="--error-exitcode=1 --leak-check=full" . - name: Build run: ninja - name: Memcheck run: ctest --output-on-failure -LE WillFail -T memcheck id: memcheck - name: MemoryChecker.*.log run: cat Testing/Temporary/MemoryChecker.*.log > $GITHUB_STEP_SUMMARY if: failure() clang-tidy: needs: clang name: Clang-Tidy runs-on: ubuntu-20.04 steps: - name: Install run: sudo apt-get install -y clang-tidy cmake ninja-build - name: Checkout uses: actions/checkout@v4 - name: Configure run: cmake -G Ninja -DCMAKE_CXX_CLANG_TIDY="clang-tidy-10;--warnings-as-errors=*" -DCMAKE_BUILD_TYPE=Debug . env: CC: clang-10 CXX: clang++-10 - name: Check run: cmake --build . -- -k 0 amalgamate: needs: gcc name: Amalgamate ArduinoJson.h runs-on: ubuntu-20.04 steps: - name: Checkout uses: actions/checkout@v4 - name: Setup run: | if [[ $GITHUB_REF == refs/tags/* ]]; then VERSION=${GITHUB_REF#refs/tags/} else VERSION=${GITHUB_SHA::7} fi echo "ARDUINOJSON_H=ArduinoJson-$VERSION.h" >> $GITHUB_ENV echo "ARDUINOJSON_HPP=ArduinoJson-$VERSION.hpp" >> $GITHUB_ENV - name: Amalgamate ArduinoJson.h run: extras/scripts/build-single-header.sh "src/ArduinoJson.h" "$ARDUINOJSON_H" - name: Amalgamate ArduinoJson.hpp run: extras/scripts/build-single-header.sh "src/ArduinoJson.hpp" "$ARDUINOJSON_HPP" - name: Upload artifact uses: actions/upload-artifact@v4 with: name: Single headers path: | ${{ env.ARDUINOJSON_H }} ${{ env.ARDUINOJSON_HPP }} - name: Smoke test ArduinoJson.h run: | g++ -x c++ - <