Merge from origin/emacs-29
[emacs.git] / admin / automerge
blobe751183f5f45f0d743947acea48bfb23525bece3
1 #!/bin/bash
2 ### automerge - automatically merge the Emacs release branch to master
4 ## Copyright (C) 2018-2024 Free Software Foundation, Inc.
6 ## Author: Glenn Morris <rgm@gnu.org>
7 ## Maintainer: Stefan Kangas <stefankangas@gmail.com>
9 ## This file is part of GNU Emacs.
11 ## GNU Emacs is free software: you can redistribute it and/or modify
12 ## it under the terms of the GNU General Public License as published by
13 ## the Free Software Foundation, either version 3 of the License, or
14 ## (at your option) any later version.
16 ## GNU Emacs is distributed in the hope that it will be useful,
17 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ## GNU General Public License for more details.
21 ## You should have received a copy of the GNU General Public License
22 ## along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
24 ### Commentary:
26 ## Automatically merge the Emacs release branch to master.
27 ## If the merge succeeds, optionally build and test the results,
28 ## and then push it.
29 ## Intended usage:
30 ## Have a dedicated git directory just for this.
31 ## Have a cron job that calls this script with -r -p.
33 ## Modifying a running shell script can have unpredictable results,
34 ## so the paranoid will first make a copy of this script, and then run
35 ## it with the -d option in the repository directory, in case a pull
36 ## updates this script while it is working.
38 source "${0%/*}/emacs-shell-lib"
40 usage ()
42 cat 1>&2 <<EOF
43 Usage: ${PN} [-b] [-d] [-e emacs] [-n nmin] [-p] [-r] [-t] [-- mflags]
44 Merge the Emacs release branch to master.
45 Passes any non-option args to make (eg -- -j2).
46 Options:
47 -d: no initial cd to parent of script directory
48 -e: Emacs executable to use for the initial merge (default $emacs)
49 -n: minimum number of commits to try merging (default $nmin)
50 -b: try to build after merging
51 -t: try to check after building
52 -p: if merge, build, check all succeed, push when finished (caution!)
53 -r: start by doing a hard reset (caution!) and pull
54 EOF
55 exit 1
59 ## Defaults.
61 emacs=emacs
62 nmin=10
63 build=
64 test=
65 push=
66 quiet=
67 reset=
68 nocd=
70 while getopts ":hbde:n:pqrt" option ; do
71 case $option in
72 (h) usage ;;
74 (b) build=1 ;;
76 (d) nocd=1 ;;
78 (e) emacs=$OPTARG ;;
80 (n) nmin=$OPTARG ;;
82 (p) push=1 ;;
84 (q) quiet=1 ;;
86 (r) reset=1 ;;
88 (t) test=1 ;;
90 (\?) die "Bad option -$OPTARG" ;;
92 (:) die "Option -$OPTARG requires an argument" ;;
94 (*) die "getopts error" ;;
95 esac
96 done
97 shift $(( --OPTIND ))
98 OPTIND=1
101 [ "$nocd" ] || {
102 # $PD should be the admin directory
103 cd $PD || die "Could not change directory to $PD"
104 cd ../
107 [ -d admin ] || die "Could not locate admin directory"
109 [ -e .git ] || die "No .git"
112 ## Does not work 100% because a lot of Emacs batch output comes on
113 ## stderr (?).
114 [ "$quiet" ] && exec 1> /dev/null
117 [ "$push" ] && test=1
118 [ "$test" ] && build=1
121 tempfile="$(emacs_mktemp)"
124 [ -e Makefile ] && [ "$build" ] && {
125 echo "Cleaning..."
126 make maintainer-clean >& /dev/null
130 [ "$reset" ] && {
131 echo "Resetting..."
132 git reset -q --hard origin/master || die "reset error"
134 echo "Pulling..."
135 git pull -q --ff-only || die "pull error"
139 rev=$(git rev-parse HEAD)
141 [ "$(git rev-parse @{u})" = "$rev" ] || die "Local state does not match origin"
144 merge ()
146 echo "Merging..."
148 if $emacs --batch -Q -l ./admin/gitmerge.el \
149 --eval "(setq gitmerge-minimum-missing $nmin)" -f gitmerge \
150 >| "$tempfile" 2>&1; then
151 echo "merged ok"
152 return 0
154 else
155 grep -E "Nothing to merge|Number of missing commits" "$tempfile" && \
156 exit 0
158 cat "$tempfile" 1>&2
160 die "merge error"
165 merge
168 ## FIXME it would be better to trap this in gitmerge.
169 ## NEWS should never be modified, only eg NEWS.26.
170 git diff --stat --cached origin/master | grep -q "etc/NEWS " && \
171 die "etc/NEWS has been modified"
174 [ "$build" ] || exit 0
177 echo "Running autoreconf..."
179 autoreconf -i -I m4 2>| "$tempfile"
181 retval=$?
183 ## Annoyingly, autoreconf puts the "installing `./foo' messages on stderr.
184 if [ "$quiet" ]; then
185 grep -v 'installing `\.' "$tempfile" 1>&2
186 else
187 cat "$tempfile" 1>&2
190 [ $retval -ne 0 ] && die "autoreconf error"
193 echo "Running ./configure..."
195 ## Minimize required packages.
196 ./configure --without-x || die "configure error"
199 echo "Building..."
201 make "$@" || die "make error"
203 echo "Build finished ok"
206 [ "$test" ] || exit 0
209 echo "Testing..."
211 ## We just want a fast pass/fail, we don't want to debug.
212 make "$@" check TEST_LOAD_EL=no || die "check error"
214 echo "Tests finished ok"
217 [ "$push" ] || exit 0
220 ## In case someone else pushed while we were working.
221 echo "Checking for remote changes..."
222 git fetch || die "fetch error"
224 [ "$(git rev-parse @{u})" = "$rev" ] || {
226 echo "Upstream has changed"
228 ## Rebasing would be incorrect, since it would rewrite the
229 ## (already published) release branch commits.
230 ## Ref eg https://lists.gnu.org/r/emacs-devel/2014-12/msg01435.html
231 ## Instead, we throw away what we just did, and do the merge again.
232 echo "Resetting..."
233 git reset --hard "$rev"
235 echo "Pulling..."
236 git pull --ff-only || die "pull error"
238 merge
240 ## If the merge finished ok again, we don't bother doing a second
241 ## build and test.
244 echo "Pushing..."
245 git push || die "push error"
248 exit 0