volontariapp-ci-tools
Modifier la CI partagée (workflows réutilisables GitHub Actions appelés par tous les repos) ou l'infrastructure locale docker-compose de ci-tools (bases, Redis, MinIO, Datadog). À utiliser avant de toucher ci-tools : tout changement a un impact multi-repo immédiat.
- License 许可
- MIT
- 最近更新
- 2026-11-10
- Stars
- ★ 0
- Forks
- 0
01 前言 Front Matter
- name
- volontariapp-ci-tools
- tags
- [ "ci", "github-actions", "docker-compose" ]
- type
- Catalogue
- paths
- [ "ci-tools/.github/workflows/**", "ci-tools/docker-compose.yml", "ci-tools/scripts/**", "ci-tools/templates/**" ]
- title
- CI partagée et infra locale (ci-tools)
- status
- stable
- sources
- [ { "id": "workflows", "title": "Workflows réutilisables", "resource": "ci-tools/.github/workflows" }, { "id": "compose", "title": "docker-compose local", "resource": "ci-tools/docker-compose.yml" }, { "id": "buckets", "title": "init-buckets.sh (MinIO)", "resource": "ci-tools/scripts/init-buckets.sh" } ]
- verified
- [ { "at": "2026-11-03T14:03:07Z", "by": "process:claude-code", "digest": "d17365b608116a1c" }, { "at": "2026-11-05T17:34:09Z", "by": "claude-code/agent", "digest": "da39a3ee5e6b4b0d" }, { "at": "2026-11-07T15:34:34Z", "by": "claude-code/agent", "digest": "2757689e145423c0" }, { "at": "2026-11-07T15:49:21Z", "by": "claude-code/agent", "digest": "2757689e145423c0" }, { "at": "2026-11-07T15:55:38Z", "by": "claude-code/agent", "digest": "2757689e145423c0" } ]
- generated
- { "at": "2026-10-06T09:12:34Z", "by": "claude-code/claude-opus-5-5" }
- mesh_keys
- [ "ci-tools", "docker-compose", "e2e-orchestrator", "service-ci.yml" ]
- description
- Modifier la CI partagée (workflows réutilisables GitHub Actions appelés par tous les repos) ou l'infrastructure locale docker-compose de ci-tools (bases, Redis, MinIO, Datadog). À utiliser avant de toucher ci-tools : tout changement a un impact multi-repo immédiat.
02 资源文件 3
- 参考文档index.md632 B
- 参考文档log.md5.9 KB
- 参考文档references/lessons.md16.9 KB
03 SKILL.md 正文
CI partagée et infra locale (ci-tools)
ci-tools ne contient aucune logique métier : des workflows réutilisables appelés par les autres repos (uses: Volontariapp/ci-tools/.github/workflows/<x>.yml@main) et l'environnement local complet. Il est aussi présent comme sous-module ci-tools/ dans chaque repo : on le modifie dans le repo meta/ci-tools, jamais dans une copie de sous-module.
Workflows réutilisables[^workflows]
| Famille | Workflows |
|---|---|
| Microservices | service-ci.yml (lint, tests, couverture), service-docker-smoke.yml (healthcheck en conteneur isolé), service-docker-build-push.yml (build et push GHCR) |
| E2E multi-repo | e2e-orchestrator.yml (démarre DB et tous les services, lance la suite E2E), e2e-matrix-checker.yml (bloque une PR qui viserait des images de test sur main) |
npm-packages |
npm-packages-pipeline.yml (orchestration, test-build, snapshot, release), npm-packages-snap-release.yml, npm-packages-release.yml, npm-packages-emergency-release.yml, npm-packages-changelog.yml |
proto-registry |
proto-sync.yml (lint, puis génération et PR dans npm-packages sur main), proto-reset.yml |
| Sécurité | security-scan.yml (Trivy fs : vulnérabilités, secrets, misconfigurations ; input blocking, false par défaut = mode warning ; appelé en job security par service-ci, runner-pipeline, npm-packages-pipeline et nativapp-ci, donc aucun repo appelant à modifier ; ci-tools le lance sur lui-même via security.yml, et proto-registry, deploy et docs ont leur propre security.yml car ils n'utilisent pas la CI partagée) |
| Notification | pr-ready-notify.yml : un message Discord par PR prête (voir ci-dessous) |
| Autres | runner-pipeline.yml, nativapp-ci.yml, validate-compose.yml, ghcr-cleanup.yml, sync-all.yml |
pr-ready-notify.yml s'appelle comme DERNIER job du ci.yml de chaque repo, avec needs: listant tous les jobs de la CI du repo (c'est needs: qui garantit « CI verte », pas une interrogation de l'API). Le if: de l'appelant est ${{ !failure() && !cancelled() && github.event_name == 'pull_request' }} : needs: impose success() implicite, donc un job skipped (e2e conditionnel) bloquerait la notification. L'appelant déclare aussi permissions: { contents: read, issues: write, pull-requests: write } sur ce job : un workflow réutilisable ne peut pas élever les permissions de son appelant, un permissions: contents: read au niveau workflow empêche sinon de poser le label. Input channel : backend (secret DISCORD_WEBHOOK_BACKEND) ou frontend (DISCORD_WEBHOOK_FRONTEND, nativapp). Il notifie si l'auteur est dependabot[bot] ou si la PR porte le label notify-discord, sans conflit (mergeable, relu jusqu'à 10 x 6 s tant que UNKNOWN), hors brouillon. Une PR = un message : le label discord-notified est posé AVANT l'envoi (le claim) ; s'il ne peut pas l'être le job échoue sans rien envoyer (sinon chaque push renotifierait), et si l'envoi échoue le label est retiré pour qu'un rerun puisse renvoyer. Retirer le label à la main pour être renotifié. Une concurrency par PR sérialise deux runs rapprochés. L'appel Discord a --max-time 20 --retry 3 --retry-all-errors et le job timeout-minutes: 3 ; le payload a allowed_mentions: {parse: []} et un titre tronqué. Ce job ne doit pas être un check requis (une panne Discord le met en rouge). Limites assumées : aucune autre gâchette n'existe, donc une PR encore UNKNOWN/conflictuelle à la fin de la CI, ou un label notify-discord ajouté après la CI, ne notifie qu'au push suivant. Les secrets doivent exister en secrets d'organisation ET en secrets Dependabot ; le GITHUB_TOKEN de Dependabot est en lecture seule, le label est donc posé avec ORG_REPO_TOKEN. Sans secret webhook, le job avertit et ne fait rien. Les repos qui listent leurs secrets un par un (npm-packages, runners) doivent passer les deux webhooks et ORG_REPO_TOKEN explicitement. Le titre et les branches de la PR sont lus via gh, jamais interpolés avec ${{ }} dans un script.
Dependabot : ci-tools/.github/dependabot.yml ne couvre que ci-tools. Dependabot n'a ni config partagée ni include distant : le fichier doit exister dans chaque repo. Les modèles sont dans ci-tools/templates/dependabot/ (service.yml, runner.yml) et scripts/render-dependabot.py les rend par type de repo (service, service-nodocker, monorepo, runner, actions). Le workflow sync-dependabot.yml (push sur les modèles ou workflow_dispatch avec l'input repos) ouvre une PR ci/dependabot-sync par repo dont le fichier diffère (secret ORG_REPO_TOKEN requis) : ne jamais éditer <repo>/.github/dependabot.yml à la main, modifier les modèles. sync-all.yml ne propage que le pointeur du sous-module, jamais ce fichier. Le modèle runner liste tous les sous-packages dans directories pour obtenir une seule PR groupée ; garder cette liste alignée sur l'input services du ci.yml du runner. Les PR Dependabot portent les labels docker-e2e (demandé par le Lead Dev) et docker-and-e2e (celui qu'exige service-docker-build-push.yml, sans lui la CI complète refuse la PR) ; les deux labels doivent exister dans le repo. Le contrôle du label docker-and-e2e (service-docker-build-push.yml, e2e-orchestrator.yml) relit les labels en direct avec ORG_REPO_TOKEN et réessaie jusqu'à 5 minutes (10 x 30 s), car le payload de l'événement est figé et Dependabot peut ajouter ses labels plusieurs minutes après l'ouverture de la PR (sinon ci-docker échoue par course, vu sur ms-event#70). Les repos sont publics : un checkout de PR ne doit pas recevoir token: ${{ secrets.ORG_REPO_TOKEN }} (une valeur Dependabot invalide casse alors le checkout, Bad credentials, même sur un repo public) ; ce secret reste réservé aux étapes qui poussent ou ouvrent des PR dans un autre repo. Dependabot n'expose pas les secrets du repo à la CI : ORG_REPO_TOKEN doit aussi être déclaré dans les secrets Dependabot (repo ou organisation) et son GITHUB_TOKEN est en lecture seule, ce qui bloque le push GHCR. Peu de PR : npm passe en hebdomadaire (lundi) avec un groupe dependencies (mineurs et patchs, @volontariapp/* inclus, mergeable seul), un groupe majors séparé (un majeur cassé comme typeorm 1.x, bullmq 6 ou expo 58 ne bloque plus le groupe précédent) et un groupe npm-security pour que les correctifs de sécurité ne soient pas retardés ; la limite est de 3 PR npm ; github-actions et docker passent en mensuel. Pour un runner, directories réunit tous les sous-packages dans cette même PR, donc les E2E ne tournent qu'une fois. Les majeurs de @nestjs/*, @types/node et de l'image Docker node, ainsi que les majeurs et mineurs de eslint, @eslint/js et typescript (typescript-eslint de @volontariapp/eslint-config exige typescript <5.8), ainsi que @opentelemetry/api (@opentelemetry/core exige <1.10.0), sont ignorés (ignore) : les @volontariapp/* demandent NestJS ^11 en peer (Validate Peer Requirements échoue sinon), la CI et engines sont en Node 24, et Node 26 n'embarque plus corepack (corepack: not found dans le Dockerfile). Pour npm-packages (monorepo, directories / et /packages/*), @opentelemetry/sdk-node, @opentelemetry/exporter-*, @opentelemetry/auto-instrumentations-node, bullmq et sharp sont gelés en mineur et majeur : leurs versions 0.x ou mineures ont changé l'API wrappée par les paquets publiés (metricReader devenu metricReaders dans monitoring/src/tracing.ts, appel à 4 arguments dans workers/src/core/base.worker.ts, failOnError retiré de SharpOptions dans storage-pipeline) ; les migrer dans une PR dédiée avec changesets (règle du STOP). Attention : le motif de remplacement directory: "/" + open-pull-requests-limit de render-dependabot.py doit suivre la limite du modèle, sinon packages/* disparaît silencieusement. Pour nativapp, react, react-dom, react-test-renderer, @types/react, typescript-eslint et @typescript-eslint/* sont aussi ignorés pour toute mise à jour (react 19.1.10 casse l'accord avec le SDK qui épingle 19.1.0 ; typescript-eslint résout en 8.72 et lève 10 erreurs no-unsafe-enum-assignment), de même que react-native, react-native-*, @react-native-community/* et @react-navigation/native-stack sont ignorés même en patch : l'étape expo install --check du CI refuse toute version différente de celle du SDK (datetimepicker 8.4.7, keyboard-controller 1.18.6, worklets 0.5.2) et react-native 0.81.6 casse 24 tests sous SDK 54 (qui épingle 0.81.5), et @react-navigation/bottom-tabs 7.21 (render is not a function) et typescript-eslint 8.72 (10 erreurs no-unsafe-enum-assignment) sont gelés en mineur ; trouvé par bisect de la PR groupée contre les tests. Pour nativapp (service-nodocker), react, react-dom, react-native, react-native-*, expo, expo-*, @expo/*, @react-native/* et @types/react sont limités aux patchs : leurs versions sont épinglées par l'Expo SDK (la PR groupée qui montait react-native 0.81 vers 0.88 cassait le lint, 35 erreurs contre 0 sur main) et ne bougent que par une montée de SDK (expo install --fix). Les majeurs de typeorm, bullmq, redis, ioredis et @opentelemetry/core sont aussi ignorés (typeorm 1.x contredit le ~0.3 de @volontariapp/bridge, @opentelemetry/core 3 exige @opentelemetry/api >=1.10) : la PR majors ne garde alors que les outils de dev (globals, lint-staged, @types/supertest). Pour nativapp, les majeurs de jest, jest-expo, @types/jest, @testing-library/react-native et @babel/core suivent la version d'Expo SDK. Retirer ces règles seulement après migration et publication de npm-packages, et passer image, CI et engines ensemble.
Règle : @main est consommé immédiatement par tous les repos. Avant de changer les inputs ou secrets d'un workflow, lister ses appelants (rg "ci-tools/.github/workflows/<x>.yml" <repo> repo par repo) et garder la compatibilité.
Infra locale[^compose]
docker-compose.yml: une base Postgres par service (postgres-user,-post,-event,-social,-ws,-storage,-rankingsur le port 5438),neo4j-social,redisetredis-ws-service, MinIO (minio-initexécutescripts/init-buckets.sh[^buckets]), un conteneur*-migrationavant chaquems-*,api-gatewayetapi-gateway-e2e.otel-collectoretjaegersont encore déclarés à côté dedatadog-agent.- Piège :
e2e-orchestrator.ymllance--profile migrations pull, qui tire l'image de TOUS les*-migrationdéclarés. Déclarerms-<x>-migrationavant la première publication deghcr.io/volontariapp/ms-<x>casse l'E2E de tous les repos : ajouter d'abordpostgres-<x>seul (suffisant pourservice-ci.yml), puis le service de migration une fois l'image publiée. - Piège (commentaire « CI Snapshot Report » de
npm-packages) :npm-packages-snap-release.ymltélécharge les résumés de coverage avecpattern: coverage-summary-*. Avec un seul artefact correspondant (une PR qui ne construit qu'un paquet),download-artifactl'extrait directement danscoverage-artifacts/au lieu d'un dossier par artefact, etscripts/ci-pr-comment.py(qui litcoverage-artifacts/coverage-summary-<id>/coverage-summary.json) affichait des tirets. L'étape « Normalize the coverage artifact layout » range le fichier dans son dossier quand un seul paquet est enBUILD. - Observabilité locale : service
datadog-agent(gcr.io/datadoghq/agent:7), OTLP gRPC sur 4317, APM sur 8126 ;OTEL_EXPORTER_OTLP_ENDPOINT=http://datadog-agent:4317dansx-ms-common-env;DD_API_KEYlu dans le.envlocal. MS_STORAGE_URL: ms-storage:5006est déjà déclaré, maisms-storagen'écoute pas encore en gRPC (voirvolontariapp-file-storage-flow).
[^workflows]: Workflows réutilisables [^compose]: docker-compose local [^buckets]: init-buckets.sh (MinIO)
04 同仓库更多 Skills
volontariapp-user-account-deletion
Suppression de compte en deux temps (PENDING_DELETION): requestDeletionWithUserDeleted, finalizeDeletion, fan-out de user.deleted vers les domaines et gather ws. A utiliser pour tout changement de domain-user touchant la suppression, le statut ou le cycle de vie d'un user.
volontariapp-proto-contract-evolution
Modifier un contrat Protobuf de proto-registry (champ, message, enum, RPC) sans casser la compatibilité wire, puis suivre la cascade proto-registry, PR automatique dans npm-packages, publication, consommateurs. À utiliser avant toute édition d'un .proto.
volontariapp-meta-scripts
Utiliser et faire evoluer la CLI Node de meta (setup, doctor, migrate, certs, repos, bump) et le manifeste repos.json, source unique des repos et unites du workspace.
volontariapp-implement-async-event-flow
Guide pas-à-pas pour concevoir et implémenter un flux asynchrone complet (messaging -> outbox -> post-processors -> ws-service -> client).
research
Investigate a question against high-trust primary sources and capture the findings as a Markdown file in the repo. Use when the user wants a topic researched, docs or API facts gathered, or reading legwork delegated to a background agent.
prototype
Build a throwaway prototype to answer a design question. Use when the user wants to sanity-check whether a state model or logic feels right, or explore what a UI should look like.