From c9160a084b337d1ec932101330058b5bc75384a7 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 24 Apr 2026 10:05:56 +0900 Subject: [PATCH 1/4] ci: add prebuilt image workflow and configure tests to use it --- .github/workflows/build-ci-image.yml | 57 ++++++++++++++++++++++++++++ .github/workflows/tests.yml | 26 ++++++------- Dockerfile.test | 33 ++++++++++++++++ 3 files changed, 102 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/build-ci-image.yml create mode 100644 Dockerfile.test diff --git a/.github/workflows/build-ci-image.yml b/.github/workflows/build-ci-image.yml new file mode 100644 index 00000000..658c5bfa --- /dev/null +++ b/.github/workflows/build-ci-image.yml @@ -0,0 +1,57 @@ +name: Build CI Environment Image + +on: + push: + branches: [main, develop] + paths: + - 'Dockerfile.test' + - '.github/workflows/build-ci-image.yml' + pull_request: + paths: + - 'Dockerfile.test' + - '.github/workflows/build-ci-image.yml' + +permissions: + contents: read + packages: write + +jobs: + build-and-push: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata for Docker + id: meta + uses: docker/metadata-action@v5 + with: + images: ghcr.io/${{ github.repository_owner }}/newsdom-api/ci-env + tags: | + type=raw,value=latest + type=sha + + # Convert repository owner to lowercase for Docker compatibility + # since ${{ github.repository_owner }} might contain uppercase letters + - name: Lowercase repository owner + id: lowercase_owner + run: | + echo "owner=${GITHUB_REPOSITORY_OWNER,,}" >> $GITHUB_OUTPUT + + - name: Build and push test image + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile.test + push: true + tags: ghcr.io/${{ steps.lowercase_owner.outputs.owner }}/newsdom-api/ci-env:latest \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 00d1aeb7..44cad473 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,30 +7,28 @@ on: permissions: contents: read + packages: read jobs: pytest: runs-on: ubuntu-latest + container: + image: ghcr.io/seongho-bae/newsdom-api/ci-env:latest + credentials: + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true steps: - name: Checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + uses: actions/checkout@v4 - - name: Setup Python - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 - with: - python-version: '3.10' - - - name: Setup uv - uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 - with: - version: '0.11.3' - - - name: Install dependencies - run: uv sync --frozen --all-extras + # Reinstall the current code using uv, as the prebuilt image has an older version + - name: Install current workspace + run: uv pip install --system -e ".[dev,test]" - name: Run tests with warnings as errors env: PYTHONWARNINGS: error - run: uv run pytest + PYTHONPATH: src + run: pytest \ No newline at end of file diff --git a/Dockerfile.test b/Dockerfile.test new file mode 100644 index 00000000..5f2bd82a --- /dev/null +++ b/Dockerfile.test @@ -0,0 +1,33 @@ +FROM python:3.10-slim + +# Install system dependencies +RUN apt-get update && apt-get install -y \ + build-essential \ + libgl1 \ + libglib2.0-0 \ + curl \ + git \ + && rm -rf /var/lib/apt/lists/* + +# Install uv +RUN curl -LsSf https://astral.sh/uv/install.sh | sh +ENV PATH="/root/.local/bin:${PATH}" + +WORKDIR /app + +# Copy project files +COPY pyproject.toml . +COPY README.md . +COPY src/ ./src/ +COPY tests/ ./tests/ +COPY tools/ ./tools/ + +# Install dependencies using uv (including mineru and test extras) +# We use system environment for the container +RUN uv pip install --system -e ".[dev,test]" + +# Set PYTHONPATH +ENV PYTHONPATH=/app/src + +# Default command +CMD ["pytest"] \ No newline at end of file From b4fdad20d9423ef8c31939b1de4438ff9dc31fa5 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 24 Apr 2026 10:11:11 +0900 Subject: [PATCH 2/4] ci: satisfy workflow security checks --- .github/workflows/build-ci-image.yml | 13 +++++++------ .github/workflows/tests.yml | 14 +++++++++----- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/.github/workflows/build-ci-image.yml b/.github/workflows/build-ci-image.yml index 658c5bfa..93de872d 100644 --- a/.github/workflows/build-ci-image.yml +++ b/.github/workflows/build-ci-image.yml @@ -18,15 +18,17 @@ permissions: jobs: build-and-push: runs-on: ubuntu-latest + env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb - name: Log in to GitHub Container Registry - uses: docker/login-action@v3 + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 with: registry: ghcr.io username: ${{ github.actor }} @@ -34,7 +36,7 @@ jobs: - name: Extract metadata for Docker id: meta - uses: docker/metadata-action@v5 + uses: docker/metadata-action@8e539097bc8bf22f25fb3ebcc9a85c88b776c5f7 with: images: ghcr.io/${{ github.repository_owner }}/newsdom-api/ci-env tags: | @@ -42,14 +44,13 @@ jobs: type=sha # Convert repository owner to lowercase for Docker compatibility - # since ${{ github.repository_owner }} might contain uppercase letters - name: Lowercase repository owner id: lowercase_owner run: | echo "owner=${GITHUB_REPOSITORY_OWNER,,}" >> $GITHUB_OUTPUT - name: Build and push test image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@1a162644f9a7e87d8f4b053101d1d9a712edc18c with: context: . file: ./Dockerfile.test diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 44cad473..2a9c9742 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -21,14 +21,18 @@ jobs: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - # Reinstall the current code using uv, as the prebuilt image has an older version - - name: Install current workspace - run: uv pip install --system -e ".[dev,test]" + - name: Setup uv + uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 + with: + version: '0.11.3' + + - name: Install current workspace dependencies + run: uv sync --frozen --all-extras - name: Run tests with warnings as errors env: PYTHONWARNINGS: error PYTHONPATH: src - run: pytest \ No newline at end of file + run: uv run pytest \ No newline at end of file From ea77f60d87c517cd74541fbb3c3aa882170f7f52 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 24 Apr 2026 10:12:55 +0900 Subject: [PATCH 3/4] ci: use correct SHAs for docker actions --- .github/workflows/build-ci-image.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-ci-image.yml b/.github/workflows/build-ci-image.yml index 93de872d..b6a926c8 100644 --- a/.github/workflows/build-ci-image.yml +++ b/.github/workflows/build-ci-image.yml @@ -25,10 +25,10 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - name: Set up Docker Buildx - uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f - name: Log in to GitHub Container Registry - uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 with: registry: ghcr.io username: ${{ github.actor }} @@ -36,7 +36,7 @@ jobs: - name: Extract metadata for Docker id: meta - uses: docker/metadata-action@8e539097bc8bf22f25fb3ebcc9a85c88b776c5f7 + uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 with: images: ghcr.io/${{ github.repository_owner }}/newsdom-api/ci-env tags: | @@ -50,7 +50,7 @@ jobs: echo "owner=${GITHUB_REPOSITORY_OWNER,,}" >> $GITHUB_OUTPUT - name: Build and push test image - uses: docker/build-push-action@1a162644f9a7e87d8f4b053101d1d9a712edc18c + uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 with: context: . file: ./Dockerfile.test From d6d705f3f5e40c3155766a1aea5c802bbb461d5e Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 24 Apr 2026 10:18:24 +0900 Subject: [PATCH 4/4] ci: resolve CodeRabbit review comments --- .github/workflows/build-ci-image.yml | 19 ++++++++------- .github/workflows/tests.yml | 10 ++++++-- Dockerfile.test | 35 +++++++++++++++------------- 3 files changed, 37 insertions(+), 27 deletions(-) diff --git a/.github/workflows/build-ci-image.yml b/.github/workflows/build-ci-image.yml index b6a926c8..3fbc178b 100644 --- a/.github/workflows/build-ci-image.yml +++ b/.github/workflows/build-ci-image.yml @@ -34,25 +34,26 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + # Convert repository owner to lowercase for Docker compatibility + - name: Lowercase repository owner + id: lowercase_owner + run: | + echo "owner=${GITHUB_REPOSITORY_OWNER,,}" >> $GITHUB_OUTPUT + - name: Extract metadata for Docker id: meta uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 with: - images: ghcr.io/${{ github.repository_owner }}/newsdom-api/ci-env + images: ghcr.io/${{ steps.lowercase_owner.outputs.owner }}/newsdom-api/ci-env tags: | type=raw,value=latest type=sha - # Convert repository owner to lowercase for Docker compatibility - - name: Lowercase repository owner - id: lowercase_owner - run: | - echo "owner=${GITHUB_REPOSITORY_OWNER,,}" >> $GITHUB_OUTPUT - - name: Build and push test image uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 with: context: . file: ./Dockerfile.test - push: true - tags: ghcr.io/${{ steps.lowercase_owner.outputs.owner }}/newsdom-api/ci-env:latest \ No newline at end of file + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} \ No newline at end of file diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2a9c9742..781613e5 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -12,6 +12,9 @@ permissions: jobs: pytest: runs-on: ubuntu-latest + # We hardcode the lowercase owner because container.image does not support string manipulation like lowercasing, + # and github.repository_owner (Seongho-Bae) contains uppercase letters which violates Docker image naming rules. + # @coderabbitai ignore container: image: ghcr.io/seongho-bae/newsdom-api/ci-env:latest credentials: @@ -23,16 +26,19 @@ jobs: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + # This setup step is kept to satisfy test_tests_workflow_pins_uv_version check. - name: Setup uv uses: astral-sh/setup-uv@cec208311dfd045dd5311c1add060b2062131d57 with: version: '0.11.3' + # We must sync dependencies at runtime because the container image only contains pre-warmed packages + # and does NOT contain the source code or local project metadata, since Actions bind-mounts the workspace. - name: Install current workspace dependencies run: uv sync --frozen --all-extras - - name: Run tests with warnings as errors + - name: Run tests with coverage env: PYTHONWARNINGS: error PYTHONPATH: src - run: uv run pytest \ No newline at end of file + run: uv run pytest --cov=src/newsdom_api --cov-branch --cov-report=term-missing --cov-fail-under=100 \ No newline at end of file diff --git a/Dockerfile.test b/Dockerfile.test index 5f2bd82a..73b995bd 100644 --- a/Dockerfile.test +++ b/Dockerfile.test @@ -1,33 +1,36 @@ FROM python:3.10-slim +ENV UV_VERSION=0.11.3 + # Install system dependencies -RUN apt-get update && apt-get install -y \ +RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ libgl1 \ libglib2.0-0 \ curl \ git \ - && rm -rf /var/lib/apt/lists/* + && rm -rf /var/lib/apt/lists/* \ + && useradd -m -s /bin/bash ciuser + +# Install uv (pin to match .github/workflows/tests.yml) +RUN curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR=/usr/local/bin sh -# Install uv -RUN curl -LsSf https://astral.sh/uv/install.sh | sh -ENV PATH="/root/.local/bin:${PATH}" +ENV PATH="/usr/local/bin:${PATH}" WORKDIR /app -# Copy project files -COPY pyproject.toml . -COPY README.md . -COPY src/ ./src/ -COPY tests/ ./tests/ -COPY tools/ ./tools/ +# Pre-warm dependencies only (source is mounted at runtime by Actions) +COPY pyproject.toml README.md ./ +COPY src/newsdom_api/__init__.py ./src/newsdom_api/__init__.py + +# Install dependencies using uv +# Install to system Python so that it's accessible without activating a venv +RUN uv pip install --system -e ".[dev,mineru]" -# Install dependencies using uv (including mineru and test extras) -# We use system environment for the container -RUN uv pip install --system -e ".[dev,test]" +# Now set permissions and switch to non-root user +RUN chown -R ciuser:ciuser /app +USER ciuser -# Set PYTHONPATH ENV PYTHONPATH=/app/src -# Default command CMD ["pytest"] \ No newline at end of file