Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve release script #917

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 16 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -217,13 +217,19 @@ GitHub Actions allows users to select a specific version of the action to use,
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.
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.
1. **Retrieving the latest release tag:** The script starts by fetching the
most 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 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.
121 changes: 94 additions & 27 deletions script/release
Original file line number Diff line number Diff line change
@@ -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'

# Get the latest release tag
latest_tag=$(git describe --tags "$(git rev-list --tags --max-count=1)")
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'

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

# 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

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

# Tag the new release
git tag -a "$new_tag" -m "$new_tag Release"
echo -e "${GREEN}Tagged: $new_tag${OFF}"
# 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

# Push the new tag to the remote
git push --tags
echo -e "${GREEN}Release tag pushed to remote${OFF}"
echo -e "${GREEN}Done!${OFF}"
# Completed
echo -e "${BOLD_GREEN}Done!${OFF}"