aboutsummaryrefslogtreecommitdiff
path: root/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'scripts')
-rwxr-xr-xscripts/release-notes.pl214
1 files changed, 214 insertions, 0 deletions
diff --git a/scripts/release-notes.pl b/scripts/release-notes.pl
new file mode 100755
index 000000000..3726dc977
--- /dev/null
+++ b/scripts/release-notes.pl
@@ -0,0 +1,214 @@
+#!/usr/bin/perl
+#***************************************************************************
+# _ _ ____ _
+# Project ___| | | | _ \| |
+# / __| | | | |_) | |
+# | (__| |_| | _ <| |___
+# \___|\___/|_| \_\_____|
+#
+# Copyright (C) 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at https://curl.haxx.se/docs/copyright.html.
+#
+# You may opt to use, copy, modify, merge, publish, distribute and/or sell
+# copies of the Software, and permit persons to whom the Software is
+# furnished to do so, under the terms of the COPYING file.
+#
+# This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+# KIND, either express or implied.
+#
+###########################################################################
+
+###############################################
+#
+# ==== How to use this script ====
+#
+# 1. Get recent commits added to RELEASE-NOTES:
+#
+# $ ./scripts/release-notes
+#
+# 2. Edit RELEASE-NOTES and *remove* entries among the newly added ones that
+# don't belong. Don't mind leaving unused references below. Make sure to move
+# "changes" up to the changes section. All new ones will by default be listed
+# under bug-fixes as the script can't know where to put them.
+#
+# 3. Run the cleanup script and let it sort the entries and remove unused
+# references from lines you removed in step (2):
+#
+# $ ./script/release-notes cleanup
+#
+# 4. Reload RELEASE-NOTES and verify that things look okay. The cleanup
+# procedure can and should be re-run when lines are removed or rephrased.
+#
+# 5. Run ./scripts/contributors.sh and update the contributor list of names
+# The list can also be extended or edited manually.
+#
+# 6. Run ./scripts/delta and update the contributor count at the top, and
+# double-check/update the other counters.
+#
+# 7. Commit the file using "RELEASE-NOTES: synced" as commit message.
+#
+################################################
+
+my $cleanup = ($ARGV[0] eq "cleanup");
+my @gitlog=`git log @^{/RELEASE-NOTES:.synced}..` if(!$cleanup);
+my @releasenotes=`cat RELEASE-NOTES`;
+
+my $refnum; # the highest number used so far
+my @refused;
+
+my @o;
+for my $l (@releasenotes) {
+ if($l =~ /^ o .*\[(\d+)\]/) {
+ $refused[$1]=1;
+ }
+ elsif($l =~ /^ \[(\d+)\] = /) {
+ $refused[$1] |= 2;
+ $refnum=$1;
+ }
+}
+
+sub getref {
+ for my $r (1 .. $refnum) {
+ if(!$refused[$r] & 1) {
+ return $r;
+ }
+ }
+ # add at the end
+ return ++$refnum;
+}
+
+my $short;
+my $first;
+for my $l (@gitlog) {
+ chomp $l;
+ if($l =~ /^commit/) {
+ if($first) {
+ onecommit($short);
+ }
+ # starts a new commit
+ undef @fixes;
+ undef @closes;
+ undef @bug;
+ $short = "";
+ $first = 0;
+ }
+ elsif(($l =~ /^ (.*)/) && !$first) {
+ # first line
+ $short = $1;
+ $first = 1;
+ push @line, $short;
+ }
+ elsif(($l =~ /^ (.*)/) && $first) {
+ # not the first
+ my $line = $1;
+
+ if($line =~ /^Fixes .*[^0-9](\d+)/i) {
+ push @fixes, $1;
+ }
+ elsif($line =~ /^Closes .*[^0-9](\d+)/i) {
+ push @closes, $1;
+ }
+ elsif($line =~ /^Bug: (.*)/i) {
+ push @bug, $1;
+ }
+ }
+}
+if($first) {
+ onecommit($short);
+}
+
+# call at the end of a parsed commit
+sub onecommit {
+ my ($short)=@_;
+ my $ref;
+
+ if($bug[0]) {
+ $ref = $bug[0];
+ }
+ elsif($fixes[0]) {
+ $ref = $fixes[0];
+ }
+ elsif($closes[0]) {
+ $ref = $closes[0];
+ }
+
+ if($ref =~ /^(\d+)/) {
+ $ref = "https://curl.haxx.se/bug/?i=$1"
+ }
+ if($ref) {
+ my $r = getref();
+ $refs[$r] = $ref;
+ $moreinfo{$short}=$r;
+ $refused[$r] |= 1;
+ }
+}
+
+#### Output the new RELEASE-NOTES
+
+my @bullets;
+for my $l (@releasenotes) {
+ if(($l =~ /^This release includes the following bugfixes:/) && !$cleanup) {
+ push @o, $l;
+ push @o, "\n";
+ for my $f (@line) {
+ push @o, sprintf " o $f%s\n", $moreinfo{$f}? sprintf(" [%d]", $moreinfo{$f}): "";
+ $refused[$moreinfo{$f}]=3;
+ }
+ push @o, " --- new entries are listed above this ---";
+ }
+ elsif($cleanup) {
+ if($l =~ /^ --- new entries are listed/) {
+ # ignore this if still around
+ next;
+ }
+ elsif($l =~ /^ o .*/) {
+ push @bullets, $l;
+ next;
+ }
+ elsif($l =~ /^ \[(\d+)\] = /) {
+ if($refused[$1] & 1) {
+ # only output actually used references
+ push @o, $l;
+ }
+ next;
+ }
+ elsif($bullets[0]) {
+ # output them case insensitively
+ for my $b (sort { "\L$a" cmp "\L$b" } @bullets) {
+ push @o, $b;
+ }
+ undef @bullets;
+ }
+ push @o, $l;
+ }
+ else {
+ push @o, $l;
+ }
+}
+
+for my $f (@line) {
+ my $n = $moreinfo{$f};
+ my $r;
+ if($n) {
+ $r = $refs[$n];
+ push @o, sprintf " [%d] = %s\n", $n, $r;
+ }
+}
+
+open(O, ">RELEASE-NOTES");
+for my $l (@o) {
+ print O $l;
+}
+close(O);
+
+exit;
+
+# Debug: show unused references
+for my $r (1 .. ($refnum - 1)) {
+ if($refused[$r] != 3) {
+ printf "$r is %d!\n", $refused[$r];
+ }
+}