Skip to content

Commit

Permalink
Add githooks
Browse files Browse the repository at this point in the history
  • Loading branch information
npaun committed Aug 20, 2024
1 parent 9e58676 commit a666f32
Show file tree
Hide file tree
Showing 3 changed files with 247 additions and 0 deletions.
45 changes: 45 additions & 0 deletions githooks/pre-push
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#!/usr/bin/env bash

set -euo pipefail


source "$(dirname -- $BASH_SOURCE)/../tools/unix/find-python3.sh"
PYTHON_PATH=$(get_python3)
if [[ -z "$PYTHON_PATH" ]]; then
echo
echo "python3 is required for formatting and was not found"
echo
echo "ERROR: you must either install python3 and try pushing again or run `git push` with `--no-verify`"
exit 1
fi

while read LOCAL_REF LOCAL_SHA REMOTE_REF REMOTE_SHA
do
git fetch origin master &>/dev/null
# Check all local changes, not present in origin/master, for lint.
set +e
$PYTHON_PATH "$(dirname -- $BASH_SOURCE)/../tools/cross/format.py" --check git --source $LOCAL_SHA --target origin/master
EXIT_CODE=$?
set -e
case $EXIT_CODE in
0)
# No lint.
;;
1)
echo
echo "ERROR: changes in $LOCAL_REF have lint which may fail CI."
echo
echo "To fix lint:"
echo " python3 ./tools/cross/format.py"
echo
exit 1
;;
2)
echo
echo "ERROR: failed to run format.py, Pass '--no-verify' or '-n' to skip."
echo
exit 1
;;
esac
done

181 changes: 181 additions & 0 deletions tools/unix/apply-big-move.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
#! /bin/bash
#
# This script applies the most recent "big change".
#
# This script is designed so that it can help you rebase an in-flight PR across this change. Once
# the big move has been merged, you may simply run this script inside your branch, and it will
# take care of updating your change in order to avoid any merge conflicts.
#
# How it does this:
# 1. Rebases your change to the commit just before the Big Move.
# 2. Applies the same logical changes that the Big Move did, but now applies this to the changes
# on your branch too.
# 3. Rewrites git history so that your commits are now based on the commit immediately after the
# Big Move.
#
# To use the script, just run it in your branch. It'll take care of everything, and you'll end up
# with the changes in your branch all based on the commit after The Big Move.

set -euo pipefail

AFTER_MOVE_TAG=after-big-move-1
BEFORE_MOVE_TAG=before-big-move-1
NEXT_BIG_MOVE=before-big-move-2
ORIG_BRANCH=$(git branch --show-current)

fail() {
echo -e '\e[0;1;31mFAILED:\e[0m '"$@" >&2
exit 1
}

check_big_move_dependencies() {
source "$(dirname -- $BASH_SOURCE)/find-python3.sh"
PYTHON_PATH=$(get_python3)
if [[ -z "$PYTHON_PATH" ]]; then
fail "Cannot find python3. Run install python3 first."
fi
}

apply_big_move() {
echo "Applying format..."

source "$(dirname -- $BASH_SOURCE)/find-python3.sh"
PYTHON_PATH=$(get_python3)
$PYTHON_PATH "$(dirname -- $BASH_SOURCE)/../cross/format.py"

echo "Changes applied successfully."
}

rebase_and_rerun() {
# Rebase on top of tag $1 and then run the script again.

BASE=$1

echo -e '\e[0;1;34mRebasing onto tag '"$BASE"'...\e[0m'
git rebase $BASE || \
fail "Rebase had conflicts. Please resolve them and run the script again."
git submodule update

# Make sure we're using the correct version of the script by starting it over.
exec ./apply-big-move.sh
}

check_for_next_move() {
# Check if there's a new "Big Move" in the future and, if so, prompt the user to apply it too.

if git describe $NEXT_BIG_MOVE >/dev/null 2>&1; then
while true; do
echo -en '\e[0;1;33mIt looks like there is another big move after this one. Should we apply it now? [y/n]\e[0m '
read -n1 CHOICE
echo
case "$CHOICE" in
y | Y )
rebase_and_rerun $NEXT_BIG_MOVE
;;
n | N )
echo "OK. When you are ready, please run the script again to apply the next move."
exit 0
;;
esac
echo "??? Please press either y or n."
done
fi
}

