feat: ci/cd

This commit is contained in:
Leon Morival 2026-05-24 21:43:09 +02:00
parent a85507f7dc
commit e315ecb316
6 changed files with 196 additions and 2 deletions

14
.dockerignore Normal file
View File

@ -0,0 +1,14 @@
.git
.gitea
.idea
.next
node_modules
coverage
.env
.env.*
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*
*.tsbuildinfo
README.md

View File

@ -0,0 +1,97 @@
name: Next CI-CD
on:
push:
branches: ["main"]
env:
BUN_IMAGE: oven/bun:1-alpine
KAMAL_IMAGE: ghcr.io/basecamp/kamal:v2.11.0
jobs:
deploy:
name: Lint, Build and Deploy
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Lint and build
run: |
set -eu
docker run --rm \
--user "$(id -u):$(id -g)" \
-e HOME=/tmp \
-e NEXT_TELEMETRY_DISABLED=1 \
-v "$PWD:/app" \
-w /app \
"$BUN_IMAGE" \
sh -lc "bun install --frozen-lockfile && bun run lint && bun run build"
- name: Deploy with Kamal
env:
GITEA_TOKEN: ${{ secrets.TOKEN_GITEA }}
SSH_HOST: ${{ secrets.SSH_HOST }}
SSH_USER: ${{ secrets.SSH_USER }}
SSH_PRIVATE_KEY: ${{ secrets.SSH_PRIVATE_KEY }}
run: |
set -eu
: "${GITEA_TOKEN:?TOKEN_GITEA secret is required}"
: "${SSH_PRIVATE_KEY:?SSH_PRIVATE_KEY secret is required}"
: "${SSH_HOST:=89.167.35.217}"
: "${SSH_USER:=root}"
export SSH_HOST SSH_USER
WORKSPACE="${GITHUB_WORKSPACE:-$PWD}"
test -f "$WORKSPACE/config/deploy.yml"
tar \
--exclude=.git \
--exclude=.next \
--exclude=.kamal/secrets \
--exclude=.kamal/secrets.* \
--exclude=.env \
--exclude=.env.* \
--exclude=node_modules \
-C "$WORKSPACE" -cf - . | docker run --rm -i \
-v /var/run/docker.sock:/var/run/docker.sock \
-e GITEA_TOKEN \
-e SSH_HOST \
-e SSH_USER \
-e SSH_PRIVATE_KEY \
--entrypoint /bin/sh \
"$KAMAL_IMAGE" -lc '
set -eu
mkdir -p /workdir /root/.ssh
tar -xf - -C /workdir
cd /workdir
chmod 700 /root/.ssh
printf "%s\n" "$SSH_PRIVATE_KEY" | tr -d "\r" > /root/.ssh/id_ed25519
chmod 600 /root/.ssh/id_ed25519
mkdir -p /workdir/.ssh
cat > /workdir/.ssh/config <<'"'"'SSH_CONFIG'"'"'
Host *
IdentityFile /root/.ssh/id_ed25519
IdentitiesOnly yes
StrictHostKeyChecking yes
UserKnownHostsFile /workdir/.ssh/known_hosts
GlobalKnownHostsFile /dev/null
CheckHostIP no
SSH_CONFIG
ssh-keyscan -H "$SSH_HOST" > /workdir/.ssh/known_hosts
chmod 600 /workdir/.ssh/config /workdir/.ssh/known_hosts
mkdir -p .kamal
cat > .kamal/secrets <<'"'"'SECRETS'"'"'
GITEA_TOKEN=$GITEA_TOKEN
SSH_PRIVATE_KEY=$SSH_PRIVATE_KEY
SECRETS
chmod 600 .kamal/secrets
/kamal/bin/kamal deploy
'

38
Dockerfile Normal file
View File

@ -0,0 +1,38 @@
FROM oven/bun:1-alpine AS deps
WORKDIR /app
COPY package.json bun.lock ./
RUN bun install --frozen-lockfile
FROM oven/bun:1-alpine AS builder
WORKDIR /app
ENV NEXT_TELEMETRY_DISABLED=1
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN bun run build
FROM node:22-alpine AS runner
WORKDIR /app
ENV HOSTNAME=0.0.0.0
ENV NEXT_TELEMETRY_DISABLED=1
ENV NODE_ENV=production
ENV PORT=3000
RUN addgroup --system --gid 1001 nodejs \
&& adduser --system --uid 1001 nextjs
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
USER nextjs
EXPOSE 3000
CMD ["node", "server.js"]

44
config/deploy.yml Normal file
View File

@ -0,0 +1,44 @@
service: bowli-landing
image: daily_meal/bowli-landing
deploy_timeout: 120
x-hosts: &hosts
- <%= ENV.fetch("SSH_HOST", "89.167.35.217") %>
servers:
web:
hosts: *hosts
proxy:
host: landing.leonmorival.com
ssl: false
app_port: 3000
run:
http_port: 8081
https_port: 8443
healthcheck:
path: /
registry:
server: gitea.leonmorival.com
username: leon.morival@gmail.com
password:
- GITEA_TOKEN
ssh:
user: <%= ENV.fetch("SSH_USER", "root") %>
keys_only: true
key_data:
- SSH_PRIVATE_KEY
config: false
builder:
arch: amd64
env:
clear:
NODE_ENV: production
NEXT_TELEMETRY_DISABLED: "1"
NEXT_PUBLIC_SITE_URL: https://landing.leonmorival.com
NEXT_PUBLIC_API_URL: https://bemeal.leonmorival.com/api
NEXT_PUBLIC_SUPPORT_EMAIL: support@bowli.app

View File

@ -1,7 +1,7 @@
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
/* config options here */
output: "standalone",
};
export default nextConfig;

View File

@ -6,7 +6,8 @@ export const siteConfig = {
description:
"Bowli aide à suivre ses repas, ses objectifs nutritionnels et ses activités sportives depuis une application mobile.",
supportEmail: process.env.NEXT_PUBLIC_SUPPORT_EMAIL ?? "support@bowli.app",
siteUrl: process.env.NEXT_PUBLIC_SITE_URL ?? "https://bowli.app",
siteUrl:
process.env.NEXT_PUBLIC_SITE_URL ?? "https://landing.leonmorival.com",
legalPublishedAt: "2026-05-24T00:00:00+02:00",
legalUpdatedLabel: "24 mai 2026",
} as const;