diff --git a/scripts/upgrade-packagespec b/scripts/upgrade-packagespec new file mode 100755 index 0000000000..2d2427f723 --- /dev/null +++ b/scripts/upgrade-packagespec @@ -0,0 +1,110 @@ +#!/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" + +if [ -z "$VERSION" ]; then + echo "usage: $0 " + exit 1 +fi +if [ -z "$BRANCH" ]; then + echo "usage: $0 " + exit 1 +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"