|
1 | 1 | #!/bin/bash |
2 | 2 |
|
| 3 | +# Exit early |
| 4 | +# See: https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#The-Set-Builtin |
| 5 | +set -e |
| 6 | + |
3 | 7 | # About: |
4 | 8 | # |
5 | 9 | # This is a helper script to tag and push a new release. GitHub Actions use |
6 | 10 | # release tags to allow users to select a specific version of the action to use. |
7 | 11 | # |
8 | 12 | # See: https://github.com/actions/typescript-action#publishing-a-new-release |
| 13 | +# See: https://github.com/actions/toolkit/blob/master/docs/action-versioning.md#recommendations |
9 | 14 | # |
10 | 15 | # This script will do the following: |
11 | 16 | # |
12 | | -# 1. Get the latest release tag |
13 | | -# 2. Prompt the user for a new release tag |
14 | | -# 3. Tag the new release |
15 | | -# 4. Push the new tag to the remote |
| 17 | +# 1. Retrieve the latest release tag |
| 18 | +# 2. Display the latest release tag |
| 19 | +# 3. Prompt the user for a new release tag |
| 20 | +# 4. Validate the new release tag |
| 21 | +# 5. Remind user to update the version field in package.json |
| 22 | +# 6. Tag a new release |
| 23 | +# 7. Set 'is_major_release' variable |
| 24 | +# 8. Point separate major release tag (e.g. v1, v2) to the new release |
| 25 | +# 9. Push the new tags (with commits, if any) to remote |
| 26 | +# 10. If this is a major release, create a 'releases/v#' branch and push |
16 | 27 | # |
17 | 28 | # Usage: |
18 | 29 | # |
19 | 30 | # script/release |
20 | 31 |
|
| 32 | +# Variables |
| 33 | +semver_tag_regex='v[0-9]+\.[0-9]+\.[0-9]+$' |
| 34 | +semver_tag_glob='v[0-9].[0-9].[0-9]*' |
| 35 | +git_remote='origin' |
| 36 | +major_semver_tag_regex='\(v[0-9]*\)' |
| 37 | + |
21 | 38 | # Terminal colors |
22 | 39 | OFF='\033[0m' |
23 | | -RED='\033[0;31m' |
24 | | -GREEN='\033[0;32m' |
25 | | -BLUE='\033[0;34m' |
26 | | - |
27 | | -# Get the latest release tag |
28 | | -latest_tag=$(git describe --tags "$(git rev-list --tags --max-count=1)") |
| 40 | +BOLD_RED='\033[1;31m' |
| 41 | +BOLD_GREEN='\033[1;32m' |
| 42 | +BOLD_BLUE='\033[1;34m' |
| 43 | +BOLD_PURPLE='\033[1;35m' |
| 44 | +BOLD_UNDERLINED='\033[1;4m' |
| 45 | +BOLD='\033[1m' |
29 | 46 |
|
30 | | -if [[ -z "$latest_tag" ]]; then |
| 47 | +# 1. Retrieve the latest release tag |
| 48 | +if ! latest_tag=$(git describe --abbrev=0 --match="$semver_tag_glob"); then |
31 | 49 | # There are no existing release tags |
32 | 50 | echo -e "No tags found (yet) - Continue to create and push your first tag" |
33 | 51 | latest_tag="[unknown]" |
34 | 52 | fi |
35 | 53 |
|
36 | | -# Display the latest release tag |
37 | | -echo -e "The latest release tag is: ${BLUE}${latest_tag}${OFF}" |
| 54 | +# 2. Display the latest release tag |
| 55 | +echo -e "The latest release tag is: ${BOLD_BLUE}${latest_tag}${OFF}" |
38 | 56 |
|
39 | | -# Prompt the user for the new release tag |
| 57 | +# 3. Prompt the user for a new release tag |
40 | 58 | read -r -p 'Enter a new release tag (vX.X.X format): ' new_tag |
41 | 59 |
|
42 | | -# Validate the new release tag |
43 | | -tag_regex='v[0-9]+\.[0-9]+\.[0-9]+$' |
44 | | -if echo "$new_tag" | grep -q -E "$tag_regex"; then |
45 | | - echo -e "Tag: ${BLUE}$new_tag${OFF} is valid" |
| 60 | +# 4. Validate the new release tag |
| 61 | +if echo "$new_tag" | grep -q -E "$semver_tag_regex"; then |
| 62 | + # Release tag is valid |
| 63 | + echo -e "Tag: ${BOLD_BLUE}$new_tag${OFF} is valid syntax" |
46 | 64 | else |
47 | | - # Release tag is not `vX.X.X` format |
48 | | - echo -e "Tag: ${BLUE}$new_tag${OFF} is ${RED}not valid${OFF} (must be in vX.X.X format)" |
| 65 | + # Release tag is not in `vX.X.X` format |
| 66 | + echo -e "Tag: ${BOLD_BLUE}$new_tag${OFF} is ${BOLD_RED}not valid${OFF} (must be in ${BOLD}vX.X.X${OFF} format)" |
| 67 | + exit 1 |
| 68 | +fi |
| 69 | + |
| 70 | +# 5. Remind user to update the version field in package.json |
| 71 | +echo -e -n "Make sure the version field in package.json is ${BOLD_BLUE}$new_tag${OFF}. Yes? [Y/${BOLD_UNDERLINED}n${OFF}] " |
| 72 | +read -r YN |
| 73 | + |
| 74 | +if [[ ! ($YN == "y" || $YN == "Y") ]]; then |
| 75 | + # Package.json version field is not up to date |
| 76 | + echo -e "Please update the package.json version to ${BOLD_PURPLE}$new_tag${OFF} and commit your changes" |
49 | 77 | exit 1 |
50 | 78 | fi |
51 | 79 |
|
52 | | -# Tag the new release |
53 | | -git tag -a "$new_tag" -m "$new_tag Release" |
54 | | -echo -e "${GREEN}Tagged: $new_tag${OFF}" |
| 80 | +# 6. Tag a new release |
| 81 | +git tag "$new_tag" --annotate --message "$new_tag Release" |
| 82 | +echo -e "Tagged: ${BOLD_GREEN}$new_tag${OFF}" |
| 83 | + |
| 84 | +# 7. Set 'is_major_release' variable |
| 85 | +latest_major_release_tag=$(expr "$latest_tag" : "$major_semver_tag_regex") |
| 86 | +new_major_release_tag=$(expr "$new_tag" : "$major_semver_tag_regex") |
| 87 | + |
| 88 | +if ! [[ "$new_major_release_tag" = "$latest_major_release_tag" ]]; then |
| 89 | + is_major_release='yes' |
| 90 | +else |
| 91 | + is_major_release='no' |
| 92 | +fi |
| 93 | + |
| 94 | +# 8. Point separate major release tag (e.g. v1, v2) to the new release |
| 95 | +if [ $is_major_release = 'yes' ]; then |
| 96 | + # Create a new major verison tag and point it to this release |
| 97 | + git tag "$new_major_release_tag" --annotate --message "$new_major_release_tag Release" |
| 98 | + echo -e "New major version tag: ${BOLD_GREEN}$new_major_release_tag${OFF}" |
| 99 | +else |
| 100 | + # Update the major verison tag to point it to this release |
| 101 | + git tag "$latest_major_release_tag" --force --annotate --message "Sync $latest_major_release_tag tag with $new_tag" |
| 102 | + echo -e "Synced ${BOLD_GREEN}$latest_major_release_tag${OFF} with ${BOLD_GREEN}$new_tag${OFF}" |
| 103 | +fi |
| 104 | + |
| 105 | +# 9. Push the new tags (with commits, if any) to remote |
| 106 | +git push --follow-tags |
| 107 | + |
| 108 | +if [ $is_major_release = 'yes' ]; then |
| 109 | + # New major version tag is pushed with the '--follow-tags' flags |
| 110 | + echo -e "Tags: ${BOLD_GREEN}$new_major_release_tag${OFF} and ${BOLD_GREEN}$new_tag${OFF} pushed to remote" |
| 111 | +else |
| 112 | + # Force push the updated major version tag |
| 113 | + git push $git_remote "$latest_major_release_tag" --force |
| 114 | + echo -e "Tags: ${BOLD_GREEN}$latest_major_release_tag${OFF} and ${BOLD_GREEN}$new_tag${OFF} pushed to remote" |
| 115 | +fi |
| 116 | + |
| 117 | +# 10. If this is a major release, create a 'releases/v#' branch and push |
| 118 | +if [ $is_major_release = 'yes' ]; then |
| 119 | + git branch "releases/$latest_major_release_tag" "$latest_major_release_tag" |
| 120 | + echo -e "Branch: ${BOLD_BLUE}releases/$latest_major_release_tag${OFF} created from ${BOLD_BLUE}$latest_major_release_tag${OFF} tag" |
| 121 | + git push --set-upstream $git_remote "releases/$latest_major_release_tag" |
| 122 | + echo -e "Branch: ${BOLD_GREEN}releases/$latest_major_release_tag${OFF} pushed to remote" |
| 123 | +fi |
55 | 124 |
|
56 | | -# Push the new tag to the remote |
57 | | -git push --tags |
58 | | -echo -e "${GREEN}Release tag pushed to remote${OFF}" |
59 | | -echo -e "${GREEN}Done!${OFF}" |
| 125 | +# Completed |
| 126 | +echo -e "${BOLD_GREEN}Done!${OFF}" |
0 commit comments