|
1 | 1 | #!/bin/bash |
2 | 2 | # |
3 | 3 | # Usage: |
4 | | -# $ release.sh [-f] <organization/project-name> |
| 4 | +# $ release.sh [-f] <organization/project-name> [<new-version>] |
| 5 | +# |
| 6 | +# Args: |
| 7 | +# organization/project-name Required. The GitHub repo to release. |
| 8 | +# |
| 9 | +# new-version Optional. The new version number to use, |
| 10 | +# specified as M.N.0. If not specified, the |
| 11 | +# new version will be computed from existing |
| 12 | +# git tags. This flag should only be needed |
| 13 | +# when jumping to a non-sequential version |
| 14 | +# number. |
5 | 15 | # |
6 | 16 | # Options: |
7 | 17 | # -f Force; actually make and push the changes |
8 | 18 | # -h Print help message |
9 | 19 | # |
10 | | -# Example: |
11 | | -# # Shows what commands would be run. NO CHANGES ARE PUSHED |
12 | | -# $ release.sh googleapis/google-cloud-cpp-spanner |
13 | | -# |
14 | | -# # Shows commands AND PUSHES changes when -f is specified |
15 | | -# $ release.sh -f googleapis/google-cloud-cpp-spanner |
16 | | -# |
17 | 20 | # This script creates a "release" on github by doing the following: |
18 | | -# 1. Computes the next version to use |
| 21 | +# |
| 22 | +# 1. Computes the next version to use, if not specified on the command line |
19 | 23 | # 2. Creates and pushes the tag w/ the new version |
20 | 24 | # 3. Creates and pushes a new branch w/ the new version |
21 | 25 | # 4. Creates the "Pre-Release" in the GitHub UI. |
|
25 | 29 | # happen. Then run this script. After running this script, the user must still |
26 | 30 | # go to the GH UI where the new release will exist as a "pre-release", and edit |
27 | 31 | # the release notes. |
| 32 | +# |
| 33 | +# Examples: |
| 34 | +# |
| 35 | +# # NO CHANGES ARE PUSHED. Shows what commands would be run. |
| 36 | +# $ release.sh googleapis/google-cloud-cpp-spanner |
| 37 | +# |
| 38 | +# # NO CHANGES ARE PUSHED. Shows what commands would be run. |
| 39 | +# $ release.sh googleapis/google-cloud-cpp-spanner 2.0.0 |
| 40 | +# |
| 41 | +# # PUSHES CHANGES to release -spanner |
| 42 | +# $ release.sh -f googleapis/google-cloud-cpp-spanner |
| 43 | +# |
| 44 | +# # PUSHES CHANGES to release -spanner, setting its new version to 2.0.0 |
| 45 | +# $ release.sh -f googleapis/google-cloud-cpp-spanner 2.0.0 |
28 | 46 |
|
29 | 47 | set -eu |
30 | 48 |
|
31 | 49 | # Extracts all the documentation at the top of this file as the usage text. |
32 | 50 | readonly USAGE="$(sed -n '3,/^$/s/^# \?//p' "$0")" |
33 | 51 |
|
| 52 | +# Takes an optional list of strings to be printed with a trailing newline and |
| 53 | +# exits the program with code 1 |
| 54 | +function die_with_message() { |
| 55 | + for m in "$@"; do |
| 56 | + echo "$m" 1>&2 |
| 57 | + done |
| 58 | + exit 1 |
| 59 | +} |
| 60 | + |
34 | 61 | FORCE_FLAG="no" |
35 | 62 | while getopts "fh" opt "$@"; do |
36 | 63 | case "$opt" in |
37 | 64 | [f]) |
38 | 65 | FORCE_FLAG="yes";; |
39 | 66 | [h]) |
40 | | - echo "$USAGE" |
| 67 | + echo "${USAGE}" |
41 | 68 | exit 0;; |
42 | 69 | *) |
43 | | - echo "$USAGE" |
44 | | - exit 1;; |
| 70 | + die_with_message "${USAGE}";; |
45 | 71 | esac |
46 | 72 | done |
47 | 73 | shift $((OPTIND - 1)) |
48 | 74 | declare -r FORCE_FLAG |
49 | 75 |
|
50 | | -if [[ $# -ne 1 ]]; then |
51 | | - echo "Missing repo name, example googleapis/google-cloud-cpp-spanner" |
52 | | - echo "$USAGE" |
53 | | - exit 1; |
| 76 | +PROJECT_ARG="" |
| 77 | +VERSION_ARG="" |
| 78 | +if [[ $# -eq 1 ]]; then |
| 79 | + PROJECT_ARG="$1" |
| 80 | +elif [[ $# -eq 2 ]]; then |
| 81 | + PROJECT_ARG="$1" |
| 82 | + VERSION_ARG="$2" |
| 83 | +else |
| 84 | + die_with_message "Invalid arguments" "${USAGE}" |
54 | 85 | fi |
| 86 | +declare -r PROJECT_ARG |
| 87 | +declare -r VERSION_ARG |
55 | 88 |
|
56 | | -readonly PROJECT="$1" |
57 | | -readonly CLONE_URL= "[email protected]:${PROJECT}.git" |
58 | | -readonly TMP_DIR="$(mktemp -d "/tmp/${PROJECT//\//-}-release.XXXXXXXX")" |
| 89 | +readonly CLONE_URL= "[email protected]:${PROJECT_ARG}.git" |
| 90 | +readonly TMP_DIR="$(mktemp -d "/tmp/${PROJECT_ARG//\//-}-release.XXXXXXXX")" |
59 | 91 | readonly REPO_DIR="${TMP_DIR}/repo" |
60 | 92 |
|
61 | 93 | function banner() { |
@@ -87,25 +119,40 @@ trap exit_handler EXIT |
87 | 119 | # of the release. We also use 'hub' to do the clone so that the user is asked |
88 | 120 | # to authenticate at the beginning of the process rather than at the end. |
89 | 121 | if ! command -v hub > /dev/null; then |
90 | | - echo "Can't find 'hub' command" |
91 | | - echo "Maybe run: sudo apt install hub" |
92 | | - echo "Or build it from https://github.com/github/hub" |
93 | | - exit 1 |
| 122 | + die_with_message \ |
| 123 | + "Can't find 'hub' command" \ |
| 124 | + "Maybe run: sudo apt install hub" \ |
| 125 | + "Or build it from https://github.com/github/hub" |
94 | 126 | fi |
95 | 127 |
|
96 | | -banner "Starting release for ${PROJECT} (${CLONE_URL})" |
97 | | -hub clone "${PROJECT}" "${REPO_DIR}" # May force login to GH at this point |
| 128 | +banner "Starting release for ${PROJECT_ARG} (${CLONE_URL})" |
| 129 | +hub clone "${PROJECT_ARG}" "${REPO_DIR}" # May force login to GH at this point |
98 | 130 | cd "${REPO_DIR}" |
99 | 131 |
|
100 | 132 | # Figures out the most recent tagged version, and computes the next version. |
101 | 133 | readonly TAG="$(git describe --tags --abbrev=0 origin/master)" |
102 | 134 | readonly CUR_TAG="$(test -n "${TAG}" && echo "${TAG}" || echo "v0.0.0")" |
103 | | -readonly NEW_RELEASE="$(perl -pe 's/v0.(\d+).0/"v0.${\($1+1)}"/e' <<<"${CUR_TAG}")" |
104 | | -readonly NEW_TAG="${NEW_RELEASE}.0" |
105 | | -readonly NEW_BRANCH="${NEW_RELEASE}.x" |
| 135 | +readonly CUR_VERSION="${CUR_TAG#v}" |
| 136 | + |
| 137 | +NEW_VERSION="" |
| 138 | +if [[ -n "${VERSION_ARG}" ]]; then |
| 139 | + NEW_VERSION="${VERSION_ARG}" |
| 140 | +else |
| 141 | + # No new version specified; compute the new version number |
| 142 | + NEW_VERSION="$(perl -pe 's/(\d+).(\d+).(\d+)/"$1.${\($2+1)}.$3"/e' <<<"${CUR_VERSION}")" |
| 143 | +fi |
| 144 | +declare -r NEW_VERSION |
| 145 | + |
| 146 | +# Avoid handling patch releases for now, because we wouldn't need a new branch |
| 147 | +# for those. |
| 148 | +if ! grep -P "\d+\.\d+\.0" <<<"${NEW_VERSION}" > /dev/null; then |
| 149 | + die_with_message "Sorry, cannot handle patch releases (yet)" "${USAGE}" |
| 150 | +fi |
| 151 | + |
| 152 | +readonly NEW_TAG="v${NEW_VERSION}" |
| 153 | +readonly NEW_BRANCH="${NEW_TAG%.0}.x" |
106 | 154 |
|
107 | | -banner "Release info for ${NEW_RELEASE}" |
108 | | -echo "Current tag: ${CUR_TAG}" |
| 155 | +banner "Release info for ${CUR_TAG} -> ${NEW_TAG}" |
109 | 156 | echo " New tag: ${NEW_TAG}" |
110 | 157 | echo " New branch: ${NEW_BRANCH}" |
111 | 158 |
|
|
0 commit comments