# CI image: PHP + Composer + Node/npm. Unit/feature tests run against SQLite in # memory (see .env.testing), so no database client or cache extension is needed. # Browser tests need the `sockets` extension (pest-plugin-browser boots Laravel # in-process) and Node/npm to drive Playwright; the Chromium binary itself is # installed per run so it always matches the playwright version from the lockfile. # # Published as dishplanner-ci:php8.3-. The CI workflow # builds and tags this image from the current lockfile, so a PHP dependency # change automatically yields a fresh, uniquely-tagged image (no manual revision # bump). # # Debian-based rather than Alpine to avoid the DNS resolution timeouts against # codeload.github.com that the Alpine base hit during composer install. FROM php:8.3-cli COPY --from=mlocati/php-extension-installer:2 /usr/bin/install-php-extensions /usr/local/bin/ RUN install-php-extensions \ pdo_sqlite \ sockets \ mbstring \ dom \ xml \ fileinfo \ pcntl \ zip # git is needed by the checkout action; nodejs+npm run the Forgejo JavaScript # actions (checkout, cache) and Playwright; unzip lets Composer extract dist # archives. RUN apt-get update \ && apt-get install -y --no-install-recommends git unzip nodejs npm \ && rm -rf /var/lib/apt/lists/* COPY --from=composer:2 /usr/bin/composer /usr/bin/composer # Bake the project's PHP dependencies (dev included) into the image so CI # restores them with a local copy instead of paying a per-run composer install # over the network. # # The token lifts GitHub's API rate limit from 60 to 5000 requests/hour, which # is what forced --prefer-source before; dist archives need no special handling. # # --no-scripts skips `php artisan package:discover` (the app isn't present # here). CI runs `composer install` after restoring vendor, which regenerates # bootstrap/cache. WORKDIR /opt/deps COPY composer.json composer.lock ./ RUN --mount=type=secret,id=gh_pat \ if [ -s /run/secrets/gh_pat ]; then \ composer config --global github-oauth.github.com "$(cat /run/secrets/gh_pat)" || exit 1; \ fi; \ composer install --no-interaction --no-progress --no-scripts; \ STATUS=$?; \ composer config --global --unset github-oauth.github.com >/dev/null 2>&1 || true; \ exit $STATUS # Bake the Node dependencies and the Chromium build alongside the PHP ones, so a # run installs neither. Both are keyed to package-lock.json via the image tag. WORKDIR /opt/deps-node COPY package.json package-lock.json ./ RUN npm ci --no-audit --no-fund \ && PLAYWRIGHT_BROWSERS_PATH=/opt/playwright ./node_modules/.bin/playwright install --with-deps chromium ENV PLAYWRIGHT_BROWSERS_PATH=/opt/playwright # Cosmetic only — the runner overrides this with its own --workdir. WORKDIR /workspace