chiark / gitweb /
git-debpush: check_treesame: Show diffstat when there is a diff
[dgit.git] / git-debpush
index 80594f5cd0c5f392521fa6c77a052792abb048f2..bd0357b5dc3a301979297023efc67dce5fb727e3 100755 (executable)
@@ -35,9 +35,11 @@ set -o pipefail
 #   mode; if there is a previous tag, and no quilt mode provided, assume
 #   same quilt mode as in previous tag created by this script
 
 #   mode; if there is a previous tag, and no quilt mode provided, assume
 #   same quilt mode as in previous tag created by this script
 
-# ---- Helper functions and variables
+# **** Helper functions and variables ****
 
 us="$(basename $0)"
 
 us="$(basename $0)"
+git_playtree_setup=git-playtree-setup ###substituted###
+git_playtree_setup=${DEBPUSH_GIT_PLAYTREE_SETUP-$git_playtree_setup}
 
 cleanup() {
     if [ -d "$temp" ]; then
 
 cleanup() {
     if [ -d "$temp" ]; then
@@ -65,14 +67,25 @@ get_file_from_ref () {
 
 failed_check=false
 fail_check () {
 
 failed_check=false
 fail_check () {
-    if $force; then
-        echo >&2 "$us: warning: $*"
+    local check=$1; shift
+    local check_is_forced=false
+
+    case ",$force," in
+        *",$check,"*) check_is_forced=true ;;
+    esac
+    if $force_all || $check_is_forced; then
+        echo >&2 "$us: warning: $* ('$check' check)"
     else
     else
-        echo >&2 "$us: $*"
+        echo >&2 "$us: $* ('$check' check)"
         failed_check=true
     fi
 }
 
         failed_check=true
     fi
 }
 
+fail_check_upstream_nonidentical () {
+    fail_check upstream-nonidentical \
+ "the upstream source in tag $upstream_tag is not identical to the upstream source in $branch"
+}
+
 find_last_tag () {
     local prefix=$1
 
 find_last_tag () {
     local prefix=$1
 
@@ -86,10 +99,32 @@ find_last_tag () {
     set -o pipefail
 }
 
     set -o pipefail
 }
 
-# ---- Parse command line
+check_treesame () {
+    local first=$1
+    local second=$2
+    shift 2
+
+    set +e
+    git diff --quiet --exit-code "$first".."$second" -- . "$@"
+    git_diff_rc=$?
+    set -e
+
+    # show the user what the difference was
+    if [ $git_diff_rc = 1 ]; then
+        git diff --compact-summary "$first".."$second" -- . "$@"
+    fi
+
+    if [ $git_diff_rc -le 1 ]; then
+        return $git_diff_rc
+    else
+        fail "'git diff' exited with unexpected code $git_diff_rc"
+    fi
+}
+
+# **** Parse command line ****
 
 getopt=$(getopt -s bash -o 'nfu:' \
 
 getopt=$(getopt -s bash -o 'nfu:' \
-              -l 'no-push,force,branch:,remote:,distro:,upstream:,quilt:,gbp,dpm,\
+              -l 'no-push,force::,branch:,remote:,distro:,upstream:,quilt:,gbp,dpm,\
 baredebian,baredebian+git,baredebian+tarball' \
               -n "$us" -- "$@")
 eval "set - $getopt"
 baredebian,baredebian+git,baredebian+tarball' \
               -n "$us" -- "$@")
 eval "set - $getopt"
@@ -97,7 +132,8 @@ set -e$DGIT_TEST_DEBPUSH_DEBUG
 
 git_tag_opts=()
 pushing=true
 
 git_tag_opts=()
 pushing=true
-force=false
+force_all=false
+force=""
 distro=debian
 quilt_mode=""
 branch="HEAD"
 distro=debian
 quilt_mode=""
 branch="HEAD"
@@ -106,7 +142,7 @@ while true; do
     case "$1" in
         '-n'|'--no-push') pushing=false;           shift;   continue ;;
        '-u')             git_tag_opts+=(-u "$2"); shift 2; continue ;;
     case "$1" in
         '-n'|'--no-push') pushing=false;           shift;   continue ;;
        '-u')             git_tag_opts+=(-u "$2"); shift 2; continue ;;
-        '-f'|'--force')   force=true;              shift;   continue ;;
+        '-f')             force_all=true;          shift;   continue ;;
         '--gbp')          quilt_mode='gbp';        shift;   continue ;;
         '--dpm')          quilt_mode='dpm';        shift;   continue ;;
         '--branch')       branch=$2;               shift 2; continue ;;
         '--gbp')          quilt_mode='gbp';        shift;   continue ;;
         '--dpm')          quilt_mode='dpm';        shift;   continue ;;
         '--branch')       branch=$2;               shift 2; continue ;;
