Willy Tarreau | 62b71ee | 2016-05-10 12:04:13 +0200 | [diff] [blame] | 1 | #!/bin/bash |
| 2 | # creates a new haproxy release at the current commit |
| 3 | # Copyright (c) 2006-2016 Willy Tarreau <w@1wt.eu> |
| 4 | # |
| 5 | # In short : |
| 6 | # - requires git |
| 7 | # - works only from master branch |
| 8 | # - finds old and new version by itself |
| 9 | # - builds changelog |
| 10 | # - updates dates and versions in files |
| 11 | # - commits + tags + signs |
| 12 | # - no upload! |
| 13 | |
| 14 | USAGE="Usage: ${0##*/} [-i] [-y] [-t] [-b branch] [-d date] [-o oldver] [-n newver]" |
| 15 | INTERACTIVE= |
| 16 | TAGONLY= |
| 17 | SAYYES= |
| 18 | BRANCH= |
| 19 | DATE= |
| 20 | YEAR= |
| 21 | OLD= |
| 22 | NEW= |
| 23 | |
| 24 | die() { |
| 25 | [ "$#" -eq 0 ] || echo "$*" >&2 |
| 26 | exit 1 |
| 27 | } |
| 28 | |
| 29 | err() { |
| 30 | echo "$*" >&2 |
| 31 | } |
| 32 | |
| 33 | quit() { |
| 34 | [ "$#" -eq 0 ] || echo "$*" |
| 35 | exit 0 |
| 36 | } |
| 37 | |
| 38 | do_commit() { |
| 39 | ( |
| 40 | echo "[RELEASE] Released version $NEW" |
| 41 | echo |
| 42 | echo "Released version $NEW with the following main changes :" |
| 43 | sed -ne '/^[ ]*-/,/^$/{p;b a};d;:a;/^$/q' CHANGELOG |
| 44 | ) | git commit -a -F - |
| 45 | } |
| 46 | |
| 47 | do_tag() { |
| 48 | git tag -u "$GIT_GPG_KEY" -s -m "HAProxy $NEW" v$NEW && echo "Tagged as v$NEW" |
| 49 | } |
| 50 | |
| 51 | while [ -n "$1" -a -z "${1##-*}" ]; do |
| 52 | case "$1" in |
| 53 | -y) SAYYES=1 ; shift ;; |
| 54 | -i) INTERACTIVE=1 ; shift ;; |
| 55 | -t) TAGONLY=1 ; shift ;; |
| 56 | -d) DATE="$2" ; shift 2 ;; |
| 57 | -b) BRANCH="$2" ; shift 2 ;; |
| 58 | -o) OLD="$2" ; shift 2 ;; |
| 59 | -n) NEW="$2" ; shift 2 ;; |
| 60 | -h|--help) quit "$USAGE" ;; |
| 61 | *) die "$USAGE" ;; |
| 62 | esac |
| 63 | done |
| 64 | |
| 65 | if [ $# -gt 0 ]; then |
| 66 | die "$USAGE" |
| 67 | fi |
| 68 | |
| 69 | if [ -z "$GIT_GPG_KEY" ]; then |
| 70 | die "GIT_GPG_KEY is not set, it must contain your GPG key ID." |
| 71 | fi |
| 72 | |
| 73 | if ! git rev-parse --verify -q HEAD >/dev/null; then |
| 74 | die "Failed to check git HEAD." |
| 75 | fi |
| 76 | |
| 77 | # we want to go to the git top dir |
| 78 | cd $(git rev-parse --show-toplevel) |
| 79 | |
| 80 | if [ "$(git rev-parse --verify -q HEAD)" != "$(git rev-parse --verify -q master)" ]; then |
| 81 | die "git HEAD doesn't match master branch." |
| 82 | fi |
| 83 | |
| 84 | if [ "$(git diff HEAD|wc -c)" != 0 ]; then |
| 85 | err "You appear to have uncommitted local changes, please commit them first :" |
| 86 | git status -s -uno >&2 |
| 87 | die |
| 88 | fi |
| 89 | |
| 90 | if [ -z "$OLD" ]; then |
| 91 | OLD="$(git describe --tags HEAD --abbrev=0)" |
| 92 | OLD="${OLD#v}" |
| 93 | fi |
| 94 | |
| 95 | if ! git rev-parse --verify -q "v$OLD" >/dev/null; then |
| 96 | die "git tag v$OLD doesn't exist." |
| 97 | fi |
| 98 | |
| 99 | if [ -z "$NEW" ]; then |
| 100 | radix="$OLD" |
| 101 | while [ -n "$radix" -a -z "${radix%%*[0-9]}" ]; do |
| 102 | radix="${radix%[0-9]}" |
| 103 | done |
| 104 | |
| 105 | number=${OLD#$radix} |
| 106 | if [ -z "$number" -o "$radix" = "$OLD" ]; then |
| 107 | die "Fatal: cannot determine new version, please specify it." |
| 108 | fi |
| 109 | NEW=${radix}$((number+1)) |
| 110 | fi |
| 111 | |
| 112 | if git show-ref --tags "v$NEW" >/dev/null; then |
| 113 | die "git tag v$NEW already exists, please remove it first." |
| 114 | fi |
| 115 | |
| 116 | # determine the product branch from the new release |
| 117 | if [ -z "$BRANCH" ]; then |
| 118 | subvers=${NEW#[0-9]*.[0-9]*[-.]*[0-9].} |
| 119 | [ "${subvers}" = "${NEW}" ] && subvers="" |
| 120 | major=${NEW%.$subvers} |
| 121 | branch_ext=${major#*[0-9].*[0-9]} |
| 122 | BRANCH=${major%${branch_ext}} |
| 123 | fi |
| 124 | |
| 125 | |
| 126 | # determine the release date |
| 127 | if [ -z "$DATE" ]; then |
| 128 | # Uncomment the line below to use the date of the last commit, |
| 129 | # otherwise fall back to current date |
| 130 | DATE="$(git log --pretty=fuller -1 v$NEW 2>/dev/null | sed -ne '/^CommitDate:/{s/\(^[^ ]*:\)\|\( [-+].*\)//gp;q}')" |
| 131 | DATE="$(date +%Y/%m/%d -d "$DATE")" |
| 132 | else |
| 133 | if [ "$DATE" != "$(date +%Y/%m/%d -d "$DATE")" ]; then |
| 134 | die "Date format must exclusively be YYYY/MM/DD ; date was '$DATE'." |
| 135 | fi |
| 136 | fi |
| 137 | YEAR="${DATE%%/*}" |
| 138 | |
| 139 | if [ -n "$TAGONLY" ]; then |
| 140 | do_tag || die "Failed to tag changes" |
| 141 | echo "Done. You may have to push changes." |
| 142 | exit 0 |
| 143 | fi |
| 144 | |
| 145 | echo "About to release version $NEW from $OLD at $DATE (branch $BRANCH)." |
| 146 | if [ -z "$SAYYES" ]; then |
| 147 | echo "Press ENTER to continue or Ctrl-C to abort now!" |
| 148 | read |
| 149 | fi |
| 150 | |
| 151 | echo "Updating CHANGELOG ..." |
| 152 | ( echo "ChangeLog :" |
| 153 | echo "===========" |
| 154 | echo |
| 155 | echo "$DATE : $NEW" |
| 156 | #git shortlog v$OLD.. | sed -ne 's/^ / - /p' |
| 157 | git log --oneline --reverse --format=" - %s" v$OLD.. |
| 158 | echo |
| 159 | tail +4 CHANGELOG |
| 160 | ) >.chglog.tmp && mv .chglog.tmp CHANGELOG |
| 161 | |
| 162 | echo "Updating VERSION ..." |
| 163 | rm -f VERSION VERDATE |
| 164 | echo "$NEW" > VERSION |
| 165 | |
| 166 | echo "Updating VERDATE ..." |
| 167 | echo '$Format:%ci$' > VERDATE |
| 168 | echo "$DATE" >> VERDATE |
| 169 | |
| 170 | echo "Updating haproxy.spec ..." |
| 171 | sed -e "s/^Version: .*/Version: $NEW/" < examples/haproxy.spec >examples/haproxy.spec- && mv examples/haproxy.spec- examples/haproxy.spec |
| 172 | |
| 173 | (sed -ne '0,/^%changelog/p'; |
| 174 | date -d "$DATE" "+* %a %b %e %Y $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" |
| 175 | echo "- updated to $(cat VERSION)" |
| 176 | echo |
| 177 | ) < examples/haproxy.spec >examples/haproxy.spec- |
| 178 | sed -ne '0,/^%changelog/d;p' < examples/haproxy.spec >>examples/haproxy.spec- |
| 179 | mv examples/haproxy.spec- examples/haproxy.spec |
| 180 | |
| 181 | # updating branch and date in README and all modified doc files except the outdated architecture.txt |
| 182 | for file in README doc/intro.txt doc/configuration.txt doc/management.txt $(git diff --name-only v${OLD}.. -- doc); do |
| 183 | if [ ! -e "$file" ]; then continue; fi |
| 184 | if [ "$file" = doc/architecture.txt ]; then continue; fi |
| 185 | echo "Updating $file ..." |
| 186 | sed -e "1,10s:\(\sversion\s\).*:\1$BRANCH:" \ |
| 187 | -e "1,10s:\(\s\)\(20[0-9]\{2\}/[0-9]\{1,2\}/[0-9]\{1,2\}\):\1$DATE:" \ |
| 188 | -i "$file" |
| 189 | done |
| 190 | |
| 191 | echo "Updating haproxy.c ..." |
| 192 | sed -e "s:Copyright 2000-[0-9]*\s*Willy Tarreau.*>:Copyright 2000-$YEAR Willy Tarreau <willy@haproxy.org>:" \ |
| 193 | -i src/haproxy.c |
| 194 | |
| 195 | if [ -n "$INTERACTIVE" ]; then |
| 196 | vi CHANGELOG VERSION VERDATE examples/haproxy*.spec \ |
| 197 | src/haproxy.c README doc/configuration.txt \ |
| 198 | $(git diff --name-only v${OLD}.. -- doc) |
| 199 | fi |
| 200 | |
| 201 | if [ "$(git diff -- CHANGELOG | wc -c)" = 0 ]; then |
| 202 | die "CHANGELOG must be updated." |
| 203 | fi |
| 204 | |
| 205 | if [ -z "$SAYYES" ]; then |
| 206 | echo "Press ENTER to review the changes..." |
| 207 | read |
| 208 | fi |
| 209 | |
| 210 | git diff |
| 211 | |
| 212 | echo |
| 213 | echo "About to commit and tag version $NEW with the following message:" |
| 214 | echo |
| 215 | echo "[RELEASE] Released version $NEW with the following main changes :" |
| 216 | sed -ne '/^[ ]*-/,/^$/{p;b a};d;:a;/^$/q' CHANGELOG |
| 217 | |
| 218 | echo |
| 219 | echo "LAST chance to cancel! Press ENTER to proceed now or Ctrl-C to abort." |
| 220 | read |
| 221 | |
| 222 | do_commit || die "Failed to commit changes" |
| 223 | do_tag || die "Failed to tag changes" |
| 224 | |
| 225 | echo "Do not forget to push updates, publish and announce this version :" |
| 226 | echo |
| 227 | echo "git push origin master v$NEW" |
| 228 | echo "${0%/*}/publish-release" |
| 229 | echo "${0%/*}/announce-release" |