summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xscripts/check_mergability.sh165
1 files changed, 158 insertions, 7 deletions
diff --git a/scripts/check_mergability.sh b/scripts/check_mergability.sh
index ef99194fe..3ef77b605 100755
--- a/scripts/check_mergability.sh
+++ b/scripts/check_mergability.sh
@@ -109,15 +109,30 @@ prompt_or_summary () {
esac
}
+# format tool "aliases", where needed
+usort () { env usort format "$@"; }
+black () { env black -q "$@"; }
+pyupgrade () { git ls-files | grep -F .py | xargs pyupgrade --py37-plus; }
+
generate_report () {
# checkout a branch, try to merge each of the open PRs, write the results to
# a CSV file
base="${1:-master}"
- quiet=$2
+ quiet="$2"
+ rewrite_strategy="$3"
+ cmds="$4"
+ pr="$5"
+ report_file=../report-$base.csv
+
+ # prefix for working branch when we are going to re-write stuff so we don't
+ # mess up the pr/* branches and have to re-fetch them.
+ [ -n "$rewrite_strategy" ] && {
+ prefix="tmp-rewrite-"
+ report_file=../report-$base-$rewrite_strategy.csv
+ }
git checkout -q $base
- report_file=../report-$base.csv
[ -e $report_file ] && [ -z "$quiet" ] && {
prompt_or_summary "$report_file exists, overwrite?"
}
@@ -128,9 +143,37 @@ generate_report () {
}
jq -r '.[] | "\(.number) \(.updatedAt) \(.title)"' < ../prs.json | while read number updated title; do
- [ -n "$quiet" ] || echo "trying pr/$number $updated $title"
+ [ -n "$pr" ] && [ "$pr" != "$number" ] continue
+ [ -n "$quiet" ] || echo "trying ${prefix}pr/$number $updated $title"
head_sha=$(git rev-parse HEAD)
- git merge -q --no-ff --no-edit pr/$number 2>&1 1>/dev/null | grep -v preimage
+
+ case "$rewrite_strategy" in
+ rebase|merge)
+ # Only attempt branches that actually merge cleanly with master.
+ # Theoretically it wouldn't hurt to do all of them but a) running
+ # black via the filter driver is slow b) rebase_with_formatting needs
+ # some work to handle more errors in that case (the "git commit -qam
+ # 'fix lint" bit at least needs to look for conflict markers)
+ # I'm hardcoding master because of a lack of imagination.
+ grep "^$number" ../report-master.csv | grep failed && {
+ echo "pr/$number succeeded already in ../report-master.csv, skipping"
+ continue
+ }
+ rebase_with_formatting "$number" "$base" "$cmds" "$prefix" "$rewrite_strategy" || {
+ report $number $updated "$title" failed 999 999
+ continue
+ }
+ ;;
+ '')
+ true
+ ;;
+ *)
+ echo "Unknown rewrite strategy '$rewrite_strategy'"
+ exit 1
+ ;;
+ esac
+
+ git merge -q --no-ff --no-edit ${prefix}pr/$number 2>&1 1>/dev/null | grep -v preimage
if [ -e .git/MERGE_HEAD ] ;then
# merge failed, clean lines staged and conflicting lines in working
# tree
@@ -149,16 +192,124 @@ generate_report () {
done
}
+rebase_with_formatting () {
+ number="$1"
+ base="$2"
+ cmds="$3"
+ prefix="${4:-tmp-rewrite-}"
+ strategy="$5"
+
+ # We need to apply formatting to PRs and base them on a reformatted base
+ # branch.
+ # I haven't looked into doing that via a merge but here is an attempt
+ # doing a rebase.
+ # Rebasing directly on to a formatted branch will fail very easily when it
+ # runs into a formatting change. So I'm using git's "filter" attribute to
+ # apply the same formatter to the trees corresponding to the
+ # commits being rebased. Hopefully if we apply the same formatter to the
+ # base branch and to the individual commits from the PRs we can minimize
+ # conflicts.
+ # An alternative to using the filter attribute might be to use something
+ # like the "darker" tool to re-write the commits. I suspect that won't
+ # help with conflicts in the context around changes though.
+
+ # Checkout the parent commit of the branch then apply formatting tools to
+ # it. This will provide a target for rebasing which doesn't have any
+ # additional drift from changes to master. After that then we can rebase
+ # the re-written PR branch to the more current, autoformatted, master.
+ # TODO: It might be possible to skip the intermediate base branch.
+ git checkout -b tmp-master-rewrite-pr/$number `git merge-base origin/master pr/$number`
+ echo "$cmds" | tr ' ' '\n' | while read cmd; do
+ $cmd qutebrowser tests
+ git commit -am "dropme! $cmd" # mark commits for dropping when we rebase onto the more recent master
+ done
+
+ git checkout -b ${prefix}pr/$number pr/$number
+
+ # Setup the filters. A "smudge" filter is configured for each tool then we
+ # add the required tools to a gitattributes file. And make sure to clean
+ # it up later.
+ # Running the formatters as filters is slower than running them directly
+ # because they seem to be run on the files serially. TODO: can we
+ # parallelize them?
+ # Maybe just adding a wrapper around the formatters that caches the output
+ # would be simpler. At least then you just have to sit through them once.
+ git config --local --get filter.black.smudge >/dev/null || {
+ git config --local filter.black.smudge "black -q -"
+ git config --local filter.isort.smudge "isort -q -"
+ git config --local filter.pyupgrade.smudge "pyupgrade --py27-plus -"
+ git config --local filter.usort.smudge "usort format -"
+ }
+ printf "*.py" > .git/info/attributes
+ echo "$cmds" | tr ' ' '\n' | while read cmd; do
+ printf " filter=$cmd" >> .git/info/attributes
+ done
+ echo >> .git/info/attributes
+
+ # not sure why I had to do the extra git commit in there, there are some
+ # changes left in the working directory sometimes? TODO: change to a
+ # commit --amend -C HEAD after confirming overall results
+ # TODO: look for conflict markers before merging
+ git rebase -q -X renormalize --exec 'git commit -qam "fix lint" || true' tmp-master-rewrite-pr/$number
+ exit_code="$?"
+ [ $exit_code -eq 0 ] || git rebase --abort
+ git branch -D tmp-master-rewrite-pr/$number
+ rm .git/info/attributes
+
+ [ $exit_code -eq 0 ] || return $exit_code
+
+ if [ "$strategy" = "rebase" ] ;then
+ # now transplant onto the actual upstream branch -- might have to drop this
+ # if it causes problems.
+ EDITOR='sed -i /dropme/d' git rebase -qi "$base" || {
+ git rebase --abort
+ return 1
+ }
+ fi
+
+ git checkout -q $base
+}
+
cd qutebrowser
# run as `$0 some-branch` to report on merging all open PRs to a branch you
# made yourself. Otherwise run without args to try with a bunch of builtin
# configurations.
+
+strategy=""
+pull_request=""
+while [ -n "$1" ] ;do
+ case "$1" in
+ -s|--rewrite-strategy)
+ shift
+ [ -n "$1" ] || {
+ echo "What strategy?"
+ exit 1
+ }
+ strategy="$1"
+ ;;
+ -p|--pull-request)
+ shift
+ [ -n "$1" ] || {
+ echo "Which PR?"
+ exit 1
+ }
+ pull_request="$1"
+ ;;
+ -*)
+ echo "Unknown argument '$1'"
+ exit 1
+ ;;
+ *)
+ break
+ ;;
+ esac
+ shift
+done
+
if [ -n "$1" ] ;then
generate_report "$1"
else
- usort () { env usort format "$@"; }
- pyupgrade () { git ls-files | grep -F .py | xargs pyupgrade --py37-plus; }
clean_branches () {
# only clean up tmp- branches in case I run it on my main qutebrowser
# checkout by mistake :)
@@ -191,7 +342,7 @@ else
$cmd qutebrowser tests
git commit -am "$cmd"
done
- generate_report "$branch" y
+ generate_report "$branch" y "$strategy" "$cmds" "$pull_request"
done
fi