Guide : Promouvoir une Release (dev -> main)
Dans EPURE, dev est la branche d'intégration et main est la ligne de release. Ni les développeurs humains ni l'Agent App ne poussent sur main : seule la Release App (<owner>-epure-release) le fait, depuis le workflow de release, dans l'environnement protégé release.
La promotion d'une release constitue le 4e Jalon de Validation Humaine Obligatoire (Q101).
Les deux points d'entrée exécutent la même implémentation, le workflow réutilisable Giskard-AI/epure/.github/workflows/release-promote.yml :
| Dépôt | Workflow à déclencher | Rulesets où la Release App doit être Bypass Actor |
|---|---|---|
Dépôt consommateur initialisé par /setup-repo | .github/workflows/release.yml (EPURE Controlled Release (dev -> main)), un appelant minimal épinglé sur un SHA d'EPURE | epure-release-immutability |
Giskard-AI/epure lui-même | .github/workflows/release-promote.yml (Promote Dev to Main (Fast-Forward Release)) | Main basic protection, epure-branch-governance, epure-tag-immutability |
Entrées : semver_tag (vMAJOR.MINOR.PATCH), expected_dev_sha (le SHA complet de 40 caractères de la tête de dev que vous avez relue) et, sur release-promote.yml, l'entrée optionnelle ci_workflow (par défaut ci.yml, le fichier du workflow dont l'exécution sur dev doit avoir réussi).
1. Configuration Initiale (une seule fois)
Créer et installer la Release App. L'étape 3 de
scripts/wizards/setup-github-apps-wizard.sh --repo <owner>/<repo>crée<owner>-epure-release(permissions de dépôtContents: Read and write,Metadata: Read-only, sans webhook), l'installe sur ce seul dépôt et enregistre deux secrets dans l'environnementrelease:EPURE_RELEASE_APP_ID(identifiant numérique de l'App) etEPURE_RELEASE_APP_PRIVATE_KEY(PEM). L'assistant enchaîne toujours toutes les étapes, y compris l'Agent App ; si seule la Release App vous intéresse, suivez les mêmes étapes à la main puis enregistrez les secrets avecgh secret set <NAME> -R <owner>/<repo> --env release.Déclarer la Release App comme Bypass Actor (
actor_type: Integration,actor_id: <App ID>,bypass_mode: always) sur chaque ruleset couvrantmainet les tagsv*(voir le tableau ci-dessus). Dans un dépôt consommateur,node dist/cli/setup-repo.mjs --repo <owner>/<repo> --release-app-id <App ID> --apply --apply-github-settingsle fait pourepure-release-immutability. Ailleurs, ajoutez l'acteur avecgh apien conservant les acteurs existants :bashgh api repos/<owner>/<repo>/rulesets/<ruleset-id> \ | jq '{name, target, enforcement, conditions, rules, bypass_actors: (.bypass_actors + [{actor_id: <App ID>, actor_type: "Integration", bypass_mode: "always"}])}' \ | gh api -X PUT repos/<owner>/<repo>/rulesets/<ruleset-id> --input -Protéger l'environnement
releaseavec au moins un relecteur obligatoire et une politique de branches de déploiement limitée àdev:bashgh api -X PUT repos/<owner>/<repo>/environments/release --input - <<'EOF' { "reviewers": [{"type": "User", "id": <reviewer-user-id>}], "deployment_branch_policy": {"protected_branches": false, "custom_branch_policies": true} } EOF gh api -X POST repos/<owner>/<repo>/environments/release/deployment-branch-policies \ -f name=dev -f type=branch
2. Prérequis Avant Chaque Release
- Toutes les PRs
feature/* -> devprévues pour la version ont été fusionnées en squash dansdev. - Le workflow
CI(.github/workflows/ci.yml) s'est terminé ensuccesssur la tête dedev. - Vous avez choisi le prochain tag à partir des Conventional Commits depuis le tag précédent (
fix:-> PATCH,feat:-> MINOR,!:/BREAKING CHANGE-> MAJOR).
3. Déclencher la Release
Déclenchez le workflow depuis dev (l'environnement release refuse les autres refs), puis approuvez le déploiement en attente dans l'onglet Actions.
Dépôt consommateur :
DEV_SHA="$(gh api repos/my-org/craft-calculator/branches/dev --jq .commit.sha)"
gh workflow run release.yml -R my-org/craft-calculator --ref dev \
-f semver_tag=v1.0.0 -f expected_dev_sha="$DEV_SHA"EPURE lui-même :
DEV_SHA="$(gh api repos/Giskard-AI/epure/branches/dev --jq .commit.sha)"
gh workflow run release-promote.yml -R Giskard-AI/epure --ref dev \
-f semver_tag=v1.0.0 -f expected_dev_sha="$DEV_SHA"4. Ce qu'exécute release-promote.yml
- Valide tout avant la moindre écriture et s'arrête avec une annotation
::error::lorsque :semver_tagne respecte pasvMAJOR.MINOR.PATCH(sans zéro initial) ;expected_dev_shan'est pas un SHA de 40 caractères égal à la tête actuelle deorigin/dev;- le tag existe déjà ;
origin/mainn'est pas un ancêtre deexpected_dev_sha(fast-forward impossible) ;- la dernière exécution de
CIpour ce SHA surdevne s'est pas terminée ensuccess; EPURE_RELEASE_APP_IDouEPURE_RELEASE_APP_PRIVATE_KEYmanque dans l'environnementrelease.
- Vérifie la séparation des rôles de la Release App avec
actions/verify-app-role(promote_dev_to_mainsurrefs/heads/main, depuisrelease.yml/release-promote.yml, environnementrelease). - Émet un jeton d'installation éphémère avec
actions/create-github-app-token, limité à ce dépôt et à la seule permissioncontents: write. - Fast-forward de
mainet tag atomiques : crée le tag annoté surexpected_dev_shaau nom de<owner>-epure-release[bot], puis exécute un uniquegit push --atomicde<sha>:refs/heads/mainetrefs/tags/<tag>. Les deux refs avancent ensemble ou aucune ne bouge ; aucun push forcé, et le jeton n'est transmis àgitque par l'environnement du processus (jamais écrit dans.git/config). - Publie la GitHub Release avec
gh release create --verify-tag --generate-notes --notes-start-tag <tag précédent> --latest. - Révoque le jeton dans une étape
always(), même si une étape précédente a échoué.
5. Relancer Après un Échec
Relancez avec les mêmes entrées :
- Échec avant le push : rien n'a été écrit ; corrigez la cause et relancez.
- Push effectué, release non publiée : le workflow constate que le tag et
origin/mainpointent déjà surexpected_dev_sha, saute le push (ainsi que la vérification de la tête dedev, qui a pu avancer) et publie seulement la GitHub Release. - Release déjà publiée : l'exécution se termine par une notice sans rien modifier.
- Tag existant sur un autre commit : l'exécution s'arrête. Les tags de release sont immuables ; choisissez la version suivante.

