#!/usr/bin/env bash # This script takes 2 positional args: # # 1: The version of packagespec to upgrade a branch to (e.g. 1.2.3) # 2: The target branch to upgrade. # # It works in a temp directory, so does not interfere with your work tree # or git index or config. # # It does this: # # 1. Inspects your remote config for URL remotes. # 2. Clone this directory into a temp dir. # 3. Sets the remotes in the clone to match the remotes you have configured. # 4. Fetches everything from all remotes. # 5. Determines which remote your target branch is on. If it's more than one # remote, then exits with an error as there would be no way to choose. # 6. Checks out a new branch named packagespec/ # 7. Runs packagespec upgrade -version # 8. Commits the relevant paths with the message 'packagespec upgrade -version ' # 9. Pushes the new branch to the same remote as the original branch. # 0. Tells you to open a PR. # VERSION is the packagespec version to upgrade to. VERSION="$1" BRANCH="$2" FLAG="$3" REPO_NAME="$4" BINNAME="$0" usage() { echo "usage: $BINNAME [-pr PRODUCT_NAME]"; } if [ -z "$VERSION" ]; then usage; exit 1 fi if [ -z "$BRANCH" ]; then usage; exit 1 fi PR=false if [ -n "$FLAG" ]; then if [ "$FLAG" = "-pr" ]; then if [ -z "$REPO_NAME" ]; then usage; exit 1 fi PR=true else usage; exit 1 fi fi set -euo pipefail declare -A REMOTES # url_remotes lists remotes along with their push URLs, where they are # not filesystem paths (i.e. do not start with / or . ). url_remotes() { git remote -v | grep -F "(push)" | sed -E 's/[[:space:]]+\(push\)//g' | grep -Ev "\t(/|\.)"; } for R in $(url_remotes | cut -f1); do REMOTES[$R]="$(url_remotes | grep -E "^$R\t" | cut -f2)" done for R in "${!REMOTES[@]}"; do echo "Remote: $R = ${REMOTES[$R]}" done TEMP=".upgrade-packagespec" mkdir -p "$TEMP" echo "*" > "$TEMP/.gitignore" CLONEDIR="$TEMP/product-repo" if ! [ -d "$CLONEDIR/.git" ]; then git clone . "$CLONEDIR" fi cd "$CLONEDIR" echo "==> WORKING IN TEMP DIR: $CLONEDIR" git reset --hard # Remove existing remotes for R in $(git remote); do git remote rm "$R"; done # Add remotes from original checkout dir for R in "${!REMOTES[@]}"; do git remote add "$R" "${REMOTES[$R]}" done # Fetch everything from these remotes, ignore errors. git remote update || true BRANCH_ESCAPED="$(sed -E -e 's/\./\\./g' -e 's/\+/\\+/g' -e 's/\//\\\//g' <<< "$BRANCH")" # Determine which remotes the branch is on. declare -A BRANCH_REMOTES for R in "${!REMOTES[@]}"; do if git branch -a | grep -E "^[[:space:]]*remotes/$R/$BRANCH_ESCAPED\$"; then TARGET_REMOTE="$R" BRANCH_REMOTES[$R]=1 fi done COUNT="${#BRANCH_REMOTES[@]}" if [ "$COUNT" -ne "1" ]; then echo "==> ERROR: Branch $BRANCH found on $COUNT remotes; want exactly 1" exit 1 fi # Checkout the target update branch. git checkout "$BRANCH" git reset --hard "$TARGET_REMOTE/$BRANCH" NEW_BRANCH="packagespec$VERSION/$BRANCH" git checkout -B "$NEW_BRANCH" "$BRANCH" COMMAND="packagespec upgrade -version $VERSION" echo "==> Running $COMMAND" $COMMAND git add .circleci/ packages*.lock packagespec* git commit -m "$COMMAND" git push -u "$TARGET_REMOTE" "$NEW_BRANCH" echo "==> All done: upgrade pushed to branch $NEW_BRANCH on ${REMOTES[$TARGET_REMOTE]}" echo "==> ACTIONS FOR YOU: Open a PR with base: $BRANCH compare: $NEW_BRANCH" if ! $PR; then exit 0 fi # Open browser with PR ready: open https://github.com/hashicorp/$REPO_NAME/compare/$BRANCH...$NEW_BRANCH?expand=1