From 30608dfc835fa98a358c4a46139894b41a6f3752 Mon Sep 17 00:00:00 2001 From: Isaac Hollander McCreery Date: Fri, 23 Oct 2015 18:04:12 -0700 Subject: [PATCH 01/19] release.sh WIP --- build/mark-new-version.sh | 153 ------------------- build/versionize-docs.sh | 2 +- release/release.sh | 306 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 307 insertions(+), 154 deletions(-) delete mode 100755 build/mark-new-version.sh create mode 100755 release/release.sh diff --git a/build/mark-new-version.sh b/build/mark-new-version.sh deleted file mode 100755 index c573d62e2b..0000000000 --- a/build/mark-new-version.sh +++ /dev/null @@ -1,153 +0,0 @@ -#!/bin/bash - -# Copyright 2014 The Kubernetes Authors All rights reserved. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -# Bumps the version number by creating a couple of commits. - -set -o errexit -set -o nounset -set -o pipefail - -if [ "$#" -ne 1 ]; then - echo "Usage: ${0} " - exit 1 -fi - -KUBE_ROOT=$(dirname "${BASH_SOURCE}")/.. - -NEW_VERSION=${1-} - -fetch_url=$(git remote -v | grep kubernetes/kubernetes.git | grep fetch | awk '{ print $2 }') -if ! push_url=$(git remote -v | grep kubernetes/kubernetes.git | grep push | awk '{ print $2 }'); then - push_url="https://github.com/kubernetes/kubernetes.git" -fi -fetch_remote=$(git remote -v | grep kubernetes/kubernetes.git | grep fetch | awk '{ print $1 }') - -VERSION_REGEX="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$" -[[ ${NEW_VERSION} =~ $VERSION_REGEX ]] || { - echo "!!! You must specify the version in the form of '$VERSION_REGEX'" >&2 - exit 1 -} - -VERSION_MAJOR="${BASH_REMATCH[1]}" -VERSION_MINOR="${BASH_REMATCH[2]}" -VERSION_PATCH="${BASH_REMATCH[3]}" - -if ! git diff HEAD --quiet; then - echo "!!! You must not have any uncommitted changes when running this command" - exit 1 -fi - -if ! git diff-files --quiet pkg/version/base.go; then - echo "!!! You have changes in 'pkg/version/base.go' already." - exit 1 -fi - -release_branch="release-${VERSION_MAJOR}.${VERSION_MINOR}" -current_branch=$(git rev-parse --abbrev-ref HEAD) -head_commit=$(git rev-parse --short HEAD) - -if [[ "${VERSION_PATCH}" != "0" ]]; then - # sorry, no going back in time, pull latest from upstream - git remote update > /dev/null 2>&1 - - if git ls-remote --tags --exit-code ${fetch_url} refs/tags/${NEW_VERSION} > /dev/null; then - echo "!!! You are trying to tag ${NEW_VERSION} but it already exists. Stop it!" - exit 1 - fi - - last_version="v${VERSION_MAJOR}.${VERSION_MINOR}.$((VERSION_PATCH-1))" - if ! git ls-remote --tags --exit-code ${fetch_url} refs/tags/${last_version} > /dev/null; then - echo "!!! You are trying to tag ${NEW_VERSION} but ${last_version} doesn't even exist!" - exit 1 - fi - - # this is rather magic. This checks that HEAD is a descendant of the github branch release-x.y - branches=$(git branch --contains $(git ls-remote --heads ${fetch_url} refs/heads/${release_branch} | cut -f1) ${current_branch}) - if [[ $? -ne 0 ]]; then - echo "!!! git failed, I dunno...." - exit 1 - fi - - if [[ ${branches} != "* ${current_branch}" ]]; then - echo "!!! You are trying to tag to an existing minor release but branch: ${release_branch} is not an ancestor of ${current_branch}" - exit 1 - fi -fi - -SED=sed -if which gsed &>/dev/null; then - SED=gsed -fi -if ! ($SED --version 2>&1 | grep -q GNU); then - echo "!!! GNU sed is required. If on OS X, use 'brew install gnu-sed'." -fi - -echo "+++ Running ./versionize-docs" -# Links in docs should always point to the release branch. -${KUBE_ROOT}/build/versionize-docs.sh ${release_branch} -git commit -am "Versioning docs and examples to ${release_branch}" - -VERSION_FILE="${KUBE_ROOT}/pkg/version/base.go" - -GIT_MINOR="${VERSION_MINOR}.${VERSION_PATCH}" -echo "+++ Updating to ${NEW_VERSION}" -$SED -ri -e "s/gitMajor\s+string = \"[^\"]*\"/gitMajor string = \"${VERSION_MAJOR}\"/" "${VERSION_FILE}" -$SED -ri -e "s/gitMinor\s+string = \"[^\"]*\"/gitMinor string = \"${GIT_MINOR}\"/" "${VERSION_FILE}" -$SED -ri -e "s/gitVersion\s+string = \"[^\"]*\"/gitVersion string = \"$NEW_VERSION-${release_branch}+\$Format:%h\$\"/" "${VERSION_FILE}" -gofmt -s -w "${VERSION_FILE}" - -echo "+++ Committing version change" -git add "${VERSION_FILE}" -git commit -m "Kubernetes version ${NEW_VERSION}" - -echo "+++ Tagging version" -git tag -a -m "Kubernetes version ${NEW_VERSION}" "${NEW_VERSION}" -# We have to sleep for a bit so that the timestamp of the beta tag is after the -# timestamp of the release version, so that future commits are described as -# beta, and not release versions. -echo "+++ Waiting for 5 seconds to ensure timestamps are different before continuing" -sleep 5 -echo "+++ Tagging beta tag" -declare -r beta_ver="v${VERSION_MAJOR}.${VERSION_MINOR}.$((${VERSION_PATCH}+1))-beta" -git tag -a -m "Kubernetes version ${beta_ver}" "${beta_ver}" -newtag=$(git rev-parse --short HEAD) - -if [[ "${VERSION_PATCH}" == "0" ]]; then - declare -r alpha_ver="v${VERSION_MAJOR}.$((${VERSION_MINOR}+1)).0-alpha.0" - git tag -a -m "Kubernetes pre-release branch ${alpha_ver}" "${alpha_ver}" "${head_commit}" -fi - -echo "" -echo "Success you must now:" -echo "" -echo "- Push the tags:" -echo " git push ${push_url} ${NEW_VERSION}" -echo " git push ${push_url} ${beta_ver}" - -if [[ "${VERSION_PATCH}" == "0" ]]; then - echo "- Push the alpha tag:" - echo " git push ${push_url} ${alpha_ver}" - echo "- Push the new release branch:" - echo " git push ${push_url} ${current_branch}:${release_branch}" - echo "- DO NOTHING TO MASTER. You were done with master when you pushed the alpha tag." -else - echo "- Send branch: ${current_branch} as a PR to ${release_branch} <-- NOTE THIS" - echo "- In the contents of the PR, include the PRs in the release:" - echo " hack/cherry_pick_list.sh ${current_branch}^1" - echo " This helps cross-link PRs to patch releases they're part of in GitHub." - echo "- Have someone review the PR. This is a mechanical review to ensure it contains" - echo " the ${NEW_VERSION} commit, which was tagged at ${newtag}." -fi diff --git a/build/versionize-docs.sh b/build/versionize-docs.sh index 8eb4c0aaff..d102b6b67b 100755 --- a/build/versionize-docs.sh +++ b/build/versionize-docs.sh @@ -45,7 +45,7 @@ if ! ($SED --version 2>&1 | grep -q GNU); then exit 1 fi -echo "+++ Versioning documentation and examples" +echo "+++ Versioning documentation and examples at ${NEW_VERSION}" # Update the docs to match this version. HTML_PREVIEW_PREFIX="https://htmlpreview.github.io/\?https://github.com/kubernetes/kubernetes" diff --git a/release/release.sh b/release/release.sh new file mode 100755 index 0000000000..452fd46e40 --- /dev/null +++ b/release/release.sh @@ -0,0 +1,306 @@ +#!/bin/bash + +# Copyright 2014 The Kubernetes Authors All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# TODO What does this script do? + +set -o errexit +set -o nounset +set -o pipefail + +# TODO Audit echos to make sure they're all consistent. +# TODO Refactor to remove globals? + +function main() { + if [ "$#" -gt 3 ]; then + usage + exit 1 + fi + + declare -r NEW_VERSION=${1-} + # TODO(ihmccreery) Stop calling it githash; it's not a githash. + declare -r GITHASH=${2-} + DRY_RUN=true + if [[ "${3-}" == "--no-dry-run" ]]; then + DRY_RUN=false + else + echo "!!! THIS IS A DRY RUN" + fi + + declare -r ALPHA_VERSION_REGEX="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.0-alpha\\.([1-9][0-9]*)$" + declare -r OFFICIAL_VERSION_REGEX="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$" + declare -r SERIES_VERSION_REGEX="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$" + if [[ "${NEW_VERSION}" =~ $ALPHA_VERSION_REGEX ]]; then + RELEASE_TYPE='alpha' + VERSION_MAJOR="${BASH_REMATCH[1]}" + VERSION_MINOR="${BASH_REMATCH[2]}" + VERSION_ALPHA_REV="${BASH_REMATCH[3]}" + ANCESTOR="v${VERSION_MAJOR}.${VERSION_MINOR}.0-alpha.$((VERSION_ALPHA_REV-1))" + elif [[ "${NEW_VERSION}" =~ $OFFICIAL_VERSION_REGEX ]]; then + RELEASE_TYPE='official' + VERSION_MAJOR="${BASH_REMATCH[1]}" + VERSION_MINOR="${BASH_REMATCH[2]}" + VERSION_PATCH="${BASH_REMATCH[3]}" + ANCESTOR="${NEW_VERSION}-beta" + RELEASE_BRANCH="release-${VERSION_MAJOR}.${VERSION_MINOR}" + elif [[ "${NEW_VERSION}" =~ $SERIES_VERSION_REGEX ]]; then + RELEASE_TYPE='series' + VERSION_MAJOR="${BASH_REMATCH[1]}" + VERSION_MINOR="${BASH_REMATCH[2]}" + # NOTE: We check the second alpha version, ...-alpha.1, because ...-alpha.0 + # is the branch point for the previous release cycle, so could provide a + # false positive if we accidentally try to release off of the old release + # branch. + ANCESTOR="v${VERSION_MAJOR}.${VERSION_MINOR}.0-alpha.1" + RELEASE_BRANCH="release-${VERSION_MAJOR}.${VERSION_MINOR}" + else + usage + echo + echo "!!! You specified an invalid version '${NEW_VERSION}'." + exit 1 + fi + + # Get the git commit from the githash and verify it + declare -r GIT_COMMIT_REGEX="^[0-9a-f]{7}$" + declare -r GIT_COMMIT=$(echo "${GITHASH}" | awk -F'+' '{print $2}' | head -c7) + if ! [[ "${GIT_COMMIT}" =~ $GIT_COMMIT_REGEX ]]; then + usage + echo + echo "!!! You specified an invalid githash '${GITHASH}'." + echo "!!! Tried to extract commit, got ${GIT_COMMIT}." + exit 1 + fi + echo "Doing ${RELEASE_TYPE} release '${NEW_VERSION}'." + + # Set the default umask for the release. This ensures consistency + # across our release builds. + # + # TODO(ihmccreery): This should be in our build process, not our release + # process. + declare -r RELEASE_UMASK=${RELEASE_UMASK:-022} + umask "${RELEASE_UMASK}" + + declare -r GITHUB="https://github.com/kubernetes/kubernetes.git" + declare -r DIR="/tmp/kubernetes-${RELEASE_TYPE}-release-${NEW_VERSION}-$(date +%s)" + echo "Cloning from '${GITHUB}'..." + git clone "${GITHUB}" "${DIR}" + + # !!! REMINDER !!! + # + # Past this point, you are dealing with a different clone of the repo at some + # version. Don't assume you're executing code from the same repo as this script + # is running in. This is a version agnostic process. + pushd "${DIR}" + + if [[ "${RELEASE_TYPE}" == 'alpha' ]]; then + git checkout "${GIT_COMMIT}" + verify-at-git-commit + verify-ancestor + + alpha-release "${NEW_VERSION}" + elif [[ "${RELEASE_TYPE}" == 'official' ]]; then + declare -r RELEASE_BRANCH="release-${VERSION_MAJOR}.${VERSION_MINOR}" + declare -r BETA_VERSION="v${VERSION_MAJOR}.${VERSION_MINOR}.$((${VERSION_PATCH}+1))-beta" + + git checkout "${RELEASE_BRANCH}" + verify-at-git-commit + # TODO uncomment this once we've pushed v1.1.1-beta + #verify-ancestor + + official-release "${NEW_VERSION}" + beta-release "${BETA_VERSION}" + else # [[ "${RELEASE_TYPE}" == 'series' ]] + declare -r RELEASE_BRANCH="release-${VERSION_MAJOR}.${VERSION_MINOR}" + declare -r ALPHA_VERSION="v${VERSION_MAJOR}.$((${VERSION_MINOR}+1)).0-alpha.0" + declare -r BETA_VERSION="v${VERSION_MAJOR}.${VERSION_MINOR}.0-beta" + + git checkout "${GIT_COMMIT}" + verify-at-git-commit + verify-ancestor + + # TODO (Fix versioning.md if you don't do this.) We maybe could actually do + # the alpha rev (in a series release) at HEAD, and patch the version/base.go + # logic then. We'd then have some part of the tree between the branch of + # vX.Y series and the vX.(Y+1).0-alpha.0 tag, but I don't think that's a + # problem. + alpha-release "${ALPHA_VERSION}" + + echo "Branching ${RELEASE_BRANCH}." + git checkout -b "${RELEASE_BRANCH}" + + beta-release "${BETA_VERSION}" + fi + + cleanup +} + +function usage() { + echo "Usage: ${0} [--no-dry-run]" + echo + echo "See docs/devel/releasing.md for more info." +} + +function alpha-release() { + local -r alpha_version="${1}" + + echo "Doing an alpha release of ${alpha_version}." + + echo "Tagging ${alpha_version} at $(git rev-parse --short HEAD)." + git tag -a -m "Kubernetes pre-release ${alpha_version}" "${alpha_version}" + git-push "${alpha_version}" + build + # TODO prompt for GitHub bits + echo "FAKE prompt GitHub bits for ${alpha_version}" +} + +function beta-release() { + local -r beta_version="${1}" + + echo "Doing a beta release of ${beta_version}." + + # TODO We need to rev something so that we have a separate commit on the + # release-X.Y branch, since we don't want master to pick up with beta tag. + # TODO rev-docs and/or version? + versionize-docs-and-commit + rev-version-and-commit + + echo "Tagging ${beta_version} at $(git rev-parse --short HEAD)." + git tag -a -m "Kubernetes pre-release ${beta_version}" "${beta_version}" + git-push "${beta_version}" + build + # TODO prompt for GitHub bits + echo "FAKE prompt GitHub bits for ${beta_version}" +} + +function official-release() { + local -r official_version="${1}" + + echo "Doing an official release of ${official_version}." + + # TODO rev-docs and/or version? + versionize-docs-and-commit + rev-version-and-commit + + echo "Tagging ${official_version} at $(git rev-parse --short HEAD)." + git tag -a -m "Kubernetes release ${official_version}" "${official_version}" + git-push "${official_version}" + build + # TODO prompt for GitHub bits + echo "FAKE prompt GitHub bits for ${official_version}" +} + +function verify-at-git-commit() { + echo "Verifying we are at ${GIT_COMMIT}." + if [[ $(git rev-parse --short HEAD) != ${GIT_COMMIT} ]]; then + echo "!!! We are not at commit ${GIT_COMMIT}!" + cleanup + exit 1 + fi +} + +function verify-ancestor() { + # Check to make sure the/a previous version is an ancestor. + echo "Checking that previous version '${ANCESTOR}' is an ancestor." + if ! git merge-base --is-ancestor "${ANCESTOR}" HEAD; then + echo "!!! Previous version '${ANCESTOR}' is not an ancestor!" + cleanup + exit 1 + fi +} + +function git-push() { + if ${DRY_RUN}; then + echo "FAKE git push "$@"" + else + echo "OH NO!!! YOU'RE NOT REALLY IN DRY_RUN! git push "$@"" + echo "You don't really want to push, do you?" + # git push "$@" + fi +} + +# TODO(ihmccreery): Review and fix this function. +function versionize-docs-and-commit() { + echo "FAKE versionize-docs-and-commit" + # # NOTE: This is using versionize-docs.sh at the release point. + # ./build/versionize-docs.sh ${NEW_VERSION} + # git commit -am "Versioning docs and examples for ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}" +} + +# TODO(ihmccreery): Review and fix this function. +function rev-version-and-commit() { + echo "FAKE rev-version-and-commit" + # SED=sed + # if which gsed &>/dev/null; then + # SED=gsed + # fi + # if ! ($SED --version 2>&1 | grep -q GNU); then + # echo "!!! GNU sed is required. If on OS X, use 'brew install gnu-sed'." + # cleanup + # exit 1 + # fi + + # VERSION_FILE="./pkg/version/base.go" + + # GIT_MINOR="${VERSION_MINOR}.${VERSION_PATCH}" + # echo "+++ Updating to ${NEW_VERSION}" + # $SED -ri -e "s/gitMajor\s+string = \"[^\"]*\"/gitMajor string = \"${VERSION_MAJOR}\"/" "${VERSION_FILE}" + # $SED -ri -e "s/gitMinor\s+string = \"[^\"]*\"/gitMinor string = \"${GIT_MINOR}\"/" "${VERSION_FILE}" + # $SED -ri -e "s/gitVersion\s+string = \"[^\"]*\"/gitVersion string = \"$NEW_VERSION-${release_branch}+\$Format:%h\$\"/" "${VERSION_FILE}" + # gofmt -s -w "${VERSION_FILE}" + + # echo "+++ Committing version change" + # git add "${VERSION_FILE}" + # git commit -m "Kubernetes version ${NEW_VERSION}" +} + +# TODO What's in this step? +function build() { + echo "FAKE build" + # TODO Do we need to publish the build to GCS? +} + +function cleanup() { + if ${DRY_RUN}; then + echo "Dry run:" + echo " pushd ${DIR}" + echo "to have a look around." + else + popd + fi +} + +main "$@" + +# echo "" +# echo "Success you must now:" +# echo "" +# echo "- Push the tags:" +# echo " git push ${push_url} ${NEW_VERSION}" +# echo " git push ${push_url} ${beta_ver}" +# +# if [[ "${VERSION_PATCH}" == "0" ]]; then +# echo "- Push the alpha tag:" +# echo " git push ${push_url} ${alpha_ver}" +# echo "- Push the new release branch:" +# echo " git push ${push_url} ${current_branch}:${release_branch}" +# echo "- DO NOTHING TO MASTER. You were done with master when you pushed the alpha tag." +# else +# echo "- Send branch: ${current_branch} as a PR to ${release_branch} <-- NOTE THIS" +# echo "- In the contents of the PR, include the PRs in the release:" +# echo " hack/cherry_pick_list.sh ${current_branch}^1" +# echo " This helps cross-link PRs to patch releases they're part of in GitHub." +# echo "- Have someone review the PR. This is a mechanical review to ensure it contains" +# echo " the ${NEW_VERSION} commit, which was tagged at ${newtag}." +# fi From 7215f2c4ec463a841bcd020d2a0b80fc97466c59 Mon Sep 17 00:00:00 2001 From: Isaac Hollander McCreery Date: Mon, 26 Oct 2015 17:31:41 -0700 Subject: [PATCH 02/19] release/release.sh WIP --- release/release.sh | 202 ++++++++++++++++++++++----------------------- 1 file changed, 98 insertions(+), 104 deletions(-) diff --git a/release/release.sh b/release/release.sh index 452fd46e40..e9be093c66 100755 --- a/release/release.sh +++ b/release/release.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Copyright 2014 The Kubernetes Authors All rights reserved. +# Copyright 2015 The Kubernetes Authors All rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -14,136 +14,127 @@ # See the License for the specific language governing permissions and # limitations under the License. -# TODO What does this script do? +# This script automates the release processes for all pre-releases and official +# releases for Kubernetes. See docs/devel/releasing.md for more info. set -o errexit set -o nounset set -o pipefail # TODO Audit echos to make sure they're all consistent. -# TODO Refactor to remove globals? +# Sets global DRY_RUN function main() { - if [ "$#" -gt 3 ]; then + # Parse arguments + if [[ "$#" -ne 2 && "$#" -ne 3 ]]; then usage exit 1 fi - - declare -r NEW_VERSION=${1-} + local -r new_version=${1-} # TODO(ihmccreery) Stop calling it githash; it's not a githash. - declare -r GITHASH=${2-} + local -r githash=${2-} DRY_RUN=true if [[ "${3-}" == "--no-dry-run" ]]; then DRY_RUN=false else - echo "!!! THIS IS A DRY RUN" + echo "THIS IS A DRY RUN" fi - declare -r ALPHA_VERSION_REGEX="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.0-alpha\\.([1-9][0-9]*)$" - declare -r OFFICIAL_VERSION_REGEX="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$" - declare -r SERIES_VERSION_REGEX="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$" - if [[ "${NEW_VERSION}" =~ $ALPHA_VERSION_REGEX ]]; then - RELEASE_TYPE='alpha' - VERSION_MAJOR="${BASH_REMATCH[1]}" - VERSION_MINOR="${BASH_REMATCH[2]}" - VERSION_ALPHA_REV="${BASH_REMATCH[3]}" - ANCESTOR="v${VERSION_MAJOR}.${VERSION_MINOR}.0-alpha.$((VERSION_ALPHA_REV-1))" - elif [[ "${NEW_VERSION}" =~ $OFFICIAL_VERSION_REGEX ]]; then - RELEASE_TYPE='official' - VERSION_MAJOR="${BASH_REMATCH[1]}" - VERSION_MINOR="${BASH_REMATCH[2]}" - VERSION_PATCH="${BASH_REMATCH[3]}" - ANCESTOR="${NEW_VERSION}-beta" - RELEASE_BRANCH="release-${VERSION_MAJOR}.${VERSION_MINOR}" - elif [[ "${NEW_VERSION}" =~ $SERIES_VERSION_REGEX ]]; then - RELEASE_TYPE='series' - VERSION_MAJOR="${BASH_REMATCH[1]}" - VERSION_MINOR="${BASH_REMATCH[2]}" - # NOTE: We check the second alpha version, ...-alpha.1, because ...-alpha.0 - # is the branch point for the previous release cycle, so could provide a - # false positive if we accidentally try to release off of the old release - # branch. - ANCESTOR="v${VERSION_MAJOR}.${VERSION_MINOR}.0-alpha.1" - RELEASE_BRANCH="release-${VERSION_MAJOR}.${VERSION_MINOR}" + # Get and verify version info + local -r alpha_version_regex="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.0-alpha\\.([1-9][0-9]*)$" + local -r official_version_regex="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$" + local -r series_version_regex="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$" + if [[ "${new_version}" =~ $alpha_version_regex ]]; then + local -r release_type='alpha' + local -r version_major="${BASH_REMATCH[1]}" + local -r version_minor="${BASH_REMATCH[2]}" + local -r version_alpha_rev="${BASH_REMATCH[3]}" + elif [[ "${new_version}" =~ $official_version_regex ]]; then + local -r release_type='official' + local -r version_major="${BASH_REMATCH[1]}" + local -r version_minor="${BASH_REMATCH[2]}" + local -r version_patch="${BASH_REMATCH[3]}" + elif [[ "${new_version}" =~ $series_version_regex ]]; then + local -r release_type='series' + local -r version_major="${BASH_REMATCH[1]}" + local -r version_minor="${BASH_REMATCH[2]}" else usage echo - echo "!!! You specified an invalid version '${NEW_VERSION}'." + echo "!!! You specified an invalid version '${new_version}'." exit 1 fi # Get the git commit from the githash and verify it - declare -r GIT_COMMIT_REGEX="^[0-9a-f]{7}$" - declare -r GIT_COMMIT=$(echo "${GITHASH}" | awk -F'+' '{print $2}' | head -c7) - if ! [[ "${GIT_COMMIT}" =~ $GIT_COMMIT_REGEX ]]; then + local -r git_commit_regex="^[0-9a-f]{7}$" + local -r git_commit=$(echo "${githash}" | awk -F'+' '{print $2}' | head -c7) + if ! [[ "${git_commit}" =~ $git_commit_regex ]]; then usage echo - echo "!!! You specified an invalid githash '${GITHASH}'." - echo "!!! Tried to extract commit, got ${GIT_COMMIT}." + echo "!!! You specified an invalid githash '${githash}'." + echo "!!! Tried to extract commit, got ${git_commit}." exit 1 fi - echo "Doing ${RELEASE_TYPE} release '${NEW_VERSION}'." + echo "Doing ${release_type} release '${new_version}'." # Set the default umask for the release. This ensures consistency # across our release builds. # # TODO(ihmccreery): This should be in our build process, not our release # process. - declare -r RELEASE_UMASK=${RELEASE_UMASK:-022} - umask "${RELEASE_UMASK}" + local -r release_umask=${release_umask:-022} + umask "${release_umask}" - declare -r GITHUB="https://github.com/kubernetes/kubernetes.git" - declare -r DIR="/tmp/kubernetes-${RELEASE_TYPE}-release-${NEW_VERSION}-$(date +%s)" - echo "Cloning from '${GITHUB}'..." - git clone "${GITHUB}" "${DIR}" + local -r github="https://github.com/kubernetes/kubernetes.git" + local -r dir="/tmp/kubernetes-${release_type}-release-${new_version}-$(date +%s)" + echo "Cloning from '${github}'..." + git clone "${github}" "${dir}" # !!! REMINDER !!! # # Past this point, you are dealing with a different clone of the repo at some # version. Don't assume you're executing code from the same repo as this script # is running in. This is a version agnostic process. - pushd "${DIR}" + pushd "${dir}" - if [[ "${RELEASE_TYPE}" == 'alpha' ]]; then - git checkout "${GIT_COMMIT}" - verify-at-git-commit - verify-ancestor + if [[ "${release_type}" == 'alpha' ]]; then + git checkout "${git_commit}" + verify-at-git-commit "${git_commit}" + verify-ancestor "v${version_major}.${version_minor}.0-alpha.$((${version_alpha_rev}-1))" - alpha-release "${NEW_VERSION}" - elif [[ "${RELEASE_TYPE}" == 'official' ]]; then - declare -r RELEASE_BRANCH="release-${VERSION_MAJOR}.${VERSION_MINOR}" - declare -r BETA_VERSION="v${VERSION_MAJOR}.${VERSION_MINOR}.$((${VERSION_PATCH}+1))-beta" + alpha-release "${new_version}" + elif [[ "${release_type}" == 'official' ]]; then + local -r release_branch="release-${version_major}.${version_minor}" + local -r beta_version="v${version_major}.${version_minor}.$((${version_patch}+1))-beta" - git checkout "${RELEASE_BRANCH}" - verify-at-git-commit - # TODO uncomment this once we've pushed v1.1.1-beta - #verify-ancestor + git checkout "${release_branch}" + verify-at-git-commit "${git_commit}" + verify-ancestor "${new_version}-beta" - official-release "${NEW_VERSION}" - beta-release "${BETA_VERSION}" - else # [[ "${RELEASE_TYPE}" == 'series' ]] - declare -r RELEASE_BRANCH="release-${VERSION_MAJOR}.${VERSION_MINOR}" - declare -r ALPHA_VERSION="v${VERSION_MAJOR}.$((${VERSION_MINOR}+1)).0-alpha.0" - declare -r BETA_VERSION="v${VERSION_MAJOR}.${VERSION_MINOR}.0-beta" + official-release "${new_version}" + beta-release "${beta_version}" + else # [[ "${release_type}" == 'series' ]] + local -r release_branch="release-${version_major}.${version_minor}" + local -r alpha_version="v${version_major}.$((${version_minor}+1)).0-alpha.0" + local -r beta_version="v${version_major}.${version_minor}.0-beta" - git checkout "${GIT_COMMIT}" - verify-at-git-commit - verify-ancestor + git checkout "${git_commit}" + verify-at-git-commit "${git_commit}" + # NOTE: We check the second alpha version, ...-alpha.1, because ...-alpha.0 + # is the branch point for the previous release cycle, so could provide a + # false positive if we accidentally try to release off of the old release + # branch. + verify-ancestor "v${version_major}.${version_minor}.0-alpha.1" - # TODO (Fix versioning.md if you don't do this.) We maybe could actually do - # the alpha rev (in a series release) at HEAD, and patch the version/base.go - # logic then. We'd then have some part of the tree between the branch of - # vX.Y series and the vX.(Y+1).0-alpha.0 tag, but I don't think that's a - # problem. - alpha-release "${ALPHA_VERSION}" + alpha-release "${alpha_version}" - echo "Branching ${RELEASE_BRANCH}." - git checkout -b "${RELEASE_BRANCH}" + echo "Branching ${release_branch}." + git checkout -b "${release_branch}" - beta-release "${BETA_VERSION}" + beta-release "${beta_version}" fi - cleanup + cleanup "${dir}" } function usage() { @@ -157,7 +148,7 @@ function alpha-release() { echo "Doing an alpha release of ${alpha_version}." - echo "Tagging ${alpha_version} at $(git rev-parse --short HEAD)." + echo "Tagging ${alpha_version} at $(current-git-commit)." git tag -a -m "Kubernetes pre-release ${alpha_version}" "${alpha_version}" git-push "${alpha_version}" build @@ -170,13 +161,10 @@ function beta-release() { echo "Doing a beta release of ${beta_version}." - # TODO We need to rev something so that we have a separate commit on the - # release-X.Y branch, since we don't want master to pick up with beta tag. - # TODO rev-docs and/or version? - versionize-docs-and-commit + versionize-docs-and-commit "${beta_version}" rev-version-and-commit - echo "Tagging ${beta_version} at $(git rev-parse --short HEAD)." + echo "Tagging ${beta_version} at $(current-git-commit)." git tag -a -m "Kubernetes pre-release ${beta_version}" "${beta_version}" git-push "${beta_version}" build @@ -189,11 +177,10 @@ function official-release() { echo "Doing an official release of ${official_version}." - # TODO rev-docs and/or version? - versionize-docs-and-commit + versionize-docs-and-commit "${official_version}" rev-version-and-commit - echo "Tagging ${official_version} at $(git rev-parse --short HEAD)." + echo "Tagging ${official_version} at $(current-git-commit)." git tag -a -m "Kubernetes release ${official_version}" "${official_version}" git-push "${official_version}" build @@ -202,20 +189,26 @@ function official-release() { } function verify-at-git-commit() { - echo "Verifying we are at ${GIT_COMMIT}." - if [[ $(git rev-parse --short HEAD) != ${GIT_COMMIT} ]]; then - echo "!!! We are not at commit ${GIT_COMMIT}!" - cleanup + local -r git_commit="${1}" + echo "Verifying we are at ${git_commit}." + if [[ $(current-git-commit) != ${git_commit} ]]; then + echo "!!! We are not at commit ${git_commit}!" + cleanup "${dir}" exit 1 fi } +function current-git-commit() { + git rev-parse --short HEAD +} + function verify-ancestor() { + local -r ancestor="${1}" # Check to make sure the/a previous version is an ancestor. - echo "Checking that previous version '${ANCESTOR}' is an ancestor." - if ! git merge-base --is-ancestor "${ANCESTOR}" HEAD; then - echo "!!! Previous version '${ANCESTOR}' is not an ancestor!" - cleanup + echo "Checking that previous version '${ancestor}' is an ancestor." + if ! git merge-base --is-ancestor "${ancestor}" HEAD; then + echo "!!! Previous version '${ancestor}' is not an ancestor!" + cleanup "${dir}" exit 1 fi } @@ -230,12 +223,12 @@ function git-push() { fi } -# TODO(ihmccreery): Review and fix this function. function versionize-docs-and-commit() { - echo "FAKE versionize-docs-and-commit" - # # NOTE: This is using versionize-docs.sh at the release point. - # ./build/versionize-docs.sh ${NEW_VERSION} - # git commit -am "Versioning docs and examples for ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}" + local -r version="${1}" + echo "Versionizing docs and committing." + # NOTE: This is using versionize-docs.sh at the release point. + ./build/versionize-docs.sh ${version} + git commit -am "Versioning docs and examples for ${version}." } # TODO(ihmccreery): Review and fix this function. @@ -253,9 +246,9 @@ function rev-version-and-commit() { # VERSION_FILE="./pkg/version/base.go" - # GIT_MINOR="${VERSION_MINOR}.${VERSION_PATCH}" + # GIT_MINOR="${version_minor}.${VERSION_PATCH}" # echo "+++ Updating to ${NEW_VERSION}" - # $SED -ri -e "s/gitMajor\s+string = \"[^\"]*\"/gitMajor string = \"${VERSION_MAJOR}\"/" "${VERSION_FILE}" + # $SED -ri -e "s/gitMajor\s+string = \"[^\"]*\"/gitMajor string = \"${version_major}\"/" "${VERSION_FILE}" # $SED -ri -e "s/gitMinor\s+string = \"[^\"]*\"/gitMinor string = \"${GIT_MINOR}\"/" "${VERSION_FILE}" # $SED -ri -e "s/gitVersion\s+string = \"[^\"]*\"/gitVersion string = \"$NEW_VERSION-${release_branch}+\$Format:%h\$\"/" "${VERSION_FILE}" # gofmt -s -w "${VERSION_FILE}" @@ -272,9 +265,10 @@ function build() { } function cleanup() { + local -r dir="${1}" if ${DRY_RUN}; then echo "Dry run:" - echo " pushd ${DIR}" + echo " pushd ${dir}" echo "to have a look around." else popd From ab7576ff5bbcfe83648d70f485746e858f59ad3d Mon Sep 17 00:00:00 2001 From: Isaac Hollander McCreery Date: Thu, 29 Oct 2015 11:04:28 -0700 Subject: [PATCH 03/19] WIP still --- build/build-official-release.sh | 2 +- release/{release.sh => cut.sh} | 181 +++++++++++++++----------------- 2 files changed, 88 insertions(+), 95 deletions(-) rename release/{release.sh => cut.sh} (67%) diff --git a/build/build-official-release.sh b/build/build-official-release.sh index 161441278d..8db1957ea4 100755 --- a/build/build-official-release.sh +++ b/build/build-official-release.sh @@ -45,7 +45,7 @@ declare -r KUBE_GITHUB="https://github.com/kubernetes/kubernetes.git" declare -r KUBE_RELEASE_VERSION=${1-} declare -r KUBE_RELEASE_UMASK=${KUBE_RELEASE_UMASK:-022} -VERSION_REGEX="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$" +VERSION_REGEX="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(-beta|-alpha\\.(0|[1-9][0-9]*))?$" [[ ${KUBE_RELEASE_VERSION} =~ ${VERSION_REGEX} ]] || { echo "!!! You must specify the version you are releasing in the form of '${VERSION_REGEX}'" >&2 exit 1 diff --git a/release/release.sh b/release/cut.sh similarity index 67% rename from release/release.sh rename to release/cut.sh index e9be093c66..46512c2c92 100755 --- a/release/release.sh +++ b/release/cut.sh @@ -23,10 +23,10 @@ set -o pipefail # TODO Audit echos to make sure they're all consistent. -# Sets global DRY_RUN +# Sets DIR, INSTRUCTIONS function main() { # Parse arguments - if [[ "$#" -ne 2 && "$#" -ne 3 ]]; then + if [[ "$#" -ne 2 ]]; then usage exit 1 fi @@ -35,11 +35,14 @@ function main() { local -r githash=${2-} DRY_RUN=true if [[ "${3-}" == "--no-dry-run" ]]; then + echo "!!! This NOT is a dry run." DRY_RUN=false else - echo "THIS IS A DRY RUN" + echo "(This is a dry run.)" fi + check-prereqs + # Get and verify version info local -r alpha_version_regex="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.0-alpha\\.([1-9][0-9]*)$" local -r official_version_regex="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$" @@ -85,17 +88,24 @@ function main() { local -r release_umask=${release_umask:-022} umask "${release_umask}" + # Start a tmp file that will hold instructions for the user. + declare -r INSTRUCTIONS="/tmp/kubernetes-${release_type}-release-${new_version}-$(date +%s)-instructions" + cat > "${INSTRUCTIONS}" <<- EOM +Success! You must now: + +EOM + local -r github="https://github.com/kubernetes/kubernetes.git" - local -r dir="/tmp/kubernetes-${release_type}-release-${new_version}-$(date +%s)" + declare -r DIR="/tmp/kubernetes-${release_type}-release-${new_version}-$(date +%s)" echo "Cloning from '${github}'..." - git clone "${github}" "${dir}" + git clone "${github}" "${DIR}" # !!! REMINDER !!! # # Past this point, you are dealing with a different clone of the repo at some # version. Don't assume you're executing code from the same repo as this script # is running in. This is a version agnostic process. - pushd "${dir}" + pushd "${DIR}" if [[ "${release_type}" == 'alpha' ]]; then git checkout "${git_commit}" @@ -132,17 +142,30 @@ function main() { git checkout -b "${release_branch}" beta-release "${beta_version}" + git-push ${release_branch} fi - cleanup "${dir}" + echo + cat "${INSTRUCTIONS}" } function usage() { - echo "Usage: ${0} [--no-dry-run]" + echo "Usage: ${0} " echo echo "See docs/devel/releasing.md for more info." } +function check-prereqs() { + SED=sed + if which gsed &>/dev/null; then + SED=gsed + fi + if ! ($SED --version 2>&1 | grep -q GNU); then + echo "!!! GNU sed is required. If on OS X, use 'brew install gnu-sed'." + exit 1 + fi +} + function alpha-release() { local -r alpha_version="${1}" @@ -151,9 +174,7 @@ function alpha-release() { echo "Tagging ${alpha_version} at $(current-git-commit)." git tag -a -m "Kubernetes pre-release ${alpha_version}" "${alpha_version}" git-push "${alpha_version}" - build - # TODO prompt for GitHub bits - echo "FAKE prompt GitHub bits for ${alpha_version}" + finish-release-instructions "${alpha_version}" } function beta-release() { @@ -162,14 +183,13 @@ function beta-release() { echo "Doing a beta release of ${beta_version}." versionize-docs-and-commit "${beta_version}" - rev-version-and-commit + rev-version-and-commit "${beta_version}" echo "Tagging ${beta_version} at $(current-git-commit)." git tag -a -m "Kubernetes pre-release ${beta_version}" "${beta_version}" + # TODO what about a PR? git-push "${beta_version}" - build - # TODO prompt for GitHub bits - echo "FAKE prompt GitHub bits for ${beta_version}" + finish-release-instructions "${beta_version}" } function official-release() { @@ -178,22 +198,24 @@ function official-release() { echo "Doing an official release of ${official_version}." versionize-docs-and-commit "${official_version}" - rev-version-and-commit + rev-version-and-commit "${official_version}" echo "Tagging ${official_version} at $(current-git-commit)." git tag -a -m "Kubernetes release ${official_version}" "${official_version}" + # TODO what about a PR? git-push "${official_version}" - build - # TODO prompt for GitHub bits - echo "FAKE prompt GitHub bits for ${official_version}" + finish-release-instructions "${official_version}" } function verify-at-git-commit() { local -r git_commit="${1}" echo "Verifying we are at ${git_commit}." if [[ $(current-git-commit) != ${git_commit} ]]; then - echo "!!! We are not at commit ${git_commit}!" - cleanup "${dir}" + echo <<- EOM +!!! We are not at commit ${git_commit}! (If you're cutting an official release, +that probably means your release branch isn't frozen, so the commit you want to +release isn't at HEAD of the release branch.)" +EOM exit 1 fi } @@ -204,97 +226,68 @@ function current-git-commit() { function verify-ancestor() { local -r ancestor="${1}" - # Check to make sure the/a previous version is an ancestor. + # Check to make sure the previous version is an ancestor. echo "Checking that previous version '${ancestor}' is an ancestor." if ! git merge-base --is-ancestor "${ancestor}" HEAD; then echo "!!! Previous version '${ancestor}' is not an ancestor!" - cleanup "${dir}" exit 1 fi } -function git-push() { - if ${DRY_RUN}; then - echo "FAKE git push "$@"" - else - echo "OH NO!!! YOU'RE NOT REALLY IN DRY_RUN! git push "$@"" - echo "You don't really want to push, do you?" - # git push "$@" - fi -} - function versionize-docs-and-commit() { local -r version="${1}" - echo "Versionizing docs and committing." + echo "Versionizing docs for ${version} and committing." # NOTE: This is using versionize-docs.sh at the release point. ./build/versionize-docs.sh ${version} git commit -am "Versioning docs and examples for ${version}." } -# TODO(ihmccreery): Review and fix this function. function rev-version-and-commit() { - echo "FAKE rev-version-and-commit" - # SED=sed - # if which gsed &>/dev/null; then - # SED=gsed - # fi - # if ! ($SED --version 2>&1 | grep -q GNU); then - # echo "!!! GNU sed is required. If on OS X, use 'brew install gnu-sed'." - # cleanup - # exit 1 - # fi + local -r version="${1}" + local -r version_file="pkg/version/base.go" - # VERSION_FILE="./pkg/version/base.go" - - # GIT_MINOR="${version_minor}.${VERSION_PATCH}" - # echo "+++ Updating to ${NEW_VERSION}" - # $SED -ri -e "s/gitMajor\s+string = \"[^\"]*\"/gitMajor string = \"${version_major}\"/" "${VERSION_FILE}" - # $SED -ri -e "s/gitMinor\s+string = \"[^\"]*\"/gitMinor string = \"${GIT_MINOR}\"/" "${VERSION_FILE}" - # $SED -ri -e "s/gitVersion\s+string = \"[^\"]*\"/gitVersion string = \"$NEW_VERSION-${release_branch}+\$Format:%h\$\"/" "${VERSION_FILE}" - # gofmt -s -w "${VERSION_FILE}" - - # echo "+++ Committing version change" - # git add "${VERSION_FILE}" - # git commit -m "Kubernetes version ${NEW_VERSION}" -} - -# TODO What's in this step? -function build() { - echo "FAKE build" - # TODO Do we need to publish the build to GCS? -} - -function cleanup() { - local -r dir="${1}" - if ${DRY_RUN}; then - echo "Dry run:" - echo " pushd ${dir}" - echo "to have a look around." + local -r version_regex="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(-beta)?$" + if [[ "${version}" =~ $version_regex ]]; then + local -r version_major="${BASH_REMATCH[1]}" + # We append a '+' to the minor version on a beta build per hack/lib/version.sh's logic. + if [[ "${BASH_REMATCH[4]}" == '-beta' ]]; then + local -r version_minor="${BASH_REMATCH[2]}+" + else + local -r version_minor="${BASH_REMATCH[2]}" + fi else - popd + echo "!!! Something went wrong. Tried to rev version to invalid version; should not have gotten to this point." + exit 1 + fi + + echo "Updating ${version_file} to ${version}" + $SED -ri -e "s/gitMajor\s+string = \"[^\"]*\"/gitMajor string = \"${version_major}\"/" "${version_file}" + $SED -ri -e "s/gitMinor\s+string = \"[^\"]*\"/gitMinor string = \"${version_minor}\"/" "${version_file}" + $SED -ri -e "s/gitVersion\s+string = \"[^\"]*\"/gitVersion string = \"${version}+\$Format:%h\$\"/" "${version_file}" + gofmt -s -w "${version_file}" + + echo "Committing version change ${version}" + git add "${version_file}" + git commit -m "Kubernetes version ${version}" +} + +function git-push() { + local -r object="${1}" + if $DRY_RUN; then + echo "Dry run: would have done git push ${object}" + else + echo "NOT A DRY RUN: you don't really want to git push ${object}, do you?" + # git push "${object}" fi } -main "$@" +function finish-release-instructions() { + local -r version="${1}" -# echo "" -# echo "Success you must now:" -# echo "" -# echo "- Push the tags:" -# echo " git push ${push_url} ${NEW_VERSION}" -# echo " git push ${push_url} ${beta_ver}" -# -# if [[ "${VERSION_PATCH}" == "0" ]]; then -# echo "- Push the alpha tag:" -# echo " git push ${push_url} ${alpha_ver}" -# echo "- Push the new release branch:" -# echo " git push ${push_url} ${current_branch}:${release_branch}" -# echo "- DO NOTHING TO MASTER. You were done with master when you pushed the alpha tag." -# else -# echo "- Send branch: ${current_branch} as a PR to ${release_branch} <-- NOTE THIS" -# echo "- In the contents of the PR, include the PRs in the release:" -# echo " hack/cherry_pick_list.sh ${current_branch}^1" -# echo " This helps cross-link PRs to patch releases they're part of in GitHub." -# echo "- Have someone review the PR. This is a mechanical review to ensure it contains" -# echo " the ${NEW_VERSION} commit, which was tagged at ${newtag}." -# fi + cat >> "${INSTRUCTIONS}" <<- EOM +- Finish the ${version} release build: + ./build/build-official-release.sh ${version} +EOM +} + +main "$@" From bf763387bb22101c0b4682b3557b883d9ed5af79 Mon Sep 17 00:00:00 2001 From: Isaac Hollander McCreery Date: Thu, 29 Oct 2015 14:11:28 -0700 Subject: [PATCH 04/19] Release tool finished --- release/cut.sh | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/release/cut.sh b/release/cut.sh index 46512c2c92..1312076129 100755 --- a/release/cut.sh +++ b/release/cut.sh @@ -21,8 +21,6 @@ set -o errexit set -o nounset set -o pipefail -# TODO Audit echos to make sure they're all consistent. - # Sets DIR, INSTRUCTIONS function main() { # Parse arguments @@ -38,7 +36,7 @@ function main() { echo "!!! This NOT is a dry run." DRY_RUN=false else - echo "(This is a dry run.)" + echo "This is a dry run." fi check-prereqs @@ -90,10 +88,17 @@ function main() { # Start a tmp file that will hold instructions for the user. declare -r INSTRUCTIONS="/tmp/kubernetes-${release_type}-release-${new_version}-$(date +%s)-instructions" - cat > "${INSTRUCTIONS}" <<- EOM -Success! You must now: + if $DRY_RUN; then + cat > "${INSTRUCTIONS}" <<- EOM +Success! You would now do the following, if not a dry run: EOM + else + cat > "${INSTRUCTIONS}" <<- EOM +Success! You must now do the following: + +EOM + fi local -r github="https://github.com/kubernetes/kubernetes.git" declare -r DIR="/tmp/kubernetes-${release_type}-release-${new_version}-$(date +%s)" @@ -187,7 +192,6 @@ function beta-release() { echo "Tagging ${beta_version} at $(current-git-commit)." git tag -a -m "Kubernetes pre-release ${beta_version}" "${beta_version}" - # TODO what about a PR? git-push "${beta_version}" finish-release-instructions "${beta_version}" } @@ -202,7 +206,6 @@ function official-release() { echo "Tagging ${official_version} at $(current-git-commit)." git tag -a -m "Kubernetes release ${official_version}" "${official_version}" - # TODO what about a PR? git-push "${official_version}" finish-release-instructions "${official_version}" } From d9b583e631351b31f786c97680fa32a99d0522b9 Mon Sep 17 00:00:00 2001 From: Isaac Hollander McCreery Date: Thu, 22 Oct 2015 05:24:34 -0700 Subject: [PATCH 05/19] Remove out-of-date information about releasing --- docs/devel/releasing.md | 74 ----------------------------------------- 1 file changed, 74 deletions(-) diff --git a/docs/devel/releasing.md b/docs/devel/releasing.md index 9a73405f30..6ff8e862a0 100644 --- a/docs/devel/releasing.md +++ b/docs/devel/releasing.md @@ -249,80 +249,6 @@ can, for instance, tell it to override `gitVersion` and set it to `v0.4-13-g4567bcdef6789-dirty` and set `gitCommit` to `4567bcdef6789...` which is the complete SHA1 of the (dirty) tree used at build time. -## Handling Official Versions - -Handling official versions from git is easy, as long as there is an annotated -git tag pointing to a specific version then `git describe` will return that tag -exactly which will match the idea of an official version (e.g. `v0.5`). - -Handling it on tarballs is a bit harder since the exact version string must be -present in `pkg/version/base.go` for it to get embedded into the binaries. But -simply creating a commit with `v0.5` on its own would mean that the commits -coming after it would also get the `v0.5` version when built from tarball or `go -get` while in fact they do not match `v0.5` (the one that was tagged) exactly. - -To handle that case, creating a new release should involve creating two adjacent -commits where the first of them will set the version to `v0.5` and the second -will set it to `v0.5-dev`. In that case, even in the presence of merges, there -will be a single commit where the exact `v0.5` version will be used and all -others around it will either have `v0.4-dev` or `v0.5-dev`. - -The diagram below illustrates it. - -![Diagram of git commits involved in the release](releasing.png) - -After working on `v0.4-dev` and merging PR 99 we decide it is time to release -`v0.5`. So we start a new branch, create one commit to update -`pkg/version/base.go` to include `gitVersion = "v0.5"` and `git commit` it. - -We test it and make sure everything is working as expected. - -Before sending a PR for it, we create a second commit on that same branch, -updating `pkg/version/base.go` to include `gitVersion = "v0.5-dev"`. That will -ensure that further builds (from tarball or `go install`) on that tree will -always include the `-dev` prefix and will not have a `v0.5` version (since they -do not match the official `v0.5` exactly.) - -We then send PR 100 with both commits in it. - -Once the PR is accepted, we can use `git tag -a` to create an annotated tag -*pointing to the one commit* that has `v0.5` in `pkg/version/base.go` and push -it to GitHub. (Unfortunately GitHub tags/releases are not annotated tags, so -this needs to be done from a git client and pushed to GitHub using SSH or -HTTPS.) - -## Parallel Commits - -While we are working on releasing `v0.5`, other development takes place and -other PRs get merged. For instance, in the example above, PRs 101 and 102 get -merged to the master branch before the versioning PR gets merged. - -This is not a problem, it is only slightly inaccurate that checking out the tree -at commit `012abc` or commit `345cde` or at the commit of the merges of PR 101 -or 102 will yield a version of `v0.4-dev` *but* those commits are not present in -`v0.5`. - -In that sense, there is a small window in which commits will get a -`v0.4-dev` or `v0.4-N-gXXX` label and while they're indeed later than `v0.4` -but they are not really before `v0.5` in that `v0.5` does not contain those -commits. - -Unfortunately, there is not much we can do about it. On the other hand, other -projects seem to live with that and it does not really become a large problem. - -As an example, Docker commit a327d9b91edf has a `v1.1.1-N-gXXX` label but it is -not present in Docker `v1.2.0`: - -```console -$ git describe a327d9b91edf -v1.1.1-822-ga327d9b91edf - -$ git log --oneline v1.2.0..a327d9b91edf -a327d9b91edf Fix data space reporting from Kb/Mb to KB/MB - -(Non-empty output here means the commit is not present on v1.2.0.) -``` - ## Release Notes No official release should be made final without properly matching release notes. From 64f456343c5bb0c1e162e0e85a9c0bb88575ecf2 Mon Sep 17 00:00:00 2001 From: Isaac Hollander McCreery Date: Thu, 22 Oct 2015 05:25:35 -0700 Subject: [PATCH 06/19] TODOs --- docs/devel/releasing.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/devel/releasing.md b/docs/devel/releasing.md index 6ff8e862a0..7366d9996a 100644 --- a/docs/devel/releasing.md +++ b/docs/devel/releasing.md @@ -177,6 +177,8 @@ include everything in the release notes. ## Origin of the Sources +TODO(ihmccreery) update this + Kubernetes may be built from either a git tree (using `hack/build-go.sh`) or from a tarball (using either `hack/build-go.sh` or `go install`) or directly by the Go native build system (using `go get`). @@ -193,6 +195,8 @@ between releases (e.g. at some point in development between v0.3 and v0.4). ## Version Number Format +TODO(ihmccreery) update this + In order to account for these use cases, there are some specific formats that may end up representing the Kubernetes version. Here are a few examples: @@ -251,6 +255,8 @@ is the complete SHA1 of the (dirty) tree used at build time. ## Release Notes +TODO(ihmccreery) update this + No official release should be made final without properly matching release notes. There should be made available, per release, a small summary, preamble, of the From 48eb83a499f04b1889822156bc2d6d0cc7a84fc9 Mon Sep 17 00:00:00 2001 From: Isaac Hollander McCreery Date: Thu, 22 Oct 2015 08:37:26 -0700 Subject: [PATCH 07/19] Proposed design for release infra --- docs/devel/releasing.md | 215 +++++++++++++++++++++++----------------- 1 file changed, 125 insertions(+), 90 deletions(-) diff --git a/docs/devel/releasing.md b/docs/devel/releasing.md index 7366d9996a..acb46a34d3 100644 --- a/docs/devel/releasing.md +++ b/docs/devel/releasing.md @@ -42,31 +42,53 @@ after the first section. Regardless of whether you are cutting a major or minor version, cutting a release breaks down into four pieces: -1. Selecting release components. -1. Tagging and merging the release in Git. -1. Building and pushing the binaries. -1. Writing release notes. +1. selecting release components; +1. cutting/branching the release; +1. publishing binaries and release notes. You should progress in this strict order. -### Building a New Major/Minor Version (`vX.Y.0`) +### Selecting release components -#### Selecting Release Components +First, figure out what kind of release you're doing, what branch you're cutting +from, and other prerequisites. -When cutting a major/minor release, your first job is to find the branch -point. We cut `vX.Y.0` releases directly from `master`, which is also the -branch that we have most continuous validation on. Go first to [the main GCE -Jenkins end-to-end job](http://go/k8s-test/job/kubernetes-e2e-gce) and next to [the -Critical Builds page](http://go/k8s-test/view/Critical%20Builds) and hopefully find a -recent Git hash that looks stable across at least `kubernetes-e2e-gce` and -`kubernetes-e2e-gke-ci`. First glance through builds and look for nice solid -rows of green builds, and then check temporally with the other Critical Builds -to make sure they're solid around then as well. Once you find some greens, you -can find the Git hash for a build by looking at the "Console Log", then look for -`githash=`. You should see a line line: +* Alpha releases (`vX.Y.0-alpha.W`) are cut directly from `master`. + * Alpha releases don't require anything besides green tests, (see below). +* Official releases (`vX.Y.Z`) are cut from their respective release branch, + `release-X.Y`. + * Make sure all necessary cherry picks have been resolved. You should ensure + that all outstanding cherry picks have been reviewed and merged and the + branch validated on Jenkins. See [Cherry Picks](cherry-picks.md) for more + information on how to manage cherry picks prior to cutting the release. + * Official releases also require green tests, (see below). +* New release series are also cut direclty from `master`. + * **This is a big deal!** If you're reading this doc for the first time, you + probably shouldn't be doing this release, and should talk to someone on the + release team. + * New release series cut a new release branch, `release-X.Y`, off of + `master`, and also release the first beta in the series, `vX.Y.0-beta`. + * Every change in the `vX.Y` series from this point on will have to be + cherry picked, so be sure you want to do this before proceeding. + * You should still look for green tests, (see below). + +No matter what you're cutting, you're going to want to look at +[Jenkins](http://go/k8s-test/). Figure out what branch you're cutting from, +(see above,) and look at the critical jobs building from that branch. First +glance through builds and look for nice solid rows of green builds, and then +check temporally with the other critical builds to make sure they're solid +around then as well. Once you find some greens, you can find the Git hash for a +build by looking at the Full Console Output and searching for `githash=`. You +should see a line: ```console -+ githash=v0.20.2-322-g974377b +githash=v1.2.0-alpha.2.164+b44c7d79d6c9bb +``` + +Or, if you're cutting from a release branch (i.e. doing an official release), + +```console +githash=v1.1.0-beta.567+d79d6c9bbb44c7 ``` Because Jenkins builds frequently, if you're looking between jobs @@ -81,99 +103,112 @@ oncall. Before proceeding to the next step: ```sh -export BRANCHPOINT=v0.20.2-322-g974377b +export GITHASH=v1.2.0-alpha.2.164+b44c7d79d6c9bb ``` -Where `v0.20.2-322-g974377b` is the git hash you decided on. This will become -our (retroactive) branch point. +Where `v1.2.0-alpha.2.164+b44c7d79d6c9bb` is the Git hash you decided on. This +will become your release point. -#### Branching, Tagging and Merging +### Cutting/branching the release -Do the following: +You'll need the latest version of the releasing tools: -1. `export VER=x.y` (e.g. `0.20` for v0.20) -1. cd to the base of the repo -1. `git fetch upstream && git checkout -b release-${VER} ${BRANCHPOINT}` (you did set `${BRANCHPOINT}`, right?) -1. Make sure you don't have any files you care about littering your repo (they - better be checked in or outside the repo, or the next step will delete them). -1. `make clean && git reset --hard HEAD && git clean -xdf` -1. `make` (TBD: you really shouldn't have to do this, but the swagger output step requires it right now) -1. `./build/mark-new-version.sh v${VER}.0` to mark the new release and get further - instructions. This creates a series of commits on the branch you're working - on (`release-${VER}`), including forking our documentation for the release, - the release version commit (which is then tagged), and the post-release - version commit. -1. Follow the instructions given to you by that script. They are canon for the - remainder of the Git process. If you don't understand something in that - process, please ask! +```console +git clone git@github.com:kubernetes/contrib.git +cd contrib/release +``` -**TODO**: how to fix tags, etc., if you have to shift the release branchpoint. +#### Cutting an alpha release (`vX.Y.0-alpha.W`) -#### Building and Pushing Binaries +Figure out what version you're cutting, and -In your git repo (you still have `${VER}` set from above right?): +```console +export VER=vX.Y.0-alpha.W +``` -1. `git checkout upstream/master && build/build-official-release.sh v${VER}.0` (the `build-official-release.sh` script is version agnostic, so it's best to run it off `master` directly). -1. Follow the instructions given to you by that script. -1. At this point, you've done all the Git bits, you've got all the binary bits pushed, and you've got the template for the release started on GitHub. +then, from `contrib/release`, run -#### Writing Release Notes +```console +cut-alpha.sh "${VER}" "${GITHASH}" +``` -[This helpful guide](making-release-notes.md) describes how to write release -notes for a major/minor release. In the release template on GitHub, leave the -last PR number that the tool finds for the `.0` release, so the next releaser -doesn't have to hunt. +This will: -### Building a New Patch Release (`vX.Y.Z` for `Z > 0`) +1. clone a temporary copy of the [kubernetes repo](https://github.com/kubernetes/kubernetes); +1. mark the `vX.Y.0-alpha.W` tag at the given Git hash; +1. push the tag to GitHub; +1. build the release binaries at the given Git hash; +1. publish the binaries to GCS; +1. prompt you to do the remainder of the work. -#### Selecting Release Components +#### Cutting an official release (`vX.Y.Z`) -We cut `vX.Y.Z` releases from the `release-vX.Y` branch after all cherry picks -to the branch have been resolved. You should ensure all outstanding cherry picks -have been reviewed and merged and the branch validated on Jenkins (validation -TBD). See the [Cherry Picks](cherry-picks.md) for more information on how to -manage cherry picks prior to cutting the release. +Figure out what version you're cutting, and -#### Tagging and Merging +```console +export VER=vX.Y.Z +``` -1. `export VER=x.y` (e.g. `0.20` for v0.20) -1. `export PATCH=Z` where `Z` is the patch level of `vX.Y.Z` -1. cd to the base of the repo -1. `git fetch upstream && git checkout -b upstream/release-${VER} release-${VER}` -1. Make sure you don't have any files you care about littering your repo (they - better be checked in or outside the repo, or the next step will delete them). -1. `make clean && git reset --hard HEAD && git clean -xdf` -1. `make` (TBD: you really shouldn't have to do this, but the swagger output step requires it right now) -1. `./build/mark-new-version.sh v${VER}.${PATCH}` to mark the new release and get further - instructions. This creates a series of commits on the branch you're working - on (`release-${VER}`), including forking our documentation for the release, - the release version commit (which is then tagged), and the post-release - version commit. -1. Follow the instructions given to you by that script. They are canon for the - remainder of the Git process. If you don't understand something in that - process, please ask! When proposing PRs, you can pre-fill the body with - `hack/cherry_pick_list.sh upstream/release-${VER}` to inform people of what - is already on the branch. +then, from `contrib/release`, run -**TODO**: how to fix tags, etc., if the release is changed. +```console +cut-official.sh "${VER}" "${GITHASH}" +``` -#### Building and Pushing Binaries +This will: -In your git repo (you still have `${VER}` and `${PATCH}` set from above right?): +1. clone a temporary copy of the [kubernetes repo](https://github.com/kubernetes/kubernetes); +1. do a series of commits on the branch, including forking the documentation + and doing the release version commit; + * TODO(ihmccreery) it's not yet clear what exactly this is going to look like. +1. mark both the `vX.Y.Z` and `vX.Y.(Z+1)-beta` tags at the given Git hash; +1. push the tags to GitHub; +1. build the release binaries at the given Git hash (on the appropriate + branch); +1. publish the binaries to GCS; +1. prompt you to do the remainder of the work. -1. `git checkout upstream/master && build/build-official-release.sh - v${VER}.${PATCH}` (the `build-official-release.sh` script is version - agnostic, so it's best to run it off `master` directly). -1. Follow the instructions given to you by that script. At this point, you've - done all the Git bits, you've got all the binary bits pushed, and you've got - the template for the release started on GitHub. +#### Branching a new release series (`vX.Y`) -#### Writing Release Notes +Once again, **this is a big deal!** If you're reading this doc for the first +time, you probably shouldn't be doing this release, and should talk to someone +on the release team. -Run `hack/cherry_pick_list.sh ${VER}.${PATCH}~1` to get the release notes for -the patch release you just created. Feel free to prune anything internal, like -you would for a major release, but typically for patch releases we tend to -include everything in the release notes. +Figure out what series you're cutting, and + +```console +export VER=vX.Y +``` + +then, from `contrib/release`, run + +```console +branch-series.sh "${VER}" "${GITHASH}" +``` + +This will: + +1. clone a temporary copy of the [kubernetes repo](https://github.com/kubernetes/kubernetes); +1. mark the `vX.(Y+1).0-alpha.0` tag at the given Git hash on `master`; +1. fork a new branch `release-X.Y` off of `master` at the Given Git hash; +1. do a series of commits on the branch, including forking the documentation + and doing the release version commit; + * TODO(ihmccreery) it's not yet clear what exactly this is going to look like. +1. mark the `vX.Y.0-beta` tag at the appropriate commit on the new `release-X.Y` branch; +1. push the tags to GitHub; +1. build the release binaries at the appropriate Git hash on the appropriate + branches, (for both the new alpha and beta releases); +1. publish the binaries to GCS; +1. prompt you to do the remainder of the work. + +**TODO(ihmccreery)**: can we fix tags, etc., if you have to shift the release branchpoint? + +### Publishing binaries and release notes + +Whichever script you ran above will prompt you to take any remaining steps, +including publishing binaries and release notes. + +**TODO(ihmccreery)**: deal with the `making-release-notes` doc in `docs/devel`. ## Origin of the Sources @@ -195,7 +230,7 @@ between releases (e.g. at some point in development between v0.3 and v0.4). ## Version Number Format -TODO(ihmccreery) update this +TODO(ihmccreery) update everything below here In order to account for these use cases, there are some specific formats that may end up representing the Kubernetes version. Here are a few examples: From d5b5f370abdeebf727889dc2272409f87c80e0f9 Mon Sep 17 00:00:00 2001 From: Isaac Hollander McCreery Date: Fri, 9 Oct 2015 15:29:17 -0700 Subject: [PATCH 08/19] Updates to versioning.md --- docs/design/versioning.md | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/docs/design/versioning.md b/docs/design/versioning.md index c764a585a6..75cdffce80 100644 --- a/docs/design/versioning.md +++ b/docs/design/versioning.md @@ -35,23 +35,26 @@ Documentation for other releases can be found at Legend: -* **Kube <major>.<minor>.<patch>** refers to the version of Kubernetes that is released. This versions all components: apiserver, kubelet, kubectl, etc. +* **Kube X.Y.Z** refers to the version of Kubernetes that is released. This versions all components: apiserver, kubelet, kubectl, etc. (**X** is the major version, **Y** is the minor version, and **Z** is the patch version.) * **API vX[betaY]** refers to the version of the HTTP API. -## Release Timeline +## Release versioning ### Minor version scheme and timeline -* Kube 1.0.0, 1.0.1 -- DONE! -* Kube 1.0.X (X>1): Standard operating procedure. We patch the release-1.0 branch as needed and increment the patch number. -* Kube 1.1.0-alpha.X: Released roughly every two weeks by cutting from HEAD. No cherrypick releases. If there is a critical bugfix, a new release from HEAD can be created ahead of schedule. -* Kube 1.1.0-beta: When HEAD is feature-complete, we will cut the release-1.1.0 branch 2 weeks prior to the desired 1.1.0 date and only merge PRs essential to 1.1. This cut will be marked as 1.1.0-beta, and HEAD will be revved to 1.2.0-alpha.0. -* Kube 1.1.0: Final release, cut from the release-1.1.0 branch cut two weeks prior. Should occur between 3 and 4 months after 1.0. 1.1.1-beta will be tagged at the same time on the same branch. +* Kube X.Y.0-alpha.W, W > 0: Alpha releases are released roughly every two weeks directly from the master branch. No cherrypick releases. If there is a critical bugfix, a new release from master can be created ahead of schedule. +* Kube X.Y.Z-beta: When master is feature-complete for Kube X.Y, we will cut the release-X.Y branch 2 weeks prior to the desired X.Y.0 date and cherrypick only PRs essential to X.Y. This cut will be marked as X.Y.0-beta, and master will be revved to X.Y+1.0-alpha.0. +* Kube X.Y.0: Final release, cut from the release-X.Y branch cut two weeks prior. X.Y.1-beta will be tagged at the same commit on the same branch. X.Y.0 occur 3 to 4 months after X.Y-1.0. +* Kube X.Y.Z, Z > 0: [Patch releases](#patches) are released as we cherrypick commits into the release-X.Y branch, (which is at X.Y.Z-beta,) as needed. X.Y.Z is cut straight from the release-X.Y branch, and X.Y.Z+1-beta is tagged on the same commit. ### Major version timeline There is no mandated timeline for major versions. They only occur when we need to start the clock on deprecating features. A given major version should be the latest major version for at least one year from its original release date. +### CI version scheme + +* Continuous integration versions also exist, and are versioned off of alpha and beta releases. X.Y.Z-alpha.W.C+aaaa is C commits after X.Y.Z-alpha.W, with an additional +aaaa build suffix added; X.Y.Z-beta.C+bbbb is C commits after X.Y.Z-beta, with an additional +bbbb build suffix added. + ## Release versions as related to API versions Here is an example major release cycle: @@ -64,11 +67,11 @@ Here is an example major release cycle: * Before Kube 2.0 is cut, API v2 must be released in 1.x. This enables two things: (1) users can upgrade to API v2 when running Kube 1.x and then switch over to Kube 2.x transparently, and (2) in the Kube 2.0 release itself we can cleanup and remove all API v2beta\* versions because no one should have v2beta\* objects left in their database. As mentioned above, tooling will exist to make sure there are no calls or references to a given API version anywhere inside someone's kube installation before someone upgrades. * Kube 2.0 must include the v1 API, but Kube 3.0 must include the v2 API only. It *may* include the v1 API as well if the burden is not high - this will be determined on a per-major-version basis. -## Rationale for API v2 being complete before v2.0's release +### Rationale for API v2 being complete before v2.0's release It may seem a bit strange to complete the v2 API before v2.0 is released, but *adding* a v2 API is not a breaking change. *Removing* the v2beta\* APIs *is* a breaking change, which is what necessitates the major version bump. There are other ways to do this, but having the major release be the fresh start of that release's API without the baggage of its beta versions seems most intuitive out of the available options. -# Patches +## Patches Patch releases are intended for critical bug fixes to the latest minor version, such as addressing security vulnerabilities, fixes to problems affecting a large number of users, severe problems with no workaround, and blockers for products based on Kubernetes. @@ -76,7 +79,7 @@ They should not contain miscellaneous feature additions or improvements, and esp Dependencies, such as Docker or Etcd, should also not be changed unless absolutely necessary, and also just to fix critical bugs (so, at most patch version changes, not new major nor minor versions). -# Upgrades +## Upgrades * Users can upgrade from any Kube 1.x release to any other Kube 1.x release as a rolling upgrade across their cluster. (Rolling upgrade means being able to upgrade the master first, then one node at a time. See #4855 for details.) * No hard breaking changes over version boundaries. From 1b0082569b54e57f2e53d70a6407eb497ec195b1 Mon Sep 17 00:00:00 2001 From: Isaac Hollander McCreery Date: Wed, 28 Oct 2015 11:08:55 -0700 Subject: [PATCH 09/19] Doc fixup to reflect script reality --- docs/devel/releasing.md | 68 +++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 40 deletions(-) diff --git a/docs/devel/releasing.md b/docs/devel/releasing.md index acb46a34d3..971c2878ed 100644 --- a/docs/devel/releasing.md +++ b/docs/devel/releasing.md @@ -44,6 +44,7 @@ release breaks down into four pieces: 1. selecting release components; 1. cutting/branching the release; +1. building and pushing the binaries; and 1. publishing binaries and release notes. You should progress in this strict order. @@ -77,7 +78,7 @@ No matter what you're cutting, you're going to want to look at (see above,) and look at the critical jobs building from that branch. First glance through builds and look for nice solid rows of green builds, and then check temporally with the other critical builds to make sure they're solid -around then as well. Once you find some greens, you can find the Git hash for a +around then as well. Once you find some greens, you can find the git hash for a build by looking at the Full Console Output and searching for `githash=`. You should see a line: @@ -106,7 +107,7 @@ Before proceeding to the next step: export GITHASH=v1.2.0-alpha.2.164+b44c7d79d6c9bb ``` -Where `v1.2.0-alpha.2.164+b44c7d79d6c9bb` is the Git hash you decided on. This +Where `v1.2.0-alpha.2.164+b44c7d79d6c9bb` is the git hash you decided on. This will become your release point. ### Cutting/branching the release @@ -123,50 +124,46 @@ cd contrib/release Figure out what version you're cutting, and ```console -export VER=vX.Y.0-alpha.W +export VER="vX.Y.0-alpha.W" ``` then, from `contrib/release`, run ```console -cut-alpha.sh "${VER}" "${GITHASH}" +cut.sh "${VER}" "${GITHASH}" ``` This will: -1. clone a temporary copy of the [kubernetes repo](https://github.com/kubernetes/kubernetes); -1. mark the `vX.Y.0-alpha.W` tag at the given Git hash; -1. push the tag to GitHub; -1. build the release binaries at the given Git hash; -1. publish the binaries to GCS; -1. prompt you to do the remainder of the work. +1. mark the `vX.Y.0-alpha.W` tag at the given git hash; +1. prompt you to do the remainder of the work, including building the + appropriate binaries and pushing them to the appropriate places. #### Cutting an official release (`vX.Y.Z`) Figure out what version you're cutting, and ```console -export VER=vX.Y.Z +export VER="vX.Y.Z" ``` then, from `contrib/release`, run ```console -cut-official.sh "${VER}" "${GITHASH}" +cut.sh "${VER}" "${GITHASH}" ``` This will: -1. clone a temporary copy of the [kubernetes repo](https://github.com/kubernetes/kubernetes); -1. do a series of commits on the branch, including forking the documentation - and doing the release version commit; - * TODO(ihmccreery) it's not yet clear what exactly this is going to look like. -1. mark both the `vX.Y.Z` and `vX.Y.(Z+1)-beta` tags at the given Git hash; -1. push the tags to GitHub; -1. build the release binaries at the given Git hash (on the appropriate - branch); -1. publish the binaries to GCS; -1. prompt you to do the remainder of the work. +1. do a series of commits on the branch for `vX.Y.Z`, including versionizing + the documentation and doing the release version commit; +1. mark the `vX.Y.Z` tag at the release version commit; +1. do a series of commits on the branch for `vX.Y.(Z+1)-beta` on top of the + previous commits, including versionizing the documentation and doing the + beta version commit; +1. mark the `vX.Y.(Z+1)-beta` tag at the release version commit; +1. prompt you to do the remainder of the work, including building the + appropriate binaries and pushing them to the appropriate places. #### Branching a new release series (`vX.Y`) @@ -177,39 +174,30 @@ on the release team. Figure out what series you're cutting, and ```console -export VER=vX.Y +export VER="vX.Y" ``` then, from `contrib/release`, run ```console -branch-series.sh "${VER}" "${GITHASH}" +cut.sh "${VER}" "${GITHASH}" ``` This will: -1. clone a temporary copy of the [kubernetes repo](https://github.com/kubernetes/kubernetes); -1. mark the `vX.(Y+1).0-alpha.0` tag at the given Git hash on `master`; -1. fork a new branch `release-X.Y` off of `master` at the Given Git hash; -1. do a series of commits on the branch, including forking the documentation - and doing the release version commit; - * TODO(ihmccreery) it's not yet clear what exactly this is going to look like. -1. mark the `vX.Y.0-beta` tag at the appropriate commit on the new `release-X.Y` branch; -1. push the tags to GitHub; -1. build the release binaries at the appropriate Git hash on the appropriate - branches, (for both the new alpha and beta releases); -1. publish the binaries to GCS; -1. prompt you to do the remainder of the work. - -**TODO(ihmccreery)**: can we fix tags, etc., if you have to shift the release branchpoint? +1. mark the `vX.(Y+1).0-alpha.0` tag at the given git hash on `master`; +1. fork a new branch `release-X.Y` off of `master` at the given git hash; +1. do a series of commits on the branch for `vX.Y.0-beta`, including versionizing + the documentation and doing the release version commit; +1. mark the `vX.Y.(Z+1)-beta` tag at the beta version commit; +1. prompt you to do the remainder of the work, including building the + appropriate binaries and pushing them to the appropriate places. ### Publishing binaries and release notes Whichever script you ran above will prompt you to take any remaining steps, including publishing binaries and release notes. -**TODO(ihmccreery)**: deal with the `making-release-notes` doc in `docs/devel`. - ## Origin of the Sources TODO(ihmccreery) update this From f2b8edddaeff8a37aa02399449b830ef571cbb47 Mon Sep 17 00:00:00 2001 From: Isaac Hollander McCreery Date: Thu, 29 Oct 2015 15:10:00 -0700 Subject: [PATCH 10/19] Fixups of docs and scripts --- build/build-official-release.sh | 54 +++++------ .../cut.sh => build/cut-official-release.sh | 58 ++++++++---- docs/design/versioning.md | 2 +- docs/devel/releasing.md | 90 ++++++------------- 4 files changed, 96 insertions(+), 108 deletions(-) rename release/cut.sh => build/cut-official-release.sh (84%) diff --git a/build/build-official-release.sh b/build/build-official-release.sh index 8db1957ea4..176b32cb33 100755 --- a/build/build-official-release.sh +++ b/build/build-official-release.sh @@ -88,29 +88,31 @@ ln -s ${KUBE_BUILD_DIR}/_output/release-tars/kubernetes.tar.gz ${KUBE_BUILD_DIR} MD5=$(md5 "${KUBE_BUILD_DIR}/kubernetes.tar.gz") SHA1=$(sha1 "${KUBE_BUILD_DIR}/kubernetes.tar.gz") -echo "" -echo "Success! You must now do the following: (you may want to cut" -echo " and paste these instructions elsewhere, step 1 can be spammy)" -echo "" -echo " 1) (cd ${KUBE_BUILD_DIR}; build/push-official-release.sh ${KUBE_RELEASE_VERSION})" -echo " 2) Go to https://github.com/GoogleCloudPlatform/kubernetes/releases" -echo " and create a new 'Release ${KUBE_RELEASE_VERSION} Candidate' release" -echo " with the ${KUBE_RELEASE_VERSION} tag. Mark it as a pre-release." -echo " 3) Upload the ${KUBE_BUILD_DIR}/kubernetes.tar.gz to GitHub" -echo " 4) Use this template for the release:" -echo "" -echo "## [Documentation](http://releases.k8s.io/${KUBE_RELEASE_VERSION}/docs/README.md)" -echo "## [Examples](http://releases.k8s.io/${KUBE_RELEASE_VERSION}/examples)" -echo "## Changes since (last PR )" -echo "" -echo "" -echo "" -echo "binary | hash alg | hash" -echo "------ | -------- | ----" -echo "\`kubernetes.tar.gz\` | md5 | \`${MD5}\`" -echo "\`kubernetes.tar.gz\` | sha1 | \`${SHA1}\`" -echo "" -echo " We'll fill in the release notes in the next stage." -echo " 5) Ensure all the binaries are in place on GitHub and GCS before cleaning." -echo " 6) (cd ${KUBE_BUILD_DIR}; make clean; cd -; rm -rf ${KUBE_BUILD_DIR})" -echo "" +echo <<- EOM + +Success! You must now do the following: (you may want to cut + and paste these instructions elsewhere, step 1 can be spammy) + + 1) (cd ${KUBE_BUILD_DIR}; build/push-official-release.sh ${KUBE_RELEASE_VERSION}) + 2) Go to https://github.com/GoogleCloudPlatform/kubernetes/releases + and create a new 'Release ${KUBE_RELEASE_VERSION} Candidate' release + with the ${KUBE_RELEASE_VERSION} tag. Mark it as a pre-release. + 3) Upload the ${KUBE_BUILD_DIR}/kubernetes.tar.gz to GitHub + 4) Use this template for the release: + +## [Documentation](http://releases.k8s.io/${KUBE_RELEASE_VERSION}/docs/README.md) +## [Examples](http://releases.k8s.io/${KUBE_RELEASE_VERSION}/examples) +## Changes since (last PR ) + + + +binary | hash alg | hash +------ | -------- | ---- +\`kubernetes.tar.gz\` | md5 | \`${MD5}\` +\`kubernetes.tar.gz\` | sha1 | \`${SHA1}\` + + We'll fill in the release notes in the next stage. + 5) Ensure all the binaries are in place on GitHub and GCS before cleaning. + 6) (cd ${KUBE_BUILD_DIR}; make clean; cd -; rm -rf ${KUBE_BUILD_DIR}) + +EOM diff --git a/release/cut.sh b/build/cut-official-release.sh similarity index 84% rename from release/cut.sh rename to build/cut-official-release.sh index 1312076129..328f90027f 100755 --- a/release/cut.sh +++ b/build/cut-official-release.sh @@ -113,18 +113,20 @@ EOM pushd "${DIR}" if [[ "${release_type}" == 'alpha' ]]; then + local -r ancestor="v${version_major}.${version_minor}.0-alpha.$((${version_alpha_rev}-1))" git checkout "${git_commit}" verify-at-git-commit "${git_commit}" - verify-ancestor "v${version_major}.${version_minor}.0-alpha.$((${version_alpha_rev}-1))" + verify-ancestor "${ancestor}" alpha-release "${new_version}" elif [[ "${release_type}" == 'official' ]]; then local -r release_branch="release-${version_major}.${version_minor}" local -r beta_version="v${version_major}.${version_minor}.$((${version_patch}+1))-beta" + local -r ancestor="${new_version}-beta" git checkout "${release_branch}" verify-at-git-commit "${git_commit}" - verify-ancestor "${new_version}-beta" + verify-ancestor "${ancestor}" official-release "${new_version}" beta-release "${beta_version}" @@ -132,14 +134,15 @@ EOM local -r release_branch="release-${version_major}.${version_minor}" local -r alpha_version="v${version_major}.$((${version_minor}+1)).0-alpha.0" local -r beta_version="v${version_major}.${version_minor}.0-beta" - - git checkout "${git_commit}" - verify-at-git-commit "${git_commit}" # NOTE: We check the second alpha version, ...-alpha.1, because ...-alpha.0 # is the branch point for the previous release cycle, so could provide a # false positive if we accidentally try to release off of the old release # branch. - verify-ancestor "v${version_major}.${version_minor}.0-alpha.1" + local -r ancestor="v${version_major}.${version_minor}.0-alpha.1" + + git checkout "${git_commit}" + verify-at-git-commit "${git_commit}" + verify-ancestor "${ancestor}" alpha-release "${alpha_version}" @@ -179,7 +182,18 @@ function alpha-release() { echo "Tagging ${alpha_version} at $(current-git-commit)." git tag -a -m "Kubernetes pre-release ${alpha_version}" "${alpha_version}" git-push "${alpha_version}" - finish-release-instructions "${alpha_version}" + + cat >> "${INSTRUCTIONS}" <<- EOM +- Finish the ${alpha_version} release build: + - From this directory (clone of upstream/master), + ./release/build-official-release.sh ${alpha_version} + - Figure out what the PR numbers for this release and last release are, and + get an api-token from GitHub (https://github.com/settings/tokens). From a + clone of kubernetes/contrib at upstream/master, + go run release-notes/release-notes.go --last-release-pr= --current-release-pr= --api-token= + Feel free to prune, but typically for patch releases we tend to include + everything in the release notes. +EOM } function beta-release() { @@ -193,7 +207,10 @@ function beta-release() { echo "Tagging ${beta_version} at $(current-git-commit)." git tag -a -m "Kubernetes pre-release ${beta_version}" "${beta_version}" git-push "${beta_version}" - finish-release-instructions "${beta_version}" + + # NOTE: We currently don't build/release beta versions, since they're almost + # identical to the prior version, so we don't prompt for build or release + # here. } function official-release() { @@ -207,7 +224,21 @@ function official-release() { echo "Tagging ${official_version} at $(current-git-commit)." git tag -a -m "Kubernetes release ${official_version}" "${official_version}" git-push "${official_version}" - finish-release-instructions "${official_version}" + + cat >> "${INSTRUCTIONS}" <<- EOM +- Finish the ${version} release build: + - From this directory (clone of upstream/master), + ./release/build-official-release.sh ${version} + - Prep release notes: + - From this directory (clone of upstream/master), run + ./hack/cherry_pick_list.sh ${version} + to get the release notes for the patch release you just created. Feel + free to prune anything internal, but typically for patch releases we tend + to include everything in the release notes. + - If this is a first official release (vX.Y.0), scan through the release + notes for all of the alpha releases since the last cycle, and include + anything important in release notes. +EOM } function verify-at-git-commit() { @@ -284,13 +315,4 @@ function git-push() { fi } -function finish-release-instructions() { - local -r version="${1}" - - cat >> "${INSTRUCTIONS}" <<- EOM -- Finish the ${version} release build: - ./build/build-official-release.sh ${version} -EOM -} - main "$@" diff --git a/docs/design/versioning.md b/docs/design/versioning.md index 75cdffce80..a189d0cfa4 100644 --- a/docs/design/versioning.md +++ b/docs/design/versioning.md @@ -53,7 +53,7 @@ There is no mandated timeline for major versions. They only occur when we need t ### CI version scheme -* Continuous integration versions also exist, and are versioned off of alpha and beta releases. X.Y.Z-alpha.W.C+aaaa is C commits after X.Y.Z-alpha.W, with an additional +aaaa build suffix added; X.Y.Z-beta.C+bbbb is C commits after X.Y.Z-beta, with an additional +bbbb build suffix added. +* Continuous integration versions also exist, and are versioned off of alpha and beta releases. X.Y.Z-alpha.W.C+aaaa is C commits after X.Y.Z-alpha.W, with an additional +aaaa build suffix added; X.Y.Z-beta.C+bbbb is C commits after X.Y.Z-beta, with an additional +bbbb build suffix added. Furthermore, builds that are built off of a dirty build tree, (with things in the tree that are not checked it,) it will be appended with -dirty. ## Release versions as related to API versions diff --git a/docs/devel/releasing.md b/docs/devel/releasing.md index 971c2878ed..2ba88bd335 100644 --- a/docs/devel/releasing.md +++ b/docs/devel/releasing.md @@ -78,9 +78,16 @@ No matter what you're cutting, you're going to want to look at (see above,) and look at the critical jobs building from that branch. First glance through builds and look for nice solid rows of green builds, and then check temporally with the other critical builds to make sure they're solid -around then as well. Once you find some greens, you can find the git hash for a -build by looking at the Full Console Output and searching for `githash=`. You -should see a line: +around then as well. + +If you're doing an alpha release or cutting a new release series, you can +choose an arbitrary build. If you are doing an official release, you have to +release from HEAD of the branch, (because you have to do some version-rev +commits,) so choose the latest build on the release branch. (Remember, that +branch should be frozen.) + +Once you find some greens, you can find the git hash for a build by looking at +the Full Console Output and searching for `githash=`. You should see a line: ```console githash=v1.2.0-alpha.2.164+b44c7d79d6c9bb @@ -115,10 +122,12 @@ will become your release point. You'll need the latest version of the releasing tools: ```console -git clone git@github.com:kubernetes/contrib.git -cd contrib/release +git clone git@github.com:kubernetes/kubernetes.git +cd kubernetes ``` +or `git checkout upstream/master` from an existing repo. + #### Cutting an alpha release (`vX.Y.0-alpha.W`) Figure out what version you're cutting, and @@ -127,10 +136,10 @@ Figure out what version you're cutting, and export VER="vX.Y.0-alpha.W" ``` -then, from `contrib/release`, run +then, run ```console -cut.sh "${VER}" "${GITHASH}" +build/cut-official-release.sh "${VER}" "${GITHASH}" ``` This will: @@ -147,10 +156,10 @@ Figure out what version you're cutting, and export VER="vX.Y.Z" ``` -then, from `contrib/release`, run +then, run ```console -cut.sh "${VER}" "${GITHASH}" +build/cut-official-release.sh "${VER}" "${GITHASH}" ``` This will: @@ -161,7 +170,7 @@ This will: 1. do a series of commits on the branch for `vX.Y.(Z+1)-beta` on top of the previous commits, including versionizing the documentation and doing the beta version commit; -1. mark the `vX.Y.(Z+1)-beta` tag at the release version commit; +1. mark the `vX.Y.(Z+1)-beta` tag at the beta version commit; 1. prompt you to do the remainder of the work, including building the appropriate binaries and pushing them to the appropriate places. @@ -177,10 +186,10 @@ Figure out what series you're cutting, and export VER="vX.Y" ``` -then, from `contrib/release`, run +then, run ```console -cut.sh "${VER}" "${GITHASH}" +build/cut-official-release.sh "${VER}" "${GITHASH}" ``` This will: @@ -189,18 +198,19 @@ This will: 1. fork a new branch `release-X.Y` off of `master` at the given git hash; 1. do a series of commits on the branch for `vX.Y.0-beta`, including versionizing the documentation and doing the release version commit; -1. mark the `vX.Y.(Z+1)-beta` tag at the beta version commit; +1. mark the `vX.Y.0-beta` tag at the beta version commit; 1. prompt you to do the remainder of the work, including building the appropriate binaries and pushing them to the appropriate places. ### Publishing binaries and release notes -Whichever script you ran above will prompt you to take any remaining steps, -including publishing binaries and release notes. +The script you ran above will prompt you to take any remaining steps, including +publishing binaries and release notes. -## Origin of the Sources +## Injecting Version into Binaries -TODO(ihmccreery) update this +*Please note that this information may be out of date. The scripts are the +authoritative source on how version injection works.* Kubernetes may be built from either a git tree (using `hack/build-go.sh`) or from a tarball (using either `hack/build-go.sh` or `go install`) or directly by @@ -216,36 +226,6 @@ access to the information about the git tree, but we still want to be able to tell whether this build corresponds to an exact release (e.g. v0.3) or is between releases (e.g. at some point in development between v0.3 and v0.4). -## Version Number Format - -TODO(ihmccreery) update everything below here - -In order to account for these use cases, there are some specific formats that -may end up representing the Kubernetes version. Here are a few examples: - -- **v0.5**: This is official version 0.5 and this version will only be used - when building from a clean git tree at the v0.5 git tag, or from a tree - extracted from the tarball corresponding to that specific release. -- **v0.5-15-g0123abcd4567**: This is the `git describe` output and it indicates - that we are 15 commits past the v0.5 release and that the SHA1 of the commit - where the binaries were built was `0123abcd4567`. It is only possible to have - this level of detail in the version information when building from git, not - when building from a tarball. -- **v0.5-15-g0123abcd4567-dirty** or **v0.5-dirty**: The extra `-dirty` prefix - means that the tree had local modifications or untracked files at the time of - the build, so there's no guarantee that the source code matches exactly the - state of the tree at the `0123abcd4567` commit or at the `v0.5` git tag - (resp.) -- **v0.5-dev**: This means we are building from a tarball or using `go get` or, - if we have a git tree, we are using `go install` directly, so it is not - possible to inject the git version into the build information. Additionally, - this is not an official release, so the `-dev` prefix indicates that the - version we are building is after `v0.5` but before `v0.6`. (There is actually - an exception where a commit with `v0.5-dev` is not present on `v0.6`, see - later for details.) - -## Injecting Version into Binaries - In order to cover the different build cases, we start by providing information that can be used when using only Go build tools or when we do not have the git version information available. @@ -276,22 +256,6 @@ can, for instance, tell it to override `gitVersion` and set it to `v0.4-13-g4567bcdef6789-dirty` and set `gitCommit` to `4567bcdef6789...` which is the complete SHA1 of the (dirty) tree used at build time. -## Release Notes - -TODO(ihmccreery) update this - -No official release should be made final without properly matching release notes. - -There should be made available, per release, a small summary, preamble, of the -major changes, both in terms of feature improvements/bug fixes and notes about -functional feature changes (if any) regarding the previous released version so -that the BOM regarding updating to it gets as obvious and trouble free as possible. - -After this summary, preamble, all the relevant PRs/issues that got in that -version should be listed and linked together with a small summary understandable -by plain mortals (in a perfect world PR/issue's title would be enough but often -it is just too cryptic/geeky/domain-specific that it isn't). - [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/devel/releasing.md?pixel)]() From 710970071349042da143f9cac8102a5a2921e2bb Mon Sep 17 00:00:00 2001 From: Isaac Hollander McCreery Date: Thu, 29 Oct 2015 15:11:48 -0700 Subject: [PATCH 11/19] Don't mess with versionize-docs here --- build/versionize-docs.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/versionize-docs.sh b/build/versionize-docs.sh index d102b6b67b..8eb4c0aaff 100755 --- a/build/versionize-docs.sh +++ b/build/versionize-docs.sh @@ -45,7 +45,7 @@ if ! ($SED --version 2>&1 | grep -q GNU); then exit 1 fi -echo "+++ Versioning documentation and examples at ${NEW_VERSION}" +echo "+++ Versioning documentation and examples" # Update the docs to match this version. HTML_PREVIEW_PREFIX="https://htmlpreview.github.io/\?https://github.com/kubernetes/kubernetes" From 72a586db7f1f4b09a67194e3ae8308da55a4e76c Mon Sep 17 00:00:00 2001 From: Isaac Hollander McCreery Date: Thu, 29 Oct 2015 15:14:13 -0700 Subject: [PATCH 12/19] Move to release/ --- docs/devel/releasing.md | 6 +++--- {build => release}/build-official-release.sh | 0 {build => release}/cut-official-release.sh | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename {build => release}/build-official-release.sh (100%) rename {build => release}/cut-official-release.sh (100%) diff --git a/docs/devel/releasing.md b/docs/devel/releasing.md index 2ba88bd335..fad957b622 100644 --- a/docs/devel/releasing.md +++ b/docs/devel/releasing.md @@ -139,7 +139,7 @@ export VER="vX.Y.0-alpha.W" then, run ```console -build/cut-official-release.sh "${VER}" "${GITHASH}" +release/cut-official-release.sh "${VER}" "${GITHASH}" ``` This will: @@ -159,7 +159,7 @@ export VER="vX.Y.Z" then, run ```console -build/cut-official-release.sh "${VER}" "${GITHASH}" +release/cut-official-release.sh "${VER}" "${GITHASH}" ``` This will: @@ -189,7 +189,7 @@ export VER="vX.Y" then, run ```console -build/cut-official-release.sh "${VER}" "${GITHASH}" +release/cut-official-release.sh "${VER}" "${GITHASH}" ``` This will: diff --git a/build/build-official-release.sh b/release/build-official-release.sh similarity index 100% rename from build/build-official-release.sh rename to release/build-official-release.sh diff --git a/build/cut-official-release.sh b/release/cut-official-release.sh similarity index 100% rename from build/cut-official-release.sh rename to release/cut-official-release.sh From 235aaf73c4174911473299279564b76b332e4e3c Mon Sep 17 00:00:00 2001 From: Isaac Hollander McCreery Date: Thu, 29 Oct 2015 15:21:35 -0700 Subject: [PATCH 13/19] Remove old releasing illustrations --- docs/devel/releasing.dot | 113 --------------------------------------- docs/devel/releasing.png | Bin 30693 -> 0 bytes docs/devel/releasing.svg | 113 --------------------------------------- 3 files changed, 226 deletions(-) delete mode 100644 docs/devel/releasing.dot delete mode 100644 docs/devel/releasing.png delete mode 100644 docs/devel/releasing.svg diff --git a/docs/devel/releasing.dot b/docs/devel/releasing.dot deleted file mode 100644 index fe8124c36d..0000000000 --- a/docs/devel/releasing.dot +++ /dev/null @@ -1,113 +0,0 @@ -// Build it with: -// $ dot -Tsvg releasing.dot >releasing.svg - -digraph tagged_release { - size = "5,5" - // Arrows go up. - rankdir = BT - subgraph left { - // Group the left nodes together. - ci012abc -> pr101 -> ci345cde -> pr102 - style = invis - } - subgraph right { - // Group the right nodes together. - version_commit -> dev_commit - style = invis - } - { // Align the version commit and the info about it. - rank = same - // Align them with pr101 - pr101 - version_commit - // release_info shows the change in the commit. - release_info - } - { // Align the dev commit and the info about it. - rank = same - // Align them with 345cde - ci345cde - dev_commit - dev_info - } - // Join the nodes from subgraph left. - pr99 -> ci012abc - pr102 -> pr100 - // Do the version node. - pr99 -> version_commit - dev_commit -> pr100 - tag -> version_commit - pr99 [ - label = "Merge PR #99" - shape = box - fillcolor = "#ccccff" - style = "filled" - fontname = "Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif" - ]; - ci012abc [ - label = "012abc" - shape = circle - fillcolor = "#ffffcc" - style = "filled" - fontname = "Consolas, Liberation Mono, Menlo, Courier, monospace" - ]; - pr101 [ - label = "Merge PR #101" - shape = box - fillcolor = "#ccccff" - style = "filled" - fontname = "Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif" - ]; - ci345cde [ - label = "345cde" - shape = circle - fillcolor = "#ffffcc" - style = "filled" - fontname = "Consolas, Liberation Mono, Menlo, Courier, monospace" - ]; - pr102 [ - label = "Merge PR #102" - shape = box - fillcolor = "#ccccff" - style = "filled" - fontname = "Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif" - ]; - version_commit [ - label = "678fed" - shape = circle - fillcolor = "#ccffcc" - style = "filled" - fontname = "Consolas, Liberation Mono, Menlo, Courier, monospace" - ]; - dev_commit [ - label = "456dcb" - shape = circle - fillcolor = "#ffffcc" - style = "filled" - fontname = "Consolas, Liberation Mono, Menlo, Courier, monospace" - ]; - pr100 [ - label = "Merge PR #100" - shape = box - fillcolor = "#ccccff" - style = "filled" - fontname = "Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif" - ]; - release_info [ - label = "pkg/version/base.go:\ngitVersion = \"v0.5\";" - shape = none - fontname = "Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif" - ]; - dev_info [ - label = "pkg/version/base.go:\ngitVersion = \"v0.5-dev\";" - shape = none - fontname = "Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif" - ]; - tag [ - label = "$ git tag -a v0.5" - fillcolor = "#ffcccc" - style = "filled" - fontname = "Helvetica Neue, Helvetica, Segoe UI, Arial, freesans, sans-serif" - ]; -} - diff --git a/docs/devel/releasing.png b/docs/devel/releasing.png deleted file mode 100644 index 935628deddc5ba9c608cd7f97d7c587bf519e333..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30693 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 A2LJ#7 diff --git a/docs/devel/releasing.svg b/docs/devel/releasing.svg deleted file mode 100644 index f703e6e2ac..0000000000 --- a/docs/devel/releasing.svg +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - -tagged_release - - -ci012abc - -012abc - - -pr101 - -Merge PR #101 - - -ci012abc->pr101 - - - - -ci345cde - -345cde - - -pr101->ci345cde - - - - -pr102 - -Merge PR #102 - - -ci345cde->pr102 - - - - -pr100 - -Merge PR #100 - - -pr102->pr100 - - - - -version_commit - -678fed - - -dev_commit - -456dcb - - -version_commit->dev_commit - - - - -dev_commit->pr100 - - - - -release_info -pkg/version/base.go: -gitVersion = "v0.5"; - - -dev_info -pkg/version/base.go: -gitVersion = "v0.5-dev"; - - -pr99 - -Merge PR #99 - - -pr99->ci012abc - - - - -pr99->version_commit - - - - -tag - -$ git tag -a v0.5 - - -tag->version_commit - - - - - From 612158b3192344b1059f174b47c8eb8afec368fe Mon Sep 17 00:00:00 2001 From: Isaac Hollander McCreery Date: Thu, 29 Oct 2015 16:06:55 -0700 Subject: [PATCH 14/19] A few more fixups --- release/build-official-release.sh | 2 +- release/cut-official-release.sh | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/release/build-official-release.sh b/release/build-official-release.sh index 176b32cb33..d539cdb049 100755 --- a/release/build-official-release.sh +++ b/release/build-official-release.sh @@ -88,7 +88,7 @@ ln -s ${KUBE_BUILD_DIR}/_output/release-tars/kubernetes.tar.gz ${KUBE_BUILD_DIR} MD5=$(md5 "${KUBE_BUILD_DIR}/kubernetes.tar.gz") SHA1=$(sha1 "${KUBE_BUILD_DIR}/kubernetes.tar.gz") -echo <<- EOM +cat <<- EOM Success! You must now do the following: (you may want to cut and paste these instructions elsewhere, step 1 can be spammy) diff --git a/release/cut-official-release.sh b/release/cut-official-release.sh index 328f90027f..da527426f3 100755 --- a/release/cut-official-release.sh +++ b/release/cut-official-release.sh @@ -187,12 +187,12 @@ function alpha-release() { - Finish the ${alpha_version} release build: - From this directory (clone of upstream/master), ./release/build-official-release.sh ${alpha_version} - - Figure out what the PR numbers for this release and last release are, and - get an api-token from GitHub (https://github.com/settings/tokens). From a - clone of kubernetes/contrib at upstream/master, - go run release-notes/release-notes.go --last-release-pr= --current-release-pr= --api-token= - Feel free to prune, but typically for patch releases we tend to include - everything in the release notes. + - Prep release notes: + - Figure out what the PR numbers for this release and last release are, and + get an api-token from GitHub (https://github.com/settings/tokens). From a + clone of kubernetes/contrib at upstream/master, + go run release-notes/release-notes.go --last-release-pr= --current-release-pr= --api-token= + Feel free to prune. EOM } @@ -226,12 +226,12 @@ function official-release() { git-push "${official_version}" cat >> "${INSTRUCTIONS}" <<- EOM -- Finish the ${version} release build: +- Finish the ${official_version} release build: - From this directory (clone of upstream/master), - ./release/build-official-release.sh ${version} + ./release/build-official-release.sh ${official_version} - Prep release notes: - From this directory (clone of upstream/master), run - ./hack/cherry_pick_list.sh ${version} + ./hack/cherry_pick_list.sh ${official_version} to get the release notes for the patch release you just created. Feel free to prune anything internal, but typically for patch releases we tend to include everything in the release notes. @@ -245,7 +245,7 @@ function verify-at-git-commit() { local -r git_commit="${1}" echo "Verifying we are at ${git_commit}." if [[ $(current-git-commit) != ${git_commit} ]]; then - echo <<- EOM + cat <<- EOM !!! We are not at commit ${git_commit}! (If you're cutting an official release, that probably means your release branch isn't frozen, so the commit you want to release isn't at HEAD of the release branch.)" From adaf9c3078201aa4ce43e97a4f07e701589f6ac2 Mon Sep 17 00:00:00 2001 From: Isaac Hollander McCreery Date: Fri, 30 Oct 2015 10:33:23 -0700 Subject: [PATCH 15/19] Only versionize docs at the beginning of a release cycle. --- release/cut-official-release.sh | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/release/cut-official-release.sh b/release/cut-official-release.sh index da527426f3..e396a51f83 100755 --- a/release/cut-official-release.sh +++ b/release/cut-official-release.sh @@ -148,6 +148,7 @@ EOM echo "Branching ${release_branch}." git checkout -b "${release_branch}" + versionize-docs-and-commit "${release_branch}" beta-release "${beta_version}" git-push ${release_branch} @@ -201,7 +202,6 @@ function beta-release() { echo "Doing a beta release of ${beta_version}." - versionize-docs-and-commit "${beta_version}" rev-version-and-commit "${beta_version}" echo "Tagging ${beta_version} at $(current-git-commit)." @@ -218,7 +218,6 @@ function official-release() { echo "Doing an official release of ${official_version}." - versionize-docs-and-commit "${official_version}" rev-version-and-commit "${official_version}" echo "Tagging ${official_version} at $(current-git-commit)." @@ -269,11 +268,11 @@ function verify-ancestor() { } function versionize-docs-and-commit() { - local -r version="${1}" - echo "Versionizing docs for ${version} and committing." + local -r release_branch="${1}" + echo "Versionizing docs for ${release_branch} and committing." # NOTE: This is using versionize-docs.sh at the release point. - ./build/versionize-docs.sh ${version} - git commit -am "Versioning docs and examples for ${version}." + ./build/versionize-docs.sh ${release_branch} + git commit -am "Versioning docs and examples for ${release_branch}." } function rev-version-and-commit() { From bc9feec409f0f96c3d72b12366a07ca2a0058496 Mon Sep 17 00:00:00 2001 From: Isaac Hollander McCreery Date: Mon, 2 Nov 2015 14:54:11 -0800 Subject: [PATCH 16/19] Versioned beta releases --- docs/design/versioning.md | 8 +++--- docs/devel/releasing.md | 10 +++++-- release/cut-official-release.sh | 46 ++++++++++++++++++++++++++------- 3 files changed, 48 insertions(+), 16 deletions(-) diff --git a/docs/design/versioning.md b/docs/design/versioning.md index a189d0cfa4..7b63059ce9 100644 --- a/docs/design/versioning.md +++ b/docs/design/versioning.md @@ -43,9 +43,9 @@ Legend: ### Minor version scheme and timeline * Kube X.Y.0-alpha.W, W > 0: Alpha releases are released roughly every two weeks directly from the master branch. No cherrypick releases. If there is a critical bugfix, a new release from master can be created ahead of schedule. -* Kube X.Y.Z-beta: When master is feature-complete for Kube X.Y, we will cut the release-X.Y branch 2 weeks prior to the desired X.Y.0 date and cherrypick only PRs essential to X.Y. This cut will be marked as X.Y.0-beta, and master will be revved to X.Y+1.0-alpha.0. -* Kube X.Y.0: Final release, cut from the release-X.Y branch cut two weeks prior. X.Y.1-beta will be tagged at the same commit on the same branch. X.Y.0 occur 3 to 4 months after X.Y-1.0. -* Kube X.Y.Z, Z > 0: [Patch releases](#patches) are released as we cherrypick commits into the release-X.Y branch, (which is at X.Y.Z-beta,) as needed. X.Y.Z is cut straight from the release-X.Y branch, and X.Y.Z+1-beta is tagged on the same commit. +* Kube X.Y.Z-beta.W: When master is feature-complete for Kube X.Y, we will cut the release-X.Y branch 2 weeks prior to the desired X.Y.0 date and cherrypick only PRs essential to X.Y. This cut will be marked as X.Y.0-beta.0, and master will be revved to X.Y+1.0-alpha.0. If we're not satisfied with X.Y.0-beta.0, we'll release other beta releases, (X.Y.0-beta.W | W > 0) as necessary. +* Kube X.Y.0: Final release, cut from the release-X.Y branch cut two weeks prior. X.Y.1-beta.0 will be tagged at the same commit on the same branch. X.Y.0 occur 3 to 4 months after X.Y-1.0. +* Kube X.Y.Z, Z > 0: [Patch releases](#patches) are released as we cherrypick commits into the release-X.Y branch, (which is at X.Y.Z-beta.W,) as needed. X.Y.Z is cut straight from the release-X.Y branch, and X.Y.Z+1-beta.0 is tagged on the same commit. ### Major version timeline @@ -53,7 +53,7 @@ There is no mandated timeline for major versions. They only occur when we need t ### CI version scheme -* Continuous integration versions also exist, and are versioned off of alpha and beta releases. X.Y.Z-alpha.W.C+aaaa is C commits after X.Y.Z-alpha.W, with an additional +aaaa build suffix added; X.Y.Z-beta.C+bbbb is C commits after X.Y.Z-beta, with an additional +bbbb build suffix added. Furthermore, builds that are built off of a dirty build tree, (with things in the tree that are not checked it,) it will be appended with -dirty. +* Continuous integration versions also exist, and are versioned off of alpha and beta releases. X.Y.Z-alpha.W.C+aaaa is C commits after X.Y.Z-alpha.W, with an additional +aaaa build suffix added; X.Y.Z-beta.W.C+bbbb is C commits after X.Y.Z-beta.W, with an additional +bbbb build suffix added. Furthermore, builds that are built off of a dirty build tree, (with things in the tree that are not checked it,) it will be appended with -dirty. ## Release versions as related to API versions diff --git a/docs/devel/releasing.md b/docs/devel/releasing.md index fad957b622..f430b3a395 100644 --- a/docs/devel/releasing.md +++ b/docs/devel/releasing.md @@ -56,14 +56,20 @@ from, and other prerequisites. * Alpha releases (`vX.Y.0-alpha.W`) are cut directly from `master`. * Alpha releases don't require anything besides green tests, (see below). -* Official releases (`vX.Y.Z`) are cut from their respective release branch, +* Beta releases (`vX.Y.Z-beta.W`) are cut from their respective release branch, `release-X.Y`. * Make sure all necessary cherry picks have been resolved. You should ensure that all outstanding cherry picks have been reviewed and merged and the branch validated on Jenkins. See [Cherry Picks](cherry-picks.md) for more information on how to manage cherry picks prior to cutting the release. + * Beta releases also require green tests, (see below). +* Official releases (`vX.Y.Z`) are cut from their respective release branch, + `release-X.Y`. + * Official releases should be similar or identical to their respective beta + releases, so have a look at the cherry picks that have been merged since + the beta release and question everything you find. * Official releases also require green tests, (see below). -* New release series are also cut direclty from `master`. +* New release series are also cut directly from `master`. * **This is a big deal!** If you're reading this doc for the first time, you probably shouldn't be doing this release, and should talk to someone on the release team. diff --git a/release/cut-official-release.sh b/release/cut-official-release.sh index e396a51f83..eed2fe31c4 100755 --- a/release/cut-official-release.sh +++ b/release/cut-official-release.sh @@ -43,6 +43,7 @@ function main() { # Get and verify version info local -r alpha_version_regex="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.0-alpha\\.([1-9][0-9]*)$" + local -r beta_version_regex="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)-beta\\.([1-9][0-9]*)$" local -r official_version_regex="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$" local -r series_version_regex="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$" if [[ "${new_version}" =~ $alpha_version_regex ]]; then @@ -50,6 +51,12 @@ function main() { local -r version_major="${BASH_REMATCH[1]}" local -r version_minor="${BASH_REMATCH[2]}" local -r version_alpha_rev="${BASH_REMATCH[3]}" + elif [[ "${new_version}" =~ $beta_version_regex ]]; then + local -r release_type='beta' + local -r version_major="${BASH_REMATCH[1]}" + local -r version_minor="${BASH_REMATCH[2]}" + local -r version_patch="${BASH_REMATCH[3]}" + local -r version_beta_rev="${BASH_REMATCH[4]}" elif [[ "${new_version}" =~ $official_version_regex ]]; then local -r release_type='official' local -r version_major="${BASH_REMATCH[1]}" @@ -114,11 +121,23 @@ EOM if [[ "${release_type}" == 'alpha' ]]; then local -r ancestor="v${version_major}.${version_minor}.0-alpha.$((${version_alpha_rev}-1))" + git checkout "${git_commit}" verify-at-git-commit "${git_commit}" verify-ancestor "${ancestor}" alpha-release "${new_version}" + elif [[ "${release_type}" == 'beta' ]]; then + local -r release_branch="release-${version_major}.${version_minor}" + local -r ancestor="v${version_major}.${version_minor}.${version_patch}-beta.$((${version_beta_rev}-1))" + + git checkout "${release_branch}" + verify-at-git-commit "${git_commit}" + verify-ancestor "${ancestor}" + + beta-release "${new_version}" + + git-push ${release_branch} elif [[ "${release_type}" == 'official' ]]; then local -r release_branch="release-${version_major}.${version_minor}" local -r beta_version="v${version_major}.${version_minor}.$((${version_patch}+1))-beta" @@ -130,6 +149,8 @@ EOM official-release "${new_version}" beta-release "${beta_version}" + + git-push ${release_branch} else # [[ "${release_type}" == 'series' ]] local -r release_branch="release-${version_major}.${version_minor}" local -r alpha_version="v${version_major}.$((${version_minor}+1)).0-alpha.0" @@ -151,6 +172,7 @@ EOM versionize-docs-and-commit "${release_branch}" beta-release "${beta_version}" + git-push ${release_branch} fi @@ -208,9 +230,13 @@ function beta-release() { git tag -a -m "Kubernetes pre-release ${beta_version}" "${beta_version}" git-push "${beta_version}" - # NOTE: We currently don't build/release beta versions, since they're almost - # identical to the prior version, so we don't prompt for build or release - # here. + # NOTE: We currently don't publish beta release notes, since they'll go out + # with the official release, so we don't prompt for compiling them here. + cat >> "${INSTRUCTIONS}" <<- EOM +- Finish the ${beta_version} release build: + - From this directory (clone of upstream/master), + ./release/build-official-release.sh ${beta_version} +EOM } function official-release() { @@ -245,9 +271,9 @@ function verify-at-git-commit() { echo "Verifying we are at ${git_commit}." if [[ $(current-git-commit) != ${git_commit} ]]; then cat <<- EOM -!!! We are not at commit ${git_commit}! (If you're cutting an official release, -that probably means your release branch isn't frozen, so the commit you want to -release isn't at HEAD of the release branch.)" +!!! We are not at commit ${git_commit}! (If you're cutting a beta or official +release, that probably means your release branch isn't frozen, so the commit +you want to release isn't at HEAD of the release branch.)" EOM exit 1 fi @@ -279,14 +305,14 @@ function rev-version-and-commit() { local -r version="${1}" local -r version_file="pkg/version/base.go" - local -r version_regex="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(-beta)?$" + local -r version_regex="^v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(-beta\\.(0|[1-9][0-9]*))?$" if [[ "${version}" =~ $version_regex ]]; then local -r version_major="${BASH_REMATCH[1]}" # We append a '+' to the minor version on a beta build per hack/lib/version.sh's logic. - if [[ "${BASH_REMATCH[4]}" == '-beta' ]]; then - local -r version_minor="${BASH_REMATCH[2]}+" - else + if [[ -z "${BASH_REMATCH[4]}" ]]; then local -r version_minor="${BASH_REMATCH[2]}" + else + local -r version_minor="${BASH_REMATCH[2]}+" fi else echo "!!! Something went wrong. Tried to rev version to invalid version; should not have gotten to this point." From 346676280fa29a8f770a1a1af3e20b600f59f235 Mon Sep 17 00:00:00 2001 From: Isaac Hollander McCreery Date: Mon, 2 Nov 2015 15:38:57 -0800 Subject: [PATCH 17/19] Update docs and prompts for better dry-runs and no more versionizing docs --- docs/devel/releasing.md | 68 ++++++++++++++++++++++++++++----- release/cut-official-release.sh | 13 +++++-- 2 files changed, 69 insertions(+), 12 deletions(-) diff --git a/docs/devel/releasing.md b/docs/devel/releasing.md index f430b3a395..671ab8afc0 100644 --- a/docs/devel/releasing.md +++ b/docs/devel/releasing.md @@ -148,12 +148,49 @@ then, run release/cut-official-release.sh "${VER}" "${GITHASH}" ``` -This will: +This will do a dry run of: 1. mark the `vX.Y.0-alpha.W` tag at the given git hash; 1. prompt you to do the remainder of the work, including building the appropriate binaries and pushing them to the appropriate places. +If you're satisfied with the result, run + +```console +release/cut-official-release.sh "${VER}" "${GITHASH}" --no-dry-run +``` + +and follow the instructions. + +#### Cutting an beta release (`vX.Y.Z-beta.W`) + +Figure out what version you're cutting, and + +```console +export VER="vX.Y.Z-beta.W" +``` + +then, run + +```console +release/cut-official-release.sh "${VER}" "${GITHASH}" +``` + +This will do a dry run of: + +1. do a series of commits on the release branch for `vX.Y.Z-beta`; +1. mark the `vX.Y.Z-beta` tag at the beta version commit; +1. prompt you to do the remainder of the work, including building the + appropriate binaries and pushing them to the appropriate places. + +If you're satisfied with the result, run + +```console +release/cut-official-release.sh "${VER}" "${GITHASH}" --no-dry-run +``` + +and follow the instructions. + #### Cutting an official release (`vX.Y.Z`) Figure out what version you're cutting, and @@ -168,18 +205,24 @@ then, run release/cut-official-release.sh "${VER}" "${GITHASH}" ``` -This will: +This will do a dry run of: -1. do a series of commits on the branch for `vX.Y.Z`, including versionizing - the documentation and doing the release version commit; +1. do a series of commits on the branch for `vX.Y.Z`; 1. mark the `vX.Y.Z` tag at the release version commit; 1. do a series of commits on the branch for `vX.Y.(Z+1)-beta` on top of the - previous commits, including versionizing the documentation and doing the - beta version commit; + previous commits; 1. mark the `vX.Y.(Z+1)-beta` tag at the beta version commit; 1. prompt you to do the remainder of the work, including building the appropriate binaries and pushing them to the appropriate places. +If you're satisfied with the result, run + +```console +release/cut-official-release.sh "${VER}" "${GITHASH}" --no-dry-run +``` + +and follow the instructions. + #### Branching a new release series (`vX.Y`) Once again, **this is a big deal!** If you're reading this doc for the first @@ -198,16 +241,23 @@ then, run release/cut-official-release.sh "${VER}" "${GITHASH}" ``` -This will: +This will do a dry run of: 1. mark the `vX.(Y+1).0-alpha.0` tag at the given git hash on `master`; 1. fork a new branch `release-X.Y` off of `master` at the given git hash; -1. do a series of commits on the branch for `vX.Y.0-beta`, including versionizing - the documentation and doing the release version commit; +1. do a series of commits on the branch for `vX.Y.0-beta`; 1. mark the `vX.Y.0-beta` tag at the beta version commit; 1. prompt you to do the remainder of the work, including building the appropriate binaries and pushing them to the appropriate places. +If you're satisfied with the result, run + +```console +release/cut-official-release.sh "${VER}" "${GITHASH}" --no-dry-run +``` + +and follow the instructions. + ### Publishing binaries and release notes The script you ran above will prompt you to take any remaining steps, including diff --git a/release/cut-official-release.sh b/release/cut-official-release.sh index eed2fe31c4..cc95056c22 100755 --- a/release/cut-official-release.sh +++ b/release/cut-official-release.sh @@ -93,11 +93,20 @@ function main() { local -r release_umask=${release_umask:-022} umask "${release_umask}" + local -r github="https://github.com/kubernetes/kubernetes.git" + declare -r DIR="/tmp/kubernetes-${release_type}-release-${new_version}-$(date +%s)" + # Start a tmp file that will hold instructions for the user. declare -r INSTRUCTIONS="/tmp/kubernetes-${release_type}-release-${new_version}-$(date +%s)-instructions" if $DRY_RUN; then cat > "${INSTRUCTIONS}" <<- EOM -Success! You would now do the following, if not a dry run: +Success on dry run! Do + + pushd ${DIR} + +to see what happened. + +You would now do the following, if not a dry run: EOM else @@ -107,8 +116,6 @@ Success! You must now do the following: EOM fi - local -r github="https://github.com/kubernetes/kubernetes.git" - declare -r DIR="/tmp/kubernetes-${release_type}-release-${new_version}-$(date +%s)" echo "Cloning from '${github}'..." git clone "${github}" "${DIR}" From a9fc43d12030bb718237bc15fe124e892e35beac Mon Sep 17 00:00:00 2001 From: Isaac Hollander McCreery Date: Tue, 3 Nov 2015 09:26:01 -0800 Subject: [PATCH 18/19] Fix releasing clause about cutting beta releases --- docs/devel/releasing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/devel/releasing.md b/docs/devel/releasing.md index 671ab8afc0..238f379152 100644 --- a/docs/devel/releasing.md +++ b/docs/devel/releasing.md @@ -74,7 +74,7 @@ from, and other prerequisites. probably shouldn't be doing this release, and should talk to someone on the release team. * New release series cut a new release branch, `release-X.Y`, off of - `master`, and also release the first beta in the series, `vX.Y.0-beta`. + `master`, and also release the first beta in the series, `vX.Y.0-beta.0`. * Every change in the `vX.Y` series from this point on will have to be cherry picked, so be sure you want to do this before proceeding. * You should still look for green tests, (see below). From ed7b42c4a3e4e3aad8e79d92ca28625165962a88 Mon Sep 17 00:00:00 2001 From: Isaac Hollander McCreery Date: Tue, 3 Nov 2015 09:42:49 -0800 Subject: [PATCH 19/19] Clarify -dirty language, and add --no-dry-run to usage --- docs/design/versioning.md | 4 ++-- release/cut-official-release.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/design/versioning.md b/docs/design/versioning.md index 7b63059ce9..341e3b36de 100644 --- a/docs/design/versioning.md +++ b/docs/design/versioning.md @@ -51,9 +51,9 @@ Legend: There is no mandated timeline for major versions. They only occur when we need to start the clock on deprecating features. A given major version should be the latest major version for at least one year from its original release date. -### CI version scheme +### CI and dev version scheme -* Continuous integration versions also exist, and are versioned off of alpha and beta releases. X.Y.Z-alpha.W.C+aaaa is C commits after X.Y.Z-alpha.W, with an additional +aaaa build suffix added; X.Y.Z-beta.W.C+bbbb is C commits after X.Y.Z-beta.W, with an additional +bbbb build suffix added. Furthermore, builds that are built off of a dirty build tree, (with things in the tree that are not checked it,) it will be appended with -dirty. +* Continuous integration versions also exist, and are versioned off of alpha and beta releases. X.Y.Z-alpha.W.C+aaaa is C commits after X.Y.Z-alpha.W, with an additional +aaaa build suffix added; X.Y.Z-beta.W.C+bbbb is C commits after X.Y.Z-beta.W, with an additional +bbbb build suffix added. Furthermore, builds that are built off of a dirty build tree, (during development, with things in the tree that are not checked it,) it will be appended with -dirty. ## Release versions as related to API versions diff --git a/release/cut-official-release.sh b/release/cut-official-release.sh index cc95056c22..3938566477 100755 --- a/release/cut-official-release.sh +++ b/release/cut-official-release.sh @@ -188,7 +188,7 @@ EOM } function usage() { - echo "Usage: ${0} " + echo "Usage: ${0} [--no-dry-run]" echo echo "See docs/devel/releasing.md for more info." }