Skip to content

update unit tests

update unit tests #6

Workflow file for this run

name: CI/CD — OmniBioAI Dev Docker
on:
push:
branches: [main, dev, "release/**", "feature/**"]
tags: ["v*.*.*"]
pull_request:
branches: [main, dev]
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
IMAGE_NAME: omnibioai-dev-env
REGISTRY: ghcr.io
FULL_IMAGE: ghcr.io/${{ github.repository_owner }}/omnibioai-dev-env
jobs:
# -----------------------------------------------------------------------
# 1. Lint Dockerfile + shell script
# -----------------------------------------------------------------------
lint:
name: Lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Lint Dockerfile (hadolint)
uses: hadolint/hadolint-action@v3.1.0
with:
dockerfile: Dockerfile
ignore: DL3008,DL3009,DL4006
failure-threshold: error
- name: Lint run_ai_dev.sh (shellcheck)
uses: ludeeus/action-shellcheck@master
with:
scandir: .
severity: warning
# -----------------------------------------------------------------------
# 2. Build Docker image (no push, CPU runner)
# -----------------------------------------------------------------------
build:
name: Build
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v4
- name: Free up disk space
run: |
sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/lib/android
df -h
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=sha,prefix=sha-,format=short
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
- name: Build image (no push)
uses: docker/build-push-action@v6
with:
context: .
push: false
load: true
tags: ${{ env.IMAGE_NAME }}:ci-test
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Smoke test — Python + key packages importable
run: |
docker run --rm ${{ env.IMAGE_NAME }}:ci-test \
python -c "
import torch, transformers, pandas, numpy, sklearn
print('torch :', torch.__version__)
print('transformers:', transformers.__version__)
print('pandas :', pandas.__version__)
print('All imports OK')
"
- name: Smoke test — CUDA flag (non-fatal on CPU runner)
run: |
docker run --rm ${{ env.IMAGE_NAME }}:ci-test \
python -c "import torch; print('CUDA available:', torch.cuda.is_available())"
continue-on-error: true
- name: Smoke test — Jupyter installed
run: |
docker run --rm ${{ env.IMAGE_NAME }}:ci-test jupyter --version
- name: Smoke test — Ollama binary present
run: |
docker run --rm ${{ env.IMAGE_NAME }}:ci-test ollama --version
- name: Smoke test — Nextflow installed
run: |
docker run --rm ${{ env.IMAGE_NAME }}:ci-test nextflow -version
- name: Smoke test — GATK installed
run: |
docker run --rm ${{ env.IMAGE_NAME }}:ci-test gatk --version
- name: Smoke test — R packages
run: |
docker run --rm ${{ env.IMAGE_NAME }}:ci-test \
Rscript -e "library(tidyverse); library(DESeq2); cat('R packages OK\n')"
continue-on-error: true
- name: Smoke test — MySQL present
run: |
docker run --rm ${{ env.IMAGE_NAME }}:ci-test mysqld --version
- name: Image size report
run: |
docker inspect ${{ env.IMAGE_NAME }}:ci-test \
--format='Image size: {{.Size}}' | \
awk '{printf "%s %.1f GB\n", $1" "$2, $3/1073741824}'
# -----------------------------------------------------------------------
# 3. Validate run_ai_dev.sh
# -----------------------------------------------------------------------
validate-script:
name: Validate run script
runs-on: ubuntu-latest
needs: lint
steps:
- uses: actions/checkout@v4
- name: Check shebang
run: |
head -1 run_ai_dev.sh | grep -q '^#!/bin/bash' || \
(echo "Missing #!/bin/bash shebang" && exit 1)
echo "Shebang OK"
- name: Syntax check
run: bash -n run_ai_dev.sh && echo "Syntax OK"
- name: Confirm required docker flags
run: |
grep -q -- '--gpus all' run_ai_dev.sh || (echo "Missing --gpus all" && exit 1)
grep -q -- '--ipc=host' run_ai_dev.sh || (echo "Missing --ipc=host" && exit 1)
grep -q -- 'huggingface' run_ai_dev.sh || (echo "Missing HF mount" && exit 1)
grep -q -- '.ollama' run_ai_dev.sh || (echo "Missing Ollama mount" && exit 1)
echo "All required flags present"
- name: Confirm nvidia-smi guard
run: |
grep -q 'nvidia-smi' run_ai_dev.sh || \
(echo "Missing nvidia-smi check" && exit 1)
echo "GPU guard OK"
# -----------------------------------------------------------------------
# 4. Push to GHCR — main + tags only
# -----------------------------------------------------------------------
push:
name: Push to GHCR
runs-on: ubuntu-latest
needs: [build, validate-script]
if: |
github.event_name == 'push' &&
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/'))
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- name: Free up disk space
run: sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/lib/android
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.FULL_IMAGE }}
tags: |
type=ref,event=branch
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=raw,value=latest,enable=${{ github.ref == 'refs/heads/main' }}
type=sha,prefix=sha-,format=short
- name: Build and push
uses: docker/build-push-action@v6
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Summary
run: |
echo "### Pushed to GHCR" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "${{ steps.meta.outputs.tags }}" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
# -----------------------------------------------------------------------
# 5. GPU validation — self-hosted runner, post-push
# -----------------------------------------------------------------------
gpu-validate:
name: GPU validation
runs-on: [self-hosted, gpu]
needs: push
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
continue-on-error: true
steps:
- name: Log in to GHCR
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Pull latest image
run: docker pull ${{ env.FULL_IMAGE }}:latest
- name: Validate CUDA + PyTorch
run: |
docker run --rm --gpus all \
${{ env.FULL_IMAGE }}:latest \
python -c "
import torch
assert torch.cuda.is_available(), 'CUDA not available!'
print(f'GPU OK: {torch.cuda.get_device_name(0)}')
print(f'PyTorch: {torch.__version__}')
a = torch.randn(512, 512, device='cuda')
b = torch.randn(512, 512, device='cuda')
c = torch.mm(a, b)
print(f'Matrix multiply OK: {c.shape}')
"
- name: Validate Ollama binary
run: |
docker run --rm --gpus all \
${{ env.FULL_IMAGE }}:latest \
bash -c "ollama --version && echo 'Ollama binary OK'"
- name: Validate run_ai_dev.sh mounts exist on runner
run: |
[[ -d "$HOME/.cache/huggingface" ]] && echo "HF cache OK" || echo "HF cache missing (first run)"
[[ -d "$HOME/.ollama" ]] && echo "Ollama dir OK" || echo "Ollama dir missing (first run)"