2025-11-01 10:47:02 -04:00
|
|
|
|
# CICD Complete Setup - Optimized Build Order for Maximum Caching
|
|
|
|
|
|
# OPTIMIZATION STRATEGY:
|
|
|
|
|
|
# Phase 1: Extract dependency files (package.json, pyproject.toml)
|
|
|
|
|
|
# Phase 2: Install dependencies (cached layer, only invalidates when deps change)
|
|
|
|
|
|
# Phase 3: Clone full source code (doesn't bust dependency cache)
|
|
|
|
|
|
# Phase 4-6: Install packages and verify (requires full source)
|
|
|
|
|
|
#
|
|
|
|
|
|
# BENEFITS: Dependency installation ~20-30 minutes is cached across source code changes
|
2026-06-18 11:19:24 -04:00
|
|
|
|
ARG CICD_BASE_IMAGE=kankali.darkhelm.lan:3001/darkhelm.org/plex-playlist-cicd-base:latest
|
2025-10-31 09:09:46 -04:00
|
|
|
|
FROM ${CICD_BASE_IMAGE}
|
2025-10-27 08:39:54 -04:00
|
|
|
|
|
2025-10-29 16:01:39 -04:00
|
|
|
|
# Build args for cache busting
|
|
|
|
|
|
ARG GITHUB_SHA
|
|
|
|
|
|
ENV GITHUB_SHA=${GITHUB_SHA}
|
2026-06-18 11:19:24 -04:00
|
|
|
|
LABEL org.opencontainers.image.revision=${GITHUB_SHA}
|
2025-10-29 16:01:39 -04:00
|
|
|
|
|
2025-10-27 15:30:11 -04:00
|
|
|
|
# Accept build arguments for Git checkout (no secrets here!)
|
2025-10-27 08:59:27 -04:00
|
|
|
|
ARG GITHUB_SHA
|
|
|
|
|
|
|
2025-10-27 08:39:54 -04:00
|
|
|
|
# Set working directory
|
|
|
|
|
|
WORKDIR /workspace
|
|
|
|
|
|
|
2025-11-01 10:47:02 -04:00
|
|
|
|
# OPTIMIZATION: Extract dependency files first for better layer caching
|
|
|
|
|
|
# Step 1: Clone repository minimally to get dependency files only
|
2025-10-27 15:30:11 -04:00
|
|
|
|
RUN --mount=type=secret,id=ssh_private_key \
|
|
|
|
|
|
mkdir -p ~/.ssh && \
|
|
|
|
|
|
cp /run/secrets/ssh_private_key ~/.ssh/id_rsa && \
|
|
|
|
|
|
chmod 600 ~/.ssh/id_rsa && \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
echo "Host kankali.darkhelm.lan" > ~/.ssh/config && \
|
2025-10-27 15:30:11 -04:00
|
|
|
|
echo " Port 2222" >> ~/.ssh/config && \
|
|
|
|
|
|
echo " StrictHostKeyChecking no" >> ~/.ssh/config && \
|
|
|
|
|
|
echo " UserKnownHostsFile /dev/null" >> ~/.ssh/config && \
|
|
|
|
|
|
chmod 600 ~/.ssh/config && \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
(ssh-keyscan -p 2222 kankali.darkhelm.lan >> ~/.ssh/known_hosts 2>/dev/null || echo "Warning: ssh-keyscan failed, continuing with StrictHostKeyChecking=no") && \
|
2025-11-01 10:47:02 -04:00
|
|
|
|
echo "=== Extracting dependency files for optimized caching ===" && \
|
2025-10-27 15:30:11 -04:00
|
|
|
|
GIT_SSH_COMMAND="ssh -F ~/.ssh/config" \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
git -c core.autocrlf=false -c core.eol=lf clone --depth 1 --branch main \
|
|
|
|
|
|
ssh://git@kankali.darkhelm.lan:2222/DarkHelm.org/plex-playlist.git /tmp/repo && \
|
|
|
|
|
|
git -C /tmp/repo config core.autocrlf false && \
|
|
|
|
|
|
git -C /tmp/repo config core.eol lf && \
|
2025-10-27 08:59:27 -04:00
|
|
|
|
if [ -n "$GITHUB_SHA" ]; then \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
cd /tmp/repo && \
|
|
|
|
|
|
if GIT_SSH_COMMAND="ssh -F ~/.ssh/config" git fetch --depth 1 origin "$GITHUB_SHA" >/tmp/git-fetch-sha.log 2>&1 && \
|
|
|
|
|
|
git checkout "$GITHUB_SHA" >/tmp/git-checkout-sha.log 2>&1; then \
|
|
|
|
|
|
echo "✓ Checked out requested GITHUB_SHA: $GITHUB_SHA"; \
|
|
|
|
|
|
else \
|
|
|
|
|
|
echo "❌ Failed to checkout requested GITHUB_SHA: $GITHUB_SHA"; \
|
|
|
|
|
|
echo "--- git fetch output ---"; \
|
|
|
|
|
|
cat /tmp/git-fetch-sha.log 2>/dev/null || true; \
|
|
|
|
|
|
echo "--- git checkout output ---"; \
|
|
|
|
|
|
cat /tmp/git-checkout-sha.log 2>/dev/null || true; \
|
|
|
|
|
|
exit 1; \
|
|
|
|
|
|
fi; \
|
2025-10-27 15:30:11 -04:00
|
|
|
|
fi && \
|
2025-11-01 10:47:02 -04:00
|
|
|
|
# Extract only dependency files for caching optimization
|
|
|
|
|
|
mkdir -p /workspace/backend /workspace/frontend && \
|
|
|
|
|
|
cp /tmp/repo/backend/pyproject.toml /workspace/backend/ 2>/dev/null || echo "No backend pyproject.toml" && \
|
|
|
|
|
|
cp /tmp/repo/frontend/package.json /workspace/frontend/ 2>/dev/null || echo "No frontend package.json" && \
|
|
|
|
|
|
cp /tmp/repo/frontend/yarn.lock /workspace/frontend/ 2>/dev/null || echo "No frontend yarn.lock" && \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
cp /tmp/repo/frontend/.yarnrc.yml /workspace/frontend/ 2>/dev/null || echo "No frontend .yarnrc.yml" && \
|
2025-11-01 10:47:02 -04:00
|
|
|
|
cp /tmp/repo/.pre-commit-config.yaml /workspace/ 2>/dev/null || echo "No pre-commit config" && \
|
2026-06-19 17:00:57 -04:00
|
|
|
|
cp /tmp/repo/.markdownlint.yaml /workspace/ 2>/dev/null || echo "No markdownlint config" && \
|
2025-11-01 10:47:02 -04:00
|
|
|
|
echo "✓ Dependency files extracted for optimized layer caching" && \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
rm -rf ~/.ssh
|
2025-10-27 08:39:54 -04:00
|
|
|
|
|
2025-11-01 10:47:02 -04:00
|
|
|
|
# OPTIMIZATION PHASE 1: Install backend dependencies from extracted pyproject.toml
|
2025-10-27 08:39:54 -04:00
|
|
|
|
WORKDIR /workspace/backend
|
|
|
|
|
|
ENV VIRTUAL_ENV=/workspace/backend/.venv
|
|
|
|
|
|
|
2025-11-01 10:47:02 -04:00
|
|
|
|
# Install backend dependencies first (before source code) for better caching
|
|
|
|
|
|
RUN echo "=== Installing Backend Dependencies (Phase 1: Optimized Caching) ===" && \
|
2025-10-31 18:42:23 -04:00
|
|
|
|
# Create project virtual environment
|
2025-10-31 11:25:34 -04:00
|
|
|
|
uv venv $VIRTUAL_ENV && \
|
2025-10-31 18:42:23 -04:00
|
|
|
|
# Check if base image optimization is available
|
|
|
|
|
|
echo "=== Base Image Optimization Status ===" && \
|
|
|
|
|
|
if [ -f "/opt/python-dev-tools/bin/python" ]; then \
|
|
|
|
|
|
echo "✓ Found pre-installed Python dev tools - leveraging cache" && \
|
|
|
|
|
|
uv pip list --python /opt/python-dev-tools/bin/python --format=freeze > /tmp/base-tools.txt && \
|
|
|
|
|
|
echo "Available pre-installed tools:" && \
|
|
|
|
|
|
head -10 /tmp/base-tools.txt; \
|
|
|
|
|
|
else \
|
|
|
|
|
|
echo "⚠ Pre-installed Python dev tools not found - fresh installation" && \
|
|
|
|
|
|
echo "Base image may need rebuild for optimal caching"; \
|
|
|
|
|
|
fi && \
|
2025-11-01 10:47:02 -04:00
|
|
|
|
# Install dependencies from extracted pyproject.toml (this layer will cache!)
|
|
|
|
|
|
if [ -f "pyproject.toml" ]; then \
|
|
|
|
|
|
echo "Installing project dependencies from pyproject.toml..." && \
|
2025-11-01 11:20:56 -04:00
|
|
|
|
# Create minimal source structure to satisfy package build requirements
|
|
|
|
|
|
mkdir -p src/backend && \
|
|
|
|
|
|
echo "# Temporary README for dependency caching phase" > ../README.md && \
|
|
|
|
|
|
echo "# Minimal __init__.py for build" > src/backend/__init__.py && \
|
|
|
|
|
|
# Install all dependencies including dev dependencies
|
2025-11-01 10:47:02 -04:00
|
|
|
|
uv sync --dev && \
|
|
|
|
|
|
echo "✓ Backend dependencies installed and cached"; \
|
2025-10-31 11:25:34 -04:00
|
|
|
|
else \
|
2025-11-01 10:47:02 -04:00
|
|
|
|
echo "No pyproject.toml found, skipping dependency installation"; \
|
2025-10-31 11:25:34 -04:00
|
|
|
|
fi
|
2025-10-30 10:02:17 -04:00
|
|
|
|
|
2025-11-01 10:47:02 -04:00
|
|
|
|
ENV PATH="$VIRTUAL_ENV/bin:$PATH"
|
|
|
|
|
|
|
|
|
|
|
|
# OPTIMIZATION PHASE 2: Install frontend dependencies from extracted package.json
|
2025-10-27 08:39:54 -04:00
|
|
|
|
WORKDIR /workspace/frontend
|
2025-10-28 09:30:12 -04:00
|
|
|
|
|
2025-11-01 10:47:02 -04:00
|
|
|
|
# Setup frontend environment and install dependencies (before source code) for better caching
|
|
|
|
|
|
RUN echo "=== Installing Frontend Dependencies (Phase 2: Optimized Caching) ===" && \
|
2025-10-31 12:48:40 -04:00
|
|
|
|
echo "Available global tools (installed via npm):" && \
|
|
|
|
|
|
npm list -g --depth=0 2>/dev/null | head -10 || echo "Global npm tools available" && \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
which tsc && which eslint && which prettier || echo "Global tools verified"
|
2025-10-28 09:30:12 -04:00
|
|
|
|
|
2025-11-01 10:47:02 -04:00
|
|
|
|
# Install frontend dependencies from extracted package.json (this layer will cache!)
|
|
|
|
|
|
RUN if [ -f "package.json" ]; then \
|
|
|
|
|
|
echo "Installing frontend dependencies from extracted package.json..." && \
|
|
|
|
|
|
export NODE_OPTIONS="--max-old-space-size=1024 --max-semi-space-size=64" && \
|
|
|
|
|
|
export UV_WORKERS=1 && \
|
|
|
|
|
|
echo "Memory info before install:" && \
|
|
|
|
|
|
free -h || true && \
|
|
|
|
|
|
INSTALL_SUCCESS=false && \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
echo "Attempt 1/1: Installing project-specific frontend dependencies..." && \
|
|
|
|
|
|
echo "(Common dev tools pre-installed globally for performance)" && \
|
|
|
|
|
|
timeout 1200 yarn install --immutable --mode=skip-build \
|
|
|
|
|
|
&& INSTALL_SUCCESS=true || \
|
|
|
|
|
|
(echo "Attempt failed, cleaning up..." && \
|
|
|
|
|
|
rm -rf node_modules .yarn/cache .yarn/install-state.gz && \
|
|
|
|
|
|
yarn cache clean --all 2>/dev/null || true) && \
|
2025-11-01 10:47:02 -04:00
|
|
|
|
rm -rf .yarn/cache && \
|
|
|
|
|
|
if [ "$INSTALL_SUCCESS" = "false" ]; then \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
echo "WARNING: Frontend dependencies installation failed"; \
|
2025-11-01 10:47:02 -04:00
|
|
|
|
echo "Continuing without frontend dependencies for CI/CD environment"; \
|
|
|
|
|
|
touch .frontend-deps-failed; \
|
|
|
|
|
|
else \
|
|
|
|
|
|
echo "✓ Frontend dependencies installed and cached"; \
|
|
|
|
|
|
fi; \
|
|
|
|
|
|
else \
|
|
|
|
|
|
echo "No package.json found, skipping frontend dependencies"; \
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
2026-06-18 11:19:24 -04:00
|
|
|
|
# OPTIMIZATION PHASE 3: Reuse the repo cloned in phase 1 to avoid re-clone/session timeout
|
2025-11-01 10:47:02 -04:00
|
|
|
|
WORKDIR /workspace
|
2026-06-18 11:19:24 -04:00
|
|
|
|
RUN if [ ! -d "/tmp/repo/.git" ]; then \
|
|
|
|
|
|
echo "❌ Missing /tmp/repo clone from phase 1" && \
|
|
|
|
|
|
exit 1; \
|
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
|
|
RUN echo "Copying source code while preserving installed dependencies..." && \
|
2025-11-01 13:03:18 -04:00
|
|
|
|
echo "Source files in repo:" && \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
ls -la /tmp/repo/ && \
|
2025-11-01 13:03:18 -04:00
|
|
|
|
echo "Current workspace state:" && \
|
|
|
|
|
|
find /workspace -name "node_modules" -o -name ".venv" -o -name ".yarn" && \
|
|
|
|
|
|
echo "Copying source files (excluding dependencies)..." && \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
for item in /tmp/repo/*; do \
|
2025-11-01 13:03:18 -04:00
|
|
|
|
basename_item=$(basename "$item"); \
|
|
|
|
|
|
if [ "$basename_item" = "backend" ] && [ -d "/workspace/backend/.venv" ]; then \
|
|
|
|
|
|
echo "Copying backend files while preserving .venv..."; \
|
|
|
|
|
|
find "$item" -mindepth 1 -maxdepth 1 ! -name ".venv" -exec cp -rf {} /workspace/backend/ \;; \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
elif [ "$basename_item" = "frontend" ] && [ -d "/workspace/frontend/node_modules" ]; then \
|
|
|
|
|
|
echo "Copying frontend files (including dotfiles) while preserving node_modules..."; \
|
|
|
|
|
|
find "$item" -mindepth 1 -maxdepth 1 ! -name "node_modules" -exec cp -rf {} /workspace/frontend/ \;; \
|
2025-11-01 13:03:18 -04:00
|
|
|
|
else \
|
|
|
|
|
|
echo "Copying $basename_item..."; \
|
|
|
|
|
|
cp -rf "$item" /workspace/; \
|
|
|
|
|
|
fi; \
|
|
|
|
|
|
done && \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
# Copy common hidden root files without touching . or ..
|
2026-06-19 17:00:57 -04:00
|
|
|
|
for dotfile in .dockerignore .gitignore .pre-commit-config.yaml .markdownlint.yaml .editorconfig; do \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
if [ -f "/tmp/repo/${dotfile}" ]; then \
|
|
|
|
|
|
cp -f "/tmp/repo/${dotfile}" /workspace/; \
|
|
|
|
|
|
fi; \
|
|
|
|
|
|
done && \
|
2025-11-01 13:03:18 -04:00
|
|
|
|
echo "Final dependency check:" && \
|
|
|
|
|
|
find /workspace -name "node_modules" -o -name ".venv" -o -name ".yarn" && \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
if [ -n "${GITHUB_SHA}" ]; then \
|
|
|
|
|
|
echo "${GITHUB_SHA}" > /workspace/.cicd-source-sha; \
|
|
|
|
|
|
fi && \
|
2025-11-01 10:47:02 -04:00
|
|
|
|
echo "✓ Full source code copied, dependencies preserved" && \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
rm -rf /tmp/repo
|
2025-11-01 10:47:02 -04:00
|
|
|
|
|
2026-06-18 11:19:24 -04:00
|
|
|
|
# PHASE 3.5: Re-link Yarn after source code update (node-modules linker only)
|
2025-11-01 16:13:30 -04:00
|
|
|
|
WORKDIR /workspace/frontend
|
2026-06-18 11:19:24 -04:00
|
|
|
|
RUN if [ -f "package.json" ] && [ -d "node_modules" ]; then \
|
|
|
|
|
|
echo "=== Re-linking Yarn node_modules After Source Code Update ===" && \
|
|
|
|
|
|
echo "Ensuring package.json and installed node_modules are in sync..." && \
|
2025-11-01 16:13:30 -04:00
|
|
|
|
yarn install --immutable && \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
echo "✓ Yarn node_modules re-linked successfully"; \
|
2025-11-01 16:13:30 -04:00
|
|
|
|
else \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
echo "ℹ No node_modules detected, skipping Yarn re-link"; \
|
2025-11-01 16:13:30 -04:00
|
|
|
|
fi
|
|
|
|
|
|
|
2025-11-01 10:47:02 -04:00
|
|
|
|
# PHASE 4: Install backend package in development mode (requires full source)
|
|
|
|
|
|
WORKDIR /workspace/backend
|
|
|
|
|
|
RUN echo "=== Installing Backend Package in Development Mode ===" && \
|
|
|
|
|
|
uv pip install -e . && \
|
|
|
|
|
|
echo "✓ Backend package installed in development mode"
|
|
|
|
|
|
|
|
|
|
|
|
# PHASE 5: Install pre-commit environments (requires full source with .pre-commit-config.yaml)
|
|
|
|
|
|
WORKDIR /workspace
|
|
|
|
|
|
RUN echo "=== Installing Pre-commit Hook Environments ===" && \
|
|
|
|
|
|
if [ -f ".pre-commit-config.yaml" ]; then \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
# pre-commit requires a git repo at runtime; keep it in the final image.
|
|
|
|
|
|
git config --global user.email "ci@cicd" && \
|
|
|
|
|
|
git config --global user.name "CICD" && \
|
|
|
|
|
|
git init /workspace && \
|
|
|
|
|
|
git -C /workspace add -A && \
|
|
|
|
|
|
cd /workspace/backend && \
|
|
|
|
|
|
if uv run pre-commit install-hooks; then \
|
|
|
|
|
|
echo "✓ Pre-commit hook environments installed successfully"; \
|
|
|
|
|
|
else \
|
|
|
|
|
|
echo "⚠ pre-commit hook prewarming failed; continuing"; \
|
|
|
|
|
|
fi; \
|
2025-10-31 11:25:34 -04:00
|
|
|
|
else \
|
2025-11-01 10:47:02 -04:00
|
|
|
|
echo "No .pre-commit-config.yaml found, skipping hook installation"; \
|
2025-10-30 18:47:47 -04:00
|
|
|
|
fi
|
2025-10-27 08:39:54 -04:00
|
|
|
|
|
2026-06-18 11:19:24 -04:00
|
|
|
|
# PHASE 6: Playwright browsers optimization check
|
2025-11-01 10:47:02 -04:00
|
|
|
|
WORKDIR /workspace/frontend
|
2025-10-30 18:47:47 -04:00
|
|
|
|
RUN if [ -f ".frontend-deps-failed" ]; then \
|
2025-10-31 11:25:34 -04:00
|
|
|
|
echo "Frontend dependencies failed - Playwright E2E tests will be skipped"; \
|
2025-11-01 10:47:02 -04:00
|
|
|
|
elif [ -f "package.json" ] && grep -q '@playwright/test' package.json && [ -d "node_modules" ]; then \
|
2025-11-01 00:20:31 -04:00
|
|
|
|
echo "Checking Playwright browser optimization status..." && \
|
|
|
|
|
|
# Check if Playwright CLI is available via yarn (from project dependencies)
|
|
|
|
|
|
if yarn playwright --version >/dev/null 2>&1; then \
|
|
|
|
|
|
echo "✓ Playwright CLI available via yarn" && \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
PW_BROWSER_PATH="${PLAYWRIGHT_BROWSERS_PATH:-/root/.cache/ms-playwright}" && \
|
|
|
|
|
|
if find "${PW_BROWSER_PATH}" -maxdepth 1 -type d -name 'chromium-*' | grep -q .; then \
|
|
|
|
|
|
echo "✓ Playwright Chromium browser preinstalled at ${PW_BROWSER_PATH}"; \
|
2025-11-01 00:20:31 -04:00
|
|
|
|
else \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
echo "⚠ Playwright Chromium not preinstalled at ${PW_BROWSER_PATH} - CI will install on demand"; \
|
2025-11-01 00:20:31 -04:00
|
|
|
|
fi; \
|
|
|
|
|
|
else \
|
|
|
|
|
|
echo "⚠ Playwright CLI not available - E2E setup will be handled in CI"; \
|
|
|
|
|
|
fi && \
|
|
|
|
|
|
echo "✓ Playwright environment checked"; \
|
2025-10-30 16:24:21 -04:00
|
|
|
|
else \
|
2025-11-01 00:20:31 -04:00
|
|
|
|
echo "ℹ No Playwright tests configured in this project"; \
|
2025-10-30 16:24:21 -04:00
|
|
|
|
fi
|
|
|
|
|
|
|
2025-10-27 08:39:54 -04:00
|
|
|
|
# Verify all tools are working with the project
|
|
|
|
|
|
RUN cd /workspace/backend && \
|
|
|
|
|
|
echo "=== Backend Tools Verification ===" && \
|
|
|
|
|
|
uv run ruff --version && \
|
|
|
|
|
|
uv run pyright --version && \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
uv run pydoclint --version && \
|
2025-10-27 08:39:54 -04:00
|
|
|
|
uv run pytest --version && \
|
|
|
|
|
|
uv run yamllint --version && \
|
|
|
|
|
|
uv run toml-sort --version && \
|
2025-10-30 10:02:17 -04:00
|
|
|
|
uv run xdoctest --version && \
|
|
|
|
|
|
uv run pre-commit --version
|
2025-10-27 08:39:54 -04:00
|
|
|
|
|
|
|
|
|
|
RUN cd /workspace/frontend && \
|
|
|
|
|
|
echo "=== Frontend Tools Verification ===" && \
|
2025-10-30 18:47:47 -04:00
|
|
|
|
if [ -f ".frontend-deps-failed" ]; then \
|
|
|
|
|
|
echo "WARNING: Skipping frontend tool verification due to failed dependencies installation"; \
|
|
|
|
|
|
echo "Frontend CI/CD jobs may be limited in this environment"; \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
elif [ -d "node_modules" ]; then \
|
|
|
|
|
|
verify_required_tool() { \
|
|
|
|
|
|
tool_name="$1"; \
|
|
|
|
|
|
yarn_target="$2"; \
|
|
|
|
|
|
fallback_bin="$3"; \
|
|
|
|
|
|
if yarn "${yarn_target}" --version; then \
|
|
|
|
|
|
return 0; \
|
|
|
|
|
|
fi; \
|
|
|
|
|
|
if command -v "${fallback_bin}" >/dev/null 2>&1; then \
|
|
|
|
|
|
"${fallback_bin}" --version; \
|
|
|
|
|
|
return 0; \
|
|
|
|
|
|
fi; \
|
|
|
|
|
|
echo "ERROR: ${tool_name} is not available via yarn or global fallback"; \
|
|
|
|
|
|
return 1; \
|
|
|
|
|
|
}; \
|
|
|
|
|
|
verify_optional_yarn_tool() { \
|
|
|
|
|
|
tool_name="$1"; \
|
|
|
|
|
|
yarn_target="$2"; \
|
|
|
|
|
|
if yarn "${yarn_target}" --version; then \
|
|
|
|
|
|
return 0; \
|
|
|
|
|
|
fi; \
|
|
|
|
|
|
echo "⚠ ${tool_name} version check failed under Yarn wrapper; continuing"; \
|
|
|
|
|
|
return 0; \
|
|
|
|
|
|
}; \
|
|
|
|
|
|
echo "✓ node_modules dependencies found, verifying tools..." && \
|
|
|
|
|
|
verify_required_tool "eslint" "eslint" "eslint" && \
|
|
|
|
|
|
verify_required_tool "prettier" "prettier" "prettier" && \
|
|
|
|
|
|
verify_required_tool "typescript" "tsc" "tsc" && \
|
|
|
|
|
|
verify_optional_yarn_tool "vitest" "vitest" && \
|
2025-10-30 18:47:47 -04:00
|
|
|
|
echo "✓ All frontend tools verified successfully"; \
|
2025-10-29 16:01:39 -04:00
|
|
|
|
else \
|
2026-06-18 11:19:24 -04:00
|
|
|
|
echo "ERROR: No frontend node_modules found"; \
|
2025-11-01 13:27:56 -04:00
|
|
|
|
echo "Available files in frontend:"; \
|
2025-11-01 13:03:18 -04:00
|
|
|
|
ls -la .; \
|
2025-10-29 16:01:39 -04:00
|
|
|
|
exit 1; \
|
|
|
|
|
|
fi
|
2025-10-27 08:39:54 -04:00
|
|
|
|
|
|
|
|
|
|
# Set Python path for backend
|
|
|
|
|
|
ENV PYTHONPATH=/workspace/backend/src:/workspace/backend
|
|
|
|
|
|
|
2025-10-31 11:25:34 -04:00
|
|
|
|
# Make global development tools available in PATH for fallback
|
|
|
|
|
|
ENV PATH="/opt/python-dev-tools/bin:$PATH"
|
|
|
|
|
|
|
2025-10-27 08:39:54 -04:00
|
|
|
|
# Set working directory back to root
|
|
|
|
|
|
WORKDIR /workspace
|
|
|
|
|
|
|
|
|
|
|
|
# Default to bash
|
|
|
|
|
|
SHELL ["/bin/bash", "-c"]
|
|
|
|
|
|
CMD ["/bin/bash"]
|