#======================================================================= # FILE: .gitea/workflows/ci.yml # DESC: CI/CD for H100PowerManger # - build/test on aarch64 (QEMU emulation of arm64 Ubuntu 20.04) # - publish compiled binary to Gitea Releases (manual deploy) # * tag push v* -> versioned Release # * main push -> rolling "latest" Release (pre-release / test) # Self-contained (no external actions). The runner is an Alpine # container with the host Docker socket mounted; we install the # docker CLI at runtime. #======================================================================= name: build-test-deploy on: push: branches: [main] tags: ['v*'] pull_request: env: CI_IMAGE: h100-power-manager-ci:arm64 GITEA_SERVER: https://gitea2.zhaojingkui.xyz jobs: ci: runs-on: steps: #------------------------------------------------------------------- # Checkout via git (no external actions/checkout dependency) #------------------------------------------------------------------- - name: Checkout run: | set -euo pipefail git init . git remote add origin "https://zjk:${{ secrets.CI_TOKEN }}@gitea2.zhaojingkui.xyz/zjk/H100PowerManger.git" git fetch --depth 1 origin "$GITHUB_SHA" git checkout FETCH_HEAD #------------------------------------------------------------------- # Install runtime tooling inside the (Alpine) runner container #------------------------------------------------------------------- - name: Install tools run: | apk add --no-cache docker-cli docker-cli-buildx rsync openssh-client curl jq - name: Verify docker run: | docker version docker info 2>&1 | grep -Ei 'Architecture|Server Version|Operating System|Storage Driver' || true #------------------------------------------------------------------- # Register QEMU so arm64 images can run on the x86 host daemon #------------------------------------------------------------------- - name: Register QEMU for arm64 run: | docker run --rm --privileged tonistiigi/binfmt --install arm64 \ || docker run --rm --privileged docker.m.daocloud.io/tonistiigi/binfmt --install arm64 #------------------------------------------------------------------- # Build the aarch64 CI image (MOOS-IvP + jsoncpp) #------------------------------------------------------------------- - name: Build arm64 CI image timeout-minutes: 90 env: CI_TOKEN: ${{ secrets.CI_TOKEN }} run: | docker buildx version docker buildx build --platform linux/arm64 --load \ --secret id=gitea_token,env=CI_TOKEN \ -t "$CI_IMAGE" -f ci/Dockerfile . #------------------------------------------------------------------- # Build project + unit test + startup smoke test (inside arm64) # NOTE: the runner runs inside a container, so the workspace path is # not a host path -> `-v` mounts don't work. Use `docker cp` # (streams files through the docker socket) instead. #------------------------------------------------------------------- - name: Build & test inside arm64 container timeout-minutes: 30 run: | CID="h100-ci-test" docker rm -f "$CID" >/dev/null 2>&1 || true docker create --name "$CID" --platform linux/arm64 "$CI_IMAGE" /bin/sh -c 'sleep 7200' >/dev/null docker cp "$PWD/." "$CID:/src/" docker start "$CID" >/dev/null # Run build + tests (capture exit code, don't fail the step here so # we can still collect the report on failure) docker exec \ -e GITHUB_RUN_ID="${{ github.run_id }}" \ -e GITHUB_REPOSITORY="${{ github.repository }}" \ -e GITHUB_SERVER_URL="${GITEA_SERVER}" \ "$CID" /src/ci/build-test.sh TEST_RC=$? mkdir -p bin reports docker cp "$CID:/src/bin/pPowerManger" bin/pPowerManger 2>/dev/null || true docker cp "$CID:/src/bin/pPMtest" bin/pPMtest 2>/dev/null || true docker cp "$CID:/src/bin/SQLiteTest" bin/SQLiteTest 2>/dev/null || true docker cp "$CID:/src/reports/." reports/ 2>/dev/null || true docker rm -f "$CID" >/dev/null 2>&1 || true echo "--- bin/ ---"; ls -la bin/ 2>/dev/null || true echo "--- reports/ ---"; ls -la reports/ 2>/dev/null || true exit "$TEST_RC" #------------------------------------------------------------------- # Publish visual test report (runs even if tests failed) #------------------------------------------------------------------- - name: Publish test report if: always() run: | SUMMARY_FILE="${GITHUB_STEP_SUMMARY:-/tmp/step_summary.md}" if [ -f reports/test-report.md ]; then cat reports/test-report.md >> "$SUMMARY_FILE" else echo "## H100PowerManger CI" >> "$SUMMARY_FILE" echo "测试报告未生成(构建阶段失败)" >> "$SUMMARY_FILE" fi # Persist reports to a dedicated branch (main push only) if [ "${GITHUB_REF:-}" = "refs/heads/main" ] && [ -d reports ]; then git config user.name "CI Bot" git config user.email "ci@localhost" git checkout --orphan test-reports >/dev/null 2>&1 || git checkout test-reports >/dev/null 2>&1 || true git rm -rf . >/dev/null 2>&1 || true cp -f reports/test-report.md reports/junit.xml . 2>/dev/null || true git add test-report.md junit.xml git commit -m "CI test report ${GITHUB_SHA:-}" >/dev/null 2>&1 || true git push -f origin test-reports >/dev/null 2>&1 || echo "WARN: failed to push test-reports branch" fi #------------------------------------------------------------------- # Publish the aarch64 binary to Gitea Releases (manual deployment) # * tag push (v*) -> versioned Release (e.g. v1.0.0, stable) # * main push -> rolling "latest" Release (pre-release/test) # Only runs when build + tests succeeded. #------------------------------------------------------------------- - name: Publish release if: success() && startsWith(github.ref, 'refs/tags/v') env: RELEASE_TOKEN: ${{ secrets.CI_TOKEN }} run: | set -euo pipefail REPO="${{ github.repository }}" API="https://gitea2.zhaojingkui.xyz/api/v1/repos/${REPO}" TAG="${GITHUB_REF#refs/tags/}" COMMIT_SHORT="$(git rev-parse --short HEAD)" REPORT_URL="https://gitea2.zhaojingkui.xyz/${REPO}/src/branch/test-reports/test-report.md" BODY="pPowerManger (aarch64 / RK3588 / Ubuntu 20.04) - Commit: \`${COMMIT_SHORT}\` - 时间: $(date -u +'%Y-%m-%d %H:%M:%S UTC') - 测试报告: [${REPORT_URL}](${REPORT_URL}) 手动部署: 下载后 scp/rsync 到板卡: \`\`\` rsync -avz pPowerManger root@192.168.0.223:/root/work/moos_ws/moos-ivp-extend/bin/pPowerManger \`\`\`" echo ">>> 创建版本号 Release: ${TAG}" RELEASE_JSON=$(curl -sS -X POST -H "Authorization: token ${RELEASE_TOKEN}" \ -H "Content-Type: application/json" \ -d "{\"tag_name\":\"${TAG}\",\"name\":\"${TAG}\",\"body\":$(jq -Rn --arg b "${BODY}" '$b'),\"prerelease\":false}" \ "${API}/releases") echo "${RELEASE_JSON}" | jq -e .id >/dev/null || { echo "创建 Release 失败:"; echo "${RELEASE_JSON}"; exit 1; } RELEASE_ID=$(echo "${RELEASE_JSON}" | jq -r .id) echo ">>> 上传 pPowerManger (release id=${RELEASE_ID})" curl -sS -X POST -H "Authorization: token ${RELEASE_TOKEN}" \ -F "attachment=@bin/pPowerManger" \ "${API}/releases/${RELEASE_ID}/assets?name=pPowerManger" \ | jq -e .id >/dev/null || { echo "上传失败"; exit 1; } echo ">>> 发布完成: https://gitea2.zhaojingkui.xyz/${REPO}/releases/tag/${TAG}" - name: Publish latest release if: success() && github.ref == 'refs/heads/main' env: RELEASE_TOKEN: ${{ secrets.CI_TOKEN }} run: | set -euo pipefail REPO="${{ github.repository }}" API="https://gitea2.zhaojingkui.xyz/api/v1/repos/${REPO}" TAG="latest" COMMIT_SHORT="$(git rev-parse --short HEAD)" REPORT_URL="https://gitea2.zhaojingkui.xyz/${REPO}/src/branch/test-reports/test-report.md" BODY="pPowerManger (aarch64 / RK3588 / Ubuntu 20.04) — 测试用最新构建 - Commit: \`${COMMIT_SHORT}\` - 时间: $(date -u +'%Y-%m-%d %H:%M:%S UTC') - 测试报告: [${REPORT_URL}](${REPORT_URL}) 手动部署: 下载后 scp/rsync 到板卡: \`\`\` rsync -avz pPowerManger root@192.168.0.223:/root/work/moos_ws/moos-ivp-extend/bin/pPowerManger \`\`\`" # 1. move the "latest" tag to current commit echo ">>> 移动 latest tag 到 ${COMMIT_SHORT}" git tag -f "${TAG}" HEAD git push -f origin "${TAG}" || true # 2. delete old "latest" release (by tag), ignore if none echo ">>> 删除旧的 latest Release (如有)" curl -sS -X DELETE -H "Authorization: token ${RELEASE_TOKEN}" \ "${API}/releases/tags/${TAG}" || true # 3. create new "latest" release (pre-release) echo ">>> 创建 latest Release (pre-release)" RELEASE_JSON=$(curl -sS -X POST -H "Authorization: token ${RELEASE_TOKEN}" \ -H "Content-Type: application/json" \ -d "{\"tag_name\":\"${TAG}\",\"name\":\"latest (测试)\",\"body\":$(jq -Rn --arg b "${BODY}" '$b'),\"prerelease\":true}" \ "${API}/releases") echo "${RELEASE_JSON}" | jq -e .id >/dev/null || { echo "创建 latest Release 失败:"; echo "${RELEASE_JSON}"; exit 1; } RELEASE_ID=$(echo "${RELEASE_JSON}" | jq -r .id) # 4. upload pPowerManger echo ">>> 上传 pPowerManger (release id=${RELEASE_ID})" curl -sS -X POST -H "Authorization: token ${RELEASE_TOKEN}" \ -F "attachment=@bin/pPowerManger" \ "${API}/releases/${RELEASE_ID}/assets?name=pPowerManger" \ | jq -e .id >/dev/null || { echo "上传失败"; exit 1; } echo ">>> 发布完成: https://gitea2.zhaojingkui.xyz/${REPO}/releases/tag/${TAG}"