Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 8 additions & 7 deletions .github/workflows/docker-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,6 @@ jobs:
packages: write
steps:
- uses: actions/checkout@v6.0.2
- name: Log in to DHI registry
uses: docker/login-action@v3
with:
registry: dhi.io
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- uses: actions/setup-python@v6.2.0
with:
python-version: "3.11"
Expand All @@ -41,11 +35,18 @@ jobs:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Log in to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Docker metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository_owner }}/codeforerunner
images: |
ghcr.io/${{ github.repository_owner }}/codeforerunner
heyderekp/codeforerunner
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
Expand Down
23 changes: 18 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,14 +1,27 @@
FROM dhi.io/python:3.13
FROM python:3.13-slim AS builder

ENV PIP_DISABLE_PIP_VERSION_CHECK=1 \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1

WORKDIR /workspace
WORKDIR /build
COPY . .

# Install the wheel into an isolated venv so only it (no build toolchain or
# source tree) is carried into the runtime stage.
RUN python -m venv /opt/venv \
&& /opt/venv/bin/pip install --no-cache-dir .

FROM python:3.13-slim

COPY . /workspace
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PATH="/opt/venv/bin:$PATH"

RUN python -m pip install --upgrade pip \
&& python -m pip install --no-cache-dir -e .
COPY --from=builder /opt/venv /opt/venv

# /workspace is a mount point: `forerunner` runs against the caller's repo
# (Path.cwd()), bind-mounted here. Source is not baked in.
WORKDIR /workspace

ENTRYPOINT ["forerunner"]
25 changes: 24 additions & 1 deletion tests/test_workflows_yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,35 @@ def test_docker_publish_workflow_uses_version_tag_and_ghcr():
step for step in steps
if isinstance(step, dict) and step.get("uses") == "docker/login-action@v3"
]
assert any(step.get("with", {}).get("registry") == "dhi.io" for step in login_steps)
# Publishes to GHCR (registry ghcr.io) and Docker Hub (login-action with no
# `registry`, which defaults to docker.io). The distroless DHI base was
# dropped (#72), so there must be no dhi.io login left. Compare registry
# values with equality (not substring `in`) to avoid host-substring checks.
registries = [step.get("with", {}).get("registry") for step in login_steps]
assert any(r == "ghcr.io" for r in registries), (
f"expected a ghcr.io login, got {registries!r}"
)
assert any(r is None or r == "docker.io" for r in registries), (
f"expected a Docker Hub login (no registry / docker.io), got {registries!r}"
)
assert all(r != "dhi.io" for r in registries), "dhi.io login should be removed (#72)"

steps_text = "\n".join(str(step) for step in publish.get("steps", []))
assert "docker/login-action" in steps_text
assert "docker/build-push-action" in steps_text
assert "scripts/check_versions.py" in steps_text

# Both publish targets must appear in the image metadata. Parse the
# metadata-action `images` list and match full image refs exactly.
meta_step = next(
step for step in steps
if isinstance(step, dict) and str(step.get("uses", "")).startswith("docker/metadata-action")
)
images = [ln.strip() for ln in str(meta_step["with"]["images"]).splitlines() if ln.strip()]
expected_ghcr = "ghcr.io/${{ github.repository_owner }}/codeforerunner"
assert expected_ghcr in images, f"expected GHCR image, got {images!r}"
assert "heyderekp/codeforerunner" in images, f"expected Docker Hub image, got {images!r}"


def test_release_pr_workflow_requires_release_signal_and_uploads_artifacts():
wf = WORKFLOWS_DIR / "release-pr.yml"
Expand Down