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