diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index c612f8e..be558a4 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -28,53 +28,68 @@ jobs: run: black --check . - # Run python tests - test: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Set up Python 3.13.1 - uses: actions/setup-python@v5 - with: - python-version: "3.13.1" - - name: Install dependencies - run: | - cd app - python -m pip install --upgrade pip - pip install pytest coverage - pip install -r requirements.txt - - name: Run pytest - run: cd app && coverage run -m pytest . - - name: Create code coverage report - run: cd app && coverage html - - name: Upload coverage report - uses: actions/upload-artifact@v4 - with: - name: coverage - path: app/htmlcov - retention-days: 30 - - - # Build Docker images to verify they can be built + # Build Docker image and save as artifact docker: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - - name: Set up QEMU - uses: docker/setup-qemu-action@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Build Docker images + - name: Build and load Docker image uses: docker/build-push-action@v5.3.0 with: # Build's context is the set of files located in the specified PATH or URL context: app - # List of target platforms for build - platforms: linux/amd64,linux/arm64 - # Don't push, just build to verify + # Build for single platform to enable loading + platforms: linux/amd64 + # Load the image into Docker daemon + load: true push: false tags: hv-coordinator:buildtest + - name: Save Docker image + run: docker save hv-coordinator:buildtest -o /tmp/docker-image.tar + - name: Upload Docker image artifact + uses: actions/upload-artifact@v4 + with: + name: docker-image + path: /tmp/docker-image.tar + retention-days: 1 + + + # Test inside Docker container + docker-test: + runs-on: ubuntu-latest + needs: docker + + steps: + - name: Download Docker image artifact + uses: actions/download-artifact@v4 + with: + name: docker-image + path: /tmp + - name: Load Docker image + run: docker load -i /tmp/docker-image.tar + - name: Run tests in container + run: | + docker run --name test-container \ + --entrypoint sh \ + -e COVERAGE_FILE=/tmp/.coverage \ + hv-coordinator:buildtest \ + -c " + mamba run -n coordinator pip install -r requirements-dev.txt + mamba run -n coordinator python -m coverage run -m pytest . + mamba run -n coordinator python -m coverage html -d /tmp/htmlcov + " + - name: Copy coverage report from container + run: docker cp test-container:/tmp/htmlcov ./coverage-output + - name: Remove container + run: docker rm test-container + - name: Upload coverage report + uses: actions/upload-artifact@v4 + with: + name: docker-coverage + path: coverage-output + retention-days: 30 diff --git a/app/Dockerfile b/app/Dockerfile index 792304f..3003e63 100644 --- a/app/Dockerfile +++ b/app/Dockerfile @@ -1,3 +1,25 @@ +# Builder stage - has all build tools +FROM condaforge/mambaforge AS builder + +WORKDIR /build +COPY requirements.txt . + +# This is where pip will be after the conda environment is created +ENV PIP=/opt/conda/envs/coordinator/bin/pip + +# Create conda environment and install dependencies +RUN mamba create -n coordinator -y python=3.13.5 gcc \ + && cd /tmp \ + && git clone https://github.com/sunpy/sunpy.git \ + && cd sunpy \ + && git fetch origin pull/8500/head:pr-8500 \ + && git checkout pr-8500 \ + && mamba run -n coordinator pip install --no-cache-dir . \ + && cd /build \ + && mamba run -n coordinator pip install --no-cache-dir -r requirements.txt \ + && rm -rf /tmp/sunpy + +# Final stage - minimal runtime image FROM condaforge/mambaforge RUN apt update && apt install -y curl @@ -5,24 +27,22 @@ RUN apt update && apt install -y curl # Create and switch to non-root user RUN useradd -m -s /bin/bash nonroot WORKDIR /home/nonroot/app -USER nonroot + +# Copy conda environment from builder (keep same path) +COPY --from=builder /opt/conda/envs/coordinator /opt/conda/envs/coordinator # copy application files to the container COPY --chown=nonroot:nonroot . . +USER nonroot + # This is where pip will be after the conda environment is created # can't conda activate in dockerfile -ENV PIP=/home/nonroot/.conda/envs/coordinator/bin/pip - -# Install dependencies in conda environment -RUN <