1#!/bin/bash 2set -e 3set -u 4 5# this will match a version or pre-release version e.g. 6# "19.2.4" or "19.2.4~pre13.xyz" 7version_regexp='([[:digit:]]+\.){2}[[:digit:]]+(~[[:alnum:]]+)?' 8 9# this will only match a stable version e.g. 10# "18.2.7" 11stable_version_regexp='([[:digit:]]+\.){2}[[:digit:]]+' 12 13topdir="$(dirname "$0")" 14prog="$(basename "$0")" 15 16git="${GIT:-$(type -p git)}" 17cmake="${CMAKE:-$(type -p cmake)}" 18 19pushd "$topdir" >/dev/null 20 21log_info() { 22 echo -e "\e[36m$prog: INFO: $*\e[0m" >&2 23} 24 25log_warn() { 26 echo -e "\e[33m$prog: WARN: $*\e[0m" >&2 27} 28 29log_fatal() { 30 echo -e "\e[31m$prog: FATAL: $*\e[0m" >&2 31 exit 1 32} 33 34# wrap stdin in a nice blue box 35print_block() { 36 local s='\e[44m\e[97m' e='\e[0m' 37 printf "\n%b┏" "$s"; printf -- "━%.0s" {1..77}; printf "┓%b\n" "$e" 38 printf "%b┃ %-73s ┃%b\n" "$s" '' "$e" 39 while read line; do 40 printf "%b┃ %-73s ┃%b\n" "$s" "$line" "$e" 41 done 42 printf "%b┃ %-73s ┃%b\n" "$s" '' "$e" 43 printf "%b┗" "$s"; printf -- "━%.0s" {1..77}; printf "┛%b\n\n" "$e" 44} 45 46# get_next_version accepts a stable version as its only parameter. 47# it will then return the patch-version that follows after the provided version. 48get_next_version() { 49 local in_parts out_parts last 50 IFS=. in_parts=($1) # split into an array 51 ((last=${#in_parts[@]} - 1 )) # get index of last element 52 out_parts=() 53 # concatenate up to, but not including last element 54 for (( i=0; i<last; i++ )); do 55 out_parts+=("${in_parts[i]}") 56 done 57 out_parts+=($(( in_parts[i]+1 ))) # add last element incremented by one 58 IFS=. echo "${out_parts[*]}" # join array to string 59} 60 61confirm() { 62 echo -ne " \e[44m\e[97m $* (y/n) \e[0m" 63 read -n 1 -r 64 echo -e "\n" 65 [[ $REPLY =~ ^[Yy]$ ]] 66} 67 68replace_define_expr() { 69 # generate an sed expression to replace the string value of a single-line 70 # C preprocessor object macro 71 # requires sed --regexp-extended 72 echo "s/(#define $1[^\"]+)\"[^\"]+\"/\1\"$2\"/" 73} 74 75if [ -z "$git" -o ! -x "$git" ]; then 76 log_fatal "git not found." 77elif [ -z "$cmake" -o ! -x "$cmake" ]; then 78 log_fatal "cmake not found." 79elif [ ! -e .git ]; then 80 log_fatal "This is not a git working copy." 81elif [ -n "$("$git" status --short)" ]; then 82 log_fatal "This script must be run in a clean working copy." 83fi 84 85# get the git remote name for the upstream GitHub repository 86git_remote="$("$git" remote -v | \ 87 awk '/git@github.com:\/?bareos\/bareos.git \(push\)/ { print $1 }')" 88if [ -z "$git_remote" ]; then 89 # warn if not found and set a default for sane messages" 90 log_warn "Could not find the upstream repository in your git remotes." 91 git_remote="<remote>" 92fi 93 94 95# we try to detect the version that should be released. 96# for this we retrieve the version of the source-tree we're running in and strip 97# any prerelease suffix. 98autodetect_version=$("$git" describe --tags --match "WIP/*" \ 99 | grep --extended-regexp --only-matching "$version_regexp") 100if [ -n "${1:-}" ]; then 101 log_info "Using provided version $1." 102 version="$1" 103elif [ -n "$autodetect_version" ]; then 104 log_info "Autodetected version $autodetect_version based on WIP-tag." 105 version="$autodetect_version" 106else 107 log_fatal Cannot autodetect version and no version passed on cmdline 108fi 109 110if ! grep --quiet --extended-regexp "^$version_regexp\$" <<< "$version"; then 111 log_fatal "Version $1 does not match the expected pattern" 112fi 113 114git_branch="$(git rev-parse --abbrev-ref=strict HEAD)" 115if ! grep --quiet --fixed-strings "$git_branch" <<< "bareos-$version"; then 116 log_warn "Git branch $git_branch is not the release branch for $version." 117fi 118 119release_tag="Release/${version/\~/-}" 120release_ts="$(date --utc --iso-8601=seconds | sed --expression='s/T/ /;s/+.*$//')" 121release_message="Release $version" 122 123# Only if we are preparing a stable release 124if grep --quiet --extended-regexp "^$stable_version_regexp\$" <<< "$version"; then 125 wip_enable=1 126 wip_version="$(get_next_version "$version")" 127 wip_tag="WIP/$wip_version-pre" 128 wip_message="Start development of $wip_version" 129else 130 log_info "Will not generate a new WIP tag for a pre-release" 131 wip_enable=0 132 wip_version="(none)" 133 wip_tag="(none)" 134 wip_message="(none)" 135fi 136 137print_block << EOT 138You are preparing a release of Bareos. As soon as you push the results of 139this script to the official git repository, the new version is released. 140If you decide not to push, nothing will be released. 141 142The release you are preparing will have the following settings: 143 Version: "$version" 144 Release tag: "$release_tag" 145 Release time: "$release_ts" 146 Release msg: "$release_message" 147 148If this is not a pre-release a new work-in-progress tag will be created: 149 Next version: "$wip_version" 150 WIP tag: "$wip_tag" 151 WIP message: "$wip_message" 152 153 154This script will do the following: 155 1. Patch version.h with the correct version and timestamps 156 2. Create a commit containing the patched version.h 157 3. Add an empty commit for a WIP tag (not for pre-releases) 158 4. Set the release tag 159 5. Set the WIP tag (not for pre-releases) 160 161Please make sure you're on the right branch before continuing and review 162the commits, tags and branch pointers before you push! 163 164For a major release you should be on the release-branch, not the master 165branch. While you can move around branch pointers later, it is a lot 166easier to branch first. 167EOT 168 169if ! confirm "Do you want to proceed?"; then 170 log_info "Exiting due to user request." 171 exit 0 172fi 173 174original_commit="$(git rev-parse HEAD)" 175log_info "if you want to rollback the commits" \ 176 "you can run 'git reset --soft $original_commit'" 177 178version_h=core/src/include/version.h 179 180define_BDATE="$(LC_TIME=C date --date="$release_ts+0000" "+%d %B %Y")" 181define_LSMDATE="$(LC_TIME=C date --date="$release_ts+0000" "+%d%b%y")" 182define_BYEAR="$(LC_TIME=C date --date="$release_ts+0000" "+%Y")" 183 184sed \ 185 --in-place \ 186 --regexp-extended \ 187 --expression="$(replace_define_expr VERSION "$version")" \ 188 --expression="$(replace_define_expr BDATE "$define_BDATE")" \ 189 --expression="$(replace_define_expr LSMDATE "$define_LSMDATE")" \ 190 --expression="$(replace_define_expr BYEAR "$define_BYEAR")" \ 191 "$version_h" 192 193"$git" diff -- "$version_h" 194 195if ! confirm "Should we proceed with the above changes applied?"; then 196 log_info "Exiting due to user request." 197 exit 0 198fi 199 200"$git" add \ 201 --no-all \ 202 -- \ 203 "$version_h" 204 205"$git" commit \ 206 --quiet \ 207 --only \ 208 --date="$release_ts" \ 209 -m "$release_message" \ 210 -- \ 211 "$version_h" 212 213release_commit="$(git rev-parse HEAD)" 214log_info "commit for release tag will be $release_commit" 215 216if [ "$wip_enable" -eq 1 ]; then 217 "$git" commit \ 218 --quiet \ 219 --allow-empty \ 220 --date="$release_ts" \ 221 -m "$wip_message" 222 223 wip_commit="$(git rev-parse HEAD)" 224 log_info "commit for WIP tag will be $wip_commit" 225fi 226 227echo 228echo The log for the new commits is: 229echo 230 231"$git" log \ 232 --decorate \ 233 --graph \ 234 "${original_commit}..HEAD" 235 236echo 237 238log_info "Creating release tag for $release_commit named $release_tag" 239"$git" tag "$release_tag" "$release_commit" 240 241if [ -n "${wip_commit:-}" ]; then 242 log_info "Creating WIP tag for $wip_commit named $wip_tag" 243 "$git" tag "$wip_tag" "$wip_commit" 244fi 245 246( 247 cat <<EOT 248To publish your new release, you need to do the follwing git push steps: 249 git push $git_remote HEAD 250 git push $git_remote $release_tag 251EOT 252 if [ -n "${wip_commit:-}" ]; then 253 echo "git push $git_remote $wip_tag" 254 fi 255) | print_block 256