script/release.sh: make it possible to create stable .x releases (x >= 1)
[Samba.git] / script / release.sh
blobe5d93a7d90a40d1c22b16063e66af89adf881134
1 #!/bin/bash
2 # make a release of Samba or a library
4 LC_ALL=C
5 export LC_ALL
6 LANG=C
7 export LANG
8 LANGUAGE=C
9 export LANGUAGE
11 set -u
12 set -e
13 umask 0022
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"
20 test -d ".git" || {
21 echo "Run this script from the top-level directory in the"
22 echo "repository"
23 exit 1
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
35 check_args() {
36 local cmd="$1"
37 local got_args="$2"
38 local take_args="$3"
40 test x"${got_args}" = x"${take_args}" || {
41 usage
42 echo "cmd[${cmd}] takes ${take_args} instead of ${got_args}"
43 return 1
46 return 0
49 min_args() {
50 local cmd="$1"
51 local got_args="$2"
52 local min_args="$3"
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
60 return 0
63 min_args "$0" "$#" "2"
65 product="$1"
66 globalcmd="$2"
67 shift 2
68 oldtagname=""
69 tagname=""
70 patchfile=""
71 cmds=""
72 next_cmd=""
74 require_tagname() {
75 min_args "${FUNCNAME}" "$#" "1" || return 1
76 local cmd="$1"
78 test -n "${tagname}" || {
79 echo "cmd[${cmd}] requires '\${tagname}' variable to be set"
80 return 1
83 local name=$(echo "${tagname}" | cut -d '-' -f1)
84 test x"${name}" = x"${productbase}" || {
85 echo "Invalid tagname[${tgzname}]"
86 return 1
89 return 0
92 cmd_allowed() {
93 min_args "${FUNCNAME}" "$#" "2" || return 1
94 local cmd="$1"
95 shift 1
97 echo "$@" | grep -q "\<${cmd}\>" || {
98 return 1
101 return 0
104 verify_samba_rc() {
105 check_args "${FUNCNAME}" "$#" "0" || return 1
107 test -f VERSION || {
108 echo "VERSION doesn't exist"
109 return 1
112 grep -q 'SAMBA_VERSION_IS_GIT_SNAPSHOT=no' VERSION || {
113 echo "SAMBA_VERSION_IS_GIT_SNAPSHOT is not 'no'"
114 return 1
117 grep -q '^SAMBA_VERSION_RC_RELEASE=' VERSION || {
118 echo "SAMBA_VERSION_RC_RELEASE= missing"
119 return 1
122 grep -q '^SAMBA_VERSION_RC_RELEASE=$' VERSION && {
123 echo "SAMBA_VERSION_RC_RELEASE= missing the rc version"
124 return 1
127 return 0
130 load_samba_stable_versions() {
131 check_args "${FUNCNAME}" "$#" "0" || return 1
133 test -n "${version-}" && {
134 return 0
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)
141 version="${SAMBA_VERSION_MAJOR}.${SAMBA_VERSION_MINOR}.${SAMBA_VERSION_RELEASE}"
142 tagname="${productbase}-${version}"
144 test ${SAMBA_VERSION_RELEASE} -gt 0 || {
145 return 0
148 oldversion="${SAMBA_VERSION_MAJOR}.${SAMBA_VERSION_MINOR}.$(expr ${SAMBA_VERSION_RELEASE} - 1)"
149 oldtagname="${productbase}-${oldversion}"
150 patchfile="${productbase}-${oldversion}-${version}.diffs"
152 return 0
155 verify_samba_stable() {
156 check_args "${FUNCNAME}" "$#" "0" || return 1
158 test -f VERSION || {
159 echo "VERSION doesn't exist"
160 return 1
163 grep -q 'SAMBA_VERSION_IS_GIT_SNAPSHOT=no' VERSION || {
164 echo "SAMBA_VERSION_IS_GIT_SNAPSHOT is not 'no'"
165 return 1
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
185 done
187 load_samba_stable_versions
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
209 test -n "${oldtagname}" || {
210 return 0
213 local verify_out="${TMPDIR}/verify-${oldtagname}.out"
215 echo "Verifying oldtagname: ${oldtagname}"
217 git tag -v "${oldtagname}" >${verify_out} 2>&1 || {
218 echo "failed to verify old tag[${oldtagname}]"
219 return 1
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
229 echo "Verifying ${oldtagname}.tar.gz and ${oldtagname}.tar.asc"
231 test -f "${oldtagname}.tar.gz" || {
232 echo "${oldtagname}.tar.gz does not exist"
233 return 1
236 test -f "${oldtagname}.tar.asc" || {
237 echo "${oldtagname}.tar.asc does not exist"
238 return 1
241 zcat "${oldtagname}.tar.gz" | gpg --verify "${oldtagname}.tar.asc" - 2>${verify_out} || {
242 echo "Failed to verify ${oldtagname}.tar.asc"
243 return 1
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
253 return 0
256 verify_release() {
257 check_args "${FUNCNAME}" "$#" "0" || return 1
259 test -n "${verify_fn}" || {
260 echo "verify_fn variable empty"
261 return 1
264 echo "Running ${verify_fn}"
265 ${verify_fn}
268 create_release() {
269 check_args "${FUNCNAME}" "$#" "0" || return 1
271 echo "Releasing product ${product}"
273 test -n "${tagname}" && {
274 git tag -l "${tagname}" | grep -q "${tagname}" && {
275 echo "tagname[${tagname}] already exist"
276 return 1
279 local _tgzname="${tagname}.tar.gz"
280 test -e "${_tgzname}" && {
281 echo "_tgzname[${_tgzname}] already exist"
282 return 1
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
292 CLEANUP_FILES="${CLEANUP_FILES} ${tgzname}"
294 local name=$(echo "${tgzname}" | cut -d '-' -f1)
295 test x"${name}" = x"${productbase}" || {
296 echo "Invalid tgzname[${tgzname}]"
297 return 1
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
307 tagname="${_tagname}"
309 local tarname=$(basename ${tgzname} .gz)
310 echo "Tarball: ${tarname}"
311 gunzip -f ${tgzname} || {
312 echo "Failed to decompress tarball ${tarname}"
313 return 1
315 test -f "${tarname}" || {
316 echo "Failed to decompress tarball ${tarname}"
317 return 1
319 CLEANUP_FILES="${CLEANUP_FILES} ${tarname}"
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
326 CLEANUP_TAGS="${CLEANUP_TAGS} ${tagname}"
328 echo "Signing ${tarname} => ${tarname}.asc"
329 rm -f "${tarname}.asc"
330 gpg -u "${GPG_USER}" --detach-sign --armor ${tarname} || {
331 return 1
333 test -f "${tarname}.asc" || {
334 echo "Failed to create signature ${tarname}.asc"
335 return 1
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
345 return 0
348 patch_release() {
349 check_args "${FUNCNAME}" "$#" "0" || return 1
350 require_tagname "${FUNCNAME}"
352 test -n "${patchfile}" || {
353 return 0
356 local oldpwd=$(pwd)
357 echo "Generating ${patchfile}"
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
367 CLEANUP_FILES="${CLEANUP_FILES} ${patchfile}"
368 mv "${TMPDIR}/${patchfile}" "${patchfile}" || {
369 echo "failed cmd[mv ${TMPDIR}/${patchfile} ${patchfile}]"
370 return 1
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
379 test -f "${patchfile}.asc" || {
380 echo "Failed to create signature ${patchfile}.asc"
381 return 1
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
391 return 0
394 whatsnew_release() {
395 check_args "${FUNCNAME}" "$#" "0" || return 1
396 require_tagname "${FUNCNAME}"
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"
402 return 0
405 check_nopatch() {
406 check_args "${FUNCNAME}" "$#" "0" || return 1
407 require_tagname "${FUNCNAME}"
409 local verify_out="${TMPDIR}/verify-${oldtagname}.out"
411 echo "Verifying tagname: ${tagname}"
413 git tag -v "${tagname}" >${verify_out} 2>&1 || {
414 echo "failed to verify old tag[${oldtagname}]"
415 return 1
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
424 echo "Verifying ${tagname}.tar.gz and ${tagname}.tar.asc"
426 test -f "${tagname}.tar.gz" || {
427 echo "${tagname}.tar.gz does not exist"
428 return 1
431 test -f "${tagname}.tar.asc" || {
432 echo "${tagname}.tar.asc does not exist"
433 return 1
436 zcat "${tagname}.tar.gz" | gpg --verify "${tagname}.tar.asc" - 2>${verify_out} || {
437 echo "Failed to verify ${tagname}.tar.asc"
438 return 1
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
447 ls -la ${tagname}.*
449 return 0
452 check_samba_stable() {
453 check_args "${FUNCNAME}" "$#" "0" || return 1
454 require_tagname "${FUNCNAME}"
456 load_samba_stable_versions
458 local verify_out="${TMPDIR}/verify-${oldtagname}.out"
460 echo "Verifying tagname: ${tagname}"
462 git tag -v "${tagname}" >${verify_out} 2>&1 || {
463 echo "failed to verify old tag[${oldtagname}]"
464 return 1
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
473 echo "Verifying ${tagname}.tar.gz and ${tagname}.tar.asc"
475 test -f "${tagname}.tar.gz" || {
476 echo "${tagname}.tar.gz does not exist"
477 return 1
480 test -f "${tagname}.tar.asc" || {
481 echo "${tagname}.tar.asc does not exist"
482 return 1
485 zcat "${tagname}.tar.gz" | gpg --verify "${tagname}.tar.asc" - 2>${verify_out} || {
486 echo "Failed to verify ${tagname}.tar.asc"
487 return 1
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
496 test -n "${patchfile}" || {
497 ls -lart ${tagname}.*
498 return 0
501 echo "Verifying ${patchfile}.gz and ${patchfile}.asc"
503 test -f "${patchfile}.gz" || {
504 echo "${patchfile}.gz does not exist"
505 return 1
508 test -f "${patchfile}.asc" || {
509 echo "${patchfile}.asc does not exist"
510 return 1
513 zcat "${patchfile}.gz" | gpg --verify "${patchfile}.asc" - 2>${verify_out} || {
514 echo "Failed to verify ${patchfile}.asc"
515 return 1
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
524 ls -lart ${tagname}.* ${patchfile}.*
525 return 0
528 check_release() {
529 check_args "${FUNCNAME}" "$#" "0" || return 1
531 test -n "${check_fn}" || {
532 echo "check_fn variable empty"
533 return 1
536 echo "Running ${check_fn}"
537 ${check_fn}
540 push_release() {
541 check_args "${FUNCNAME}" "$#" "0" || return 1
542 require_tagname "${FUNCNAME}"
544 echo "Push git tag ${tagname} to '${repo_url}'"
545 git push "${repo_url}" "refs/tags/${tagname}:refs/tags/${tagname}" || {
546 return 1
549 return 0
552 upload_nopatch() {
553 check_args "${FUNCNAME}" "$#" "0" || return 1
554 require_tagname "${FUNCNAME}"
556 echo "Upload ${tagname}.* to '${upload_url}'"
557 rsync -Pav --delay-updates ${tagname}.* "${upload_url}/" || {
558 return 1
560 rsync ${upload_url}/${tagname}.*
562 return 0
565 upload_samba_stable() {
566 check_args "${FUNCNAME}" "$#" "0" || return 1
567 require_tagname "${FUNCNAME}"
569 load_samba_stable_versions
571 local release_url="${upload_url}samba/stable/"
572 local patch_url="${upload_url}samba/patches/"
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
579 rsync ${release_url}/${tagname}.tar.*
581 test -n "${patchfile}" || {
582 return 0
585 echo "Upload ${patchfile}.* to '${patch_url}'"
586 ls -lart ${patchfile}.*
587 rsync -Pav --delay-updates ${patchfile}.* "${patch_url}/" || {
588 return 1
590 rsync ${patch_url}/${patchfile}.*
592 return 0
595 upload_release() {
596 check_args "${FUNCNAME}" "$#" "0" || return 1
598 test -n "${upload_fn}" || {
599 echo "upload_fn variable empty"
600 return 1
603 echo "Running ${upload_fn}"
604 ${upload_fn}
607 announcement_samba_rc() {
608 check_args "${FUNCNAME}" "$#" "0" || return 1
609 require_tagname "${FUNCNAME}"
611 test -f "${tagname}.WHATSNEW.txt" || {
612 echo "${tagname}.WHATSNEW.txt does not exist"
613 return 1
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
624 rcname="first"
627 rcname="second"
630 rcname="third"
633 rcname="fourth"
636 rcname="fifth"
638 esac
640 CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.to.txt"
642 echo "samba-announce@lists.samba.org, samba@lists.samba.org, samba-technical@lists.samba.org"
643 } > announce.${tagname}.to.txt
645 CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.subject.txt"
647 echo "[Announce] Samba ${version} Available for Download"
648 } > announce.${tagname}.subject.txt
650 CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.mail.txt"
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
675 CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.mutt-arguments.txt"
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
682 local headlinefile="posted_news/@UTCTIME@.${version}.headline.html"
683 CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.headline.html"
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
690 local bodyfile="posted_news/@UTCTIME@.${version}.body.html"
691 CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.body.html"
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
707 CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.todo.txt"
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
734 ls -lart announce.${tagname}.*
735 return 0
738 announcement_samba_stable() {
739 check_args "${FUNCNAME}" "$#" "0" || return 1
740 require_tagname "${FUNCNAME}"
742 load_samba_stable_versions
744 test -f "${tagname}.tar.gz" || {
745 echo "${tagname}.tar.gz does not exist"
746 return 1
749 test -f "announce.${tagname}.quotation.txt" || {
750 echo "announce.${tagname}.quotation.txt missing!"
751 return 1
754 local release_url="${download_url}samba/stable/"
755 local patch_url="${download_url}samba/patches/"
757 echo "extract WHATSNEW.txt"
758 tar xf ${tagname}.tar.gz --to-stdout ${tagname}/WHATSNEW.txt > ${TMPDIR}/WHATSNEW.txt
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
769 releasename="first"
772 releasename="latest"
774 esac
776 CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.to.txt"
778 echo "samba-announce@lists.samba.org, samba@lists.samba.org, samba-technical@lists.samba.org"
779 } > announce.${tagname}.to.txt
781 CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.subject.txt"
783 echo "[Announce] Samba ${version} Available for Download"
784 } > announce.${tagname}.subject.txt
786 CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.mail.txt"
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)
792 local skip=$(cat ${TMPDIR}/WHATSNEW.txt | grep -n '^[^ ]' | head -1 | cut -d ':' -f1)
793 local bottom=$(expr ${top} - \( ${skip} - 1 \))
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
824 CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.mutt-arguments.txt"
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
831 local htmlfile="history/${tagname}.html"
832 CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.html"
834 local tmp=$(cat ${TMPDIR}/WHATSNEW.txt | grep -n '^Reporting bugs & Development Discussion' | head -1 | cut -d ':' -f1)
835 local lines=$(expr ${tmp} - 2)
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">'
841 echo "<head>"
842 echo "<title>Samba ${version} - Release Notes</title>"
843 echo "</head>"
845 echo "<body>"
846 echo "<H2>Samba ${version} Available for Download</H2>"
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>"
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>"
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>"
879 echo "</body>"
880 echo "</html>"
881 } > announce.${tagname}.html
883 local headlinefile="posted_news/@UTCTIME@.${version}.headline.html"
884 CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.headline.html"
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
891 local bodyfile="posted_news/@UTCTIME@.${version}.body.html"
892 CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.body.html"
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."
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
911 local webrepo="${TMPDIR}/webrepo"
913 mkdir "${webrepo}" || {
914 return 1
916 git -C "${webrepo}" init || {
917 return 1
920 mkdir -p "$(dirname ${webrepo}/${htmlfile})" || {
921 return 1
923 cp -a "announce.${tagname}.html" "${webrepo}/${htmlfile}" || {
924 return 1
927 mkdir -p "$(dirname ${webrepo}/${headlinefile})" || {
928 return 1
930 cp -a "announce.${tagname}.headline.html" "${webrepo}/${headlinefile}" || {
931 return 1
934 mkdir -p "$(dirname ${webrepo}/${bodyfile})" || {
935 return 1
937 cp -a "announce.${tagname}.body.html" "${webrepo}/${bodyfile}" || {
938 return 1
941 git -C "${webrepo}" add "${htmlfile}" "${headlinefile}" "${bodyfile}" || {
942 return 1
944 git -C "${webrepo}" commit --signoff --message "NEWS[${version}]: Samba ${version} Available for Download" || {
945 return 1
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
952 CLEANUP_FILES="${CLEANUP_FILES} announce.${tagname}.todo.txt"
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
979 ls -lart announce.${tagname}.*
980 return 0
983 announcement_release() {
984 check_args "${FUNCNAME}" "$#" "0" || return 1
986 test -n "${announcement_fn}" || {
987 echo "announcement_fn variable empty"
988 return 1
991 echo "Running ${announcement_fn}"
992 ${announcement_fn}
995 announce_release() {
996 check_args "${FUNCNAME}" "$#" "0" || return 1
997 require_tagname "${FUNCNAME}"
999 test -f "announce.${tagname}.todo.txt" || {
1000 echo "announce.${tagname}.todo.txt does not exist"
1001 return 1
1004 cat announce.${tagname}.todo.txt
1005 return 0
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>'
1014 test -z "${GPG_KEYID-}" && {
1015 GPG_KEYID='13084025'
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}/"
1024 check_fn="check_nopatch"
1025 upload_fn="upload_nopatch"
1026 fullcmds="create check push upload"
1028 samba-rc)
1029 test -z "${GPG_USER-}" && {
1030 GPG_USER='Samba Distribution Verification Key <samba-bugs@samba.org>'
1033 test -z "${GPG_KEYID-}" && {
1034 GPG_KEYID='6568B7EA'
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/"
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"
1049 samba-stable)
1050 test -z "${GPG_USER-}" && {
1051 GPG_USER='Samba Distribution Verification Key <samba-bugs@samba.org>'
1054 test -z "${GPG_KEYID-}" && {
1055 GPG_KEYID='6568B7EA'
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/"
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"
1071 TODO-samba-security)
1072 test -z "${GPG_USER-}" && {
1073 GPG_USER='Samba Distribution Verification Key <samba-bugs@samba.org>'
1076 test -z "${GPG_KEYID-}" && {
1077 GPG_KEYID='6568B7EA'
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/"
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"
1095 usage
1096 echo "Unknown product ${product}"
1097 exit 1
1098 esac
1100 pushd ${srcdir} || {
1101 echo "srcdir[${srcdir}] does not exist"
1102 exit 1
1105 trap_handler() {
1106 echo ""
1107 echo "ERROR: cleaning up"
1108 echo ""
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}"
1117 done
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}"
1126 done
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}"
1135 done
1138 CLEANUP_TAGS=""
1139 CLEANUP_FILES=""
1140 CLEANUP_DIRS=""
1141 trap trap_handler INT QUIT TERM EXIT
1143 cmd_allowed "${globalcmd}" fullrelease ${fullcmds} || {
1144 usage
1145 echo "command[${globalcmd}] not supported for product[${product}]"
1146 exit 1
1149 case "${globalcmd}" in
1150 fullrelease)
1151 check_args "${globalcmd}" "$#" "0" || exit 1
1152 cmds="${fullcmds}"
1154 create)
1155 check_args "${globalcmd}" "$#" "0" || exit 1
1156 check_args "create" "$#" "0" || exit 1
1158 cmds=""
1159 cmd_allowed "verify" ${fullcmds} && {
1160 cmds="${cmds} verify"
1162 cmds="${cmds} create"
1163 cmd_allowed "whatsnew" ${fullcmds} && {
1164 cmds="${cmds} whatsnew"
1166 cmd_allowed "patch" ${fullcmds} && {
1167 cmds="${cmds} patch"
1169 cmds="${cmds} check"
1170 cmd_allowed "announcement" ${fullcmds} && {
1171 cmds="${cmds} announcement"
1173 next_cmd="push"
1175 push)
1176 check_args "${globalcmd}" "$#" "1" || exit 1
1177 tagname="$1"
1178 cmds="check push"
1179 next_cmd="upload"
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"
1189 announce)
1190 check_args "${globalcmd}" "$#" "1" || exit 1
1191 tagname="$1"
1192 cmds="check announce"
1195 usage
1196 echo "Unknown command ${globalcmd}"
1197 exit 1
1199 esac
1201 TMPDIR="release.$$"
1202 CLEANUP_DIRS="${CLEANUP_DIRS} ${TMPDIR}"
1203 umask 0077
1204 mkdir "${TMPDIR}"
1205 umask 0022
1207 for cmd in ${cmds}; do
1208 echo "Starting subcommand[${cmd}]"
1209 ${cmd}_release || {
1210 echo "Failed subcommand[${cmd}]"
1211 exit 1
1213 echo "Finished subcommand[${cmd}]"
1214 done
1216 test -d "${TMPDIR}" && {
1217 rm -rf "${TMPDIR}" || {
1218 echo "failed to remove ${TMPDIR}"
1222 test -n "${next_cmd}" && {
1223 echo "Continue with '$0 ${product} ${next_cmd} ${tagname}'."
1226 trap - INT QUIT TERM EXIT
1228 exit 0