From a499f79fd01c74ec949c927fa656d689733a7c0e Mon Sep 17 00:00:00 2001
From: Bruce Momjian <bruce@momjian.us>
Date: Mon, 16 Sep 2024 13:26:36 -0400
Subject: [PATCH] scripts:  add Perl script to add links to release notes

Reported-by: jian he

Discussion: https://postgr.es/m/ZuYsS5XdA7hVcV9l@momjian.us

Backpatch-through: 12
---
 src/tools/RELEASE_CHANGES     |   1 +
 src/tools/add_commit_links.pl | 136 ++++++++++++++++++++++++++++++++++
 2 files changed, 137 insertions(+)
 create mode 100755 src/tools/add_commit_links.pl

diff --git a/src/tools/RELEASE_CHANGES b/src/tools/RELEASE_CHANGES
index 5cf2a4dda3c..2d0fb296f95 100644
--- a/src/tools/RELEASE_CHANGES
+++ b/src/tools/RELEASE_CHANGES
@@ -10,6 +10,7 @@ For All Releases (major, minor, beta, RC)
 	o update doc/src/sgml/release-NN.sgml in relevant branches
 	o run spellchecker on result
 	o add SGML markup
+	o run src/tools/add_commit_links.pl
 
 * Update timezone data to match latest IANA timezone database and new
   Windows releases, if any (see src/timezone/README)
diff --git a/src/tools/add_commit_links.pl b/src/tools/add_commit_links.pl
new file mode 100755
index 00000000000..ebfc97ea328
--- /dev/null
+++ b/src/tools/add_commit_links.pl
@@ -0,0 +1,136 @@
+#! /usr/bin/perl
+
+#################################################################
+# add_commit_links.pl -- add commit links to the release notes
+#
+# Copyright (c) 2024, PostgreSQL Global Development Group
+#
+# src/tools/add_commit_links.pl
+#################################################################
+
+#
+# This script adds commit links to the release notes.
+#
+# Usage: cd to top of source tree and issue
+#	src/tools/add_commit_links.pl release_notes_file
+#
+# The script can add links for release note items that lack them, and update
+# those that have them.  The script is sensitive to the release note file being
+# in a specific format:
+#
+#  * File name contains the major version number preceded by a dash
+#    and followed by a period
+#  * Commit text is generated by src/tools/git_changelog
+#  * SGML comments around commit text start in the first column
+#  * The commit item title ends with an attribution that ends with
+#    a closing parentheses
+#  * previously added URL link text is unmodified
+#  * a "<para>" follows the commit item title
+#
+# The major version number is used to select the commit hash for minor
+# releases.  An error will be generated if valid commits are found but
+# no proper location for the commit links is found.
+
+use strict;
+use warnings FATAL => 'all';
+
+sub process_file
+{
+	my $file = shift;
+
+	my $in_comment = 0;
+	my $prev_line_ended_with_paren = 0;
+	my $prev_leading_space = '';
+	my $lineno = 0;
+
+	my @hashes = ();
+
+	my $tmpfile = $file . '.tmp';
+
+	# Get major version number from the file name.
+	$file =~ m/-(\d+)\./;
+	my $major_version = $1;
+
+	open(my $fh, '<', $file) || die "could not open file %s: $!\n", $file;
+	open(my $tfh, '>', $tmpfile) || die "could not open file %s: $!\n",
+	  $tmpfile;
+
+	while (<$fh>)
+	{
+		$lineno++;
+
+		$in_comment = 1 if (m/^<!--/);
+
+		# skip over commit links because we will add them below
+		next
+		  if (!$in_comment &&
+			m{^\s*<ulink url="&commit_baseurl;[\da-f]+">&sect;</ulink>\s*$});
+
+		if ($in_comment && m/\[([\da-f]+)\]/)
+		{
+			my $hash = $1;
+
+			# major release item
+			(!m/^Branch:/) && push(@hashes, $hash);
+
+			# minor release item
+			m/^Branch:/ &&
+			  defined($major_version) &&
+			  m/_${major_version}_/ &&
+			  push(@hashes, $hash);
+		}
+
+		if (!$in_comment && m{</para>})
+		{
+			if (@hashes)
+			{
+				if ($prev_line_ended_with_paren)
+				{
+					for my $hash (@hashes)
+					{
+						print({$tfh}
+							  "$prev_leading_space<ulink url=\"&commit_baseurl;$hash\">&sect;</ulink>\n"
+						);
+					}
+					@hashes = ();
+				}
+				else
+				{
+					printf(
+						"hashes found but no matching text found for placement on line %s\n",
+						$lineno);
+					exit(1);
+				}
+			}
+		}
+
+		print({$tfh} $_);
+
+		$prev_line_ended_with_paren = m/\)\s*$/;
+
+		m/^(\s*)/;
+		$prev_leading_space = $1;
+
+		$in_comment = 0 if (m/^-->/);
+	}
+
+	close($fh);
+	close($tfh);
+
+	rename($tmpfile, $file) || die "could not rename %s to %s: $!\n",
+	  $tmpfile,
+	  $file;
+
+	return;
+}
+
+if (@ARGV == 0)
+{
+	printf(STDERR "Usage: %s release_notes_file [...]\n", $0);
+	exit(1);
+}
+
+for my $file (@ARGV)
+{
+	process_file($file);
+}
-- 
2.39.5