Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 87 additions & 71 deletions .github/workflows/builds.yml
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -50,27 +13,24 @@ 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"
# 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"
# 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
# vcpkg binary caching for Windows. x-gha stores compiled vcpkg packages
# (protobuf, abseil, spdlog, ...) in the GitHub Actions cache, so the
# Windows manifest-mode dep build is skipped on a warm cache. `clear`
# drops the default (source-only) provider first. Requires the
# ACTIONS_CACHE_URL / ACTIONS_RUNTIME_TOKEN export step below.
VCPKG_BINARY_SOURCES: "clear;x-gha,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
Expand Down Expand Up @@ -111,6 +71,20 @@ jobs:
- name: Pull LFS files
run: git lfs pull

# 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 caching for Windows ----------
- name: Export GitHub Actions cache environment variables
if: runner.os == 'Windows'
Expand Down Expand Up @@ -161,21 +135,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:
Expand All @@ -187,11 +157,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-

Expand All @@ -217,6 +193,18 @@ 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 }}

# ---------- 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.
Expand Down Expand Up @@ -506,6 +494,20 @@ jobs:
if: github.event_name == 'pull_request'

steps:
# 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:
Expand Down Expand Up @@ -533,6 +535,20 @@ jobs:
if: github.event_name == 'pull_request'

steps:
# 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:
Expand Down
162 changes: 162 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
name: CI

# Aggregator workflow that fans out to every PR-gating workflow as a single,
# always-running check. Configure branch protection to require only the "CI"
# status; downstream workflows will run automatically. This avoids the
# previous footgun where path-filtered workflows skipped entire PRs (so all
# checks showed "passing" without ever executing — see #147).
#
# Each child workflow is conditionally invoked based on the paths a PR
# touched, mirroring the path filters that used to live in each child.
# Children that get skipped via `if:` count as "skipped" in the CI rollup
# (not "failed"), so the parent "CI" status reaches SUCCESS and branch
# protection is satisfied. Push-to-main and manual dispatch always run
# everything regardless of changed paths.

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 non-PR events 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 }}
docker_images: ${{ steps.filter.outputs.docker_images }}
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/**
- client-sdk-rust/**
- cmake/**
- docker/**
- scripts/clang-format.sh
- scripts/clang-tidy.sh
- CMakeLists.txt
- CMakePresets.json
- build.sh
- build.cmd
- build.h.in
- .build-info.json.in
- vcpkg.json
- .clang-format
- .clang-tidy
- .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
docker_images:
- src/**
- include/**
- client-sdk-rust/**
- cmake/**
- data/**
- docker/Dockerfile.base
- docker/Dockerfile.sdk
- CMakeLists.txt
- CMakePresets.json
- build.sh
- build.cmd
- build.h.in
- .build-info.json.in
- .github/workflows/ci.yml
- .github/workflows/docker-images.yml
- .github/workflows/docker-validate.yml

builds:
name: Builds
needs: changes
if: ${{ needs.changes.outputs.builds == 'true' || github.event_name != 'pull_request' }}
uses: ./.github/workflows/builds.yml
secrets: inherit

tests:
name: Tests
needs: changes
if: ${{ needs.changes.outputs.tests == 'true' || github.event_name != 'pull_request' }}
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

generate-docs:
name: Generate Docs
needs: changes
if: ${{ needs.changes.outputs.docs == 'true' || github.event_name != 'pull_request' }}
uses: ./.github/workflows/generate-docs.yml

docker-images:
name: Docker Images
needs: changes
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && needs.changes.outputs.docker_images == 'true' }}
permissions:
contents: read
packages: write
uses: ./.github/workflows/docker-images.yml
secrets: inherit

docker-validate:
name: Docker Validate
needs: docker-images
if: ${{ needs.docker-images.result == 'success' }}
permissions:
contents: read
packages: read
uses: ./.github/workflows/docker-validate.yml
secrets: inherit
Loading
Loading