main() {
if [ "x$(git status --untracked-files=no --porcelain)" != "x" ]; then
fail "You have uncommitted changes. Please commit or discard them first."
fi

check_big_move_dependencies

# Use --apply to just apply the Big Move changes to the current tree without committing or
# rewriting any history. This is intended to be used to create the Big Move commit in the first
# place.
if [ "${1:-}" = "--apply" ]; then
apply_big_move
exit 0
fi

# Make sure our tags are up-to-date so we can find the relevant Big Move tags.
echo "Fetching tags..."
git fetch origin --tags --force

# Check that the Big Move is actually ready. (This script will be committed to the repo before
# the Big Move itself is, so this checks if someone is running the script too early.)
if ! git describe $BEFORE_MOVE_TAG >/dev/null 2>&1; then
fail "The Big Move hasn't happened yet (tags not found)."
fi

# Check if we already applied The Big Move in this branch, as indicated by $AFTER_MOVE_TAG being
# in our history.
if git merge-base --is-ancestor $AFTER_MOVE_TAG HEAD; then
# This branch already includes The Big Move, but maybe there is a future Big Move and the
# user was actually intending to apply that?
if git describe $NEXT_BIG_MOVE >/dev/null 2>&1; then
# Indeed there is, let's skip forward to that.
rebase_and_rerun $NEXT_BIG_MOVE
fi

echo "The Big Move has already been applied to this branch."
exit 0
fi

# Check if $BEFORE_MOVE_TAG is in this branch's history. If not, we need to rebase first.
if ! git merge-base --is-ancestor $BEFORE_MOVE_TAG HEAD; then
# Branch is not yet based on $BEFORE_MOVE_TAG, so rebase onto it.
rebase_and_rerun $BEFORE_MOVE_TAG
fail "(can't get here -- rebase_and_rerun should not return)"
fi

# Get the list of commits that we need to rebase over The Big Move.
COMMITS=($(git log --reverse --format='%H' $BEFORE_MOVE_TAG..HEAD))

# Checkout $AFTER_MOVE_TAG in order to start building on it.
git checkout -q $AFTER_MOVE_TAG
git submodule update

# Apply each commit.
for COMMIT in ${COMMITS[@]}; do
git log -1 --format='%CblueRewriting commit %h:%Creset %s' $COMMIT

# Update the working tree to match the code from the source commit.
git checkout $COMMIT .
git submodule update

# Apply the Big Move on top of that.
apply_big_move

# Commit to edgeworker (including updating the workerd submodule), reusing the old commit
# message. It's possible that the diff is now empty, in which case we skip this commit, much
# like `git rebase` does by default.
if git commit -a --dry-run > /dev/null 2>&1; then
git commit -aC $COMMIT
fi
done

# Record the final commit.
FINAL_COMMIT=$(git log -1 --format=%H)

# Check out the original branch, and reset it to the final commit.
git checkout -q "$ORIG_BRANCH"
git reset --hard "$FINAL_COMMIT"

# Success!
echo -e '\e[0;1;32mSUCCESS:\e[0m Applied Big Move.'

# Check if there's another move upcoming that we should apply next.
check_for_next_move

exit 0
}

# Ensure that if the file changes while bash is reading it, bash won't go off the rails. Normally,
# bash reads one line from the file at a time and then executes it before reading the next.
# Wrapping the whole script body in a function ensures that bash buffers it in memory. Placing
# `exit 0` on the same line ensures that bash won't attempt to read anything more after the
# function returns.
#
# This ensures that if further changes are made to this file before the Big Move actually happens,
# then the rebase command that rebases to the commit before the Big Move won't confuse bash.
main "$@"; exit 0
21 changes: 21 additions & 0 deletions tools/unix/find-python3.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

get_python3() {
# Search for python3
python=$(which python3 2>/dev/null)

# If not found, search for python
if [ -z "$python" ]; then
python=$(which python 2>/dev/null)
if [ -n "$python" ]; then
local python_version=$($python -V 2>&1 | head -n 1 | cut -d ' ' -f 2- | cut -d '.' -f1)
if [ "$python_version" != "3" ]; then
unset python
fi
fi
fi

if [ -z "$python" ]; then
return
fi
echo "$python"
}

0 comments on commit a666f32

Please sign in to comment.