name: Build and Push Holoscan Application on: push: paths: - '.riahub/workflows/**' env: REGISTRY_HOST: NAMESPACE: ${{ gitea.repository_owner }} REGISTRY_USER: ${{ gitea.actor }} REGISTRY_TOKEN: ${{ secrets.TOKEN_DEV }} SOURCE_REPO: qoherent/RIA_Example SOURCE_BRANCH: main SOURCE_FILE: Applications/Example_Application.json APP_NAME: applications_example_application_json DOCKER_IMAGE_NAME: applications-example-application-json TARGET_IMAGE_TAG: /${{ gitea.repository_owner }}/ria-applications-example-application-json-runtime:latest BUILD_TOOLS_REPO: ${{ gitea.repository_owner }}/qac-mvp RIA_CORE_REPO: ${{ gitea.repository_owner }}/ria-core ENABLE_HOLOSCAN: true jobs: build: name: Build and Push RIA runs-on: ubuntu-latest permissions: packages: write contents: read steps: - name: Verify Docker is available run: docker info --format '{{.ServerVersion}}' - name: Login to RIA Hub Container Registry run: | LOWERCASE_USER=$(echo "$REGISTRY_USER" | tr '[:upper:]' '[:lower:]') echo "$REGISTRY_TOKEN" | docker login $REGISTRY_HOST -u "$LOWERCASE_USER" --password-stdin - name: Checkout build tools repository run: | git clone "http://riahub.ai/${{ env.BUILD_TOOLS_REPO }}.git" build-tools cd build-tools && git checkout main - name: Checkout ria_core library run: | git clone "http://riahub.ai/${{ env.RIA_CORE_REPO }}.git" ria-core cd ria-core && git checkout main - name: Checkout source repository with application run: | ENCODED_USER=$(printf '%s' "$REGISTRY_USER" | sed 's/:/%3A/g; s/@/%40/g; s/#/%23/g; s/?/%3F/g') ENCODED_TOKEN=$(printf '%s' "$REGISTRY_TOKEN" | sed 's/:/%3A/g; s/@/%40/g; s/#/%23/g; s/?/%3F/g') git clone "http://$ENCODED_USER:$ENCODED_TOKEN@riahub.ai/qoherent/RIA_Example.git" source-app cd source-app && git checkout $SOURCE_BRANCH - name: Install dependencies run: | command -v jq >/dev/null || { apt-get update && apt-get install -y python3 python3-pip python3-venv jq; } pip install -r build-tools/requirements.txt || true - name: Parse Application Config id: parse_config run: | CONFIG_PATH="source-app/$SOURCE_FILE" BACKEND=$(jq -r '.ops[] | select(.type=="inference") | .specs[] | select(.key=="backend") | .default // "onnxrt"' $CONFIG_PATH | head -n 1) MODEL_VAL=$(jq -r '.ops[] | select(.type=="inference") | .specs[] | select(.key=="model_path_map" or .key=="model_path" or .key=="model_file") | .default' $CONFIG_PATH | head -n 1) if [ -z "$MODEL_VAL" ] || [ "$MODEL_VAL" == "null" ]; then if [ "$BACKEND" == "trt" ]; then TARGET_NAME="model.engine"; else TARGET_NAME="model.onnx"; fi else TARGET_NAME=$(basename "$MODEL_VAL") fi if [ "$ENABLE_HOLOSCAN" = "false" ]; then BACKEND="onnxrt" fi echo "INFERENCE_BACKEND=$BACKEND" >> $GITHUB_ENV echo "TARGET_MODEL_NAME=$TARGET_NAME" >> $GITHUB_ENV - name: Generate C++ code and CMakeLists.txt id: codegen run: | APP_DIR="apps/$APP_NAME" mkdir -p "$APP_DIR" cp "source-app/$SOURCE_FILE" "$APP_DIR/app_flow_graph.json" if [ "$ENABLE_HOLOSCAN" = "false" ]; then python3 build-tools/src/patch_for_cpu.py "$APP_DIR/app_flow_graph.json" fi python build-tools/src/full_generator.py --config "$APP_DIR/app_flow_graph.json" --output-dir "$APP_DIR" if [ -f "$APP_DIR/src/CMakeLists.txt" ]; then mv "$APP_DIR/src/CMakeLists.txt" "$APP_DIR/CMakeLists.txt" fi TARGET_NAME=$(grep "add_executable" "$APP_DIR/CMakeLists.txt" | head -1 | cut -d'(' -f2 | cut -d' ' -f1) echo "cmake_target=$TARGET_NAME" >> $GITEA_OUTPUT - name: Generate YAML config file run: | python build-tools/src/yaml_generator.py --input apps/$APP_NAME/app_flow_graph.json --output apps/$APP_NAME/config.yaml - name: Stage Inference Model run: | APP_DIR="apps/$APP_NAME" mkdir -p "$APP_DIR/assets" FOUND_FILE="" if [ -f "source-app/$TARGET_MODEL_NAME" ]; then FOUND_FILE="source-app/$TARGET_MODEL_NAME" else if [ "$INFERENCE_BACKEND" == "trt" ]; then FOUND_FILE=$(find source-app -name "*.trt" -o -name "*.engine" -o -name "*.onnx" | head -n 1) else FOUND_FILE=$(find source-app -name "*.onnx" | head -n 1) fi fi if [ -n "$FOUND_FILE" ]; then echo "Staging model: $FOUND_FILE -> $APP_DIR/assets/$TARGET_MODEL_NAME" cp "$FOUND_FILE" "$APP_DIR/assets/$TARGET_MODEL_NAME" else HAS_INFERENCE=$(jq '[.ops[] | select(.type=="inference")] | length' "source-app/$SOURCE_FILE") if [ "$HAS_INFERENCE" -gt 0 ]; then echo "ERROR: Pipeline has inference operator(s) but no model file found in source repository." echo "Looked for: $TARGET_MODEL_NAME, *.onnx, *.trt, *.engine" exit 1 fi echo "No inference model needed for this pipeline." fi - name: Prepare Docker Context run: | APP_DIR="apps/$APP_NAME" cp -r ria-core "$APP_DIR/ria_core" rm -rf "$APP_DIR/ria_core/.git" "$APP_DIR/ria_core/build" if [ "$ENABLE_HOLOSCAN" = "false" ]; then cp build-tools/src/install_dummy_driver.py "$APP_DIR/" fi - name: Generate Dockerfile run: | APP_DIR="apps/$APP_NAME" CMAKE_TARGET="${{ steps.codegen.outputs.cmake_target }}" DF="$APP_DIR/Dockerfile" cat > "$DF" <<'DOCKERFILE_BUILD' # syntax=docker/dockerfile:1 FROM nvcr.io/nvidia/clara-holoscan/holoscan:v3.4.0-dgpu AS build WORKDIR /workspace ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get -y install --no-install-recommends pkg-config build-essential cmake git wget libiio-dev libiio0 libad9361-dev libad9361-0 libfftw3-dev && apt-get clean RUN wget -q https://github.com/microsoft/onnxruntime/releases/download/v1.14.1/onnxruntime-linux-x64-1.14.1.tgz && \ tar -xzf onnxruntime-linux-x64-1.14.1.tgz && \ mkdir -p /usr/include/onnxruntime && \ cp -r onnxruntime-linux-x64-1.14.1/include/* /usr/include/onnxruntime/ && \ cp -r onnxruntime-linux-x64-1.14.1/lib/* /usr/lib/ && \ rm -rf onnxruntime-linux-x64-1.14.1* RUN wget -q https://github.com/Kitware/CMake/releases/download/v3.31.0/cmake-3.31.0-linux-x86_64.tar.gz && \ tar -xzf cmake-3.31.0-linux-x86_64.tar.gz -C /opt && \ mv /opt/cmake-3.31.0-linux-x86_64 /opt/cmake && \ rm cmake-3.31.0-linux-x86_64.tar.gz DOCKERFILE_BUILD if [ "$CPU_ONLY_MODE" = "true" ]; then echo 'COPY install_dummy_driver.py .' >> "$DF" echo 'RUN python3 install_dummy_driver.py && rm install_dummy_driver.py' >> "$DF" fi cat >> "$DF" <> "$DF" <<'DOCKERFILE_RUNTIME' FROM nvcr.io/nvidia/clara-holoscan/holoscan:v3.4.0-dgpu WORKDIR /app ENV DEBIAN_FRONTEND=noninteractive LABEL ria.app="applications_example_application_json" ria.profile="nvidia-x86" ria.hardware="pluto" ria.operators="PlutoTXOp,inference_builtin,model_mapper,pluto_source,postprocessor,preprocessor,spectrogram,spectrogram_dashboard" ria.version="${{ gitea.sha }}" RUN (CODENAME=$(. /etc/os-release && echo $VERSION_CODENAME) && grep -q 'universe' /etc/apt/sources.list.d/ubuntu.sources 2>/dev/null && true || sed -i '/^Components:/ s/$/ universe/' /etc/apt/sources.list.d/ubuntu.sources 2>/dev/null || echo "deb http://archive.ubuntu.com/ubuntu $CODENAME universe" >> /etc/apt/sources.list) && apt-get update && apt-get -y install --no-install-recommends libiio-dev libiio0 libad9361-dev libad9361-0 libfftw3-3 && apt-get clean && rm -rf /var/lib/apt/lists/* COPY --from=build /usr/lib/libonnxruntime* /usr/lib/ ENV LD_LIBRARY_PATH=\$LD_LIBRARY_PATH:/usr/lib/x86_64-linux-gnu DOCKERFILE_RUNTIME echo 'USER root' >> "$DF" cat >> "$DF" <&1 | tee build.log - name: Push to Registry run: | TAG="${{ gitea.run_number }}" TARGET_LATEST="${{ env.TARGET_IMAGE_TAG }}" TARGET_SHA="${REGISTRY_HOST}/${NAMESPACE}/ria-${DOCKER_IMAGE_NAME}-runtime:${{ gitea.sha }}" docker tag "$DOCKER_IMAGE_NAME:$TAG" "$TARGET_LATEST" docker tag "$DOCKER_IMAGE_NAME:$TAG" "$TARGET_SHA" echo "Pushing: $TARGET_LATEST" docker push "$TARGET_LATEST" echo "Pushing: $TARGET_SHA" docker push "$TARGET_SHA" - name: Build Summary if: always() run: | echo "## Build Summary" >> $GITHUB_STEP_SUMMARY echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY echo "| Application | $APP_NAME |" >> $GITHUB_STEP_SUMMARY echo "| Source | $SOURCE_REPO/$SOURCE_FILE ($SOURCE_BRANCH) |" >> $GITHUB_STEP_SUMMARY echo "| Image | ${{ env.TARGET_IMAGE_TAG }} |" >> $GITHUB_STEP_SUMMARY echo "| Mode | Holoscan |" >> $GITHUB_STEP_SUMMARY echo "| Run | #${{ gitea.run_number }} |" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY if [ "$ENABLE_HOLOSCAN" = "false" ]; then echo "\`\`\`" >> $GITHUB_STEP_SUMMARY echo "docker pull ${{ env.TARGET_IMAGE_TAG }}" >> $GITHUB_STEP_SUMMARY echo "docker run -it --rm --net=host --privileged ${{ env.TARGET_IMAGE_TAG }}" >> $GITHUB_STEP_SUMMARY echo "\`\`\`" >> $GITHUB_STEP_SUMMARY else echo "\`\`\`" >> $GITHUB_STEP_SUMMARY echo "docker pull ${{ env.TARGET_IMAGE_TAG }}" >> $GITHUB_STEP_SUMMARY echo "docker run --runtime=nvidia --gpus all -it --rm --net=host --privileged ${{ env.TARGET_IMAGE_TAG }}" >> $GITHUB_STEP_SUMMARY echo "\`\`\`" >> $GITHUB_STEP_SUMMARY fi - uses: actions/upload-artifact@v3 with: name: deployment_instructions_${{ gitea.run_number }} path: build.log