Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
33599db5a3 | ||
| 34e75a35fb | |||
|
|
1696602abb | ||
|
|
cacd8718e5 |
119
.gitea/workflows/pull-request.yml
Normal file
119
.gitea/workflows/pull-request.yml
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
name: Pull Request — Quality gate
|
||||||
|
|
||||||
|
# Lance les tests + lint + build sur chaque PR ciblant develop.
|
||||||
|
# Deux jobs en parallele (backend / frontend) pour reduire le temps de feedback.
|
||||||
|
# E2E volontairement hors scope (cf. regle d'or testing.md).
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
|
||||||
|
# Annule les runs obsoletes quand on repush sur la meme PR.
|
||||||
|
concurrency:
|
||||||
|
group: pr-${{ gitea.event.pull_request.number }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
backend:
|
||||||
|
name: Backend (PHP CS + PHPUnit)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
services:
|
||||||
|
postgres:
|
||||||
|
image: postgres:16-alpine
|
||||||
|
env:
|
||||||
|
# Doivent matcher la DATABASE_URL ci-dessous. Le suffixe `_test`
|
||||||
|
# est applique automatiquement par Doctrine en APP_ENV=test.
|
||||||
|
POSTGRES_USER: app
|
||||||
|
POSTGRES_PASSWORD: '!ChangeMe!'
|
||||||
|
POSTGRES_DB: app
|
||||||
|
# Pas de `ports:` host mapping — le runner partage l'hote avec la
|
||||||
|
# prod (Postgres deja sur 5432) et les jobs Gitea Actions tournent
|
||||||
|
# en container sur un reseau Docker dedie : le service est joignable
|
||||||
|
# via son nom (`postgres`), pas via 127.0.0.1.
|
||||||
|
options: >-
|
||||||
|
--health-cmd "pg_isready -U app"
|
||||||
|
--health-interval 5s
|
||||||
|
--health-timeout 5s
|
||||||
|
--health-retries 10
|
||||||
|
|
||||||
|
env:
|
||||||
|
APP_ENV: test
|
||||||
|
APP_SECRET: ci-secret-not-used
|
||||||
|
APP_DEBUG: 0
|
||||||
|
DEFAULT_URI: http://localhost/
|
||||||
|
DATABASE_URL: postgresql://app:!ChangeMe!@postgres:5432/app?serverVersion=16&charset=utf8
|
||||||
|
JWT_SECRET_KEY: '%kernel.project_dir%/config/jwt/private.pem'
|
||||||
|
JWT_PUBLIC_KEY: '%kernel.project_dir%/config/jwt/public.pem'
|
||||||
|
JWT_PASSPHRASE: change_me_in_env_local
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup PHP 8.4
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: '8.4'
|
||||||
|
extensions: pdo, pdo_pgsql, intl, opcache, zip, mbstring, sodium
|
||||||
|
coverage: none
|
||||||
|
tools: composer:v2
|
||||||
|
|
||||||
|
- name: Cache Composer
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ~/.composer/cache
|
||||||
|
key: composer-${{ hashFiles('composer.lock') }}
|
||||||
|
restore-keys: |
|
||||||
|
composer-
|
||||||
|
|
||||||
|
- name: Install PHP dependencies
|
||||||
|
run: composer install --no-interaction --no-progress --prefer-dist
|
||||||
|
|
||||||
|
- name: Generate JWT keypair
|
||||||
|
run: php bin/console lexik:jwt:generate-keypair --skip-if-exists --no-interaction
|
||||||
|
|
||||||
|
- name: PHP CS Fixer (dry-run)
|
||||||
|
run: vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php --allow-risky=yes --dry-run --diff
|
||||||
|
|
||||||
|
- name: Bootstrap test database
|
||||||
|
run: |
|
||||||
|
php bin/console doctrine:database:create --env=test --if-not-exists --no-interaction
|
||||||
|
php bin/console doctrine:migrations:migrate --env=test --no-interaction
|
||||||
|
php bin/console doctrine:schema:update --env=test --force --no-interaction
|
||||||
|
php bin/console doctrine:fixtures:load --env=test --no-interaction
|
||||||
|
php bin/console app:sync-permissions --env=test --no-interaction
|
||||||
|
|
||||||
|
- name: Run PHPUnit
|
||||||
|
run: php -d memory_limit=512M vendor/bin/phpunit
|
||||||
|
|
||||||
|
frontend:
|
||||||
|
name: Frontend (lint + Vitest + build)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
defaults:
|
||||||
|
run:
|
||||||
|
working-directory: frontend
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup Node 22
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '22'
|
||||||
|
cache: npm
|
||||||
|
cache-dependency-path: frontend/package-lock.json
|
||||||
|
|
||||||
|
- name: Install Node dependencies
|
||||||
|
run: npm ci
|
||||||
|
|
||||||
|
- name: ESLint
|
||||||
|
run: npm run lint
|
||||||
|
|
||||||
|
- name: Unit tests (Vitest)
|
||||||
|
run: npm run test
|
||||||
|
|
||||||
|
- name: Build production (nuxt build)
|
||||||
|
run: npm run build:dist
|
||||||
@@ -1,2 +1,2 @@
|
|||||||
parameters:
|
parameters:
|
||||||
app.version: '0.1.37'
|
app.version: '0.1.39'
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ DATABASE_URL="postgresql://malio:password@host.docker.internal:5432/starseed_pro
|
|||||||
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
|
JWT_SECRET_KEY=%kernel.project_dir%/config/jwt/private.pem
|
||||||
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
|
JWT_PUBLIC_KEY=%kernel.project_dir%/config/jwt/public.pem
|
||||||
JWT_PASSPHRASE=<generer avec: openssl rand -hex 32>
|
JWT_PASSPHRASE=<generer avec: openssl rand -hex 32>
|
||||||
JWT_COOKIE_SECURE=1
|
JWT_COOKIE_SECURE=0
|
||||||
JWT_COOKIE_SAMESITE=lax
|
JWT_COOKIE_SAMESITE=lax
|
||||||
JWT_TOKEN_TTL=86400
|
JWT_TOKEN_TTL=86400
|
||||||
JWT_COOKIE_TTL=86400
|
JWT_COOKIE_TTL=86400
|
||||||
@@ -161,7 +161,7 @@ JWT_COOKIE_TTL=86400
|
|||||||
CORS_ALLOW_ORIGIN='^https?://starseed\.malio-dev\.fr$'
|
CORS_ALLOW_ORIGIN='^https?://starseed\.malio-dev\.fr$'
|
||||||
|
|
||||||
# App
|
# App
|
||||||
DEFAULT_URI=https://starseed.malio-dev.fr
|
DEFAULT_URI=http://starseed.malio-dev.fr
|
||||||
```
|
```
|
||||||
|
|
||||||
### 6. Generer les cles JWT
|
### 6. Generer les cles JWT
|
||||||
|
|||||||
@@ -2,8 +2,9 @@
|
|||||||
|
|
||||||
Copier-coller integralement dans une session Claude lancee **sur le serveur de prod** apres que :
|
Copier-coller integralement dans une session Claude lancee **sur le serveur de prod** apres que :
|
||||||
- le push develop + build CI ont publie l'image `gitea.malio.fr/malio-dev/starseed:latest`,
|
- le push develop + build CI ont publie l'image `gitea.malio.fr/malio-dev/starseed:latest`,
|
||||||
- le DNS `starseed.malio-dev.fr` resout vers ce serveur,
|
- la resolution reseau local (DNS interne ou `/etc/hosts` des postes clients) pour `starseed.malio-dev.fr` est en place.
|
||||||
- un certificat Let's Encrypt existe (ou est pret a etre genere) pour `starseed.malio-dev.fr`.
|
|
||||||
|
> Setup : HTTP en reseau local, pas de TLS. Pas de Let's Encrypt.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -11,7 +12,7 @@ Copier-coller integralement dans une session Claude lancee **sur le serveur de p
|
|||||||
|
|
||||||
Tu es sur le serveur de production d'une app Symfony+Nuxt qui s'appelait **Coltura** et qui doit etre renommee en **Starseed**. Le rename cote code est deja fait et merge. Le repo Gitea s'appelle deja `starseed`. L'image `gitea.malio.fr/malio-dev/starseed:latest` est publiee.
|
Tu es sur le serveur de production d'une app Symfony+Nuxt qui s'appelait **Coltura** et qui doit etre renommee en **Starseed**. Le rename cote code est deja fait et merge. Le repo Gitea s'appelle deja `starseed`. L'image `gitea.malio.fr/malio-dev/starseed:latest` est publiee.
|
||||||
|
|
||||||
Le DNS `starseed.malio-dev.fr` resout vers ce serveur. Le certificat Let's Encrypt pour ce nom de domaine est gere a la main par l'admin (a confirmer avant l'etape nginx).
|
L'app est servie en **HTTP sur reseau local** (pas de TLS, pas de Let's Encrypt). La resolution `starseed.malio-dev.fr` est faite via DNS interne ou `/etc/hosts` cote postes clients — pas de certificat a gerer.
|
||||||
|
|
||||||
Objectif : basculer la prod sur le nouveau nom (registry, container, DB, path FS, vhost) **sans perdre les donnees** et avec downtime minimal (mode maintenance pendant la migration).
|
Objectif : basculer la prod sur le nouveau nom (registry, container, DB, path FS, vhost) **sans perdre les donnees** et avec downtime minimal (mode maintenance pendant la migration).
|
||||||
|
|
||||||
@@ -30,9 +31,6 @@ ls -la /var/www/starseed/ 2>/dev/null | head -5
|
|||||||
|
|
||||||
# 4. Vhost nginx system
|
# 4. Vhost nginx system
|
||||||
sudo ls -la /etc/nginx/sites-enabled/ | grep -E "coltura|starseed"
|
sudo ls -la /etc/nginx/sites-enabled/ | grep -E "coltura|starseed"
|
||||||
|
|
||||||
# 5. Cert Let's Encrypt
|
|
||||||
sudo ls /etc/letsencrypt/live/ | grep -E "coltura|starseed"
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**Apres confirmation de l'etat, executer dans cet ordre, en demandant validation utilisateur AVANT chaque etape destructive (DB drop, rm -rf, certificat) :**
|
**Apres confirmation de l'etat, executer dans cet ordre, en demandant validation utilisateur AVANT chaque etape destructive (DB drop, rm -rf, certificat) :**
|
||||||
@@ -43,7 +41,7 @@ sudo ls /etc/letsencrypt/live/ | grep -E "coltura|starseed"
|
|||||||
cd /var/www/coltura
|
cd /var/www/coltura
|
||||||
touch maintenance.on
|
touch maintenance.on
|
||||||
# Verifier qu'une requete renvoie 503
|
# Verifier qu'une requete renvoie 503
|
||||||
curl -s -o /dev/null -w "HTTP %{http_code}\n" https://coltura.malio-dev.fr/
|
curl -s -o /dev/null -w "HTTP %{http_code}\n" http://coltura.malio-dev.fr/
|
||||||
```
|
```
|
||||||
|
|
||||||
Doit renvoyer `503`.
|
Doit renvoyer `503`.
|
||||||
@@ -100,17 +98,18 @@ sudo test -f /var/www/starseed/.env && echo ".env OK"
|
|||||||
Editer `/var/www/starseed/.env` :
|
Editer `/var/www/starseed/.env` :
|
||||||
- `DATABASE_URL` : remplacer `/coltura_prod` -> `/starseed_prod` (et user si renomme a etape 3)
|
- `DATABASE_URL` : remplacer `/coltura_prod` -> `/starseed_prod` (et user si renomme a etape 3)
|
||||||
- `CORS_ALLOW_ORIGIN` : remplacer `coltura.malio-dev.fr` -> `starseed.malio-dev.fr`
|
- `CORS_ALLOW_ORIGIN` : remplacer `coltura.malio-dev.fr` -> `starseed.malio-dev.fr`
|
||||||
- `DEFAULT_URI` : `https://starseed.malio-dev.fr`
|
- `DEFAULT_URI` : `http://starseed.malio-dev.fr`
|
||||||
|
- `JWT_COOKIE_SECURE` : doit etre `0` (HTTP, pas de TLS) — verifier qu'il l'est deja
|
||||||
|
|
||||||
Diff attendu :
|
Diff attendu :
|
||||||
|
|
||||||
```diff
|
```diff
|
||||||
- DATABASE_URL="postgresql://malio:xxx@host.docker.internal:5432/coltura_prod?..."
|
- DATABASE_URL="postgresql://malio:xxx@host.docker.internal:5432/coltura_prod?..."
|
||||||
+ DATABASE_URL="postgresql://malio:xxx@host.docker.internal:5432/starseed_prod?..."
|
+ DATABASE_URL="postgresql://malio:xxx@host.docker.internal:5432/starseed_prod?..."
|
||||||
- CORS_ALLOW_ORIGIN='^https?://coltura\.malio-dev\.fr$'
|
- CORS_ALLOW_ORIGIN='^http://coltura\.malio-dev\.fr$'
|
||||||
+ CORS_ALLOW_ORIGIN='^https?://starseed\.malio-dev\.fr$'
|
+ CORS_ALLOW_ORIGIN='^http://starseed\.malio-dev\.fr$'
|
||||||
- DEFAULT_URI=https://coltura.malio-dev.fr
|
- DEFAULT_URI=http://coltura.malio-dev.fr
|
||||||
+ DEFAULT_URI=https://starseed.malio-dev.fr
|
+ DEFAULT_URI=http://starseed.malio-dev.fr
|
||||||
```
|
```
|
||||||
|
|
||||||
### Etape 6 — Stopper et supprimer l'ancien container
|
### Etape 6 — Stopper et supprimer l'ancien container
|
||||||
@@ -144,9 +143,9 @@ sudo docker compose exec -T -u www-data app php bin/console cache:clear --env=pr
|
|||||||
sudo docker compose exec -T -u www-data app php bin/console cache:warmup --env=prod
|
sudo docker compose exec -T -u www-data app php bin/console cache:warmup --env=prod
|
||||||
```
|
```
|
||||||
|
|
||||||
### Etape 9 — Vhost nginx system + certificat
|
### Etape 9 — Vhost nginx system (HTTP only)
|
||||||
|
|
||||||
Copier le nouveau vhost (a jour avec `server_name starseed.malio-dev.fr` et `root /var/www/starseed/public`) :
|
Copier le nouveau vhost (a jour avec `server_name starseed.malio-dev.fr` et `root /var/www/starseed/public`, `listen 80` uniquement) :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sudo cp /var/www/starseed/infra/prod/nginx-proxy.conf /etc/nginx/sites-available/starseed.conf
|
sudo cp /var/www/starseed/infra/prod/nginx-proxy.conf /etc/nginx/sites-available/starseed.conf
|
||||||
@@ -155,14 +154,10 @@ sudo rm -f /etc/nginx/sites-enabled/coltura.conf
|
|||||||
sudo nginx -t
|
sudo nginx -t
|
||||||
```
|
```
|
||||||
|
|
||||||
**Avant de reload nginx**, generer le certificat Let's Encrypt pour le nouveau domaine (l'utilisateur doit confirmer ; certbot peut casser temporairement le vhost actuel pendant la challenge) :
|
Verifier la resolution reseau local avant reload :
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Verifier le DNS d'abord
|
getent hosts starseed.malio-dev.fr || echo "ATTENTION : starseed.malio-dev.fr ne resout pas localement"
|
||||||
dig +short starseed.malio-dev.fr
|
|
||||||
|
|
||||||
# Generer le cert (l'utilisateur valide)
|
|
||||||
sudo certbot --nginx -d starseed.malio-dev.fr --non-interactive --agree-tos -m matthieu@malio.fr
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Puis :
|
Puis :
|
||||||
@@ -176,9 +171,9 @@ sudo systemctl reload nginx
|
|||||||
```bash
|
```bash
|
||||||
rm -f /var/www/starseed/maintenance.on
|
rm -f /var/www/starseed/maintenance.on
|
||||||
|
|
||||||
# Tests externes
|
# Tests externes (HTTP local)
|
||||||
curl -s -o /dev/null -w "HTTP %{http_code}\n" https://starseed.malio-dev.fr/
|
curl -s -o /dev/null -w "HTTP %{http_code}\n" http://starseed.malio-dev.fr/
|
||||||
curl -s https://starseed.malio-dev.fr/api/version
|
curl -s http://starseed.malio-dev.fr/api/version
|
||||||
```
|
```
|
||||||
|
|
||||||
`/api/version` doit renvoyer du JSON avec la version courante.
|
`/api/version` doit renvoyer du JSON avec la version courante.
|
||||||
@@ -229,8 +224,8 @@ rm -f /var/www/coltura/maintenance.on
|
|||||||
## Regles de comportement pour le Claude prod
|
## Regles de comportement pour le Claude prod
|
||||||
|
|
||||||
- **Ne jamais skipper le backup** (etape 2).
|
- **Ne jamais skipper le backup** (etape 2).
|
||||||
- **Demander confirmation utilisateur** avant : `DROP DATABASE`, `rm -rf`, `certbot`, et avant de lever le mode maintenance final.
|
- **Demander confirmation utilisateur** avant : `DROP DATABASE`, `rm -rf`, et avant de lever le mode maintenance final.
|
||||||
- **Une seule operation destructive a la fois**, attendre le retour utilisateur entre chaque.
|
- **Une seule operation destructive a la fois**, attendre le retour utilisateur entre chaque.
|
||||||
- **Logger systematiquement** la sortie des commandes critiques (pg_dump, docker compose up, certbot).
|
- **Logger systematiquement** la sortie des commandes critiques (pg_dump, docker compose up, nginx -t / reload).
|
||||||
- **Si une etape echoue**, NE PAS continuer — declencher le rollback.
|
- **Si une etape echoue**, NE PAS continuer — declencher le rollback.
|
||||||
- **Ne commit rien** sur le repo depuis le serveur prod.
|
- **Ne commit rien** sur le repo depuis le serveur prod.
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ APP_SECRET=CHANGE_ME_IN_PRODUCTION
|
|||||||
DATABASE_URL="postgresql://starseed:CHANGE_ME@host.docker.internal:5432/starseed_prod?serverVersion=16&charset=utf8"
|
DATABASE_URL="postgresql://starseed:CHANGE_ME@host.docker.internal:5432/starseed_prod?serverVersion=16&charset=utf8"
|
||||||
|
|
||||||
JWT_PASSPHRASE=CHANGE_ME_IN_PRODUCTION
|
JWT_PASSPHRASE=CHANGE_ME_IN_PRODUCTION
|
||||||
JWT_COOKIE_SECURE=1
|
# HTTP en reseau local => cookie non secure
|
||||||
|
JWT_COOKIE_SECURE=0
|
||||||
JWT_TOKEN_TTL=86400
|
JWT_TOKEN_TTL=86400
|
||||||
JWT_COOKIE_TTL=86400
|
JWT_COOKIE_TTL=86400
|
||||||
|
|
||||||
CORS_ALLOW_ORIGIN='^https://starseed\.malio-dev\.fr$'
|
CORS_ALLOW_ORIGIN='^http://starseed\.malio-dev\.fr$'
|
||||||
|
|||||||
6
makefile
6
makefile
@@ -70,6 +70,7 @@ help:
|
|||||||
@printf " \033[36m%-28s\033[0m %s\n" "install-e2e-deps" "One-time : Chromium + libs systeme (sudo)"
|
@printf " \033[36m%-28s\033[0m %s\n" "install-e2e-deps" "One-time : Chromium + libs systeme (sudo)"
|
||||||
@printf "\n \033[1;33mQualite code\033[0m\n"
|
@printf "\n \033[1;33mQualite code\033[0m\n"
|
||||||
@printf " \033[36m%-28s\033[0m %s\n" "php-cs-fixer-allow-risky" "Fix code style PHP (utilise par le pre-commit)"
|
@printf " \033[36m%-28s\033[0m %s\n" "php-cs-fixer-allow-risky" "Fix code style PHP (utilise par le pre-commit)"
|
||||||
|
@printf " \033[36m%-28s\033[0m %s\n" "php-cs-fixer-check" "Dry-run du fixer (CI / verif avant push)"
|
||||||
@printf "\n Plus de details : \033[4mREADME.md\033[0m, \033[4mCLAUDE.md\033[0m\n\n"
|
@printf "\n Plus de details : \033[4mREADME.md\033[0m, \033[4mCLAUDE.md\033[0m\n\n"
|
||||||
|
|
||||||
env-init:
|
env-init:
|
||||||
@@ -258,6 +259,11 @@ php-cs-fixer-allow-risky:
|
|||||||
@echo "Fixing files: $(FILES)"
|
@echo "Fixing files: $(FILES)"
|
||||||
$(EXEC_PHP_CS_FIXER) fix --config=.php-cs-fixer.dist.php --allow-risky=yes $(FILES)
|
$(EXEC_PHP_CS_FIXER) fix --config=.php-cs-fixer.dist.php --allow-risky=yes $(FILES)
|
||||||
|
|
||||||
|
# Dry-run du fixer : echec si au moins un fichier n'est pas conforme.
|
||||||
|
# Utilise par la CI (Gitea pull_request) et avant un push manuel.
|
||||||
|
php-cs-fixer-check:
|
||||||
|
$(EXEC_PHP_CS_FIXER) fix --config=.php-cs-fixer.dist.php --allow-risky=yes --dry-run --diff $(FILES)
|
||||||
|
|
||||||
test:
|
test:
|
||||||
$(EXEC_PHP) php -d memory_limit="512M" vendor/bin/phpunit $(FILES)
|
$(EXEC_PHP) php -d memory_limit="512M" vendor/bin/phpunit $(FILES)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user