From 63c5774cc57c734190bfcc0c28d2c6f5068bf66c Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 5 Feb 2026 09:35:20 +0000 Subject: [PATCH 01/13] Add Docker and Docker Compose support for dev and prod - Added `Dockerfile.backend` for Python/FastAPI backend (with uv and deno). - Added `web/Dockerfile` for React/Vite frontend (multi-stage: dev, build, prod). - Added `web/nginx.conf` for production serving of frontend. - Added `docker-compose.yml` for immutable production deployment. - Added `docker-compose.dev.yml` for local development with hot-reloading. - Added `DOCKER.md` with instructions. - Updated `web/vite.config.ts` to support dynamic API URL via env var. - Updated `README.md` to link to Docker guide. Co-authored-by: ngoyal16 <10145666+ngoyal16@users.noreply.github.com> --- DOCKER.md | 75 +++++ Dockerfile.backend | 38 +++ README.md | 2 + docker-compose.dev.yml | 22 ++ docker-compose.yml | 23 ++ web/Dockerfile | 25 ++ web/nginx.conf | 40 +++ web/package-lock.json | 664 +++++++++++++++++++++++++++++++++++++++++ web/vite.config.ts | 2 +- 9 files changed, 890 insertions(+), 1 deletion(-) create mode 100644 DOCKER.md create mode 100644 Dockerfile.backend create mode 100644 docker-compose.dev.yml create mode 100644 docker-compose.yml create mode 100644 web/Dockerfile create mode 100644 web/nginx.conf diff --git a/DOCKER.md b/DOCKER.md new file mode 100644 index 0000000..62ca516 --- /dev/null +++ b/DOCKER.md @@ -0,0 +1,75 @@ +# Docker Setup for AsyncReview + +This guide explains how to run AsyncReview using Docker, both for production (immutable usage) and local development. + +## Prerequisites + +- **Docker** and **Docker Compose** installed on your machine. +- A `.env` file with your API keys (see [README.md](README.md) or copy `.env.example`). + +## Quick Start (Production/User Mode) + +To run the application in a stable, immutable container environment: + +1. Ensure your `.env` file is populated. +2. Run: + +```bash +docker compose up --build +``` + +- The Web UI will be available at: http://localhost:3000 +- The Backend API will be available at: http://localhost:8000 + +To stop the application: +```bash +docker compose down +``` + +## Local Development + +To run the application in development mode with hot-reloading (changes to your code are immediately reflected): + +1. Run: + +```bash +docker compose -f docker-compose.yml -f docker-compose.dev.yml up --build +``` + +- The Web UI (Vite dev server) will be available at: http://localhost:5173 +- The Backend API (Uvicorn with reload) will be available at: http://localhost:8000 + +*Note: In development mode, the `web/` directory and the root directory are mounted into the containers. Changes you make locally will trigger reloads.* + +## Running CLI Commands + +You can run the `cr` CLI tool inside the backend container. + +**In Production Mode:** +```bash +docker compose run --rm backend cr --help +docker compose run --rm backend cr review --url https://github.com/org/repo/pull/123 +``` + +**In Development Mode:** +```bash +docker compose -f docker-compose.yml -f docker-compose.dev.yml run --rm backend cr --help +``` + +## Troubleshooting + +### Port Conflicts +If port 3000, 8000, or 5173 are in use, you can modify the ports in `docker-compose.yml` or `docker-compose.dev.yml`. + +### Deno/Pyodide Issues +The backend container installs Deno and caches the Pyodide environment during the build. If you encounter issues, try rebuilding: +```bash +docker compose build --no-cache backend +``` + +### Dependencies +If you add new Python dependencies to `pyproject.toml`, you must rebuild the backend container: +```bash +docker compose build backend +``` +In development mode, since the source is mounted but dependencies are installed in the system python path, a rebuild is usually required to install new dependencies. diff --git a/Dockerfile.backend b/Dockerfile.backend new file mode 100644 index 0000000..1ecf053 --- /dev/null +++ b/Dockerfile.backend @@ -0,0 +1,38 @@ +# Base image +FROM python:3.11-slim + +# Install system dependencies +RUN apt-get update && apt-get install -y \ + curl \ + unzip \ + && rm -rf /var/lib/apt/lists/* + +# Install uv +RUN curl -LsSf https://astral.sh/uv/install.sh | sh +ENV PATH="/root/.cargo/bin:$PATH" + +# Install Deno +ENV DENO_INSTALL="/root/.deno" +RUN curl -fsSL https://deno.land/install.sh | sh +ENV PATH="$DENO_INSTALL/bin:$PATH" + +# Set working directory +WORKDIR /app + +# Copy project files +COPY pyproject.toml README.md ./ +COPY cr/ ./cr/ +COPY cli/ ./cli/ + +# Install python dependencies +# We use --system to install into the container's system python environment +RUN uv pip install --system . + +# Cache Deno dependencies +RUN deno cache npm:pyodide/pyodide.js + +# Expose port +EXPOSE 8000 + +# Default command +CMD ["uvicorn", "cr.server:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/README.md b/README.md index e34a981..8e04749 100644 --- a/README.md +++ b/README.md @@ -120,6 +120,8 @@ If you prefer manual configuration, point your agent to the skill definition fil To run the full backend server or web interface locally, please see the [Installation Guide](INSTALLATION.md). +To run using **Docker**, see the [Docker Guide](DOCKER.md). + ## License MIT diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 0000000..143d8d9 --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,22 @@ +services: + backend: + volumes: + - ./:/app + # Use anonymous volumes to prevent host directories from overwriting container directories + - /app/.venv + - /app/.deno + command: uvicorn cr.server:app --reload --host 0.0.0.0 --port 8000 + environment: + - WATCHFILES_FORCE_POLLING=true + + frontend: + build: + target: dev + volumes: + - ./web:/app + - /app/node_modules + ports: + - "5173:5173" + environment: + - API_URL=http://backend:8000 + command: npm run dev -- --host diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..d20d6a2 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,23 @@ +services: + backend: + build: + context: . + dockerfile: Dockerfile.backend + ports: + - "8000:8000" + env_file: + - .env + environment: + - PYTHONUNBUFFERED=1 + restart: unless-stopped + + frontend: + build: + context: ./web + dockerfile: Dockerfile + target: prod + ports: + - "3000:80" + depends_on: + - backend + restart: unless-stopped diff --git a/web/Dockerfile b/web/Dockerfile new file mode 100644 index 0000000..a743189 --- /dev/null +++ b/web/Dockerfile @@ -0,0 +1,25 @@ +# Base stage +FROM node:20-alpine AS base +WORKDIR /app +COPY package*.json ./ +RUN npm ci + +# Development stage +FROM base AS dev +# Expose default Vite port +EXPOSE 5173 +# Command to run dev server, binding to all interfaces +CMD ["npm", "run", "dev", "--", "--host"] + +# Build stage +FROM base AS build +COPY . . +RUN npm run build + +# Production stage +FROM nginx:alpine AS prod +COPY --from=build /app/dist /usr/share/nginx/html +# We will copy a custom nginx config to handle SPA routing and API proxying +COPY nginx.conf /etc/nginx/conf.d/default.conf +EXPOSE 80 +CMD ["nginx", "-g", "daemon off;"] diff --git a/web/nginx.conf b/web/nginx.conf new file mode 100644 index 0000000..24eb313 --- /dev/null +++ b/web/nginx.conf @@ -0,0 +1,40 @@ +server { + listen 80; + server_name localhost; + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + # Support SPA routing (redirect to index.html for non-existent files) + try_files $uri $uri/ /index.html; + } + + # Proxy API requests to the backend service + location /api/ { + proxy_pass http://backend:8000/api/; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # Support SSE (Server Sent Events) + proxy_buffering off; + proxy_cache off; + proxy_set_header Connection ''; + proxy_http_version 1.1; + chunked_transfer_encoding off; + } + + # Health check + location /health { + proxy_pass http://backend:8000/health; + } + + # Docs + location /docs { + proxy_pass http://backend:8000/docs; + } + location /openapi.json { + proxy_pass http://backend:8000/openapi.json; + } +} diff --git a/web/package-lock.json b/web/package-lock.json index 0209729..36df989 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -456,6 +456,70 @@ "node": ">=18" } }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@esbuild/darwin-arm64": { "version": "0.21.5", "cpu": [ @@ -470,6 +534,294 @@ "node": ">=12" } }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "license": "MIT", @@ -526,6 +878,32 @@ "version": "1.0.0-beta.27", "license": "MIT" }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.56.0.tgz", + "integrity": "sha512-LNKIPA5k8PF1+jAFomGe3qN3bbIgJe/IlpDBwuVjrDKrJhVWywgnJvflMt/zkbVNLFtF1+94SljYQS6e99klnw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.56.0.tgz", + "integrity": "sha512-lfbVUbelYqXlYiU/HApNMJzT1E87UPGvzveGg2h0ktUNlOCxKlWuJ9jtfvs1sKHdwU4fzY7Pl8sAl49/XaEk6Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.56.0", "cpu": [ @@ -537,6 +915,292 @@ "darwin" ] }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.56.0.tgz", + "integrity": "sha512-1vXe1vcMOssb/hOF8iv52A7feWW2xnu+c8BV4t1F//m9QVLTfNVpEdja5ia762j/UEJe2Z1jAmEqZAK42tVW3g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.56.0.tgz", + "integrity": "sha512-bof7fbIlvqsyv/DtaXSck4VYQ9lPtoWNFCB/JY4snlFuJREXfZnm+Ej6yaCHfQvofJDXLDMTVxWscVSuQvVWUQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.56.0.tgz", + "integrity": "sha512-KNa6lYHloW+7lTEkYGa37fpvPq+NKG/EHKM8+G/g9WDU7ls4sMqbVRV78J6LdNuVaeeK5WB9/9VAFbKxcbXKYg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.56.0.tgz", + "integrity": "sha512-E8jKK87uOvLrrLN28jnAAAChNq5LeCd2mGgZF+fGF5D507WlG/Noct3lP/QzQ6MrqJ5BCKNwI9ipADB6jyiq2A==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.56.0.tgz", + "integrity": "sha512-jQosa5FMYF5Z6prEpTCCmzCXz6eKr/tCBssSmQGEeozA9tkRUty/5Vx06ibaOP9RCrW1Pvb8yp3gvZhHwTDsJw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.56.0.tgz", + "integrity": "sha512-uQVoKkrC1KGEV6udrdVahASIsaF8h7iLG0U0W+Xn14ucFwi6uS539PsAr24IEF9/FoDtzMeeJXJIBo5RkbNWvQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.56.0.tgz", + "integrity": "sha512-vLZ1yJKLxhQLFKTs42RwTwa6zkGln+bnXc8ueFGMYmBTLfNu58sl5/eXyxRa2RarTkJbXl8TKPgfS6V5ijNqEA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.56.0.tgz", + "integrity": "sha512-FWfHOCub564kSE3xJQLLIC/hbKqHSVxy8vY75/YHHzWvbJL7aYJkdgwD/xGfUlL5UV2SB7otapLrcCj2xnF1dg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.56.0.tgz", + "integrity": "sha512-z1EkujxIh7nbrKL1lmIpqFTc/sr0u8Uk0zK/qIEFldbt6EDKWFk/pxFq3gYj4Bjn3aa9eEhYRlL3H8ZbPT1xvA==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.56.0.tgz", + "integrity": "sha512-iNFTluqgdoQC7AIE8Q34R3AuPrJGJirj5wMUErxj22deOcY7XwZRaqYmB6ZKFHoVGqRcRd0mqO+845jAibKCkw==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.56.0.tgz", + "integrity": "sha512-MtMeFVlD2LIKjp2sE2xM2slq3Zxf9zwVuw0jemsxvh1QOpHSsSzfNOTH9uYW9i1MXFxUSMmLpeVeUzoNOKBaWg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.56.0.tgz", + "integrity": "sha512-in+v6wiHdzzVhYKXIk5U74dEZHdKN9KH0Q4ANHOTvyXPG41bajYRsy7a8TPKbYPl34hU7PP7hMVHRvv/5aCSew==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.56.0.tgz", + "integrity": "sha512-yni2raKHB8m9NQpI9fPVwN754mn6dHQSbDTwxdr9SE0ks38DTjLMMBjrwvB5+mXrX+C0npX0CVeCUcvvvD8CNQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.56.0.tgz", + "integrity": "sha512-zhLLJx9nQPu7wezbxt2ut+CI4YlXi68ndEve16tPc/iwoylWS9B3FxpLS2PkmfYgDQtosah07Mj9E0khc3Y+vQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.56.0.tgz", + "integrity": "sha512-MVC6UDp16ZSH7x4rtuJPAEoE1RwS8N4oK9DLHy3FTEdFoUTCFVzMfJl/BVJ330C+hx8FfprA5Wqx4FhZXkj2Kw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.56.0.tgz", + "integrity": "sha512-ZhGH1eA4Qv0lxaV00azCIS1ChedK0V32952Md3FtnxSqZTBTd6tgil4nZT5cU8B+SIw3PFYkvyR4FKo2oyZIHA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.56.0.tgz", + "integrity": "sha512-O16XcmyDeFI9879pEcmtWvD/2nyxR9mF7Gs44lf1vGGx8Vg2DRNx11aVXBEqOQhWb92WN4z7fW/q4+2NYzCbBA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.56.0.tgz", + "integrity": "sha512-LhN/Reh+7F3RCgQIRbgw8ZMwUwyqJM+8pXNT6IIJAqm2IdKkzpCh/V9EdgOMBKuebIrzswqy4ATlrDgiOwbRcQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.56.0.tgz", + "integrity": "sha512-kbFsOObXp3LBULg1d3JIUQMa9Kv4UitDmpS+k0tinPBz3watcUiV2/LUDMMucA6pZO3WGE27P7DsfaN54l9ing==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.56.0.tgz", + "integrity": "sha512-vSSgny54D6P4vf2izbtFm/TcWYedw7f8eBrOiGGecyHyQB9q4Kqentjaj8hToe+995nob/Wv48pDqL5a62EWtg==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.56.0.tgz", + "integrity": "sha512-FeCnkPCTHQJFbiGG49KjV5YGW/8b9rrXAM2Mz2kiIoktq2qsJxRD5giEMEOD2lPdgs72upzefaUvS+nc8E3UzQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.56.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.56.0.tgz", + "integrity": "sha512-H8AE9Ur/t0+1VXujj90w0HrSOuv0Nq9r1vSZF2t5km20NTfosQsGGUXDaKdQZzwuLts7IyL1fYT4hM95TI9c4g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@shikijs/core": { "version": "3.21.0", "license": "MIT", diff --git a/web/vite.config.ts b/web/vite.config.ts index dc0602a..eba9623 100644 --- a/web/vite.config.ts +++ b/web/vite.config.ts @@ -7,7 +7,7 @@ export default defineConfig({ port: 3000, proxy: { '/api': { - target: 'http://localhost:8000', + target: process.env.API_URL || 'http://localhost:8000', changeOrigin: true, }, }, From 0d71ba188c21232060a3c72f3b9b492c902932d5 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 5 Feb 2026 09:44:42 +0000 Subject: [PATCH 02/13] Add Docker and Docker Compose support for dev and prod - Added `Dockerfile.backend` for Python/FastAPI backend (with uv and deno). - Added `web/Dockerfile` for React/Vite frontend (multi-stage: dev, build, prod). - Added `web/nginx.conf` for production serving of frontend. - Added `docker-compose.yml` for immutable production deployment (Frontend on port 3000 proxies to Backend). - Added `docker-compose.dev.yml` for local development (Hot-reload, ports 3000 and 8000 exposed). - Updated `Makefile` with `docker-up` and `docker-dev` convenience targets. - Added `DOCKER.md` with detailed instructions. - Updated `web/vite.config.ts` to support dynamic API URL via env var. - Updated `README.md` to link to Docker guide. Co-authored-by: ngoyal16 <10145666+ngoyal16@users.noreply.github.com> --- DOCKER.md | 28 ++++++++++++++++++++-------- Makefile | 25 +++++++++++++++++++++++-- docker-compose.dev.yml | 2 ++ docker-compose.yml | 2 -- 4 files changed, 45 insertions(+), 12 deletions(-) diff --git a/DOCKER.md b/DOCKER.md index 62ca516..8be3216 100644 --- a/DOCKER.md +++ b/DOCKER.md @@ -7,19 +7,28 @@ This guide explains how to run AsyncReview using Docker, both for production (im - **Docker** and **Docker Compose** installed on your machine. - A `.env` file with your API keys (see [README.md](README.md) or copy `.env.example`). +**Note:** You *must* create a `.env` file before running any Docker commands. +```bash +cp .env.example .env +# Edit .env and add your GEMINI_API_KEY +``` + ## Quick Start (Production/User Mode) -To run the application in a stable, immutable container environment: +To run the application in a stable, immutable container environment using the convenience Makefile command: -1. Ensure your `.env` file is populated. -2. Run: +```bash +make docker-up +``` +Alternatively, using Docker Compose directly: ```bash docker compose up --build ``` -- The Web UI will be available at: http://localhost:3000 -- The Backend API will be available at: http://localhost:8000 +- **Web UI:** http://localhost:3000 +- **API:** Proxied via the Web UI at http://localhost:3000/api + - Note: The backend service is not directly exposed to the host in production mode. To stop the application: ```bash @@ -30,14 +39,17 @@ docker compose down To run the application in development mode with hot-reloading (changes to your code are immediately reflected): -1. Run: +```bash +make docker-dev +``` +Alternatively, using Docker Compose directly (requires both files): ```bash docker compose -f docker-compose.yml -f docker-compose.dev.yml up --build ``` -- The Web UI (Vite dev server) will be available at: http://localhost:5173 -- The Backend API (Uvicorn with reload) will be available at: http://localhost:8000 +- **Web UI:** http://localhost:5173 (Vite dev server) +- **API:** http://localhost:8000 (Direct access for debugging) *Note: In development mode, the `web/` directory and the root directory are mounted into the containers. Changes you make locally will trigger reloads.* diff --git a/Makefile b/Makefile index bb1ec52..684e536 100644 --- a/Makefile +++ b/Makefile @@ -8,12 +8,16 @@ # make all - Build, install, and test # make clean - Clean build artifacts # +# Docker Usage: +# make docker-up - Run production environment (User mode) +# make docker-dev - Run development environment (Hot-reload) +# # Version Management: # make bump-patch - Bump patch version (0.5.0 -> 0.5.1) # make bump-minor - Bump minor version (0.5.0 -> 0.6.0) # make bump-major - Bump major version (0.5.0 -> 1.0.0) -.PHONY: all build install test publish clean bump-patch bump-minor bump-major version +.PHONY: all build install test publish clean bump-patch bump-minor bump-major version docker-up docker-dev # Version file - single source of truth VERSION_FILE := VERSION @@ -75,6 +79,20 @@ clean: @rm -rf .runtime_stage @echo "Done." +# ============================================================ +# Docker Helpers +# ============================================================ + +docker-up: + @if [ ! -f .env ]; then echo "Error: .env file not found. Copy .env.example to .env and fill in API keys."; exit 1; fi + @echo "==> Starting AsyncReview in Production Mode (Immutable)..." + @docker compose up --build + +docker-dev: + @if [ ! -f .env ]; then echo "Error: .env file not found. Copy .env.example to .env and fill in API keys."; exit 1; fi + @echo "==> Starting AsyncReview in Development Mode (Hot-Reload)..." + @docker compose -f docker-compose.yml -f docker-compose.dev.yml up --build + # ============================================================ # Version Management # ============================================================ @@ -171,6 +189,10 @@ publish-npm: $(VERSION_FILE) help: @echo "AsyncReview Runtime Build System" @echo "" + @echo "Docker Commands (Preferred):" + @echo " make docker-up - Run production environment (User mode)" + @echo " make docker-dev - Run development environment (Hot-reload)" + @echo "" @echo "Build Commands:" @echo " make build - Build runtime v$(VERSION) for $(PLATFORM)" @echo " make install - Install built runtime locally" @@ -197,4 +219,3 @@ help: @echo "Dev Commands:" @echo " make build-npx - Build TypeScript only" @echo " make dev URL=... Q=... - Run dev mode" - diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 143d8d9..4de34f7 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -6,6 +6,8 @@ services: - /app/.venv - /app/.deno command: uvicorn cr.server:app --reload --host 0.0.0.0 --port 8000 + ports: + - "8000:8000" environment: - WATCHFILES_FORCE_POLLING=true diff --git a/docker-compose.yml b/docker-compose.yml index d20d6a2..6b20cf0 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -3,8 +3,6 @@ services: build: context: . dockerfile: Dockerfile.backend - ports: - - "8000:8000" env_file: - .env environment: From 45e225a6cb7293543671206e3d76b2f598d2fd4d Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Thu, 5 Feb 2026 09:48:28 +0000 Subject: [PATCH 03/13] Add Docker and Docker Compose support for dev and prod - Added `Dockerfile.backend` for Python/FastAPI backend (with uv and deno). - Added `web/Dockerfile` for React/Vite frontend (multi-stage: dev, build, prod). - Added `web/nginx.conf` for production serving of frontend. - Added `docker-compose.yml` for immutable production deployment (Frontend on port 3000 proxies to Backend). - Added `docker-compose.dev.yml` for local development (Hot-reload, ports 3000 and 8000 exposed). - Updated `Makefile` with `docker-up` and `docker-dev` convenience targets. - Added `DOCKER.md` with detailed instructions. - Updated `web/vite.config.ts` to support dynamic API URL via env var. - Updated `README.md` to link to Docker guide. - Fixed TypeScript errors in `web/src/components/PRSummary.tsx` and `web/src/types.ts`. Co-authored-by: ngoyal16 <10145666+ngoyal16@users.noreply.github.com> --- web/src/components/PRSummary.tsx | 2 +- web/src/types.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/web/src/components/PRSummary.tsx b/web/src/components/PRSummary.tsx index 927929b..df20969 100644 --- a/web/src/components/PRSummary.tsx +++ b/web/src/components/PRSummary.tsx @@ -104,7 +104,7 @@ export function PRSummary({ prInfo }: PRSummaryProps) { {activeTab === 'commits' && (