@@ -121,6 +157,18 @@ while true; do
             fail "--baredebian+tarball quilt mode not supported"
             ;;
 
             fail "--baredebian+tarball quilt mode not supported"
             ;;
 
+        # we require the long form of the option to skip individual
+        # checks, not permitting `-f check`, to avoid problems if we
+        # later want to introduce positional args
+        '--force')
+            case "$2" in
+                '')
+                    force_all=true                         ;;
+                *)
+                    force="$force,$2"                      ;;
+            esac
+            shift 2; continue ;;
+
         '--') shift; break ;;
        *) badusage "unknown option $1" ;;
     esac
         '--') shift; break ;;
        *) badusage "unknown option $1" ;;
     esac
@@ -137,10 +185,10 @@ case "$quilt_mode" in
     *) badusage "invalid quilt mode: $quilt_mode" ;;
 esac
 
     *) badusage "invalid quilt mode: $quilt_mode" ;;
 esac
 
-# ---- Gather git information
+# **** Gather git information ****
 
 remoteconfigs=()
 
 remoteconfigs=()
-push_branch=()
+to_push=()
 
 # Maybe $branch is a symbolic ref.  If so, resolve it
 branchref="$(git symbolic-ref -q $branch || test $? = 1)"
 
 # Maybe $branch is a symbolic ref.  If so, resolve it
 branchref="$(git symbolic-ref -q $branch || test $? = 1)"
