Skip to content

Commit

Permalink
add automated release targets (#41)
Browse files Browse the repository at this point in the history
  • Loading branch information
brycahta authored Feb 8, 2021
1 parent 3e18336 commit 1673039
Show file tree
Hide file tree
Showing 5 changed files with 520 additions and 0 deletions.
17 changes: 17 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,20 @@ jobs:

- name: Release Assets
run: make release

postRelease:
name: Post Release
runs-on: ubuntu-20.04
needs: [release]
if: github.event_name == 'push' && contains(github.ref, 'refs/tags/')
steps:
- name: Set up Go 1.x
uses: actions/setup-go@v2
with:
go-version: ${{ env.DEFAULT_GO_VERSION }}

- name: Check out code into the Go module directory
uses: actions/checkout@v2

- name: Sync to Homebrew
run: make homebrew-sync
30 changes: 30 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,33 @@ release: build-binaries build-docker-images upload-resources-to-github

help:
@grep -E '^[a-zA-Z_-]+:.*$$' $(MAKEFILE_LIST) | sort

## Targets intended to be run in preparation for a new release
draft-release-notes:
${MAKEFILE_PATH}/scripts/draft-release-notes

create-local-release-tag-major:
${MAKEFILE_PATH}/scripts/create-local-tag-for-release -m

create-local-release-tag-minor:
${MAKEFILE_PATH}/scripts/create-local-tag-for-release -i

create-local-release-tag-patch:
${MAKEFILE_PATH}/scripts/create-local-tag-for-release -p

create-release-prep-pr:
${MAKEFILE_PATH}/scripts/prepare-for-release

create-release-prep-pr-draft:
${MAKEFILE_PATH}/scripts/prepare-for-release -d

release-prep-major: create-local-release-tag-major create-release-prep-pr

release-prep-minor: create-local-release-tag-minor create-release-prep-pr

release-prep-patch: create-local-release-tag-patch create-release-prep-pr

release-prep-custom: # Run make NEW_VERSION=v1.2.3 release-prep-custom to prep for a custom release version
ifdef NEW_VERSION
$(shell echo "${MAKEFILE_PATH}/scripts/create-local-tag-for-release -v $(NEW_VERSION) && echo && make create-release-prep-pr")
endif
150 changes: 150 additions & 0 deletions scripts/create-local-tag-for-release
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#!/bin/bash

# Script to create a new local tag in preparation for a release
# This script is idempotent i.e. it always fetches remote tags to create the new tag.
# E.g. If the current remote release tag is v1.0.0,
## 1) running `create-local-tag-for-release -p` will create a new tag v1.0.1
## 2) immediately running `create-local-tag-for-release -m` will create a new tag v2.0.0

set -euo pipefail

REPO_ROOT_PATH="$( cd "$(dirname "$0")"; cd ../; pwd -P )"
MAKEFILE_PATH=$REPO_ROOT_PATH/Makefile
TAG_REGEX="^v[0-9]+\.[0-9]+\.[0-9]+(-[a-zA-Z]*)?$"

HELP=$(cat << 'EOM'
Create a new local tag in preparation for a release. This script is idempotent i.e. it always fetches remote tags to create the new tag.
Usage: create-local-tag-for-release [options]
Options:
-v new tag / version number. The script relies on the user to specify a valid and accurately incremented tag.
-m increment major version
-i increment minor version
-p increment patch version
-h help
Examples:
create-local-tag-for-release -v v1.0.0 Create local tag for new version v1.0.0
create-local-tag-for-release -i Create local tag for new version by incrementing minor version only (previous tag=v1.0.0, new tag=v1.1.0)
EOM
)

MAJOR_INC=false
MINOR_INC=false
PATCH_INC=false
NEW_TAG=""
CURR_REMOTE_RELEASE_TAG=""

process_args() {
while getopts "hmipv:" opt; do
case ${opt} in
h )
echo -e "$HELP" 1>&2
exit 0
;;
m )
MAJOR_INC=true
;;
i )
MINOR_INC=true
;;
p )
PATCH_INC=true
;;
v )
NEW_TAG="${OPTARG}"
;;
\? )
echo "$HELP" 1>&2
exit 0
;;
esac
done
}

