|
#!/usr/bin/env bash |
|
|
|
VERBOSE=false |
|
DRY=false |
|
BRANCH_PREFIX=${CLEAN_STAGING_PREFIX:=recette-} |
|
MASTER_OR_MAIN=${CLEAN_STAGING_ROOT:=master} |
|
ORIGIN_OR_OTHER=${CLEAN_STAGING_ORIGIN:=origin} |
|
POSITIONAL=() |
|
SKIP=() |
|
|
|
command_help () { |
|
echo "" |
|
echo "Clean staging branch ($PREFIX<environment>)." |
|
echo "" |
|
echo -e "\e[33mUsage:\e[0m" |
|
echo " clean-staging <environment> [-s|--skip <branch name>] [-v|--verbose] [--dry-run] [-h|--help]" |
|
echo "" |
|
echo -e "\e[33mDescription:\e[0m" |
|
echo " This command will replay all merges on a staging branch resseted from $MASTER_OR_MAIN" |
|
echo "" |
|
echo -e "\e[33mOptions:\e[0m" |
|
echo -e " \e[32m-h, --help\e[0m Show this screen." |
|
echo -e " \e[32m-v, --verbose\e[0m Display executed commands." |
|
echo -e " \e[32m-s, --skip <branch>\e[0m Specify <branch> name (without origin) to exclude during merge (repeatable)." |
|
echo -e " \e[32m--dry-run\e[0m Don't execute anything, just simulate commands" |
|
echo "" |
|
echo -e "\e[33mHelp:\e[0m" |
|
echo -e " This command will fetch your git remote (\e[33m$ORIGIN_OR_OTHER\e[0m) staging branch (\e[33m$BRANCH_PREFIX<environment>\e[0m)," |
|
echo -e " will reset your local staging branch to latest remote \e[33m$MASTER_OR_MAIN\e[0m branch" |
|
echo -e " and will try to remerge all previously merged branches in \e[33m$BRANCH_PREFIX<environment>\e[0m." |
|
echo " If conflict occured it is reverted, you will be warned and script will go on." |
|
echo "" |
|
echo " You can configure :" |
|
echo -e " - the staging branch prefix by setting \e[33mCLEAN_STAGING_PREFIX\e[0m environment variable (currently \e[33m$BRANCH_PREFIX\e[0m)." |
|
echo -e " - the source branch by setting \e[33mCLEAN_STAGING_ROOT\e[0m environment variable (currently \e[33m$MASTER_OR_MAIN\e[0m)." |
|
echo -e " - the remote name by setting \e[33mCLEAN_STAGING_ORIGIN\e[0m environment variable (currently \e[33m$ORIGIN_OR_OTHER\e[0m)." |
|
echo "" |
|
exit 1 |
|
} |
|
|
|
while [[ $# -gt 0 ]] |
|
do |
|
key="$1" |
|
|
|
case $key in |
|
-h|--help) |
|
command_help |
|
shift # past argument |
|
;; |
|
-v|--verbose) |
|
VERBOSE=true |
|
shift # past argument |
|
;; |
|
--dry-run) |
|
DRY=true |
|
shift # past argument |
|
;; |
|
-s|--skip) |
|
SKIP+=("$2") |
|
shift # past argument |
|
shift # past argument |
|
;; |
|
*) # unknown option |
|
POSITIONAL+=("$1") # save it in an array for later |
|
shift # past argument |
|
;; |
|
esac |
|
done |
|
|
|
set -- "${POSITIONAL[@]}" # restore positional parameters |
|
|
|
die () { |
|
echo >&2 "$@" |
|
exit 1 |
|
} |
|
|
|
command () { |
|
local __resultvar=$2 |
|
|
|
[[ "$VERBOSE" = "true" ]] && echo -e "\e[36m$1\e[0m" |
|
|
|
if [[ "$DRY" = "false" ]]; then |
|
if [[ "$__resultvar" ]]; then |
|
eval "$__resultvar=\`$1\`" |
|
else |
|
eval $1 |
|
fi |
|
fi |
|
} |
|
|
|
command_no_dry () { |
|
local __resultvar=$2 |
|
|
|
[[ "$VERBOSE" = "true" ]] && echo -e "\e[36m$1\e[0m" |
|
|
|
if [[ "$__resultvar" ]]; then |
|
eval "$__resultvar=\`$1\`" |
|
else |
|
eval $1 |
|
fi |
|
} |
|
|
|
if [[ "$#" -ne 1 ]]; then |
|
echo |
|
echo -e "\e[1m\e[31m1 argument required, $# provided\e[0m" |
|
command_help; |
|
fi |
|
command_no_dry "git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/'" current_branch |
|
staging_branch=`echo $BRANCH_PREFIX$1`; |
|
|
|
echo -e "Current branch is \e[33m$current_branch\e[0m" |
|
[[ "$current_branch" = "$staging_branch" ]] || echo -e "Switching to \e[33m$staging_branch\e[0m" && command "git checkout ${staging_branch} &> /dev/null" |
|
|
|
echo -e "Refreshing repository" |
|
command_no_dry "git fetch -p &> /dev/null" |
|
|
|
echo -e "Comparing \e[33m$ORIGIN_OR_OTHER/$MASTER_OR_MAIN\e[39m to \e[33m$ORIGIN_OR_OTHER/$staging_branch\e[0m" |
|
command_no_dry "git log $ORIGIN_OR_OTHER/$MASTER_OR_MAIN..$ORIGIN_OR_OTHER/${staging_branch} --oneline --merges 2> /dev/null | grep -E \"^\\S+\\s+Merge\" | sed -e \"s/^.*'\(.*\)'.*$/\1/g\" -e 's/$ORIGIN_OR_OTHER\/\(.*\)/\1/'" merged_branches |
|
|
|
merged_branches_list=($(echo ${merged_branches} | tr ' ' "\n")) |
|
merged_branches_list=(`for i in ${merged_branches_list[@]}; do echo $i; done`) |
|
merged_branches_list=(`echo ${merged_branches_list[@]} | tac -s' '`) |
|
|
|
echo -e "Resetting \e[33m$ORIGIN_OR_OTHER/$staging_branch\e[39m at latest \e[33m$ORIGIN_OR_OTHER/$MASTER_OR_MAIN\e[0m" |
|
command "git reset --hard $ORIGIN_OR_OTHER/$MASTER_OR_MAIN &> /dev/null" |
|
|
|
echo -e "Selecting mergeable branches" |
|
|
|
contains() { |
|
[[ $1 =~ (^|[[:space:]])$2($|[[:space:]]) ]] && echo "1" || echo "0" |
|
} |
|
|
|
mergeable_branches_list=() |
|
treated=() |
|
for element in "${merged_branches_list[@]}" |
|
do |
|
echo "${treated[@]}" | grep -w -q $element |
|
absent=$(echo "$?") |
|
|
|
if [[ "$absent" = "1" ]]; then |
|
treated+=("${element}") |
|
command_no_dry "git ls-remote --exit-code --heads \"$ORIGIN_OR_OTHER\" \"${element}\" &> /dev/null" |
|
|
|
if [[ "$?" -eq 0 ]]; then |
|
valid=1 |
|
|
|
for skipable in "${SKIP[@]}" |
|
do |
|
if [[ "$element" = "$skipable" ]]; then |
|
valid=0 |
|
fi |
|
done |
|
|
|
if [[ "$valid" = "0" ]]; then |
|
echo -e "\e[36m✖ Skipping branch \e[33m$ORIGIN_OR_OTHER/${element}\e[0m" |
|
elif [[ "$element" = "$staging_branch" ]]; then |
|
echo -e "\e[36m✖ Skipping same branch \e[33m$ORIGIN_OR_OTHER/${element}\e[0m" |
|
elif [[ "$element" = "$MASTER_OR_MAIN" ]]; then |
|
echo -e "\e[36m✖ Skipping source branch \e[33m$ORIGIN_OR_OTHER/${element}\e[0m" |
|
else |
|
mergeable_branches_list+=(${element}) |
|
echo -e "\e[32m✓ Branch \e[33m$ORIGIN_OR_OTHER/$element\e[32m added to merge list\e[0m" |
|
fi |
|
else |
|
echo -e "\e[31m✖ Branch \e[33m$ORIGIN_OR_OTHER/$element\e[31m does not exists on the remote\e[0m" |
|
fi |
|
fi |
|
done |
|
|
|
echo -e "${#mergeable_branches_list[@]} branch$([[ "${#mergeable_branches_list[@]}" -le 1 ]] || echo "es") to merge" |
|
|
|
errored=() |
|
|
|
for element in "${mergeable_branches_list[@]}" |
|
do |
|
if [[ "$element" = "$staging_branch" ]]; then |
|
echo -e "\e[36mSkipping same branch $ORIGIN_OR_OTHER/${element}\e[0m" |
|
elif [[ "$element" = "$MASTER_OR_MAIN" ]]; then |
|
echo -e "\e[36mSkipping source branch $ORIGIN_OR_OTHER/${element}\e[0m" |
|
else |
|
echo -e "Merging \e[33m$ORIGIN_OR_OTHER/${element}\e[0m" |
|
TMP=$(mktemp) |
|
command "git merge --no-ff $ORIGIN_OR_OTHER/${element} 1>$TMP 2>/dev/null" |
|
if [ $? -ne 0 ]; then |
|
echo -e "\033[0;31mAn error occured during merge of \e[33m$ORIGIN_OR_OTHER/${element}\033[0;31m, reverting.\033[0m"; |
|
echo -e "\e[37m"; |
|
cat $TMP |
|
echo -e "\033[0m"; |
|
command "git merge --abort" |
|
errored+=("$ORIGIN_OR_OTHER/${element}") |
|
fi |
|
fi |
|
done |
|
|
|
if [ ${#errored[@]} -eq 0 ]; then |
|
echo -e "Script has ended, you can now force push the branch \e[33m$staging_branch\e[0m" |
|
else |
|
echo -e "Script has ended, but got error during merge of \e[33m${errored[*]}\e[0m, try merging it manually and force push the branch \e[33m$staging_branch\e[0m" |
|
exit 1 |
|
fi |
hello,
j'ai testé l'install sur mac, j'ai fait un fork avec quelques modifs de compat sur les couleurs et affichage printf plutot que echo -e qui apparement est plus compatible comme interpretation entre les plateformes. Et de la doc sur les requis sous mac notament wget et tac à installer via brew.