Merge pull request #35 from zero-objects/fix/issue27-multilocator-dis… #178
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: | |
| env: | |
| CARGO_TERM_COLOR: always | |
| CARGO_INCREMENTAL: "0" | |
| RUSTFLAGS: "-D warnings" | |
| jobs: | |
| # --------------------------------------------------------------------------- | |
| # Lint & format — must pass before anything else runs. | |
| # Maps to docs/architecture/04_safety_by_architecture.md §3.2. | |
| # --------------------------------------------------------------------------- | |
| fmt: | |
| name: rustfmt | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: rustfmt | |
| - run: cargo fmt --all -- --check | |
| clippy: | |
| name: clippy | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: clippy | |
| - uses: Swatinem/rust-cache@v2 | |
| # NOTE: no `--all-features` here. `--all-features` activates the opt-in | |
| # `wolfcrypt` backend, whose `wolfcrypt-sys` build needs libwolfssl / | |
| # WOLFSSL_SRC — not present on the hosted GitHub runner (it panics: | |
| # "required wolfcrypt source not found"). wolfCrypt is an opt-in, | |
| # GPL-3.0/wolfSSL-commercial backend; the FULL `--all-features` clippy | |
| # (including wolfcrypt, aws-lc, fips) runs on the GitLab CI, whose ci-rust | |
| # image ships libwolfssl. This public mirror lints default features | |
| # (ring backend) + all targets, which is green without any system lib. | |
| - run: cargo clippy --workspace --all-targets -- -D warnings | |
| deny: | |
| name: cargo-deny (licenses, advisories, bans) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| # rust-toolchain.toml pins 1.88.0; the cargo-deny-action Docker image | |
| # only has 1.85.0-musl pre-installed. The rust-version input forces | |
| # the action to rustup-install the pinned version before cargo-deny. | |
| - uses: EmbarkStudios/cargo-deny-action@v2 | |
| with: | |
| command: check | |
| rust-version: "1.88.0" | |
| # --------------------------------------------------------------------------- | |
| # jscpd — copy/paste-detection gate (catches code duplication). | |
| # | |
| # Why: a duplicate C# `ExtensibilityKind` enum slipped in and only surfaced | |
| # at a build break. jscpd is language-agnostic (Rust, C#, Java, Kotlin, TS, | |
| # Go, Zig, …) so it covers the WHOLE codebase, not just the Rust crates. | |
| # | |
| # Config lives in `.jscpd.json` at the repo root — `minTokens` (50), the | |
| # `ignore` globs (build/generated output, content mirrors like docs/website, | |
| # the release mirror, and intentional teaching duplication under | |
| # examples/tutorials), and the `threshold`: the max duplicated-LINES % over | |
| # all scanned files. The threshold (8.5) sits ~0.5pp above the measured | |
| # cleaned baseline (8.01% lines on main, 2026-07), so the gate is GREEN | |
| # today but trips on new large-scale copy-paste (a duplicated file / module | |
| # / enum block — the ExtensibilityKind failure class). It is a RATCHET: | |
| # lower it as the known real clones (crates/idl-* cross-backend emitters, | |
| # the coap/mqtt/websocket bridge daemons, crates/ts-node ↔ crates/ts-wasm | |
| # cdr code) get de-duplicated. Do NOT raise it to paper over new duplication. | |
| # | |
| # To whitelist a legitimate clone: add a narrow glob to `.jscpd.json` | |
| # `ignore`, or wrap the block in `jscpd:ignore-start` / `jscpd:ignore-end` | |
| # comments. `.jscpd.json` is auto-discovered; its `threshold` reporter exits | |
| # non-zero when duplication% exceeds the threshold. | |
| # | |
| # This job MUST stay in sync with the `jscpd` job in .gitlab-ci.yml (the | |
| # authoritative root/GitLab CI) — otherwise the mirror sync re-diverges the | |
| # gate. | |
| # --------------------------------------------------------------------------- | |
| jscpd: | |
| name: jscpd (copy/paste detection) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-node@v4 | |
| with: | |
| node-version: "22" | |
| - run: npx --yes jscpd@5 . | |
| # --------------------------------------------------------------------------- | |
| # cpd — the SECOND, token-based copy/paste gate (PMD CPD), run alongside the | |
| # line-based `jscpd` job above. Two independent detectors on purpose: jscpd | |
| # tokenizes by lines, PMD CPD by language tokens, so each catches clones the | |
| # other misses (notably small same-language clones — the C# | |
| # `ExtensibilityKind` class — that a repo-wide line-% budget does not fail | |
| # on). | |
| # | |
| # All logic (per-language minimum-tokens + committed baselines, the shared | |
| # exclude list mirroring .jscpd.json, and the PMD download) lives in ONE | |
| # script, scripts/cpd-gate.sh, called identically here and in the GitLab CI | |
| # so the gate can't drift. PMD 7.x is a JVM tool → setup-java; the script | |
| # fetches pmd-dist at runtime (never committed). To re-baseline: | |
| # `scripts/cpd-gate.sh --update-baseline` and copy the numbers into the file. | |
| # | |
| # This job MUST stay in sync with the `cpd` job in .gitlab-ci.yml (the | |
| # authoritative root/GitLab CI) — otherwise the mirror sync re-diverges it. | |
| # --------------------------------------------------------------------------- | |
| cpd: | |
| name: cpd (token-based copy/paste detection) | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: actions/setup-java@v4 | |
| with: | |
| distribution: temurin | |
| java-version: "21" | |
| - run: bash scripts/cpd-gate.sh | |
| # --------------------------------------------------------------------------- | |
| # Build & test matrix — Full profile on Linux x86_64 and ARM64. | |
| # Phase-0 scope per docs/architecture/06_roadmap.md §3. | |
| # Windows, macOS, QNX, and embedded targets land with later phases. | |
| # --------------------------------------------------------------------------- | |
| build-test: | |
| name: build & test (${{ matrix.target }}) | |
| needs: [fmt, clippy] | |
| runs-on: ${{ matrix.runner }} | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - target: x86_64-unknown-linux-gnu | |
| runner: ubuntu-latest | |
| cross: false | |
| - target: aarch64-unknown-linux-gnu | |
| runner: ubuntu-latest | |
| cross: true | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: ${{ matrix.target }} | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Install cross | |
| if: matrix.cross | |
| run: cargo install cross --locked | |
| - name: Build | |
| run: | | |
| if [ "${{ matrix.cross }}" = "true" ]; then | |
| # Exclude iceoryx2-oracle-consumer from the cross build: it is a | |
| # publish=false, x86_64-Linux-only oracle tool that hard-depends on | |
| # the upstream iceoryx2 crate, whose iceoryx2-pal-posix runs bindgen | |
| # and fails to cross-compile for aarch64 (clang can't find stddef.h | |
| # in the cross sysroot). Not part of the shipped library and | |
| # meaningless on an aarch64 embedded target. | |
| cross build --workspace --exclude iceoryx2-oracle-consumer --target ${{ matrix.target }} | |
| else | |
| cargo build --workspace --target ${{ matrix.target }} | |
| fi | |
| - name: Test (non-DCPS workspace, parallel) | |
| if: ${{ !matrix.cross }} | |
| run: cargo test --workspace --exclude zerodds-dcps --target ${{ matrix.target }} | |
| - name: Test (DCPS, serial — UDP multicast tests share one multicast group per binary) | |
| if: ${{ !matrix.cross }} | |
| run: cargo test -p zerodds-dcps --target ${{ matrix.target }} -- --test-threads=1 | |
| # --------------------------------------------------------------------------- | |
| # tsn-live — live AF_PACKET transport (DDS-TSN 1.0 Annex A, EtherType | |
| # 0x88B5). The workspace test job builds WITHOUT the transport-tsn | |
| # `live` feature, so socket.rs (target_os=linux) and its frame logic | |
| # are otherwise never compiled/run. GitHub ubuntu runners allow | |
| # `sudo ip link add` (veth) + AF_PACKET, so unlike the internal GitLab | |
| # runner the real veth RTPS round trip executes here. See | |
| # internal/ci/tsn-live.md. | |
| # --------------------------------------------------------------------------- | |
| tsn-live: | |
| name: TSN live AF_PACKET transport | |
| needs: [fmt, clippy] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: dtolnay/rust-toolchain@stable | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Build socket.rs + run live_frame unit tests | |
| run: cargo test -p zerodds-transport-tsn --features live | |
| - name: Real RTPS round trip over a veth pair (needs root) | |
| run: | | |
| sudo -E "$(command -v cargo)" test -p zerodds-transport-tsn \ | |
| --features live --test veth_loopback -- --ignored --test-threads=1 | |
| # --------------------------------------------------------------------------- | |
| # No-std build for the Safe-Subset crates. | |
| # Verifies the Safe-Subset contract from | |
| # docs/architecture/04_safety_by_architecture.md §2. | |
| # Scope widens as Safe-Subset crates gain real content. | |
| # --------------------------------------------------------------------------- | |
| no-std: | |
| name: no_std build (safe subset) | |
| needs: [fmt, clippy] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| targets: thumbv7em-none-eabihf | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Build safe-subset crates for bare-metal | |
| run: | | |
| cargo build --target thumbv7em-none-eabihf \ | |
| -p zerodds-foundation \ | |
| -p zerodds-cdr \ | |
| -p zerodds-types \ | |
| -p zerodds-qos \ | |
| -p zerodds-rtps \ | |
| -p zerodds-discovery \ | |
| -p zerodds-transport \ | |
| -p zerodds-xrce-client \ | |
| --no-default-features | |
| # --------------------------------------------------------------------------- | |
| # Coverage — cargo-llvm-cov, line/region/function coverage. | |
| # Branch coverage requires nightly Rust and will be added later as a separate | |
| # nightly job. Target bar: 99% (soft gate, no merge block | |
| # during the bootstrap era, see memory/project_quality_bar_branch_coverage). | |
| # --------------------------------------------------------------------------- | |
| coverage: | |
| name: coverage (cargo-llvm-cov) | |
| needs: [fmt, clippy] | |
| runs-on: ubuntu-latest | |
| steps: | |
| - uses: actions/checkout@v7 | |
| - uses: dtolnay/rust-toolchain@stable | |
| with: | |
| components: llvm-tools-preview | |
| - uses: Swatinem/rust-cache@v2 | |
| - name: Install cargo-llvm-cov | |
| run: cargo install cargo-llvm-cov --version 0.6.21 --locked | |
| - name: Run coverage | |
| # `--lib --bins`: measures only library and binary code paths | |
| # (unit tests in the crates themselves). Integration tests | |
| # (`tests/*.rs`) are end-to-end discovery tests and primarily | |
| # yield line coverage, hardly any branch coverage. They also | |
| # have E2E timing dependencies under cov instrumentation | |
| # (see docs/timing-architecture-audit.md prio 4). | |
| # build-test x86_64 + aarch64 still run the integration tests | |
| # — coverage measures code, build-test measures behavior. | |
| run: cargo llvm-cov --workspace --lib --bins --lcov --output-path lcov.info | |
| - name: Coverage summary | |
| run: cargo llvm-cov --workspace --lib --bins --summary-only | |
| - name: Upload lcov artifact | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: lcov | |
| path: lcov.info | |
| retention-days: 30 |