From ab9d1777a183fe9071c162009e15c2736ec9e4a3 Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Wed, 26 Aug 2015 09:38:39 +0100 Subject: [PATCH 1/6] Support `make UPDATE_LATEST=false publish` When publishing pre-releases via the release script we do not want to modify the `latest` tag in DockerHub - specifying UPDATE_LATEST=false causes publish to push to $WEAVE_VERSION only. Omitting the flag entirely retains the existing behaviour for backwards compatability. --- Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Makefile b/Makefile index 3d4ca10c..cbbd0f83 100644 --- a/Makefile +++ b/Makefile @@ -111,7 +111,9 @@ tests: $(COVER_EXE) $(PUBLISH): publish_%: $(IMAGES_UPTODATE) $(SUDO) docker tag -f $(DOCKERHUB_USER)/$* $(DOCKERHUB_USER)/$*:$(WEAVE_VERSION) $(SUDO) docker push $(DOCKERHUB_USER)/$*:$(WEAVE_VERSION) +ifneq ($(UPDATE_LATEST),false) $(SUDO) docker push $(DOCKERHUB_USER)/$*:latest +endif publish: $(PUBLISH) From f48a4373d14e7430fa0ca15fd0b288c3452947c4 Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Mon, 24 Aug 2015 16:08:44 +0100 Subject: [PATCH 2/6] Allow freeform version tags To support arbitrarily named pre-releases we no longer impose any restrictions on the format of the most recent annotated tag - instead we expect to find a single annotated tag pointing at HEAD of the current branch and assume this is the version to release. --- bin/release | 37 ++++++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 9 deletions(-) diff --git a/bin/release b/bin/release index 2e34a3f1..6eb13c6d 100755 --- a/bin/release +++ b/bin/release @@ -11,14 +11,33 @@ RELEASE_DESCRIPTION=${RELEASE_DESCRIPTION:-"Weaving Containers into Applications PWD=`pwd` setup() { - ## Get the new version number from the most recent tag - if ! LATEST_TAG=$(git describe --abbrev=0 --match='v*' 2>/dev/null) ; then - echo "Could not find an annotated 'v*' version tag." >&2 - exit 1 - fi + # Ensure we have exactly one annotated tag pointing at HEAD + HEAD_TAGS=$(git tag --points-at HEAD) + case $(echo $HEAD_TAGS | wc -w) in + 1) + if [ $HEAD_TAGS != "latest_release" ] ; then + LATEST_TAG=$HEAD_TAGS + else + echo "Cannot determine version - latest_release points at HEAD" >&2 + exit 1 + fi + ;; + 0) + echo "Cannot determine version - no tags point at HEAD" >&2 + exit 1 + ;; + *) + echo "Cannot determine version - multiple tags point at HEAD:" >&2 + for TAG in $HEAD_TAGS ; do + echo -e "\t$TAG" >&2 + done + exit 1 + ;; + esac + LATEST_TAG_SHA=$(git rev-parse $LATEST_TAG) LATEST_RELEASE_SHA=$(git rev-parse latest_release) - VERSION=${LATEST_TAG#v} + VERSION=${LATEST_TAG} # NB does not check that this tag is on master RELEASE_DIR=./releases/$LATEST_TAG } @@ -39,8 +58,8 @@ build() { cd $RELEASE_DIR ## Check that the top changelog entry is this version - if ! latest_changelog=$(grep -o "## Release [0-9].*" -m1 ./CHANGELOG.md) || \ - ! [ `echo "$latest_changelog" | grep -o '[0-9][^ ]*'` == "$VERSION" ]; then + if ! latest_changelog=$(grep -oP '(?<=^## Release ).*' -m1 ./CHANGELOG.md) || \ + ! [ `echo "$latest_changelog" = "$VERSION"` ]; then echo -e "\u2757 Latest changelog entry \"$latest_changelog\" does not match the release version $VERSION" >&2 exit 1 fi @@ -61,7 +80,7 @@ build() { fi ## Run tests with the distributables, including version check - v=$(./prog/weaver/weaver --version | grep -o '[0-9].*') + v=$(./prog/weaver/weaver --version | grep -oP '(?<=^weave router ).*') if ! [ "$v" == "$VERSION" ]; then echo "Version of distributable "$v" does not match release version $VERSION" >&2 exit 1 From 82f2f7b2b9076fc16d6f7df6c36c0132b28f8a62 Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Mon, 24 Aug 2015 17:42:08 +0100 Subject: [PATCH 3/6] Check for required tooling at top level Pull common checks out to top level in preparation for the introduction of an additional process step. --- bin/release | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/bin/release b/bin/release index 6eb13c6d..9cbae07c 100755 --- a/bin/release +++ b/bin/release @@ -96,13 +96,6 @@ publish() { echo "== Sanity checks" - if ! which github-release >/dev/null; then - echo "Please install git-release:" >&2 - echo -e "\tgo get github.com/aktau/github-release" >&2 - echo "and create a git token per https://github.com/aktau/github-release" >&2 - exit 1 - fi - if ! [ $(git rev-list -1 $LATEST_TAG) == $(git rev-list -1 latest_release) ]; then echo -e "\u2757 The tag latest_release does not point to the same commit as $LATEST_TAG" exit 1 @@ -196,6 +189,14 @@ usage() { echo "-- Publish the artefacts for the latest tag to GitHub and DockerHub" } +# Ensure required tooling is installed +if ! which github-release >/dev/null; then + echo "Please install git-release:" >&2 + echo -e "\tgo get github.com/aktau/github-release" >&2 + echo "and create a git token per https://github.com/aktau/github-release" >&2 + exit 1 +fi + case "$1" in build) build From b13baccbd20e1f88e1765592c62218996562288f Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Wed, 26 Aug 2015 09:38:10 +0100 Subject: [PATCH 4/6] Introduce draft step The publish stage has been split into two pieces - a draft step that creates a draft version release in Github and a publish step that publishes the draft, updates `latest_release` and pushes images to DockerHub. It is also possible to specify `--pre-release` to draft. Once published such a release will be marked with a prominent warning in GitHub; additionally we do not update `latest_release` in GitHub nor push an update to the `latest` tag in DockerHub. --- bin/release | 169 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 119 insertions(+), 50 deletions(-) diff --git a/bin/release b/bin/release index 9cbae07c..e577468f 100755 --- a/bin/release +++ b/bin/release @@ -90,17 +90,24 @@ build() { echo '** Release artefacts in' $RELEASE_DIR } -publish() { +draft() { setup + + TYPE="release" + RELEASE_ARGS="--draft" + if [ $# -ne 0 ] ; then + if [ $# -eq 1 -a "$1" = "--pre-release" ] ; then + TYPE="pre-release" + RELEASE_ARGS="$RELEASE_ARGS --pre-release" + else + usage + fi + fi + cd $PWD/$RELEASE_DIR echo "== Sanity checks" - if ! [ $(git rev-list -1 $LATEST_TAG) == $(git rev-list -1 latest_release) ]; then - echo -e "\u2757 The tag latest_release does not point to the same commit as $LATEST_TAG" - exit 1 - fi - ## Check that the tag exists by looking at github if ! curl -sSf https://api.github.com/repos/$GITHUB_USER/weave/git/tags/$LATEST_TAG_SHA >/dev/null 2>&1; then echo -e "\u2757 Tag $LATEST_TAG is not on GitHub, or is not the same as the local tag" >&2 @@ -110,19 +117,9 @@ publish() { exit 1 fi - ## Check that the 'latest_release' tag exists by looking at github - if ! curl -sSf https://api.github.com/repos/$GITHUB_USER/weave/git/tags/$LATEST_RELEASE_SHA >/dev/null 2>&1; then - echo -e "\u2757 Tag latest_release is not on GitHub, or is not the same as the local tag" >&2 - echo -e "\thttps://github.com/$GITHUB_USER/weave/tags" >&2 - echo "You may need to" >&2 - echo -e "\tgit tag -af latest_release" - echo -e "\tgit push -f git@github.com:$GITHUB_USER/weave latest_release" - exit 1 - fi - echo -e "\u2713 Tag $LATEST_TAG exists in GitHub repo $GITHUB_USER/weave" - ## Check that the version doesn't already exist by looking at github + ## Check that the version does not already exist by looking at github ## releases if github-release info --user $GITHUB_USER --repo weave --tag $LATEST_TAG >/dev/null 2>&1; then echo -e "\u2757 Release $LATEST_TAG already exists on GitHub" >&2 @@ -132,13 +129,8 @@ publish() { echo '** Sanity checks OK for publishing tag' $LATEST_TAG as $DOCKERHUB_USER/weave:$VERSION - echo "== Tagging and publishing images on docker hub as user $DOCKERHUB_USER" - make SUDO=$SUDO WEAVE_VERSION=$VERSION DOCKERHUB_USER=$DOCKERHUB_USER publish - - echo "== Creating GitHub release $RELEASE_NAME $VERSION" - # This cannot be done as a draft because of a bug in - # github-release: https://github.com/aktau/github-release/issues/7 - github-release release \ + echo "== Creating draft GitHub $TYPE $RELEASE_NAME $VERSION" + github-release release $RELEASE_ARGS \ --user $GITHUB_USER \ --repo weave \ --tag $LATEST_TAG \ @@ -152,41 +144,111 @@ publish() { --name "weave" \ --file "./weave" - echo "** Published release $RELEASE_NAME $VERSION" + echo "** Draft $TYPE $RELEASE_NAME $VERSION created at" echo -e "\thttps://github.com/$GITHUB_USER/weave/releases/$LATEST_TAG" +} - if github-release info --user $GITHUB_USER --repo weave \ - --tag latest_release >/dev/null 2>&1; then - github-release delete \ - --user $GITHUB_USER \ - --repo weave \ - --tag latest_release +publish() { + setup + cd $PWD/$RELEASE_DIR + + echo "== Detecting draft type" + # Determine whether $LATEST_TAG version in GitHub is marked as pre-release + if ! INFO=$(github-release info --user $GITHUB_USER --repo weave --tag $LATEST_TAG) ; then + # github-release prints errors to stdout https://github.com/aktau/github-release/issues/32 + echo $info >&2 + exit 1 fi - github-release release \ - --user $GITHUB_USER \ - --repo weave \ - --tag latest_release \ - --name "$RELEASE_NAME latest ($VERSION)" \ - --description "$RELEASE_DESCRIPTION" + PRERELEASE= + TICK=$(echo -e '\u2714') + # Pre-releases are signified with a unicode $TICK character ಠ_ಠ + if echo "$INFO" | grep -q "prerelease: $TICK" ; then + PRERELEASE=1 + fi - github-release upload \ - --user $GITHUB_USER \ - --repo weave \ - --tag latest_release \ - --name "weave" \ - --file "./weave" + if [ -n "$PRERELEASE" ] ; then + echo "** Pre-release draft detected" + echo "== Tagging and pushing images on docker hub as user $DOCKERHUB_USER" + make UPDATE_LATEST=false SUDO=$SUDO WEAVE_VERSION=$VERSION DOCKERHUB_USER=$DOCKERHUB_USER publish + echo "** Docker images tagged and pushed" - echo "** Published $RELEASE_NAME as latest_release at" - echo -e "\thttps://github.com/$GITHUB_USER/weave/releases/latest_release" + echo "== Publishing pre-release on GitHub" + + github-release publish \ + --user $GITHUB_USER \ + --repo weave \ + --tag $LATEST_TAG + + echo "** Pre-release $RELEASE_NAME $VERSION published at" + echo -e "\thttps://github.com/$GITHUB_USER/weave/releases/$LATEST_TAG" + else + echo "** Release draft detected" + echo "== Sanity checks" + if ! [ $(git rev-list -1 $LATEST_TAG) == $(git rev-list -1 latest_release) ]; then + echo -e "\u2757 The tag latest_release does not point to the same commit as $LATEST_TAG" + exit 1 + fi + + ## Check that the 'latest_release' tag exists by looking at github + if ! curl -sSf https://api.github.com/repos/$GITHUB_USER/weave/git/tags/$LATEST_RELEASE_SHA >/dev/null 2>&1; then + echo -e "\u2757 Tag latest_release is not on GitHub, or is not the same as the local tag" >&2 + echo -e "\thttps://github.com/$GITHUB_USER/weave/tags" >&2 + echo "You may need to" >&2 + echo -e "\tgit tag -af latest_release" + echo -e "\tgit push -f git@github.com:$GITHUB_USER/weave latest_release" + exit 1 + fi + echo '** Sanity checks OK for publishing tag' $LATEST_TAG as $DOCKERHUB_USER/weave:$VERSION + + echo "== Tagging and pushing images on docker hub as user $DOCKERHUB_USER" + make SUDO=$SUDO WEAVE_VERSION=$VERSION DOCKERHUB_USER=$DOCKERHUB_USER publish + echo "** Docker images tagged and pushed" + + echo "== Publishing release on GitHub" + + github-release publish \ + --user $GITHUB_USER \ + --repo weave \ + --tag $LATEST_TAG + + if github-release info --user $GITHUB_USER --repo weave \ + --tag latest_release >/dev/null 2>&1; then + github-release delete \ + --user $GITHUB_USER \ + --repo weave \ + --tag latest_release + fi + + github-release release \ + --user $GITHUB_USER \ + --repo weave \ + --tag latest_release \ + --name "$RELEASE_NAME latest ($VERSION)" \ + --description "$RELEASE_DESCRIPTION" + + github-release upload \ + --user $GITHUB_USER \ + --repo weave \ + --tag latest_release \ + --name "weave" \ + --file "./weave" + + echo "** Release $RELEASE_NAME $VERSION published at" + echo -e "\thttps://github.com/$GITHUB_USER/weave/releases/$LATEST_TAG" + echo -e "\thttps://github.com/$GITHUB_USER/weave/releases/latest_release" + fi } usage() { echo "Usage:" echo -e "\t./bin/release build" echo "-- Build artefacts for the latest version tag" + echo -e "\t./bin/release draft [--pre-release]" + echo "-- Create draft release with artefacts in GitHub" echo -e "\t./bin/release publish" - echo "-- Publish the artefacts for the latest tag to GitHub and DockerHub" + echo "-- Publish the GitHub release and update DockerHub" + exit 1 } # Ensure required tooling is installed @@ -197,15 +259,22 @@ if ! which github-release >/dev/null; then exit 1 fi -case "$1" in +[ $# -eq 0 ] && usage +COMMAND=$1 +shift + +case "$COMMAND" in build) - build + build "$@" + ;; + draft) + draft "$@" ;; publish) - publish + publish "$@" ;; *) - echo "Unknown command \"$1\"" + echo "Unknown command \"$COMMAND\"" usage ;; esac From 6a5df80bda7a9924c0cdc921a8d6aee0dc0f0af3 Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Fri, 28 Aug 2015 11:51:37 +0100 Subject: [PATCH 5/6] Fix latest_release hash test Obtain the version and latest_release tag commit hashes before changing into the cloned repository so that all tagging and pushing happens on the outer repository. --- bin/release | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/bin/release b/bin/release index e577468f..e7378019 100755 --- a/bin/release +++ b/bin/release @@ -36,7 +36,9 @@ setup() { esac LATEST_TAG_SHA=$(git rev-parse $LATEST_TAG) + LATEST_TAG_COMMIT_SHA=$(git rev-list -1 $LATEST_TAG) LATEST_RELEASE_SHA=$(git rev-parse latest_release) + LATEST_RELEASE_COMMIT_SHA=$(git rev-list -1 latest_release) VERSION=${LATEST_TAG} # NB does not check that this tag is on master RELEASE_DIR=./releases/$LATEST_TAG @@ -185,8 +187,10 @@ publish() { else echo "** Release draft detected" echo "== Sanity checks" - if ! [ $(git rev-list -1 $LATEST_TAG) == $(git rev-list -1 latest_release) ]; then - echo -e "\u2757 The tag latest_release does not point to the same commit as $LATEST_TAG" + if ! [ "$LATEST_TAG_COMMIT_SHA" == "$LATEST_RELEASE_COMMIT_SHA" ] ; then + echo -e "\u2757 The tag latest_release does not point to the same commit as $LATEST_TAG" >&2 + echo "You may need to" >&2 + echo -e "\tgit tag -af latest_release $LATEST_TAG" >&2 exit 1 fi @@ -195,8 +199,7 @@ publish() { echo -e "\u2757 Tag latest_release is not on GitHub, or is not the same as the local tag" >&2 echo -e "\thttps://github.com/$GITHUB_USER/weave/tags" >&2 echo "You may need to" >&2 - echo -e "\tgit tag -af latest_release" - echo -e "\tgit push -f git@github.com:$GITHUB_USER/weave latest_release" + echo -e "\tgit push -f git@github.com:$GITHUB_USER/weave latest_release" >&2 exit 1 fi echo '** Sanity checks OK for publishing tag' $LATEST_TAG as $DOCKERHUB_USER/weave:$VERSION From 5744ed8994bb5429d7a6b26961623d025c5f62f1 Mon Sep 17 00:00:00 2001 From: Adam Harrison Date: Wed, 2 Sep 2015 12:35:13 +0100 Subject: [PATCH 6/6] Document release process --- docs/release-process.md | 131 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 docs/release-process.md diff --git a/docs/release-process.md b/docs/release-process.md new file mode 100644 index 00000000..80ed163c --- /dev/null +++ b/docs/release-process.md @@ -0,0 +1,131 @@ +# Release Process +## Prerequisites + +* Up-to-date versions of `git`, `go` etc +* Install GitHub release tool `go get github.com/weaveworks/github-release` +* Create a [github token for + github-release](https://help.github.com/articles/creating-an-access-token-for-command-line-use/); +set and export `$GITHUB_TOKEN` with this value +* Update all dependencies with `make update` + +## Build Phase +### Update CHANGELOG.md + +* Checkout the branch from which you wish to release +* Choose an appropriate version tag, henceforth referred to as `$TAG`. + Mainline releases use a version number (e.g. `TAG=v2.0.0`), whereas + pre-releases get a descriptive name (e.g. `TAG=feature-preview-20150902`) +* Add a changelog entry for the new tag at the top of `CHANGELOG.md`. + The first line must be a markdown header of the form `## Release + $TAG` + +Commit the changelog update: + + git commit -m "Add release $TAG" CHANGELOG.md + +### Create Version Tag + +Next you must tag the changelog commit with `$TAG` + + git tag -a -m "Release $TAG" $TAG + +### Execute Build + +You are now ready to perform the build. If you have skipped the +previous steps (e.g. because you're doing a rebuild), you must ensure +that `HEAD` points to the tagged commit. You may then execute + + bin/release build + +This has the following effects: + +* `git tag --points-at HEAD` is used to determine `$TAG` (hence the + `HEAD` requirement) +* Your *local* repository is cloned into `releases/$TAG` +* `CHANGELOG.md` is checked to ensure it has an entry for `$TAG` +* Distributables injected with `$TAG` are built +* Tests are executed + +## Draft Phase +### Push Version Tag Upstream + +First you must push your version tag upstream, so that an associated +GitHub release may be created: + + git push git@github.com:weaveworks/weave $TAG + +N.B. if you're testing the release process, push to your fork +instead! + +### Create Draft Release + +You're now ready to draft your release notes: + + bin/release draft [--pre-release] + +This has the following effects: + +* A [release](https://help.github.com/articles/about-releases) is + created in GitHub for `$TAG`. This release is in the draft state, so + it is only visible to contributors +* The `weave` script is uploaded as an attachment to the release +* If `--pre-release` is specified, the release will have the + pre-release attribute set (this affects the way GitHub displays the + release and modifies the behaviour of the publish phase) + +Navigate to https://github.com/weaveworks/weave/releases, 'Edit' the +draft and input the release notes. When you are done make sure you +'Save draft' (and not 'Publish release'!). + +Once the release notes have passed review, proceed to the publish +phase. + +## Publish Phase +### Move/Force Push `latest_release` Tag + +This step must only be performed for mainline (non pre-release) +releases: + + git tag -af -m "Release $TAG" latest_release $TAG + git push -f git@github.com:weaveworks/weave latest_release + +The `latest_release` tag *must* point at `$TAG`, *not* at `HEAD` - +the build script will complain otherwise. + +N.B. if you're testing the release process, push to your fork +instead! + +### Publish Release & Distributable Artefacts + +You can now publish the release and upload the remaining +distributables to DockerHub: + + bin/release publish + +This has the following effects: + +* Docker images are tagged `$TAG` and pushed to DockerHub +* GitHub release moves from draft to published state + +Furthermore, if this is a mainline release (detected automatically +from the GitHub release, you do not need to specify the flag again to +the publish step) + +* Images tagged `latest` are updated on DockerHub +* Release named `latest_release` is updated on GitHub + + +## Troubleshooting + +There's a few things that can go wrong. + + * If the build is wonky, e.g., the tests don't pass, you can delete + the directory in `./releases/`, fix whatever it is, move the + version tag (which should still be only local) and have another go. + * If the DockerHub pushes fail (which sadly seems to happen a lot), + you can just run `./bin/release publish` again. + * If you need to overwrite a release you can do so by manually + deleting the GitHub version release and re-running the process. + Please note that the DockerHub `latest` images, GitHub + `latest_release` and download links may be in an inconsistent state + until the overwrite is completed.