Compare commits

...

6 Commits

Author SHA1 Message Date
0dc3ba0da4 chore: Reorder pnpm build arguments in Dockerfile.nextjs.
Some checks failed
Monorepo Pipeline / 🧪 Quality Assurance (push) Successful in 2m30s
Monorepo Pipeline / 🚀 Release (push) Successful in 2m31s
Monorepo Pipeline / 🐳 Build & Push Images (push) Failing after 25m10s
2026-02-03 22:40:10 +01:00
1a94465dba feat: streamline Docker builds with .dockerignore and pass NPM_TOKEN as a build secret for pnpm install.
Some checks failed
Monorepo Pipeline / 🧪 Quality Assurance (push) Successful in 2m34s
Monorepo Pipeline / 🚀 Release (push) Successful in 2m40s
Monorepo Pipeline / 🐳 Build & Push Images (push) Failing after 3m6s
2026-02-03 22:13:34 +01:00
7e256025ea refactor: remove pnpm cache configuration from Node.js setup actions in pipeline workflows. 2026-02-03 19:41:31 +01:00
e843de42da ci: Add catthehacker/ubuntu:act-latest container image to Gitea workflow jobs.
Some checks failed
Monorepo Pipeline / 🧪 Quality Assurance (push) Successful in 12m11s
Monorepo Pipeline / 🐳 Build & Push Images (push) Failing after 49s
Monorepo Pipeline / 🚀 Release (push) Successful in 2m32s
2026-02-03 19:28:35 +01:00
4d1b2231e3 refactor: update pipeline to use Docker actions for registry login, build, and push.
Some checks failed
Monorepo Pipeline / 🧪 Quality Assurance (push) Successful in 2m35s
Monorepo Pipeline / 🐳 Build & Push Images (push) Failing after 2m21s
Monorepo Pipeline / 🚀 Release (push) Successful in 2m35s
2026-02-03 19:10:35 +01:00
71f47f9037 refactor: extract language utilities to lang.ts and adjust CI pipeline triggers.
Some checks failed
Monorepo Pipeline / 🧪 Quality Assurance (push) Successful in 12m31s
Monorepo Pipeline / 🐳 Build & Push Images (push) Failing after 10s
Monorepo Pipeline / 🚀 Release (push) Successful in 2m43s
2026-02-03 18:51:25 +01:00
8 changed files with 122 additions and 92 deletions

12
.dockerignore Normal file
View File

@@ -0,0 +1,12 @@
node_modules
.next
.git
.npmrc
dist
build
out
coverage
.vercel
.turbo
*.log
.DS_Store

View File

