diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2a303370d..8d5c83fff 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -276,7 +276,8 @@ jobs: file: ${{ matrix.file }} target: ${{ matrix.target }} push: false - load: false + load: ${{ matrix.service == 'bot' }} + tags: lucky-${{ matrix.service }}:ci provenance: false sbom: false cache-from: type=gha,scope=${{ matrix.service }} @@ -292,7 +293,8 @@ jobs: file: ${{ matrix.file }} target: ${{ matrix.target }} push: false - load: false + load: ${{ matrix.service == 'bot' }} + tags: lucky-${{ matrix.service }}:ci provenance: false sbom: false cache-from: type=gha,scope=${{ matrix.service }} @@ -300,6 +302,20 @@ jobs: build-args: | COMMIT_SHA=${{ github.sha }} NPM_CACHE_KEY=${{ hashFiles('package-lock.json') }} + # A built image is not a working image: the bot's native addons + # (@discordjs/opus) and the baked Prisma engines only fail at + # require()-time, which `docker build` never reaches. #1735 shipped a + # Prisma engine that crash-looped 262x behind a green build. Load the + # real production-bot image and require the modules for real. + - name: Verify native modules load — bot + if: matrix.service == 'bot' + run: | + docker run --rm lucky-bot:ci node -e " + const { OpusEncoder } = require('@discordjs/opus'); + const frame = new OpusEncoder(48000, 2).encode(Buffer.alloc(3840)); + if (!frame.length) throw new Error('opus encoded an empty frame'); + console.log('opus OK — encoded', frame.length, 'bytes'); + " docker-build-check: name: Build — Docker images diff --git a/Dockerfile b/Dockerfile index 7e7b6c2d4..5888757f0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -115,11 +115,16 @@ COPY packages/bot/package*.json ./packages/bot/ COPY packages/backend/package*.json ./packages/backend/ COPY packages/frontend/package*.json ./packages/frontend/ -RUN --mount=type=cache,id=npm-deps-production-v4-${NPM_CACHE_KEY},target=/root/.npm,sharing=locked \ - YOUTUBE_DL_SKIP_DOWNLOAD=1 \ - YOUTUBE_DL_SKIP_PYTHON_CHECK=1 \ - npm ci --legacy-peer-deps --omit=dev --no-audit --no-fund && \ - (npm cache verify 2>/dev/null || true) +# Reuse already-compiled node_modules from build stage (avoids double @discordjs/opus +# compilation). Copy root + workspace node_modules, then prune devDeps in-place while +# preserving the pre-built .node binary. +COPY --from=build /app/node_modules ./node_modules +COPY --from=build /app/packages/shared/node_modules ./packages/shared/node_modules +COPY --from=build /app/packages/bot/node_modules ./packages/bot/node_modules +COPY --from=build /app/packages/backend/node_modules ./packages/backend/node_modules +COPY --from=build /app/packages/frontend/node_modules ./packages/frontend/node_modules + +RUN npm prune --omit=dev --legacy-peer-deps # Production stage — bot (full runtime with ffmpeg/opus/yt-dlp) FROM base-runtime AS production-bot