# -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 # configuration par défaut # doit être identique au contenu de pman.conf # les branches sont mergées dans cet ordre: # upstream --> develop --> [release -->] main --> dist # feature _/ hotfix _/ # branche upstream UPSTREAM= # branches de développement DEVELOP=develop FEATURE=wip/ # branche de préparation de release RELEASE=release- # branche de release MAIN=master TAG_PREFIX= TAG_SUFFIX= # branche de hotfix HOTFIX=hotfix- # branche de distribution DIST= # désactiver les releases automatiques? NOAUTO= CONFIG_VARS=( UPSTREAM DEVELOP FEATURE RELEASE MAIN TAG_PREFIX TAG_SUFFIX HOTFIX DIST NOAUTO ) ################################################################################ PMAN_TOOL_PUPS=UPSTREAM PMAN_TOOL_PDEV=DEVELOP PMAN_TOOL_PWIP=FEATURE PMAN_TOOL_PMAIN=MAIN PMAN_TOOL_PDIST=DIST UPSTREAM_BASE= ; UPSTREAM_MERGE_FROM= ; UPSTREAM_MERGE_TO=DEVELOP ; UPSTREAM_PREL= ; UPSTREAM_DELETE= DEVELOP_BASE=MAIN ; DEVELOP_MERGE_FROM=FEATURE ; DEVELOP_MERGE_TO=MAIN ; DEVELOP_PREL=to ; DEVELOP_DELETE=from MAIN_BASE= ; MAIN_MERGE_FROM=DEVELOP ; MAIN_MERGE_TO=DIST ; MAIN_PREL=from ; MAIN_DELETE= DIST_BASE=MAIN ; DIST_MERGE_FROM=MAIN ; DIST_MERGE_TO= ; DIST_PREL= ; DIST_DELETE= FEATURE_BASE=DEVELOP ; FEATURE_MERGE_FROM= ; FEATURE_MERGE_TO=DEVELOP ; FEATURE_PREL= ; FEATURE_DELETE=to function get_base_branch() { # afficher la branche depuis laquelle créer la branche $1 # retourner 1 en cas d'erreur (pas de branche source) local branch="$1" infos [ -n "$branch" ] || return 1 infos="${branch^^}_BASE"; branch="${!infos}" [ -n "$branch" ] && echo "$branch" || return 1 } function get_merge_from_branch() { # afficher la branche depuis laquelle la branche $1 doit merger # retourner 1 en cas d'erreur (pas de branche source) local branch="$1" infos [ -n "$branch" ] || return 1 infos="${branch^^}_MERGE_FROM"; branch="${!infos}" [ -n "$branch" ] && echo "$branch" || return 1 } function get_merge_to_branch() { # afficher la branche dans laquelle la branche $1 doit merger # retourner 1 en cas d'erreur (pas de branche destination) local branch="$1" infos [ -n "$branch" ] || return 1 infos="${branch^^}_MERGE_TO"; branch="${!infos}" [ -n "$branch" ] && echo "$branch" || return 1 } function should_prel_merge() { # tester si la branche $1 doit être mergée avec prel dans la direction # $2(=to) local branch="$1" dir="${2:-to}" infos [ -n "$branch" ] || return 1 infos="${branch^^}_PREL" [ "${!infos}" == "$dir" ] } function should_delete_merged() { # tester si la branche $1 doit être supprimée après avoir été mergée dans la # direction $2(=to) local branch="$1" dir="${2:-to}" infos [ -n "$branch" ] || return 1 infos="${branch^^}_DELETE" [ "${!infos}" == "$dir" ] } : " # description des variables # * PMAN_TOOL -- nom de l'outil, e.g pdev, pmain, pdist * PMAN_REF_BRANCH -- code de la branche de référence basé sur le nom de l'outil * PmanRefBranch -- nom effectif de la branche si elle est définie dans .pman.conf, vide sinon * IfRefBranch -- nom effectif de la branche *si elle existe*, vide sinon * PMAN_UNIQUE -- si la branche de référence est unique. est vide pour les codes de branches multiples, telle que FEATURE * PMAN_BASE_BRANCH -- branche de base à partir de laquelle créer la branche de référence * PmanBaseBranch -- nom effectif de la branche de base si elle est définie dans .pman.conf, vide sinon * IfBaseBranch -- nom effectif de la branche de base *si elle existe*, vide sinon * PMAN_MERGE_FROM -- code de la branche source à partir de laquelle la fusion est faite dans PMAN_REF_BRANCH. vide si la branche n'a pas de source * PMAN_MERGE_TO -- code de la branche destination dans laquelle la fusion est faite depuis PMAN_REF_BRANCH. vide si la branche n'a pas de destination * PMAN_DIR -- direction de la fusion: 'from' si on fait PMAN_MERGE_FROM --> PMAN_REF_BRANCH 'to' si on fait PMAN_REF_BRANCH --> PMAN_MERGE_TO * PMAN_PREL_MERGE -- si la fusion devrait se faire avec prel * PMAN_DELETE_MERGED -- s'il faut supprimer la branche source après la fusion * PMAN_MERGE_SRC -- code de la branche source pour la fusion, ou vide si la fusion n'est pas possible * PmanMergeSrc -- nom effectif de la branche source si elle est définie dans .pman.conf * IfMergeSrc -- nom effectif de la branche source *si elle existe*, vide sinon * PMAN_MERGE_DEST -- code de la branche destination pour la fusion, ou vide si la fusion n'est pas possible * PmanMergeDest -- nom effectif de la branche destination si elle est définie dans .pman.conf * IfMergeDest -- nom effectif de la branche source *si elle existe*, vide sinon" [ -n "$PMAN_TOOL" ] || PMAN_TOOL="$MYNAME" PMAN_REF_BRANCH="PMAN_TOOL_${PMAN_TOOL^^}"; PMAN_REF_BRANCH="${!PMAN_REF_BRANCH}" function set_pman_vars() { PmanRefBranch="${!PMAN_REF_BRANCH}" case "$PMAN_REF_BRANCH" in FEATURE|RELEASE|HOTFIX) PMAN_UNIQUE=;; *) PMAN_UNIQUE=1;; esac PMAN_BASE_BRANCH=$(get_base_branch "$PMAN_REF_BRANCH") [ -n "$PMAN_BASE_BRANCH" ] && PmanBaseBranch="${!PMAN_BASE_BRANCH}" || PmanBaseBranch= PMAN_MERGE_FROM=$(get_merge_from_branch "$PMAN_REF_BRANCH") PMAN_MERGE_TO=$(get_merge_to_branch "$PMAN_REF_BRANCH") if [ -n "$1" ]; then PMAN_DIR="$1" else PMAN_DIR=to #elif [ -n "$PMAN_MERGE_TO" ]; then PMAN_DIR=to #else PMAN_DIR=from fi PMAN_PREL_MERGE=$(should_prel_merge "$PMAN_REF_BRANCH" "$PMAN_DIR" && echo 1) PMAN_DELETE_MERGED=$(should_delete_merged "$PMAN_REF_BRANCH" "$PMAN_DIR" && echo 1) case "$PMAN_DIR" in to) PMAN_MERGE_SRC="$PMAN_REF_BRANCH" PMAN_MERGE_DEST="$PMAN_MERGE_TO" ;; from) PMAN_MERGE_SRC="$PMAN_MERGE_FROM" PMAN_MERGE_DEST="$PMAN_REF_BRANCH" ;; esac [ -n "$PMAN_MERGE_SRC" ] && PmanMergeSrc="${!PMAN_MERGE_SRC}" || PmanMergeSrc= [ -n "$PMAN_MERGE_DEST" ] && PmanMergeDest="${!PMAN_MERGE_DEST}" || PmanMergeDest= } ################################################################################ function _init_changelog() { setx date=date +%d/%m/%Y-%H:%M ac_set_tmpfile changelog echo >"$changelog" "\ Vérifiez et complétez la liste des changements le cas échéant. Un fichier vide annule l'opération Ces lignes ne seront pas incluses dans le fichier destination ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ " } function _filter_rel() { # enlever les commits "techniques" générés par ce script awk ' BEGIN { tech = 0 } tech == 0 && $0 ~ /^\+.*/ { tech = 1; next } tech == 1 && $0 ~ /^\|/ { next } tech == 1 && $0 ~ /^\+/ { tech = 0 } $0 !~ // { print } ' } function _filter_changes() { # enlever les commits "inutiles" pour générer le fichier CHANGES.md grep -vE '^([+|] )?[0-9a-f]+ modifs\.mineures sans commentaires$' | grep -vE '^([+|] )?[0-9a-f]+ (cosmetic|typo|bug|fix|maj projet|maj deps)$' } function _format_md() { awk ' $0 == "" || $0 ~ /^#/ { print; next } $1 == "+" { $1 = "*" $2 = "`" $2 "`" print; next } $1 == "|" { $1 = " *" $2 = "`" $2 "`" print; next } { $1 = "* `" $1 "`" print; next } ' } function _list_commits() { local source="${1:-$SrcBranch}" dest="${2:-$DestBranch}" mergebase setx mergebase=git merge-base "$dest" "$source" git log --oneline --graph --no-decorate "$mergebase..$source" | grep -vF '|\' | grep -vF '|/' | sed -r 's/^(\| )+\* +/| /; s/^\* +/+ /' | _filter_rel } function _show_diff() { local source="${1:-$SrcBranch}" dest="${2:-$DestBranch}" mergebase setx mergebase=git merge-base "$dest" "$source" git diff ${_sd_COLOR:+--color=$_sd_COLOR} "$mergebase..$source" } function _scripte() { echo >>"$script" echo "$comment$(qvals "$@")" >>"$script" } function _scripta() { [ $# -gt 0 ] && _scripte einfo "$*" cat >>"$script" } function _script_push_branches() { [ ${#push_branches[*]} -gt 0 ] || return [ -n "$Origin" ] || Origin=origin git_have_remote "$Origin" || return local branch cmd remote rbranch for branch in "${push_branches[@]}"; do if [[ "$branch" == *:* ]]; then cmd="$(qvals git push "$Origin" "$branch")" else setx remote=git_get_branch_remote "$branch" if [ "$remote" == "$Origin" ]; then setx rbranch=git_get_branch_merge "$branch" if [ -n "$rbranch" ]; then # pousser vers la branche distante existante cmd="$(qvals git push "$Origin" "$branch:${rbranch#refs/heads/}")" else # pas de branche distante: pousser et traquer cmd="$(qvals git push -u "$Origin" "$branch:$branch")" fi elif [ -n "$remote" ]; then # pousser vers un remote différent cmd="$(qvals git push "$Origin" "$branch:$branch")" else # pas de remote: pousser et traquer cmd="$(qvals git push -u "$Origin" "$branch:$branch")" fi fi _scripta <<<"$comment$cmd$or_die" done } function _script_push_tags() { local origin tag _scripte einfo "push tags" for tag in "${push_tags[@]}"; do origin="$Origin" [ -n "$origin" ] || origin=origin _scripta <"$config" 2>/dev/null [ -s "$config" ] || die "$ConfigBranch: aucune configuration trouvée sur cette branche" || return source "$config" fi elif [ -f .pman.conf ]; then ConfigFile="$(pwd)/.pman.conf" source "$ConfigFile" else ConfigFile="$NULIBDIR/bash/src/pman.conf.sh" fi # S'assurer que nulib est dans le PATH pour que les scripts utilisateurs # puissent utiliser les outils fournis export PATH="$NULIBDIR/bin:$PATH" } ################################################################################ # Divers function resolve_should_push() { local quiet="$1" ShouldPush=1 if ! git_have_remote "$Origin" && [ -n "$Push" ]; then [ -n "$quiet" ] || enote "L'option --no-push a été forcée puisque ce dépôt n'a pas d'origine" ShouldPush= fi [ -z "$ShouldPush" ] && Push= } function _push_branches() { [ ${#push_branches[*]} -gt 0 ] || return [ -n "$Origin" ] || Origin=origin git_have_remote "$Origin" || return local -a cmds; local branch cmd remote rbranch for branch in "${push_branches[@]}"; do if [[ "$branch" == *:* ]]; then cmds+=("$(qvals git push "$Origin" "$branch")") else setx remote=git_get_branch_remote "$branch" if [ "$remote" == "$Origin" ]; then setx rbranch=git_get_branch_merge "$branch" if [ -n "$rbranch" ]; then # pousser vers la branche distante existante cmds+=("$(qvals git push "$Origin" "$branch:${rbranch#refs/heads/}")") else # pas de branche distante: pousser et traquer cmds+=("$(qvals git push -u "$Origin" "$branch:$branch")") fi elif [ -n "$remote" ]; then # pousser vers un remote différent cmds+=("$(qvals git push "$Origin" "$branch:$branch")") else # pas de remote: pousser et traquer cmds+=("$(qvals git push -u "$Origin" "$branch:$branch")") fi fi done [ -n "$Push" ] || enote "L'option --no-push étant utilisée, les opérations à effectuer sont simplement affichées" for cmd in "${cmds[@]}"; do einfo "$cmd" if [ -n "$Push" ]; then if ! eval "$cmd"; then ewarn "Une erreur s'est produite, les opérations seront simplement affichées" Push= fi fi done } ################################################################################ # Merge function _mscript_start() { >"$script" _scripta <"$script" _scripta <>"$changelog" "\ ## Release $Tag du $date " _list_commits | _filter_changes | _format_md >>"$changelog" "${EDITOR:-nano}" +7 "$changelog" [ -s "$changelog" ] || exit_with ewarn "Création de la release annulée" # créer la branche de release et basculer dessus _scripta "create branch $ReleaseBranch" <"\$tmpchanges" if [ -s CHANGES.md ]; then echo >>"\$tmpchanges" cat CHANGES.md >>"\$tmpchanges" fi cat "\$tmpchanges" >CHANGES.md rm -f "\$tmpchanges" git add CHANGES.md EOF # mettre à jour la version _scripta "update VERSION.txt" <VERSION.txt git add VERSION.txt EOF # Enregistrer les changements _scripta "commit" <Init changelog & version $Tag") EOF } function _rscript_merge_release_branch() { local dest="$1" tag="$2" # basculer sur la branche _scripta "switch to branch $dest" <Intégration de la branche $ReleaseBranch" --no-ff)$or_die EOF array_addu push_branches "$dest" # tagger la release if [ -n "$tag" ]; then _scripta "create tag $tag" <