#!/bin/bash # Script to: ## 1) create and checkout a new branch with the latest tag name ## 2) update AEMM and Helm chart versions ## 3) commit release prep changes to new branch ## 4) create a PR from the new branch to upstream/main ## The following files are updated in step (2): ### - helm charts' Chart.yaml ### - helm charts' values.yaml ### - helm charts' README ### - README.md ### - version.txt # Prerequisites: ## 1) git and gh cli (make sure to use gh cli before running this script as authentication is required) ## 2) git tracking is expected to be set as follows: origin=fork (e.g. https://github.com/pdk27/amazon-ec2-metadata-mock-1.git), upstream=https://github.com/aws/amazon-ec2-metadata-mock.git ## 3) local tag creation is separated from this script and a new tag must be created before this script is run. This is automated when this script is run via make targets. # NOTE: only the files updated by this script is included in the commit / PR i.e. release version updates in $FILES # This script is NOT intended to be combined with other unmerged local changes set -euo pipefail REPO_ROOT_PATH="$( cd "$(dirname "$0")"; cd ../; pwd -P )" MAKEFILE_PATH=$REPO_ROOT_PATH/Makefile LATEST_VERSION=$(make -s -f $MAKEFILE_PATH latest-release-tag | cut -b 2- ) PREVIOUS_VERSION=$(make -s -f $MAKEFILE_PATH previous-release-tag | cut -b 2- ) # files with versions, to update REPO_README=$REPO_ROOT_PATH/README.md APP_VERSION=$REPO_ROOT_PATH/pkg/cmd/root/version.txt CHART=$REPO_ROOT_PATH/helm/amazon-ec2-metadata-mock/Chart.yaml CHART_VALUES=$REPO_ROOT_PATH/helm/amazon-ec2-metadata-mock/values.yaml CHART_README=$REPO_ROOT_PATH/helm/amazon-ec2-metadata-mock/README.md FILES=("$REPO_README" "$CHART" "$CHART_README" "$CHART_VALUES" "$APP_VERSION") FILES_CHANGED=() # release prep LATEST_TAG="v$LATEST_VERSION" NEW_BRANCH="pr/$LATEST_TAG-release" COMMIT_MESSAGE="πŸ₯‘πŸ€– $LATEST_TAG release prep [Skip Helm E2E Tests] πŸ€–πŸ₯‘" # PR details DEFAULT_REPO_FULL_NAME=$(make -s -f $MAKEFILE_PATH repo-full-name) PR_BASE=main # target PR_TITLE="πŸ₯‘πŸ€– $LATEST_TAG release prep" PR_BODY="πŸ₯‘πŸ€– Auto-generated PR for $LATEST_TAG release. Updating release versions in repo." PR_LABEL_1="release-prep" PR_LABEL_2="πŸ€– auto-generatedπŸ€–" HELP=$(cat << 'EOM' Update repo with the new release version and create a pr from a new release prep branch. This script prompts the user with complete details about the PR before pushing the new local branch to remote and creating the PR. The new release version is the latest local git tag. Note: The local tag creation for a new release is separated from this script. A new tag must be created before this script is run which is automated when this script is run via make targets. Usage: prepare-for-release [options] Options: -d create a draft pr -r target repo full name for the pr (default: aws/amazon-ec2-metadata-mock) -h help Examples: prepare-for-release -d update release version in repo and create a draft pr against aws/amazon-ec2-metadata-mock prepare-for-release -r username/amazon-ec2-metadata-mock update release version in repo and create a pr against username/amazon-ec2-metadata-mock EOM ) DRAFT=false REPO_FULL_NAME="" NEED_ROLLBACK=true process_args() { while getopts "hdr:" opt; do case ${opt} in h ) echo -e "$HELP" 1>&2 exit 0 ;; d ) DRAFT=true ;; r ) # todo: validate $REPO_FULL_NAME REPO_FULL_NAME="${OPTARG}" ;; \? ) echo "$HELP" 1>&2 exit 0 ;; esac done # set repo full name to the default value if unset if [ -z $REPO_FULL_NAME ]; then REPO_FULL_NAME=$DEFAULT_REPO_FULL_NAME fi } # output formatting [[ -z $TERM ]] || export TERM=linux RED=$(tput setaf 1) MAGENTA=$(tput setaf 5) RESET_FMT=$(tput sgr 0) BOLD=$(tput bold) # verify origin tracking before creating and pushing new branches verify_origin_tracking() { origin=$(git remote get-url origin 2>&1) || true if [[ $origin == "fatal: No such remote 'origin'" ]] || [[ $origin == "https://github.com/aws/amazon-ec2-metadata-mock.git" ]]; then echo -e "❌ ${RED}Expected remote 'origin' to be tracking fork but found \"$origin\". Set it up before running this script again.${RESET_FMT}" NEED_ROLLBACK=false exit 1 fi } create_release_branch() { exists=$(git checkout -b $NEW_BRANCH 2>&1) || true if [[ $exists == "fatal: A branch named '$NEW_BRANCH' already exists." ]]; then echo -e "❌ ${RED}$exists${RESET_FMT}" NEED_ROLLBACK=false exit 1 fi echo -e "βœ… ${BOLD}Created new release branch $NEW_BRANCH\n\n${RESET_FMT}" } update_versions() { # update release version for release prep echo -e "πŸ₯‘ Attempting to update AEMM release version and Helm chart version in preparation for a new release." for f in "${FILES[@]}"; do has_incorrect_version=$(cat $f | grep $PREVIOUS_VERSION) if [[ ! -z $has_incorrect_version ]]; then sed -i '' "s/$PREVIOUS_VERSION/$LATEST_VERSION/g" $f FILES_CHANGED+=("$f") fi done if [[ ${#FILES_CHANGED[@]} -eq 0 ]]; then echo -e "\nNo files were modified. Either all files already use git the latest release version $LATEST_VERSION or the files don't currently have the previous version $PREVIOUS_VERSION." else echo -e "βœ…βœ… ${BOLD}Updated versions from $PREVIOUS_VERSION to $LATEST_VERSION in files: \n$(echo "${FILES_CHANGED[@]}" | tr ' ' '\n')" echo -e "To see changes, run \`git diff HEAD^ HEAD\`${RESET_FMT}" fi echo } commit_changes() { echo -e "\nπŸ₯‘ Adding and committing release version changes." git add "${FILES_CHANGED[@]}" git commit -m"$COMMIT_MESSAGE" echo -e "βœ…βœ…βœ… ${BOLD}Committed release prep changes to new branch $NEW_BRANCH with commit message '$COMMIT_MESSAGE'\n\n${RESET_FMT}" } confirm_with_user_and_create_pr(){ git checkout $NEW_BRANCH # checkout new branch before printing git diff echo -e "\nπŸ₯‘${BOLD}The following PR will be created:\n" cat << EOM PR draft mode: $DRAFT PR target repository: $REPO_FULL_NAME PR source branch: $NEW_BRANCH PR target branch: $REPO_FULL_NAME/$PR_BASE PR title: $PR_TITLE PR body: $PR_BODY PR labels: $PR_LABEL_1, $PR_LABEL_2 Changes in $NEW_BRANCH: ${MAGENTA}$(git diff HEAD^ HEAD)${RESET_FMT} EOM while true; do echo -e "πŸ₯‘${BOLD}Do you wish to create the release prep PR? Enter y/n" read -p "" yn case $yn in [Yy]* ) create_pr; break;; [Nn]* ) rollback; exit;; * ) echo "πŸ₯‘Please answer yes or no.";; esac done echo "${RESET_FMT}" } create_pr() { git push -u origin $NEW_BRANCH # sets source branch for PR to NEW_BRANCH on the fork or origin git checkout $NEW_BRANCH # checkout new branch before creating a pr if [[ $DRAFT == true ]]; then gh pr create \ --repo "$REPO_FULL_NAME" \ --base "$PR_BASE" \ --title "$PR_TITLE" \ --body "$PR_BODY" \ --label "$PR_LABEL_1" --label "$PR_LABEL_2" \ --draft else gh pr create \ --repo "$REPO_FULL_NAME" \ --base "$PR_BASE" \ --title "$PR_TITLE" \ --body "$PR_BODY" \ --label "$PR_LABEL_1" --label "$PR_LABEL_2" fi if [[ $? == 0 ]]; then echo -e "βœ…βœ…βœ…βœ… ${BOLD}Created $LATEST_TAG release prep PR\n${RESET_FMT}" else echo -e "❌ ${RED}PR creation failed.${RESET_FMT}❌" exit 1 fi } # rollback partial changes to make this script atomic, iff the current execution of the script created a new branch and made changes rollback() { if [[ $NEED_ROLLBACK == true ]]; then echo "πŸ₯‘${BOLD}Rolling back" # checkout of current branch to main git checkout main # delete local and remote release branch only if current execution of the script created them git branch -D $NEW_BRANCH git push origin --delete $NEW_BRANCH fi echo "${RESET_FMT}" } handle_errors() { # error handling if [ $1 != "0" ]; then FAILED_COMMAND=${*:2} echo -e "\n❌ ${RED}Error occurred while running command '$FAILED_COMMAND'.${RESET_FMT}❌" rollback exit 1 fi exit $1 } main() { process_args "$@" trap 'handle_errors $? $BASH_COMMAND' EXIT verify_origin_tracking echo -e "πŸ₯‘ Attempting to create a release prep branch and PR with release version updates.\n Previous version: $PREVIOUS_VERSION ---> Latest version: $LATEST_VERSION" create_release_branch update_versions commit_changes confirm_with_user_and_create_pr } main "$@"