ci: overhaul CI workflows for reliability and maintainability

- add CODEOWNERS assigning .github/ to @neonsolstice
- configure automated updates for npm, docker, and github-actions ecosystems
- replace custom change-detection bash script with dorny/paths-filter@v4
- consolidate lint, typecheck, and test into a single checks matrix job
- gate per-package change detection via has-changes step (matrix unavailable in job-level if)
- fix duplicate actions/setup-node call in setup-node-pnpm composite action
- scope pnpm store cache key by pnpm version to prevent stale cross-version cache hits
- pin all action references to commit SHAs
- fix container-image concurrency group to use commit SHA across all trigger types
- add timeout-minutes to all jobs
- document fail-fast: false rationale and checks: write trade-off
This commit is contained in:
neon
2026-03-07 18:14:36 -06:00
parent f911c552a7
commit a3579ac57f
72 changed files with 1290 additions and 812 deletions
+21 -11
View File
@@ -1,5 +1,7 @@
ARG NODE_IMAGE=node:24.11-alpine
# Stage 1: Build client
FROM node:24-alpine AS client-builder
FROM ${NODE_IMAGE} AS client-builder
RUN npm install -g pnpm@10
WORKDIR /app
@@ -11,8 +13,8 @@ RUN pnpm install --filter client... --frozen-lockfile
COPY client/ ./client/
RUN pnpm --filter client run build-only
# Stage 2: Build server + create prod deploy bundle
FROM node:24-alpine AS server-builder
# Stage 2: Build server + create deploy bundle
FROM ${NODE_IMAGE} AS server-builder
RUN npm install -g pnpm@10
WORKDIR /app
@@ -24,21 +26,29 @@ RUN pnpm install --filter server... --frozen-lockfile
COPY server/ ./server/
RUN pnpm --filter server run build
# pnpm deploy prunes to prod deps; dist/ is gitignored so copy it in after
# pnpm deploy prunes to prod deps; dist/ is gitignored so copy it in after.
RUN pnpm --filter server deploy --prod --legacy /deploy
RUN cp -r /app/server/dist /deploy/dist
RUN mkdir -p /deploy/migrations && cp -r /app/server/src/db/migrations/. /deploy/migrations/
# Stage 3: Final image
FROM node:24-alpine
# Stage 3: Runtime image
FROM ${NODE_IMAGE} AS runtime
WORKDIR /app
COPY --from=server-builder /deploy ./
COPY --from=client-builder /app/client/dist ./public
ENV NODE_ENV=production
ENV PORT=3000
COPY --from=server-builder --chown=node:node /deploy ./
COPY --from=client-builder --chown=node:node /app/client/dist ./public
COPY --from=server-builder --chown=node:node /app/server/entrypoint.sh ./entrypoint.sh
RUN chmod +x /app/entrypoint.sh && mkdir -p /books /tmp && chown -R node:node /books /tmp
USER node
EXPOSE 3000
ENV NODE_ENV=production
COPY --from=server-builder /app/server/entrypoint.sh ./entrypoint.sh
RUN chmod +x entrypoint.sh
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
CMD node -e "const p=process.env.PORT||3000;fetch('http://127.0.0.1:'+p+'/api/v1/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
CMD ["sh", "entrypoint.sh"]