diff options
Diffstat (limited to '')
-rwxr-xr-x | scripts/announce-release | 279 | ||||
-rwxr-xr-x | scripts/backport | 146 | ||||
-rwxr-xr-x | scripts/build-ot.sh | 27 | ||||
-rwxr-xr-x | scripts/build-ssl.sh | 146 | ||||
-rwxr-xr-x | scripts/build-vtest.sh | 10 | ||||
-rwxr-xr-x | scripts/create-release | 237 | ||||
-rwxr-xr-x | scripts/git-show-backports | 273 | ||||
-rwxr-xr-x | scripts/make-releases-json | 103 | ||||
-rwxr-xr-x | scripts/publish-release | 191 | ||||
-rwxr-xr-x | scripts/run-regtests.sh | 416 |
10 files changed, 1828 insertions, 0 deletions
diff --git a/scripts/announce-release b/scripts/announce-release new file mode 100755 index 0000000..c990821 --- /dev/null +++ b/scripts/announce-release @@ -0,0 +1,279 @@ +#!/usr/bin/env bash +# prepares a template e-mail and HTML file to announce a new release +# Copyright (c) 2006-2016 Willy Tarreau <w@1wt.eu> +# +# In short : +# - requires git +# - wants that last commit is a release/tag +# - no restriction to master, uses last tag +# - creates mail-$version.txt +# - creates web-$version.html +# - indicates how to edit the mail and how to send it + +USAGE="Usage: ${0##*/} [-f] [-p] [-b branch] [-d date] [-o oldver] [-n newver] + -f: force to overwrite existing files and ignore local changes + -p: prepare future release (skip branch and tags existence checks) + -b: force the project branch name to this (def: inherited from the version) + -d: force the release date (e.g. to rework a failed announce) + -o: previous version (def: newver-1) + -n: new version (if not last tag) +" +PREPARE= +FORCE= +OUTPUT= +BRANCH= +HTML= +DATE= +YEAR= +OLD= +LASTCOM= +NEWVER= +NEWTAG= +DIR= + +die() { + [ "$#" -eq 0 ] || echo "$*" >&2 + exit 1 +} + +err() { + echo "$*" >&2 +} + +quit() { + [ "$#" -eq 0 ] || echo "$*" + exit 0 +} + +while [ -n "$1" -a -z "${1##-*}" ]; do + case "$1" in + -d) DATE="$2" ; shift 2 ;; + -b) BRANCH="$2" ; shift 2 ;; + -f) FORCE=1 ; shift ;; + -p) PREPARE=1 ; shift ;; + -o) OLD="$2" ; shift 2 ;; + -n) NEWVER="$2" ; shift 2 ;; + -h|--help) quit "$USAGE" ;; + *) die "$USAGE" ;; + esac +done + +if [ $# -gt 0 ]; then + die "$USAGE" +fi + +if ! git rev-parse --verify -q HEAD >/dev/null; then + die "Failed to check git HEAD." +fi + +# we want to go to the git root dir +DIR="$PWD" +cd $(git rev-parse --show-toplevel) + +if [ -z "$FORCE" -a "$(git diff HEAD|wc -c)" != 0 ]; then + err "You appear to have uncommitted local changes, please commit them first :" + git status -s -uno >&2 + die +fi + +if [ -z "$PREPARE" -a "$(git rev-parse --verify -q HEAD)" != "$(git rev-parse --verify -q master)" ]; then + die "git HEAD doesn't match master branch." +fi + +if [ -n "$NEWVER" ]; then + if git show-ref --tags "v$NEWVER" >/dev/null; then + NEWTAG="v$NEWVER" + else + echo "Note: no matching tag v$NEWVER, using HEAD". + fi +fi + +# version unspecified or no existing tag for it +if [ -z "$NEWTAG" ]; then + NEWTAG="$(git describe --tags HEAD --abbrev=0)" + + if [ -z "$NEWTAG" ]; then + die "Fatal: cannot determine new version, please specify it." + elif [ -n "$PREPARE" ] && ! git show-ref --tags HEAD >/dev/null; then + # HEAD not tagged, hence we have to pretend we're on one version + # after the current tag + echo "Current version not tagged, trying to determine next one." + NEWTAG="${NEWTAG#v}" + if [ -z "$OLD" ]; then + OLD="$NEWTAG" + fi + radix="$NEWTAG" + while [ -n "$radix" -a -z "${radix%%*[0-9]}" ]; do + radix="${radix%[0-9]}" + done + + number=${NEWTAG#$radix} + if [ -z "$number" -o "$radix" = "$NEWTAG" ]; then + die "Fatal: cannot determine new version, please specify it." + fi + NEWTAG="${radix}$((number+1))" + if [ -z "$NEWVER" ]; then + NEWVER="${NEWTAG}" + fi + NEWTAG="v$NEWTAG" + LASTCOM="$(git rev-parse --short HEAD)" + echo "Next version expected to be $NEWVER and next tag $NEWTAG based on commit $LASTCOM" + elif [ "$(git describe --tags HEAD)" != "$NEWTAG" ]; then + die "About to use current HEAD which doesn't seem tagged, it reports '$(git describe --tags HEAD 2>/dev/null)'. Did you release it ?" + fi +elif ! git show-ref --tags "$NEWTAG" >/dev/null 2>&1; then + die "git tag $NEWTAG doesn't exist, did you create the release ?" +fi + +if [ -z "$NEWVER" ]; then + NEWVER="${NEWTAG#v}" +fi + +if [ -z "$LASTCOM" ]; then + LASTCOM="$(git rev-parse --short ${NEWTAG}^)" +fi + +if [ -z "$OLD" ]; then + OLD="$(git describe --tags ${LASTCOM} --abbrev=0)" + OLD="${OLD#v}" +fi + +if ! git rev-parse --verify -q "v$OLD" >/dev/null; then + die "git tag v$OLD doesn't exist." +fi + +# determine the product branch from the new release +if [ -z "$BRANCH" ]; then + subvers=${NEWVER#[0-9]*.[0-9]*[-.]*[0-9].} + [ "${subvers}" = "${NEWVER}" ] && subvers="" + major=${NEWVER%.$subvers} + branch_ext=${major#*[0-9].*[0-9]} + BRANCH=${major%${branch_ext}} +fi + +# determine the release date +if [ -z "$DATE" ]; then + DATE="$(git log -1 --pretty=fuller ${NEWTAG} 2>/dev/null | sed -ne '/^CommitDate:/{s/\(^[^ ]*:\)\|\( [-+].*\)//gp;q}')" + DATE="$(date +%Y/%m/%d -d "$DATE")" +fi +YEAR="${DATE%%/*}" + +OUTPUT="$DIR/mail-haproxy-$NEWVER.txt" +HTML="$DIR/web-haproxy-$NEWVER.html" + +[ -z "$FORCE" ] || rm -f "${OUTPUT}" "${HTML}" + +if [ -e "$OUTPUT" ]; then + die "${OUTPUT##*/} already exists, please remove it or retry with -f." +fi + +if [ -e "$HTML" ]; then + die "$HTML already exists, please remove it or retry with -f." +fi + +( + echo "# Send this using:" + echo "# mutt -H <(tail -n +4 ${OUTPUT##*/}) -s \"[ANNOUNCE] haproxy-$NEWVER\" haproxy@formilux.org" +) >> "$OUTPUT" + +(echo + echo "Hi," + echo + echo -n "HAProxy $NEWVER was released on $DATE. It added " + echo -n $(git log --oneline --reverse --format="%s" "v$OLD".."$LASTCOM" | wc -l) + echo " new commits" + echo "after version $OLD." + echo + echo "- per tag :" + git log --oneline --reverse --format="%s" "v$OLD".."$LASTCOM" | cut -f1 -d':' | sort | uniq -c + echo + echo "major commits :" + git log --oneline --reverse --format=" - %s" "v$OLD".."$LASTCOM" | grep MAJOR + echo + echo "- per file :" + git show "v$OLD".."$LASTCOM" -- src/ | grep ^diff | awk '{ print substr($3,7)}' | sort | uniq -c | sort -nr | head -15 + echo + echo "- per topic :" + git log --oneline --reverse --format="%s" "v$OLD".."$LASTCOM" | cut -f2 -d':' | awk '{sub("s$","",$1); print $1}' | sort | uniq -c + echo + echo "- sorted changelog :" + git log --oneline --reverse --format="%s" "v$OLD".."$LASTCOM" | sort + echo + echo "#############################################################################################" +) >> "$OUTPUT" + +# report the download paths +if [ -z "${NEWVER##*-dev*}" ]; then + gitdir="haproxy.git" +else + gitdir="haproxy-$BRANCH.git" +fi + +(echo "Please find the usual URLs below :" + echo " Site index : https://www.haproxy.org/" + echo " Documentation : https://docs.haproxy.org/" + echo " Wiki : https://github.com/haproxy/wiki/wiki" + echo " Discourse : https://discourse.haproxy.org/" + echo " Slack channel : https://slack.haproxy.org/" + echo " Issue tracker : https://github.com/haproxy/haproxy/issues" + echo " Sources : https://www.haproxy.org/download/${BRANCH}/src/" + echo " Git repository : https://git.haproxy.org/git/${gitdir}/" + echo " Git Web browsing : https://git.haproxy.org/?p=${gitdir}" + echo " Changelog : https://www.haproxy.org/download/${BRANCH}/src/CHANGELOG" + echo " Dataplane API : https://github.com/haproxytech/dataplaneapi/releases/latest" + echo " Pending bugs : https://www.haproxy.org/l/pending-bugs" + echo " Reviewed bugs : https://www.haproxy.org/l/reviewed-bugs" + echo " Code reports : https://www.haproxy.org/l/code-reports" + echo " Latest builds : https://www.haproxy.org/l/dev-packages" +) >> "$OUTPUT" + +# sign +(echo + echo "${GIT_COMMITTER_NAME% *}" +) >> "$OUTPUT" + +(echo "---" + echo "Complete changelog :" + git shortlog "v$OLD".."$LASTCOM" + echo "---" +) >> "$OUTPUT" + + +# prepare the HTML update +set -- $(date +%e -d "$DATE") +case "$1" in + 11|12|13) day="${1}th" ;; + *1) day="${1}st" ;; + *2) day="${2}nd" ;; + *3) day="${1}rd" ;; + *) day="${1}th" ;; +esac + +humandate=$(date "+%B, $day, %Y" -d "$DATE") +(echo "$humandate</b> : <i>$NEWVER</i>" + echo " <p>" + echo " <ul>" + echo "<--------------------------- edit contents below --------------------------->" + echo "- per tag :" + git log --oneline --reverse --format="%s" "v$OLD".."$LASTCOM" | cut -f1 -d':' | sort | uniq -c + echo + echo "- per topic :" + git log --oneline --reverse --format="%s" "v$OLD".."$LASTCOM" | cut -f2 -d':' | awk '{sub("s$","",$1); print $1}' | sort | uniq -c + echo + echo "major commits :" + git log --oneline --reverse --format=" - %s" "v$OLD".."$LASTCOM" | grep MAJOR + echo + echo "<--------------------------------------------------------------------------->" + echo " Code and changelog are available <a href=\"/download/${BRANCH}/src/\">here</a> as usual." + echo " </ul>" + echo " <p>" + echo " <b>" +) >> "$HTML" + +echo "The announce was emitted into file $OUTPUT." +echo "You can edit it and send it this way :" +echo +echo " mutt -H <(tail -n +4 ${OUTPUT##*/}) -s \"[ANNOUNCE] haproxy-$NEWVER\" haproxy@formilux.org" +echo +echo "The HTML block was emitted into $HTML and needs to be finished by hand." +echo diff --git a/scripts/backport b/scripts/backport new file mode 100755 index 0000000..4f60140 --- /dev/null +++ b/scripts/backport @@ -0,0 +1,146 @@ +#!/usr/bin/env bash + +USAGE="Usage: ${0##*/} <last> <commit> [...]" +START="$PWD" +LAST= +UPSTREAM= +COMMIT= +BRANCH= + +die() { + [ "$#" -eq 0 ] || echo "$*" >&2 + exit 1 +} + +err() { + echo "$*" >&2 +} + +quit() { + [ "$#" -eq 0 ] || echo "$*" + exit 0 +} + +short() { + git rev-parse --short "$1" +} + +# returns the latest commit ID in $REPLY. Returns 0 on success, non-zero on +# failure with $REPLY empty. +get_last_commit() { + REPLY=$(git rev-parse HEAD) + test -n "$REPLY" +} + +# returns the name of the current branch (1.8, 1.9, etc) in $REPLY. Returns 0 +# on success, non-zero on failure with $REPLY empty. +get_branch() { + local major subver ext + REPLY=$(git describe --tags HEAD --abbrev=0 2>/dev/null) + REPLY=${REPLY#v} + subver=${REPLY#[0-9]*.[0-9]*[-.]*[0-9].} + [ "${subver}" != "${REPLY}" ] || subver="" + major=${REPLY%.$subver} + ext=${major#*[0-9].*[0-9]} + REPLY=${major%${ext}} + test -n "$REPLY" +} + +# returns the path to the next "up" remote in $REPLY, and zero on success +# or non-zero when the last one was reached. +up() { + REPLY=$(git remote -v | awk '/^up\t.*\(fetch\)$/{print $2}') + test -n "$REPLY" +} + +# returns the path to the next "down" remote in $REPLY, and zero on success +# or non-zero when the last one was reached. +down() { + REPLY=$(git remote -v | awk '/^down\t.*\(fetch\)$/{print $2}') + test -n "$REPLY" +} + +# verifies that the repository is clean of any pending changes +check_clean() { + test -z "$(git status -s -uno)" +} + +# verifies that HEAD is the master +check_master() { + test "$(git rev-parse --verify -q HEAD 2>&1)" = "$(git rev-parse --verify -q master 2>&1)" +} + +# tries to switch to the master branch, only if the current one is clean. Dies on failure. +switch_master() { + check_clean || die "$BRANCH: local changes, stopping on commit $COMMIT (upstream $UPSTREAM)" + git checkout master >/dev/null 2>&1 || die "$BRANCH: failed to checkout master, stopping on commit $COMMIT (upstream $UPSTREAM)" +} + +# walk up to the first repo +walk_up() { + cd "$START" +} + +# updates the "up" remote repository. Returns non-zero on error. +update_up() { + git remote update up >/dev/null 2>&1 +} + +# backports commit "$1" with a signed-off by tag. In case of failure, aborts +# the change and returns non-zero. Unneeded cherry-picks do return an error +# because we don't want to accidentally backport the latest commit instead of +# this one, and we don't know this one's ID. +backport_commit() { + local empty=1 + + if ! git cherry-pick -sx "$1"; then + [ -n "$(git diff)" -o -n "$(git diff HEAD)" ] || empty=0 + git cherry-pick --abort + return 1 + fi +} + +[ "$1" != "-h" -a "$1" != "--help" ] || quit "$USAGE" +[ -n "$1" -a -n "$2" ] || die "$USAGE" + +LAST="$1" +shift + +# go back to the root of the repo +cd $(git rev-parse --show-toplevel) +START="$PWD" + +while [ -n "$1" ]; do + UPSTREAM="$(short $1)" + [ -n "$UPSTREAM" ] || die "branch $BRANCH: unknown commit ID $1, cannot backport." + COMMIT="$UPSTREAM" + BRANCH="-source-" + while :; do + if ! down; then + err "branch $BRANCH: can't go further, is repository 'down' properly set ?" + break + fi + + cd "$REPLY" || die "Failed to 'cd' to '$REPLY' from '$PWD', is repository 'down' properly set ?" + + check_clean || die "Local changes in $PWD, stopping before backporting commit $COMMIT (upstream $UPSTREAM)" + + check_master || switch_master || die "Cannot switch to 'master' branch in $PWD, stopping before backporting commit $COMMIT (upstream $UPSTREAM)" + get_branch || die "Failed to get branch name in $PWD, stopping before backporting commit $COMMIT (upstream $UPSTREAM)" + BRANCH="$REPLY" + + update_up || die "$BRANCH: failed to update repository 'up', stopping before backporting commit $COMMIT (upstream $UPSTREAM)" + + backport_commit "$COMMIT" || die "$BRANCH: failed to backport commit $COMMIT (upstream $UPSTREAM). Leaving repository $PWD intact." + + if [ "$BRANCH" = "$LAST" ]; then + # reached the stop point, don't apply further + break + fi + + get_last_commit || die "$BRANCH: cannot retrieve last commit ID, stopping after backporting commit $COMMIT (upstream $UPSTREAM)" + COMMIT="$(short $REPLY)" + done + walk_up || die "Failed to go back to $PWD, stopping *after* backporting upstream $UPSTREAM" + shift +done diff --git a/scripts/build-ot.sh b/scripts/build-ot.sh new file mode 100755 index 0000000..fb128b3 --- /dev/null +++ b/scripts/build-ot.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +# +# OT helper. script built from documentation: https://github.com/haproxytech/opentracing-c-wrapper +# + +set -e + +OT_CPP_VERSION="${OT_CPP_VERSION:-1.6.0}" +OT_PREFIX="${OT_PREFIX:-${HOME}/opt}" + +wget -P download-cache/ "https://github.com/opentracing/opentracing-cpp/archive/v${OT_CPP_VERSION}.tar.gz" + +tar xf download-cache/v${OT_CPP_VERSION}.tar.gz +cd opentracing-cpp-${OT_CPP_VERSION} +mkdir build +cd build +cmake -DCMAKE_INSTALL_PREFIX=${OT_PREFIX} -DBUILD_STATIC_LIBS=OFF -DBUILD_MOCKTRACER=OFF -DBUILD_TESTING=OFF .. +make -j$(nproc) +make install + +git clone https://github.com/haproxytech/opentracing-c-wrapper.git +cd opentracing-c-wrapper + ./scripts/bootstrap + ./configure --prefix=${OT_PREFIX} --with-opentracing=${OT_PREFIX} + make -j$(nproc) + make install diff --git a/scripts/build-ssl.sh b/scripts/build-ssl.sh new file mode 100755 index 0000000..d143cec --- /dev/null +++ b/scripts/build-ssl.sh @@ -0,0 +1,146 @@ +#!/bin/sh +set -eux + +download_openssl () { + if [ ! -f "download-cache/openssl-${OPENSSL_VERSION}.tar.gz" ]; then + +# +# OpenSSL has different links for latest and previous releases +# since we want to download several versions, let us try to treat +# current version as latest, if it fails, follow with previous +# + + wget -P download-cache/ \ + "https://www.openssl.org/source/openssl-${OPENSSL_VERSION}.tar.gz" || \ + wget -P download-cache/ \ + "https://www.openssl.org/source/old/${OPENSSL_VERSION%[a-z]}/openssl-${OPENSSL_VERSION}.tar.gz" + fi +} + +# recent openssl versions support parallel builds and skipping the docs, +# while older ones require to build everything sequentially. +build_openssl_linux () { + ( + cd "openssl-${OPENSSL_VERSION}/" + ./config shared --prefix="${HOME}/opt" --openssldir="${HOME}/opt" --libdir=lib -DPURIFY + if [ -z "${OPENSSL_VERSION##1.*}" ]; then + make all + else + make -j$(nproc) build_sw + fi + make install_sw + ) +} + +build_openssl_osx () { + ( + cd "openssl-${OPENSSL_VERSION}/" + ./Configure darwin64-x86_64-cc shared \ + --prefix="${HOME}/opt" --openssldir="${HOME}/opt" --libdir=lib -DPURIFY + make depend build_sw install_sw + ) +} + +build_openssl () { + if [ "$(cat ${HOME}/opt/.openssl-version)" != "${OPENSSL_VERSION}" ]; then + tar zxf "download-cache/openssl-${OPENSSL_VERSION}.tar.gz" + case `uname` in + 'Darwin') + build_openssl_osx + ;; + 'Linux') + build_openssl_linux + ;; + esac + echo "${OPENSSL_VERSION}" > "${HOME}/opt/.openssl-version" + fi +} + +download_libressl () { + if [ ! -f "download-cache/libressl-${LIBRESSL_VERSION}.tar.gz" ]; then + wget -P download-cache/ \ + "https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/libressl-${LIBRESSL_VERSION}.tar.gz" + fi +} + +build_libressl () { + if [ "$(cat ${HOME}/opt/.libressl-version)" != "${LIBRESSL_VERSION}" ]; then + tar zxf "download-cache/libressl-${LIBRESSL_VERSION}.tar.gz" + ( + cd "libressl-${LIBRESSL_VERSION}/" + ./configure --prefix="${HOME}/opt" + make all install + ) + echo "${LIBRESSL_VERSION}" > "${HOME}/opt/.libressl-version" + fi +} + +download_boringssl () { + if [ ! -d "download-cache/boringssl" ]; then + git clone --depth=1 https://boringssl.googlesource.com/boringssl download-cache/boringssl + else + ( + cd download-cache/boringssl + git pull + ) + fi +} + +download_quictls () { + if [ ! -d "download-cache/quictls" ]; then + git clone --depth=1 https://github.com/quictls/openssl download-cache/quictls + else + ( + cd download-cache/quictls + git pull + ) + fi +} + +if [ ! -z ${LIBRESSL_VERSION+x} ]; then + download_libressl + build_libressl +fi + +if [ ! -z ${OPENSSL_VERSION+x} ]; then + download_openssl + build_openssl +fi + +if [ ! -z ${BORINGSSL+x} ]; then + ( + + # travis-ci comes with go-1.11, while boringssl requires go-1.13 + eval "$(curl -sL https://raw.githubusercontent.com/travis-ci/gimme/master/gimme | GIMME_GO_VERSION=1.13 bash)" + + download_boringssl + cd download-cache/boringssl + if [ -d build ]; then rm -rf build; fi + mkdir build + cd build + cmake -GNinja -DCMAKE_BUILD_TYPE=release -DBUILD_SHARED_LIBS=1 .. + ninja + + rm -rf ${HOME}/opt/lib || exit 0 + rm -rf ${HOME}/opt/include || exit 0 + + mkdir -p ${HOME}/opt/lib + cp crypto/libcrypto.so ssl/libssl.so ${HOME}/opt/lib + + mkdir -p ${HOME}/opt/include + cp -r ../include/* ${HOME}/opt/include + ) +fi + +if [ ! -z ${QUICTLS+x} ]; then + ( + + download_quictls + cd download-cache/quictls + + ./config shared --prefix="${HOME}/opt" --openssldir="${HOME}/opt" --libdir=lib -DPURIFY + make -j$(nproc) build_sw + make install_sw + + ) +fi diff --git a/scripts/build-vtest.sh b/scripts/build-vtest.sh new file mode 100755 index 0000000..4db35d6 --- /dev/null +++ b/scripts/build-vtest.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +set -eux + +curl -fsSL https://github.com/vtest/VTest/archive/master.tar.gz -o VTest.tar.gz +mkdir ../vtest +tar xvf VTest.tar.gz -C ../vtest --strip-components=1 +# Special flags due to: https://github.com/vtest/VTest/issues/12 +make -C ../vtest FLAGS="-O2 -s -Wall" + diff --git a/scripts/create-release b/scripts/create-release new file mode 100755 index 0000000..b8a867c --- /dev/null +++ b/scripts/create-release @@ -0,0 +1,237 @@ +#!/usr/bin/env bash +# creates a new haproxy release at the current commit +# Copyright (c) 2006-2016 Willy Tarreau <w@1wt.eu> +# +# In short : +# - requires git +# - works only from master branch +# - finds old and new version by itself +# - builds changelog +# - updates dates and versions in files +# - commits + tags + signs +# - no upload! + +USAGE="Usage: ${0##*/} [-i] [-y] [-t] [-b branch] [-d date] [-o oldver] [-n newver]" +INTERACTIVE= +TAGONLY= +SAYYES= +BRANCH= +DATE= +YEAR= +OLD= +NEW= + +die() { + [ "$#" -eq 0 ] || echo "$*" >&2 + exit 1 +} + +err() { + echo "$*" >&2 +} + +quit() { + [ "$#" -eq 0 ] || echo "$*" + exit 0 +} + +do_commit() { + ( + echo "[RELEASE] Released version $NEW" + echo + echo "Released version $NEW with the following main changes :" + sed -ne '/^[ ]*-/,/^$/{p;b a};d;:a;/^$/q' CHANGELOG + ) | git commit -a -F - +} + +do_tag() { + git tag -u "$GIT_GPG_KEY" -s -m "HAProxy $NEW" v$NEW && echo "Tagged as v$NEW" +} + +if [ -z "$GIT_COMMITTER_NAME" ]; then + GIT_COMMITTER_NAME=$(git config --get user.name) + [ -n "$GIT_COMMITTER_NAME" ] || die "GIT_COMMITTER_NAME not set" +fi + +if [ -z "$GIT_COMMITTER_EMAIL" ]; then + GIT_COMMITTER_EMAIL=$(git config --get user.email) + [ -n "$GIT_COMMITTER_EMAIL" ] || die "GIT_COMMITTER_EMAIL not set" +fi + +while [ -n "$1" -a -z "${1##-*}" ]; do + case "$1" in + -y) SAYYES=1 ; shift ;; + -i) INTERACTIVE=1 ; shift ;; + -t) TAGONLY=1 ; shift ;; + -d) DATE="$2" ; shift 2 ;; + -b) BRANCH="$2" ; shift 2 ;; + -o) OLD="$2" ; shift 2 ;; + -n) NEW="$2" ; shift 2 ;; + -h|--help) quit "$USAGE" ;; + *) die "$USAGE" ;; + esac +done + +if [ $# -gt 0 ]; then + die "$USAGE" +fi + +if [ -z "$GIT_GPG_KEY" ]; then + die "GIT_GPG_KEY is not set, it must contain your GPG key ID." +fi + +if ! git rev-parse --verify -q HEAD >/dev/null; then + die "Failed to check git HEAD." +fi + +# we want to go to the git top dir +cd $(git rev-parse --show-toplevel) + +if [ "$(git rev-parse --verify -q HEAD)" != "$(git rev-parse --verify -q master)" ]; then + die "git HEAD doesn't match master branch." +fi + +if [ "$(git diff HEAD|wc -c)" != 0 ]; then + err "You appear to have uncommitted local changes, please commit them first :" + git status -s -uno >&2 + die +fi + +if [ -z "$OLD" ]; then + OLD="$(git describe --tags HEAD --abbrev=0)" + OLD="${OLD#v}" +fi + +if ! git rev-parse --verify -q "v$OLD" >/dev/null; then + die "git tag v$OLD doesn't exist." +fi + +if [ -z "$NEW" ]; then + radix="$OLD" + while [ -n "$radix" -a -z "${radix%%*[0-9]}" ]; do + radix="${radix%[0-9]}" + done + + number=${OLD#$radix} + if [ -z "$number" -o "$radix" = "$OLD" ]; then + die "Fatal: cannot determine new version, please specify it." + fi + NEW=${radix}$((number+1)) +fi + +if git show-ref --tags "v$NEW" >/dev/null; then + die "git tag v$NEW already exists, please remove it first." +fi + +# determine the product branch from the new release +if [ -z "$BRANCH" ]; then + subvers=${NEW#[0-9]*.[0-9]*[-.]*[0-9].} + [ "${subvers}" = "${NEW}" ] && subvers="" + major=${NEW%.$subvers} + branch_ext=${major#*[0-9].*[0-9]} + BRANCH=${major%${branch_ext}} +fi + + +# determine the release date +if [ -z "$DATE" ]; then + # Uncomment the line below to use the date of the last commit, + # otherwise fall back to current date + DATE="$(git log --pretty=fuller -1 v$NEW 2>/dev/null | sed -ne '/^CommitDate:/{s/\(^[^ ]*:\)\|\( [-+].*\)//gp;q}')" + DATE="$(date +%Y/%m/%d -d "$DATE")" +else + if [ "$DATE" != "$(date +%Y/%m/%d -d "$DATE")" ]; then + die "Date format must exclusively be YYYY/MM/DD ; date was '$DATE'." + fi +fi +YEAR="${DATE%%/*}" + +if [ -n "$TAGONLY" ]; then + do_tag || die "Failed to tag changes" + echo "Done. You may have to push changes." + exit 0 +fi + +echo "About to release version $NEW from $OLD at $DATE (branch $BRANCH)." +if [ -z "$SAYYES" ]; then + echo "Press ENTER to continue or Ctrl-C to abort now!" + read +fi + +echo "Updating CHANGELOG ..." +( echo "ChangeLog :" + echo "===========" + echo + echo "$DATE : $NEW" + #git shortlog v$OLD.. | sed -ne 's/^ / - /p' + if [ $(git log --oneline v$OLD.. | wc -l) = 0 ]; then + echo " - exact copy of $OLD" + else + git log --oneline --reverse --format=" - %s" v$OLD.. + fi + echo + tail -n +4 CHANGELOG +) >.chglog.tmp && mv .chglog.tmp CHANGELOG + +echo "Updating VERSION ..." +rm -f VERSION VERDATE +echo "$NEW" > VERSION + +echo "Updating VERDATE ..." +echo '$Format:%ci$' > VERDATE +echo "$DATE" >> VERDATE + +# updating branch and date in all modified doc files except the outdated architecture.txt +for file in doc/intro.txt doc/configuration.txt doc/management.txt $(git diff --name-only v${OLD}.. -- doc); do + if [ ! -e "$file" ]; then continue; fi + if [ "$file" = doc/architecture.txt ]; then continue; fi + echo "Updating $file ..." + sed -e "1,10s:\(\sversion\s\).*:\1$BRANCH:" \ + -e "1,10s:\(\s\)\(20[0-9]\{2\}/[0-9]\{1,2\}/[0-9]\{1,2\}\):\1$DATE:" \ + -i "$file" +done + +echo "Updating haproxy.c ..." +sed -e "s:Copyright 2000-[0-9]*\s*Willy Tarreau.*>:Copyright 2000-$YEAR Willy Tarreau <willy@haproxy.org>:" \ + -i src/haproxy.c + +echo "Updating version.h ..." +sed -e "s:^\(#define\s*PRODUCT_BRANCH\s*\)\"[^\"]*\":\1\"$BRANCH\":" \ + -i include/haproxy/version.h + +if [ -n "$INTERACTIVE" ]; then + vi CHANGELOG VERSION VERDATE \ + src/haproxy.c doc/configuration.txt \ + $(git diff --name-only v${OLD}.. -- doc) +fi + +if [ "$(git diff -- CHANGELOG | wc -c)" = 0 ]; then + die "CHANGELOG must be updated." +fi + +if [ -z "$SAYYES" ]; then + echo "Press ENTER to review the changes..." + read +fi + +git diff + +echo +echo "About to commit and tag version $NEW with the following message:" +echo +echo "[RELEASE] Released version $NEW with the following main changes :" +sed -ne '/^[ ]*-/,/^$/{p;b a};d;:a;/^$/q' CHANGELOG + +echo +echo "LAST chance to cancel! Press ENTER to proceed now or Ctrl-C to abort." +read + +do_commit || die "Failed to commit changes" +do_tag || die "Failed to tag changes" + +remote=$(git config --get branch.master.remote) +echo "Do not forget to push updates, publish and announce this version :" +echo +echo "git push ${remote:-origin} master v$NEW" +echo "${0%/*}/publish-release" +echo "${0%/*}/announce-release" diff --git a/scripts/git-show-backports b/scripts/git-show-backports new file mode 100755 index 0000000..01a9e63 --- /dev/null +++ b/scripts/git-show-backports @@ -0,0 +1,273 @@ +#!/usr/bin/env bash +# +# Compares multiple branches against a reference and shows which ones contain +# each commit, and the level of backports since the origin or its own ancestors. +# +# Copyright (c) 2016 Willy Tarreau <w@1wt.eu> +# +# The purpose is to make it easy to visualize what backports might be missing +# in a maintenance branch, and to easily spot the ones that are needed and the +# ones that are not. It solely relies on the "cherry-picked from" tags in the +# commit messages to find what commit is available where, and can even find a +# reference commit's ancestor in another branch's commit ancestors as well to +# detect that the patch is present. When done with the proper references and +# a correct ordering of the branches, it can be used to quickly apply a set of +# fixes to a branch since it dumps suggested commands at the end. When doing +# so it is a good idea to use "HEAD" as the last branch to avoid doing mistakes. +# +# Examples : +# - find what's in master and not in current branch : +# show-backports -q -m -r master HEAD +# - find what's in 1.6/master and in hapee-maint-1.5r2 but not in current branch : +# show-backports -q -m -r 1.6/master hapee-maint-1.5r2 HEAD | grep ' [a-f0-9]\{8\}[-+][0-9] ' +# - check that no recent fix from master is missing in any maintenance branch : +# show-backports -r master hapee-maint-1.5r2 aloha-7.5 hapee-maint-1.5r1 aloha-7.0 +# - see what was recently merged into 1.6 and has no equivalent in local master : +# show-backports -q -m -r 1.6/master -b "1.6/master@{1 week ago}" master +# - check what extra backports are present in hapee-r2 compared to hapee-r1 : +# show-backports -q -m -r hapee-r2 hapee-r1 + + +USAGE="Usage: ${0##*/} [-q] [-H] [-m] [-u] [-r reference] [-l logexpr] [-s subject] [-b base] {branch|range} [...] [-- file*]" +BASES=( ) +BRANCHES=( ) +REF=master +BASE= +QUIET= +LOGEXPR= +SUBJECT= +MISSING= +UPSTREAM= +BODYHASH= + +die() { + [ "$#" -eq 0 ] || echo "$*" >&2 + exit 1 +} + +err() { + echo "$*" >&2 +} + +quit() { + [ "$#" -eq 0 ] || echo "$*" + exit 0 +} + +short() { + # git rev-parse --short $1 + echo "${1::8}" +} + +dump_commit_matrix() { + title=":$REF:" + for branch in "${BRANCHES[@]}"; do + #echo -n " $branch" + title="$title :${branch}:" + done + title="$title |" + + count=0 + # now look up commits + while read ref subject; do + if [ -n "$MISSING" -a "${subject:0:9}" = "[RELEASE]" ]; then + continue + fi + + upstream="none" + missing=0 + refbhash="" + line="" + for branch in "${BRANCHES[@]}"; do + set -- $(grep -m 1 $ref "$WORK/${branch//\//_}") + newhash=$1 ; shift + bhash="" + # count the number of cherry-picks after this one. Since we shift, + # the result is in "$#" + while [ -n "$1" -a "$1" != "$ref" ]; do + shift + done + if [ -n "$newhash" ]; then + line="${line} $(short $newhash)-$#" + else + # before giving up we can check if our current commit was + # itself cherry-picked and check this again. In order not + # to have to do it all the time, we can cache the result + # for the current line. If a match is found we report it + # with the '+' delimiter instead of '-'. + if [ "$upstream" = "none" ]; then + upstream=( $(git log -1 --pretty --format=%B "$ref" | \ + sed -n 's/^commit \([^)]*\) upstream\.$/\1/p;s/^(cherry picked from commit \([^)]*\))/\1/p') ) + fi + newhash="" + for h in ${upstream[@]}; do + set -- $(grep -m 1 $h "$WORK/${branch//\//_}") + newhash=$1 ; shift + while [ -n "$1" -a "$1" != "$h" ]; do + shift + done + if [ -n "$newhash" ]; then + line="${line} $(short $newhash)+$#" + break + fi + done + if [ -z "$newhash" -a -n "$BODYHASH" ]; then + if [ -z "$refbhash" ]; then + refbhash=$(git log -1 --pretty="%an|%ae|%at|%B" "$ref" | sed -n '/^\(Signed-off-by\|(cherry picked\)/q;p' | md5sum) + fi + + + set -- $(grep -m 1 "H$refbhash\$" "$WORK/${branch//\//_}") + newhash=$1 ; shift + if [ -n "$newhash" ]; then + line="${line} $(short $newhash)+?" + break + fi + fi + if [ -z "$newhash" ]; then + line="${line} -" + missing=1 + fi + fi + done + line="${line} |" + if [ -z "$MISSING" -o $missing -gt 0 ]; then + [ $((count++)) -gt 0 ] || echo "$title" + [ "$QUIET" != "" -o $count -lt 20 ] || count=0 + if [ -z "$UPSTREAM" -o "$upstream" = "none" -o -z "$upstream" ]; then + echo "$(short $ref) $line" + else + echo "$(short $upstream) $line" + fi + fi + done < "$WORK/${REF//\//_}" +} + +while [ -n "$1" -a -z "${1##-*}" ]; do + case "$1" in + -b) BASE="$2" ; shift 2 ;; + -r) REF="$2" ; shift 2 ;; + -l) LOGEXPR="$2" ; shift 2 ;; + -s) SUBJECT="$2" ; shift 2 ;; + -q) QUIET=1 ; shift ;; + -m) MISSING=1 ; shift ;; + -u) UPSTREAM=1 ; shift ;; + -H) BODYHASH=1 ; shift ;; + -h|--help) quit "$USAGE" ;; + *) die "$USAGE" ;; + esac +done + +# branches may also appear as id1..id2 to limit the history instead of looking +# back to the common base. The field is left empty if not set. +BRANCHES=( ) +BASES=( ) +while [ $# -gt 0 ]; do + if [ "$1" = "--" ]; then + shift + break + fi + branch="${1##*..}" + if [ "$branch" == "$1" ]; then + base="" + else + base="${1%%..*}" + fi + BASES[${#BRANCHES[@]}]="$base" + BRANCHES[${#BRANCHES[@]}]="$branch" + shift +done + +# args left for git-log +ARGS=( "$@" ) + +if [ ${#BRANCHES[@]} = 0 ]; then + die "$USAGE" +fi + +for branch in "$REF" "${BRANCHES[@]}"; do + if ! git rev-parse --verify -q "$branch" >/dev/null; then + die "Failed to check git branch $branch." + fi +done + +if [ -z "$BASE" ]; then + err "Warning! No base specified, looking for common ancestor." + BASE=$(git merge-base --all "$REF" "${BRANCHES[@]}") + if [ -z "$BASE" ]; then + die "Couldn't find a common ancestor between these branches" + fi +fi + +# we want to go to the git root dir +DIR="$PWD" +cd $(git rev-parse --show-toplevel) + +mkdir -p .git/.show-backports #|| die "Can't create .git/.show-backports" +WORK=.git/.show-backports + +rm -f "$WORK/${REF//\//_}" +git log --reverse ${LOGEXPR:+--grep $LOGEXPR} --pretty="%H %s" "$BASE".."$REF" -- "${ARGS[@]}" | grep "${SUBJECT}" > "$WORK/${REF//\//_}" + +# for each branch, enumerate all commits and their ancestry + +branch_num=0; +while [ $branch_num -lt "${#BRANCHES[@]}" ]; do + branch="${BRANCHES[$branch_num]}" + base="${BASES[$branch_num]}" + base="${base:-$BASE}" + rm -f "$WORK/${branch//\//_}" + git log --reverse --pretty="%H %s" "$base".."$branch" -- "${ARGS[@]}" | grep "${SUBJECT}" | while read h subject; do + echo -n "$h" $(git log -1 --pretty --format=%B "$h" | \ + sed -n 's/^commit \([^)]*\) upstream\.$/\1/p;s/^(cherry picked from commit \([^)]*\))/\1/p') + if [ -n "$BODYHASH" ]; then + echo " H$(git log -1 --pretty="%an|%ae|%at|%B" "$h" | sed -n '/^\(Signed-off-by\|(cherry picked\)/q;p' | md5sum)" + else + echo + fi + done > "$WORK/${branch//\//_}" + (( branch_num++ )) +done + +count=0 +dump_commit_matrix | column -t | \ +( + left_commits=( ) + right_commits=( ) + while read line; do + # append the subject at the end of the line + set -- $line + echo -n "$line " + if [ "${line::1}" = ":" ]; then + echo "---- Subject ----" + else + # doing it this way prevents git from abusing the terminal + echo "$(git log -1 --pretty="%s" "$1")" + left_commits[${#left_commits[@]}]="$1" + comm="" + while [ -n "$1" -a "$1" != "-" -a "$1" != "|" ]; do + comm="${1%-*}" + shift + done + right_commits[${#right_commits[@]}]="$comm" + fi + done + if [ -n "$MISSING" -a ${#left_commits[@]} -eq 0 ]; then + echo "No missing commit to apply." + elif [ -n "$MISSING" ]; then + echo + echo + echo "In order to show and/or apply all leftmost commits to current branch :" + echo " git show --pretty=format:'%C(yellow)commit %H%C(normal)%nAuthor: %an <%ae>%nDate: %aD%n%n%C(green)%C(bold)git cherry-pick -sx %h%n%n%w(72,4,4)%B%N' ${left_commits[@]}" + echo + echo " git cherry-pick -sx ${left_commits[@]}" + echo + if [ "${left_commits[*]}" != "${right_commits[*]}" ]; then + echo "In order to show and/or apply all rightmost commits to current branch :" + echo " git show --pretty=format:'%C(yellow)commit %H%C(normal)%nAuthor: %an <%ae>%nDate: %aD%n%n%C(green)%C(bold)git cherry-pick -sx %h%n%n%w(72,4,4)%B%N' ${right_commits[@]}" + echo + echo " git cherry-pick -sx ${right_commits[@]}" + echo + fi + fi +) diff --git a/scripts/make-releases-json b/scripts/make-releases-json new file mode 100755 index 0000000..38bb2b6 --- /dev/null +++ b/scripts/make-releases-json @@ -0,0 +1,103 @@ +#!/usr/bin/env bash +# +# Scan a branch directory for source tarballs and rebuild the releases.json +# file for that branch. md5 and sha256 are added if present. The highest +# numberred version is referenced as the latest release. +# +# Usage: $0 [-b branch] [-o outfile] /path/to/download/branch +# + +USAGE="Usage: ${0##*/} [-b branch] [-o outfile] DIR" +OUTPUT= +BRANCH= +DIR= + +die() { + [ "$#" -eq 0 ] || echo "$*" >&2 + exit 1 +} + +err() { + echo "$*" >&2 +} + +quit() { + [ "$#" -eq 0 -o -n "$QUIET" ] || echo "$*" + exit 0 +} + +emit_json() { + printf '{\n "branch": "%s",\n' ${BRANCH} + latest="" + for file in $(find "$DIR/src" -name 'haproxy-[0-9]*.gz' -printf "%P\n" |grep -v '[0-9]-patches*' | sort -rV ); do + rel="${file##*haproxy-}" + rel="${rel%%.tar.*}" + if [ -z "$latest" ]; then + latest="$rel"; + printf ' "latest_release": "%s",\n' ${latest} + printf ' "releases": {\n' + else + printf ",\n" + fi + printf ' "%s": {\n' ${rel} + printf ' "file": "%s"' ${file} + if [ -s "$DIR/src/$file.md5" ]; then + printf ',\n "md5": "%s"' $(awk '{print $1}' "$DIR/src/$file.md5") + fi + if [ -s "$DIR/src/$file.sha256" ]; then + printf ',\n "sha256": "%s"' $(awk '{print $1}' "$DIR/src/$file.sha256") + fi + printf '\n }' + done + + if [ -n "$latest" ]; then + printf "\n }" ## "releases" + fi + + printf '\n}\n' +} + + +### main + +while [ -n "$1" -a -z "${1##-*}" ]; do + case "$1" in + -b) BRANCH="$2" ; shift 2 ;; + -o) OUTPUT="$2" ; shift 2 ;; + -h|--help) quit "$USAGE" ;; + *) die "$USAGE" ;; + esac +done + +if [ $# -ne 1 ]; then + die "$USAGE" +fi + +DIR="$1" ; shift +if [ -z "$DIR" ]; then + die "Missing download directory name." +fi + +if [ ! -d "$DIR/." ]; then + die "Download directory doesn't exist : $DIR" +fi + +if [ ! -d "$DIR/src" ]; then + die "Download directory must contain 'src' : $DIR" +fi + +if [ -z "$BRANCH" ]; then + BRANCH=${DIR##*/} + if [ -n "${BRANCH//[0-9.]}" ]; then + die "Couldn't determine branch number from dir name: $BRANCH" + fi +fi + +# echo "debug: DIR=$DIR BRANCH=$BRANCH" +if [ -n "$OUTPUT" ]; then + emit_json > "$OUTPUT.tmp" + mv -f "$OUTPUT.tmp" "$OUTPUT" + rm -f "$OUTPUT.tmp" +else + emit_json +fi diff --git a/scripts/publish-release b/scripts/publish-release new file mode 100755 index 0000000..3cf32d8 --- /dev/null +++ b/scripts/publish-release @@ -0,0 +1,191 @@ +#!/usr/bin/env bash +# puts the public files online after a release +# Copyright (c) 2006-2016 Willy Tarreau <w@1wt.eu> +# +# In short : +# - requires git +# - no restriction to master, uses last tag +# - copies & compresses files, changelog & docs to the final destination +# - shows a listing of the final file + +USAGE="Usage: ${0##*/} [-a] [-q] [-y] [-b branch] [-n newver] DIR" +CMD_GZIP="${CMD_GZIP:-gzip -nc9}" +TARGET_DIR= +OUTPUT= +SAYYES= +BRANCH= +DEVEL= +QUIET= +AUTO= +ARG0="$0" +NEW= +DIR= +DOC=( ) + +die() { + [ "$#" -eq 0 ] || echo "$*" >&2 + exit 1 +} + +err() { + echo "$*" >&2 +} + +quit() { + [ "$#" -eq 0 -o -n "$QUIET" ] || echo "$*" + exit 0 +} + +while [ -n "$1" -a -z "${1##-*}" ]; do + case "$1" in + -a) AUTO=1 ; shift ;; + -q) QUIET=1 ; shift ;; + -y) SAYYES=1 ; shift ;; + -b) BRANCH="$2" ; shift 2 ;; + -n) NEW="$2" ; shift 2 ;; + -h|--help) quit "$USAGE" ;; + *) die "$USAGE" ;; + esac +done + +if [ $# -ne 1 ]; then + die "$USAGE" +fi + +DIR="$1" ; shift +if [ -z "$DIR" ]; then + die "Missing target directory name." +fi + +if [ -n "${DIR##/*}" ]; then + DIR="$PWD/$DIR" +fi + +if [ ! -d "$DIR/." ]; then + die "Target directory doesn't exist : $DIR" +fi + +if ! git rev-parse --verify -q HEAD >/dev/null; then + die "Failed to check git HEAD." +fi + +# we want to go to the git top dir +toplvl=$(git rev-parse --show-toplevel) +if [ -n "$toplvl" ]; then + cd "$toplvl" +fi + +# ensure that a master branch exists here +if [ -z "$(git rev-parse --verify -q master 2>/dev/null)" ]; then + die "Current directory doesn't seem to be a valid git directory (no master branch)." +fi + +if [ "$(git rev-parse --verify -q HEAD)" != "$(git rev-parse --verify -q master)" ]; then + die "git HEAD doesn't match master branch." +fi + +if [ "$(git diff HEAD 2>/dev/null |wc -c)" != 0 ]; then + err "You appear to have uncommitted local changes, please commit them first :" + git status -s -uno >&2 + die +fi + +if [ -z "$NEW" -o -n "$AUTO" ]; then + if [ -z "$NEW" ]; then + NEW="$(git describe --tags HEAD --abbrev=0)" + NEW="${NEW#v}" + if [ -z "$NEW" ]; then + die "Fatal: cannot determine new version, please specify it." + fi + fi + + if [ "$(git describe --tags HEAD)" != "v$NEW" ]; then + if [ -n "$AUTO" ]; then + quit "Not tagged, nothing to do." + fi + die "Current version doesn't seem tagged, it reports $(git describe --tags "v$NEW"). Did you release it ?" + fi +fi + +if ! git show-ref --tags "v$NEW" >/dev/null; then + die "git tag v$NEW doesn't exist, did you create the release ?" +fi + +# determine the product branch from the new release +if [ -z "$BRANCH" ]; then + subvers=${NEW#[0-9]*.[0-9]*[-.]*[0-9].} + [ "${subvers}" = "${NEW}" ] && subvers="" + major=${NEW%.$subvers} + branch_ext=${major#*[0-9].*[0-9]} + BRANCH=${major%${branch_ext}} +fi + +TARGET_DIR="$DIR/$BRANCH" +if [ ! -d "$TARGET_DIR/." ]; then + die "Target directory doesn't contain branch $BRANCH. You may have to create it in $DIR." +fi + +if [ -z "${NEW##*-dev*}" ]; then + DEVEL="/devel" +fi + +if [ -n "$AUTO" -a -e "$TARGET_DIR/src${DEVEL}/haproxy-$NEW.tar.gz.md5" ]; then + quit "Version $NEW Already released." +fi + +if ! mkdir -p "$TARGET_DIR/src$DEVEL" "$TARGET_DIR/doc"; then + die "failed to create target directories." +fi + +case "$BRANCH" in + 1.3) DOC=( doc/{haproxy-en,haproxy-fr,configuration,architecture}.txt ) ;; + 1.4) DOC=( doc/{haproxy-en,haproxy-fr,configuration}.txt ) ;; + 1.5) DOC=( doc/{coding-style,configuration,proxy-protocol}.txt ) ;; + 1.6) DOC=( doc/{coding-style,intro,management,configuration,proxy-protocol,lua}.txt ) ;; + *) DOC=( doc/{coding-style,intro,management,configuration,proxy-protocol,lua,SPOE}.txt ) ;; +esac + +if [ -z "$AUTO" ]; then + echo "Ready to produce the following files in $TARGET_DIR/ :" + echo " haproxy-$NEW.tar.gz -> src${DEVEL}/" + echo " CHANGELOG -> src/CHANGELOG" + echo " ${DOC[@]} -> doc/*{,.gz}" + echo + + git ls-tree -l --abbrev=12 "v$NEW" -- CHANGELOG "${DOC[@]}" + + if [ -z "$SAYYES" ]; then + echo "Press ENTER to continue or Ctrl-C to abort now!" + read + fi +fi + +echo "Archiving sources for version $NEW ..." +rm -f "${TARGET_DIR}/src${DEVEL}/haproxy-${NEW}.tar.gz"{,.md5,.sha256} +if ! git archive --format=tar --prefix="haproxy-${NEW}/" "v$NEW" | \ + $CMD_GZIP > "${TARGET_DIR}/src${DEVEL}/haproxy-${NEW}.tar.gz"; then + die "Failed to produce the tar.gz archive" +fi + +( cd "$TARGET_DIR/src${DEVEL}" ; \ + md5sum haproxy-$NEW.tar.gz > haproxy-$NEW.tar.gz.md5 ; \ + sha256sum haproxy-$NEW.tar.gz > haproxy-$NEW.tar.gz.sha256 ) + +echo "Extracting doc ..." +git show "v$NEW:CHANGELOG" > "$TARGET_DIR/src/CHANGELOG" + +for i in "${DOC[@]}"; do + git show "v$NEW:$i" > "$TARGET_DIR/doc/${i#doc/}" + $CMD_GZIP < "$TARGET_DIR/doc/${i#doc/}" > "$TARGET_DIR/doc/${i#doc/}.gz" +done + +if [ -x "${ARG0%/*}/make-releases-json" ]; then + # regenerate versions + "${ARG0%/*}/make-releases-json" -o "$TARGET_DIR/src/releases.json" "$TARGET_DIR" +fi + +echo "Done : ls -l ${TARGET_DIR}" +( cd "$TARGET_DIR" ; + ls -l src/CHANGELOG "src${DEVEL}/haproxy-${NEW}".tar.gz{,.md5,.sha256} $(for i in "${DOC[@]}"; do echo "doc/${i#doc/}"{,.gz}; done) +) +echo diff --git a/scripts/run-regtests.sh b/scripts/run-regtests.sh new file mode 100755 index 0000000..5126efb --- /dev/null +++ b/scripts/run-regtests.sh @@ -0,0 +1,416 @@ +#!/bin/sh + +_help() +{ + cat << EOF +### run-regtests.sh ### + Running run-regtests.sh --help shows this information about how to use it + + Run without parameters to run all tests in the current folder (including subfolders) + run-regtests.sh + + Provide paths to run tests from (including subfolders): + run-regtests.sh ./tests1 ./tests2 + + Parameters: + --j <NUM>, To run vtest with multiple jobs / threads for a faster overall result + run-regtests.sh ./fasttest --j 16 + + --v, to run verbose + run-regtests.sh --v, disables the default vtest 'quiet' parameter + + --debug to show test logs on standard output (implies --v) + run-regtests.sh --debug + + --keep-logs to keep all log directories (by default kept if test fails) + run-regtests.sh --keep-logs + + --vtestparams <ARGS>, passes custom ARGS to vtest + run-regtests.sh --vtestparams "-n 10" + + --type <reg tests types> filter the types of the tests to be run, depending on + the commented REGTESTS_TYPE variable value in each VTC file. + The value of REGTESTS_TYPE supported are: default, slow, bug, broken, devel + and experimental. When not specified, it is set to 'default' as default value. + + run-regtest.sh --type slow,default + + --clean to cleanup previous reg-tests log directories and exit + run-regtests.sh --clean + + Including text below into a .vtc file will check for its requirements + related to haproxy's target and compilation options + # Below targets are not capable of completing this test successfully + #EXCLUDE_TARGET=freebsd, abns sockets are not available on freebsd + + #EXCLUDE_TARGETS=dos,freebsd,windows + + # Below option is required to complete this test successfully + #REQUIRE_OPTION=OPENSSL, this test needs OPENSSL compiled in. + #REQUIRE_OPTIONS=ZLIB|SLZ,OPENSSL,LUA + + #REQUIRE_SERVICE=prometheus-exporter + #REQUIRE_SERVICES=prometheus-exporter,foo + + # To define a range of versions that a test can run with: + #REQUIRE_VERSION=0.0 + #REQUIRE_VERSION_BELOW=99.9 + + Configure environment variables to set the haproxy and vtest binaries to use + setenv HAPROXY_PROGRAM /usr/local/sbin/haproxy + setenv VTEST_PROGRAM /usr/local/bin/vtest + setenv HAPROXY_ARGS "-dM -de -m 50" + or + export HAPROXY_PROGRAM=/usr/local/sbin/haproxy + export VTEST_PROGRAM=/usr/local/bin/vtest + export HAPROXY_ARGS="-dM -de -m 50" +EOF + exit 0 +} + +add_range_to_test_list() +{ + level0="*.vtc" + level1="h*.vtc" + level2="s*.vtc" + level3="l*.vtc" + level4="b*.vtc" + level5="k*.vtc" + level6="e*.vtc" + + new_range=$(echo $1 | tr '-' ' ') + non_digit=$(echo $new_range | grep '[^0-9 ]') + if [ -n "$non_digit" ] ; then + return + fi + if [ "$new_range" = "$1" ] ; then + if [ $1 -gt 6 ] ; then + return + fi + eval echo '$'level$1 + return + fi + if [ -z "$new_range" ] ; then + return + fi + list= + for l in $(seq $new_range) ; do + if [ -n "l" ] ; then + if [ -z "$list" ] ; then + list="$(eval echo '$'level${l})" + else + list="$list $(eval echo '$'level${l})" + fi + fi + done + + echo $list +} + +_startswith() { + _str="$1" + _sub="$2" + echo "$_str" | grep "^$_sub" >/dev/null 2>&1 +} + +_findtests() { + set -f + + REGTESTS_TYPES="${REGTESTS_TYPES:-default,bug,devel,slow}" + any_test=$(echo $REGTESTS_TYPES | grep -cw "any") + for i in $( find "$1" -name *.vtc ); do + skiptest= + OLDIFS="$IFS"; IFS="$LINEFEED" + set -- $(grep '^#[0-9A-Z_]*=' "$i") + IFS="$OLDIFS" + + require_version=""; require_version_below=""; require_options=""; + require_services=""; exclude_targets=""; regtest_type="" + requiredoption=""; requiredservice=""; excludedtarget=""; + + while [ $# -gt 0 ]; do + v="$1"; v="${v#*=}" + case "$1" in + "#REQUIRE_VERSION="*) require_version="$v" ;; + "#REQUIRE_VERSION_BELOW="*) require_version_below="$v" ;; + "#REQUIRE_OPTIONS="*) require_options="$v" ;; + "#REQUIRE_SERVICES="*) require_services="$v" ;; + "#EXCLUDE_TARGETS="*) exclude_targets="$v" ;; + "#REGTEST_TYPE="*) regtest_type="$v" ;; + "#REQUIRE_OPTION="*) requiredoption="${v%,*}" ;; + "#REQUIRE_SERVICE="*) required_service="${v%,*}" ;; + "#EXCLUDE_TARGET="*) excludedtarget="${v%,*}" ;; + # Note: any new variable declared here must be initialized above. + esac + shift + done + + if [ $any_test -ne 1 ] ; then + if [ -z $regtest_type ] ; then + regtest_type=default + fi + if ! $(echo $REGTESTS_TYPES | grep -wq $regtest_type) ; then + echo " Skip $i because its type '"$regtest_type"' is excluded" + skiptest=1 + fi + fi + + if [ -n "$requiredoption" ]; then + require_options="$require_options,$requiredoption" + fi + + if [ -n "$requiredservice" ]; then + require_services="$require_services,$requiredservice" + fi + + if [ -n "$excludedtarget" ]; then + exclude_targets="$exclude_targets,$excludedtarget" + fi + + IFS=","; set -- $require_options; IFS=$OLDIFS; require_options="$*" + IFS=","; set -- $require_services; IFS=$OLDIFS; require_services="$*" + IFS=","; set -- $exclude_targets; IFS=$OLDIFS; exclude_targets="$*" + + if [ -n "$require_version" ]; then + if [ $(_version "$HAPROXY_VERSION") -lt $(_version "$require_version") ]; then + echo " Skip $i because option haproxy is version: $HAPROXY_VERSION" + echo " REASON: this test requires at least version: $require_version" + skiptest=1 + fi + fi + if [ -n "$require_version_below" ]; then + if [ $(_version "$HAPROXY_VERSION") -ge $(_version "$require_version_below") ]; then + echo " Skip $i because option haproxy is version: $HAPROXY_VERSION" + echo " REASON: this test requires a version below: $require_version_below" + skiptest=1 + fi + fi + + for excludedtarget in $exclude_targets; do + if [ "$excludedtarget" = "$TARGET" ]; then + echo " Skip $i because haproxy is compiled for the excluded target $TARGET" + skiptest=1 + fi + done + + for requiredoption in $require_options; do + IFS="|"; set -- $requiredoption; IFS=$OLDIFS; alternatives="$*" + found= + for alt in $alternatives; do + if [ -z "${FEATURES_PATTERN##* +$alt *}" ]; then + found=1; + fi + done + if [ -z $found ]; then + echo " Skip $i because haproxy is not compiled with the required option $requiredoption" + skiptest=1 + fi + done + + for requiredservice in $require_services; do + IFS="|"; set -- $requiredservice; IFS=$OLDIFS; alternatives="$*" + found= + for alt in $alternatives; do + if [ -z "${SERVICES_PATTERN##* $alt *}" ]; then + found=1; + fi + done + if [ -z $found ]; then + echo " Skip $i because haproxy is not compiled with the required service $requiredservice" + skiptest=1 + fi + done + + if [ -z $skiptest ]; then + echo " Add test: $i" + testlist="$testlist $i" + fi + done +} + +_cleanup() +{ + DIRS=$(find "${TESTDIR}" -maxdepth 1 -type d -name "haregtests-*" -exec basename {} \; 2>/dev/null) + if [ -z "${DIRS}" ]; then + echo "No reg-tests log directory found" + else + echo "Cleanup following reg-tests log directories:" + for d in ${DIRS}; do + echo " o ${TESTDIR}/$d" + done + read -p "Continue (y/n)?" reply + case "$reply" in + y|Y) + for d in ${DIRS}; do + rm -r "${TESTDIR}/$d" + done + echo "done" + exit 0 + ;; + *) + echo "aborted" + exit 1 + ;; + esac + fi +} + + +_process() { + while [ ${#} -gt 0 ]; do + if _startswith "$1" "-"; then + case "${1}" in + --j) + jobcount="$2" + shift + ;; + --vtestparams) + vtestparams="$2" + shift + ;; + --v) + verbose="" + ;; + --debug) + verbose="" + debug="-v" + ;; + --keep-logs) + keep_logs="-L" + ;; + --type) + REGTESTS_TYPES="$2" + shift + ;; + --clean) + _cleanup + exit 0 + ;; + --help) + _help + ;; + *) + echo "Unknown parameter : $1" + exit 1 + ;; + esac + else + REGTESTS="${REGTESTS} $1" + fi + shift 1 + done +} + +# compute a version from up to 4 sub-version components, each multiplied +# by a power of 1000, and padded left with 0, 1 or 2 zeroes. +_version() { + OLDIFS="$IFS"; IFS="."; set -- $*; IFS="$OLDIFS" + set -- ${1%%[!0-9]*} 000${2%%[!0-9]*} 000${3%%[!0-9]*} 000${4%%[!0-9]*} + prf2=${2%???}; prf3=${3%???}; prf4=${4%???} + echo ${1}${2#$prf2}${3#$prf3}${4#$prf4} +} + + +HAPROXY_PROGRAM="${HAPROXY_PROGRAM:-${PWD}/haproxy}" +HAPROXY_ARGS="${HAPROXY_ARGS--dM}" +VTEST_PROGRAM="${VTEST_PROGRAM:-vtest}" +TESTDIR="${TMPDIR:-/tmp}" +REGTESTS="" +LINEFEED=" +" + +jobcount="" +verbose="-q" +debug="" +keep_logs="-l" +testlist="" + +_process "$@"; + +echo "" +echo "########################## Preparing to run tests ##########################" + +preparefailed= +if ! [ -x "$(command -v $HAPROXY_PROGRAM)" ]; then + echo "haproxy not found in path, please specify HAPROXY_PROGRAM environment variable" + preparefailed=1 +fi +if ! [ -x "$(command -v $VTEST_PROGRAM)" ]; then + echo "vtest not found in path, please specify VTEST_PROGRAM environment variable" + preparefailed=1 +fi +if [ $preparefailed ]; then + exit 1 +fi + +{ read HAPROXY_VERSION; read TARGET; read FEATURES; read SERVICES; } << EOF +$($HAPROXY_PROGRAM $HAPROXY_ARGS -vv | grep 'HA-\?Proxy version\|TARGET.*=\|^Feature\|^Available services' | sed 's/.* [:=] //') +EOF + +HAPROXY_VERSION=$(echo $HAPROXY_VERSION | cut -d " " -f 3) +echo "Testing with haproxy version: $HAPROXY_VERSION" + +FEATURES_PATTERN=" $FEATURES " +SERVICES_PATTERN=" $SERVICES " + +TESTRUNDATETIME="$(date '+%Y-%m-%d_%H-%M-%S')" + +mkdir -p "$TESTDIR" || exit 1 +TESTDIR=$(mktemp -d "$TESTDIR/haregtests-$TESTRUNDATETIME.XXXXXX") || exit 1 + +export TMPDIR="$TESTDIR" +export HAPROXY_PROGRAM="$HAPROXY_PROGRAM" +if [ -n "$HAPROXY_ARGS" ]; then + export HAPROXY_ARGS +fi + +echo "Target : $TARGET" +echo "Options : $FEATURES" +echo "Services : $SERVICES" + +echo "########################## Gathering tests to run ##########################" + +if [ -z "$REGTESTS" ]; then + _findtests reg-tests/ +else + for t in $REGTESTS; do + _findtests $t + done +fi + +echo "########################## Starting vtest ##########################" +echo "Testing with haproxy version: $HAPROXY_VERSION" +_vtresult=0 +if [ -n "$testlist" ]; then + if [ -n "$jobcount" ]; then + jobcount="-j $jobcount" + fi + cmd="$VTEST_PROGRAM -b $((2<<20)) -k -t 10 $keep_logs $verbose $debug $jobcount $vtestparams $testlist" + eval $cmd + _vtresult=$? +else + echo "No tests found that meet the required criteria" +fi + + +if [ $_vtresult -eq 0 ]; then + # all tests were successful, removing tempdir (the last part.) + # ignore errors is the directory is not empty or if it does not exist + rmdir "$TESTDIR" 2>/dev/null +fi + +if [ -d "${TESTDIR}" ]; then + echo "########################## Gathering results ##########################" + export TESTDIR + find "$TESTDIR" -type d -name "vtc.*" -exec sh -c 'for i; do + if [ ! -e "$i/LOG" ] ; then continue; fi + + cat <<- EOF | tee -a "$TESTDIR/failedtests.log" +$(echo "###### $(cat "$i/INFO") ######") +$(echo "## test results in: \"$i\"") +$(grep -E -- "^(----|\* diag)" "$i/LOG") +EOF + done' sh {} + +fi + +exit $_vtresult |