@@ -2,13 +2,8 @@ name: Monorepo Pipeline
on: on:
push: push:
branches:
- main
tags: tags:
- 'v*' - 'v*'
pull_request:
branches:
- main
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
@@ -18,6 +13,8 @@ jobs:
qa: qa:
name: 🧪 Quality Assurance name: 🧪 Quality Assurance
runs-on: docker runs-on: docker
container:
image: catthehacker/ubuntu:act-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
@@ -31,7 +28,6 @@ jobs:
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node_version: 20 node_version: 20
cache: 'pnpm'
- name: Install dependencies - name: Install dependencies
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
@@ -52,6 +48,8 @@ jobs:
needs: qa needs: qa
if: startsWith(github.ref, 'refs/tags/v') if: startsWith(github.ref, 'refs/tags/v')
runs-on: docker runs-on: docker
container:
image: catthehacker/ubuntu:act-latest
env: env:
NPM_TOKEN: ${{ secrets.NPM_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -70,7 +68,6 @@ jobs:
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node_version: 20 node_version: 20
cache: 'pnpm'
- name: Install dependencies - name: Install dependencies
run: pnpm install --frozen-lockfile run: pnpm install --frozen-lockfile
@@ -86,6 +83,8 @@ jobs:
needs: qa needs: qa
if: startsWith(github.ref, 'refs/tags/v') if: startsWith(github.ref, 'refs/tags/v')
runs-on: docker runs-on: docker
container:
image: catthehacker/ubuntu:act-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
@@ -94,49 +93,60 @@ jobs:
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
- name: 🔐 Registry Login - name: 🔐 Registry Login
run: | uses: docker/login-action@v3
echo "${{ secrets.REGISTRY_PASS }}" | docker login registry.infra.mintel.me -u "${{ secrets.REGISTRY_USER }}" --password-stdin with:
registry: registry.infra.mintel.me
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASS }}
- name: 🏗️ Build & Push Nextjs Build-Base - name: 🏗️ Build & Push Nextjs Build-Base
env: uses: docker/build-push-action@v5
TAG: ${{ github.ref_name }} with:
run: | context: .
docker buildx build \ file: packages/infra/docker/Dockerfile.nextjs
--platform linux/amd64,linux/arm64 \ platforms: linux/amd64,linux/arm64
-t registry.infra.mintel.me/mintel/nextjs:$TAG \ push: true
-t registry.infra.mintel.me/mintel/nextjs:latest \ secrets: |
-f packages/infra/docker/Dockerfile.nextjs \ NPM_TOKEN=${{ secrets.NPM_TOKEN }}
--push . tags: |
registry.infra.mintel.me/mintel/nextjs:${{ github.ref_name }}
registry.infra.mintel.me/mintel/nextjs:latest
- name: 🏗️ Build & Push Production Runtime - name: 🏗️ Build & Push Production Runtime
env: uses: docker/build-push-action@v5
TAG: ${{ github.ref_name }} with:
run: | context: .
docker buildx build \ file: packages/infra/docker/Dockerfile.runtime
--platform linux/amd64,linux/arm64 \ platforms: linux/amd64,linux/arm64
-t registry.infra.mintel.me/mintel/runtime:$TAG \ push: true
-t registry.infra.mintel.me/mintel/runtime:latest \ secrets: |
-f packages/infra/docker/Dockerfile.runtime \ NPM_TOKEN=${{ secrets.NPM_TOKEN }}
--push . tags: |
registry.infra.mintel.me/mintel/runtime:${{ github.ref_name }}
registry.infra.mintel.me/mintel/runtime:latest
- name: 🏗️ Build & Push Gatekeeper (Product) - name: 🏗️ Build & Push Gatekeeper (Product)
env: uses: docker/build-push-action@v5
TAG: ${{ github.ref_name }} with:
run: | context: .
docker buildx build \ file: packages/infra/docker/Dockerfile.gatekeeper
--platform linux/amd64,linux/arm64 \ platforms: linux/amd64,linux/arm64
-t registry.infra.mintel.me/mintel/gatekeeper:$TAG \ push: true
-t registry.infra.mintel.me/mintel/gatekeeper:latest \ secrets: |
-f packages/infra/docker/Dockerfile.gatekeeper \ NPM_TOKEN=${{ secrets.NPM_TOKEN }}
--push . tags: |
registry.infra.mintel.me/mintel/gatekeeper:${{ github.ref_name }}
registry.infra.mintel.me/mintel/gatekeeper:latest
- name: 🏗️ Build & Push Directus (Base) - name: 🏗️ Build & Push Directus (Base)
env: uses: docker/build-push-action@v5
TAG: ${{ github.ref_name }} with:
run: | context: .
docker buildx build \ file: packages/infra/docker/Dockerfile.directus
--platform linux/amd64,linux/arm64 \ platforms: linux/amd64,linux/arm64
-t registry.infra.mintel.me/mintel/directus:$TAG \ push: true
-t registry.infra.mintel.me/mintel/directus:latest \ secrets: |
-f packages/infra/docker/Dockerfile.directus \ NPM_TOKEN=${{ secrets.NPM_TOKEN }}
--push . tags: |
registry.infra.mintel.me/mintel/directus:${{ github.ref_name }}
registry.infra.mintel.me/mintel/directus:latest

View File

