Pre-release versioning
[cvc5.git] / contrib / cut-release
1 #!/bin/bash
2 #
3 # usage: cut-release [-n] version-designation [make-args...]
4 #
5
6 function isthatright {
7 if $dryrun; then
8 echo -n "[DRY RUN] "
9 fi
10 if [ -z "$1" ]; then
11 echo -n "Does that look right? [y/n] "
12 else
13 echo -n "$1? [y/n] "
14 fi
15 while read yn; do
16 if [ "$yn" = y -o "$yn" = Y -o "$yn" = yes -o "$yn" = YES -o "$yn" = Yes ]; then
17 break
18 elif [ "$yn" = n -o "$yn" = N -o "$yn" = no -o "$yn" = NO -o "$yn" = No ]; then
19 echo "Aborting as per user request." >&2
20 exit 1
21 else
22 echo -n "[y/n] "
23 fi
24 done
25 }
26
27 if [ "$1" = -n ]; then
28 dryrun=true
29 shift
30 echo
31 echo '************************* DRY RUN *************************'
32 else
33 dryrun=false
34 fi
35
36 if [ $# -lt 1 ]; then
37 echo "Usage: $(basename "$0") [-n] version-designation [make-args...]" >&2
38 echo "-n does a dry run (i.e., do sanity checks and build but don't touch the repository)"
39 exit 1
40 fi
41
42 if ! [ -e src/expr/node.h -a -e .git ]; then
43 echo "$(basename "$0"): ERROR: You should run this from the top-level of a CVC4 git working directory" >&2
44 exit 1
45 fi
46
47 version="$1"
48 shift
49
50 if echo "$version" | grep '[^a-zA-Z0-9_.+(){}^%#-]' &>/dev/null; then
51 echo "$(basename "$0"): ERROR: Version designation \`$version' contains illegal characters" >&2
52 exit 1
53 fi
54
55 eval "declare -a vs=($(echo "$version" | sed 's,^\([0-9]*\)\.\([0-9]*\)\(\.\([0-9]*\)\)\?\(.*\),[0]=\1 [1]=\2 [2]=\4 [3]=\5,'))"
56 major=${vs[0]}
57 minor=${vs[1]}; if [ -z "$minor" ]; then minor=0; fi
58 release=${vs[2]}; if [ -z "$release" ]; then release=0; fi
59 extra=${vs[3]}
60 echo
61 echo "Major : $major"
62 echo "Minor : $minor"
63 echo "Release: $release"
64 echo "Extra : $extra"
65 echo
66 version="$major.$minor"
67 if [ "$release" != 0 ]; then
68 version="$version.$release"
69 fi
70 version="$version$extra"
71 echo "Version: $version"
72 echo
73 isthatright
74
75 echo "Checking whether release \`$version' already exists..."
76 if [ -n "`git tag -l "$version"`" ]; then
77 echo "$(basename "$0"): ERROR: Git repo already contains a release \`$version'" >&2
78 $dryrun || exit 1
79 fi
80
81 echo "Checking working directory for local modifications..."
82 if $dryrun; then
83 if [ -n "$(git status -s configure.ac)" ]; then
84 echo "$(basename "$0"): ERROR: In dry-run mode, cannot operate properly with local modifications to \"configure.ac\", sorry" >&2
85 exit 1
86 fi
87 elif [ -n "$(git status -s | grep -v '^ *M *\(NEWS\|README\|AUTHORS\|RELEASE-NOTES\|INSTALL\|THANKS\|library_versions\|contrib/cut-release\)$')" ]; then
88 echo "$(basename "$0"): ERROR: \"git status\" indicates there are local modifications; please commit first" >&2
89 exit 1
90 fi
91
92 echo "Checking repo for unmerged updates..."
93 git fetch &>/dev/null
94 if git status -sb | grep -q '^## .* \[.*behind '; then
95 echo "$(basename "$0"): ERROR: This working directory isn't up to date" 2>&1
96 $dryrun || exit 1
97 fi
98
99 echo "Checking sources for broken public headers..."
100 suspect_files="\
101 $(grep -r --exclude-dir=.git '^[ \t]*#[ \t]*include[ \t]*"[^/]*"' src |
102 grep -v '"cvc4parser_public\.h"' |
103 grep -v '"cvc4_public\.h"' |
104 grep -v '"cvc4_private\.h"' |
105 grep -v '"cvc4autoconfig\.h"' |
106 grep -v '"cvc4parser_private\.h"' |
107 cut -f1 -d: |
108 sort -u |
109 xargs grep -l '^[ \t]*#[ \t]*include[ \t]*"cvc4.*public\.h"' |
110 xargs echo)"
111 if [ -n "$suspect_files" ]; then
112 echo "$(basename "$0"): ERROR: The following publicly-installed headers appear" 2>&1
113 echo "$(basename "$0"): ERROR: to have relative #includes and may be broken" 2>&1
114 echo "$(basename "$0"): ERROR: after install: $suspect_files" 2>&1
115 $dryrun || exit 1
116 fi
117
118 for updatefile in NEWS README AUTHORS RELEASE-NOTES INSTALL THANKS; do
119 echo "Checking $updatefile file for recent updates..."
120 if [ -n "$(git status -s $updatefile)" ]; then
121 echo "+ It's locally modified."
122 else
123 git log -n 1 --date=local --pretty=format:'+ Last changed on %ad (%ar)' $updatefile
124 echo
125 case $updatefile in
126 NEWS)
127 echo "You should make sure to put some notes in the NEWS file for"
128 echo "release $version, indicating the most important changes since the"
129 echo "last release."
130 ;;
131 AUTHORS)
132 echo "You should make sure there are no new authors to list for $version."
133 ;;
134 *)
135 echo "You should ensure that $updatefile is appropriately updated"
136 echo "for $version before continuing. (Maybe it even lists the previous"
137 echo "version number!)"
138 ;;
139 esac
140 echo
141 isthatright "Continue without updating $updatefile"
142 fi
143 done
144
145 echo "Adjusting version info lines in configure.ac..."
146 if ! grep '^m4_define(_CVC4_MAJOR, *[0-9][0-9]* *)' configure.ac &>/dev/null ||
147 ! grep '^m4_define(_CVC4_MINOR, *[0-9][0-9]* *)' configure.ac &>/dev/null ||
148 ! grep '^m4_define(_CVC4_RELEASE, *[0-9][0-9]* *)' configure.ac &>/dev/null ||
149 ! grep '^m4_define(_CVC4_EXTRAVERSION, *\[.*\] *)' configure.ac &>/dev/null; then
150 echo "$(basename "$0"): ERROR: Cannot locate the version info lines of configure.ac" >&2
151 $dryrun || exit 1
152 fi
153 perl -pi -e 's/^m4_define\(_CVC4_MAJOR, ( *)[0-9]+( *)\)/m4_define(_CVC4_MAJOR, ${1}'"$major"'$2)/;
154 s/^m4_define\(_CVC4_MINOR, ( *)[0-9]+( *)\)/m4_define(_CVC4_MINOR, ${1}'"$minor"'$2)/;
155 s/^m4_define\(_CVC4_RELEASE, ( *)[0-9]+( *)\)/m4_define(_CVC4_RELEASE, ${1}'"$release"'$2)/;
156 s/^m4_define\(_CVC4_EXTRAVERSION, ( *)\[.*\]( *)\)/m4_define(_CVC4_EXTRAVERSION, $1\['"$extra"'\]$2)/' configure.ac
157
158 trap 'echo; echo; echo "Aborting in error."; git co -- configure.ac; echo' EXIT
159
160 echo
161 echo 'Made the following change to configure.ac:'
162 echo
163 git diff configure.ac
164 echo
165 isthatright
166
167 if ! grep '^m4_define(_CVC4_MAJOR, *'"$major"' *)' configure.ac &>/dev/null ||
168 ! grep '^m4_define(_CVC4_MINOR, *'"$minor"' *)' configure.ac &>/dev/null ||
169 ! grep '^m4_define(_CVC4_RELEASE, *'"$release"' *)' configure.ac &>/dev/null ||
170 ! grep '^m4_define(_CVC4_EXTRAVERSION, *\['"$extra"'\] *)' configure.ac &>/dev/null; then
171 echo "$(basename "$0"): INTERNAL ERROR: Cannot find the modified version info lines in configure.ac, bailing..." >&2
172 exit 1
173 fi
174 if [ -z "$(git status -s configure.ac)" ]; then
175 echo "$(basename "$0"): INTERNAL ERROR: \"git status\" indicates there are no local modifications to configure.ac; I expected the ones I just made!" >&2
176 exit 1
177 fi
178
179 echo "Building and checking distribution \`cvc4-$version'..."
180 if ! $SHELL -c '\
181 version="'$version'"; \
182 set -ex; \
183 ./autogen.sh || echo "autoconf failed; does library_versions have something to match $version?"; \
184 mkdir "release-$version"; \
185 cd "release-$version"; \
186 ../configure production-staticbinary --disable-shared --enable-unit-testing --with-readline --with-portfolio; \
187 make dist "$@"; \
188 tar xf "cvc4-$version.tar.gz"; \
189 cd "cvc4-$version"; \
190 ./configure production-staticbinary --disable-shared --enable-unit-testing --with-readline --with-portfolio; \
191 make check "$@"; \
192 make distcheck "$@"; \
193 '; then
194 exit 1
195 fi
196
197 if ! [ -e release-$version/cvc4-$version.tar.gz ]; then
198 echo "$(basename "$0"): INTERNAL ERROR: Cannot find the distribution tarball I just built" >&2
199 exit 1
200 fi
201 if ! [ -e release-$version/cvc4-$version/builds/src/main/cvc4 ]; then
202 echo "$(basename "$0"): INTERNAL ERROR: Cannot find the binary I just built" >&2
203 exit 1
204 fi
205
206 echo
207 echo 'This release of CVC4 will identify itself as:'
208 echo
209 release-$version/cvc4-$version/builds/src/main/cvc4 --version
210 echo
211 isthatright
212
213 echo
214 echo 'This binary release of CVC4 will identify itself as being configured like this:'
215 echo
216 release-$version/cvc4-$version/builds/src/main/cvc4 --show-config
217 echo
218 isthatright
219
220 echo
221 echo "Signing tarball..."
222 cp -p "release-$version/cvc4-$version.tar.gz" .
223 gpg -b --armor "cvc4-$version.tar.gz"
224
225 #echo
226 #echo "Signing cvc4 binary..."
227 #cp -p "release-$version/cvc4-$version/builds/src/main/cvc4" "cvc4-$version"
228 #gpg -b --armor "cvc4-$version"
229
230 #echo
231 #echo "Signing pcvc4 binary..."
232 #cp -p "release-$version/src/main/pcvc4" "pcvc4-$version"
233 #gpg -b --armor "pcvc4-$version"
234
235 if $dryrun; then
236 echo
237 echo '************************* DRY RUN *************************'
238 fi
239
240 echo
241 echo "About to run: git commit -am \"Cutting release $version.\""
242 isthatright
243 $dryrun || git commit -am "Cutting release $version."
244
245 echo
246 echo "About to run: git tag \"$version\""
247 isthatright
248 $dryrun || git tag "$version"
249
250 echo
251 andbranch=
252 if git status -bs | grep -q '^## master\($\| *\|\.\.\.\)'; then
253 if [ "$release" = 0 ]; then
254 echo "About to run: git branch \"$version.x\""
255 isthatright
256 $dryrun || git branch "$version.x"
257 andbranch=", the $version.x branch,"
258 else
259 echo "Not branching, because this is a minor release (i.e., not a \"dot-oh\""
260 echo "release), so I'm guessing you have a devel branch outside of master"
261 echo "somewhere? You can still make a branch manually, of course."
262 fi
263 else
264 echo "Not branching, because it appears there already is a branch"
265 echo "to work with for version $version ..? (You're not on master.)"
266 echo "You can still make a branch manually, of course."
267 fi
268
269 echo
270 echo "Done. Next steps are to:"
271 echo
272 echo "1. push to GitHub (don't forget to push master$andbranch and the $version tag)"
273 echo "2. upload source and binaries"
274 echo "3. advertise these packages"
275 echo "4. add a $version release and next-milestone to Bugzilla."
276 echo "5. change $version to pre-release in master$andbranch"
277 echo " (in configure.ac) and update library_versions and NEWS."
278 echo
279
280 trap '' EXIT
281