fix: copy package includes in Docker builds, incl. GPU (#450)

* fix: copy package includes in Docker build

* fix: copy package includes in GPU Docker builds too

PR #450 fixed the CPU Dockerfile but Dockerfile.gpu and
Dockerfile.gpu.rocm have the identical bug: they COPY src/ then
`uv pip install ".[server]"` without copying the non-src
force-include paths (scripts/install, deploy/windows), so hatchling's
wheel build fails the same way on GPU images (#447).

Adds the two COPY lines to both GPU Dockerfiles and generalizes the
regression test to guard every wheel-building Dockerfile (CPU + both
GPU variants) instead of only the CPU one.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Jon Saad-Falcon <41205309+jonsaadfalcon@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sourish Chakraborty
2026-06-01 09:23:22 -07:00
committed by GitHub
co-authored by Jon Saad-Falcon Claude Opus 4.8
parent 0fcee8236e
commit a13d8a909d
4 changed files with 45 additions and 0 deletions
+2
View File
@@ -13,6 +13,8 @@ FROM python:3.12-slim-bookworm AS builder
WORKDIR /app
COPY pyproject.toml README.md ./
COPY src/ src/
COPY scripts/install scripts/install
COPY deploy/windows deploy/windows
# Copy built frontend into the server static directory
COPY --from=frontend /src/openjarvis/server/static src/openjarvis/server/static/
+2
View File
@@ -17,6 +17,8 @@ RUN apt-get update && \
WORKDIR /app
COPY pyproject.toml README.md ./
COPY src/ src/
COPY scripts/install scripts/install
COPY deploy/windows deploy/windows
COPY --from=frontend /src/openjarvis/server/static src/openjarvis/server/static/
+2
View File
@@ -17,6 +17,8 @@ RUN apt-get update && \
WORKDIR /app
COPY pyproject.toml README.md ./
COPY src/ src/
COPY scripts/install scripts/install
COPY deploy/windows deploy/windows
COPY --from=frontend /src/openjarvis/server/static src/openjarvis/server/static/
+39
View File
@@ -4,6 +4,11 @@ from __future__ import annotations
from pathlib import Path
try:
import tomllib
except ModuleNotFoundError: # pragma: no cover - Python < 3.11
import tomli as tomllib
ROOT = Path(__file__).resolve().parent.parent.parent
DOCKER_DIR = ROOT / "deploy" / "docker"
@@ -20,6 +25,40 @@ class TestDockerFiles:
assert "ENTRYPOINT" in content
assert "jarvis" in content
def test_dockerfile_copies_forced_package_includes(self):
# Every Dockerfile that builds the wheel from an explicit `COPY src/`
# context (rather than `COPY . .`) must also copy the non-src
# force-include paths before installing, or hatchling's wheel build
# fails (see #447). Guard ALL such Dockerfiles, not just the CPU one,
# so the GPU variants can't silently regress.
project = tomllib.loads((ROOT / "pyproject.toml").read_text())
force_include = project["tool"]["hatch"]["build"]["targets"]["wheel"][
"force-include"
]
non_src_includes = [s for s in force_include if not s.startswith("src/")]
install_marker = 'uv pip install --system ".[server]"'
wheel_dockerfiles = [
p
for p in sorted(DOCKER_DIR.glob("Dockerfile*"))
if install_marker in p.read_text() and "COPY src/ src/" in p.read_text()
]
# Sanity: we actually found the wheel-building Dockerfiles to guard.
assert wheel_dockerfiles, "no wheel-building Dockerfiles found to check"
for dockerfile in wheel_dockerfiles:
content = dockerfile.read_text()
install_step = content.index(install_marker)
for source in non_src_includes:
copy_marker = f"COPY {source} "
assert copy_marker in content, (
f"{dockerfile.name} is missing '{copy_marker.strip()}' "
f"(a non-src force-include path)"
)
assert content.index(copy_marker) < install_step, (
f"{dockerfile.name} copies '{source}' after the install step"
)
def test_docker_compose_valid_yaml(self):
import importlib