Files
siop2/.github/workflows/ci.yml
pr-daaif 5c8d5aac92 feat(r4.1): socle mobile Expo — connexion démo, Ma journée, lecture hors-ligne
apps/mobile (Expo SDK 57, TS strict, workspace pnpm) : connexion
e-mail/mdp + sélecteur démo ADR-002 (uniquement si l'API l'expose),
tabbar de la maquette validée (onglets futurs marqués R4.2/R4.3),
« Ma journée » triée priorité puis échéance (fonction pure testée),
urgence en tête, pastille de synchro.

D1 en actes (lecture) : cache TanStack persisté dans AsyncStorage
(7 jours), NetInfo → onlineManager + bandeau hors-ligne horodaté ;
jeton en SecureStore ; tokens light/dark répliqués et testés ; client
typé régénéré depuis docs/openapi.json (règle d'or).

API : CORS_ORIGINS opt-in (vide par défaut) — Expo web/debug seulement,
le web de prod reste derrière le proxy, les apps natives n'ont pas
d'Origin.

Vérifié 10/10 en Expo web piloté (connexion démo Ahmed → Ma journée
scopée → hors-ligne servie du cache → retour) ; 6 tests jest-expo ;
lint racine étendu (react-hooks) ; job CI mobile, deploy en dépend.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-17 03:12:34 +01:00

212 lines
7.6 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CI SIOP V2 (R0.12) — trois verrous :
# ci-contract : la règle d'or (Zod → OpenAPI → clients typés) — échoue au
# moindre diff entre le contrat committé et la génération ;
# api : migration + tests Jest (couverture ≥ 70 % bloquante, jest.config) ;
# web : typecheck + vitest + build de production.
# lint : ESLint monorepo (dont la règle ADR-001 « pas d'import MinIO
# hors FileStorage ») ;
# e2e : parcours démo Playwright (connexion 1 clic → coquille →
# bascule de rôle < 3 s → /design) contre l'API construite.
name: CI
on:
push:
branches: [main]
pull_request:
concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true
jobs:
lint:
name: lint (ESLint monorepo)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v5
with:
node-version-file: .nvmrc
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm lint
contract:
name: ci-contract (règle d'or)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v5
with:
node-version-file: .nvmrc
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm --filter @siop/shared build
- name: Régénérer la spec et le client typé
run: |
pnpm --filter @siop/shared contract
pnpm --filter @siop/web generate:client
- name: Vérifier qu'aucun artefact ne dérive du contrat
run: |
if ! git diff --exit-code -- docs/openapi.json apps/web/src/api/schema.d.ts; then
echo "::error::Contrat désynchronisé — régénérez spec et clients dans le même commit (pnpm contract && pnpm --filter @siop/web generate:client)."
exit 1
fi
api:
name: api (tests + couverture ≥ 70 %)
runs-on: ubuntu-latest
services:
# R1+ : la migration r1_referentiel exige PostGIS (colonne générée geography).
# pgvector arrivera en R5 (bascule alors sur limage infra/postgres).
postgres:
image: postgis/postgis:18-3.6
env:
POSTGRES_USER: siop
POSTGRES_PASSWORD: siop
POSTGRES_DB: siop
ports: ['5432:5432']
options: >-
--health-cmd "pg_isready -U siop -d siop"
--health-interval 5s --health-timeout 3s --health-retries 10
redis:
image: redis:7.4-alpine
ports: ['6379:6379']
options: >-
--health-cmd "redis-cli ping"
--health-interval 5s --health-timeout 3s --health-retries 10
env:
DATABASE_URL: postgresql://siop:siop@localhost:5432/siop
REDIS_URL: redis://localhost:6379
JWT_SECRET: ci-only-secret-0123456789abcdef
MINIO_ENDPOINT: localhost
MINIO_ACCESS_KEY: siop
MINIO_SECRET_KEY: siop-minio
steps:
- uses: actions/checkout@v5
- name: Démarrer MinIO (l'image officielle exige une commande — pas un service)
run: |
docker run -d --name minio -p 9000:9000 \
-e MINIO_ROOT_USER=siop -e MINIO_ROOT_PASSWORD=siop-minio \
minio/minio:RELEASE.2025-09-07T16-13-09Z server /data
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v5
with:
node-version-file: .nvmrc
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm --filter @siop/shared build
- run: pnpm --filter @siop/api prisma:generate
- run: pnpm --filter @siop/api exec prisma migrate deploy
- run: pnpm --filter @siop/api typecheck
- run: pnpm --filter @siop/api test:cov
web:
name: web (typecheck + tests + build)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v5
with:
node-version-file: .nvmrc
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm --filter @siop/shared build
- run: pnpm --filter @siop/web test
- run: pnpm --filter @siop/web build
mobile:
name: mobile (typecheck + tests jest-expo)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v5
with:
node-version-file: .nvmrc
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm --filter @siop/shared build
- run: pnpm --filter @siop/mobile typecheck
- run: pnpm --filter @siop/mobile test -- --ci
e2e:
name: e2e (parcours démo Playwright)
runs-on: ubuntu-latest
services:
postgres:
image: postgis/postgis:18-3.6
env:
POSTGRES_USER: siop
POSTGRES_PASSWORD: siop
POSTGRES_DB: siop
ports: ['5432:5432']
options: >-
--health-cmd "pg_isready -U siop -d siop"
--health-interval 5s --health-timeout 3s --health-retries 10
redis:
image: redis:7.4-alpine
ports: ['6379:6379']
options: >-
--health-cmd "redis-cli ping"
--health-interval 5s --health-timeout 3s --health-retries 10
env:
DATABASE_URL: postgresql://siop:siop@localhost:5432/siop
REDIS_URL: redis://localhost:6379
JWT_SECRET: ci-only-secret-0123456789abcdef
MINIO_ENDPOINT: localhost
MINIO_ACCESS_KEY: siop
MINIO_SECRET_KEY: siop-minio
steps:
- uses: actions/checkout@v5
- name: Démarrer MinIO (l'image officielle exige une commande — pas un service)
run: |
docker run -d --name minio -p 9000:9000 \
-e MINIO_ROOT_USER=siop -e MINIO_ROOT_PASSWORD=siop-minio \
minio/minio:RELEASE.2025-09-07T16-13-09Z server /data
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v5
with:
node-version-file: .nvmrc
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm --filter @siop/shared build
- run: pnpm --filter @siop/api prisma:generate
- run: pnpm --filter @siop/api exec prisma migrate deploy
- run: pnpm --filter @siop/api build
- run: pnpm --filter @siop/web exec playwright install --with-deps chromium
- run: pnpm --filter @siop/web e2e
- name: Traces Playwright en cas d'échec
if: failure()
uses: actions/upload-artifact@v4
with:
name: playwright-report
path: apps/web/playwright-report/
retention-days: 7
# Déploiement continu (runbook §4) : Dokploy reconstruit et redéploie le
# compose UNIQUEMENT quand les 5 verrous sont verts sur main. Le webhook
# vit dans le secret DOKPLOY_WEBHOOK_URL (Dokploy → service compose →
# Deployments → Webhook URL) ; tant qu'il n'est pas configuré, le job
# se termine en « skip » sans faire échouer le pipeline.
deploy:
name: deploy (Dokploy — siop2.apps.enset.top)
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
needs: [lint, contract, api, web, mobile, e2e]
runs-on: ubuntu-latest
environment: production
steps:
- name: Déclencher le déploiement Dokploy
env:
WEBHOOK_URL: ${{ secrets.DOKPLOY_WEBHOOK_URL }}
run: |
if [ -z "$WEBHOOK_URL" ]; then
echo "::notice::DOKPLOY_WEBHOOK_URL absent — déploiement sauté (configurer le secret pour activer le CD)."
exit 0
fi
curl -fsS -X POST "$WEBHOOK_URL"
echo "Déploiement déclenché — suivi : Dokploy → Deployments."