util: add Tagged<T, "Name"> newtype helper; relax Quantity/Rational DecimalPlaces floor to 0 #235
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| push: | |
| branches: [main, master] | |
| pull_request: | |
| # actions: write lets the sccache save step evict the previous entry under | |
| # the same static key via `gh cache delete` before re-saving (actions/cache | |
| # never overwrites an existing key). On pull_request runs from a fork, the | |
| # token is read-only regardless of this declaration; the delete step is | |
| # best-effort (continue-on-error) for exactly that case. | |
| permissions: | |
| contents: read | |
| actions: write | |
| env: | |
| VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" | |
| SCCACHE_DIR: /home/runner/.cache/sccache | |
| # Caps each leg's on-disk sccache blob so ~11 legs stay well under GitHub's | |
| # 10 GB per-repo actions-cache budget. See the cache save/restore steps | |
| # below: keys are static per leg (no SHA/branch suffix) so the cache warms | |
| # up once and is refreshed in place every run, instead of growing a new | |
| # generation per commit that only gets reclaimed by GitHub's LRU eviction. | |
| SCCACHE_CACHE_SIZE: "1G" | |
| CLANG_VERSION: "22" | |
| # MORPH_BUILD_FORMS_QML needs Qt 6.5+; ubuntu-24.04 apt still ships 6.4.2. | |
| QT_VERSION: "6.8.1" | |
| jobs: | |
| # ── Windows: MSVC + clang-cl ────────────────────────────────────────── | |
| windows: | |
| name: Windows / ${{ matrix.preset }} | |
| runs-on: windows-latest | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| preset: [cl-debug, cl-release, clangcl-debug, clangcl-release] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Setup MSVC environment | |
| uses: ilammy/msvc-dev-cmd@v1 | |
| - name: Setup vcpkg | |
| uses: lukka/run-vcpkg@v11 | |
| with: | |
| vcpkgGitCommitId: c3867e714dd3a51c272826eea77267876517ed99 | |
| - name: Export vcpkg GHA binary cache vars | |
| uses: actions/github-script@v7 | |
| with: | |
| script: | | |
| core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); | |
| core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); | |
| - name: Configure | |
| run: cmake --preset ${{ matrix.preset }} | |
| - name: Build | |
| run: cmake --build --preset ${{ matrix.preset }} | |
| - name: Test | |
| if: matrix.preset == 'cl-debug' || matrix.preset == 'clangcl-debug' | |
| run: ctest --preset ${{ matrix.preset }} | |
| # ── Linux: GCC and Clang plain builds ──────────────────────────────── | |
| linux-compilers: | |
| name: Linux / ${{ matrix.preset }} | |
| runs-on: ubuntu-24.04 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| preset: [gcc-debug, gcc-release, clang-debug, clang-release] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Cache apt packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: /var/cache/apt/archives | |
| key: apt-compilers-${{ matrix.preset }}-${{ hashFiles('.github/workflows/ci.yml') }} | |
| restore-keys: apt-compilers-${{ matrix.preset }}- | |
| - name: Install GCC 15 and ninja | |
| if: startsWith(matrix.preset, 'gcc-') | |
| run: | | |
| sudo apt-get update -q | |
| sudo apt-get install -y software-properties-common | |
| sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test | |
| sudo apt-get update -q | |
| sudo apt-get install -y gcc-15 g++-15 ninja-build catch2 | |
| sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-15 15 | |
| sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-15 15 | |
| - name: Install Clang ${{ env.CLANG_VERSION }} from apt.llvm.org | |
| if: startsWith(matrix.preset, 'clang-') | |
| run: | | |
| sudo apt-get update -q | |
| sudo apt-get install -y ninja-build catch2 | |
| wget -qO- https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ env.CLANG_VERSION }} | |
| - name: Restore sccache | |
| uses: actions/cache/restore@v4 | |
| with: | |
| path: /home/runner/.cache/sccache | |
| key: sccache-compilers-${{ matrix.preset }} | |
| - name: Install sccache | |
| run: | | |
| curl -sSL https://github.com/mozilla/sccache/releases/download/v0.9.1/sccache-v0.9.1-x86_64-unknown-linux-musl.tar.gz \ | |
| | tar -xz --strip-components=1 -C /usr/local/bin sccache-v0.9.1-x86_64-unknown-linux-musl/sccache | |
| - name: Configure (gcc) | |
| if: startsWith(matrix.preset, 'gcc-') | |
| run: | | |
| cmake --preset ${{ matrix.preset }} \ | |
| -DCMAKE_C_COMPILER_LAUNCHER=sccache \ | |
| -DCMAKE_CXX_COMPILER_LAUNCHER=sccache | |
| - name: Configure (clang) | |
| if: startsWith(matrix.preset, 'clang-') | |
| run: | | |
| cmake --preset ${{ matrix.preset }} \ | |
| -DCMAKE_C_COMPILER=clang-${{ env.CLANG_VERSION }} \ | |
| -DCMAKE_CXX_COMPILER=clang++-${{ env.CLANG_VERSION }} \ | |
| -DCMAKE_C_COMPILER_LAUNCHER=sccache \ | |
| -DCMAKE_CXX_COMPILER_LAUNCHER=sccache | |
| - name: Build | |
| run: cmake --build --preset ${{ matrix.preset }} | |
| - name: Test | |
| if: endsWith(matrix.preset, '-debug') | |
| run: ctest --preset ${{ matrix.preset }} | |
| # actions/cache never overwrites an existing key, so the previous | |
| # generation under this static key is evicted first (best-effort — a | |
| # forked-PR token can't do this, and that's fine: the save below just | |
| # no-ops with a warning instead of refreshing the cache). | |
| - name: Evict previous sccache entry | |
| if: always() | |
| continue-on-error: true | |
| run: gh cache delete "sccache-compilers-${{ matrix.preset }}" | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| - name: Save sccache | |
| if: always() | |
| uses: actions/cache/save@v4 | |
| with: | |
| path: /home/runner/.cache/sccache | |
| key: sccache-compilers-${{ matrix.preset }} | |
| # ── Linux: sanitizers + coverage (all clang) ───────────────────────── | |
| linux-sanitizers: | |
| name: Linux / ${{ matrix.preset }} | |
| runs-on: ubuntu-24.04 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| preset: [clang-asan, clang-tsan, clang-ubsan, clang-coverage] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Cache apt packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: /var/cache/apt/archives | |
| key: apt-sanitizers-${{ hashFiles('.github/workflows/ci.yml') }} | |
| restore-keys: apt-sanitizers- | |
| - name: Install Clang ${{ env.CLANG_VERSION }} from apt.llvm.org | |
| run: | | |
| sudo apt-get update -q | |
| sudo apt-get install -y ninja-build catch2 libsqlite3-dev | |
| wget -qO- https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ env.CLANG_VERSION }} | |
| - name: Restore sccache | |
| uses: actions/cache/restore@v4 | |
| with: | |
| path: /home/runner/.cache/sccache | |
| key: sccache-sanitizers-${{ matrix.preset }} | |
| - name: Install sccache | |
| run: | | |
| curl -sSL https://github.com/mozilla/sccache/releases/download/v0.9.1/sccache-v0.9.1-x86_64-unknown-linux-musl.tar.gz \ | |
| | tar -xz --strip-components=1 -C /usr/local/bin sccache-v0.9.1-x86_64-unknown-linux-musl/sccache | |
| # morph::net and the SQLite offline queue are opt-in, but they are also | |
| # where the memory/threading/UB risk actually lives (raw sockets, an I/O | |
| # thread, a hand-rolled frame reader, a C API). Left off, the sanitizers | |
| # and the coverage number both silently skipped them. Qt/QML and the | |
| # fuzzers stay out of this matrix — they are covered by the | |
| # linux-all-features job, and a GUI stack under TSan is mostly noise. | |
| - name: Configure | |
| run: | | |
| cmake --preset ${{ matrix.preset }} \ | |
| -DMORPH_BUILD_NET=ON \ | |
| -DMORPH_BUILD_OFFLINE_SQLITE=ON \ | |
| -DCMAKE_C_COMPILER=clang-${{ env.CLANG_VERSION }} \ | |
| -DCMAKE_CXX_COMPILER=clang++-${{ env.CLANG_VERSION }} \ | |
| -DCMAKE_C_COMPILER_LAUNCHER=sccache \ | |
| -DCMAKE_CXX_COMPILER_LAUNCHER=sccache | |
| - name: Build | |
| run: cmake --build --preset ${{ matrix.preset }} | |
| - name: Test | |
| run: | | |
| if [ "${{ matrix.preset }}" = "clang-coverage" ]; then | |
| LLVM_PROFILE_FILE="build/clang-coverage/%p.profraw" ctest --preset clang-coverage | |
| else | |
| ctest --preset ${{ matrix.preset }} | |
| fi | |
| - name: Generate coverage report | |
| if: matrix.preset == 'clang-coverage' | |
| run: bash scripts/coverage.sh | |
| - name: Upload coverage to Codecov | |
| if: matrix.preset == 'clang-coverage' | |
| uses: codecov/codecov-action@v5 | |
| with: | |
| files: build/clang-coverage/coverage.lcov | |
| token: ${{ secrets.CODECOV_TOKEN }} | |
| - name: Upload coverage HTML | |
| if: matrix.preset == 'clang-coverage' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: coverage-report | |
| path: build/clang-coverage/html/ | |
| - name: Evict previous sccache entry | |
| if: always() | |
| continue-on-error: true | |
| run: gh cache delete "sccache-sanitizers-${{ matrix.preset }}" | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| - name: Save sccache | |
| if: always() | |
| uses: actions/cache/save@v4 | |
| with: | |
| path: /home/runner/.cache/sccache | |
| key: sccache-sanitizers-${{ matrix.preset }} | |
| # ── Linux: Qt WebSocket backend build + tests ───────────────────────── | |
| linux-qt: | |
| name: Linux / Qt6 WebSockets | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Cache apt packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: /var/cache/apt/archives | |
| key: apt-qt-${{ hashFiles('.github/workflows/ci.yml') }} | |
| restore-keys: apt-qt- | |
| - name: Install GCC 15, ninja, catch2, Qt6 WebSockets | |
| run: | | |
| sudo apt-get update -q | |
| sudo apt-get install -y software-properties-common | |
| sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test | |
| sudo apt-get update -q | |
| sudo apt-get install -y gcc-15 g++-15 ninja-build catch2 \ | |
| qt6-base-dev qt6-websockets-dev qt6-tools-dev libgl1-mesa-dev | |
| sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-15 15 | |
| sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-15 15 | |
| - name: Restore sccache | |
| uses: actions/cache/restore@v4 | |
| with: | |
| path: /home/runner/.cache/sccache | |
| key: sccache-qt | |
| - name: Install sccache | |
| run: | | |
| curl -sSL https://github.com/mozilla/sccache/releases/download/v0.9.1/sccache-v0.9.1-x86_64-unknown-linux-musl.tar.gz \ | |
| | tar -xz --strip-components=1 -C /usr/local/bin sccache-v0.9.1-x86_64-unknown-linux-musl/sccache | |
| - name: Configure (gcc-debug with MORPH_BUILD_QT=ON) | |
| run: | | |
| cmake --preset gcc-debug \ | |
| -DMORPH_BUILD_QT=ON \ | |
| -DCMAKE_C_COMPILER_LAUNCHER=sccache \ | |
| -DCMAKE_CXX_COMPILER_LAUNCHER=sccache | |
| - name: Build | |
| run: cmake --build --preset gcc-debug | |
| - name: Test (offscreen Qt platform) | |
| env: | |
| QT_QPA_PLATFORM: offscreen | |
| run: ctest --preset gcc-debug | |
| - name: Evict previous sccache entry | |
| if: always() | |
| continue-on-error: true | |
| run: gh cache delete "sccache-qt" | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| - name: Save sccache | |
| if: always() | |
| uses: actions/cache/save@v4 | |
| with: | |
| path: /home/runner/.cache/sccache | |
| key: sccache-qt | |
| # ── Linux: every optional feature enabled at once ───────────────────── | |
| # Every MORPH_BUILD_* option below is off by default, and until this job | |
| # existed no CI configuration turned any of them on — so several thousand | |
| # lines (morph::net, the Qt/QML forms renderer, the SQLite queue, the fuzz | |
| # harnesses, the vetted-HMAC adapters, the soak/bench targets) were never | |
| # compiled here, let alone tested. That is how a build that cannot configure | |
| # (MORPH_REQUIRE_VETTED_HMAC) and a replay test matching the wrong file | |
| # extension both reached master green. Enabling them together also proves | |
| # they compose, which building each alone would not. | |
| linux-all-features: | |
| name: Linux / all optional features (${{ matrix.compiler }}) | |
| runs-on: ubuntu-24.04 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| # Clang additionally builds the libFuzzer harnesses, which require it. | |
| - compiler: clang | |
| preset: clang-debug | |
| fuzzers: 'ON' | |
| - compiler: gcc | |
| preset: gcc-debug | |
| fuzzers: 'OFF' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Cache apt packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: /var/cache/apt/archives | |
| key: apt-all-features-${{ matrix.compiler }}-${{ hashFiles('.github/workflows/ci.yml') }} | |
| restore-keys: apt-all-features-${{ matrix.compiler }}- | |
| - name: Install toolchain and the non-Qt dependencies | |
| run: | | |
| sudo apt-get update -q | |
| sudo apt-get install -y software-properties-common | |
| sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test | |
| sudo apt-get update -q | |
| sudo apt-get install -y ninja-build catch2 \ | |
| libsqlite3-dev libsodium-dev libssl-dev \ | |
| libgl1-mesa-dev libxkbcommon-x11-0 libxcb-cursor0 libxcb-icccm4 \ | |
| libxcb-keysyms1 libxcb-shape0 libxcb-xinerama0 | |
| if [ "${{ matrix.compiler }}" = "gcc" ]; then | |
| sudo apt-get install -y gcc-15 g++-15 | |
| sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-15 15 | |
| sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-15 15 | |
| else | |
| wget -qO- https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ env.CLANG_VERSION }} | |
| fi | |
| # Not the distro's Qt: MORPH_BUILD_FORMS_QML needs 6.5+ (see the version | |
| # floor in CMakeLists.txt) and Ubuntu 24.04 still ships 6.4.2, whose | |
| # QQmlApplicationEngine has no loadFromModule. | |
| - name: Install Qt ${{ env.QT_VERSION }} | |
| uses: jurplel/install-qt-action@v4 | |
| with: | |
| version: ${{ env.QT_VERSION }} | |
| modules: qtwebsockets | |
| cache: true | |
| - name: Restore sccache | |
| uses: actions/cache/restore@v4 | |
| with: | |
| path: /home/runner/.cache/sccache | |
| key: sccache-all-features-${{ matrix.compiler }} | |
| - name: Install sccache | |
| run: | | |
| curl -sSL https://github.com/mozilla/sccache/releases/download/v0.9.1/sccache-v0.9.1-x86_64-unknown-linux-musl.tar.gz \ | |
| | tar -xz --strip-components=1 -C /usr/local/bin sccache-v0.9.1-x86_64-unknown-linux-musl/sccache | |
| # MORPH_REQUIRE_VETTED_HMAC is deliberately combined with | |
| # MORPH_BUILD_TESTS=ON (the preset default). docs/spec/security.md | |
| # documents that pairing as supported; this is what keeps it that way. | |
| - name: Configure (every optional feature ON) | |
| run: | | |
| EXTRA="" | |
| if [ "${{ matrix.compiler }}" = "clang" ]; then | |
| EXTRA="-DCMAKE_C_COMPILER=clang-${{ env.CLANG_VERSION }} -DCMAKE_CXX_COMPILER=clang++-${{ env.CLANG_VERSION }}" | |
| fi | |
| # shellcheck disable=SC2086 | |
| cmake --preset ${{ matrix.preset }} \ | |
| -DMORPH_BUILD_NET=ON \ | |
| -DMORPH_BUILD_QT=ON \ | |
| -DMORPH_BUILD_FORMS_QML=ON \ | |
| -DMORPH_BUILD_OFFLINE_SQLITE=ON \ | |
| -DMORPH_BUILD_LOAD_TESTS=ON \ | |
| -DMORPH_BUILD_HMAC_EXAMPLES=ON \ | |
| -DMORPH_BUILD_FUZZERS=${{ matrix.fuzzers }} \ | |
| -DMORPH_REQUIRE_VETTED_HMAC=ON \ | |
| $EXTRA \ | |
| -DCMAKE_C_COMPILER_LAUNCHER=sccache \ | |
| -DCMAKE_CXX_COMPILER_LAUNCHER=sccache | |
| - name: Build | |
| run: cmake --build --preset ${{ matrix.preset }} | |
| # Includes the fuzz *replay* tests on the clang leg: each committed seed | |
| # and crash reproducer is replayed once and must not crash. This is a | |
| # deterministic regression check, not a fuzzing campaign. | |
| - name: Test (offscreen Qt platform) | |
| env: | |
| QT_QPA_PLATFORM: offscreen | |
| run: ctest --preset ${{ matrix.preset }} --output-on-failure | |
| # A guard that never fires is indistinguishable from one that works, so | |
| # assert the fuzz replay actually ran the committed crash reproducers | |
| # rather than silently matching nothing (the `.txt`-vs-`.bin` glob bug). | |
| - name: Verify the fuzz replay covered the committed reproducers | |
| if: matrix.fuzzers == 'ON' | |
| run: | | |
| ctest --preset ${{ matrix.preset }} -R fuzz -V > fuzz-replay.log 2>&1 | |
| status=0 | |
| for finding in tests/fuzz/findings/*/*; do | |
| if ! grep -qF "$(basename "$finding")" fuzz-replay.log; then | |
| echo "::error::fuzz replay never referenced committed reproducer $finding" | |
| status=1 | |
| fi | |
| done | |
| exit "$status" | |
| - name: Evict previous sccache entry | |
| if: always() | |
| continue-on-error: true | |
| run: gh cache delete "sccache-all-features-${{ matrix.compiler }}" | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| - name: Save sccache | |
| if: always() | |
| uses: actions/cache/save@v4 | |
| with: | |
| path: /home/runner/.cache/sccache | |
| key: sccache-all-features-${{ matrix.compiler }} | |
| # ── Valgrind (memcheck) ─────────────────────────────────────────────── | |
| valgrind: | |
| name: Valgrind memcheck | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Cache apt packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: /var/cache/apt/archives | |
| key: apt-valgrind-${{ hashFiles('.github/workflows/ci.yml') }} | |
| restore-keys: apt-valgrind- | |
| - name: Install GCC 15, ninja, catch2, valgrind | |
| run: | | |
| sudo apt-get update -q | |
| sudo apt-get install -y software-properties-common | |
| sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test | |
| sudo apt-get update -q | |
| sudo apt-get install -y gcc-15 g++-15 ninja-build catch2 valgrind | |
| sudo update-alternatives --install /usr/bin/gcc gcc /usr/bin/gcc-15 15 | |
| sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-15 15 | |
| - name: Restore sccache | |
| uses: actions/cache/restore@v4 | |
| with: | |
| path: /home/runner/.cache/sccache | |
| key: sccache-valgrind | |
| - name: Install sccache | |
| run: | | |
| curl -sSL https://github.com/mozilla/sccache/releases/download/v0.9.1/sccache-v0.9.1-x86_64-unknown-linux-musl.tar.gz \ | |
| | tar -xz --strip-components=1 -C /usr/local/bin sccache-v0.9.1-x86_64-unknown-linux-musl/sccache | |
| # morph::net and the SQLite queue are where the raw pointers, manual | |
| # buffers and C API calls live — precisely what memcheck is for — so they | |
| # are built here rather than left to the default (Qt/QML stays out: it | |
| # drags in a GUI stack whose own allocations dominate the report). | |
| - name: Configure | |
| run: | | |
| cmake --preset gcc-debug \ | |
| -DMORPH_BUILD_NET=ON \ | |
| -DMORPH_BUILD_OFFLINE_SQLITE=ON \ | |
| -DCMAKE_C_COMPILER_LAUNCHER=sccache \ | |
| -DCMAKE_CXX_COMPILER_LAUNCHER=sccache | |
| - name: Build | |
| run: cmake --build --preset gcc-debug | |
| - name: Run tests under Valgrind | |
| run: | | |
| status=0 | |
| for suite in tests/morph_tests tests/net/morph_net_tests tests/offline_sqlite/morph_offline_sqlite_tests; do | |
| binary="build/gcc-debug/$suite" | |
| if [ ! -x "$binary" ]; then | |
| echo "::error::expected Valgrind suite $binary was not built" | |
| exit 1 | |
| fi | |
| echo "── memcheck: $suite ──" | |
| valgrind \ | |
| --tool=memcheck \ | |
| --leak-check=full \ | |
| --show-leak-kinds=definite,indirect \ | |
| --errors-for-leak-kinds=definite,indirect \ | |
| --error-exitcode=1 \ | |
| --suppressions=cmake/valgrind.supp \ | |
| "$binary" || status=1 | |
| done | |
| exit "$status" | |
| - name: Evict previous sccache entry | |
| if: always() | |
| continue-on-error: true | |
| run: gh cache delete "sccache-valgrind" | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| - name: Save sccache | |
| if: always() | |
| uses: actions/cache/save@v4 | |
| with: | |
| path: /home/runner/.cache/sccache | |
| key: sccache-valgrind | |
| # ── clang-tidy-diff (changed lines only) ────────────────────────────── | |
| clang-tidy: | |
| name: clang-tidy-diff | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 # need full history for git diff against base | |
| - name: Cache apt packages | |
| uses: actions/cache@v4 | |
| with: | |
| path: /var/cache/apt/archives | |
| key: apt-clang-tidy-${{ hashFiles('.github/workflows/ci.yml') }} | |
| restore-keys: apt-clang-tidy- | |
| - name: Install Clang ${{ env.CLANG_VERSION }}, clang-tidy, and the non-Qt deps | |
| run: | | |
| sudo apt-get update -q | |
| sudo apt-get install -y ninja-build catch2 \ | |
| libsqlite3-dev libsodium-dev libssl-dev \ | |
| libgl1-mesa-dev libxkbcommon-x11-0 libxcb-cursor0 libxcb-icccm4 \ | |
| libxcb-keysyms1 libxcb-shape0 libxcb-xinerama0 | |
| wget -qO- https://apt.llvm.org/llvm.sh | sudo bash -s -- ${{ env.CLANG_VERSION }} | |
| sudo apt-get install -y clang-tidy-${{ env.CLANG_VERSION }} | |
| # See the linux-all-features job: the QML renderer needs Qt 6.5+. | |
| - name: Install Qt ${{ env.QT_VERSION }} | |
| uses: jurplel/install-qt-action@v4 | |
| with: | |
| version: ${{ env.QT_VERSION }} | |
| modules: qtwebsockets | |
| cache: true | |
| - name: Restore sccache | |
| uses: actions/cache/restore@v4 | |
| with: | |
| path: /home/runner/.cache/sccache | |
| key: sccache-clang-tidy | |
| - name: Install sccache | |
| run: | | |
| curl -sSL https://github.com/mozilla/sccache/releases/download/v0.9.1/sccache-v0.9.1-x86_64-unknown-linux-musl.tar.gz \ | |
| | tar -xz --strip-components=1 -C /usr/local/bin sccache-v0.9.1-x86_64-unknown-linux-musl/sccache | |
| # Every optional feature is ON here purely so its sources land in | |
| # compile_commands.json. clang-tidy only ever analyses *changed lines*, so | |
| # this costs a wider build, not a wider lint. Configured narrowly before, | |
| # the whole opt-in surface — morph::net, the Qt transport, the QML forms | |
| # renderer, the SQLite queue, the fuzz harnesses — was invisible to the | |
| # one gate in this workflow that reads code rather than running it. | |
| - name: Configure (generates compile_commands.json over every optional feature) | |
| run: | | |
| cmake --preset clang-debug \ | |
| -DMORPH_BUILD_NET=ON \ | |
| -DMORPH_BUILD_QT=ON \ | |
| -DMORPH_BUILD_FORMS_QML=ON \ | |
| -DMORPH_BUILD_OFFLINE_SQLITE=ON \ | |
| -DMORPH_BUILD_LOAD_TESTS=ON \ | |
| -DMORPH_BUILD_HMAC_EXAMPLES=ON \ | |
| -DMORPH_BUILD_FUZZERS=ON \ | |
| -DCMAKE_C_COMPILER=clang-${{ env.CLANG_VERSION }} \ | |
| -DCMAKE_CXX_COMPILER=clang++-${{ env.CLANG_VERSION }} \ | |
| -DCMAKE_C_COMPILER_LAUNCHER=sccache \ | |
| -DCMAKE_CXX_COMPILER_LAUNCHER=sccache | |
| - name: Build | |
| run: cmake --build --preset clang-debug | |
| - name: Run clang-tidy-diff on changed lines | |
| run: | | |
| if [ "${{ github.event_name }}" = "pull_request" ]; then | |
| BASE_SHA="${{ github.event.pull_request.base.sha }}" | |
| else | |
| BASE_SHA="${{ github.event.before }}" | |
| fi | |
| CLANG_TIDY_DIFF="$(find /usr/lib/llvm-${{ env.CLANG_VERSION }}/share/clang /usr/share/clang \ | |
| -name 'clang-tidy-diff.py' 2>/dev/null | head -1)" | |
| if [ -z "$CLANG_TIDY_DIFF" ]; then | |
| echo "::error::clang-tidy-diff.py not found" | |
| exit 1 | |
| fi | |
| echo "Base SHA: $BASE_SHA" | |
| echo "Script: $CLANG_TIDY_DIFF" | |
| git diff -U0 "$BASE_SHA" | \ | |
| python3 "$CLANG_TIDY_DIFF" \ | |
| -path build/clang-debug \ | |
| -clang-tidy-binary clang-tidy-${{ env.CLANG_VERSION }} \ | |
| -p1 \ | |
| -j "$(nproc)" \ | |
| -extra-arg=-std=c++23 \ | |
| -extra-arg=-warnings-as-errors=* \ | |
| -quiet \ | |
| 2>&1 | tee clang-tidy-report.txt | |
| - name: Upload clang-tidy report | |
| if: always() | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: clang-tidy-report | |
| path: clang-tidy-report.txt | |
| - name: Evict previous sccache entry | |
| if: always() | |
| continue-on-error: true | |
| run: gh cache delete "sccache-clang-tidy" | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| - name: Save sccache | |
| if: always() | |
| uses: actions/cache/save@v4 | |
| with: | |
| path: /home/runner/.cache/sccache | |
| key: sccache-clang-tidy | |
| # ── Deprecation-marker format lint ──────────────────────────────────── | |
| deprecation-lint: | |
| name: Deprecation marker format | |
| runs-on: ubuntu-24.04 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| # The checker itself is tested first. A lint gate nobody tests reports | |
| # green whether or not it still detects anything — this one was blind to | |
| # both the bare `[[deprecated]]` form and any message wrapped across | |
| # lines, which is exactly what VERSIONING.md forbids. | |
| - name: Self-test the deprecation-marker checker | |
| run: bash scripts/test_check_deprecated_markers.sh | |
| - name: Check [[deprecated]] markers cite a replacement and removal version | |
| run: bash scripts/check_deprecated_markers.sh include/morph |