diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..ca502ab --- /dev/null +++ b/.dockerignore @@ -0,0 +1,10 @@ +.git +.gitignore +.gitattributes +.cache +build +bin +lib +*.db +*.log +Dockerfile diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..d366746 --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -0,0 +1,83 @@ +#======================================================================= +# FILE: .gitea/workflows/ci.yml +# DESC: CI/CD for H100PowerManger +# - build/test on aarch64 (via QEMU emulation of arm64 Ubuntu 20.04) +# - deploy the cross-built binary to the RK3588 board +#======================================================================= + +name: build-test-deploy + +on: + push: + branches: [main] + tags: ['v*'] + pull_request: + +env: + CI_IMAGE: h100-power-manager-ci:arm64 + +jobs: + #--------------------------------------------------------------------- + # Build (aarch64) + unit test + startup smoke test + #--------------------------------------------------------------------- + build-test: + runs-on: + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Register QEMU for arm64 + run: | + docker run --rm --privileged tonistiigi/binfmt --install arm64 + + - name: Build arm64 CI image + run: | + docker build -t "$CI_IMAGE" -f ci/Dockerfile . + + - name: Build & test inside arm64 container + run: | + docker run --rm \ + -v "$GITHUB_WORKSPACE:/src" \ + "$CI_IMAGE" /src/ci/build-test.sh + + - name: Upload artifacts + uses: actions/upload-artifact@v3 + with: + name: arm64-bin + path: | + bin/pPowerManger + bin/pPMtest + bin/SQLiteTest + + #--------------------------------------------------------------------- + # Deploy the binary to the RK3588 board (push only, no restart) + #--------------------------------------------------------------------- + deploy: + needs: build-test + if: github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/') + runs-on: + steps: + - name: Download artifacts + uses: actions/download-artifact@v3 + with: + name: arm64-bin + path: bin/ + + - name: Deploy to board + env: + DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }} + DEPLOY_USER: ${{ vars.DEPLOY_USER }} + DEPLOY_PATH: ${{ vars.DEPLOY_PATH }} + DEPLOY_SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }} + run: | + set -euo pipefail + USER="${DEPLOY_USER:-root}" + HOST="${DEPLOY_HOST:?DEPLOY_HOST secret is not set}" + DEST="${DEPLOY_PATH:-/root/work/moos_ws/moos-ivp-extend/bin}" + mkdir -p ~/.ssh && chmod 700 ~/.ssh + printf '%s\n' "$DEPLOY_SSH_KEY" > ~/.ssh/id_ed25519 + chmod 600 ~/.ssh/id_ed25519 + ssh-keyscan -H "$HOST" >> ~/.ssh/known_hosts 2>/dev/null + chmod 755 bin/pPowerManger + rsync -avz bin/pPowerManger "${USER}@${HOST}:${DEST}/pPowerManger" + echo "Deployed pPowerManger -> ${USER}@${HOST}:${DEST}/" diff --git a/ci/Dockerfile b/ci/Dockerfile new file mode 100755 index 0000000..4ed0f65 --- /dev/null +++ b/ci/Dockerfile @@ -0,0 +1,43 @@ +#======================================================================= +# FILE: ci/Dockerfile +# DESC: aarch64 (RK3588 / Ubuntu 20.04) build & test environment. +# - Ubuntu 20.04 arm64 base (matches the target board) +# - MOOS-IvP built from source and installed to /usr/local +# - jsoncpp (the only extra dep used by pPowerManger) +#======================================================================= + +FROM arm64v8/ubuntu:20.04 + +ENV DEBIAN_FRONTEND=noninteractive + +#----------------------------------------------------------------------- +# System toolchain + dependencies +#----------------------------------------------------------------------- +RUN apt-get update && apt-get install -y --no-install-recommends \ + build-essential \ + cmake \ + git \ + ca-certificates \ + libjsoncpp-dev \ + rsync \ + && rm -rf /var/lib/apt/lists/* + +#----------------------------------------------------------------------- +# Build & install MOOS-IvP (bundles MOOS core + essentials + geodesy + ivp) +# build-moos.sh -m : skip GUI tools (no FLTK needed) +# build-ivp.sh -n : skip GUI apps (no FLTK needed) +# Installs libMOOS + MOOSConfig.cmake + ivp headers/libs to /usr/local, +# matching the layout expected by the project's top-level CMakeLists.txt. +#----------------------------------------------------------------------- +WORKDIR /opt + +RUN git clone --depth 1 https://github.com/moos-ivp/moos-ivp.git && \ + cd moos-ivp && \ + ./build-moos.sh -m -j"$(nproc)" && \ + make -C build/MOOS/MOOSCore install && \ + make -C build/MOOS/MOOSGeodesy install && \ + ./build-ivp.sh -n -j"$(nproc)" && \ + make -C build/ivp install && \ + ldconfig + +WORKDIR /src diff --git a/ci/build-test.sh b/ci/build-test.sh new file mode 100755 index 0000000..67fe1ee --- /dev/null +++ b/ci/build-test.sh @@ -0,0 +1,88 @@ +#!/bin/bash +#======================================================================= +# FILE: ci/build-test.sh +# DESC: Build the project, run unit tests and a startup smoke test. +# Executed INSIDE the aarch64 build container (ci/Dockerfile). +#======================================================================= +set -euo pipefail + +SRC_DIR="${SRC_DIR:-/src}" +cd "${SRC_DIR}" + +#----------------------------------------------------------------------- +# 1. Build +#----------------------------------------------------------------------- +echo ">>> Building (aarch64, Release)..." +rm -rf build +mkdir -p build +cd build +cmake -DCMAKE_BUILD_TYPE=Release .. +make -j"$(nproc)" + +BIN_DIR="${SRC_DIR}/bin" +echo ">>> Build artifacts:" +ls -la "${BIN_DIR}" + +#----------------------------------------------------------------------- +# 2. Unit test (SQLiteTest) +#----------------------------------------------------------------------- +echo ">>> Running unit test: SQLiteTest" +"${BIN_DIR}/SQLiteTest" +echo ">>> SQLiteTest passed" + +#----------------------------------------------------------------------- +# 3. Startup smoke test: MOOSDB + pPowerManger liveness +#----------------------------------------------------------------------- +echo ">>> Smoke test: launch MOOSDB + pPowerManger" + +# Locate MOOSDB (installed by MOOS build) +MOOSDB="$(command -v MOOSDB || true)" +if [ -z "${MOOSDB}" ]; then + MOOSDB="$(ls /opt/moos-ivp/bin/MOOSDB 2>/dev/null || true)" +fi +if [ -z "${MOOSDB}" ] || [ ! -x "${MOOSDB}" ]; then + echo "ERROR: MOOSDB not found" >&2 + exit 1 +fi +echo "Using MOOSDB: ${MOOSDB}" + +# Minimal mission file for MOOSDB + pPowerManger +MISSION_FILE="/tmp/smoke.moos" +cat > "${MISSION_FILE}" < /tmp/moosdb_smoke.log 2>&1 & +MOOSDB_PID=$! +sleep 2 + +./pPowerManger "${MISSION_FILE}" > /tmp/pm_smoke.log 2>&1 & +PM_PID=$! +sleep 5 + +if kill -0 "${PM_PID}" 2>/dev/null; then + echo ">>> Smoke test PASSED (pPowerManger alive after 5s)" + kill "${PM_PID}" "${MOOSDB_PID}" 2>/dev/null || true + wait "${PM_PID}" "${MOOSDB_PID}" 2>/dev/null || true + exit 0 +else + echo ">>> Smoke test FAILED (pPowerManger exited)" >&2 + echo "--- pPowerManger log ---" >&2 + cat /tmp/pm_smoke.log >&2 || true + echo "--- MOOSDB log ---" >&2 + cat /tmp/moosdb_smoke.log >&2 || true + kill "${MOOSDB_PID}" 2>/dev/null || true + exit 1 +fi