diff --git a/project/RELEASE-PROCESS.md b/project/RELEASE-PROCESS.md index 966e06ee48..30a9805af2 100644 --- a/project/RELEASE-PROCESS.md +++ b/project/RELEASE-PROCESS.md @@ -3,20 +3,20 @@ Building a Compose release ## To get started with a new release -1. Create a `bump-$VERSION` branch off master: +Create a branch, update version, and add release notes by running `make-branch` - git checkout -b bump-$VERSION master + ./script/release/make-branch $VERSION [$BASE_VERSION] -2. Merge in the `release` branch on the upstream repo, discarding its tree entirely: +`$BASE_VERSION` will default to master. Use the last version tag for a bug fix +release. - git fetch origin - git merge --strategy=ours origin/release +As part of this script you'll be asked to: -3. Update the version in `docs/install.md` and `compose/__init__.py`. +1. Update the version in `docs/install.md` and `compose/__init__.py`. If the next release will be an RC, append `rcN`, e.g. `1.4.0rc1`. -4. Write release notes in `CHANGES.md`. +2. Write release notes in `CHANGES.md`. Almost every feature enhancement should be mentioned, with the most visible/exciting ones first. Use descriptive sentences and give context where appropriate. @@ -24,72 +24,44 @@ Building a Compose release Improvements to the code are not worth mentioning. -5. Add a bump commit: - - git commit -am "Bump $VERSION" - -6. Push the bump branch to your fork: - - git push --set-upstream $USERNAME bump-$VERSION - -7. Open a PR from the bump branch against the `release` branch on the upstream repo, **not** against master. ## When a PR is merged into master that we want in the release -1. Check out the bump branch: +1. Check out the bump branch and run the cherry pick script git checkout bump-$VERSION + ./script/release/cherry-pick-pr $PR_NUMBER -2. Cherry-pick the merge commit, fixing any conflicts if necessary: - - git cherry-pick -xm1 $MERGE_COMMIT_HASH - -3. Add a signoff (it’s missing from merge commits): - - git commit --amend --signoff - -4. Move the bump commit back to the tip of the branch: - - git rebase --interactive $PARENT_OF_BUMP_COMMIT - -5. Force-push the bump branch to your fork: +2. When you are done cherry-picking branches move the bump version commit to HEAD + ./script/release/rebase-bump-commit git push --force $USERNAME bump-$VERSION + ## To release a version (whether RC or stable) -1. Check that CI is passing on the bump PR. - -2. Check out the bump branch: +Check out the bump branch and run the `build-binary` script git checkout bump-$VERSION + ./script/release/build-binary -3. Build the Linux binary: +When prompted build the non-linux binaries and test them. - script/build-linux - -4. Build the Mac binary in a Mountain Lion VM: +1. Build the Mac binary in a Mountain Lion VM: script/prepare-osx script/build-osx -5. Test the binaries and/or get some other people to test them. +2. Download the windows binary from AppVeyor -6. Create a tag: + https://ci.appveyor.com/project/docker/compose/build//artifacts - TAG=$VERSION # or $VERSION-rcN, if it's an RC - git tag $TAG +3. Draft a release from the tag on GitHub (the script will open the window for + you) -7. Push the tag to the upstream repo: + In the "Tag version" dropdown, select the tag you just pushed. - git push git@github.com:docker/compose.git $TAG - -8. Draft a release from the tag on GitHub. - - - Go to https://github.com/docker/compose/releases and click "Draft a new release". - - In the "Tag version" dropdown, select the tag you just pushed. - -9. Paste in installation instructions and release notes. Here's an example - change the Compose version and Docker version as appropriate: +4. Paste in installation instructions and release notes. Here's an example - change the Compose version and Docker version as appropriate: Firstly, note that Compose 1.5.0 requires Docker 1.8.0 or later. @@ -108,24 +80,19 @@ Building a Compose release ...release notes go here... -10. Attach the binaries. +5. Attach the binaries. -11. Don’t publish it just yet! +6. If everything looks good, it's time to push the release. -12. Upload the latest version to PyPi: - python setup.py sdist upload + ./script/release/push-release -13. Check that the pip package installs and runs (best done in a virtualenv): - pip install -U docker-compose==$TAG - docker-compose version +7. Publish the release on GitHub. -14. Publish the release on GitHub. +8. Check that both binaries download (following the install instructions) and run. -15. Check that both binaries download (following the install instructions) and run. - -16. Email maintainers@dockerproject.org and engineering@docker.com about the new release. +9. Email maintainers@dockerproject.org and engineering@docker.com about the new release. ## If it’s a stable release (not an RC) diff --git a/script/release/build-binaries b/script/release/build-binaries new file mode 100755 index 0000000000..9f65b45d27 --- /dev/null +++ b/script/release/build-binaries @@ -0,0 +1,21 @@ +#!/bin/bash +# +# Build the release binaries +# + +. "$(dirname "${BASH_SOURCE[0]}")/utils.sh" + +REPO=docker/compose + +# Build the binaries +script/clean +script/build-linux +# TODO: build osx binary +# script/prepare-osx +# script/build-osx +# TODO: build or fetch the windows binary +echo "You need to build the osx/windows binaries, that step is not automated yet." + +echo "Create a github release" +# TODO: script more of this https://developer.github.com/v3/repos/releases/ +browser https://github.com/$REPO/releases/new diff --git a/script/release/cherry-pick-pr b/script/release/cherry-pick-pr new file mode 100755 index 0000000000..604600872c --- /dev/null +++ b/script/release/cherry-pick-pr @@ -0,0 +1,34 @@ +#!/bin/bash +# +# Cherry-pick a PR into the release branch +# + +set -e +set -o pipefail + + +function usage() { + >&2 cat << EOM +Cherry-pick commits from a github pull request. + +Usage: + + $0 +EOM + exit 1 +} + +[ -n "$1" ] || usage + +if [ -z "$(command -v hub 2> /dev/null)" ]; then + >&2 echo "$0 requires https://hub.github.com/." + >&2 echo "Please install it and ake sure it is available on your \$PATH." + exit 2 +fi + + +REPO=docker/compose +GITHUB=https://github.com/$REPO/pull +PR=$1 +url="$GITHUB/$PR" +hub am -3 $url diff --git a/script/release/make-branch b/script/release/make-branch new file mode 100755 index 0000000000..66ed6bbf35 --- /dev/null +++ b/script/release/make-branch @@ -0,0 +1,96 @@ +#!/bin/bash +# +# Prepare a new release branch +# + +. "$(dirname "${BASH_SOURCE[0]}")/utils.sh" + +function usage() { + >&2 cat << EOM +Create a new release branch 'release-' + +Usage: + + $0 [] + +Options: + + version version string for the release (ex: 1.6.0) + base_version branch or tag to start from. Defaults to master. For + bug-fix releases use the previous stage release tag. + +EOM + exit 1 +} + + +[ -n "$1" ] || usage +VERSION=$1 +BRANCH=bump-$VERSION +REPO=docker/compose +GITHUB_REPO=git@github.com:$REPO + +if [ -z "$2" ]; then + BASE_VERSION="master" +else + BASE_VERSION=$2 +fi + + +DEFAULT_REMOTE=release +REMOTE="$(find_remote "$GITHUB_REPO")" +# If we don't have a docker origin add one +if [ -z "$REMOTE" ]; then + echo "Creating $DEFAULT_REMOTE remote" + git remote add ${DEFAULT_REMOTE} ${GITHUB_REPO} +fi + +# handle the difference between a branch and a tag +if [ -z "$(git name-rev $BASE_VERSION | grep tags)" ]; then + BASE_VERSION=$REMOTE/$BASE_VERSION +fi + +echo "Creating a release branch $VERSION from $BASE_VERSION" +read -n1 -r -p "Continue? (ctrl+c to cancel)" +git fetch $REMOTE -p +git checkout -b $BRANCH $BASE_VERSION + + +# Store the release version for this branch in git, so that other release +# scripts can use it +git config "branch.${BRANCH}.release" $VERSION + + +echo "Update versions in docs/install.md and compose/__init__.py" +$EDITOR docs/install.md +$EDITOR compose/__init__.py + + +echo "Write release notes in CHANGELOG.md" +browser "https://github.com/docker/compose/issues?q=milestone%3A$VERSION+is%3Aclosed" +$EDITOR CHANGELOG.md + + +git diff +echo "Verify changes before commit. Exit the shell to commit changes" +$SHELL || true +git commit -a -m "Bump $VERSION" --signoff --no-verify + + +echo "Push branch to user remote" +GITHUB_USER=$USER +USER_REMOTE="$(find_remote $GITHUB_USER/compose)" +if [ -z "$USER_REMOTE" ]; then + echo "No user remote found for $GITHUB_USER" + read -r -p "Enter the name of your github user: " GITHUB_USER + # assumes there is already a user remote somewhere + USER_REMOTE=$(find_remote $GITHUB_USER/compose) +fi +if [ -z "$USER_REMOTE" ]; then + >&2 echo "No user remote found. You need to 'git push' your branch." + exit 2 +fi + + +git push $USER_REMOTE +browser https://github.com/$REPO/compare/docker:release...$GITHUB_USER:$BRANCH?expand=1 diff --git a/script/release/push-release b/script/release/push-release new file mode 100755 index 0000000000..7c44866671 --- /dev/null +++ b/script/release/push-release @@ -0,0 +1,63 @@ +#!/bin/bash +# +# Create the official release +# + +. "$(dirname "${BASH_SOURCE[0]}")/utils.sh" + +function usage() { + >&2 cat << EOM +Publish a release by building all artifacts and pushing them. + +This script requires that 'git config branch.${BRANCH}.release' is set to the +release version for the release branch. + +EOM + exit 1 +} + +BRANCH="$(git rev-parse --abbrev-ref HEAD)" +VERSION="$(git config "branch.${BRANCH}.release")" || usage + +if [ -z "$(command -v jq 2> /dev/null)" ]; then + >&2 echo "$0 requires https://stedolan.github.io/jq/" + >&2 echo "Please install it and ake sure it is available on your \$PATH." + exit 2 +fi + + +API=https://api.github.com/repos +REPO=docker/compose +GITHUB_REPO=git@github.com:$REPO + +# Check the build status is green +sha=$(git rev-parse HEAD) +url=$API/$REPO/statuses/$sha +build_status=$(curl -s $url | jq -r '.[0].state') +if [[ "$build_status" != "success" ]]; then + >&2 echo "Build status is $build_status, but it should be success." + exit -1 +fi + +echo "Tagging the release as $VERSION" +git tag $VERSION +git push $GITHUB_REPO $VERSION + +echo "Uploading sdist to pypi" +python setup.py sdist + +if [ "$(command -v twine 2> /dev/null)" ]; then + twine upload ./dist/docker-compose-${VERSION}.tar.gz +else + python setup.py upload +fi + +echo "Testing pip package" +virtualenv venv-test +source venv-test/bin/activate +pip install docker-compose==$VERSION +docker-compose version +deactivate + +echo "Now publish the github release, and test the downloads." +echo "Email maintainers@dockerproject.org and engineering@docker.com about the new release." diff --git a/script/release/rebase-bump-commit b/script/release/rebase-bump-commit new file mode 100755 index 0000000000..14ad22a982 --- /dev/null +++ b/script/release/rebase-bump-commit @@ -0,0 +1,38 @@ +#!/bin/bash +# +# Move the "bump to " commit to the HEAD of the branch +# + +. "$(dirname "${BASH_SOURCE[0]}")/utils.sh" + +function usage() { + >&2 cat << EOM +Move the "bump to " commit to the HEAD of the branch + +This script requires that 'git config branch.${BRANCH}.release' is set to the +release version for the release branch. + +EOM + exit 1 +} + + +BRANCH="$(git rev-parse --abbrev-ref HEAD)" +VERSION="$(git config "branch.${BRANCH}.release")" || usage + + +COMMIT_MSG="Bump $VERSION" +sha="$(git log --grep "$COMMIT_MSG" --format="%H")" +if [ -z "$sha" ]; then + >&2 echo "No commit with message \"$COMMIT_MSG\"" + exit 2 +fi +if [[ "$sha" == "$(git rev-parse HEAD)" ]]; then + >&2 echo "Bump commit already at HEAD" + exit 0 +fi + +commits=$(git log --format="%H" "$sha..HEAD" | wc -l) + +git rebase --onto $sha~1 HEAD~$commits $BRANCH +git cherry-pick $sha diff --git a/script/release/utils.sh b/script/release/utils.sh new file mode 100644 index 0000000000..b4e5a2e6a0 --- /dev/null +++ b/script/release/utils.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# +# Util functions for release scritps +# + +set -e +set -o pipefail + + +function browser() { + local url=$1 + xdg-open $url || open $url +} + + +function find_remote() { + local url=$1 + for remote in $(git remote); do + git config --get remote.${remote}.url | grep $url > /dev/null && echo -n $remote + done + # Always return true, extra remotes cause it to return false + true +}