#!/bin/bash # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 if [ $# -eq 1 -a "$1" == --nutools-completion ]; then echo ' function __prel_completion() { local cur _get_comp_words_by_ref cur COMPREPLY=($(compgen -W "$(__prel_branches)" "$cur")) } complete -F __prel_completion prel ' exit 0 fi source "$(dirname "$0")/lib/ulib/ulib" || exit 1 urequire DEFAULTS ptools # XXX Ajouter une option pour fusionner les modifications d'une branche de # pré-release dans develop function display_help() { uecho "$scriptname: basculer sur une branche de release USAGE $scriptname -u [SOURCE] $scriptname -c [RELEASE [SOURCE]] $scriptname -m|-l|-d [RELEASE] - Vérifier s'il n'y a pas de modifications locales. Sinon, proposer de faire un commit ou un stash. - Avec l'option -c, s'il existe une branche de release, proposer de basculer vers elle ou sur la branche master. Sinon, basculer sur la branche master. - Avec l'option -u, proposer ou fixer une branche de release à créer. Si elle existe déjà, basculer vers elle. Sinon, la créer en la basant sur SOURCE, qui vaut par défaut develop OPTIONS -C, --projdir PROJDIR Spécifier le répertoire de base du projet qui est dans git. Par défaut, on travaille dans le répertoire courant et on laisse git trouver le répertoire de base du projet. Avec cette option, le répertoire courant est modifié avant de lancer les commandes git. -O, --origin ORIGIN Spécifier le nom de l'origine. Par défaut, utiliser 'origin' -o, --offline En cas de création d'une branche, ne pas pousser vers l'origine; ne pas tenter le cas échéant de traquer la branche dans l'origine; ne pas supprimer une branche dans l'origine. Cette option est automatiquement activée si la variable UTOOLS_VCS_OFFLINE est définie. --online Annuler l'effet de la variable UTOOLS_VCS_OFFLINE: forcer le mode online -c, --checkout Basculer vers une branche de release existante. C'est l'option par défaut. Si aucune branche de release n'existe, basculer vers master -u, --update Préparer une nouvelle release. Utiliser une des options -x, -z ou -p pour spécifier le type de release à préparer. Si la branche qui serait créée pour le type de release existe déjà, basculer vers cette branche. S'il faut la créer, la baser sur la branche SOURCE, qui vaut par défaut develop --menu -x, --major -z, --minor -p, --patchlevel Utilisé avec l'option -u, soit afficher un menu pour choisir la version de la nouvelle release (par défaut), soit préparer respectivement une release majeure, mineure, ou pour correction de bug. -v-OPT Avec l'option -u, spécifier une option de pver permettant de choisir la version de la nouvelle release. Les options supportées sont -v, -l, -a, -b, -r et -R. Par exemple, si la version actuelle sur la branche master est 0.2.3, les options '-uz -v-lbeta' permettent de préparer la release 0.3.0-beta En principe, cette option n'a pas à être utilisée, puisque dans une branche de release, on peut faire vivre les versions de pré-release jusqu'à la release finale. Ainsi, la branche de release est nommée d'après la version finale, mais le projet peut recevoir une version de pré-release incrémentale. -w, --write Si une nouvelle branche est créée avec -u, mettre à jour le fichier VERSION.txt avec pver. C'est l'option par défaut. -n, --no-write Si une nouvelle branche est créée avec -u, NE PAS mettre à jour le fichier VERSION.txt avec pver. Utiliser cette option si la mise à jour du numéro de version doit être faite par manière particulière. -m, --merge Si la branche actuelle est une branche de release, ou s'il existe une branche de release, la merger dans master, puis dans develop, puis la supprimer. Puis basculer sur la branche master. S'il n'existe pas de branche de release, proposer de fusionner les modifications de la branche develop dans la branche master, sans préparer de branche de release au préalable. -l, --log Afficher les modifications actuellement effectuée dans la branche de release par rapport à develop. -d, --diff Afficher les modifications actuellement effectuée dans la branche de release par rapport à develop, sous forme de diff." } projdir= origin=origin action=auto update= merge= checkout= incversion= pver_opts=() write=1 log= diff= parse_opts "${PRETTYOPTS[@]}" \ --help '$exit_with display_help' \ -C:,--projdir: projdir= \ -O:,--origin: origin= \ -o,--offline UTOOLS_VCS_OFFLINE=1 \ --online UTOOLS_VCS_OFFLINE= \ -c,--checkout checkout=1 \ -u,--update '$update=1; [ -z "$incversion" ] && incversion=auto' \ --menu '$update=1; incversion=menu' \ -x,--major '$update=1; incversion=major' \ -z,--minor '$update=1; incversion=minor' \ -p,--patchlevel '$update=1; incversion=patchlevel' \ -v: '$update=1; add@ pver_opts' \ -w,--write write=1 \ -n,--no-write write= \ -m,--merge merge=1 \ -l,--log '$action=diff; log=1' \ -d,--diff '$action=diff; diff=1' \ @ args -- "$@" && set -- "${args[@]}" || die "$args" if [ "$action" == auto ]; then if [ -n "$update" ]; then action=update elif [ -n "$merge" ]; then action=merge elif [ -n "$checkout" ]; then action=checkout else # checkout par défaut action=checkout fi fi if [ -n "$projdir" ]; then cd "$projdir" || die fi git_ensure_gitvcs setx branch=git_get_branch if [ "$action" == update ]; then setx oldver=pver -g "" newver= if [ "$incversion" == auto ]; then if [ ${#pver_opts[*]} -gt 0 ]; then # des options ont été spécifiées, les honorer setx newver=pver -s "$oldver" "${pver_opts[@]}" release="release-$newver" else # sinon, prendre une décision en fonction des branches de release # qui existent déjà setx -a branches=list_release_branches "$origin" if [ ${#branches[*]} -eq 0 ]; then # en l'absence de branche de release, proposer d'en créer une incversion=menu elif [ ${#branches[*]} -eq 1 ]; then # s'il n'y en a qu'une, la prendre release="${branches[0]}" else # sinon, donner le choix dans un menu array_add branches master default_branch="$branch" array_contains branches "$default_branch" || default_branch="${branches[0]}" simple_menu release branches -d "$default_branch" \ -t "Basculer vers une branche de release" \ -m "Veuillez choisir la branche vers laquelle basculer" fi fi fi case "$incversion" in menu) setx majorv=pver -s "$oldver" -ux "${pver_opts[@]}" setx minorv=pver -s "$oldver" -uz "${pver_opts[@]}" setx patchlevelv=pver -g "$oldver" -up "${pver_opts[@]}" release="release-$minorv" branches=("release-$majorv" "release-$minorv" "release-$patchlevelv" master) simple_menu release branches \ -t "Basculer vers une nouvelle branche de release" \ -m "Veuillez choisir la branche à créer" ;; major) setx newver=pver -s "$oldver" -ux "${pver_opts[@]}" release="release-$newver" ;; minor) setx newver=pver -s "$oldver" -uz "${pver_opts[@]}" release="release-$newver" ;; patchlevel) setx newver=pver -s "$oldver" -up "${pver_opts[@]}" release="release-$newver" ;; esac if [ -z "$newver" ]; then # le cas échéant, tenter de calculer la version en fonction de la # release [[ "$release" == release-* ]] && newver="${release#release-}" fi set -- "$release" "$1" action=checkout fi if [ "$action" == checkout ]; then release="$1" source="${2:-develop}" if [ -z "$release" ]; then setx -a branches=list_release_branches "$origin" if [ ${#branches[*]} -eq 0 ]; then # en l'absence de branche de release, basculer sur master release=master elif [ ${#branches[*]} -eq 1 ]; then # s'il n'y en a qu'une, la prendre release="${branches[0]}" else # sinon, donner le choix dans un menu array_add branches master default_branch="$branch" array_contains branches "$default_branch" || default_branch="${branches[0]}" simple_menu release branches -d "$default_branch" \ -t "Basculer vers une branche de release" \ -m "Veuillez choisir la branche vers laquelle basculer" fi fi # On est peut-être déjà sur la bonne branche if git_is_branch "$release"; then if [ -z "$UTOOLS_VCS_OFFLINE" ]; then git_track_branch "$release" "$origin" fi git_fast_forward "$release" "" "$origin" exit 0 fi # Créer/basculer vers une release branch git_ensure_cleancheckout is_any_branch "$release" master release || die "$release: ce n'est pas une branche de release" r=0 if git_have_branch "$release"; then git checkout "$release"; r=$? else estepn "\ Vous allez créer la nouvelle branche de release ${COULEUR_VERTE}$release${COULEUR_NORMALE} à partir de la branche source ${COULEUR_BLEUE}$source${COULEUR_NORMALE}" ask_yesno "Voulez-vous continuer?" O || die git_ensure_branch "$release" "$source" "$origin" [ $? -eq 2 ] && die "Impossible de créer la branche $release. Veuillez vérifier que la branche $source existe" git checkout "$release"; r=$? if [ "$r" -eq 0 -a -n "$newver" -a -n "$write" ]; then if pver -uv "$newver"; then git add -A git commit -m "Init version $newver" fi fi fi if [ "$r" -eq 0 ]; then # éventuellement fast-forwarder automatiquement git_fast_forward "$release" "" "$origin" fi if [ "$r" -eq 0 -a -n "$merge" ]; then set -- "$release" action=merge else exit "$r" fi fi setx -a branches=list_release_branches setb have_release_branches=[ ${#branches[*]} -gt 0 ] release="$1" if [ -n "$release" ]; then if [ -n "$have_release_branches" ]; then is_release_branch "$release" || die "$release: ce n'est pas une branche de release" elif ! is_develop_branch "$release"; then die "Aucune branche de release n'existe, vous devez fusionner à partir de develop" fi git_have_branch "$release" || die "$release: branche invalide" elif is_release_branch "$branch"; then release="$branch" fi if [ "$action" == merge ]; then confirm= if [ -z "$release" ]; then if [ ${#branches[*]} -eq 0 ]; then ewarn "Aucune branche de release n'a été préparée." ewarn "La branche develop sera fusionnée directement dans master." release=develop confirm=-y elif [ ${#branches[*]} -eq 1 ]; then release="${branches[0]}" estepn "Autosélection de $release" else default_release="$branch" array_contains branches "$default_release" || default_release="${branches[0]}" simple_menu release branches -d "$default_release" \ -t "Choix de la branche de release" \ -m "Veuillez choisir la branche" fi fi estepn "Intégration ${COULEUR_VERTE}$release${COULEUR_NORMALE} --> ${COULEUR_BLEUE}master${COULEUR_NORMALE}" ask_yesno $confirm "Voulez-vous continuer?" O || die git checkout master git merge "$release" -m "Intégration de la branche $release" --no-ff || die if [ "$release" != develop ]; then estepn "Intégration ${COULEUR_VERTE}$release${COULEUR_NORMALE} --> ${COULEUR_BLEUE}develop${COULEUR_NORMALE}" git checkout develop git merge "$release" -m "Intégration de la branche $release" --no-ff || die git checkout master estepi "Suppression de la branche locale" git branch -D "$release" if git_have_remote "$origin"; then if [ -z "$UTOOLS_VCS_OFFLINE" ]; then estepi "Suppression de la branche distante" git push "$origin" ":$release" else eimportant "\ La branche $release n'a plus lieu d'être, mais la configuration actuelle interdit de la supprimer dans le dépôt distant. Veuillez le faire manuellement avec la commande suivante: $(qvals git push "$origin" ":$release")" fi fi fi elif [ "$action" == diff ]; then if [ -n "$log" ]; then if [ -n "$release" ]; then git log ${diff:+-p} master.."$release" else git log ${diff:+-p} master..develop fi elif [ -n "$diff" ]; then if [ -n "$release" ]; then git diff master.."$release" else git diff master..develop fi fi fi