2 # make a release of Samba or a library
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"
20 echo "Run this script from the top-level directory in the"
26 echo "Usage: release.sh <PRODUCT> <COMMAND>"
28 echo "PRODUCT: ldb, talloc, tevent, tdb, samba-rc"
29 echo "COMMAND: fullrelease, create, push, upload, announce"
39 test x
"${got_args}" = x
"${take_args}" ||
{
41 echo "cmd[${cmd}] takes ${take_args} instead of ${got_args}"
53 test "${got_args}" -ge "${min_args}" ||
{
55 echo "cmd[${cmd}] takes at least ${min_args} instead of ${got_args}"
62 min_args
"$0" "$#" "2"
72 min_args
"${FUNCNAME}" "$#" "1" ||
return 1
75 test -n "${tagname}" ||
{
76 echo "cmd[${cmd}] requires '\${tagname}' variable to be set"
80 local name
=$
(echo "${tagname}" | cut
-d '-' -f1)
81 test x
"${name}" = x
"${productbase}" ||
{
82 echo "Invalid tagname[${tgzname}]"
90 min_args
"${FUNCNAME}" "$#" "2" ||
return 1
94 echo "$@" |
grep -q "\<${cmd}\>" ||
{
102 check_args
"${FUNCNAME}" "$#" "0" ||
return 1
105 echo "VERSION doesn't exist"
109 grep -q 'SAMBA_VERSION_IS_GIT_SNAPSHOT=no' VERSION ||
{
110 echo "SAMBA_VERSION_IS_GIT_SNAPSHOT is not 'no'"
114 grep -q '^SAMBA_VERSION_RC_RELEASE=' VERSION ||
{
115 echo "SAMBA_VERSION_RC_RELEASE= missing"
119 grep -q '^SAMBA_VERSION_RC_RELEASE=$' VERSION
&& {
120 echo "SAMBA_VERSION_RC_RELEASE= missing the rc version"
128 check_args
"${FUNCNAME}" "$#" "0" ||
return 1
130 test -n "${verify_fn}" ||
{
131 echo "verify_fn variable empty"
135 echo "Running ${verify_fn}"
140 check_args
"${FUNCNAME}" "$#" "0" ||
return 1
142 echo "Releasing product ${product}"
144 echo "Building release tarball"
145 local tgzname
=$
(make dist
2>&1 |
grep ^Created | cut
-d' ' -f2)
146 test -f "${tgzname}" ||
{
147 echo "Failed to create tarball"
150 CLEANUP_FILES
="${CLEANUP_FILES} ${tgzname}"
152 local name
=$
(echo "${tgzname}" | cut
-d '-' -f1)
153 test x
"${name}" = x
"${productbase}" ||
{
154 echo "Invalid tgzname[${tgzname}]"
158 local tarname
=$
(basename ${tgzname} .gz
)
159 echo "Tarball: ${tarname}"
160 gunzip
-f ${tgzname} ||
exit 1
161 test -f "${tarname}" ||
{
162 echo "Failed to decompress tarball ${tarname}"
165 CLEANUP_FILES
="${CLEANUP_FILES} ${tarname}"
168 tagname
=$
(basename ${tarname} .
tar)
169 echo "Tagging as ${tagname}"
170 git tag
-u ${GPG_KEYID} -s "${tagname}" -m "${productbase}: tag release ${tagname}" || {
173 CLEANUP_TAGS="${CLEANUP_TAGS} ${tagname}"
176 rm -f "${tarname}.asc
"
177 gpg -u "${GPG_USER}" --detach-sign --armor ${tarname} || {
180 test -f "${tarname}.asc
" || {
181 echo "Failed to create signature
${tarname}.asc
"
184 CLEANUP_FILES="${CLEANUP_FILES} ${tarname}.asc
"
186 gzip -f -9 ${tarname}
187 test -f "${tgzname}" || {
188 echo "Failed to
compress ${tgzname}"
196 check_args "${FUNCNAME}" "$#" "0" || return 1
197 require_tagname "${FUNCNAME}"
199 echo "extract
${tagname}.WHATSNEW.txt
"
200 tar xf ${tagname}.tar.gz --to-stdout ${tagname}/WHATSNEW.txt > ${tagname}.WHATSNEW.txt
201 CLEANUP_FILES="${CLEANUP_FILES} ${tagname}.WHATSNEW.txt
"
207 check_args "${FUNCNAME}" "$#" "0" || return 1
208 require_tagname "${FUNCNAME}"
210 git tag -v "${tagname}" || {
211 echo "failed to verify tag
[${tagname}]"
215 test -f "${tagname}.
tar.gz
" || {
216 echo "${tagname}.
tar.gz does not exist
"
220 test -f "${tagname}.
tar.asc
" || {
221 echo "${tagname}.
tar.asc does not exist
"
231 check_args "${FUNCNAME}" "$#" "0" || return 1
233 test -n "${check_fn}" || {
234 echo "check_fn variable empty
"
238 echo "Running
${check_fn}"
243 check_args "${FUNCNAME}" "$#" "0" || return 1
244 require_tagname "${FUNCNAME}"
246 echo "Push git tag
${tagname} to
'${repo_url}'"
247 git push "${repo_url}" "refs/tags/${tagname}:refs/tags/${tagname}" || {
255 check_args "${FUNCNAME}" "$#" "0" || return 1
256 require_tagname "${FUNCNAME}"
258 echo "Upload
${tagname}.
* to
'${upload_url}'"
259 rsync -Pav ${tagname}.* "${upload_url}/" || {
262 rsync ${upload_url}/${tagname}.*
267 announce_samba_rc() {
268 check_args "${FUNCNAME}" "$#" "0" || return 1
269 require_tagname "${FUNCNAME}"
271 test -f "${tagname}.WHATSNEW.txt
" || {
272 echo "${tagname}.WHATSNEW.txt does not exist
"
277 local utcdate=$(date --utc +"%d
%B
%Y
")
278 local utctime=$(date --utc +"%Y
%m
%d-
%H
%M
%S
")
279 local version=$(echo "${tagname}" | sed -e 's!^samba-!!')
280 local href="#${version}"
281 local series
=$
(echo "${version}" | cut
-d '.' -f1-2)
282 local rc
=$
(echo "${version}" |
sed -e 's!.*rc\([0-9][0-9]*\)!\1!')
283 local rcname
="${rc}th"
303 echo "samba-announce@lists.samba.org, samba@lists.samba.org, samba-technical@lists.samba.org"
304 } > announce.
${tagname}.to.txt
305 CLEANUP_FILES
="${CLEANUP_FILES} announce.${tagname}.to.txt"
308 echo "[Announce] Samba ${version} Available for Download"
309 } > announce.
${tagname}.subject.txt
310 CLEANUP_FILES
="${CLEANUP_FILES} announce.${tagname}.subject.txt"
313 cat ${tagname}.WHATSNEW.txt
315 echo "================"
316 echo "Download Details"
317 echo "================"
319 echo "The uncompressed tarballs and patch files have been signed"
320 echo "using GnuPG (ID 6568B7EA). The source code can be downloaded"
323 echo " ${download_url}"
325 echo "The release notes are available online at:"
327 echo " ${download_url}${tagname}.WHATSNEW.txt"
329 echo "Our Code, Our Bugs, Our Responsibility."
330 echo "(https://bugzilla.samba.org/)"
333 echo " The Samba Team"
334 } > announce.
${tagname}.
mail.txt
335 CLEANUP_FILES
="${CLEANUP_FILES} announce.${tagname}.mail.txt"
338 echo -n "-i announce.${tagname}.mail.txt "
339 echo -n "-s \"$(cat announce.${tagname}.subject.txt | xargs)\" "
340 echo -n "$(cat announce.${tagname}.to.txt | xargs)"
341 } > announce.
${tagname}.mutt-arguments.txt
342 CLEANUP_FILES
="${CLEANUP_FILES} announce.${tagname}.mutt-arguments.txt"
344 local headlinefile
="${utctime}.${version}.headline.html"
346 echo "<!-- BEGIN: posted_news/${headlinefile} -->"
347 echo "<li> ${utcdate} <a href=\"${href}\">Samba ${version} Available for Download</a></li>"
348 echo "<!-- END: posted_news/${headlinefile} -->"
350 CLEANUP_FILES
="${CLEANUP_FILES} ${headlinefile}"
352 local bodyfile
="${utctime}.${version}.body.html"
354 echo "<!-- BEGIN: posted_news/${bodyfile} -->"
355 echo "<h5><a name=\"${version}\">${utcdate}</a></h5>"
356 echo "<p class="headline
">Samba ${version} Available for Download</p>"
358 echo "This is the ${rcname} release candidate of the upcoming Samba ${series} release series."
361 echo "The uncompressed tarball has been signed using GnuPG (ID ${GPG_KEYID})."
362 echo "The source code can be <a href=\"${download_url}${tagname}.tar.gz\">downloaded now</a>."
363 echo "See <a href=\"${download_url}${tagname}.WHATSNEW.txt\">the release notes for more info</a>."
365 echo "<!-- END: posted_news/${bodyfile} -->"
368 CLEANUP_FILES
="${CLEANUP_FILES} ${bodyfile}"
371 ls -lart announce.
${tagname}.* ${headlinefile} ${bodyfile}
374 echo "You need to do the following manual steps in order"
375 echo "to finish the announcement of ${tagname}!"
377 echo "Copy the following files into the posted_news/"
378 echo "subdirectory of the samba-web.git repository and commit them:"
379 echo " ${headlinefile}"
382 echo " cp -a ${utctime}.${version}.*.html /path/to/samba-web/posted_news/"
383 echo " pushd /path/to/samba-web"
384 echo " git add posted_news/${utctime}.${version}.*.html"
385 echo " git commit --signoff --message \"NEWS[${version}]: Samba ${version} Available for Download\""
386 echo " git show -p --stat HEAD"
390 echo "Once the resulting commit is pushed a cron job will update "
391 echo "the content exported by the webserver every 5mins."
393 echo "If the web content is updated, you need to send the announce mail (gpg signed)."
394 echo "- announce.${tagname}.to.txt contains the mail's recipients for the To: header."
395 echo "- announce.${tagname}.subject.txt contains the mail's subject line."
396 echo "- announce.${tagname}.mail.txt contains the content of the mail body."
397 echo "In case your're using mutt, you can use the following shortcut:"
398 echo " eval mutt \$(cat announce.${tagname}.mutt-arguments.txt)"
400 echo "NOTICE: you're not done yet! Read the above instructions carefully!"
401 echo "See: announce.${tagname}.todo.txt"
403 } > announce.
${tagname}.todo.txt
404 CLEANUP_FILES
="${CLEANUP_FILES} announce.${tagname}.todo.txt"
406 cat announce.
${tagname}.todo.txt
412 check_args
"${FUNCNAME}" "$#" "0" ||
return 1
414 test -n "${announce_fn}" ||
{
415 echo "announce_fn variable empty"
419 echo "Running ${announce_fn}"
424 talloc | tdb | tevent | ldb
)
425 test -z "${GPG_USER-}" && {
426 GPG_USER
='Samba Library Distribution Key <samba-bugs@samba.org>'
429 test -z "${GPG_KEYID-}" && {
433 productbase
="${product}"
434 srcdir
="lib/${product}"
435 repo_url
="${CONF_REPO_URL}"
436 upload_url
="${CONF_UPLOAD_URL}/${product}/"
437 download_url
="${CONF_DOWNLOAD_URL}/${product}/"
439 check_fn
="check_nopatch"
440 fullcmds
="create check push upload"
443 test -z "${GPG_USER-}" && {
444 GPG_USER
='Samba Distribution Verification Key <samba-bugs@samba.org>'
447 test -z "${GPG_KEYID-}" && {
453 repo_url
="${CONF_REPO_URL}"
454 upload_url
="${CONF_UPLOAD_URL}/samba/rc/"
455 download_url
="${CONF_DOWNLOAD_URL}/samba/rc/"
457 verify_fn
="verify_samba_rc"
458 check_fn
="check_nopatch"
459 announce_fn
="announce_samba_rc"
460 fullcmds
="verify create check whatsnew push upload announce"
463 test -z "${GPG_USER-}" && {
464 GPG_USER
='Samba Distribution Verification Key <samba-bugs@samba.org>'
467 test -z "${GPG_KEYID-}" && {
473 repo_url
="${CONF_REPO_URL}"
474 upload_url
="${CONF_UPLOAD_URL}/samba/stable/"
475 download_url
="${CONF_DOWNLOAD_URL}/samba/stable/"
477 verify_fn
="verify_samba_stable"
478 check_fn
="check_withpatch"
479 announce_fn
="announce_samba_stable"
480 fullcmds
="verify create patch check push upload announce"
483 test -z "${GPG_USER-}" && {
484 GPG_USER
='Samba Distribution Verification Key <samba-bugs@samba.org>'
487 test -z "${GPG_KEYID-}" && {
493 repo_url
="${CONF_REPO_URL}"
494 upload_url
="${CONF_UPLOAD_URL}/samba/stable/"
495 download_url
="${CONF_DOWNLOAD_URL}/samba/stable/"
497 verify_fn
="verify_samba_stable"
498 check_fn
="check_samba_stable"
499 announce_fn
="announce_samba_security"
500 fullcmds
="verify create patch check"
505 echo "Unknown product ${product}"
510 echo "srcdir[${srcdir}] does not exist"
516 echo "ERROR: cleaning up"
519 for t
in ${CLEANUP_TAGS}; do
520 echo "Removing tag[${t}]"
521 git tag
-v "${t}" && {
522 git tag
-d "${t}" ||
{
523 echo "failed to remove tag ${t}"
528 for f
in ${CLEANUP_FILES}; do
529 echo "Removing file[${f}]"
532 echo "failed to remove ${f}"
540 trap trap_handler INT QUIT TERM EXIT
542 cmd_allowed
"${globalcmd}" fullrelease
${fullcmds} ||
{
544 echo "command[${globalcmd}] not supported for product[${product}]"
548 case "${globalcmd}" in
550 check_args
"${globalcmd}" "$#" "0" ||
exit 1
554 check_args
"${globalcmd}" "$#" "0" ||
exit 1
555 check_args
"create" "$#" "0" ||
exit 1
558 cmd_allowed
"verify" ${fullcmds} && {
559 cmds
="${cmds} verify"
561 cmds
="${cmds} create"
562 cmd_allowed
"whatsnew" ${fullcmds} && {
563 cmds
="${cmds} whatsnew"
565 cmd_allowed
"patch" ${fullcmds} && {
572 check_args
"${globalcmd}" "$#" "1" ||
exit 1
578 check_args
"${globalcmd}" "$#" "1" ||
exit 1
581 cmd_allowed
"symlinks" ${fullcmds} && {
582 cmds
="${cmds} symlinks"
584 cmd_allowed
"announce" ${fullcmds} && {
589 check_args
"${globalcmd}" "$#" "1" ||
exit 1
591 cmds
="check announce"
595 echo "Unknown command ${globalcmd}"
600 for cmd
in ${cmds}; do
601 echo "Starting subcommand[${cmd}]"
603 echo "Failed subcommand[${cmd}]"
606 echo "Finished subcommand[${cmd}]"
609 test -n "${next_cmd}" && {
610 echo "Continue with '$0 ${product} ${next_cmd} ${tagname}'."
613 trap - INT QUIT TERM EXIT