@@ -167,7 +215,7 @@ esac
 case "$branch" in
     refs/heads/*)
         b=${branch#refs/heads/}
 case "$branch" in
     refs/heads/*)
         b=${branch#refs/heads/}
-        push_branch+=("$b")
+        to_push+=("$b")
         remoteconfigs+=( branch.$b.pushRemote branch.$b.remote )
         ;;
 esac
         remoteconfigs+=( branch.$b.pushRemote branch.$b.remote )
         ;;
 esac
@@ -186,7 +234,7 @@ if $pushing && [ "x$remote" = "x" ]; then
     fi
 fi
 
     fi
 fi
 
-# ---- Gather source package information
+# **** Gather source package information ****
 
 temp=$(mktemp -d)
 trap cleanup EXIT
 
 temp=$(mktemp -d)
 trap cleanup EXIT
@@ -203,9 +251,9 @@ case "$format" in
     '3.0 (quilt)')  upstream=true ;;
     '3.0 (native)') upstream=false ;;
     '1.0'|'')
     '3.0 (quilt)')  upstream=true ;;
     '3.0 (native)') upstream=false ;;
     '1.0'|'')
-       if get_file_from_ref debian/source/options | grep '^-sn *$'; then
+       if get_file_from_ref debian/source/options | grep -q '^-sn *$'; then
            upstream=false
            upstream=false
-        elif get_file_from_ref debian/source/options | grep '^-sk *$'; then
+        elif get_file_from_ref debian/source/options | grep -q '^-sk *$'; then
            upstream=true
        else
            fail 'please see "SOURCE FORMAT 1.0" in git-debpush(1)'
            upstream=true
        else
            fail 'please see "SOURCE FORMAT 1.0" in git-debpush(1)'
@@ -216,7 +264,7 @@ case "$format" in
        ;;
 esac
 
        ;;
 esac
 
-# ---- Gather git history information
+# **** Gather git history information ****
 
 last_debian_tag=$(find_last_tag "debian/")
 last_archive_tag=$(find_last_tag "archive/debian/")
 
 last_debian_tag=$(find_last_tag "debian/")
 last_archive_tag=$(find_last_tag "archive/debian/")
@@ -244,25 +292,32 @@ if $upstream; then
     fi
     upstream_committish=$(git rev-parse "refs/tags/${upstream_tag}"^{})
     upstream_info=" upstream-tag=$upstream_tag upstream=$upstream_committish"
     fi
     upstream_committish=$(git rev-parse "refs/tags/${upstream_tag}"^{})
     upstream_info=" upstream-tag=$upstream_tag upstream=$upstream_committish"
+    to_push+=("$upstream_tag")
 fi
 
 fi
 
-# ---- Useful sanity checks
+# **** Useful sanity checks ****
+
+# ---- UNRELEASED suite
 
 if [ "$target" = "UNRELEASED" ]; then
 
 if [ "$target" = "UNRELEASED" ]; then
-    fail_check "UNRELEASED changelog"
+    fail_check unreleased "UNRELEASED changelog"
 fi
 
 fi
 
+# ---- Pushing dgit view to maintainer view
+
 if ! [ "x$last_debian_tag" = "x" ] && ! [ "x$last_archive_tag" = "x" ]; then
     last_debian_tag_c=$(git rev-parse "$last_debian_tag"^{})
     last_archive_tag_c=$(git rev-parse "$last_archive_tag"^{})
     if ! [ "$last_debian_tag_c" = "$last_archive_tag_c" ] \
             && git merge-base --is-ancestor \
                    "$last_debian_tag" "$last_archive_tag"; then
 if ! [ "x$last_debian_tag" = "x" ] && ! [ "x$last_archive_tag" = "x" ]; then
     last_debian_tag_c=$(git rev-parse "$last_debian_tag"^{})
     last_archive_tag_c=$(git rev-parse "$last_archive_tag"^{})
     if ! [ "$last_debian_tag_c" = "$last_archive_tag_c" ] \
             && git merge-base --is-ancestor \
                    "$last_debian_tag" "$last_archive_tag"; then
-        fail_check \
+        fail_check dgit-view \
 "looks like you might be trying to push the dgit view to the maintainer branch?"
     fi
 fi
 
 "looks like you might be trying to push the dgit view to the maintainer branch?"
     fi
 fi
 
+# ---- Targeting different suite
+
 if ! [ "x$last_debian_tag" = "x" ]; then
     temp=$(mktemp -d)
     trap cleanup EXIT
 if ! [ "x$last_debian_tag" = "x" ]; then
     temp=$(mktemp -d)
     trap cleanup EXIT
@@ -273,21 +328,51 @@ if ! [ "x$last_debian_tag" = "x" ]; then
     trap - EXIT
 
     if ! [ "$prev_target" = "$target" ] && ! [ "$target" = "UNRELEASED" ]; then
     trap - EXIT
 
     if ! [ "$prev_target" = "$target" ] && ! [ "$target" = "UNRELEASED" ]; then
-        fail_check \
+        fail_check suite \
 "last upload targeted $prev_target, now targeting $target; might be a mistake?"
     fi
 fi
 
 "last upload targeted $prev_target, now targeting $target; might be a mistake?"
     fi
 fi
 
-if ! $force && $failed_check; then
-    fail "some checks failed; you can override with --force"
+# ---- Upstream tag is not ancestor of $branch
+
+if ! [ "x$upstream_tag" = "x" ] \
+        && ! git merge-base --is-ancestor "$upstream_tag" "$branch" \
+        && ! [ "$quilt_mode" = "baredebian" ]; then
+    fail_check upstream-nonancestor \
+ "upstream tag $upstream_tag is not an ancestor of $branch; probably a mistake"
+fi
+
+# ---- Upstream tag tree nonidentical
+
+case "$quilt_mode" in
+    gbp)
+        check_treesame "$upstream_tag" "$branch" ':!debian' ':!**.gitignore' \
+            || fail_check_upstream_nonidentical
+        ;;
+    unapplied)
+        check_treesame "$upstream_tag" "$branch" ':!debian' \
+            || fail_check_upstream_nonidentical
+        ;;
+esac
+
+# ---- Summary
+
+if $failed_check; then
+    # We don't mention the --force=check options here as those are
+    # mainly for use by scripts, or when you already know what check
+    # is going to fail before you invoke git-debpush.  Keep the
+    # script's terminal output as simple as possible.  No "see the
+    # manpage"!
+    fail "some check(s) failed; you can pass --force to ignore them"
 fi
 
 fi
 
-# ---- Create the git tag
+# **** Create the git tag ****
 
 # convert according to DEP-14 rules
 git_version=$(echo $version | tr ':~' '%_' | sed 's/\.(?=\.|$|lock$)/.#/g')
 
 debian_tag="$distro/$git_version"
 
 # convert according to DEP-14 rules
 git_version=$(echo $version | tr ':~' '%_' | sed 's/\.(?=\.|$|lock$)/.#/g')
 
 debian_tag="$distro/$git_version"
+to_push+=("$debian_tag")
 
 # If the user didn't supply a quilt mode, look for it in a previous
 # tag made by this script
 
 # If the user didn't supply a quilt mode, look for it in a previous
 # tag made by this script
@@ -313,19 +398,16 @@ if [ "$format" = "3.0 (quilt)" ]; then
     fi
 fi
 
     fi
 fi
 
-git tag "${git_tag_opts[@]}" -s -F- "$debian_tag" "$branch" <<EOF
-$source release $version for $target
+tagmessage="$source release $version for $target
 
 [dgit distro=$distro split$quilt_mode_text]
 [dgit please-upload$upstream_info]
 
 [dgit distro=$distro split$quilt_mode_text]
 [dgit please-upload$upstream_info]
-EOF
+"
 
 
-# ---- Do a git push
+git tag "${git_tag_opts[@]}" -s -m "$tagmessage" "$debian_tag" "$branch"
+
+# **** Do a git push ****
 
 if $pushing; then
 
 if $pushing; then
-    if [ "x$upstream_tag" = "x" ]; then
-        git push "$remote" "${push_branch[@]}" "$debian_tag"
-    else
-        git push "$remote" "${push_branch[@]}" "$debian_tag" "$upstream_tag"
-    fi
+    git push "$remote" "${to_push[@]}"
 fi
 fi