feat: ci/cd
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
.git
|
||||
.env
|
||||
node_modules
|
||||
vendor
|
||||
storage/logs
|
||||
docker-compose*.yml
|
||||
+32
-80
@@ -1,98 +1,50 @@
|
||||
# ============================================================
|
||||
# CD — Déploiement Continu
|
||||
# Déclenche un déploiement uniquement sur push main.
|
||||
#
|
||||
# Le runner Gitea Actions tourne directement sur le serveur.
|
||||
# Aucun SSH nécessaire — les commandes s'exécutent localement.
|
||||
# ============================================================
|
||||
|
||||
name: CD
|
||||
|
||||
on:
|
||||
push:
|
||||
workflow_run:
|
||||
workflows:
|
||||
- CI
|
||||
branches:
|
||||
- main
|
||||
|
||||
types:
|
||||
- completed
|
||||
jobs:
|
||||
deploy:
|
||||
name: 🚀 Déploiement production
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
|
||||
# ── 1. Mise à jour du code ───────────────────────────────
|
||||
- name: 🔄 Mise à jour du code
|
||||
- name: 🔐 Configuration SSH
|
||||
run: |
|
||||
set -e
|
||||
cd /data/docker/landing-api
|
||||
mkdir -p ~/.ssh
|
||||
echo "${{ secrets.DEPLOY_SSH_KEY }}" \
|
||||
> ~/.ssh/id_ed25519
|
||||
chmod 600 ~/.ssh/id_ed25519
|
||||
|
||||
echo "🔄 Pull depuis Gitea..."
|
||||
git fetch origin main
|
||||
git reset --hard origin/main
|
||||
ssh-keyscan \
|
||||
-H "${{ secrets.DEPLOY_HOST }}" \
|
||||
>> ~/.ssh/known_hosts
|
||||
|
||||
# ── 2. Build de l'image Docker ───────────────────────────
|
||||
- name: 🐳 Build image Docker
|
||||
- name: 🚀 Deploy Docker
|
||||
run: |
|
||||
set -e
|
||||
cd /data/docker/landing-api
|
||||
ssh \
|
||||
-i ~/.ssh/id_ed25519 \
|
||||
${{ secrets.DEPLOY_USER }}@${{ secrets.DEPLOY_HOST }} << 'EOF'
|
||||
set -e
|
||||
echo "📂 Projet"
|
||||
cd /data/docker/landing-api
|
||||
echo "⬇️ Pull nouvelle image"
|
||||
docker compose pull
|
||||
echo "🚀 Redémarrage"
|
||||
docker compose up -d
|
||||
echo "🗄️ Migration Laravel"
|
||||
|
||||
echo "🏗️ Build de l'image de production..."
|
||||
docker compose -f compose.prod.yaml build --no-cache app
|
||||
docker compose exec -T app \
|
||||
php artisan migrate --force
|
||||
|
||||
# ── 3. Démarrage / redémarrage des containers ────────────
|
||||
- name: 🚀 Déploiement des containers
|
||||
run: |
|
||||
set -e
|
||||
cd /data/docker/landing-api
|
||||
echo "🧹 Nettoyage"
|
||||
|
||||
echo "🚀 Redémarrage des services..."
|
||||
docker compose -f compose.prod.yaml up -d --remove-orphans
|
||||
docker image prune -f
|
||||
|
||||
# ── 4. Migrations base de données ────────────────────────
|
||||
- name: 🗄️ Migrations base de données
|
||||
run: |
|
||||
set -e
|
||||
cd /data/docker/landing-api
|
||||
echo "✅ Déploiement terminé"
|
||||
|
||||
echo "⏳ Attente que la BDD soit prête..."
|
||||
sleep 5
|
||||
|
||||
echo "🗄️ Exécution des migrations..."
|
||||
docker compose -f compose.prod.yaml exec -T app php artisan migrate --force
|
||||
|
||||
# ── 5. Optimisations Laravel ─────────────────────────────
|
||||
- name: ⚙️ Optimisations Laravel
|
||||
run: |
|
||||
set -e
|
||||
cd /data/docker/landing-api
|
||||
|
||||
echo "⚙️ Mise en cache des configs, routes, vues..."
|
||||
docker compose -f compose.prod.yaml exec -T app php artisan config:cache
|
||||
docker compose -f compose.prod.yaml exec -T app php artisan route:cache
|
||||
docker compose -f compose.prod.yaml exec -T app php artisan view:cache
|
||||
docker compose -f compose.prod.yaml exec -T app php artisan event:cache
|
||||
|
||||
echo "🔄 Redémarrage des workers..."
|
||||
docker compose -f compose.prod.yaml exec -T app php artisan queue:restart
|
||||
|
||||
# ── 6. Nettoyage des anciennes images ────────────────────
|
||||
- name: 🧹 Nettoyage Docker
|
||||
run: |
|
||||
docker image prune -f
|
||||
|
||||
# ── 7. Résultat ──────────────────────────────────────────
|
||||
- name: 🎉 Déploiement réussi
|
||||
if: success()
|
||||
run: |
|
||||
echo "✅ Application déployée avec succès !"
|
||||
echo "🔗 Commit : ${{ github.sha }}"
|
||||
echo "👤 Par : ${{ github.actor }}"
|
||||
|
||||
- name: ❌ Déploiement échoué
|
||||
if: failure()
|
||||
run: |
|
||||
echo "❌ Le déploiement a échoué — rollback recommandé"
|
||||
echo "🔗 Commit : ${{ github.sha }}"
|
||||
# Affiche les logs des containers en erreur pour debug
|
||||
cd /data/docker/landing-api
|
||||
docker compose -f compose.prod.yaml logs --tail=50
|
||||
EOF
|
||||
|
||||
+90
-52
@@ -1,78 +1,116 @@
|
||||
# ============================================================
|
||||
# CI — Intégration Continue
|
||||
# Se déclenche sur chaque push et chaque Pull Request.
|
||||
# Lance les tests PHPUnit avec SQLite en mémoire (rapide).
|
||||
# ============================================================
|
||||
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- '**' # tous les branches
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- develop
|
||||
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
test:
|
||||
name: 🧪 Tests Laravel (PHP ${{ matrix.php }})
|
||||
name: 🧪 Tests Laravel
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
php: ['8.3'] # Ajoute d'autres versions si tu veux tester plusieurs PHP
|
||||
|
||||
steps:
|
||||
# ── 1. Récupère le code ─────────────────────────────────
|
||||
- name: 📥 Checkout du code
|
||||
- name: 📥 Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# ── 2. Configure PHP avec les extensions nécessaires ────
|
||||
- name: 🐘 Setup PHP ${{ matrix.php }}
|
||||
- name: 🐘 Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
extensions: mbstring, bcmath, sqlite3, pdo_sqlite, pgsql, pdo_pgsql, xml, curl, zip, gd, intl
|
||||
coverage: none # met "xdebug" ici si tu veux du coverage
|
||||
php-version: '8.3'
|
||||
extensions: >
|
||||
bcmath,
|
||||
ctype,
|
||||
curl,
|
||||
dom,
|
||||
fileinfo,
|
||||
mbstring,
|
||||
openssl,
|
||||
pdo,
|
||||
tokenizer,
|
||||
xml,
|
||||
zip
|
||||
coverage: none
|
||||
|
||||
|
||||
# ── 3. Cache des dépendances Composer ───────────────────
|
||||
- name: 📦 Cache Composer
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: vendor
|
||||
key: composer-${{ matrix.php }}-${{ hashFiles('composer.lock') }}
|
||||
restore-keys: composer-${{ matrix.php }}-
|
||||
path: ~/.composer/cache
|
||||
key: composer-${{ hashFiles('composer.lock') }}
|
||||
|
||||
# ── 4. Installe les dépendances PHP ─────────────────────
|
||||
- name: 📦 Installation Composer
|
||||
run: composer install --no-interaction --prefer-dist --optimize-autoloader --no-scripts
|
||||
|
||||
# ── 5. Prépare l'environnement .env de test ─────────────
|
||||
- name: ⚙️ Configuration .env
|
||||
- name: 📦 Install Composer dependencies
|
||||
run: |
|
||||
composer install \
|
||||
--no-interaction \
|
||||
--prefer-dist \
|
||||
--no-progress
|
||||
|
||||
|
||||
- name: ⚙️ Prepare Laravel
|
||||
run: |
|
||||
|
||||
cp .env.example .env
|
||||
# On écrase les variables critiques pour les tests
|
||||
echo "APP_ENV=testing" >> .env
|
||||
echo "APP_KEY=" >> .env
|
||||
echo "DB_CONNECTION=sqlite" >> .env
|
||||
echo "DB_DATABASE=:memory:" >> .env
|
||||
echo "QUEUE_CONNECTION=sync" >> .env
|
||||
echo "SESSION_DRIVER=array" >> .env
|
||||
echo "CACHE_STORE=array" >> .env
|
||||
echo "MAIL_MAILER=array" >> .env
|
||||
echo "BROADCAST_CONNECTION=null" >> .env
|
||||
|
||||
# ── 6. Génère la clé d'application ──────────────────────
|
||||
- name: 🔑 Génération de la clé APP_KEY
|
||||
run: php artisan key:generate --ansi
|
||||
php artisan key:generate
|
||||
|
||||
# ── 7. Exécute les migrations (SQLite :memory:) ─────────
|
||||
- name: 🗄️ Migrations
|
||||
run: php artisan migrate --force --ansi
|
||||
touch database/database.sqlite
|
||||
|
||||
# ── 8. Lance les tests ───────────────────────────────────
|
||||
- name: ✅ Tests PHPUnit
|
||||
run: php artisan test --ansi
|
||||
php artisan migrate --force
|
||||
|
||||
|
||||
- name: 🧪 Run PHPUnit
|
||||
run: |
|
||||
php artisan test
|
||||
|
||||
|
||||
|
||||
docker:
|
||||
|
||||
|
||||
name: 🐳 Build & Push Image
|
||||
|
||||
needs: test
|
||||
|
||||
if: github.ref == 'refs/heads/main'
|
||||
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
|
||||
steps:
|
||||
|
||||
|
||||
- name: 📥 Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
|
||||
|
||||
- name: 🔐 Login Registry Gitea
|
||||
run: |
|
||||
|
||||
docker login git.leonmorival.xyz \
|
||||
-u "${{ secrets.REGISTRY_USER }}" \
|
||||
-p "${{ secrets.REGISTRY_PASSWORD }}"
|
||||
|
||||
|
||||
|
||||
- name: 🏗️ Build image
|
||||
run: |
|
||||
|
||||
docker build \
|
||||
-t git.leonmorival.xyz/leonm/landing-api:latest \
|
||||
-t git.leonmorival.xyz/leonm/landing-api:${{ github.sha }} \
|
||||
.
|
||||
|
||||
|
||||
|
||||
- name: 📤 Push image
|
||||
run: |
|
||||
|
||||
docker push git.leonmorival.xyz/leonm/landing-api:latest
|
||||
|
||||
docker push git.leonmorival.xyz/leonm/landing-api:${{ github.sha }}
|
||||
|
||||
@@ -25,3 +25,7 @@ _ide_helper.php
|
||||
Homestead.json
|
||||
Homestead.yaml
|
||||
Thumbs.db
|
||||
|
||||
**/caddy
|
||||
frankenphp
|
||||
frankenphp-worker.php
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
FROM dunglas/frankenphp:php8.3-alpine
|
||||
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
|
||||
RUN install-php-extensions \
|
||||
pdo_pgsql \
|
||||
opcache \
|
||||
pcntl \
|
||||
zip \
|
||||
intl
|
||||
|
||||
|
||||
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
|
||||
|
||||
|
||||
COPY composer.json composer.lock ./
|
||||
|
||||
|
||||
RUN composer install \
|
||||
--no-dev \
|
||||
--no-interaction \
|
||||
--prefer-dist \
|
||||
--optimize-autoloader
|
||||
|
||||
|
||||
COPY . .
|
||||
|
||||
|
||||
RUN npm install
|
||||
RUN npm run build
|
||||
|
||||
|
||||
RUN php artisan octane:install --server=frankenphp || true
|
||||
|
||||
|
||||
RUN php artisan config:cache
|
||||
RUN php artisan route:cache
|
||||
RUN php artisan view:cache
|
||||
|
||||
|
||||
RUN chown -R www-data:www-data storage bootstrap/cache
|
||||
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
|
||||
CMD [
|
||||
"php",
|
||||
"artisan",
|
||||
"octane:start",
|
||||
"--server=frankenphp",
|
||||
"--host=0.0.0.0",
|
||||
"--port=8000"
|
||||
]
|
||||
+29
-85
@@ -1,102 +1,46 @@
|
||||
# ============================================================
|
||||
# Docker Compose — Production
|
||||
#
|
||||
# Architecture :
|
||||
# [Nginx Proxy Manager] ──► [FrankenPHP app:80]
|
||||
# │
|
||||
# [PostgreSQL]
|
||||
# [Queue Worker]
|
||||
#
|
||||
# Le réseau "proxy" est externe (géré par Nginx Proxy Manager).
|
||||
# Dans NPM, configure un proxy host vers : http://landing-api-app:80
|
||||
#
|
||||
# Usage :
|
||||
# docker compose -f compose.prod.yaml up -d
|
||||
# ============================================================
|
||||
|
||||
services:
|
||||
|
||||
# ── Application FrankenPHP (web + PHP tout-en-un) ───────
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/Dockerfile.prod
|
||||
image: landing-api:latest
|
||||
container_name: landing-api-app
|
||||
image: git.leonmorival.xyz/leon/landing-api:latest
|
||||
container_name: landing-api
|
||||
restart: unless-stopped
|
||||
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
APP_ENV: production
|
||||
APP_DEBUG: "false"
|
||||
SERVER_NAME: ":80" # FrankenPHP écoute sur le port 80
|
||||
volumes:
|
||||
- app_storage:/app/storage/app
|
||||
- app_logs:/app/storage/logs
|
||||
networks:
|
||||
- proxy # réseau NPM pour être accessible depuis l'extérieur
|
||||
- internal # réseau interne pour parler à PostgreSQL
|
||||
depends_on:
|
||||
pgsql:
|
||||
condition: service_healthy
|
||||
|
||||
# ── Base de données PostgreSQL ──────────────────────────
|
||||
pgsql:
|
||||
image: postgres:17-alpine
|
||||
container_name: landing-api-pgsql
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
POSTGRES_DB: "${DB_DATABASE}"
|
||||
POSTGRES_USER: "${DB_USERNAME}"
|
||||
POSTGRES_PASSWORD: "${DB_PASSWORD}"
|
||||
PGDATA: /var/lib/postgresql/data/pgdata
|
||||
volumes:
|
||||
- pgsql_data:/var/lib/postgresql/data
|
||||
networks:
|
||||
- internal # PostgreSQL n'est PAS exposé sur le réseau proxy
|
||||
healthcheck:
|
||||
test: ["CMD-SHELL", "pg_isready -q -d ${DB_DATABASE} -U ${DB_USERNAME}"]
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 5
|
||||
start_period: 30s
|
||||
- proxy
|
||||
- database
|
||||
|
||||
# ── Worker Laravel Queue ────────────────────────────────
|
||||
queue:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/Dockerfile.prod
|
||||
image: landing-api:latest
|
||||
container_name: landing-api-queue
|
||||
restart: unless-stopped
|
||||
command: ["php", "artisan", "queue:work", "--sleep=3", "--tries=3", "--max-time=3600"]
|
||||
env_file:
|
||||
- .env
|
||||
environment:
|
||||
APP_ENV: production
|
||||
APP_DEBUG: "false"
|
||||
volumes:
|
||||
- app_storage:/app/storage/app
|
||||
- app_logs:/app/storage/logs
|
||||
- storage:/var/www/html/storage
|
||||
|
||||
|
||||
postgres:
|
||||
image: postgres:16
|
||||
container_name: landing-api-postgres
|
||||
restart: unless-stopped
|
||||
|
||||
environment:
|
||||
POSTGRES_DB: ${DB_DATABASE}
|
||||
POSTGRES_USER: ${DB_USERNAME}
|
||||
POSTGRES_PASSWORD: ${DB_PASSWORD}
|
||||
|
||||
volumes:
|
||||
- postgres-data:/var/lib/postgresql/data
|
||||
|
||||
networks:
|
||||
- internal
|
||||
depends_on:
|
||||
pgsql:
|
||||
condition: service_healthy
|
||||
- database
|
||||
|
||||
|
||||
volumes:
|
||||
storage:
|
||||
postgres-data:
|
||||
|
||||
|
||||
networks:
|
||||
# Réseau externe partagé avec Nginx Proxy Manager
|
||||
proxy:
|
||||
external: true
|
||||
|
||||
# Réseau interne isolé (app ↔ pgsql ↔ queue)
|
||||
internal:
|
||||
database:
|
||||
driver: bridge
|
||||
|
||||
volumes:
|
||||
pgsql_data:
|
||||
driver: local
|
||||
app_storage:
|
||||
driver: local
|
||||
app_logs:
|
||||
driver: local
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"php": "^8.3",
|
||||
"filament/filament": "^5.0",
|
||||
"laravel/framework": "^13.8",
|
||||
"laravel/octane": "^2.17",
|
||||
"laravel/sanctum": "^4.0",
|
||||
"laravel/tinker": "^3.0"
|
||||
},
|
||||
|
||||
Generated
+265
-1
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "10b22fffd5baa69a8732cb3894b68663",
|
||||
"content-hash": "5bbf65aa881d14aff56a15114641ac54",
|
||||
"packages": [
|
||||
{
|
||||
"name": "anourvalar/eloquent-serialize",
|
||||
@@ -2089,6 +2089,94 @@
|
||||
},
|
||||
"time": "2026-05-28T20:35:55+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laminas/laminas-diactoros",
|
||||
"version": "3.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laminas/laminas-diactoros.git",
|
||||
"reference": "60c182916b2749480895601649563970f3f12ec4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-diactoros/zipball/60c182916b2749480895601649563970f3f12ec4",
|
||||
"reference": "60c182916b2749480895601649563970f3f12ec4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "~8.2.0 || ~8.3.0 || ~8.4.0 || ~8.5.0",
|
||||
"psr/http-factory": "^1.1",
|
||||
"psr/http-message": "^1.1 || ^2.0"
|
||||
},
|
||||
"conflict": {
|
||||
"amphp/amp": "<2.6.4"
|
||||
},
|
||||
"provide": {
|
||||
"psr/http-factory-implementation": "^1.0",
|
||||
"psr/http-message-implementation": "^1.1 || ^2.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-curl": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-gd": "*",
|
||||
"ext-libxml": "*",
|
||||
"http-interop/http-factory-tests": "^2.2.0",
|
||||
"laminas/laminas-coding-standard": "~3.1.0",
|
||||
"php-http/psr7-integration-tests": "^1.4.0",
|
||||
"phpunit/phpunit": "^10.5.36",
|
||||
"psalm/plugin-phpunit": "^0.19.5",
|
||||
"vimeo/psalm": "^6.13"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laminas": {
|
||||
"module": "Laminas\\Diactoros",
|
||||
"config-provider": "Laminas\\Diactoros\\ConfigProvider"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"files": [
|
||||
"src/functions/create_uploaded_file.php",
|
||||
"src/functions/marshal_headers_from_sapi.php",
|
||||
"src/functions/marshal_method_from_sapi.php",
|
||||
"src/functions/marshal_protocol_version_from_sapi.php",
|
||||
"src/functions/normalize_server.php",
|
||||
"src/functions/normalize_uploaded_files.php",
|
||||
"src/functions/parse_cookie_header.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Laminas\\Diactoros\\": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"description": "PSR HTTP Message implementations",
|
||||
"homepage": "https://laminas.dev",
|
||||
"keywords": [
|
||||
"http",
|
||||
"laminas",
|
||||
"psr",
|
||||
"psr-17",
|
||||
"psr-7"
|
||||
],
|
||||
"support": {
|
||||
"chat": "https://laminas.dev/chat",
|
||||
"docs": "https://docs.laminas.dev/laminas-diactoros/",
|
||||
"forum": "https://discourse.laminas.dev",
|
||||
"issues": "https://github.com/laminas/laminas-diactoros/issues",
|
||||
"rss": "https://github.com/laminas/laminas-diactoros/releases.atom",
|
||||
"source": "https://github.com/laminas/laminas-diactoros"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://funding.communitybridge.org/projects/laminas-project",
|
||||
"type": "community_bridge"
|
||||
}
|
||||
],
|
||||
"time": "2025-10-12T15:31:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/framework",
|
||||
"version": "v13.19.0",
|
||||
@@ -2313,6 +2401,95 @@
|
||||
},
|
||||
"time": "2026-07-07T14:13:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/octane",
|
||||
"version": "v2.17.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laravel/octane.git",
|
||||
"reference": "058ae4d7109eed40836dc42960f9388b9bf71f73"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laravel/octane/zipball/058ae4d7109eed40836dc42960f9388b9bf71f73",
|
||||
"reference": "058ae4d7109eed40836dc42960f9388b9bf71f73",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"laminas/laminas-diactoros": "^3.0",
|
||||
"laravel/framework": "^10.10.1|^11.0|^12.0|^13.0",
|
||||
"laravel/prompts": "^0.1.24|^0.2.0|^0.3.0",
|
||||
"laravel/serializable-closure": "^1.3|^2.0",
|
||||
"nesbot/carbon": "^2.66.0|^3.0",
|
||||
"php": "^8.1.0",
|
||||
"symfony/console": "^6.0|^7.0|^8.0",
|
||||
"symfony/psr-http-message-bridge": "^2.2.0|^6.4|^7.0|^8.0"
|
||||
},
|
||||
"conflict": {
|
||||
"spiral/roadrunner": "<2023.1.0",
|
||||
"spiral/roadrunner-cli": "<2.6.0",
|
||||
"spiral/roadrunner-http": "<3.3.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"guzzlehttp/guzzle": "^7.6.1",
|
||||
"inertiajs/inertia-laravel": "^1.3.2|^2.0",
|
||||
"laravel/scout": "^10.2.1",
|
||||
"laravel/socialite": "^5.6.1",
|
||||
"livewire/livewire": "^2.12.3|^3.0",
|
||||
"nunomaduro/collision": "^6.4.0|^7.5.2|^8.0",
|
||||
"orchestra/testbench": "^8.21|^9.0|^10.0|^11.0",
|
||||
"phpstan/phpstan": "^2.1.7",
|
||||
"phpunit/phpunit": "^10.4|^11.5|^12.0|^13.0",
|
||||
"spiral/roadrunner-cli": "^2.6.0",
|
||||
"spiral/roadrunner-http": "^3.3.0"
|
||||
},
|
||||
"bin": [
|
||||
"bin/roadrunner-worker",
|
||||
"bin/swoole-server"
|
||||
],
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"laravel": {
|
||||
"aliases": {
|
||||
"Octane": "Laravel\\Octane\\Facades\\Octane"
|
||||
},
|
||||
"providers": [
|
||||
"Laravel\\Octane\\OctaneServiceProvider"
|
||||
]
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-master": "2.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Laravel\\Octane\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Taylor Otwell",
|
||||
"email": "taylor@laravel.com"
|
||||
}
|
||||
],
|
||||
"description": "Supercharge your Laravel application's performance.",
|
||||
"keywords": [
|
||||
"frankenphp",
|
||||
"laravel",
|
||||
"octane",
|
||||
"roadrunner",
|
||||
"swoole"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/laravel/octane/issues",
|
||||
"source": "https://github.com/laravel/octane"
|
||||
},
|
||||
"time": "2026-06-04T09:05:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "laravel/prompts",
|
||||
"version": "v0.3.21",
|
||||
@@ -7300,6 +7477,93 @@
|
||||
],
|
||||
"time": "2026-05-29T05:06:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/psr-http-message-bridge",
|
||||
"version": "v8.1.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/psr-http-message-bridge.git",
|
||||
"reference": "67fd34de15ded1763aa1e330fe345f080a94022c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/psr-http-message-bridge/zipball/67fd34de15ded1763aa1e330fe345f080a94022c",
|
||||
"reference": "67fd34de15ded1763aa1e330fe345f080a94022c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.4.1",
|
||||
"psr/http-message": "^1.0|^2.0",
|
||||
"symfony/http-foundation": "^7.4|^8.0"
|
||||
},
|
||||
"conflict": {
|
||||
"php-http/discovery": "<1.15"
|
||||
},
|
||||
"require-dev": {
|
||||
"nyholm/psr7": "^1.1",
|
||||
"php-http/discovery": "^1.15",
|
||||
"psr/log": "^1.1.4|^2|^3",
|
||||
"symfony/browser-kit": "^7.4|^8.0",
|
||||
"symfony/config": "^7.4|^8.0",
|
||||
"symfony/event-dispatcher": "^7.4|^8.0",
|
||||
"symfony/framework-bundle": "^7.4|^8.0",
|
||||
"symfony/http-kernel": "^7.4|^8.0",
|
||||
"symfony/runtime": "^7.4|^8.0"
|
||||
},
|
||||
"type": "symfony-bridge",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Symfony\\Bridge\\PsrHttpMessage\\": ""
|
||||
},
|
||||
"exclude-from-classmap": [
|
||||
"/Tests/"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "https://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "PSR HTTP message bridge",
|
||||
"homepage": "https://symfony.com",
|
||||
"keywords": [
|
||||
"http",
|
||||
"http-message",
|
||||
"psr-17",
|
||||
"psr-7"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/psr-http-message-bridge/tree/v8.1.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://symfony.com/sponsor",
|
||||
"type": "custom"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2026-05-29T05:06:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/routing",
|
||||
"version": "v8.1.0",
|
||||
|
||||
@@ -0,0 +1,224 @@
|
||||
<?php
|
||||
|
||||
use Laravel\Octane\Contracts\OperationTerminated;
|
||||
use Laravel\Octane\Events\RequestHandled;
|
||||
use Laravel\Octane\Events\RequestReceived;
|
||||
use Laravel\Octane\Events\RequestTerminated;
|
||||
use Laravel\Octane\Events\TaskReceived;
|
||||
use Laravel\Octane\Events\TaskTerminated;
|
||||
use Laravel\Octane\Events\TickReceived;
|
||||
use Laravel\Octane\Events\TickTerminated;
|
||||
use Laravel\Octane\Events\WorkerErrorOccurred;
|
||||
use Laravel\Octane\Events\WorkerStarting;
|
||||
use Laravel\Octane\Events\WorkerStopping;
|
||||
use Laravel\Octane\Listeners\CloseMonologHandlers;
|
||||
use Laravel\Octane\Listeners\CollectGarbage;
|
||||
use Laravel\Octane\Listeners\DisconnectFromDatabases;
|
||||
use Laravel\Octane\Listeners\EnsureUploadedFilesAreValid;
|
||||
use Laravel\Octane\Listeners\EnsureUploadedFilesCanBeMoved;
|
||||
use Laravel\Octane\Listeners\FlushOnce;
|
||||
use Laravel\Octane\Listeners\FlushTemporaryContainerInstances;
|
||||
use Laravel\Octane\Listeners\FlushUploadedFiles;
|
||||
use Laravel\Octane\Listeners\ReportException;
|
||||
use Laravel\Octane\Listeners\StopWorkerIfNecessary;
|
||||
use Laravel\Octane\Octane;
|
||||
|
||||
return [
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Octane Server
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| This value determines the default "server" that will be used by Octane
|
||||
| when starting, restarting, or stopping your server via the CLI. You
|
||||
| are free to change this to the supported server of your choosing.
|
||||
|
|
||||
| Supported: "roadrunner", "swoole", "frankenphp"
|
||||
|
|
||||
*/
|
||||
|
||||
'server' => env('OCTANE_SERVER', 'roadrunner'),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Force HTTPS
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When this configuration value is set to "true", Octane will inform the
|
||||
| framework that all absolute links must be generated using the HTTPS
|
||||
| protocol. Otherwise your links may be generated using plain HTTP.
|
||||
|
|
||||
*/
|
||||
|
||||
'https' => env('OCTANE_HTTPS', false),
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Octane Listeners
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| All of the event listeners for Octane's events are defined below. These
|
||||
| listeners are responsible for resetting your application's state for
|
||||
| the next request. You may even add your own listeners to the list.
|
||||
|
|
||||
*/
|
||||
|
||||
'listeners' => [
|
||||
WorkerStarting::class => [
|
||||
EnsureUploadedFilesAreValid::class,
|
||||
EnsureUploadedFilesCanBeMoved::class,
|
||||
],
|
||||
|
||||
RequestReceived::class => [
|
||||
...Octane::prepareApplicationForNextOperation(),
|
||||
...Octane::prepareApplicationForNextRequest(),
|
||||
//
|
||||
],
|
||||
|
||||
RequestHandled::class => [
|
||||
//
|
||||
],
|
||||
|
||||
RequestTerminated::class => [
|
||||
// FlushUploadedFiles::class,
|
||||
],
|
||||
|
||||
TaskReceived::class => [
|
||||
...Octane::prepareApplicationForNextOperation(),
|
||||
//
|
||||
],
|
||||
|
||||
TaskTerminated::class => [
|
||||
//
|
||||
],
|
||||
|
||||
TickReceived::class => [
|
||||
...Octane::prepareApplicationForNextOperation(),
|
||||
//
|
||||
],
|
||||
|
||||
TickTerminated::class => [
|
||||
//
|
||||
],
|
||||
|
||||
OperationTerminated::class => [
|
||||
FlushOnce::class,
|
||||
FlushTemporaryContainerInstances::class,
|
||||
// DisconnectFromDatabases::class,
|
||||
// CollectGarbage::class,
|
||||
],
|
||||
|
||||
WorkerErrorOccurred::class => [
|
||||
ReportException::class,
|
||||
StopWorkerIfNecessary::class,
|
||||
],
|
||||
|
||||
WorkerStopping::class => [
|
||||
CloseMonologHandlers::class,
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Warm / Flush Bindings
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The bindings listed below will either be pre-warmed when a worker boots
|
||||
| or they will be flushed before every new request. Flushing a binding
|
||||
| will force the container to resolve that binding again when asked.
|
||||
|
|
||||
*/
|
||||
|
||||
'warm' => [
|
||||
...Octane::defaultServicesToWarm(),
|
||||
],
|
||||
|
||||
'flush' => [
|
||||
//
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Octane Swoole Tables
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| While using Swoole, you may define additional tables as required by the
|
||||
| application. These tables can be used to store data that needs to be
|
||||
| quickly accessed by other workers on the particular Swoole server.
|
||||
|
|
||||
*/
|
||||
|
||||
'tables' => [
|
||||
'example:1000' => [
|
||||
'name' => 'string:1000',
|
||||
'votes' => 'int',
|
||||
],
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Octane Swoole Cache Table
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| While using Swoole, you may leverage the Octane cache, which is powered
|
||||
| by a Swoole table. You may set the maximum number of rows as well as
|
||||
| the number of bytes per row using the configuration options below.
|
||||
|
|
||||
*/
|
||||
|
||||
'cache' => [
|
||||
'rows' => 1000,
|
||||
'bytes' => 10000,
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| File Watching
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following list of files and directories will be watched when using
|
||||
| the --watch option offered by Octane. If any of the directories and
|
||||
| files are changed, Octane will automatically reload your workers.
|
||||
|
|
||||
*/
|
||||
|
||||
'watch' => [
|
||||
'app',
|
||||
'bootstrap',
|
||||
'config/**/*.php',
|
||||
'database/**/*.php',
|
||||
'public/**/*.php',
|
||||
'resources/**/*.php',
|
||||
'routes',
|
||||
'composer.lock',
|
||||
'.env',
|
||||
],
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Garbage Collection Threshold
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| When executing long-lived PHP scripts such as Octane, memory can build
|
||||
| up before being cleared by PHP. You can force Octane to run garbage
|
||||
| collection if your application consumes this amount of megabytes.
|
||||
|
|
||||
*/
|
||||
|
||||
'garbage' => 50,
|
||||
|
||||
/*
|
||||
|--------------------------------------------------------------------------
|
||||
| Maximum Execution Time
|
||||
|--------------------------------------------------------------------------
|
||||
|
|
||||
| The following setting configures the maximum execution time for requests
|
||||
| being handled by Octane. You may set this value to 0 to indicate that
|
||||
| there isn't a specific time limit on Octane request execution time.
|
||||
|
|
||||
*/
|
||||
|
||||
'max_execution_time' => 30,
|
||||
|
||||
];
|
||||
@@ -1,84 +0,0 @@
|
||||
# ============================================================
|
||||
# Dockerfile — Production (FrankenPHP)
|
||||
# FrankenPHP = serveur web + PHP runtime tout-en-un
|
||||
# Remplace PHP-FPM + Nginx en un seul container
|
||||
# ============================================================
|
||||
|
||||
FROM dunglas/frankenphp:php8.3-alpine AS base
|
||||
|
||||
# Extensions PHP nécessaires pour Laravel
|
||||
RUN apk add --no-cache \
|
||||
postgresql-dev \
|
||||
libpng-dev \
|
||||
libjpeg-turbo-dev \
|
||||
freetype-dev \
|
||||
libzip-dev \
|
||||
oniguruma-dev \
|
||||
icu-dev \
|
||||
curl \
|
||||
unzip \
|
||||
git \
|
||||
&& docker-php-ext-configure gd --with-freetype --with-jpeg \
|
||||
&& docker-php-ext-install \
|
||||
pdo \
|
||||
pdo_pgsql \
|
||||
pgsql \
|
||||
mbstring \
|
||||
zip \
|
||||
gd \
|
||||
bcmath \
|
||||
intl \
|
||||
opcache \
|
||||
pcntl
|
||||
|
||||
# Composer
|
||||
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
|
||||
|
||||
# ── Stage Build (Node pour compiler les assets Vite) ────────
|
||||
FROM base AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Dépendances PHP (sans dev)
|
||||
COPY composer.json composer.lock ./
|
||||
RUN composer install \
|
||||
--no-interaction \
|
||||
--no-dev \
|
||||
--prefer-dist \
|
||||
--optimize-autoloader \
|
||||
--no-scripts
|
||||
|
||||
# Dépendances Node + build assets
|
||||
COPY package.json package-lock.json* ./
|
||||
RUN apk add --no-cache nodejs npm \
|
||||
&& npm ci --ignore-scripts
|
||||
|
||||
COPY . .
|
||||
|
||||
# Génère les assets Vite
|
||||
RUN npm run build
|
||||
|
||||
# Post-scripts Composer
|
||||
RUN composer run-script post-autoload-dump || true
|
||||
|
||||
# ── Stage Final ──────────────────────────────────────────────
|
||||
FROM base AS production
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copie tout depuis le builder
|
||||
COPY --from=builder /app /app
|
||||
|
||||
# Config PHP optimisée prod
|
||||
COPY docker/php.prod.ini /usr/local/etc/php/conf.d/99-prod.ini
|
||||
|
||||
# Permissions sur storage et bootstrap/cache
|
||||
RUN mkdir -p storage/logs storage/framework/cache storage/framework/sessions storage/framework/views bootstrap/cache \
|
||||
&& chown -R www-data:www-data storage bootstrap/cache \
|
||||
&& chmod -R 775 storage bootstrap/cache
|
||||
|
||||
# FrankenPHP écoute sur le port 80
|
||||
EXPOSE 80
|
||||
|
||||
# FrankenPHP sert le dossier public/ de Laravel
|
||||
CMD ["frankenphp", "php-server", "--root", "/app/public"]
|
||||
@@ -1,48 +0,0 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
root /var/www/html/public;
|
||||
index index.php;
|
||||
|
||||
# Sécurité — masque la version Nginx
|
||||
server_tokens off;
|
||||
|
||||
# Taille max des uploads
|
||||
client_max_body_size 50M;
|
||||
|
||||
# Logs
|
||||
access_log /var/log/nginx/access.log;
|
||||
error_log /var/log/nginx/error.log warn;
|
||||
|
||||
# Gzip
|
||||
gzip on;
|
||||
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
gzip_min_length 256;
|
||||
|
||||
# Assets statiques — cache long terme
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot|webp)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
# Route principale Laravel
|
||||
location / {
|
||||
try_files $uri $uri/ /index.php?$query_string;
|
||||
}
|
||||
|
||||
# PHP-FPM
|
||||
location ~ \.php$ {
|
||||
fastcgi_pass app:9000;
|
||||
fastcgi_index index.php;
|
||||
fastcgi_buffers 16 16k;
|
||||
fastcgi_buffer_size 32k;
|
||||
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
|
||||
include fastcgi_params;
|
||||
}
|
||||
|
||||
# Bloque l'accès aux fichiers cachés
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
; Configuration PHP optimisée pour la production
|
||||
|
||||
[PHP]
|
||||
; Sécurité
|
||||
expose_php = Off
|
||||
display_errors = Off
|
||||
display_startup_errors = Off
|
||||
log_errors = On
|
||||
error_log = /var/www/html/storage/logs/php-errors.log
|
||||
|
||||
; Performance
|
||||
memory_limit = 256M
|
||||
max_execution_time = 60
|
||||
max_input_time = 60
|
||||
post_max_size = 50M
|
||||
upload_max_filesize = 50M
|
||||
|
||||
; OPcache
|
||||
opcache.enable = 1
|
||||
opcache.enable_cli = 0
|
||||
opcache.memory_consumption = 128
|
||||
opcache.interned_strings_buffer = 16
|
||||
opcache.max_accelerated_files = 10000
|
||||
opcache.revalidate_freq = 0
|
||||
opcache.validate_timestamps = 0
|
||||
opcache.save_comments = 1
|
||||
opcache.fast_shutdown = 1
|
||||
Reference in New Issue
Block a user