#!/bin/bash # # We fail CI if the word "F I X M E" is detedcted, as a whole word, # in any case. The word is not matched if there are word-characters # abutted to it. set -e set -o pipefail BASE_BRANCHES='main' repo=$( perl -MTOML -we ' use strict; undef $/; my $toml = from_toml(); print $toml->{package}{repository} // die; ' /dev/null 2>&1 ||: git remote rename upstream upstream.tmp >/dev/null 2>&1 ||: git remote add upstream "$repo" ORIGIN=upstream ;; '') # Not running in CI, use a guess at the baseline: # $BASE_BRANCHES at whatever `origin` points to. ORIGIN=origin ;; *) # We are apparently running in a different instance to upstream. # It's not clear what this testing would mean. # Should it use our repo URL? That would be quite exciting. echo >&2 "CI_PROJECT_URL $CI_PROJECT_URL not recognised!" exit 4 ;; esac echo "Baseline repo remote $ORIGIN, at:" git remote get-url "$ORIGIN" tlref () { echo "refs/remotes/$ORIGIN/$tbranch" } x () { echo "+ $*" "$@" } git_checkout_maybe_clean () { x=$1; shift if $x git checkout -q "$1" then : else echo "Checkout failed, trying with git clean and git reset" x git clean -xdff x git reset --hard x git checkout -q "$1" fi } old_branch=$(git symbolic-ref -q HEAD || test $? = 1) restore_old_branch () { case "$old_branch" in refs/heads/*) git_checkout_maybe_clean '' "${old_branch#refs/heads/}" || echo '*** Failed to return to original branch ***' ;; *) echo "*** Was not originally on a branch, HEAD changed! ***" ;; esac } trap 'restore_old_branch' 0 refspecs=() for tbranch in $BASE_BRANCHES; do refspecs+=(+"refs/heads/$tbranch:$(tlref)") done # If you try to unshallow a repo that's already complete, you get # an error! Hence this. Not all versions of git-rev-parse # understand this option; we err on the side of trying the unshallow. if [ "x$(git rev-parse --is-shallow-repository)" != xfalse ]; then # TODO really we want something like the converse of # git fetch --shallow-exclude # but it doesn't seem to exist. git fetch --unshallow "$ORIGIN" "${refspecs[@]}" fi for tbranch in $BASE_BRANCHES; do trevlist="$(tlref)..HEAD" tcount=$(git rev-list --count "$trevlist") printf "HEAD is %3d commits ahead of %s\n" "$tcount" "$tbranch" if [ "$count" ] && [ $count -le $tcount ]; then continue; fi count=$tcount branch=$tbranch revlist=$trevlist done echo "Testing every commit not already on $branch" commits=$(git rev-list --reverse "$revlist") i=0 for commit in $commits; do banner='##############################' printf "|\n%s %d/%d %s\n|\n" "$banner" "$i" "$count" "$banner" git log -n1 "$commit" | sed 's/^/| /' echo '|' git_checkout_maybe_clean x "$commit" if x "$@"; then :; else rc="$?" printf " | ========================= Failed after $i/$count ========================= | Earliest broken commit is " git --no-pager log -n1 --pretty=oneline "$commit" exit "$rc" fi i=$(( $i + 1 )) done echo "| $banner ok $banner |" rc=0