#!/bin/sh -e # Apply a pull request # Copyright (C) 2014 Linaro Limited # Author: Peter Maydell # This work is licensed under the terms of the GNU GPL version 2 or later. # Usage: apply-pullreq [options] remote-url remote-branch-or-tagname # # Valid options: # --no-verify-sig : disable the gpg signature verification # --submodule-ok : allow merges which change submodules # (disabled by default to prevent accidental downgrades) # --apply-only : do the merge, but don't push to gitlab or kick off local builds # --on-top : relax the "is staging up to date" check, so that one pullreq # can be applied on top of another # # The intent of --apply-only and --on-top is to allow multiple pullreqs # to be tested in one CI run, for example: # apply-pullreq --apply-only url1 tag1 # apply-pullreq --apply-only --on-top url2 tag2 # apply-pullreq --on-top url3 tag3 # This makes a bunch of assumptions about repo setup and # preferred build-and-test commands. VRFY=yes SUBMODULE=no APPLY_ONLY=no ON_TOP=no while [ $# -ge 1 ]; do case "$1" in --no-verify-sig) shift VRFY=no ;; --submodule-ok) shift SUBMODULE=yes ;; --apply-only) shift APPLY_ONLY=yes ;; --on-top) shift ON_TOP=yes ;; *) break ;; esac done if [ $# != 2 ]; then echo "Usage: apply-pullreq [options] remote-url branch-or-tagname" exit 1 fi REMOTEURL="$1" REMOTETAG="$2" # hard newline NL=' ' BRANCH="$(git symbolic-ref -q HEAD || true)" # NB that in the "detached head" case BRANCH will be the empty string if [ "$BRANCH" != "refs/heads/staging" ]; then echo "Must be on staging branch" exit 1 fi git checkout master git pull git checkout staging if [ "$ON_TOP" = "yes" ]; then # Applying this pullreq on top of another: loosen the check # on whether staging is up to date if ! git merge-base --is-ancestor master staging; then echo "staging not up to date : suggest 'git reset --hard master'" exit 1 fi elif [ "$(git rev-parse master)" != "$(git rev-parse staging)" ]; then # This is our first pullreq to be applied, so staging and master # must be identical echo "staging not up to date : suggest 'git reset --hard master'" exit 1 fi # Check we're not accidentally trying to merge after the # final release was tagged and before we reopened the devtree. VER="$(cat VERSION)" VERMIN="${VER##*.}" if [ "$VERMIN" = "0" ]; then echo "VERSION says this a release version: forgot to reopen devtree?" exit 1 fi echo "fetching from remote $REMOTEURL $REMOTETAG" git fetch "$REMOTEURL" "$REMOTETAG" if [ "$VRFY" = "yes" ]; then if ! git verify-tag FETCH_HEAD; then echo "Does not appear to be a signed tag" echo "(use --no-verify-sig to override)" exit 1 fi fi echo "merging..." git merge --no-edit --no-ff --log FETCH_HEAD # Edit the merge commit to add our signoff line git commit --amend --signoff --no-edit # Check whether there seems to be a submodule update here. NB that this # can have false positives.. if git diff master..staging | grep -q 'Subproject commit'; then if [ "$SUBMODULE" = "no" ]; then echo "ERROR: pull request includes submodule update" echo "(use --submodule-ok to override)" exit 1 fi echo "WARNING: pull appears to include submodule update, please check it!" fi # Check whether any authors needs to be corrected after SPF rewrites if git shortlog --author='qemu-.*@nongnu\.org' master..staging | grep .; then echo "ERROR: pull request includes commits attributed to list" exit 1 fi # Check for incorrect UTF-8 copy/pasting # This is a very dubious heuristic that is essentially just looking # for mangled é or for =nn hex escapes. Still, it's better than nothing. if git log master..staging \ | grep -E "^ +[[:alpha:]-]+-by: .*(=[0-9A-F]{2}|é).*@"; then echo "ERROR: pull request includes tag with UTF-8 error in person name" exit 1 fi if [ "$APPLY_ONLY" = "yes" ]; then echo "--apply-only specified: not running tests" exit 0 fi # This should exit with an error status if any of the sub-builds fails. parallel-buildtest echo "WARNING: please check these results files!" echo "Looks good; trying a dry-run publish:" git push --dry-run publish-gitlab staging:master # For obvious reasons we don't let the script automatically # do the publish to upstream master... echo "OK; to publish for real run:" echo "git push publish-gitlab staging:master"