Skip to content

feat(fe): add React ground system UI and demo telemetry injector #74

feat(fe): add React ground system UI and demo telemetry injector

feat(fe): add React ground system UI and demo telemetry injector #74

Workflow file for this run

# 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/