diff --git a/README.md b/README.md index 3e1c006..3f92a2f 100644 --- a/README.md +++ b/README.md @@ -218,12 +218,18 @@ based on release tags. This script simplifies this process by performing the following steps: 1. **Retrieving the latest release tag:** The script starts by fetching the most - recent release tag by looking at the local data available in your repository. + recent semver release tag of the current branch, by looking at the local data + available in your repository. 1. **Prompting for a new release tag:** The user is then prompted to enter a new - release tag. To assist with this, the script displays the latest release tag - and provides a regular expression to validate the format of the new tag. -1. **Tagging the new release:** Once a valid new tag is entered, the script tags - the new release. -1. **Pushing the new tag to the remote:** Finally, the script pushes the new tag - to the remote repository. From here, you will need to create a new release in - GitHub and users can easily reference the new tag in their workflows. + release tag. To assist with this, the script displays the tag retrieved in + the previous step, and validates the format of the inputted tag (vX.X.X). The + user is also reminded to update the version field in package.json. +1. **Tagging the new release:** The script then tags a new release and syncs the + separate major tag (e.g. v1, v2) with the new release tag (e.g. v1.0.0, + v2.1.2). When the user is creating a new major release, the script + auto-detects this and creates a `releases/v#` branch for the previous major + version. +1. **Pushing changes to remote:** Finally, the script pushes the necessary + commits, tags and branches to the remote repository. From here, you will need + to create a new release in GitHub so users can easily reference the new tags + in their workflows. diff --git a/script/release b/script/release index 1ae8d07..9e23fd2 100755 --- a/script/release +++ b/script/release @@ -1,59 +1,126 @@ #!/bin/bash +# Exit early +# See: https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#The-Set-Builtin +set -e + # About: # # This is a helper script to tag and push a new release. GitHub Actions use # release tags to allow users to select a specific version of the action to use. # # See: https://github.com/actions/typescript-action#publishing-a-new-release +# See: https://github.com/actions/toolkit/blob/master/docs/action-versioning.md#recommendations # # This script will do the following: # -# 1. Get the latest release tag -# 2. Prompt the user for a new release tag -# 3. Tag the new release -# 4. Push the new tag to the remote +# 1. Retrieve the latest release tag +# 2. Display the latest release tag +# 3. Prompt the user for a new release tag +# 4. Validate the new release tag +# 5. Remind user to update the version field in package.json +# 6. Tag a new release +# 7. Set 'is_major_release' variable +# 8. Point separate major release tag (e.g. v1, v2) to the new release +# 9. Push the new tags (with commits, if any) to remote +# 10. If this is a major release, create a 'releases/v#' branch and push # # Usage: # # script/release +# Variables +semver_tag_regex='v[0-9]+\.[0-9]+\.[0-9]+$' +semver_tag_glob='v[0-9].[0-9].[0-9]*' +git_remote='origin' +major_semver_tag_regex='\(v[0-9]*\)' + # Terminal colors OFF='\033[0m' -RED='\033[0;31m' -GREEN='\033[0;32m' -BLUE='\033[0;34m' +BOLD_RED='\033[1;31m' +BOLD_GREEN='\033[1;32m' +BOLD_BLUE='\033[1;34m' +BOLD_PURPLE='\033[1;35m' +BOLD_UNDERLINED='\033[1;4m' +BOLD='\033[1m' -# Get the latest release tag -latest_tag=$(git describe --tags "$(git rev-list --tags --max-count=1)") - -if [[ -z "$latest_tag" ]]; then +# 1. Retrieve the latest release tag +if ! latest_tag=$(git describe --abbrev=0 --match="$semver_tag_glob"); then # There are no existing release tags echo -e "No tags found (yet) - Continue to create and push your first tag" latest_tag="[unknown]" fi -# Display the latest release tag -echo -e "The latest release tag is: ${BLUE}${latest_tag}${OFF}" +# 2. Display the latest release tag +echo -e "The latest release tag is: ${BOLD_BLUE}${latest_tag}${OFF}" -# Prompt the user for the new release tag +# 3. Prompt the user for a new release tag read -r -p 'Enter a new release tag (vX.X.X format): ' new_tag -# Validate the new release tag -tag_regex='v[0-9]+\.[0-9]+\.[0-9]+$' -if echo "$new_tag" | grep -q -E "$tag_regex"; then - echo -e "Tag: ${BLUE}$new_tag${OFF} is valid" +# 4. Validate the new release tag +if echo "$new_tag" | grep -q -E "$semver_tag_regex"; then + # Release tag is valid + echo -e "Tag: ${BOLD_BLUE}$new_tag${OFF} is valid syntax" else - # Release tag is not `vX.X.X` format - echo -e "Tag: ${BLUE}$new_tag${OFF} is ${RED}not valid${OFF} (must be in vX.X.X format)" + # Release tag is not in `vX.X.X` format + echo -e "Tag: ${BOLD_BLUE}$new_tag${OFF} is ${BOLD_RED}not valid${OFF} (must be in ${BOLD}vX.X.X${OFF} format)" exit 1 fi -# Tag the new release -git tag -a "$new_tag" -m "$new_tag Release" -echo -e "${GREEN}Tagged: $new_tag${OFF}" +# 5. Remind user to update the version field in package.json +echo -e -n "Make sure the version field in package.json is ${BOLD_BLUE}$new_tag${OFF}. Yes? [Y/${BOLD_UNDERLINED}n${OFF}] " +read -r YN -# Push the new tag to the remote -git push --tags -echo -e "${GREEN}Release tag pushed to remote${OFF}" -echo -e "${GREEN}Done!${OFF}" +if [[ ! ($YN == "y" || $YN == "Y") ]]; then + # Package.json version field is not up to date + echo -e "Please update the package.json version to ${BOLD_PURPLE}$new_tag${OFF} and commit your changes" + exit 1 +fi + +# 6. Tag a new release +git tag "$new_tag" --annotate --message "$new_tag Release" +echo -e "Tagged: ${BOLD_GREEN}$new_tag${OFF}" + +# 7. Set 'is_major_release' variable +latest_major_release_tag=$(expr "$latest_tag" : "$major_semver_tag_regex") +new_major_release_tag=$(expr "$new_tag" : "$major_semver_tag_regex") + +if ! [[ "$new_major_release_tag" = "$latest_major_release_tag" ]]; then + is_major_release='yes' +else + is_major_release='no' +fi + +# 8. Point separate major release tag (e.g. v1, v2) to the new release +if [ $is_major_release = 'yes' ]; then + # Create a new major verison tag and point it to this release + git tag "$new_major_release_tag" --annotate --message "$new_major_release_tag Release" + echo -e "New major version tag: ${BOLD_GREEN}$new_major_release_tag${OFF}" +else + # Update the major verison tag to point it to this release + git tag "$latest_major_release_tag" --force --annotate --message "Sync $latest_major_release_tag tag with $new_tag" + echo -e "Synced ${BOLD_GREEN}$latest_major_release_tag${OFF} with ${BOLD_GREEN}$new_tag${OFF}" +fi + +# 9. Push the new tags (with commits, if any) to remote +git push --follow-tags + +if [ $is_major_release = 'yes' ]; then + # New major version tag is pushed with the '--follow-tags' flags + echo -e "Tags: ${BOLD_GREEN}$new_major_release_tag${OFF} and ${BOLD_GREEN}$new_tag${OFF} pushed to remote" +else + # Force push the updated major version tag + git push $git_remote "$latest_major_release_tag" --force + echo -e "Tags: ${BOLD_GREEN}$latest_major_release_tag${OFF} and ${BOLD_GREEN}$new_tag${OFF} pushed to remote" +fi + +# 10. If this is a major release, create a 'releases/v#' branch and push +if [ $is_major_release = 'yes' ]; then + git branch "releases/$latest_major_release_tag" "$latest_major_release_tag" + echo -e "Branch: ${BOLD_BLUE}releases/$latest_major_release_tag${OFF} created from ${BOLD_BLUE}$latest_major_release_tag${OFF} tag" + git push --set-upstream $git_remote "releases/$latest_major_release_tag" + echo -e "Branch: ${BOLD_GREEN}releases/$latest_major_release_tag${OFF} pushed to remote" +fi + +# Completed +echo -e "${BOLD_GREEN}Done!${OFF}"