script/release.sh: make it possible to create stable .x releases (x >= 1)
[vlendec/samba-autobuild/.git] / script / release.sh
1 #!/bin/bash
2 # make a release of Samba or a library
3
4 LC_ALL=C
5 export LC_ALL
6 LANG=C
7 export LANG
8 LANGUAGE=C
9 export LANGUAGE
10
11 set -u
12 set -e
13 umask 0022
14
15 CONF_REPO_URL="ssh://git.samba.org/data/git/samba.git"
16 CONF_UPLOAD_URL="samba-bugs@download-master.samba.org:/home/data/ftp/pub"
17 CONF_DOWNLOAD_URL="https://download.samba.org/pub"
18 CONF_HISTORY_URL="https://www.samba.org"
19
20 test -d ".git" || {
21         echo "Run this script from the top-level directory in the"
22         echo "repository"
23         exit 1
24 }
25
26 usage() {
27         echo "Usage: release.sh <PRODUCT> <COMMAND>"
28         echo ""
29         echo "PRODUCT: ldb, talloc, tevent, tdb, samba-rc, samba-stable"
30         echo "COMMAND: fullrelease, create, push, upload, announce"
31         echo ""
32         return 0
33 }
34
35 check_args() {
36         local cmd="$1"
37         local got_args="$2"
38         local take_args="$3"
39
40         test x"${got_args}" = x"${take_args}" || {
41                 usage
42                 echo "cmd[${cmd}] takes ${take_args} instead of ${got_args}"
43                 return 1
44         }
45
46         return 0
47 }
48
49 min_args() {
50         local cmd="$1"
51         local got_args="$2"
52         local min_args="$3"
53
54         test "${got_args}" -ge "${min_args}" || {
55                 usage
56                 echo "cmd[${cmd}] takes at least ${min_args} instead of ${got_args}"
57                 return 1
58         }
59
60         return 0
61 }
62
63 min_args "$0" "$#" "2"
64
65 product="$1"
66 globalcmd="$2"
67 shift 2
68 oldtagname=""
69 tagname=""
70 patchfile=""
71 cmds=""
72 next_cmd=""
73
74 require_tagname() {
75         min_args "${FUNCNAME}" "$#" "1" || return 1
76         local cmd="$1"
77
78         test -n "${tagname}" || {
79                 echo "cmd[${cmd}] requires '\${tagname}' variable to be set"
80                 return 1
81         }
82
83         local name=$(echo "${tagname}" | cut -d '-' -f1)
84         test x"${name}" = x"${productbase}" || {
85                 echo "Invalid tagname[${tgzname}]"
86                 return 1
87         }
88
89         return 0
90 }
91
92 cmd_allowed() {
93         min_args "${FUNCNAME}" "$#" "2" || return 1
94         local cmd="$1"
95         shift 1
96
97         echo "$@" | grep -q "\<${cmd}\>" || {
98                 return 1
99         }
100
101         return 0
102 }
103
104 verify_samba_rc() {
105         check_args "${FUNCNAME}" "$#" "0" || return 1
106
107         test -f VERSION || {
108                 echo "VERSION doesn't exist"
109                 return 1
110         }
111
112         grep -q 'SAMBA_VERSION_IS_GIT_SNAPSHOT=no' VERSION || {
113                 echo "SAMBA_VERSION_IS_GIT_SNAPSHOT is not 'no'"
114                 return 1
115         }
116
117         grep -q '^SAMBA_VERSION_RC_RELEASE=' VERSION || {
118                 echo "SAMBA_VERSION_RC_RELEASE= missing"
119                 return 1
120         }
121
122         grep -q '^SAMBA_VERSION_RC_RELEASE=$' VERSION && {
123                 echo "SAMBA_VERSION_RC_RELEASE= missing the rc version"
124                 return 1
125         }
126
127         return 0
128 }
129
130 load_samba_stable_versions() {
131         check_args "${FUNCNAME}" "$#" "0" || return 1
132
133         test -n "${version-}" && {
134                 return 0
135         }
136
137         local SAMBA_VERSION_MAJOR=$(grep '^SAMBA_VERSION_MAJOR=' VERSION | cut -d '=' -f2 | xargs)
138         local SAMBA_VERSION_MINOR=$(grep '^SAMBA_VERSION_MINOR=' VERSION | cut -d '=' -f2 | xargs)
139         local SAMBA_VERSION_RELEASE=$(grep '^SAMBA_VERSION_RELEASE=' VERSION | cut -d '=' -f2 | xargs)
140
141         version="${SAMBA_VERSION_MAJOR}.${SAMBA_VERSION_MINOR}.${SAMBA_VERSION_RELEASE}"
142         tagname="${productbase}-${version}"
143
144         test ${SAMBA_VERSION_RELEASE} -gt 0 || {
145                 return 0
146         }
147
148         oldversion="${SAMBA_VERSION_MAJOR}.${SAMBA_VERSION_MINOR}.$(expr ${SAMBA_VERSION_RELEASE} - 1)"
149         oldtagname="${productbase}-${oldversion}"
150         patchfile="${productbase}-${oldversion}-${version}.diffs"
151
152         return 0
153 }
154
155 verify_samba_stable() {
156         check_args "${FUNCNAME}" "$#" "0" || return 1
157
158         test -f VERSION || {
159                 echo "VERSION doesn't exist"
160                 return 1
161         }
162
163         grep -q 'SAMBA_VERSION_IS_GIT_SNAPSHOT=no' VERSION || {
164                 echo "SAMBA_VERSION_IS_GIT_SNAPSHOT is not 'no'"
165                 return 1
166         }
167
168         local VARS=""
169         VARS="${VARS} SAMBA_VERSION_REVISION"
170         VARS="${VARS} SAMBA_VERSION_TP_RELEASE"
171         VARS="${VARS} SAMBA_VERSION_ALPHA_RELEASE"
172         VARS="${VARS} SAMBA_VERSION_BETA_RELEASE"
173         VARS="${VARS} SAMBA_VERSION_PRE_RELEASE"
174         VARS="${VARS} SAMBA_VERSION_RC_RELEASE"
175         VARS="${VARS} SAMBA_VERSION_RELEASE_NICKNAME"
176         VARS="${VARS} SAMBA_VERSION_VENDOR_SUFFIX"
177         VARS="${VARS} SAMBA_VERSION_VENDOR_PATCH"
178         for var in ${VARS}; do
179                 grep -q "^${var}" VERSION && {
180                         grep -q "^${var}=$" VERSION || {
181                                 echo "${var} found in stable version"
182                                 return 1
183                         }
184                 }
185         done
186
187         load_samba_stable_versions
188
189         test x"${product}" = x"samba-stable" && {
190                 test -f "announce.${tagname}.quotation.txt" || {
191                         echo ""
192                         echo "announce.${tagname}.quotation.txt missing!"
193                         echo ""
194                         echo "Please create it and retry"
195                         echo ""
196                         echo "The content should look like this:"
197                         echo "cat announce.${tagname}.quotation.txt"
198                         echo '======================================================'
199                         echo '                "Some text'
200                         echo '                 from someone."'
201                         echo ''
202                         echo '                 The author'
203                         echo '======================================================'
204                         echo ""
205                         return 1
206                 }
207         }
208
209         test -n "${oldtagname}" || {
210                 return 0
211         }
212
213         local verify_out="${TMPDIR}/verify-${oldtagname}.out"
214
215         echo "Verifying oldtagname: ${oldtagname}"
216
217         git tag -v "${oldtagname}" >${verify_out} 2>&1 || {
218                 echo "failed to verify old tag[${oldtagname}]"
219                 return 1
220         }
221
222         grep -q "${GPG_KEYID}" "${verify_out}" || {
223                 echo "oldtagname[${oldtagname}] was not generated with GPG_KEYID[${GPG_KEYID}]!"
224                 echo ""
225                 cat "${verify_out}"
226                 return 1
227         }
228
229         echo "Verifying ${oldtagname}.tar.gz and ${oldtagname}.tar.asc"
230
231         test -f "${oldtagname}.tar.gz" || {
232                 echo "${oldtagname}.tar.gz does not exist"
233                 return 1
234         }
235
236         test -f "${oldtagname}.tar.asc" || {
237                 echo "${oldtagname}.tar.asc does not exist"
238                 return 1
239         }
240
241         zcat "${oldtagname}.tar.gz" | gpg --verify "${oldtagname}.tar.asc" - 2>${verify_out} || {
242                 echo "Failed to verify ${oldtagname}.tar.asc"
243                 return 1
244         }
245
246         grep -q "${GPG_KEYID}" "${verify_out}" || {
247                 echo "${oldtagname}.tar.asc was not generated with GPG_KEYID[${GPG_KEYID}]!"
248                 echo ""
249                 cat "${verify_out}"
250                 return 1
251         }
252
253         return 0
254 }
255
256 verify_release() {
257         check_args "${FUNCNAME}" "$#" "0" || return 1
258
259         test -n "${verify_fn}" || {
260                 echo "verify_fn variable empty"
261                 return 1
262         }
263
264         echo "Running ${verify_fn}"
265         ${verify_fn}
266 }
267
268 create_release() {
269         check_args "${FUNCNAME}" "$#" "0" || return 1
270
271         echo "Releasing product ${product}"
272
273         test -n "${tagname}" && {
274                 git tag -l "${tagname}" | grep -q "${tagname}" && {
275                         echo "tagname[${tagname}] already exist"
276                         return 1
277                 }
278
279                 local _tgzname="${tagname}.tar.gz"
280                 test -e "${_tgzname}" && {
281                         echo "_tgzname[${_tgzname}] already exist"
282                         return 1
283                 }
284         }
285
286         echo "Building release tarball"
287         local tgzname=$(make dist 2>&1 | grep ^Created | cut -d' ' -f2)
288         test -f "${tgzname}" || {
289                 echo "Failed to create tarball"
290                 return 1
291         }
292         CLEANUP_FILES="${CLEANUP_FILES} ${tgzname}"
293
294         local name=$(echo "${tgzname}" | cut -d '-' -f1)
295         test x"${name}" = x"${productbase}" || {
296                 echo "Invalid tgzname[${tgzname}]"
297                 return 1
298         }
299
300         local _tagname=$(basename ${tgzname} .tar.gz)
301         test -n "${tagname}" && {
302                 test x"${_tagname}" = x"${tagname}" || {
303                         echo "Invalid tgzname[${tgzname}]"
304                         return 1
305                 }
306         }
307         tagname="${_tagname}"
308
309         local tarname=$(basename ${tgzname} .gz)
310         echo "Tarball: ${tarname}"
311         gunzip -f ${tgzname} || {
312                 echo "Failed to decompress tarball ${tarname}"
313                 return 1
314         }
315         test -f "${tarname}" || {
316                 echo "Failed to decompress tarball ${tarname}"
317                 return 1
318         }
319         CLEANUP_FILES="${CLEANUP_FILES} ${tarname}"
320
321         # tagname is global
322         echo "Tagging as ${tagname}"
323         git tag -u ${GPG_KEYID} -s "${tagname}" -m "${productbase}: tag release ${tagname}" || {
324                 return 1
325         }
326         CLEANUP_TAGS="${CLEANUP_TAGS} ${tagname}"
327
328         echo "Signing ${tarname} => ${tarname}.asc"
329         rm -f "${tarname}.asc"
330         gpg -u "${GPG_USER}" --detach-sign --armor ${tarname} || {
331                 return 1
332         }
333         test -f "${tarname}.asc" || {
334                 echo "Failed to create signature ${tarname}.asc"
335                 return 1
336         }
337         CLEANUP_FILES="${CLEANUP_FILES} ${tarname}.asc"
338         echo "Compressing ${tarname} => ${tgzname}"
339         gzip -f -9 ${tarname}
340         test -f "${tgzname}" || {
341                 echo "Failed to compress ${tgzname}"
342                 return 1
343         }
344
345         return 0
346 }
347
348 patch_release() {
349         check_args "${FUNCNAME}" "$#" "0" || return 1
350         require_tagname "${FUNCNAME}"
351
352         test -n "${patchfile}" || {
353                 return 0
354         }
355
356         local oldpwd=$(pwd)
357         echo "Generating ${patchfile}"
358         (
359                 set -e
360                 set -u
361                 pushd "${TMPDIR}"
362                 tar xfz "${oldpwd}/${oldtagname}.tar.gz"
363                 tar xfz "${oldpwd}/${tagname}.tar.gz"
364                 diff -Npur "${oldtagname}/" "${tagname}/" > "${patchfile}"
365                 popd
366         )
367         CLEANUP_FILES="${CLEANUP_FILES} ${patchfile}"
368         mv "${TMPDIR}/${patchfile}" "${patchfile}" || {
369                 echo "failed cmd[mv ${TMPDIR}/${patchfile} ${patchfile}]"
370                 return 1
371         }
372
373         echo "Signing ${patchfile} => ${patchfile}.asc"
374         rm -f "${patchfile}.asc"
375         CLEANUP_FILES="${CLEANUP_FILES} ${patchfile}.asc"
376         gpg -u "${GPG_USER}" --detach-sign --armor ${patchfile} || {
377                 return 1
378         }
379         test -f "${patchfile}.asc" || {
380                 echo "Failed to create signature ${patchfile}.asc"
381                 return 1
382         }
383         echo "Compressing ${patchfile} => ${patchfile}.gz"
384         CLEANUP_FILES="${CLEANUP_FILES} ${patchfile}.gz"
385         gzip -f -9 ${patchfile}
386         test -f "${patchfile}.gz" || {
387                 echo "Failed to compress ${patchfile}.gz"
388                 return 1
389         }
390
391         return 0
392 }
393
394 whatsnew_release() {
395         check_args "${FUNCNAME}" "$#" "0" || return 1
396         require_tagname "${FUNCNAME}"
397
398         echo "extract ${tagname}.WHATSNEW.txt"
399         tar xf ${tagname}.tar.gz --to-stdout ${tagname}/WHATSNEW.txt > ${tagname}.WHATSNEW.txt
400         CLEANUP_FILES="${CLEANUP_FILES} ${tagname}.WHATSNEW.txt"
401
402         return 0
403 }
404
405 check_nopatch() {
406         check_args "${FUNCNAME}" "$#" "0" || return 1
407         require_tagname "${FUNCNAME}"
408
409         local verify_out="${TMPDIR}/verify-${oldtagname}.out"
410
411         echo "Verifying tagname: ${tagname}"
412
413         git tag -v "${tagname}" >${verify_out} 2>&1 || {
414                 echo "failed to verify old tag[${oldtagname}]"
415                 return 1
416         }
417         grep -q "${GPG_KEYID}" "${verify_out}" || {
418                 echo "tagname[${tagname}] was not generated with GPG_KEYID[${GPG_KEYID}]!"
419                 echo ""
420                 cat "${verify_out}"
421                 return 1
422         }
423
424         echo "Verifying ${tagname}.tar.gz and ${tagname}.tar.asc"
425
426         test -f "${tagname}.tar.gz" || {
427                 echo "${tagname}.tar.gz does not exist"
428                 return 1
429         }
430
431         test -f "${tagname}.tar.asc" || {
432                 echo "${tagname}.tar.asc does not exist"
433                 return 1
434         }
435
436         zcat "${tagname}.tar.gz" | gpg --verify "${tagname}.tar.asc" - 2>${verify_out} || {
437                 echo "Failed to verify ${tagname}.tar.asc"
438                 return 1
439         }
440         grep -q "${GPG_KEYID}" "${verify_out}" || {
441                 echo "${tagname}.tar.asc was not generated with GPG_KEYID[${GPG_KEYID}]!"
442                 echo ""
443                 cat "${verify_out}"
444                 return 1
445         }
446
447         ls -la ${tagname}.*
448
449         return 0
450 }
451
452 check_samba_stable() {
453         check_args "${FUNCNAME}" "$#" "0" || return 1
454         require_tagname "${FUNCNAME}"
455
456         load_samba_stable_versions
457
458         local verify_out="${TMPDIR}/verify-${oldtagname}.out"
459
460         echo "Verifying tagname: ${tagname}"
461
462         git tag -v "${tagname}" >${verify_out} 2>&1 || {
463                 echo "failed to verify old tag[${oldtagname}]"
464                 return 1
465         }
466         grep -q "${GPG_KEYID}" "${verify_out}" || {
467                 echo "tagname[${tagname}] was not generated with GPG_KEYID[${GPG_KEYID}]!"
468                 echo ""
469                 cat "${verify_out}"
470                 return 1
471         }
472
473         echo "Verifying ${tagname}.tar.gz and ${tagname}.tar.asc"
474
475         test -f "${tagname}.tar.gz" || {
476                 echo "${tagname}.tar.gz does not exist"
477                 return 1
478         }
479
480         test -f "${tagname}.tar.asc" || {
481                 echo "${tagname}.tar.asc does not exist"
482                 return 1
483         }
484
485         zcat "${tagname}.tar.gz" | gpg --verify "${tagname}.tar.asc" - 2>${verify_out} || {
486                 echo "Failed to verify ${tagname}.tar.asc"
487                 return 1
488         }
489         grep -q "${GPG_KEYID}" "${verify_out}" || {
490                 echo "${tagname}.tar.asc was not generated with GPG_KEYID[${GPG_KEYID}]!"
491                 echo ""
492                 cat "${verify_out}"
493                 return 1
494         }
495
496         test -n "${patchfile}" || {
497                 ls -lart ${tagname}.*
498                 return 0
499         }
500
501         echo "Verifying ${patchfile}.gz and ${patchfile}.asc"
502
503         test -f "${patchfile}.gz" || {
504                 echo "${patchfile}.gz does not exist"
505                 return 1
506         }
507
508         test -f "${patchfile}.asc" || {
509                 echo "${patchfile}.asc does not exist"
510                 return 1
511         }
512
513         zcat "${patchfile}.gz" | gpg --verify "${patchfile}.asc" - 2>${verify_out} || {
514                 echo "Failed to verify ${patchfile}.asc"
515                 return 1
516         }
517         grep -q "${GPG_KEYID}" "${verify_out}" || {
518                 echo "${patchfile}.asc was not generated with GPG_KEYID[${GPG_KEYID}]!"
519                 echo ""
520                 cat "${verify_out}"
521                 return 1
522         }
523
524         ls -lart ${tagname}.* ${patchfile}.*
525         return 0
526 }
527
528 check_release() {
529         check_args "${FUNCNAME}" "$#" "0" || return 1
530
531         test -n "${check_fn}" || {
532                 echo "check_fn variable empty"
533                 return 1
534         }
535
536         echo "Running ${check_fn}"
537         ${check_fn}
538 }
539
540 push_release() {
541         check_args "${FUNCNAME}" "$#" "0" || return 1
542         require_tagname "${FUNCNAME}"
543
544         echo "Push git tag ${tagname} to '${repo_url}'"
545         git push "${repo_url}" "refs/tags/${tagname}:refs/tags/${tagname}" || {
546                 return 1
547         }
548
549         return 0
550 }
551
552 upload_nopatch() {
553         check_args "${FUNCNAME}" "$#" "0" || return 1
554         require_tagname "${FUNCNAME}"
555
556         echo "Upload ${tagname}.* to '${upload_url}'"
557         rsync -Pav --delay-updates ${tagname}.* "${upload_url}/" || {
558                 return 1
559         }
560         rsync ${upload_url}/${tagname}.*
561
562         return 0
563 }
564
565 upload_samba_stable() {
566         check_args "${FUNCNAME}" "$#" "0" || return 1
567         require_tagname "${FUNCNAME}"
568
569         load_samba_stable_versions
570
571         local release_url="${upload_url}samba/stable/"
572         local patch_url="${upload_url}samba/patches/"
573
574         echo "Upload ${tagname}.tar.* to '${release_url}'"
575         ls -lart ${tagname}.tar.*
576         rsync -Pav --delay-updates ${tagname}.tar.* "${release_url}/" || {
577                 return 1
578         }
579         rsync ${release_url}/${tagname}.tar.*
580
581         test -n "${patchfile}" || {
582                 return 0
583         }
584
585         echo "Upload ${patchfile}.* to '${patch_url}'"
586         ls -lart ${patchfile}.*
587         rsync -Pav --delay-updates ${patchfile}.* "${patch_url}/" || {
588                 return 1
589         }
590         rsync ${patch_url}/${patchfile}.*
591
592         return 0
593 }
594
595 upload_release() {
596         check_args "${FUNCNAME}" "$#" "0" || return 1
597
598         test -n "${upload_fn}" || {
599                 echo "upload_fn variable empty"
600                 return 1
601         }
602
603         echo "Running ${upload_fn}"
604         ${upload_fn}
605 }
606
607 announcement_samba_rc() {
608         check_args "${FUNCNAME}" "$#" "0" || return 1
609         require_tagname "${FUNCNAME}"
610
611         test -f "${tagname}.WHATSNEW.txt" || {
612                 echo "${tagname}.WHATSNEW.txt does not exist"
613                 return 1
614         }
615
616         local t=""
617         local version=$(echo "${tagname}" | sed -e 's!^samba-!!')
618         local href="#${version}"
619         local series=$(echo "${version}" | cut -d '.' -f1-2)
620         local rc=$(echo "${version}" | sed -e 's!.*rc\([0-9][0-9]*\)!\1!')
621         local rcname="${rc}th"
622         case "${rc}" in
623         1)
624                 rcname="first"
625                 ;;
626         2)
627                 rcname="second"
628                 ;;
629         3)
630                 rcname="third"
631                 ;;
632         4)
633                 rcname="fourth"
634                 ;;
635         5)
636                 rcname="fifth"
637                 ;;
638         esac
639
640         CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.to.txt"
641         {
642                 echo "samba-announce@lists.samba.org, samba@lists.samba.org, samba-technical@lists.samba.org"
643         } > announce.${tagname}.to.txt
644
645         CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.subject.txt"
646         {
647                 echo "[Announce] Samba ${version} Available for Download"
648         } > announce.${tagname}.subject.txt
649
650         CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.mail.txt"
651         {
652                 cat ${tagname}.WHATSNEW.txt
653                 echo ""
654                 echo "================"
655                 echo "Download Details"
656                 echo "================"
657                 echo ""
658                 echo "The uncompressed tarballs and patch files have been signed"
659                 echo "using GnuPG (ID 6568B7EA).  The source code can be downloaded"
660                 echo "from:"
661                 echo ""
662                 echo "        ${download_url}"
663                 echo ""
664                 echo "The release notes are available online at:"
665                 echo ""
666                 echo "        ${download_url}${tagname}.WHATSNEW.txt"
667                 echo ""
668                 echo "Our Code, Our Bugs, Our Responsibility."
669                 echo "(https://bugzilla.samba.org/)"
670                 echo ""
671                 echo "                        --Enjoy"
672                 echo "                        The Samba Team"
673         } > announce.${tagname}.mail.txt
674
675         CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.mutt-arguments.txt"
676         {
677                 echo -n "-i announce.${tagname}.mail.txt "
678                 echo -n "-s \"$(cat announce.${tagname}.subject.txt | xargs)\" "
679                 echo -n "$(cat announce.${tagname}.to.txt | xargs)"
680         } > announce.${tagname}.mutt-arguments.txt
681
682         local headlinefile="posted_news/@UTCTIME@.${version}.headline.html"
683         CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.headline.html"
684         {
685                 echo "<!-- BEGIN: ${headlinefile} -->"
686                 echo "<li> @UTCDATE@ <a href=\"${href}\">Samba ${version} Available for Download</a></li>"
687                 echo "<!-- END: ${headlinefile} -->"
688         } > announce.${tagname}.headline.html
689
690         local bodyfile="posted_news/@UTCTIME@.${version}.body.html"
691         CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.body.html"
692         {
693                 echo "<!-- BEGIN: ${bodyfile} -->"
694                 echo "<h5><a name=\"${version}\">@UTCDATE@</a></h5>"
695                 echo "<p class="headline">Samba ${version} Available for Download</p>"
696                 echo "<p>"
697                 echo "This is the ${rcname} release candidate of the upcoming Samba ${series} release series."
698                 echo "</p>"
699                 echo "<p>"
700                 echo "The uncompressed tarball has been signed using GnuPG (ID ${GPG_KEYID})."
701                 echo "The source code can be <a href=\"${download_url}${tagname}.tar.gz\">downloaded now</a>."
702                 echo "See <a href=\"${download_url}${tagname}.WHATSNEW.txt\">the release notes for more info</a>."
703                 echo "</p>"
704                 echo "<!-- END: ${bodyfile} -->"
705         } > announce.${tagname}.body.html
706
707         CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.todo.txt"
708         {
709                 ls -lart announce.${tagname}.*
710                 echo ""
711                 echo "NOTICE:"
712                 echo "You need to do the following manual steps in order"
713                 echo "to finish the announcement of ${tagname}!"
714                 echo ""
715                 echo "Change to a samba-web checkout and run"
716                 echo "  ./announce_samba_release.sh ${version} $(pwd)/announce.${tagname}.patch.txt"
717                 echo ""
718                 echo "Once the resulting commit is pushed a cron job will update "
719                 echo "the content exported by the webserver every 5-10 mins."
720                 echo "Check https://www.samba.org"
721                 echo ""
722                 echo "If the web content is updated, you need to send the announce mail (gpg signed)."
723                 echo "- announce.${tagname}.to.txt contains the mail's recipients for the To: header."
724                 echo "- announce.${tagname}.subject.txt contains the mail's subject line."
725                 echo "- announce.${tagname}.mail.txt contains the content of the mail body."
726                 echo "In case your're using mutt, you can use the following shortcut:"
727                 echo "  eval mutt \$(cat announce.${tagname}.mutt-arguments.txt)"
728                 echo ""
729                 echo "NOTICE: you're not done yet! Read the above instructions carefully!"
730                 echo "See: announce.${tagname}.todo.txt"
731                 echo ""
732         } > announce.${tagname}.todo.txt
733
734         ls -lart announce.${tagname}.*
735         return 0
736 }
737
738 announcement_samba_stable() {
739         check_args "${FUNCNAME}" "$#" "0" || return 1
740         require_tagname "${FUNCNAME}"
741
742         load_samba_stable_versions
743
744         test -f "${tagname}.tar.gz" || {
745                 echo "${tagname}.tar.gz does not exist"
746                 return 1
747         }
748
749         test -f "announce.${tagname}.quotation.txt" || {
750                 echo "announce.${tagname}.quotation.txt missing!"
751                 return 1
752         }
753
754         local release_url="${download_url}samba/stable/"
755         local patch_url="${download_url}samba/patches/"
756
757         echo "extract WHATSNEW.txt"
758         tar xf ${tagname}.tar.gz --to-stdout ${tagname}/WHATSNEW.txt > ${TMPDIR}/WHATSNEW.txt
759
760         local t=""
761         local oldversion=$(echo "${oldtagname}" | sed -e 's!^samba-!!')
762         local version=$(echo "${tagname}" | sed -e 's!^samba-!!')
763         local href="#${version}"
764         local series=$(echo "${version}" | cut -d '.' -f1-2)
765         local release=$(echo "${version}" | cut -d '.' -f3)
766         local releasename="latest"
767         case "${release}" in
768         1)
769                 releasename="first"
770                 ;;
771         *)
772                 releasename="latest"
773                 ;;
774         esac
775
776         CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.to.txt"
777         {
778                 echo "samba-announce@lists.samba.org, samba@lists.samba.org, samba-technical@lists.samba.org"
779         } > announce.${tagname}.to.txt
780
781         CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.subject.txt"
782         {
783                 echo "[Announce] Samba ${version} Available for Download"
784         } > announce.${tagname}.subject.txt
785
786         CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.mail.txt"
787         {
788                 local top=$(cat ${TMPDIR}/WHATSNEW.txt | grep -n '^Release notes for older releases follow:' | head -1 | cut -d ':' -f1)
789                 test -n "${top}" || {
790                         top=$(cat ${TMPDIR}/WHATSNEW.txt | wc -l)
791                 }
792                 local skip=$(cat ${TMPDIR}/WHATSNEW.txt | grep -n '^[^ ]' | head -1 | cut -d ':' -f1)
793                 local bottom=$(expr ${top} - \( ${skip} - 1 \))
794
795                 cat "announce.${tagname}.quotation.txt"
796                 echo ""
797                 echo ""
798                 echo "Release Announcements"
799                 echo "---------------------"
800                 echo ""
801                 head -${top} ${TMPDIR}/WHATSNEW.txt | tail -${bottom}
802                 echo ""
803                 echo "================"
804                 echo "Download Details"
805                 echo "================"
806                 echo ""
807                 echo "The uncompressed tarballs and patch files have been signed"
808                 echo "using GnuPG (ID 6568B7EA).  The source code can be downloaded"
809                 echo "from:"
810                 echo ""
811                 echo "        ${release_url}"
812                 echo ""
813                 echo "The release notes are available online at:"
814                 echo ""
815                 echo "        ${history_url}${tagname}.html"
816                 echo ""
817                 echo "Our Code, Our Bugs, Our Responsibility."
818                 echo "(https://bugzilla.samba.org/)"
819                 echo ""
820                 echo "                        --Enjoy"
821                 echo "                        The Samba Team"
822         } > announce.${tagname}.mail.txt
823
824         CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.mutt-arguments.txt"
825         {
826                 echo -n "-i announce.${tagname}.mail.txt "
827                 echo -n "-s \"$(cat announce.${tagname}.subject.txt | xargs)\" "
828                 echo -n "$(cat announce.${tagname}.to.txt | xargs)"
829         } > announce.${tagname}.mutt-arguments.txt
830
831         local htmlfile="history/${tagname}.html"
832         CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.html"
833         {
834                 local tmp=$(cat ${TMPDIR}/WHATSNEW.txt | grep -n '^Reporting bugs & Development Discussion' | head -1 | cut -d ':' -f1)
835                 local lines=$(expr ${tmp} - 2)
836
837                 echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"'
838                 echo ' "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'
839                 echo '<html xmlns="http://www.w3.org/1999/xhtml">'
840
841                 echo "<head>"
842                 echo "<title>Samba ${version} - Release Notes</title>"
843                 echo "</head>"
844
845                 echo "<body>"
846                 echo "<H2>Samba ${version} Available for Download</H2>"
847
848                 echo "<p>"
849                 echo "<a href=\"${release_url}${tagname}.tar.gz\">Samba ${version} (gzipped)</a><br>"
850                 echo "<a href=\"${release_url}${tagname}.tar.asc\">Signature</a>"
851                 echo "</p>"
852
853                 test -n "${patchfile}" && {
854                         echo "<p>"
855                         echo "<a href=\"${patch_url}${patchfile}.gz\">Patch (gzipped) against Samba ${oldversion}</a><br>"
856                         echo "<a href=\"${patch_url}${patchfile}.asc\">Signature</a>"
857                         echo "</p>"
858                 }
859
860                 echo "<p>"
861                 echo "<pre>"
862                 head -${lines} ${TMPDIR}/WHATSNEW.txt | sed \
863                         -e 's!&!\&amp;!g' | sed \
864                         -e 's!<!\&lt;!g' \
865                         -e 's!>!\&gt;!g' \
866                         -e 's!ä!\&auml;!g' \
867                         -e 's!Ä!\&Auml;!g' \
868                         -e 's!ö!\&ouml;!g' \
869                         -e 's!Ö!\&Ouml;!g' \
870                         -e 's!ü!\&uuml;!g' \
871                         -e 's!Ü!\&Uuml;!g' \
872                         -e 's!ß!\&szlig;!g' \
873                         -e 's!"!\&quot;!g' \
874                         -e "s!'!\&apos;!g" \
875                         | cat
876                 echo "</pre>"
877                 echo "</p>"
878
879                 echo "</body>"
880                 echo "</html>"
881         } > announce.${tagname}.html
882
883         local headlinefile="posted_news/@UTCTIME@.${version}.headline.html"
884         CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.headline.html"
885         {
886                 echo "<!-- BEGIN: ${headlinefile} -->"
887                 echo "<li> @UTCDATE@ <a href=\"${href}\">Samba ${version} Available for Download</a></li>"
888                 echo "<!-- END: ${headlinefile} -->"
889         } > announce.${tagname}.headline.html
890
891         local bodyfile="posted_news/@UTCTIME@.${version}.body.html"
892         CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.body.html"
893         {
894                 echo "<!-- BEGIN: ${bodyfile} -->"
895                 echo "<h5><a name=\"${version}\">@UTCDATE@</a></h5>"
896                 echo "<p class="headline">Samba ${version} Available for Download</p>"
897                 echo "<p>"
898                 echo "This is the ${releasename} stable release of the Samba ${series} release series."
899                 echo "</p>"
900                 echo "<p>"
901                 echo "The uncompressed tarball has been signed using GnuPG (ID ${GPG_KEYID})."
902                 echo "The source code can be <a href=\"${release_url}${tagname}.tar.gz\">downloaded now</a>."
903                 test -n "${patchfile}" && {
904                         echo "A <a href=\"${patch_url}${patchfile}.gz\">patch against Samba ${oldversion}</a> is also available."
905                 }
906                 echo "See <a href=\"${history_url}${tagname}.html\">the release notes for more info</a>."
907                 echo "</p>"
908                 echo "<!-- END: ${bodyfile} -->"
909         } > announce.${tagname}.body.html
910
911         local webrepo="${TMPDIR}/webrepo"
912
913         mkdir "${webrepo}" || {
914                 return 1
915         }
916         git -C "${webrepo}" init || {
917                 return 1
918         }
919
920         mkdir -p "$(dirname ${webrepo}/${htmlfile})" || {
921                 return 1
922         }
923         cp -a "announce.${tagname}.html" "${webrepo}/${htmlfile}" || {
924                 return 1
925         }
926
927         mkdir -p "$(dirname ${webrepo}/${headlinefile})" || {
928                 return 1
929         }
930         cp -a "announce.${tagname}.headline.html" "${webrepo}/${headlinefile}" || {
931                 return 1
932         }
933
934         mkdir -p "$(dirname ${webrepo}/${bodyfile})" || {
935                 return 1
936         }
937         cp -a "announce.${tagname}.body.html" "${webrepo}/${bodyfile}" || {
938                 return 1
939         }
940
941         git -C "${webrepo}" add "${htmlfile}" "${headlinefile}" "${bodyfile}" || {
942                 return 1
943         }
944         git -C "${webrepo}" commit --signoff --message "NEWS[${version}]: Samba ${version} Available for Download" || {
945                 return 1
946         }
947         CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.patch.txt"
948         git -C "${webrepo}" format-patch --stdout -1 HEAD > announce.${tagname}.patch.txt || {
949                 return 1
950         }
951
952         CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.todo.txt"
953         {
954                 ls -lart announce.${tagname}.*
955                 echo ""
956                 echo "NOTICE:"
957                 echo "You need to do the following manual steps in order"
958                 echo "to finish the announcement of ${tagname}!"
959                 echo ""
960                 echo "Change to a samba-web checkout and run"
961                 echo "  ./announce_samba_release.sh ${version} $(pwd)/announce.${tagname}.patch.txt"
962                 echo ""
963                 echo "Once the resulting commit is pushed a cron job will update "
964                 echo "the content exported by the webserver every 5-10 mins."
965                 echo "Check https://www.samba.org"
966                 echo ""
967                 echo "If the web content is updated, you need to send the announce mail (gpg signed)."
968                 echo "- announce.${tagname}.to.txt contains the mail's recipients for the To: header."
969                 echo "- announce.${tagname}.subject.txt contains the mail's subject line."
970                 echo "- announce.${tagname}.mail.txt contains the content of the mail body."
971                 echo "In case your're using mutt, you can use the following shortcut:"
972                 echo "  eval mutt \$(cat announce.${tagname}.mutt-arguments.txt)"
973                 echo ""
974                 echo "NOTICE: you're not done yet! Read the above instructions carefully!"
975                 echo "See: announce.${tagname}.todo.txt"
976                 echo ""
977         } > announce.${tagname}.todo.txt
978
979         ls -lart announce.${tagname}.*
980         return 0
981 }
982
983 announcement_release() {
984         check_args "${FUNCNAME}" "$#" "0" || return 1
985
986         test -n "${announcement_fn}" || {
987                 echo "announcement_fn variable empty"
988                 return 1
989         }
990
991         echo "Running ${announcement_fn}"
992         ${announcement_fn}
993 }
994
995 announce_release() {
996         check_args "${FUNCNAME}" "$#" "0" || return 1
997         require_tagname "${FUNCNAME}"
998
999         test -f "announce.${tagname}.todo.txt" || {
1000                 echo "announce.${tagname}.todo.txt does not exist"
1001                 return 1
1002         }
1003
1004         cat announce.${tagname}.todo.txt
1005         return 0
1006 }
1007
1008 case "${product}" in
1009 talloc | tdb | tevent | ldb)
1010         test -z "${GPG_USER-}" && {
1011                 GPG_USER='Samba Library Distribution Key <samba-bugs@samba.org>'
1012         }
1013
1014         test -z "${GPG_KEYID-}"  && {
1015                 GPG_KEYID='13084025'
1016         }
1017
1018         productbase="${product}"
1019         srcdir="lib/${product}"
1020         repo_url="${CONF_REPO_URL}"
1021         upload_url="${CONF_UPLOAD_URL}/${product}/"
1022         download_url="${CONF_DOWNLOAD_URL}/${product}/"
1023
1024         check_fn="check_nopatch"
1025         upload_fn="upload_nopatch"
1026         fullcmds="create check push upload"
1027         ;;
1028 samba-rc)
1029         test -z "${GPG_USER-}" && {
1030                 GPG_USER='Samba Distribution Verification Key <samba-bugs@samba.org>'
1031         }
1032
1033         test -z "${GPG_KEYID-}"  && {
1034                 GPG_KEYID='6568B7EA'
1035         }
1036
1037         productbase="samba"
1038         srcdir="."
1039         repo_url="${CONF_REPO_URL}"
1040         upload_url="${CONF_UPLOAD_URL}/samba/rc/"
1041         download_url="${CONF_DOWNLOAD_URL}/samba/rc/"
1042
1043         verify_fn="verify_samba_rc"
1044         check_fn="check_nopatch"
1045         upload_fn="upload_nopatch"
1046         announcement_fn="announcement_samba_rc"
1047         fullcmds="verify create check whatsnew announcement push upload announce"
1048         ;;
1049 samba-stable)
1050         test -z "${GPG_USER-}" && {
1051                 GPG_USER='Samba Distribution Verification Key <samba-bugs@samba.org>'
1052         }
1053
1054         test -z "${GPG_KEYID-}"  && {
1055                 GPG_KEYID='6568B7EA'
1056         }
1057
1058         productbase="samba"
1059         srcdir="."
1060         repo_url="${CONF_REPO_URL}"
1061         upload_url="${CONF_UPLOAD_URL}/"
1062         download_url="${CONF_DOWNLOAD_URL}/"
1063         history_url="${CONF_HISTORY_URL}/samba/history/"
1064
1065         verify_fn="verify_samba_stable"
1066         check_fn="check_samba_stable"
1067         upload_fn="upload_samba_stable"
1068         announcement_fn="announcement_samba_stable"
1069         fullcmds="verify create patch check announcement push upload announce"
1070         ;;
1071 TODO-samba-security)
1072         test -z "${GPG_USER-}" && {
1073                 GPG_USER='Samba Distribution Verification Key <samba-bugs@samba.org>'
1074         }
1075
1076         test -z "${GPG_KEYID-}"  && {
1077                 GPG_KEYID='6568B7EA'
1078         }
1079
1080         productbase="samba"
1081         srcdir="."
1082         repo_url="${CONF_REPO_URL}"
1083         upload_url="${CONF_UPLOAD_URL}/"
1084         download_url="${CONF_DOWNLOAD_URL}/"
1085         history_url="${CONF_HISTORY_URL}/samba/history/"
1086
1087         verify_fn="verify_samba_stable"
1088         check_fn="check_samba_stable"
1089         upload_fn="upload_samba_stable"
1090         announcement_fn="announcement_samba_security"
1091         fullcmds="verify create patch check announcement"
1092         next_cmd="push"
1093         ;;
1094 *)
1095         usage
1096         echo "Unknown product ${product}"
1097         exit 1
1098 esac
1099
1100 pushd ${srcdir} || {
1101         echo "srcdir[${srcdir}] does not exist"
1102         exit 1
1103 }
1104
1105 trap_handler() {
1106         echo ""
1107         echo "ERROR: cleaning up"
1108         echo ""
1109
1110         for t in ${CLEANUP_TAGS}; do
1111                 echo "Removing tag[${t}]"
1112                 git tag -v "${t}" && {
1113                         git tag -d "${t}" || {
1114                                 echo "failed to remove tag ${t}"
1115                         }
1116                 }
1117         done
1118
1119         for f in ${CLEANUP_FILES}; do
1120                 echo "Removing file[${f}]"
1121                 test -f "${f}" && {
1122                         rm "${f}" || {
1123                                 echo "failed to remove ${f}"
1124                         }
1125                 }
1126         done
1127
1128         for d in ${CLEANUP_DIRS}; do
1129                 echo "Removing dir[${d}]"
1130                 test -d "${d}" && {
1131                         rm -rf "${d}" || {
1132                                 echo "failed to remove ${d}"
1133                         }
1134                 }
1135         done
1136 }
1137
1138 CLEANUP_TAGS=""
1139 CLEANUP_FILES=""
1140 CLEANUP_DIRS=""
1141 trap trap_handler INT QUIT TERM EXIT
1142
1143 cmd_allowed "${globalcmd}" fullrelease ${fullcmds} || {
1144         usage
1145         echo "command[${globalcmd}] not supported for product[${product}]"
1146         exit 1
1147 }
1148
1149 case "${globalcmd}" in
1150 fullrelease)
1151         check_args "${globalcmd}" "$#" "0" || exit 1
1152         cmds="${fullcmds}"
1153         ;;
1154 create)
1155         check_args "${globalcmd}" "$#" "0" || exit 1
1156         check_args "create" "$#" "0" || exit 1
1157
1158         cmds=""
1159         cmd_allowed "verify" ${fullcmds} && {
1160                 cmds="${cmds} verify"
1161         }
1162         cmds="${cmds} create"
1163         cmd_allowed "whatsnew" ${fullcmds} && {
1164                 cmds="${cmds} whatsnew"
1165         }
1166         cmd_allowed "patch" ${fullcmds} && {
1167                 cmds="${cmds} patch"
1168         }
1169         cmds="${cmds} check"
1170         cmd_allowed "announcement" ${fullcmds} && {
1171                 cmds="${cmds} announcement"
1172         }
1173         next_cmd="push"
1174         ;;
1175 push)
1176         check_args "${globalcmd}" "$#" "1" || exit 1
1177         tagname="$1"
1178         cmds="check push"
1179         next_cmd="upload"
1180         ;;
1181 upload)
1182         check_args "${globalcmd}" "$#" "1" || exit 1
1183         tagname="$1"
1184         cmds="check upload"
1185         cmd_allowed "announce" ${fullcmds} && {
1186                 next_cmd="announce"
1187         }
1188         ;;
1189 announce)
1190         check_args "${globalcmd}" "$#" "1" || exit 1
1191         tagname="$1"
1192         cmds="check announce"
1193         ;;
1194 *)
1195         usage
1196         echo "Unknown command ${globalcmd}"
1197         exit 1
1198         ;;
1199 esac
1200
1201 TMPDIR="release.$$"
1202 CLEANUP_DIRS="${CLEANUP_DIRS} ${TMPDIR}"
1203 umask 0077
1204 mkdir "${TMPDIR}"
1205 umask 0022
1206
1207 for cmd in ${cmds}; do
1208         echo "Starting subcommand[${cmd}]"
1209         ${cmd}_release || {
1210                 echo "Failed subcommand[${cmd}]"
1211                 exit 1
1212         }
1213         echo "Finished subcommand[${cmd}]"
1214 done
1215
1216 test -d "${TMPDIR}" && {
1217         rm -rf "${TMPDIR}" || {
1218                 echo "failed to remove ${TMPDIR}"
1219         }
1220 }
1221
1222 test -n "${next_cmd}" && {
1223         echo "Continue with '$0 ${product} ${next_cmd} ${tagname}'."
1224 }
1225
1226 trap - INT QUIT TERM EXIT
1227
1228 exit 0