Retour au cours

projet release

Objectifs

  • Automatiser les tâches répétitives et sujettes à erreur du processus de “release”.
  • Lire un numéro de version depuis un fichier pour garantir une source de vérité unique.
  • Générer automatiquement des notes de version (CHANGELOG) à partir de l’historique Git.
  • Créer et pousser un tag Git annoté pour marquer la version.

Le Scénario

Le processus de release est souvent manuel : on met à jour un fichier de version, on compile un changelog en copiant-collant des messages de commit, on crée un tag, puis on pousse le tout. C’est lent et on oublie souvent une étape. Un script peut automatiser tout cela pour rendre le processus rapide, fiable et cohérent.

La Stratégie du script

  1. Lire la version depuis un fichier VERSION (ex: 1.2.3).
  2. Vérifier que l’on est sur la branche main et que le dépôt est “propre”.
  3. Trouver le dernier tag Git pour déterminer le point de départ du changelog.
  4. Générer les notes de version en listant les commits depuis ce dernier tag.
  5. Créer un commit de “release” qui met à jour le CHANGELOG.md.
  6. Créer un tag Git annoté v1.2.3.
  7. Pousser les commits et le tag vers le dépôt distant.

Le Script Complet

Voici un exemple de script de release. Il utilise des commandes Git avancées mais illustre bien la puissance de l’automatisation.

#!/usr/bin/env bash

# Mode strict
set -euo pipefail

# --- Documentation ---
# Description:
#   Automatise le processus de release : mise à jour du changelog,
#   commit de version, et création d'un tag Git.
#
# Usage:
#   ./release.sh
#   Le script lit la version dans le fichier 'VERSION'.

readonly SCRIPT_NAME="$(basename "$0")"

# --- Fonctions ---

die() {
  echo >&2 "[ERREUR] $@"
  exit 1
}

# --- Fonction Principale ---
main() {
  # --- Validations ---
  if ! git diff --quiet; then
    die "Le répertoire de travail n'est pas propre. Veuillez commiter ou stasher vos changements."
  fi

  if [[ "$(git rev-parse --abbrev-ref HEAD)" != "main" ]]; then
    die "Ce script doit être lancé depuis la branche 'main'."
  fi
  
  if [[ ! -f "VERSION" ]]; then
    die "Le fichier 'VERSION' est manquant."
  fi

  # --- Logique Principale ---
  local VERSION
  VERSION=$(cat VERSION)
  local TAG_NAME="v$VERSION"

  echo "Préparation de la release : $TAG_NAME..."

  if git rev-parse "$TAG_NAME" >/dev/null 2>&1; then
    die "Le tag '$TAG_NAME' existe déjà."
  fi

  # --- Génération du Changelog ---
  local LAST_TAG
  # Trouve le tag le plus récent
  LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || git rev-list --max-parents=0 HEAD)
  
  echo "Génération des notes de version depuis le tag '$LAST_TAG'..."

  local CHANGELOG_HEADER="## $TAG_NAME ($(date +'%Y-%m-%d'))"
  local GIT_LOG
  GIT_LOG=$(git log "${LAST_TAG}..HEAD" --oneline --no-merges)

  # On utilise un fichier temporaire pour construire le nouveau changelog
  local TMP_CHANGELOG
  TMP_CHANGELOG=$(mktemp)
  
  {
    echo "$CHANGELOG_HEADER"
    echo ""
    echo "$GIT_LOG"
    echo ""
    echo "---"
    echo ""
    cat CHANGELOG.md
  } > "$TMP_CHANGELOG"

  mv "$TMP_CHANGELOG" CHANGELOG.md

  echo "Le CHANGELOG.md a été mis à jour. Veuillez le vérifier avant de continuer."
  read -p "Appuyez sur Entrée pour commiter et tagger, ou Ctrl+C pour annuler."

  # --- Commit et Tag ---
  git add CHANGELOG.md
  git commit -m "chore(release): préparer la release $TAG_NAME"
  git tag -a "$TAG_NAME" -m "Release $TAG_NAME"

  echo "Tag '$TAG_NAME' créé."
  
  # --- Push ---
  read -p "Pousser les changements et le tag vers 'origin' ? (o/N) " -n 1 -r
  echo
  if [[ $REPLY =~ ^[Oo]$ ]]; then
    echo "Push en cours..."
    git push origin main
    git push origin "$TAG_NAME"
    echo "Release terminée."
  else
    echo "Push annulé. N'oubliez pas de pousser manuellement : git push origin main && git push origin $TAG_NAME"
  fi
}

# --- Point d'entrée ---
main "$@"

Bonnes Pratiques Mises en Œuvre

  • Garde-fous : Le script refuse de s’exécuter si des changements sont en cours ou si on n’est pas sur la bonne branche.
  • Source de vérité unique : La version est lue depuis un fichier VERSION, ce qui évite les erreurs de saisie.
  • Automatisation du changelog : Générer le changelog à partir de Git incite à écrire des messages de commit clairs et utiles.
  • Interaction utilisateur : Le script demande confirmation avant d’effectuer les actions irréversibles (commit, push).
  • Tags annotés : git tag -a crée un “vrai” objet tag avec un message et une date, ce qui est la bonne pratique pour les releases.

Pièges Évités

  • Releaser sur la mauvaise branche : La vérification de la branche est une sécurité essentielle.
  • Oublier de pusher les tags : git push ne pousse pas les tags par défaut. Il faut git push origin <nom_du_tag> ou git push --tags.
  • Changelog manuel fastidieux : L’automatisation rend le processus indolore.

Exercices

  1. Mise en place du projet :

    • Créez un nouveau dépôt Git (git init).
    • Créez un fichier VERSION contenant 0.1.0.
    • Créez un fichier CHANGELOG.md vide.
    • Faites un premier commit.
  2. Simuler le développement :

    • Créez un fichier app.js.
    • Faites deux ou trois commits avec des messages clairs (ex: “feat: ajouter authentification”, “fix: corriger bug d’affichage”).
  3. Lancer la release :

    • Copiez le script de cette leçon dans votre projet sous le nom release.sh et rendez-le exécutable.
    • Lancez ./release.sh.
    • Lorsque le script vous le demande, ouvrez CHANGELOG.md dans un autre terminal pour vérifier son contenu.
    • Validez et laissez le script se terminer (vous pouvez choisir de ne pas pusher).
    • Vérifiez avec git log et git tag que le commit de release et le tag v0.1.0 ont bien été créés.