@@ -6,15 +6,15 @@ WORKDIR /app
# Enable pnpm # Enable pnpm
RUN corepack enable pnpm RUN corepack enable pnpm
# Install dependencies (using monorepo root context) # Step 2: Install dependencies
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json .npmrc* ./ # We copy everything first because we have a .dockerignore
COPY packages/gatekeeper/package.json ./packages/gatekeeper/ # and we need the workspace structure for pnpm to work correctly
COPY packages/next-utils/package.json ./packages/next-utils/ COPY . .
COPY packages/tsconfig/package.json ./packages/tsconfig/
COPY packages/eslint-config/package.json ./packages/eslint-config/
COPY packages/next-config/package.json ./packages/next-config/
# Use a secret for NPM_TOKEN to authenticate with private registry
RUN --mount=type=cache,target=/root/.local/share/pnpm/store/v3 \ RUN --mount=type=cache,target=/root/.local/share/pnpm/store/v3 \
--mount=type=secret,id=NPM_TOKEN \
export NPM_TOKEN=$(cat /run/secrets/NPM_TOKEN) && \
pnpm i --frozen-lockfile pnpm i --frozen-lockfile
# Copy source # Copy source

View File

@@ -1,24 +1,19 @@
# Step 1: Base image
FROM node:20-alpine AS base FROM node:20-alpine AS base
RUN apk add --no-cache libc6-compat curl RUN apk add --no-cache libc6-compat curl
WORKDIR /app WORKDIR /app
# Enable pnpm
RUN corepack enable pnpm RUN corepack enable pnpm
# Copy root configurations # Step 2: Install dependencies
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json .npmrc* ./ # We copy everything first because we have a .dockerignore
# and we need the workspace structure for pnpm to work correctly
# Copy all package.json files to allow pnpm install to be cached
COPY packages/*/package.json ./packages/
COPY apps/*/package.json ./apps/
# Install dependencies for the entire monorepo
RUN --mount=type=cache,target=/root/.local/share/pnpm/store/v3 \
pnpm i --frozen-lockfile
# Copy the rest of the source code
COPY . . COPY . .
# Post-install/Build shared packages if needed # Use a secret for NPM_TOKEN to authenticate with private registry
RUN pnpm -r build --filter="./packages/*" RUN --mount=type=cache,target=/root/.local/share/pnpm/store/v3 \
--mount=type=secret,id=NPM_TOKEN \
export NPM_TOKEN=$(cat /run/secrets/NPM_TOKEN) && \
pnpm i --frozen-lockfile
# Step 3: Build shared packages
RUN pnpm --filter "./packages/*" -r build

View File

