ci(release): sync uv.lock after bump so it does not drift #66
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] | |
| pull_request: | |
| branches: [main] | |
| concurrency: | |
| group: ci-${{ github.ref }} | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| jobs: | |
| build-and-test: | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 30 | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| compiler: [clang-19, gcc-14] | |
| name: ${{ matrix.compiler }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| # Need the diff base so the tidy gate can list changed files. | |
| fetch-depth: 0 | |
| - name: Install toolchain | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y llvm-18 ca-certificates wget gnupg | |
| if [[ "${{ matrix.compiler }}" == clang-* ]]; then | |
| # Ubuntu 24.04's default repos cap at clang-18; clang-19 fixes | |
| # the OpenMP frontend bug that rejects structured-binding | |
| # capture inside TUs that mix `#pragma omp` with citor's | |
| # templated dispatch headers (the benchmark surfaces it). | |
| wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key \ | |
| | sudo gpg --dearmor -o /etc/apt/keyrings/llvm.gpg | |
| echo "deb [signed-by=/etc/apt/keyrings/llvm.gpg] http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main" \ | |
| | sudo tee /etc/apt/sources.list.d/llvm.list >/dev/null | |
| sudo apt-get update | |
| sudo apt-get install -y clang-19 clang-tidy-19 lld-19 libomp-19-dev ninja-build | |
| echo "CC=clang-19" >> "$GITHUB_ENV" | |
| echo "CXX=clang++-19" >> "$GITHUB_ENV" | |
| echo "CITOR_CMAKE_EXTRA=-DCITOR_ENABLE_CLANG_TIDY=ON" >> "$GITHUB_ENV" | |
| else | |
| sudo apt-get install -y gcc-14 g++-14 ninja-build | |
| echo "CC=gcc-14" >> "$GITHUB_ENV" | |
| echo "CXX=g++-14" >> "$GITHUB_ENV" | |
| echo "CITOR_CMAKE_EXTRA=" >> "$GITHUB_ENV" | |
| fi | |
| - name: Compute clang-tidy diff scope | |
| if: ${{ startsWith(matrix.compiler, 'clang-') }} | |
| run: | | |
| # PR builds tidy only the .cpp/.h files changed in the PR; push | |
| # builds tidy the diff from the previous main tip. The tidy | |
| # wrapper (`scripts/clang-tidy-diff-gate.sh`) skips TUs not in | |
| # this list, keeping the build's compile pass intact while | |
| # shrinking tidy from "every TU" to "what changed". An empty list | |
| # disables tidy for the run (no source files touched -> no | |
| # findings to gate on); the special string `__ALL__` forces | |
| # full-tree tidy on demand. | |
| case "${{ github.event_name }}" in | |
| pull_request) | |
| base="${{ github.event.pull_request.base.sha }}" | |
| head="${{ github.event.pull_request.head.sha }}" | |
| ;; | |
| push) | |
| base="${{ github.event.before }}" | |
| head="${{ github.sha }}" | |
| # First push to a branch (no prior tip) -> tidy the full tree. | |
| if [ -z "$base" ] || [ "$base" = "0000000000000000000000000000000000000000" ]; then | |
| base="" | |
| fi | |
| ;; | |
| *) | |
| base="" | |
| head="" | |
| ;; | |
| esac | |
| # `github.event.before` for a push is the previous tip. After a | |
| # force-push it points at an orphaned commit; `git diff` against an | |
| # unreachable SHA aborts the job. Drop the base in that case and | |
| # fall through to the full-tree branch. | |
| if [ -n "$base" ] && ! git cat-file -e "$base" 2>/dev/null; then | |
| echo "tidy scope: full tree (base $base unreachable, likely force-pushed away)" | |
| base="" | |
| fi | |
| if [ -z "$base" ]; then | |
| echo "tidy scope: full tree (no diff base)" | |
| echo "CITOR_TIDY_FILES=__ALL__" >> "$GITHUB_ENV" | |
| else | |
| # Any change under include/citor/ propagates through the | |
| # header graph; gating the gate on a per-TU source-path match | |
| # would silently skip every consumer. Fall back to full-tree | |
| # tidy whenever a public header moved. | |
| header_changes=$(git diff --name-only "$base" "$head" -- \ | |
| 'include/citor/**.h') | |
| if [ -n "$header_changes" ]; then | |
| echo "tidy scope: full tree (headers changed)" | |
| echo "$header_changes" | |
| echo "CITOR_TIDY_FILES=__ALL__" >> "$GITHUB_ENV" | |
| else | |
| tu_changes=$(git diff --name-only "$base" "$head" -- \ | |
| 'tests/**.cpp' 'benchmark/**.cpp' | tr '\n' ':') | |
| if [ -z "$tu_changes" ]; then | |
| echo "tidy scope: no C++ TUs changed; skipping tidy" | |
| echo "CITOR_TIDY_FILES=" >> "$GITHUB_ENV" | |
| else | |
| echo "tidy scope (${base:0:8}..${head:0:8}):" | |
| echo "$tu_changes" | tr ':' '\n' | |
| echo "CITOR_TIDY_FILES=$tu_changes" >> "$GITHUB_ENV" | |
| fi | |
| fi | |
| fi | |
| echo "CITOR_CLANG_TIDY_BIN=clang-tidy-19" >> "$GITHUB_ENV" | |
| echo "CITOR_REPO_ROOT=$GITHUB_WORKSPACE" >> "$GITHUB_ENV" | |
| - name: CPM source cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/CPM | |
| key: cpm-${{ runner.os }}-${{ hashFiles('cmake/CPM.cmake', 'cmake/GTestDep.cmake') }} | |
| restore-keys: | | |
| cpm-${{ runner.os }}- | |
| - name: ccache | |
| uses: hendrikmuhs/ccache-action@v1.2 | |
| with: | |
| key: ${{ matrix.compiler }}-ci | |
| max-size: 500M | |
| - name: Configure | |
| env: | |
| CPM_SOURCE_CACHE: ${{ github.workspace }}/.cache/CPM | |
| run: | | |
| # bench=ON only on clang-19: gcc-14 + bench pulls third-party | |
| # headers (TooManyCooks, others) that trigger `-Werror=*` false | |
| # positives we can't fix upstream-side. clang-19 is the bench's | |
| # supported toolchain; gcc-14 stays a tests-only library-compat | |
| # row. | |
| if [[ "${{ matrix.compiler }}" == clang-* ]]; then | |
| BENCH=ON | |
| else | |
| BENCH=OFF | |
| fi | |
| cmake -S . -B build -G Ninja \ | |
| -DCITOR_BUILD_BENCHMARK=$BENCH \ | |
| -DCMAKE_C_COMPILER_LAUNCHER=ccache \ | |
| -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ | |
| $CITOR_CMAKE_EXTRA | |
| - name: Compute tidy file list | |
| run: | | |
| # Tidy on the diff only. Any header, CMake or tidy-config change | |
| # invalidates downstream TUs we cannot enumerate from the diff, | |
| # so those force `__ALL__`. | |
| if [[ "${{ github.event_name }}" == pull_request ]]; then | |
| BASE="${{ github.event.pull_request.base.sha }}" | |
| else | |
| BASE="HEAD~1" | |
| fi | |
| CHANGED=$(git diff --name-only "$BASE" HEAD) | |
| if grep -qE '\.(h|hpp|tcc)$|(^|/)\.clang-tidy$|(^|/)CMakeLists\.txt$|^cmake/.*\.cmake$|^scripts/clang-tidy-diff-gate\.sh$' <<<"$CHANGED"; then | |
| echo "CITOR_TIDY_FILES=__ALL__" >> "$GITHUB_ENV" | |
| else | |
| FILES=$(grep -E '\.cpp$' <<<"$CHANGED" | paste -sd: -) | |
| echo "CITOR_TIDY_FILES=$FILES" >> "$GITHUB_ENV" | |
| fi | |
| - name: Build | |
| run: cmake --build build -j | |
| - name: Test | |
| run: ctest --test-dir build --output-on-failure -j | |
| asan-ubsan: | |
| name: asan+ubsan | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 30 | |
| env: | |
| CC: clang-18 | |
| CXX: clang++-18 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install toolchain | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y clang-18 lld-18 ninja-build llvm-18 | |
| - name: CPM source cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/CPM | |
| key: cpm-${{ runner.os }}-${{ hashFiles('cmake/CPM.cmake', 'cmake/GTestDep.cmake') }} | |
| restore-keys: | | |
| cpm-${{ runner.os }}- | |
| - name: ccache | |
| uses: hendrikmuhs/ccache-action@v1.2 | |
| with: | |
| key: asan-ubsan-ci | |
| max-size: 500M | |
| - name: Configure | |
| env: | |
| CPM_SOURCE_CACHE: ${{ github.workspace }}/.cache/CPM | |
| # `RelWithDebInfo` keeps DWARF for sanitizer stack frames while | |
| # leaving optimisation on. `-fno-sanitize-recover=all` makes every | |
| # finding fail the test rather than printing and continuing. | |
| run: | | |
| cmake -S . -B build -G Ninja \ | |
| -DCITOR_BUILD_BENCHMARK=OFF \ | |
| -DCMAKE_BUILD_TYPE=RelWithDebInfo \ | |
| -DCMAKE_C_COMPILER_LAUNCHER=ccache \ | |
| -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ | |
| -DCMAKE_CXX_FLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer -fno-sanitize-recover=all" \ | |
| -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,undefined" | |
| - name: Build | |
| run: cmake --build build -j | |
| - name: Test | |
| env: | |
| # `detect_leaks=0` because the lazily-initialised `PoolGroup` arenas | |
| # outlive `main()` on purpose; LSan flags them as leaked otherwise. | |
| ASAN_OPTIONS: "halt_on_error=1:abort_on_error=0:detect_leaks=0" | |
| UBSAN_OPTIONS: "halt_on_error=1:print_stacktrace=1" | |
| run: ctest --test-dir build --output-on-failure -j | |
| windows-msvc: | |
| name: windows-msvc-2022 | |
| runs-on: windows-2022 | |
| timeout-minutes: 25 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: CPM source cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/AppData/Local/.cache/CPM | |
| key: cpm-windows-${{ hashFiles('cmake/CPM.cmake', 'cmake/GTestDep.cmake') }} | |
| restore-keys: | | |
| cpm-windows- | |
| - name: Configure (MSVC, x64) | |
| # The Visual Studio 2022 generator picks the MSVC toolchain by | |
| # default and pulls in `cl.exe` through CMake's `vcvars` discovery. | |
| # Bench is off (the peer-pool CPM pulls are Linux-only); tidy is | |
| # off (no clang-tidy on this runner); tests are on. | |
| env: | |
| CPM_SOURCE_CACHE: ${{ github.workspace }}\.cache\CPM | |
| run: | | |
| cmake -S . -B build -G "Visual Studio 17 2022" -A x64 ` | |
| -DCITOR_BUILD_BENCHMARK=OFF ` | |
| -DCITOR_ENABLE_CLANG_TIDY=OFF | |
| - name: Build (Release) | |
| run: cmake --build build --config Release -j | |
| - name: Test | |
| # GoogleTest binaries land under build/tests/Release/ with the | |
| # multi-config VS generator; ctest finds them automatically. | |
| run: ctest --test-dir build -C Release --output-on-failure -j | |
| tsan-smoke: | |
| name: tsan (smoke) | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 20 | |
| env: | |
| CC: clang-18 | |
| CXX: clang++-18 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install toolchain | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y clang-18 lld-18 ninja-build llvm-18 | |
| - name: CPM source cache | |
| uses: actions/cache@v4 | |
| with: | |
| path: ~/.cache/CPM | |
| key: cpm-${{ runner.os }}-${{ hashFiles('cmake/CPM.cmake', 'cmake/GTestDep.cmake') }} | |
| restore-keys: | | |
| cpm-${{ runner.os }}- | |
| - name: ccache | |
| uses: hendrikmuhs/ccache-action@v1.2 | |
| with: | |
| key: tsan-ci | |
| max-size: 500M | |
| - name: Configure | |
| env: | |
| CPM_SOURCE_CACHE: ${{ github.workspace }}/.cache/CPM | |
| run: | | |
| cmake -S . -B build -G Ninja \ | |
| -DCITOR_BUILD_BENCHMARK=OFF \ | |
| -DCITOR_BUILD_WITH_SANITIZER=ON \ | |
| -DCMAKE_BUILD_TYPE=RelWithDebInfo \ | |
| -DCMAKE_C_COMPILER_LAUNCHER=ccache \ | |
| -DCMAKE_CXX_COMPILER_LAUNCHER=ccache | |
| - name: Build | |
| run: cmake --build build -j | |
| # Curated subset that exercises the pool's concurrency surfaces under | |
| # TSan without picking up the long-running stress, fuzz, and | |
| # cross-run-determinism tests whose worst-case slowdown under TSan | |
| # exceeds the per-test timeout. | |
| - name: Test | |
| run: | | |
| ctest --test-dir build --output-on-failure -j \ | |
| -R '(parallel_for_cpo|parallel_for_partition|parallel_for_tsan|parallel_reduce_cpo|parallel_chain_basic|parallel_chain_cpo|inclusive_scan_cpo|fork_join_spawn_sync|run_plex_cpo|submit_detached_dispatch|cancellation_token)_test$' | |
| pre-commit: | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 10 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - uses: pre-commit/action@v3.0.1 | |
| version-sync: | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 5 | |
| needs: [build-and-test, pre-commit] | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install commitizen | |
| run: pip install commitizen | |
| - name: Check every version_files target matches the project version | |
| run: | | |
| set -euo pipefail | |
| PROJECT_VERSION=$(cz version --project) | |
| echo "project version = ${PROJECT_VERSION}" | |
| # commitizen errors if any tracked file's version line is missing or | |
| # does not match the project version. `--yes` skips the interactive | |
| # tag-confirmation prompt that fails with EOFError on CI runners. | |
| cz bump --files-only --dry-run --increment PATCH --yes | |
| packaging-cmake-install: | |
| name: packaging (cmake install + find_package) | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 15 | |
| env: | |
| CC: clang-18 | |
| CXX: clang++-18 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install toolchain | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y --no-install-recommends clang-18 lld-18 ninja-build | |
| - name: Build + install citor | |
| run: | | |
| cmake -S . -B build-pkg -G Ninja \ | |
| -DCITOR_BUILD_TESTS=OFF \ | |
| -DCITOR_BUILD_BENCHMARK=OFF \ | |
| -DCMAKE_INSTALL_PREFIX=/tmp/citor-inst | |
| cmake --build build-pkg -j | |
| cmake --install build-pkg | |
| - name: Build + run consumer against installed citor | |
| run: | | |
| cmake -S packaging/test/consumer -B /tmp/citor-consumer -G Ninja \ | |
| -DCMAKE_PREFIX_PATH=/tmp/citor-inst | |
| cmake --build /tmp/citor-consumer -j | |
| /tmp/citor-consumer/consumer | |
| packaging-conan: | |
| name: packaging (conan 2.x) | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 15 | |
| env: | |
| CC: clang-18 | |
| CXX: clang++-18 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install toolchain | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y --no-install-recommends clang-18 lld-18 ninja-build cmake | |
| - uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install conan | |
| run: pip install "conan>=2.0,<3.0" | |
| - name: Configure conan profile | |
| run: conan profile detect --force | |
| - name: Create local citor package | |
| run: | | |
| VERSION=$(python -c "import tomllib;print(tomllib.loads(open('pyproject.toml').read())['tool']['commitizen']['version'])") | |
| conan create packaging/conan --version "$VERSION" | |
| - name: Build + run consumer against local conan package | |
| run: | | |
| mkdir -p /tmp/citor-conan-test | |
| cp -r packaging/test/consumer/* /tmp/citor-conan-test/ | |
| cd /tmp/citor-conan-test | |
| conan install . --build=missing -s compiler.cppstd=20 | |
| cmake --preset conan-release | |
| cmake --build --preset conan-release | |
| ./build/Release/consumer | |
| packaging-single-header: | |
| name: packaging (single-header drop-in) | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 5 | |
| env: | |
| CC: clang-18 | |
| CXX: clang++-18 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install toolchain | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y --no-install-recommends clang-18 | |
| - name: Compile + run drop-in consumer with no build system | |
| # Consumes the checked-in `single_include/citor.hpp` exactly as an | |
| # end user would. The embedded commit SHA in the header drifts by | |
| # one whenever a non-source commit lands (the amalgamate hook | |
| # only fires on `include/citor/**.h` and `tools/amalgamate.py`), | |
| # so the previously-wired `--check` step would fail on every | |
| # docs/CI commit. The release pipeline owns the regen instead. | |
| run: | | |
| clang++-18 -std=c++20 -O2 -pthread -mavx2 -mfma -DCITOR_USE_AVX2 \ | |
| -I single_include \ | |
| packaging/test/consumer_single_header/main.cpp \ | |
| -o /tmp/single-header-consumer | |
| /tmp/single-header-consumer | |
| packaging-fetchcontent: | |
| name: packaging (CMake FetchContent) | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 10 | |
| env: | |
| CC: clang-18 | |
| CXX: clang++-18 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install toolchain | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y --no-install-recommends clang-18 ninja-build | |
| - name: Build + run consumer via FetchContent | |
| run: | | |
| cmake -S packaging/test/consumer_fetchcontent -B /tmp/citor-fc -G Ninja \ | |
| -DCITOR_SOURCE_DIR="$GITHUB_WORKSPACE" | |
| cmake --build /tmp/citor-fc -j | |
| /tmp/citor-fc/consumer | |
| packaging-cpm: | |
| name: packaging (CPM) | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 10 | |
| env: | |
| CC: clang-18 | |
| CXX: clang++-18 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install toolchain | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install -y --no-install-recommends clang-18 ninja-build | |
| - name: Build + run consumer via CPM | |
| run: | | |
| cmake -S packaging/test/consumer_cpm -B /tmp/citor-cpm -G Ninja \ | |
| -DCITOR_SOURCE_DIR="$GITHUB_WORKSPACE" | |
| cmake --build /tmp/citor-cpm -j | |
| /tmp/citor-cpm/consumer |