diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 260830a3..7a4032e6 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -1,47 +1,10 @@ name: Builds +# Driven by .github/workflows/ci.yml. PR and push-to-main triggers live in +# the parent so a single "CI" check gates every PR regardless of paths. on: - push: - branches: ["main"] - paths: - - src/** - - include/** - - cpp-example-collection/** - - client-sdk-rust/** - - cmake/** - - scripts/** - - CMakeLists.txt - - build.sh - - build.cmd - - .build-info.json.in - - vcpkg.json - - CMakePresets.json - - docker/Dockerfile.base - - docker/Dockerfile.sdk - - .github/workflows/** - - .clang-format - - scripts/clang-format.sh - pull_request: - branches: ["main"] - paths: - - src/** - - include/** - - cpp-example-collection/** - - client-sdk-rust/** - - cmake/** - - scripts/** - - CMakeLists.txt - - build.sh - - build.cmd - - .build-info.json.in - - vcpkg.json - - CMakePresets.json - - docker/Dockerfile.base - - docker/Dockerfile.sdk - - .github/workflows/** - - .clang-format - - scripts/clang-format.sh - workflow_dispatch: + workflow_call: {} + workflow_dispatch: {} permissions: contents: read @@ -50,27 +13,21 @@ permissions: env: CARGO_TERM_COLOR: always - # sccache caches rustc invocations across runs. RUSTC_WRAPPER is exported - # only after the setup step verifies the GHA cache backend is reachable, so - # transient cache backend failures fall back to uncached rustc instead of - # failing the build. - SCCACHE_GHA_ENABLED: "true" - # Pinned commit for cpp-example-collection smoke build (https://github.com/livekit-examples/cpp-example-collection) - CPP_EXAMPLE_COLLECTION_REF: bbf0fdf72dac2239117213475449565686f8c58b - # vcpkg binary caching for Windows + # Disable Cargo incremental artifacts. The Rust FFI is built once per + # submodule SHA and cached whole (see the cargo target cache below), so + # incremental dirs add nothing but bloat the cached target/ directory and + # slow the cache upload/download. + CARGO_INCREMENTAL: "0" + # vcpkg binary caching for Windows. The x-gha backend was removed from vcpkg, + # so use vcpkg's files provider and persist that directory with actions/cache. + VCPKG_GIT_COMMIT: fb87e2bb3fe69e16c224989acb5a61349166c782 + VCPKG_BINARY_CACHE_DIR: ${{ github.workspace }}/.vcpkg-binary-cache + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.vcpkg-binary-cache,readwrite" VCPKG_DEFAULT_TRIPLET: x64-windows-static-md VCPKG_DEFAULT_HOST_TRIPLET: x64-windows-static-md VCPKG_TARGET_TRIPLET: x64-windows-static-md jobs: - license-check: - name: License Check - uses: ./.github/workflows/license_check.yml - - pin-check: - name: Pin Check - uses: ./.github/workflows/pin_check.yml - build: strategy: fail-fast: false @@ -111,20 +68,36 @@ jobs: - name: Pull LFS files run: git lfs pull - # ---------- vcpkg caching for Windows ---------- - - name: Export GitHub Actions cache environment variables + # Cargo's freshness check is mtime-based. A fresh `actions/checkout` + # stamps every submodule source file with the checkout time, which is + # newer than the cached target/ artifacts — so cargo rebuilds the whole + # client-sdk-rust workspace (~6 min) even on an exact cargo-target cache + # hit. Pin all submodule source files to a fixed, deterministic + # timestamp (older than any cached artifact) so cargo treats them as + # unchanged across runs and reuses the cached FFI build. Runs before the + # cargo target cache is restored, so target/ does not yet exist and is + # never touched. shell: bash so this also runs under Git Bash on Windows. + - name: Stabilize Rust source mtimes for cargo freshness + shell: bash + run: | + find client-sdk-rust -type f -not -path '*/.git/*' -exec touch -t 202001010000 {} + + + # ---------- vcpkg for Windows ---------- + - name: Restore vcpkg binary cache if: runner.os == 'Windows' - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + id: cache-vcpkg-binary + uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: - script: | - core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); - core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + path: ${{ env.VCPKG_BINARY_CACHE_DIR }} + key: ${{ runner.os }}-${{ matrix.name }}-vcpkg-binary-${{ env.VCPKG_TARGET_TRIPLET }}-${{ env.VCPKG_GIT_COMMIT }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.name }}-vcpkg-binary-${{ env.VCPKG_TARGET_TRIPLET }}-${{ env.VCPKG_GIT_COMMIT }}- - name: Setup vcpkg (Windows only) if: runner.os == 'Windows' uses: lukka/run-vcpkg@6fe69898af670ac05f4a8427cc5cff4fb361cee5 # v11.5 with: - vcpkgGitCommitId: 'fb87e2bb3fe69e16c224989acb5a61349166c782' + vcpkgGitCommitId: ${{ env.VCPKG_GIT_COMMIT }} # ---------- OS-specific deps ---------- - name: Install deps (Ubuntu) @@ -161,21 +134,17 @@ jobs: if: matrix.name == 'macos-x64' run: rustup target add x86_64-apple-darwin - # ---------- Setup sccache ---------- - - name: Setup sccache - uses: mozilla-actions/sccache-action@054db53350805f83040bf3e6e9b8cf5a139aa7c9 # v0.0.7 - - - name: Enable sccache wrapping (probe first) + # ---------- Cache Cargo ---------- + # The Rust FFI is built from the pinned client-sdk-rust submodule. Its + # compiled output only changes when the submodule commit changes, so we + # key the target cache on the submodule SHA (not Cargo.lock, which is + # pinned inside the submodule and effectively immutable -- that froze the + # old cache permanently). Resolve it once here for the restore/save steps. + - name: Resolve Rust submodule SHA + id: rust_sha shell: bash - run: | - if sccache --start-server >/dev/null 2>&1; then - echo "RUSTC_WRAPPER=sccache" >> "$GITHUB_ENV" - echo "::notice::sccache enabled (RUSTC_WRAPPER=sccache)" - else - echo "::warning::sccache backend unreachable; building without compile cache this run" - fi + run: echo "sha=$(git -C client-sdk-rust rev-parse HEAD)" >> "$GITHUB_OUTPUT" - # ---------- Cache Cargo ---------- - name: Cache cargo registry uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: @@ -187,11 +156,17 @@ jobs: restore-keys: | ${{ runner.os }}-${{ matrix.name }}-cargo-registry- - - name: Cache cargo target - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + # Restore-only here; the matching save runs after a successful build (see + # "Save cargo target" below). A combined actions/cache saves in a post-job + # step that runs AFTER the "Clean after build" cleanup wipes target/debug + # and target/release, which is why the old cache was always ~empty. The + # restore/save split lets us snapshot the populated target/ before cleanup. + - name: Restore cargo target + id: cache-cargo-target + uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: client-sdk-rust/target/ - key: ${{ runner.os }}-${{ matrix.name }}-cargo-target-${{ hashFiles('client-sdk-rust/Cargo.lock') }} + key: ${{ runner.os }}-${{ matrix.name }}-cargo-target-${{ steps.rust_sha.outputs.sha }} restore-keys: | ${{ runner.os }}-${{ matrix.name }}-cargo-target- @@ -199,10 +174,10 @@ jobs: - name: Set Linux build environment if: runner.os == 'Linux' run: | - echo "CXXFLAGS=-Wno-deprecated-declarations" >> $GITHUB_ENV - echo "CFLAGS=-Wno-deprecated-declarations" >> $GITHUB_ENV + echo "CXXFLAGS=-Wno-deprecated-declarations" >> "$GITHUB_ENV" + echo "CFLAGS=-Wno-deprecated-declarations" >> "$GITHUB_ENV" LLVM_VERSION=$(llvm-config --version | cut -d. -f1) - echo "LIBCLANG_PATH=/usr/lib/llvm-${LLVM_VERSION}/lib" >> $GITHUB_ENV + echo "LIBCLANG_PATH=/usr/lib/llvm-${LLVM_VERSION}/lib" >> "$GITHUB_ENV" # ---------- Build ---------- - name: Build (Unix) @@ -217,6 +192,25 @@ jobs: shell: pwsh run: ${{ matrix.build_cmd }} + # Save the populated target/ now, while the build output still exists and + # before the "Clean after build" step runs clean-all. Only on a miss -- + # an exact-key hit means the cache already holds this submodule's output. + # A restore-keys prefix hit still counts as a miss (cache-hit != 'true'), + # so a submodule bump always refreshes the cache under the new SHA. + - name: Save cargo target + if: steps.cache-cargo-target.outputs.cache-hit != 'true' + uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + path: client-sdk-rust/target/ + key: ${{ runner.os }}-${{ matrix.name }}-cargo-target-${{ steps.rust_sha.outputs.sha }} + + - name: Save vcpkg binary cache + if: runner.os == 'Windows' && steps.cache-vcpkg-binary.outputs.cache-hit != 'true' + uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + with: + path: ${{ env.VCPKG_BINARY_CACHE_DIR }} + key: ${{ runner.os }}-${{ matrix.name }}-vcpkg-binary-${{ env.VCPKG_TARGET_TRIPLET }}-${{ env.VCPKG_GIT_COMMIT }}-${{ hashFiles('vcpkg.json') }} + # ---------- Smoke test cpp-example-collection binaries ---------- # Built under cpp-example-collection-build/ (not build-dir/bin). Visual Studio # multi-config places executables in per-target Release/ (or Debug/) subdirs. @@ -506,6 +500,25 @@ jobs: if: github.event_name == 'pull_request' steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 1 + + # Reclaim ~30GB before loading the multi-GB SDK image and building the + # example collection inside it. Mirrors the docker-build jobs; without it + # the x64 collection build has hit "no space left on device". + - name: Free disk space + uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 + with: + tool-cache: false + android: true + dotnet: true + haskell: true + large-packages: true + docker-images: true + swap-storage: true + - name: Download Docker image artifact uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: @@ -516,7 +529,8 @@ jobs: - name: Build cpp-example-collection against installed SDK run: | - docker run -e CPP_EX_REF="${{ env.CPP_EXAMPLE_COLLECTION_REF }}" --rm livekit-cpp-sdk:${{ github.sha }} bash -lc ' + cpp_ex_ref="$(git rev-parse HEAD:cpp-example-collection)" + docker run -e CPP_EX_REF="${cpp_ex_ref}" --rm livekit-cpp-sdk:${{ github.sha }} bash -lc ' set -euxo pipefail git clone https://github.com/livekit-examples/cpp-example-collection.git /tmp/cpp-example-collection cd /tmp/cpp-example-collection @@ -525,7 +539,6 @@ jobs: cmake -S . -B build -DLIVEKIT_LOCAL_SDK_DIR=/opt/livekit-sdk cmake --build build --parallel ' - build-collections-x64: name: Build (cpp-example-collection-x64) runs-on: ubuntu-latest @@ -533,6 +546,25 @@ jobs: if: github.event_name == 'pull_request' steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 1 + + # Reclaim ~30GB before loading the multi-GB SDK image and building the + # example collection inside it. The standard ubuntu-latest runner has hit + # "no space left on device" here without this step. + - name: Free disk space + uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 + with: + tool-cache: false + android: true + dotnet: true + haskell: true + large-packages: true + docker-images: true + swap-storage: true + - name: Download Docker image artifact uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 with: @@ -543,7 +575,8 @@ jobs: - name: Build cpp-example-collection against installed SDK run: | - docker run -e CPP_EX_REF="${{ env.CPP_EXAMPLE_COLLECTION_REF }}" --rm livekit-cpp-sdk-x64:${{ github.sha }} bash -lc ' + cpp_ex_ref="$(git rev-parse HEAD:cpp-example-collection)" + docker run -e CPP_EX_REF="${cpp_ex_ref}" --rm livekit-cpp-sdk-x64:${{ github.sha }} bash -lc ' set -euxo pipefail git clone https://github.com/livekit-examples/cpp-example-collection.git /tmp/cpp-example-collection cd /tmp/cpp-example-collection @@ -552,108 +585,3 @@ jobs: cmake -S . -B build -DLIVEKIT_LOCAL_SDK_DIR=/opt/livekit-sdk cmake --build build --parallel ' - - clang-format: - name: clang-format - runs-on: ubuntu-latest - continue-on-error: false - permissions: - contents: read - - steps: - - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - # No submodules: scripts/clang-format.sh only walks our own src/ tree - fetch-depth: 1 - - - name: Install clang-format 22 - run: | - set -eux - # Pin clang-format 22 to match the current macOS Homebrew LLVM - # Ubuntu 24.04's default clang-format ships with LLVM 18 - sudo install -m 0755 -d /etc/apt/keyrings - wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key \ - | sudo tee /etc/apt/keyrings/llvm.asc >/dev/null - sudo chmod a+r /etc/apt/keyrings/llvm.asc - codename=$(lsb_release -cs) - echo "deb [signed-by=/etc/apt/keyrings/llvm.asc] http://apt.llvm.org/${codename}/ llvm-toolchain-${codename}-22 main" \ - | sudo tee /etc/apt/sources.list.d/llvm-22.list >/dev/null - sudo apt-get update - sudo apt-get install -y clang-format-22 - sudo ln -sf /usr/bin/clang-format-22 /usr/local/bin/clang-format - clang-format --version - - - name: Run clang-format - env: - FORMAT_BLOB_SHA: ${{ github.event.pull_request.head.sha || github.sha }} - run: ./scripts/clang-format.sh - - clang-tidy: - name: clang-tidy - runs-on: ubuntu-latest - continue-on-error: false - permissions: - contents: read - - steps: - - name: Checkout (with submodules) - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - with: - submodules: recursive - fetch-depth: 1 - - - name: Install dependencies - run: | - set -eux - sudo apt-get update - sudo apt-get install -y \ - build-essential cmake ninja-build pkg-config \ - llvm-dev libclang-dev clang \ - libssl-dev wget ca-certificates gnupg - - - name: Install clang-tidy 19 (for ExcludeHeaderFilterRegex support) - run: | - set -eux - # Ubuntu 24.04 apt ships clang-tidy 18, which doesn't understand - # ExcludeHeaderFilterRegex (added in 19). Pull clang-tidy 19 from - # the upstream LLVM apt repository and pin the unversioned names. - sudo install -m 0755 -d /etc/apt/keyrings - wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key \ - | sudo tee /etc/apt/keyrings/llvm.asc >/dev/null - sudo chmod a+r /etc/apt/keyrings/llvm.asc - codename=$(lsb_release -cs) - echo "deb [signed-by=/etc/apt/keyrings/llvm.asc] http://apt.llvm.org/${codename}/ llvm-toolchain-${codename}-19 main" \ - | sudo tee /etc/apt/sources.list.d/llvm-19.list >/dev/null - sudo apt-get update - sudo apt-get install -y clang-tidy-19 clang-tools-19 - sudo ln -sf /usr/bin/clang-tidy-19 /usr/local/bin/clang-tidy - sudo ln -sf /usr/bin/run-clang-tidy-19 /usr/local/bin/run-clang-tidy - clang-tidy --version - run-clang-tidy --help | head -1 || true - - - name: Install Rust (stable) - uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 - with: - toolchain: stable - - - name: Set Linux build environment - run: | - echo "CXXFLAGS=-Wno-deprecated-declarations" >> $GITHUB_ENV - echo "CFLAGS=-Wno-deprecated-declarations" >> $GITHUB_ENV - LLVM_VERSION=$(llvm-config --version | cut -d. -f1) - echo "LIBCLANG_PATH=/usr/lib/llvm-${LLVM_VERSION}/lib" >> $GITHUB_ENV - - - name: CMake configure - run: cmake --preset linux-release - - - name: Generate protobuf headers - run: cmake --build build-release --target livekit_proto - - - name: Run clang-tidy - env: - TIDY_BLOB_SHA: ${{ github.event.pull_request.head.sha || github.sha }} - # This script is intended to be run locally and in CI. It will auto-detect - # the GHA environment and add PR annotations and a run summary. - # As of writing all warnings are treateded as errors to avoid tech debt build up - run: ./scripts/clang-tidy.sh --fail-on-warning diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 00000000..e1188058 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,130 @@ +name: CI + +on: + workflow_dispatch: + pull_request: + types: [opened, reopened, synchronize, ready_for_review] + branches: ["main"] + push: + branches: ["main"] + +# concurrency: +# group: ci-${{ github.ref }} +# cancel-in-progress: ${{ github.event_name == 'pull_request' }} + +permissions: + contents: read + actions: read + packages: read + +jobs: + # Compute once which path groups changed; every other job references these + # outputs. dorny/paths-filter handles PR base diff, push base diff, and + # empty results on non-diff events (workflow_dispatch); the `if:` guards + # below explicitly opt manual runs back into running everything. + changes: + name: Detect changes + runs-on: ubuntu-latest + outputs: + builds: ${{ steps.filter.outputs.builds }} + tests: ${{ steps.filter.outputs.tests }} + docs: ${{ steps.filter.outputs.docs }} + quality: ${{ steps.filter.outputs.quality }} + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1 + id: filter + with: + filters: | + builds: + - src/** + - include/** + - benchmarks/** + - cpp-example-collection + - cpp-example-collection/** + - client-sdk-rust/** + - cmake/** + - docker/** + - CMakeLists.txt + - CMakePresets.json + - build.sh + - build.cmd + - build.h.in + - .build-info.json.in + - vcpkg.json + - .github/workflows/ci.yml + - .github/workflows/builds.yml + tests: + - src/** + - include/** + - client-sdk-rust/** + - cmake/** + - .token_helpers/** + - CMakeLists.txt + - CMakePresets.json + - build.sh + - build.cmd + - build.h.in + - .build-info.json.in + - vcpkg.json + - .github/workflows/ci.yml + - .github/workflows/tests.yml + docs: + - README.md + - include/** + - docs/** + - scripts/generate-docs.sh + - .github/workflows/ci.yml + - .github/workflows/generate-docs.yml + - .github/workflows/publish-docs.yml + - "!AGENTS.md" + quality: + - src/** + - include/** + - benchmarks/** + - client-sdk-rust/** + - cmake/** + - CMakeLists.txt + - CMakePresets.json + - scripts/clang-format.sh + - scripts/clang-tidy.sh + - .clang-format + - .clang-tidy + - .github/workflows/ci.yml + - .github/workflows/quality-checks.yml + + builds: + name: Builds + needs: changes + if: ${{ needs.changes.outputs.builds == 'true' || github.event_name == 'workflow_dispatch' }} + uses: ./.github/workflows/builds.yml + secrets: inherit + + tests: + name: Tests + needs: changes + if: ${{ needs.changes.outputs.tests == 'true' || github.event_name == 'workflow_dispatch' }} + uses: ./.github/workflows/tests.yml + secrets: inherit + + # license-check and pin-check are cheap (seconds) and broad enough that they + # should run on every PR. + license-check: + name: License Check + uses: ./.github/workflows/license_check.yml + + pin-check: + name: Pin Check + uses: ./.github/workflows/pin_check.yml + + quality-checks: + name: Quality Checks + needs: changes + if: ${{ needs.changes.outputs.quality == 'true' || github.event_name == 'workflow_dispatch' }} + uses: ./.github/workflows/quality-checks.yml + + generate-docs: + name: Generate Docs + needs: changes + if: ${{ needs.changes.outputs.docs == 'true' || github.event_name == 'workflow_dispatch' }} + uses: ./.github/workflows/generate-docs.yml diff --git a/.github/workflows/docker-images.yml b/.github/workflows/docker-images.yml index 1e9aa5a6..9c48faf0 100644 --- a/.github/workflows/docker-images.yml +++ b/.github/workflows/docker-images.yml @@ -15,8 +15,11 @@ on: - CMakePresets.json - cmake/** - data/** + - cpp-example-collection - docker/Dockerfile.base - docker/Dockerfile.sdk + - .github/workflows/docker-images.yml + - .github/workflows/docker-validate.yml permissions: contents: read @@ -89,7 +92,7 @@ jobs: fi case "${path}" in - docker/Dockerfile.sdk|src/*|include/*|client-sdk-rust/*|cmake/*|data/*|CMakeLists.txt|build.sh|build.cmd|build.h.in|.build-info.json.in|CMakePresets.json) + docker/Dockerfile.sdk|src/*|include/*|client-sdk-rust/*|cmake/*|data/*|cpp-example-collection|CMakeLists.txt|build.sh|build.cmd|build.h.in|.build-info.json.in|CMakePresets.json|.github/workflows/docker-images.yml|.github/workflows/docker-validate.yml) sdk_changed=true ;; esac diff --git a/.github/workflows/docker-validate.yml b/.github/workflows/docker-validate.yml index d8575428..a69a3c65 100644 --- a/.github/workflows/docker-validate.yml +++ b/.github/workflows/docker-validate.yml @@ -9,10 +9,6 @@ permissions: contents: read packages: read -env: - # Pinned commit for cpp-example-collection smoke build (https://github.com/livekit-examples/cpp-example-collection) - CPP_EXAMPLE_COLLECTION_REF: bbf0fdf72dac2239117213475449565686f8c58b - jobs: validate-x64: name: Validate Docker image (linux-x64) @@ -23,6 +19,11 @@ jobs: github.event.workflow_run.head_branch == 'main' steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 1 + - name: Resolve image name id: refs shell: bash @@ -52,7 +53,8 @@ jobs: - name: Build cpp-example-collection against installed SDK run: | - docker run -e CPP_EX_REF="${{ env.CPP_EXAMPLE_COLLECTION_REF }}" --rm "${{ steps.refs.outputs.sdk_image }}" bash -lc ' + cpp_ex_ref="$(git rev-parse HEAD:cpp-example-collection)" + docker run -e CPP_EX_REF="${cpp_ex_ref}" --rm "${{ steps.refs.outputs.sdk_image }}" bash -lc ' set -euxo pipefail git clone https://github.com/livekit-examples/cpp-example-collection.git /tmp/cpp-example-collection cd /tmp/cpp-example-collection @@ -71,6 +73,11 @@ jobs: github.event.workflow_run.head_branch == 'main' steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + fetch-depth: 1 + - name: Resolve image name id: refs shell: bash @@ -100,7 +107,8 @@ jobs: - name: Build cpp-example-collection against installed SDK run: | - docker run -e CPP_EX_REF="${{ env.CPP_EXAMPLE_COLLECTION_REF }}" --rm "${{ steps.refs.outputs.sdk_image }}" bash -lc ' + cpp_ex_ref="$(git rev-parse HEAD:cpp-example-collection)" + docker run -e CPP_EX_REF="${cpp_ex_ref}" --rm "${{ steps.refs.outputs.sdk_image }}" bash -lc ' set -euxo pipefail git clone https://github.com/livekit-examples/cpp-example-collection.git /tmp/cpp-example-collection cd /tmp/cpp-example-collection diff --git a/.github/workflows/generate-docs.yml b/.github/workflows/generate-docs.yml index 52ea026e..5c2c6192 100644 --- a/.github/workflows/generate-docs.yml +++ b/.github/workflows/generate-docs.yml @@ -10,16 +10,9 @@ permissions: # The artifact is attached to the workflow run so reviewers can download a preview, # but also to verify the documentation artifact is valid for subsequent release runs # that will publish them to the LiveKit docs web page: https://docs.livekit.io/reference/client-sdk-cpp/ +# Driven by .github/workflows/ci.yml on PRs. PR trigger lives in the parent +# so a single "CI" check gates every PR regardless of paths. on: - pull_request: - branches: ["main"] - paths: - - include/** - - src/** - - docs/** - - scripts/generate-docs.sh - - .github/workflows/generate-docs.yml - - .github/workflows/publish-docs.yml workflow_call: inputs: version: diff --git a/.github/workflows/make-release.yml b/.github/workflows/make-release.yml index bfce4586..09dc275e 100644 --- a/.github/workflows/make-release.yml +++ b/.github/workflows/make-release.yml @@ -13,11 +13,6 @@ on: env: CARGO_TERM_COLOR: always - # sccache caches rustc invocations across runs. RUSTC_WRAPPER is exported - # only after the setup step verifies the GHA cache backend is reachable, so - # transient cache backend failures fall back to uncached rustc instead of - # failing the build. - SCCACHE_GHA_ENABLED: "true" VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite" VCPKG_DEFAULT_TRIPLET: x64-windows-static-md VCPKG_DEFAULT_HOST_TRIPLET: x64-windows-static-md @@ -140,21 +135,16 @@ jobs: if: matrix.name == 'macos-x64' run: rustup target add x86_64-apple-darwin - # ---------- Setup sccache ---------- - - name: Setup sccache - uses: mozilla-actions/sccache-action@054db53350805f83040bf3e6e9b8cf5a139aa7c9 # v0.0.7 - - - name: Enable sccache wrapping (probe first) + # ---------- Cache Cargo ---------- + # Key the target cache on the client-sdk-rust submodule SHA (Cargo.lock is + # pinned inside the submodule and froze the old cache). No clean step runs + # in this workflow, so the combined actions/cache post-job save captures + # the populated target/ correctly once the key busts on a submodule bump. + - name: Resolve Rust submodule SHA + id: rust_sha shell: bash - run: | - if sccache --start-server >/dev/null 2>&1; then - echo "RUSTC_WRAPPER=sccache" >> "$GITHUB_ENV" - echo "::notice::sccache enabled (RUSTC_WRAPPER=sccache)" - else - echo "::warning::sccache backend unreachable; building without compile cache this run" - fi + run: echo "sha=$(git -C client-sdk-rust rev-parse HEAD)" >> "$GITHUB_OUTPUT" - # ---------- Cache Cargo ---------- - name: Cache Cargo registry uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: @@ -170,7 +160,7 @@ jobs: uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: client-sdk-rust/target/ - key: ${{ runner.os }}-${{ matrix.name }}-cargo-target-${{ hashFiles('client-sdk-rust/Cargo.lock') }} + key: ${{ runner.os }}-${{ matrix.name }}-cargo-target-${{ steps.rust_sha.outputs.sha }} restore-keys: | ${{ runner.os }}-${{ matrix.name }}-cargo-target- diff --git a/.github/workflows/quality-checks.yml b/.github/workflows/quality-checks.yml new file mode 100644 index 00000000..4c337bc9 --- /dev/null +++ b/.github/workflows/quality-checks.yml @@ -0,0 +1,112 @@ +name: Quality Checks + +# Driven by .github/workflows/ci.yml. PR and push-to-main triggers live in +# the parent so a single "CI" check gates every PR regardless of paths. +on: + workflow_call: {} + workflow_dispatch: {} + +permissions: + contents: read + +jobs: + clang-format: + name: clang-format + runs-on: ubuntu-latest + continue-on-error: false + + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + # No submodules: scripts/clang-format.sh only walks our own src/ tree + fetch-depth: 1 + + - name: Install clang-format 22 + run: | + set -eux + # Pin clang-format 22 to match the current macOS Homebrew LLVM + # Ubuntu 24.04's default clang-format ships with LLVM 18 + sudo install -m 0755 -d /etc/apt/keyrings + wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key \ + | sudo tee /etc/apt/keyrings/llvm.asc >/dev/null + sudo chmod a+r /etc/apt/keyrings/llvm.asc + codename=$(lsb_release -cs) + echo "deb [signed-by=/etc/apt/keyrings/llvm.asc] http://apt.llvm.org/${codename}/ llvm-toolchain-${codename}-22 main" \ + | sudo tee /etc/apt/sources.list.d/llvm-22.list >/dev/null + sudo apt-get update + sudo apt-get install -y clang-format-22 + sudo ln -sf /usr/bin/clang-format-22 /usr/local/bin/clang-format + clang-format --version + + - name: Run clang-format + env: + FORMAT_BLOB_SHA: ${{ github.event.pull_request.head.sha || github.sha }} + run: ./scripts/clang-format.sh + + clang-tidy: + name: clang-tidy + runs-on: ubuntu-latest + continue-on-error: false + + steps: + - name: Checkout (with submodules) + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + submodules: recursive + fetch-depth: 1 + + - name: Install dependencies + run: | + set -eux + sudo apt-get update + sudo apt-get install -y \ + build-essential cmake ninja-build pkg-config \ + llvm-dev libclang-dev clang \ + libssl-dev wget ca-certificates gnupg + + - name: Install clang-tidy 19 (for ExcludeHeaderFilterRegex support) + run: | + set -eux + # Ubuntu 24.04 apt ships clang-tidy 18, which doesn't understand + # ExcludeHeaderFilterRegex (added in 19). Pull clang-tidy 19 from + # the upstream LLVM apt repository and pin the unversioned names. + sudo install -m 0755 -d /etc/apt/keyrings + wget -qO- https://apt.llvm.org/llvm-snapshot.gpg.key \ + | sudo tee /etc/apt/keyrings/llvm.asc >/dev/null + sudo chmod a+r /etc/apt/keyrings/llvm.asc + codename=$(lsb_release -cs) + echo "deb [signed-by=/etc/apt/keyrings/llvm.asc] http://apt.llvm.org/${codename}/ llvm-toolchain-${codename}-19 main" \ + | sudo tee /etc/apt/sources.list.d/llvm-19.list >/dev/null + sudo apt-get update + sudo apt-get install -y clang-tidy-19 clang-tools-19 + sudo ln -sf /usr/bin/clang-tidy-19 /usr/local/bin/clang-tidy + sudo ln -sf /usr/bin/run-clang-tidy-19 /usr/local/bin/run-clang-tidy + clang-tidy --version + run-clang-tidy --help | head -1 || true + + - name: Install Rust (stable) + uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9 + with: + toolchain: stable + + - name: Set Linux build environment + run: | + echo "CXXFLAGS=-Wno-deprecated-declarations" >> "$GITHUB_ENV" + echo "CFLAGS=-Wno-deprecated-declarations" >> "$GITHUB_ENV" + LLVM_VERSION=$(llvm-config --version | cut -d. -f1) + echo "LIBCLANG_PATH=/usr/lib/llvm-${LLVM_VERSION}/lib" >> "$GITHUB_ENV" + + - name: CMake configure + run: cmake --preset linux-release + + - name: Generate protobuf headers + run: cmake --build build-release --target livekit_proto + + - name: Run clang-tidy + env: + TIDY_BLOB_SHA: ${{ github.event.pull_request.head.sha || github.sha }} + # This script is intended to be run locally and in CI. It will auto-detect + # the GHA environment and add PR annotations and a run summary. + # As of writing all warnings are treateded as errors to avoid tech debt build up + run: ./scripts/clang-tidy.sh --fail-on-warning diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index b998be8f..e81e3e41 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,33 +1,10 @@ name: Tests +# Driven by .github/workflows/ci.yml. PR and push-to-main triggers live in +# the parent so a single "CI" check gates every PR regardless of paths. on: - push: - branches: ["main"] - paths: - - src/** - - include/** - - client-sdk-rust/** - - CMakeLists.txt - - CMakePresets.json - - build.sh - - build.cmd - - vcpkg.json - - .token_helpers/** - - .github/workflows/tests.yml - pull_request: - branches: ["main"] - paths: - - src/** - - include/** - - client-sdk-rust/** - - CMakeLists.txt - - CMakePresets.json - - build.sh - - build.cmd - - vcpkg.json - - .token_helpers/** - - .github/workflows/tests.yml - workflow_dispatch: + workflow_call: {} + workflow_dispatch: {} permissions: contents: read @@ -36,12 +13,17 @@ permissions: env: CARGO_TERM_COLOR: always - # sccache caches rustc invocations across runs. RUSTC_WRAPPER is exported - # only after the setup step verifies the GHA cache backend is reachable, so - # transient cache backend failures fall back to uncached rustc instead of - # failing the build. - SCCACHE_GHA_ENABLED: "true" - # vcpkg binary caching for Windows (mirrors builds.yml) + # Disable Cargo incremental artifacts. The Rust FFI is built once per + # submodule SHA and cached whole (see the cargo target cache below), so + # incremental dirs add nothing but bloat the cached target/ directory and + # slow the cache upload/download. + CARGO_INCREMENTAL: "0" + # vcpkg binary caching for Windows (mirrors builds.yml). The x-gha backend + # was removed from vcpkg, so use vcpkg's files provider and persist that + # directory with actions/cache. + VCPKG_GIT_COMMIT: fb87e2bb3fe69e16c224989acb5a61349166c782 + VCPKG_BINARY_CACHE_DIR: ${{ github.workspace }}/.vcpkg-binary-cache + VCPKG_BINARY_SOURCES: "clear;files,${{ github.workspace }}/.vcpkg-binary-cache,readwrite" VCPKG_DEFAULT_TRIPLET: x64-windows-static-md VCPKG_DEFAULT_HOST_TRIPLET: x64-windows-static-md VCPKG_TARGET_TRIPLET: x64-windows-static-md @@ -86,20 +68,36 @@ jobs: - name: Pull LFS files run: git lfs pull - # ---------- vcpkg caching for Windows (mirrors builds.yml) ---------- - - name: Export GitHub Actions cache environment variables + # Cargo's freshness check is mtime-based. A fresh `actions/checkout` + # stamps every submodule source file with the checkout time, which is + # newer than the cached target/ artifacts — so cargo rebuilds the whole + # client-sdk-rust workspace (~6 min) even on an exact cargo-target cache + # hit. Pin all submodule source files to a fixed, deterministic + # timestamp (older than any cached artifact) so cargo treats them as + # unchanged across runs and reuses the cached FFI build. Runs before the + # cargo target cache is restored, so target/ does not yet exist and is + # never touched. shell: bash so this also runs under Git Bash on Windows. + - name: Stabilize Rust source mtimes for cargo freshness + shell: bash + run: | + find client-sdk-rust -type f -not -path '*/.git/*' -exec touch -t 202001010000 {} + + + # ---------- vcpkg for Windows (mirrors builds.yml) ---------- + - name: Restore vcpkg binary cache if: runner.os == 'Windows' - uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 + id: cache-vcpkg-binary + uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: - script: | - core.exportVariable('ACTIONS_CACHE_URL', process.env.ACTIONS_CACHE_URL || ''); - core.exportVariable('ACTIONS_RUNTIME_TOKEN', process.env.ACTIONS_RUNTIME_TOKEN || ''); + path: ${{ env.VCPKG_BINARY_CACHE_DIR }} + key: ${{ runner.os }}-${{ matrix.name }}-vcpkg-binary-${{ env.VCPKG_TARGET_TRIPLET }}-${{ env.VCPKG_GIT_COMMIT }}-${{ hashFiles('vcpkg.json') }} + restore-keys: | + ${{ runner.os }}-${{ matrix.name }}-vcpkg-binary-${{ env.VCPKG_TARGET_TRIPLET }}-${{ env.VCPKG_GIT_COMMIT }}- - name: Setup vcpkg (Windows only) if: runner.os == 'Windows' uses: lukka/run-vcpkg@6fe69898af670ac05f4a8427cc5cff4fb361cee5 # v11.5 with: - vcpkgGitCommitId: 'fb87e2bb3fe69e16c224989acb5a61349166c782' + vcpkgGitCommitId: ${{ env.VCPKG_GIT_COMMIT }} # ---------- OS-specific deps ---------- - name: Install deps (Ubuntu) @@ -137,21 +135,16 @@ jobs: if: matrix.name == 'macos-x64' run: rustup target add x86_64-apple-darwin - # ---------- Setup sccache ---------- - - name: Setup sccache - uses: mozilla-actions/sccache-action@054db53350805f83040bf3e6e9b8cf5a139aa7c9 # v0.0.7 - - - name: Enable sccache wrapping (probe first) + # ---------- Cache Cargo ---------- + # See builds.yml for the rationale: the Rust FFI output only changes with + # the client-sdk-rust submodule commit, so key the target cache on the + # submodule SHA. The build workflow owns saving this cache; tests are + # restore-only to avoid same-key save races across parallel jobs. + - name: Resolve Rust submodule SHA + id: rust_sha shell: bash - run: | - if sccache --start-server >/dev/null 2>&1; then - echo "RUSTC_WRAPPER=sccache" >> "$GITHUB_ENV" - echo "::notice::sccache enabled (RUSTC_WRAPPER=sccache)" - else - echo "::warning::sccache backend unreachable; building without compile cache this run" - fi + run: echo "sha=$(git -C client-sdk-rust rev-parse HEAD)" >> "$GITHUB_OUTPUT" - # ---------- Cache Cargo ---------- - name: Cache cargo registry uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: @@ -163,11 +156,12 @@ jobs: restore-keys: | ${{ runner.os }}-${{ matrix.name }}-cargo-registry- - - name: Cache cargo target - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 + - name: Restore cargo target + id: cache-cargo-target + uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: path: client-sdk-rust/target/ - key: ${{ runner.os }}-${{ matrix.name }}-cargo-target-${{ hashFiles('client-sdk-rust/Cargo.lock') }} + key: ${{ runner.os }}-${{ matrix.name }}-cargo-target-${{ steps.rust_sha.outputs.sha }} restore-keys: | ${{ runner.os }}-${{ matrix.name }}-cargo-target- @@ -175,10 +169,10 @@ jobs: - name: Set Linux build environment if: runner.os == 'Linux' run: | - echo "CXXFLAGS=-Wno-deprecated-declarations" >> $GITHUB_ENV - echo "CFLAGS=-Wno-deprecated-declarations" >> $GITHUB_ENV + echo "CXXFLAGS=-Wno-deprecated-declarations" >> "$GITHUB_ENV" + echo "CFLAGS=-Wno-deprecated-declarations" >> "$GITHUB_ENV" LLVM_VERSION=$(llvm-config --version | cut -d. -f1) - echo "LIBCLANG_PATH=/usr/lib/llvm-${LLVM_VERSION}/lib" >> $GITHUB_ENV + echo "LIBCLANG_PATH=/usr/lib/llvm-${LLVM_VERSION}/lib" >> "$GITHUB_ENV" # ---------- Build (release-tests: tests on, examples off) ---------- - name: Build tests (Unix) @@ -245,7 +239,7 @@ jobs: echo $! > livekit-server.pid # Port 7880 is a WebSocket endpoint, so a TCP-connect probe is the # most reliable readiness signal. - for i in $(seq 1 30); do + for _ in {1..30}; do if nc -z 127.0.0.1 7880 >/dev/null 2>&1; then echo "livekit-server is ready" exit 0 @@ -258,15 +252,24 @@ jobs: - name: Run integration tests if: matrix.e2e-testing - timeout-minutes: 5 + timeout-minutes: 45 shell: bash env: RUST_LOG: "metrics=debug" run: | set -euo pipefail source .token_helpers/set_data_track_test_tokens.bash - build-release/bin/livekit_integration_tests \ - --gtest_output=xml:build-release/integration-test-results.xml + # TMP: Mac crash debug - begin lldb wrapper + if [[ "$RUNNER_OS" == "macOS" ]]; then + lldb --batch \ + -o "run --gtest_repeat=10 --gtest_output=xml:build-release/integration-test-results.xml" \ + -o "thread backtrace all" \ + -- build-release/bin/livekit_integration_tests + else + build-release/bin/livekit_integration_tests \ + --gtest_output=xml:build-release/integration-test-results.xml + fi + # TMP: Mac crash debug - end lldb wrapper - name: Stop livekit-server if: always() && matrix.e2e-testing @@ -282,6 +285,27 @@ jobs: shell: bash run: tail -n 500 livekit-server.log || true + # TMP: Mac crash debug - begin crash report collection + - name: Collect macOS crash reports + if: failure() && runner.os == 'macOS' && matrix.e2e-testing + shell: bash + run: | + set -euxo pipefail + mkdir -p crash-reports + sleep 5 + cp -v "$HOME"/Library/Logs/DiagnosticReports/livekit_integration_tests*.crash crash-reports/ || true + cp -v /Library/Logs/DiagnosticReports/livekit_integration_tests*.crash crash-reports/ || true + + - name: Upload macOS crash reports + if: failure() && runner.os == 'macOS' && matrix.e2e-testing + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: macos-crash-reports-${{ matrix.name }} + path: crash-reports/** + if-no-files-found: ignore + retention-days: 7 + # TMP: Mac crash debug - end crash report collection + # ---------- Upload results ---------- - name: Upload test results if: always() @@ -303,6 +327,10 @@ jobs: coverage: name: Code Coverage runs-on: ubuntu-latest + # A debug build instrumented with --coverage is far heavier (RAM + disk) + # than the release builds. Cap the wall-clock so a stuck/OOM build fails + # fast and visibly instead of hanging toward the 6h default. + timeout-minutes: 45 steps: - name: Checkout (with submodules) @@ -314,6 +342,19 @@ jobs: - name: Pull LFS files run: git lfs pull + # Reclaim ~30GB on the runner. The debug+coverage object tree plus gcov + # data is large; prior runs died mid-build from disk/memory pressure. + - name: Free disk space + uses: jlumbroso/free-disk-space@54081f138730dfa15788a46383842cd2f914a1be # v1.3.1 + with: + tool-cache: false + android: true + dotnet: true + haskell: true + large-packages: true + docker-images: true + swap-storage: false + # ---------- OS deps ---------- - name: Install deps run: | @@ -338,21 +379,10 @@ jobs: with: toolchain: stable - # ---------- Setup sccache ---------- - - name: Setup sccache - uses: mozilla-actions/sccache-action@054db53350805f83040bf3e6e9b8cf5a139aa7c9 # v0.0.7 - - - name: Enable sccache wrapping (probe first) - shell: bash - run: | - if sccache --start-server >/dev/null 2>&1; then - echo "RUSTC_WRAPPER=sccache" >> "$GITHUB_ENV" - echo "::notice::sccache enabled (RUSTC_WRAPPER=sccache)" - else - echo "::warning::sccache backend unreachable; building without compile cache this run" - fi - # ---------- Cache Cargo ---------- + # Only the cargo registry (downloaded crate sources, ~60 MB) is cached + # here. The compiled target/ is intentionally not cached for coverage — + # see the note below the registry cache step. - name: Cache cargo registry uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 with: @@ -364,21 +394,22 @@ jobs: restore-keys: | ${{ runner.os }}-coverage-cargo-registry- - - name: Cache cargo target - uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5 - with: - path: client-sdk-rust/target/ - key: ${{ runner.os }}-coverage-cargo-target-${{ hashFiles('client-sdk-rust/Cargo.lock') }} - restore-keys: | - ${{ runner.os }}-coverage-cargo-target- + # NOTE: we deliberately do NOT cache client-sdk-rust/target/ here. The + # coverage job builds the FFI in debug mode, so its target/ was ~2.8 GB — + # the single largest entry in the repo's 10 GB Actions cache budget. That + # one cache crowded out the release build/test caches (and the Windows + # vcpkg binaries), causing repo-wide LRU eviction and cold rebuilds + # elsewhere. Coverage runs once per PR off the critical path, so eating a + # cold FFI build here is cheaper than the eviction it caused. The cargo + # registry cache above is tiny (~60 MB) and stays. # ---------- Build environment setup ---------- - name: Set build environment run: | LLVM_VERSION=$(llvm-config --version | cut -d. -f1) - echo "LIBCLANG_PATH=/usr/lib/llvm-${LLVM_VERSION}/lib" >> $GITHUB_ENV + echo "LIBCLANG_PATH=/usr/lib/llvm-${LLVM_VERSION}/lib" >> "$GITHUB_ENV" GCC_VER=$(gcc -dumpversion | cut -d. -f1) - echo "GCOV_EXECUTABLE=gcov-${GCC_VER}" >> $GITHUB_ENV + echo "GCOV_EXECUTABLE=gcov-${GCC_VER}" >> "$GITHUB_ENV" # ---------- Configure with upstream preset + coverage flag overrides ---------- - name: Configure (linux-debug-tests preset + coverage flags) @@ -389,8 +420,13 @@ jobs: -DCMAKE_EXE_LINKER_FLAGS="--coverage" \ -DCMAKE_SHARED_LINKER_FLAGS="--coverage" + # Cap parallelism: a debug build with --coverage instrumentation has a + # much larger per-TU memory footprint, and unbounded --parallel (one job + # per core) is what OOM-killed prior runs (failure surfaced only as an + # abandoned "Build" step). 2 keeps peak RAM in check on the standard + # runner; bump if/when this moves to a larger runner. - name: Build - run: cmake --build build-debug --parallel + run: cmake --build build-debug --parallel 2 # ---------- Run unit tests ---------- - name: Run unit tests @@ -399,6 +435,16 @@ jobs: build-debug/bin/livekit_unit_tests \ --gtest_output=xml:build-debug/unit-test-results.xml + # Make resource-exhaustion failures visible instead of silent. Runs only + # if an earlier step failed (e.g. OOM during Build). + - name: Diagnostics on failure + if: failure() + run: | + echo "===== disk ====="; df -h || true + echo "===== memory ====="; free -h || true + echo "===== dmesg (OOM killer) =====" + sudo dmesg 2>/dev/null | grep -iE 'killed process|out of memory|oom' | tail -20 || true + # ---------- Generate coverage reports ---------- - name: Generate coverage reports run: | @@ -438,7 +484,3 @@ jobs: path: coverage-html/ retention-days: 14 - - name: Upload coverage to Codecov - uses: getsentry/codecov-action@03112cc3b486a3397dc8d17a58680008721fc86f # v0.3.7 - with: - token: ${{ secrets.GITHUB_TOKEN }} diff --git a/AGENTS.md b/AGENTS.md index e234ec3a..f9892be1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -373,3 +373,38 @@ When adding new client facing functionality, add benchmarking to understand the - A single participant cannot subscribe to its own tracks as "remote." Testing sender/receiver requires two separate room connections with distinct identities. - macOS dylibs require `install_name_tool` fixups for `@rpath` — the CMakeLists.txt handles this automatically. Do not manually adjust RPATH unless you understand the implications. - When consuming the installed SDK, use `-DLIVEKIT_LOCAL_SDK_DIR=/path/to/sdk` to point cmake at a local install instead of downloading a release tarball. + +### CI Workflow Structure + +`ci.yml` is the PR-review aggregator. It computes path changes once with +`dorny/paths-filter` and conditionally calls reusable workflows for the +expensive stages. Manual `workflow_dispatch` runs intentionally opt back into +all filtered stages; normal pull requests and pushes use the path filters. + +- `.github/workflows/ci.yml` — Top-level PR/push/manual aggregator and path + filter owner. +- `.github/workflows/builds.yml` — Reusable SDK and example-collection build + matrix. +- `.github/workflows/tests.yml` — Reusable unit/integration test matrix. +- `.github/workflows/quality-checks.yml` — Reusable `clang-format` and + `clang-tidy` checks. +- `.github/workflows/generate-docs.yml` — Reusable Doxygen docs validation. +- `.github/workflows/license_check.yml` — Cheap license check, run on every CI + invocation. +- `.github/workflows/pin_check.yml` — Cheap action pin check, run on every CI + invocation. +- `.github/workflows/docker-images.yml` — Docker image build/publish workflow, + outside PR-review aggregation. +- `.github/workflows/docker-validate.yml` — Docker image validation workflow, + outside PR-review aggregation. + +When adding or renaming files that affect a CI stage, update the matching +`ci.yml` `changes` filter in the same PR. For example, new build scripts, +CMake files, package manifests, or reusable build workflows should be added to +the `builds` filter; test-only helpers to `tests`; formatting/static-analysis +configuration to `quality`; and docs generation inputs to `docs`. + +Keep broad agent guidance files such as `AGENTS.md` out of the expensive +`builds`, `tests`, `quality`, and `docs` filters unless they start affecting +generated docs or build artifacts. An `AGENTS.md`-only change should not trigger +those stages; only the always-on cheap checks should run. diff --git a/build.cmd b/build.cmd index 76c1ac57..1598dbbc 100644 --- a/build.cmd +++ b/build.cmd @@ -202,6 +202,7 @@ echo build.cmd clean-all goto :eof :configure_build +call :now _T_CONFIG_START echo ==^> Configuring CMake (%BUILD_TYPE%)... if not defined VCPKG_ROOT ( echo Warning: VCPKG_ROOT is not set. Attempting to configure without vcpkg... @@ -213,6 +214,7 @@ if errorlevel 1 ( echo Configuration failed! exit /b 1 ) +call :elapsed "configure (%PRESET%)" %_T_CONFIG_START% goto build_only :build_only @@ -225,15 +227,45 @@ if not defined BUILD_PARALLEL_JOBS ( set "BUILD_PARALLEL_JOBS=2" ) ) +call :now _T_BUILD_START echo ==^> Building (%BUILD_TYPE%) with %BUILD_PARALLEL_JOBS% parallel jobs... + +rem Optional Rust-FFI-first split: build the build_rust_ffi target on its own +rem first so CI logs report the Rust dep/FFI compile time separately from the +rem C++ compile time. Off by default (single build invocation). +if "%LK_BUILD_TIMING%"=="1" ( + call :now _T_FFI_START + echo ==^> [timing] Building Rust FFI target ^(build_rust_ffi^) first... + cmake --build "%BUILD_DIR%" --config %BUILD_TYPE% --parallel "%BUILD_PARALLEL_JOBS%" --target build_rust_ffi + if errorlevel 1 ( + echo Build failed! + exit /b 1 + ) + call :elapsed "build: Rust FFI (build_rust_ffi)" %_T_FFI_START% +) + cmake --build "%BUILD_DIR%" --config %BUILD_TYPE% --parallel "%BUILD_PARALLEL_JOBS%" if errorlevel 1 ( echo Build failed! exit /b 1 ) +call :elapsed "build total (%PRESET%)" %_T_BUILD_START% echo ==^> Build complete! goto :eof +rem ---- timing helpers ---- +rem :now -> sets to current Unix epoch seconds. +:now +for /f %%s in ('powershell -NoProfile -Command "[int][double]::Parse((Get-Date -UFormat %%s))"') do set "%~1=%%s" +goto :eof + +rem :elapsed "