Configuration de l'Automatisation du Dépôt
Scaffolder la stack complète commits-conventionnels + release-please + automatisation CI dans n'importe quel dépôt. Fonctionne sur les dépôts vides et ceux contenant déjà du contenu.
Vue d'ensemble
Shift Left : Détecter les problèmes le plus tôt possible. Un mauvais message de commit attrapé au moment de la PR coûte quelques secondes ; le même message polluant les notes de version coûte de la crédibilité. Déplacez la validation en amont — imposez le format du commit au niveau du titre de la PR, validez les configurations dans la CI, détectez les problèmes avant qu'ils n'atteignent la branche principale.
Plus vite est plus sûr : Des lots plus petits et des versions plus fréquentes réduisent les risques. Une version avec 3 modifications est plus facile à déboguer qu'une version avec 30. Les versions automatisées renforcent la confiance dans le processus de version lui-même.
Cette compétence met en place le mécanisme de contrôle : la validation du titre de la PR garantit que chaque fusion dans la branche principale produit un commit significatif et analysable. Release-please transforme ces commits en versions automatisées avec des changelogs. La CI détecte les problèmes de configuration et de code avant la fusion.
Quand l'utiliser
- Vous créez un nouveau dépôt et avez besoin d'automatisation des versions dès le premier jour
- Le dépôt existant ne dispose pas de versionnement automatisé ni de génération de changelog
- Migration depuis des processus de version manuels ou d'autres outils de version
- Le dépôt a besoin de validation du titre des PR et d'étiquetage automatique
Quand NE PAS l'utiliser
- Le dépôt a déjà release-please ou un équivalent configuré (vérifiez d'abord)
- Monorepo avec un outillage de version incompatible (par ex., Lerna avec versionnement indépendant déjà fonctionnel)
- Le dépôt est un fork où l'amont contrôle le processus de version
Processus
Étape 1 : Recueillir la Configuration
Demandez à l'utilisateur ces valeurs avant de générer des fichiers :
| Paramètre | Défaut | Description |
|---|---|---|
PROJECT_NAME | (obligatoire) | Nom lisible du projet pour la documentation |
INITIAL_VERSION | 0.1.0 | Version sémantique de départ |
RELEASE_TYPE | simple | simple (paquet unique) ou node / python / etc. |
REPO_LAYOUT | single | single (un paquet à la racine) ou monorepo (plusieurs paquets) |
PACKAGE_PATHS | . | Pour monorepo : chemins séparés par des virgules comme packages/api,packages/ui |
DEPENDABOT_ECOSYSTEMS | github-actions | Séparés par des virgules : github-actions, npm, pip, cargo, etc. |
DEFAULT_BRANCH | main | Branche qui déclenche les versions |
Détectez automatiquement le bon RELEASE_TYPE :
package.jsonexiste → suggérernodesetup.pyoupyproject.tomlexiste → suggérerpythonCargo.tomlexiste → suggérerrust- Aucun des cas ci-dessus → suggérer
simple
Étape 2 : Détecter les Fichiers Existants
Avant de créer quoi que ce soit, vérifiez les conflits :
for f in .github/workflows/pull-request.yml .github/workflows/main-branch.yml \
.github/release-please-config.json .release-please-manifest.json \
.github/dependabot.yml .github/pull_request_template.md docs/DEVELOPMENT.md; do
[[ -f "$f" ]] && echo "EXISTE : $f"
done
Si des fichiers existent, affichez un diff de ce qui changerait et demandez avant d'écraser. N'écrasez pas silencieusement — les fichiers existants peuvent contenir des personnalisations spécifiques au projet.
Étape 3 : Créer les Fichiers de Configuration
Créez les fichiers dans cet ordre (les dépendances circulent de haut en bas) :
3a. .github/release-please-config.json
Paquet unique :
{
"release-type": "{{RELEASE_TYPE}}",
"bump-minor-pre-major": true,
"bump-patch-for-minor-pre-major": false,
"initial-version": "{{INITIAL_VERSION}}",
"packages": {
".": {}
}
}
Monorepo : Remplacez packages par une entrée par chemin :
{
"packages": {
"packages/api": { "release-type": "node" },
"packages/ui": { "release-type": "node" }
}
}
Chaque paquet du monorepo reçoit son propre release-type — demandez à l'utilisateur par paquet s'ils diffèrent.
3b. .release-please-manifest.json
Paquet unique :
{
".": "{{INITIAL_VERSION}}"
}
Monorepo : Une entrée par chemin de paquet, chacune avec sa propre version.
3c. .github/workflows/pull-request.yml
name: Validation de la Pull Request
on:
pull_request:
types: [opened, edited, synchronize, reopened]
permissions:
pull-requests: write
contents: read
statuses: write
jobs:
validate-pr-title:
name: Valider le Titre de la PR
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@v6
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
types: |
feat
fix
docs
chore
refactor
test
ci
requireScope: false
subjectPattern: ^[a-z].+$
subjectPatternError: |
Le sujet "{subject}" trouvé dans le titre de la pull request "{title}"
ne correspond pas au modèle configuré. Veuillez vous assurer que le sujet
commence par un caractère minuscule (selon les commits conventionnels).
auto-label:
name: Étiquetage Automatique de la PR
runs-on: ubuntu-latest
steps:
- name: Étiqueter en fonction du titre de la PR
uses: actions/github-script@v8
with:
script: |
const title = context.payload.pull_request.title;
const labelMap = {
'feat': 'enhancement',
'fix': 'bug',
'docs': 'documentation',
'chore': 'chore',
'refactor': 'refactor',
'test': 'test',
'ci': 'ci'
};
for (const [type, label] of Object.entries(labelMap)) {
if (title.startsWith(`${type}:`) || title.startsWith(`${type}(`)) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
labels: [label]
});
break;
}
}
no-ai-attribution:
name: Pas d'Attribution IA
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
- name: Analyser les messages de commit et le corps de la PR
env:
PR_BODY: ${{ github.event.pull_request.body }}
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
# Seulement les formes de pied de page/trailer : un commit qui mentionne simplement Claude ou
# Anthropic dans le texte est acceptable. Les trailers Co-authored-by humains sont acceptables.
PAT='^[[:space:]]*Co-authored-by:.*(Claude|Anthropic|noreply@anthropic)|Generated with \[?(Claude|Anthropic)'
fail=0
if git log --format='%B' "$BASE_SHA..$HEAD_SHA" | grep -Eiq "$PAT"; then
echo "::error::Attribution IA trouvée dans un message de commit sur cette branche"
fail=1
fi
if printf '%s' "$PR_BODY" | grep -Eiq "$PAT"; then
echo "::error::Attribution IA trouvée dans la description de la PR"
fail=1
fi
[ "$fail" -eq 0 ] && echo "Aucune attribution IA trouvée."
exit $fail
ci-checks:
name: Vérifications CI
runs-on: ubuntu-latest
continue-on-error: true
steps:
- uses: actions/checkout@v6
- name: Valider la syntaxe YAML
run: |
sudo apt-get update && sudo apt-get install -y yamllint
find . -name "*.yml" -o -name "*.yaml" | while read file; do
echo "Vérification de $file"
yamllint -d "{extends: default, rules: {line-length: disable}}" "$file" || true
done
Pas d'Attribution IA est bloquant dès le premier jour — il n'a pas de surface de faux positifs à valider (il vérifie les formes de trailer et de pied de page, pas le texte), donc il ne passe pas par le chemin de graduation ci-dessous.
Chemin de graduation des vérifications CI :
- Déployer avec
continue-on-error: true(informatif, non bloquant) - Valider que les vérifications passent sur 3 à 5 PR réelles
- Supprimer
continue-on-erroret ajouter aux vérifications requises de la protection de branche - Ajouter des vérifications spécifiques au projet (lint, test, build) au fur et à mesure que la base de code grandit
Aucune porte ne peut être sautée. Si le lint échoue, corrigez le lint — ne désactivez pas la règle. Si un test échoue, corrigez le code — ne sautez pas le test. Quand la CI échoue, transmettez la sortie d'échec à votre agent et corrigez-la avant de pousser à nouveau.
3d. .github/workflows/main-branch.yml
name: Automatisation des Versions
on:
push:
branches:
- {{DEFAULT_BRANCH}}
permissions:
contents: write
pull-requests: write
jobs:
release-please:
name: Release Please
runs-on: ubuntu-latest
outputs:
release_created: ${{ steps.release.outputs.release_created }}
tag_name: ${{ steps.release.outputs.tag_name }}
steps:
- uses: googleapis/release-please-action@v4
id: release
with:
config-file: .github/release-please-config.json
manifest-file: .release-please-manifest.json
update-major-tag:
name: Mettre à Jour le Tag de Version Majeure
needs: release-please
if: ${{ needs.release-please.outputs.release_created == 'true' }}
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v6
with:
ref: ${{ needs.release-please.outputs.tag_name }}
- name: Mettre à jour le tag de version majeure
env:
TAG_NAME: ${{ needs.release-please.outputs.tag_name }}
run: |
MAJOR_TAG=$(echo "$TAG_NAME" | sed 's/^\(v[0-9]*\).*/\1/')
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git tag -fa "$MAJOR_TAG" -m "Mise à jour du tag $MAJOR_TAG vers $TAG_NAME"
git push origin "$MAJOR_TAG" --force
3e. .github/dependabot.yml
Générez une entrée updates par écosystème :
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
labels:
- "dependencies"
commit-message:
prefix: "chore"
include: "scope"
La configuration commit-message garantit que les PR de Dependabot sont conformes aux commits conventionnels automatiquement (par ex., chore(deps): mise à jour de actions/checkout de v5 à v6).
3f. .github/pull_request_template.md
## Ce qui a changé
[Décrivez les modifications en détail - cela apparaît dans le changelog]
## Pourquoi
[Contexte et motivation du changement]
## Liste de vérification
- [ ] Le titre de la PR respecte le format des commits conventionnels (`type: description`)
- [ ] La description explique quoi et pourquoi (pas seulement quoi)
- [ ] Aucun secret dans le code, les logs ou le contrôle de version
- [ ] Les tests passent localement
La section "Pourquoi" est cruciale — les descriptions de PR qui ne disent que quoi a changé sont redondantes avec le diff. Le pourquoi fournit le contexte qui rendra le git blame futur utile.
3g. .gitignore (si manquant)
Vérifiez si un .gitignore existe. Sinon, créez-en un adapté au projet :
# Dépendances
node_modules/
# Sortie de construction
dist/
build/
.next/
# Environnement
.env
.env.local
*.pem
# IDE
.idea/
# Système d'exploitation
.DS_Store
Thumbs.db
Adaptez à la stack détectée. Ne committez jamais node_modules/, .env ou les artefacts de construction.
3h. docs/DEVELOPMENT.md
Générez un guide de développement couvrant :
- Workflow de branches — Développement basé sur le tronc : branches de fonctionnalités courtes (1-3 jours), fusion rapide. Nommage des branches :
feature/<desc>,fix/<desc>,chore/<desc>. - Discipline des commits — Committez librement dans les branches (n'importe quel format). Seul le titre de la PR compte — il devient le message de commit squash-merge sur la branche principale et apparaît dans le changelog.
- Format du titre de la PR — Tableau des types :
feat,fix,docs,chore,refactor,test,ci. Changements cassants :feat!:ouBREAKING CHANGE:dans le corps. - Taille des changements — Visez ~100 lignes par PR. ~300 acceptable pour des changements logiques uniques. ~1000+ doit être divisé. Séparez le refactoring du travail de fonctionnalité — ce sont des changements différents.
- Descriptions de PR — Première ligne : courte, impérative, autonome. Corps : ce qui change et pourquoi. Anti-patrons : "Correction de bug", "Mise à jour du fichier", "Phase 1".
- Vérifications automatisées — Validation du titre de la PR (obligatoire, bloque la fusion), étiquetage automatique (informatif), vérifications CI (initialement non bloquantes, promues en obligatoires).
- Processus de version — release-please crée une PR de version → fusion → Release GitHub + tags + changelog. Progression des versions : avant 1.0 (
feat→ mineure,fix→ correctif) vs après 1.0 (feat→ mineure,fix→ correctif,BREAKING CHANGE→ majeure). - Dépannage — Problèmes courants : échec de validation du titre de la PR (modifier le titre), échec des vérifications CI, fusion bloquée (vérifier les statuts requis).
Utilisez {{PROJECT_NAME}} dans les titres.
Étape 4 : Recommandations de Protection de Branche
Après la création des fichiers, présentez ces étapes manuelles (non appliquées automatiquement) :
Paramètres de protection de branche GitHub recommandés pour {{DEFAULT_BRANCH}} : ✓ Exiger une pull request avant la fusion ✓ Exiger les vérifications de statut : "Valider le Titre de la PR" ✓ Exiger que les branches soient à jour ✓ Permettre uniquement la fusion squash ✓ Exiger un historique linéaire
Pourquoi la fusion squash : L'historique des branches (commits WIP, correctifs, expériences) est préservé dans la PR. La branche principale obtient un journal propre, significatif et linéaire où chaque commit est un commit conventionnel. C'est ce qui rend release-please et git log --oneline utiles.
Étape 5 : Activer les Permissions des Workflows
Release-please a besoin d'autorisation pour créer des pull requests via GitHub Actions. C'est désactivé par défaut sur les nouveaux dépôts et fera échouer le workflow d'Automatisation des Versions avec :
GitHub Actions n'est pas autorisé à créer ou approuver des pull requests.
Demandez à l'utilisateur d'activer ce paramètre :
Dépôt GitHub → Paramètres → Actions → Général → Permissions des workflows : ✓ Autorisations en lecture et écriture (requis pour que release-please pousse les commits de changelog) ✓ Autoriser GitHub Actions à créer et approuver des pull requests (requis pour les PR de version)
Cette étape doit être complétée avant le premier push vers {{DEFAULT_BRANCH}}, sinon release-please échouera à chaque push jusqu'à ce qu'elle soit activée.
Étape 6 : Vérifier
# Valider la syntaxe YAML
yamllint .github/workflows/*.yml .github/dependabot.yml
# Valider le JSON
python3 -c "import json;
… [tronqué pour la traduction]
# Valider la syntaxe YAML
yamllint .github/workflows/*.yml .github/dependabot.yml
# Valider le JSON
python3 -c "import json;
print('JSON OK')
json.load(open('.github/release-please-config.json'))
json.load(open('.release-please-manifest.json'))
print('Tous les fichiers JSON sont valides')"
# Vérifier que le modèle de PR existe
[[ -f .github/pull_request_template.md ]] && echo "Template de PR trouvé" || echo "ERREUR : Template de PR manquant"
# Vérifier que docs/DEVELOPMENT.md existe
[[ -f docs/DEVELOPMENT.md ]] && echo "Guide DEV trouvé" || echo "ERREUR : Guide DEV manquant"