because I got bored of customising my CV for every job
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ci: add provider-agnostic CI pipeline script and production Dockerfile

+115
+49
apps/server/Dockerfile
··· 27 27 28 28 WORKDIR /app/apps/server 29 29 CMD ["pnpm", "dev"] 30 + 31 + # ---- Production build ---- 32 + FROM node:24-alpine AS builder 33 + 34 + RUN apk add --no-cache openssl 35 + RUN corepack enable && corepack prepare pnpm@latest --activate 36 + 37 + WORKDIR /app 38 + 39 + COPY package.json pnpm-lock.yaml pnpm-workspace.yaml lerna.json ./ 40 + COPY packages/ ./packages/ 41 + COPY apps/ ./apps/ 42 + 43 + RUN pnpm install --frozen-lockfile 44 + 45 + WORKDIR /app/apps/server 46 + RUN pnpm exec prisma generate 47 + WORKDIR /app 48 + 49 + RUN pnpm build 50 + 51 + # ---- Production runtime ---- 52 + FROM node:24-alpine AS production 53 + 54 + RUN apk add --no-cache openssl curl 55 + RUN corepack enable && corepack prepare pnpm@latest --activate 56 + 57 + WORKDIR /app 58 + 59 + COPY package.json pnpm-lock.yaml pnpm-workspace.yaml lerna.json ./ 60 + COPY packages/ ./packages/ 61 + COPY apps/server/package.json ./apps/server/ 62 + 63 + RUN pnpm install --frozen-lockfile --prod 64 + 65 + # Copy Prisma schema + generated client 66 + COPY apps/server/prisma/ ./apps/server/prisma/ 67 + COPY --from=builder /app/apps/server/node_modules/.prisma/ ./apps/server/node_modules/.prisma/ 68 + COPY --from=builder /app/node_modules/.prisma/ ./node_modules/.prisma/ 69 + 70 + # Copy compiled output 71 + COPY --from=builder /app/apps/server/dist/ ./apps/server/dist/ 72 + COPY --from=builder /app/packages/*/dist/ ./packages/ 73 + 74 + ENV NODE_ENV=production 75 + EXPOSE 3000 76 + 77 + WORKDIR /app/apps/server 78 + CMD ["node", "dist/main.js"]
+55
ci/pipeline.ts
··· 1 + import { execSync } from "node:child_process"; 2 + import { resolve } from "node:path"; 3 + 4 + const root = resolve(import.meta.dirname, ".."); 5 + 6 + type Step = { 7 + name: string; 8 + command: string; 9 + }; 10 + 11 + const steps: Step[] = [ 12 + { name: "Install dependencies", command: "pnpm install --frozen-lockfile" }, 13 + { name: "Generate Prisma client", command: "pnpm prisma:generate" }, 14 + { name: "Lint", command: "pnpm lint" }, 15 + { name: "Typecheck", command: "pnpm typecheck" }, 16 + { name: "Build", command: "pnpm build" }, 17 + ]; 18 + 19 + const run = (step: Step): boolean => { 20 + console.log(`\n==> ${step.name}`); 21 + try { 22 + execSync(step.command, { cwd: root, stdio: "inherit" }); 23 + console.log(`==> ${step.name} passed`); 24 + return true; 25 + } catch { 26 + console.error(`==> ${step.name} FAILED`); 27 + return false; 28 + } 29 + }; 30 + 31 + const selectedStep = process.argv[2]; 32 + 33 + const stepsToRun = selectedStep 34 + ? steps.filter((s) => s.name.toLowerCase().includes(selectedStep.toLowerCase())) 35 + : steps; 36 + 37 + if (stepsToRun.length === 0) { 38 + console.error( 39 + `No step matching "${selectedStep}". Available: ${steps.map((s) => s.name).join(", ")}`, 40 + ); 41 + process.exit(1); 42 + } 43 + 44 + console.log( 45 + `Running ${stepsToRun.length} step(s): ${stepsToRun.map((s) => s.name).join(" -> ")}`, 46 + ); 47 + 48 + const failed = stepsToRun.find((step) => !run(step)); 49 + 50 + if (failed) { 51 + console.error(`\nPipeline failed at: ${failed.name}`); 52 + process.exit(1); 53 + } 54 + 55 + console.log("\nPipeline passed");
+11
ci/tsconfig.json
··· 1 + { 2 + "compilerOptions": { 3 + "target": "ES2022", 4 + "module": "ESNext", 5 + "moduleResolution": "bundler", 6 + "strict": true, 7 + "esModuleInterop": true, 8 + "skipLibCheck": true 9 + }, 10 + "include": ["*.ts"] 11 + }