feat(fe): add React ground system UI and demo telemetry injector #74
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
| # SAKURA-II PR-gate CI | |
| # Spec: docs/dev/ci-workflow.md | |
| # Triggers: pull_request (all branches), push to master, workflow_dispatch | |
| name: CI | |
| on: | |
| pull_request: | |
| push: | |
| branches: [master] | |
| workflow_dispatch: | |
| concurrency: | |
| group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| defaults: | |
| run: | |
| shell: bash | |
| jobs: | |
| # ────────────────────────────────────────────────────────────────────────── | |
| # Path-change detection — PR-only gate that drives conditional jobs below. | |
| # | |
| # Root cause of the previous always-skip bug: | |
| # github.event.pull_request.changed_files is an integer count, not a list. | |
| # contains(toJson(<int>), 'rust/') is always false → every conditional | |
| # job was permanently skipped on pull_request events. | |
| # | |
| # Fix: dorny/paths-filter fetches the actual changed-file list via the | |
| # GitHub API (no checkout needed for PR events). Non-PR events skip this | |
| # job; downstream jobs use always() to override skip-propagation and | |
| # short-circuit with github.event_name != 'pull_request'. | |
| # ────────────────────────────────────────────────────────────────────────── | |
| changes: | |
| name: detect-changes | |
| runs-on: ubuntu-22.04 | |
| if: github.event_name == 'pull_request' | |
| permissions: | |
| pull-requests: read | |
| outputs: | |
| cfs: ${{ steps.f.outputs.cfs }} | |
| ros2: ${{ steps.f.outputs.ros2 }} | |
| rust: ${{ steps.f.outputs.rust }} | |
| apps: ${{ steps.f.outputs.apps }} | |
| traceability: ${{ steps.f.outputs.traceability }} | |
| docs: ${{ steps.f.outputs.docs }} | |
| puml: ${{ steps.f.outputs.puml }} | |
| steps: | |
| - uses: dorny/paths-filter@v3 | |
| id: f | |
| with: | |
| filters: | | |
| cfs: | |
| - 'apps/**' | |
| - '_defs/**' | |
| - 'CMakeLists.txt' | |
| ros2: | |
| - 'ros2_ws/**' | |
| rust: | |
| - 'rust/**' | |
| - 'Cargo.toml' | |
| - 'Cargo.lock' | |
| apps: | |
| - 'apps/**' | |
| traceability: | |
| - 'docs/mission/requirements/**' | |
| - 'docs/mission/verification/V&V-Plan.md' | |
| docs: | |
| - 'docs/**' | |
| - 'README.md' | |
| puml: | |
| - '**/*.puml' | |
| # ────────────────────────────────────────────────────────────────────────── | |
| # 2.1 cfs-ctest — SYS-REQ-0070 | |
| # ────────────────────────────────────────────────────────────────────────── | |
| cfs-ctest: | |
| name: cfs-ctest | |
| runs-on: ubuntu-22.04 | |
| needs: [changes] | |
| if: | | |
| always() && | |
| (github.event_name != 'pull_request' || | |
| needs.changes.outputs.cfs == 'true') | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Cache cFS build | |
| uses: actions/cache@v4 | |
| with: | |
| path: build/ | |
| key: ${{ runner.os }}-cfs-${{ hashFiles('apps/**/CMakeLists.txt', '_defs/**') }} | |
| restore-keys: ${{ runner.os }}-cfs- | |
| - name: Install cmake and build tools | |
| run: | | |
| sudo apt-get update -q | |
| sudo apt-get install -y --no-install-recommends cmake ninja-build gcc g++ libcmocka-dev | |
| - name: Configure | |
| run: cmake -B build -DCMAKE_BUILD_TYPE=Debug | |
| - name: Build | |
| run: cmake --build build | |
| - name: Test | |
| run: ctest --test-dir build --output-on-failure | |
| # ────────────────────────────────────────────────────────────────────────── | |
| # 2.2 ros2-colcon — V&V-Plan §2.1 | |
| # ────────────────────────────────────────────────────────────────────────── | |
| ros2-colcon: | |
| name: ros2-colcon | |
| runs-on: ubuntu-22.04 | |
| needs: [changes] | |
| if: | | |
| always() && | |
| (github.event_name != 'pull_request' || | |
| needs.changes.outputs.ros2 == 'true') | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Cache colcon build | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ros2_ws/build | |
| ros2_ws/install | |
| key: ${{ runner.os }}-colcon-${{ hashFiles('ros2_ws/**/package.xml') }} | |
| restore-keys: ${{ runner.os }}-colcon- | |
| - name: Build and test (Space ROS container) | |
| uses: docker/build-push-action@v5 | |
| with: | |
| context: . | |
| file: .ci/ros2.Dockerfile | |
| push: false | |
| tags: sakura-ci/ros2:local | |
| - name: Run colcon build and test | |
| run: | | |
| docker run --rm \ | |
| -v "${{ github.workspace }}/ros2_ws:/workspace/ros2_ws" \ | |
| sakura-ci/ros2:local \ | |
| bash -c " | |
| source /opt/ros/spaceros/setup.bash && | |
| cd /workspace && | |
| colcon build --base-paths ros2_ws/src --symlink-install && | |
| colcon test --base-paths ros2_ws/src && | |
| colcon test-result --verbose | |
| " | |
| # ────────────────────────────────────────────────────────────────────────── | |
| # 2.3 rust-cargo — SYS-REQ-0071, SYS-REQ-0073, V&V-Plan §5.2 | |
| # ────────────────────────────────────────────────────────────────────────── | |
| rust-cargo: | |
| name: rust-cargo | |
| runs-on: ubuntu-22.04 | |
| needs: [changes] | |
| if: | | |
| always() && | |
| (github.event_name != 'pull_request' || | |
| needs.changes.outputs.rust == 'true') | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install Rust toolchain | |
| uses: dtolnay/rust-toolchain@stable | |
| - name: Cache Cargo registry | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.cargo/registry | |
| ~/.cargo/git | |
| key: ${{ runner.os }}-cargo-${{ hashFiles('rust/Cargo.lock') }} | |
| restore-keys: ${{ runner.os }}-cargo- | |
| - name: Cache Cargo target dir | |
| uses: actions/cache@v4 | |
| with: | |
| path: rust/target | |
| key: ${{ runner.os }}-cargo-target-${{ hashFiles('rust/Cargo.lock') }}-${{ hashFiles('rust/**/*.rs') }} | |
| restore-keys: ${{ runner.os }}-cargo-target- | |
| - name: Install cargo-audit | |
| run: cargo install cargo-audit --locked | |
| - name: cargo test | |
| run: cargo test --workspace --all-features | |
| - name: cargo clippy | |
| run: cargo clippy --workspace --all-targets -- -D warnings | |
| - name: cargo audit | |
| run: cargo audit --deny warnings | |
| - name: Q-C8 grep guards | |
| run: bash scripts/grep-lints.sh | |
| # ────────────────────────────────────────────────────────────────────────── | |
| # 2.3b cfs-runtime — Phase C: cFE shared-library build + startup-script check | |
| # | |
| # Runs only when the cFE submodule is initialized (cfs/cFE/CMakeLists.txt | |
| # present). On the main branch the submodule is expected; on feature branches | |
| # it is optional — the job auto-skips when the submodule is absent so that | |
| # Phases 38/39/B/D branches are unaffected. | |
| # ────────────────────────────────────────────────────────────────────────── | |
| cfs-runtime: | |
| name: cfs-runtime | |
| runs-on: ubuntu-22.04 | |
| needs: [changes] | |
| if: | | |
| always() && | |
| (github.event_name != 'pull_request' || | |
| needs.changes.outputs.cfs == 'true') | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| submodules: recursive | |
| - name: Check if cFE submodule is initialized | |
| id: cfe-present | |
| run: | | |
| if [ -f "cfs/cFE/CMakeLists.txt" ]; then | |
| echo "present=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "present=false" >> $GITHUB_OUTPUT | |
| echo "cfs/cFE submodule not initialized — skipping cfs-runtime build" | |
| fi | |
| - name: Install build deps | |
| if: steps.cfe-present.outputs.present == 'true' | |
| run: | | |
| sudo apt-get update -q | |
| sudo apt-get install -y --no-install-recommends \ | |
| cmake ninja-build gcc g++ libcmocka-dev python3 | |
| - name: Configure (SAKURA_CFS_RUNTIME=ON) | |
| if: steps.cfe-present.outputs.present == 'true' | |
| run: cmake -B build_cfs -DCMAKE_BUILD_TYPE=Debug -DSAKURA_CFS_RUNTIME=ON | |
| - name: Build shared libs | |
| if: steps.cfe-present.outputs.present == 'true' | |
| run: cmake --build build_cfs | |
| - name: Verify startup script lists all 9 apps | |
| if: steps.cfe-present.outputs.present == 'true' | |
| run: | | |
| count=$(grep -c '^CFE_APP' cpu1/startup_scripts/cfe_es_startup.scr) | |
| echo "Startup script entries: $count" | |
| [ "$count" -eq 9 ] || (echo "ERROR: expected 9 CFE_APP entries" && exit 1) | |
| - name: Smoke-check shared libs exist | |
| if: steps.cfe-present.outputs.present == 'true' | |
| run: | | |
| for app in sample_app orbiter_cdh orbiter_adcs orbiter_comm \ | |
| orbiter_power orbiter_payload \ | |
| mcu_eps_gw mcu_rwa_gw mcu_payload_gw; do | |
| lib="$(find build_cfs -name lib${app}.so 2>/dev/null | head -1)" | |
| if [ -z "$lib" ]; then | |
| echo "ERROR: lib${app}.so not found in build_cfs" | |
| exit 1 | |
| fi | |
| echo "OK: $lib" | |
| done | |
| # ────────────────────────────────────────────────────────────────────────── | |
| # 2.4 cppcheck — SYS-REQ-0072 | |
| # ────────────────────────────────────────────────────────────────────────── | |
| cppcheck: | |
| name: cppcheck | |
| runs-on: ubuntu-22.04 | |
| needs: [changes] | |
| if: | | |
| always() && | |
| (github.event_name != 'pull_request' || | |
| needs.changes.outputs.apps == 'true') | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install cppcheck | |
| run: | | |
| sudo apt-get update -q | |
| sudo apt-get install -y --no-install-recommends cppcheck | |
| - name: Run cppcheck | |
| run: cppcheck --enable=all --std=c11 --error-exitcode=1 apps/ | |
| # ────────────────────────────────────────────────────────────────────────── | |
| # 2.5 traceability-lint — SYS-REQ-0080 | |
| # ────────────────────────────────────────────────────────────────────────── | |
| traceability-lint: | |
| name: traceability-lint | |
| runs-on: ubuntu-22.04 | |
| needs: [changes] | |
| if: | | |
| always() && | |
| (github.event_name != 'pull_request' || | |
| needs.changes.outputs.traceability == 'true') | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Run traceability-lint | |
| run: python3 scripts/traceability-lint.py --repo-root . | |
| # ────────────────────────────────────────────────────────────────────────── | |
| # 2.6 apid-mid-lint — apid-registry change control (always runs) | |
| # ────────────────────────────────────────────────────────────────────────── | |
| apid-mid-lint: | |
| name: apid-mid-lint | |
| runs-on: ubuntu-22.04 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Run apid-mid-lint | |
| run: python3 scripts/apid_mid_lint.py --repo-root . | |
| # ────────────────────────────────────────────────────────────────────────── | |
| # 2.7 citation-lint — references.md preamble | |
| # ────────────────────────────────────────────────────────────────────────── | |
| citation-lint: | |
| name: citation-lint | |
| runs-on: ubuntu-22.04 | |
| needs: [changes] | |
| if: | | |
| always() && | |
| (github.event_name != 'pull_request' || | |
| needs.changes.outputs.docs == 'true') | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Run citation-lint | |
| run: python3 scripts/citation_lint.py --repo-root . | |
| # ────────────────────────────────────────────────────────────────────────── | |
| # 2.8 link-check — V&V-Plan §7.2 | |
| # ────────────────────────────────────────────────────────────────────────── | |
| link-check: | |
| name: link-check | |
| runs-on: ubuntu-22.04 | |
| needs: [changes] | |
| if: | | |
| always() && | |
| (github.event_name != 'pull_request' || | |
| needs.changes.outputs.docs == 'true') | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Cache Node tooling | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.npm | |
| .ci/node_modules | |
| key: ${{ runner.os }}-node-${{ hashFiles('.ci/package-lock.json') }} | |
| restore-keys: ${{ runner.os }}-node- | |
| - name: Install Node tooling | |
| run: cd .ci && npm ci | |
| - name: Run markdown-link-check | |
| run: | | |
| find docs -name "*.md" -print0 | \ | |
| xargs -0 -I{} .ci/node_modules/.bin/markdown-link-check \ | |
| --config .ci/markdown-link-check.json {} | |
| # ────────────────────────────────────────────────────────────────────────── | |
| # 2.9 plantuml-parse — V&V-Plan §7.2 | |
| # ────────────────────────────────────────────────────────────────────────── | |
| plantuml-parse: | |
| name: plantuml-parse | |
| runs-on: ubuntu-22.04 | |
| needs: [changes] | |
| if: | | |
| always() && | |
| (github.event_name != 'pull_request' || | |
| needs.changes.outputs.puml == 'true') | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Install PlantUML | |
| run: | | |
| sudo apt-get update -q | |
| sudo apt-get install -y --no-install-recommends plantuml | |
| - name: Parse PlantUML diagrams | |
| run: | | |
| if compgen -G "docs/architecture/diagrams/*.puml" > /dev/null; then | |
| plantuml -DRELATIVE_INCLUDE="." -checkonly docs/architecture/diagrams/*.puml | |
| else | |
| echo "plantuml-parse: no .puml files found — skipping." | |
| fi | |
| # ────────────────────────────────────────────────────────────────────────── | |
| # 2.10 mermaid-parse — V&V-Plan §7.2 | |
| # ────────────────────────────────────────────────────────────────────────── | |
| mermaid-parse: | |
| name: mermaid-parse | |
| runs-on: ubuntu-22.04 | |
| needs: [changes] | |
| if: | | |
| always() && | |
| (github.event_name != 'pull_request' || | |
| needs.changes.outputs.docs == 'true') | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Cache Node tooling | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/.npm | |
| .ci/node_modules | |
| key: ${{ runner.os }}-node-${{ hashFiles('.ci/package-lock.json') }} | |
| restore-keys: ${{ runner.os }}-node- | |
| - name: Install Node tooling | |
| run: cd .ci && npm ci | |
| - name: Parse Mermaid blocks | |
| run: | | |
| export PATH=".ci/node_modules/.bin:$PATH" | |
| bash scripts/mermaid-parse.sh docs/ |