validate_args() {
if [[ ! -z $NEW_TAG ]]; then
if ! [[ $NEW_TAG =~ $TAG_REGEX ]]; then
echo "❌ Invalid new tag specified $NEW_TAG. Examples: v1.2.3, v1.2.3-dirty"
exit 1
fi

echo "🥑 Using the new tag specified with -v flag. All other flags, if specified, will be ignored."
echo " NOTE:The script relies on the user to specify a valid and accurately incremented tag."
return
fi

if ($MAJOR_INC && $MINOR_INC) || ($MAJOR_INC && $PATCH_INC) || ($MINOR_INC && $PATCH_INC); then
echo "❌ Invalid arguments passed. Specify only one of 3 tag parts to increment for the new tag: -m (major) or -i (minor) or -p (patch)."
exit 1
fi

if $MAJOR_INC || $MINOR_INC || $PATCH_INC; then
return
fi

echo -e "❌ Invalid arguments passed. Specify atleast one argument.\n$HELP"
exit 1
}

sync_local_tags_from_remote() {
# setup remote upstream tracking to fetch tags
git remote add the-real-upstream https://github.com/awslabs/aws-simple-ec2-cli.git &> /dev/null || true
git fetch the-real-upstream

# delete all local tags
git tag -l | xargs git tag -d

# fetch remote tags
git fetch the-real-upstream --tags

# record the latest release tag in remote, before creating a new tag
CURR_REMOTE_RELEASE_TAG=$(get_latest_tag)

# clean up tracking
git remote remove the-real-upstream
}

create_tag() {
git tag $NEW_TAG
echo -e "\n✅ Created new tag $NEW_TAG (Current latest release tag in remote: v$CURR_REMOTE_RELEASE_TAG)\n"
exit 0
}

get_latest_tag() {
make -s -f $MAKEFILE_PATH latest-release-tag | cut -b 2-
}

main() {
process_args "$@"
validate_args

sync_local_tags_from_remote

# if new tag is specified, create it
if [[ ! -z $NEW_TAG ]]; then
create_tag
fi

# increment version
if $MAJOR_INC || $MINOR_INC || $PATCH_INC; then
curr_major_v=$(echo $CURR_REMOTE_RELEASE_TAG | tr '.' '\n' | head -1)
curr_minor_v=$(echo $CURR_REMOTE_RELEASE_TAG | tr '.' '\n' | head -2 | tail -1)
curr_patch_v=$(echo $CURR_REMOTE_RELEASE_TAG | tr '.' '\n' | tail -1)

if [[ $MAJOR_INC == true ]]; then
new_major_v=$(echo $(($curr_major_v + 1)))
NEW_TAG=$(echo v$new_major_v.0.0)
elif [[ $MINOR_INC == true ]]; then
new_minor_v=$(echo $(($curr_minor_v + 1)))
NEW_TAG=$(echo v$curr_major_v.$new_minor_v.0)
elif [[ $PATCH_INC == true ]]; then
new_patch_v=$(echo $(($curr_patch_v + 1)))
NEW_TAG=$(echo v$curr_major_v.$curr_minor_v.$new_patch_v)
fi
create_tag
fi
}

main "$@"
28 changes: 28 additions & 0 deletions scripts/draft-release-notes
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#!/usr/bin/env bash
set -euo pipefail

GIT_REPO_ROOT=$(git rev-parse --show-toplevel)
BUILD_DIR="${GIT_REPO_ROOT}/build"

RELEASE_NOTES="${BUILD_DIR}/release-notes.md"
touch "${RELEASE_NOTES}"

>&2 git fetch --all --tags

if git describe HEAD --tags | grep -Eq "^v[0-9]+(\.[0-9]+)*(-[a-z0-9]+)?$"; then
LAST_RELEASE_HASH=$(git rev-list --tags --max-count=1 --skip=1 --no-walk)
else
TAG=$(git describe HEAD --tags | grep -Eo "^v[0-9]+(\.[0-9]+)*")
LAST_RELEASE_HASH=$(git rev-list -1 $TAG)
fi

echo "## Changes" | tee -a "${RELEASE_NOTES}"
for change in $(git rev-list $LAST_RELEASE_HASH..HEAD); do
one_line_msg=$(git --no-pager log --pretty='%s (thanks to %an)' "${change}" -n1 | sed 's/^\[.*\]//' | xargs)
# render markdown links for cross-posting release notes
pr_num=$(echo $one_line_msg | grep -Eo '(#[0-9]*)' || [[ $? == 1 ]])
md_link="[$pr_num](https://github.com/awslabs/aws-simple-ec2-cli/pull/${pr_num:1})"
echo " - ${one_line_msg/\($pr_num\)/$md_link}" | tee -a "${RELEASE_NOTES}"
done

>&2 echo -e "\n\nRelease notes file: ${RELEASE_NOTES}"
Loading

0 comments on commit 1673039

Please sign in to comment.