@@ -24,6 +24,8 @@ jobs:
prepare: prepare:
name: 🔍 Prepare Environment name: 🔍 Prepare Environment
runs-on: docker runs-on: docker
container:
image: catthehacker/ubuntu:act-latest
outputs: outputs:
target: ${{ steps.determine.outputs.target }} target: ${{ steps.determine.outputs.target }}
image_tag: ${{ steps.determine.outputs.image_tag }} image_tag: ${{ steps.determine.outputs.image_tag }}
@@ -136,6 +138,8 @@ jobs:
needs: prepare needs: prepare
if: needs.prepare.outputs.target != 'skip' if: needs.prepare.outputs.target != 'skip'
runs-on: docker runs-on: docker
container:
image: catthehacker/ubuntu:act-latest
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
@@ -144,7 +148,6 @@ jobs:
uses: actions/setup-node@v4 uses: actions/setup-node@v4
with: with:
node-version: 20 node-version: 20
cache: 'npm'
- name: Install dependencies - name: Install dependencies
run: npm ci run: npm ci
@@ -171,6 +174,8 @@ jobs:
needs: prepare needs: prepare
if: needs.prepare.outputs.target != 'skip' if: needs.prepare.outputs.target != 'skip'
runs-on: docker runs-on: docker
container:
image: catthehacker/ubuntu:act-latest
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
@@ -179,23 +184,26 @@ jobs:
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
- name: 🔐 Registry Login - name: 🔐 Registry Login
run: | uses: docker/login-action@v3
echo "${{ secrets.REGISTRY_PASS }}" | docker login registry.infra.mintel.me -u "${{ secrets.REGISTRY_USER }}" --password-stdin with:
registry: registry.infra.mintel.me
username: ${{ secrets.REGISTRY_USER }}
password: ${{ secrets.REGISTRY_PASS }}
- name: 🏗️ Docker Build & Push - name: 🏗️ Docker Build & Push
env: uses: docker/build-push-action@v5
IMAGE_TAG: ${{ needs.prepare.outputs.image_tag }} with:
NEXT_PUBLIC_BASE_URL: ${{ needs.prepare.outputs.next_public_base_url }} context: .
run: | platforms: linux/arm64
docker buildx build \ build-args: |
--pull \ NEXT_PUBLIC_BASE_URL=${{ needs.prepare.outputs.next_public_base_url }}
--platform linux/arm64 \ NEXT_PUBLIC_TARGET=${{ needs.prepare.outputs.target }}
--build-arg NEXT_PUBLIC_BASE_URL="$NEXT_PUBLIC_BASE_URL" \ push: true
--build-arg NEXT_PUBLIC_TARGET="${{ needs.prepare.outputs.target }}" \ secrets: |
-t registry.infra.mintel.me/mintel/${{ github.event.repository.name }}:$IMAGE_TAG \ NPM_TOKEN=${{ secrets.NPM_TOKEN }}
--cache-from type=registry,ref=registry.infra.mintel.me/mintel/${{ github.event.repository.name }}:buildcache \ tags: registry.infra.mintel.me/mintel/${{ github.event.repository.name }}:${{ needs.prepare.outputs.image_tag }}
--cache-to type=registry,ref=registry.infra.mintel.me/mintel/${{ github.event.repository.name }}:buildcache,mode=max \ cache-from: type=registry,ref=registry.infra.mintel.me/mintel/${{ github.event.repository.name }}:buildcache
--push . cache-to: type=registry,ref=registry.infra.mintel.me/mintel/${{ github.event.repository.name }}:buildcache,mode=max
# ────────────────────────────────────────────────────────────────────────────── # ──────────────────────────────────────────────────────────────────────────────
# JOB 4: Deploy # JOB 4: Deploy
@@ -205,6 +213,8 @@ jobs:
needs: [prepare, build, qa] needs: [prepare, build, qa]
if: needs.prepare.outputs.target != 'skip' if: needs.prepare.outputs.target != 'skip'
runs-on: docker runs-on: docker
container:
image: catthehacker/ubuntu:act-latest
env: env:
TARGET: ${{ needs.prepare.outputs.target }} TARGET: ${{ needs.prepare.outputs.target }}
IMAGE_TAG: ${{ needs.prepare.outputs.image_tag }} IMAGE_TAG: ${{ needs.prepare.outputs.image_tag }}
@@ -271,6 +281,8 @@ jobs:
needs: [prepare, deploy] needs: [prepare, deploy]
if: always() if: always()
runs-on: docker runs-on: docker
container:
image: catthehacker/ubuntu:act-latest
steps: steps:
- name: 🔔 Gotify - Success - name: 🔔 Gotify - Success
if: needs.deploy.result == 'success' if: needs.deploy.result == 'success'

View File

@@ -1,5 +1,5 @@
import { describe, it, expect } from "vitest"; import { describe, it, expect } from "vitest";
import { isValidLang } from "../src/index"; import { isValidLang } from "./lang";
describe("next-utils", () => { describe("next-utils", () => {
it("should validate languages correctly", () => { it("should validate languages correctly", () => {

View File

@@ -30,12 +30,7 @@ export async function rateLimit(
submissions[identifier] = now; submissions[identifier] = now;
} }
export const languages = ["en", "de"] as const; export * from "./lang";
export type Lang = (typeof languages)[number];
export function isValidLang(lang: string): lang is Lang {
return (languages as readonly string[]).includes(lang);
}
export * from "./i18n"; export * from "./i18n";
export * from "./env"; export * from "./env";

View File

@@ -0,0 +1,6 @@
export const languages = ["en", "de"] as const;
export type Lang = (typeof languages)[number];
export function isValidLang(lang: string): lang is Lang {
return (languages as readonly string[]).includes(lang);
}