patch-git: Changelog formatting updates (RHEL-111490)

Long lines in changelogs are now word-wrapped automatically, unless
the changelog is explicitly formatted using "-  " lines.

RPM-Changelog: -
RPM-Skip-Release: yes
Related: RHEL-111490
This commit is contained in:
Florian Weimer 2025-09-23 10:02:55 +02:00
parent a243a59e4e
commit e95aa14bd2
2 changed files with 140 additions and 49 deletions

View File

@ -101,6 +101,9 @@ The following `Key: value` pairs are recognized.
- Fix memory leak in fdopen (bug 31840)
- libio: Test for fdopen memory leak without SEEK_END
```
If there are no `- ` lines, the changelog entry is automatically
word-wrapped. If `- ` lines are used, the line breaks found in the
trailer are preserved in the RPM `%changelog` section.
* `RPM-Changelog-Stop`. Boolean. When `yes`, generation
of changelog entries stops at this commit. Requires `Parent`.

View File

@ -883,6 +883,22 @@ do
assert(err == 'ticket reference without trailing number: bug')
end
-- Append a line to the changelog table. It is prefixed with '- '.
-- Long lines are wrapped at word boundaries and indented.
local function append_to_rpm_changelog(line, result)
if #result == 0 then
result[1] = '-'
end
for word in string.gmatch(line, '%S+') do
if #result[#result] + #word > 76 then
result[#result + 1] = ' ' .. word
else
result[#result] = result[#result] .. ' ' .. word
end
end
end
-- Extract the trailers from the passed commit message. Returns a
-- single table where keys are derived from the trailer tags.
-- On error, returns nil and an error message.
@ -928,7 +944,9 @@ do
assert(not n and err == 'Patch-Git-Version does not contain a number')
end
-- Validator for RPM-Changelog.
-- Validator for RPM-Changelog. It returns the changelog entries
-- as a table of lines. The lines start with '- ' or ' ', unless
-- they are empty.
local function parse_rpm_changelog(tag, s)
assert(string.sub(s, #s) == '\n')
@ -938,11 +956,11 @@ do
end
local lines = {}
for line in string.gmatch(s, '([^\n]+\n)') do
for line in string.gmatch(s, '([^\n]+)\n') do
lines[#lines + 1] = line
end
-- Remove leading whitespace from the first line.
lines[1] = assert(string.match(lines[1], '^[ \t]*(.*\n)$'))
lines[1] = assert(string.match(lines[1], '^[ \t]*(.*)$'))
if #lines == 1 then
-- Nothing to do
else
@ -964,22 +982,31 @@ do
local result = {}
if not string.match(lines[1], '^- ') then
-- This is not an itemized changelog entry. The loop below
-- appends to this entry.
result[1] = ''
end
for _, line in ipairs(lines) do
local tagged = string.match(line, '^-[ \t]+(.*)%s*\n')
if tagged then
-- New entry.
result[#result + 1] = tagged
else
local stripped = assert(string.match(line, '%s*(.*)%s*\n'))
local old = result[#result]
if old ~= '' then
old = old .. ' '
end
result[#result] = old .. stripped
-- This is not an itemized changelog entry. Concatenate all
-- lines with word-wrapping.
for _, line in ipairs(lines) do
append_to_rpm_changelog(line, result)
end
else
local dashed = false
for lineno, line in ipairs(lines) do
if lineno > 1 and string.match(line, '^- ') then
dashed = true
end
end
for lineno, line in ipairs(lines) do
if not string.match(line, '^- ') then
if string.match(line, '^%s*$') then
line = ''
elseif not dashed then
-- If there are no '- ' lines in the continuation
-- part, all lines need to be indented to line up
-- with with the '- ' from the first line.
line = ' ' .. line
end
end
result[lineno] = line
end
end
return result
@ -989,35 +1016,33 @@ do
local function prc(s)
return parse_rpm_changelog('RPM-Changelog', s)
end
local t, err
-- Single-line changelog entry, not itemized.
t = assert(prc('Switch to patch-git\n'))
assert(#t == 1)
assert(t[1] == 'Switch to patch-git')
assert_eq(assert(prc('Switch to patch-git\n')),
{'- Switch to patch-git'})
-- Single-line changelog entry, itemized.
t = assert(prc(' - Switch to patch-git\n'))
assert(#t == 1)
assert(t[1] == 'Switch to patch-git')
assert_eq(assert(prc(' - Switch to patch-git\n')),
{'- Switch to patch-git'})
-- Multi-line changelog entry, not itemized.
t = assert(prc(' Switch to\n patch-git\n'))
assert(#t == 1)
assert(t[1] == 'Switch to patch-git')
assert_eq(assert(prc(' Switch to\n patch-git\n')),
{'- Switch to patch-git'})
-- Multi-line changelog entry, one item.
t = assert(prc('- Switch to\n patch-git\n'))
assert(#t == 1)
assert(t[1] == 'Switch to patch-git')
assert_eq(assert(prc('- Switch to\n patch-git\n')),
{'- Switch to', ' patch-git'})
-- Multi-line changelog entry, two items.
t = assert(prc(
'- Switch to\n patch-git\n'
.. ' - Additional patch-git\n fixes\n'))
assert(#t == 2, t[1])
assert(t[1] == 'Switch to patch-git')
assert(t[2] == 'Additional patch-git fixes')
assert_eq(assert(prc([[- Switch to
patch-git
- Additional patch-git
fixes
]])),
{'- Switch to',
' patch-git',
'- Additional patch-git',
' fixes'})
end
local function parse_rpm_release(tag, s)
@ -1453,7 +1478,9 @@ local function rpm_changelog_default(message, trailer)
and tickets and #tickets > 0) then
subject = subject .. ' (' .. table.concat(tickets, ', ') .. ')'
end
return {subject}
local result = {}
append_to_rpm_changelog(subject, result)
return result
end
-- Tests for rpm_changelog_default.
do
@ -1465,15 +1492,13 @@ do
Resolves: RHEL-108475
]])
assert(#t == 1)
assert(t[1] == 'Remove memory leak in fdopen (RHEL-108475)', t[1])
assert_eq(t, {'- Remove memory leak in fdopen (RHEL-108475)'})
t = rcd([[Remove memory leak in fdopen (RHEL-108475)
Resolves: RHEL-108475
]])
assert(#t == 1)
assert(t[1] == 'Remove memory leak in fdopen (RHEL-108475)', t[1])
assert_eq(t, {'- Remove memory leak in fdopen (RHEL-108475)'})
t = rcd([[Remove memory leak in fdopen (RHEL-108475)
@ -1489,9 +1514,73 @@ RPM-Changelog:
- Remove memory leak in fdopen (bug 31840)
- libio: Test for fdopen memory leak without SEEK_END
]])
assert(#t == 2)
assert(t[1] == 'Remove memory leak in fdopen (bug 31840)')
assert(t[2] == 'libio: Test for fdopen memory leak without SEEK_END')
assert_eq(t,
{'- Remove memory leak in fdopen (bug 31840)',
'- libio: Test for fdopen memory leak without SEEK_END'})
t = rcd([[Do not wrap the cat
Resolves: RHEL-108475
RPM-Changelog:
- Do not wrap the cat!
/\_/\
( o.o )
> ^ <
- Thank you.
]])
assert_eq(t,
{'- Do not wrap the cat!',
[[ /\_/\]],
[[ ( o.o )]],
[[ > ^ <]],
'- Thank you.'})
t = rcd([[Do not wrap the cat
Resolves: RHEL-108475
RPM-Changelog:
- Do not wrap the cat!
/\_/\
( o.o )
> ^ <
- Thank you.
]])
assert_eq(t,
{'- Do not wrap the cat!',
[[ /\_/\]],
[[ ( o.o )]],
[[ > ^ <]],
'- Thank you.'})
t = rcd([[Do not wrap the cat
Resolves: RHEL-108475
RPM-Changelog:
- Do not wrap the cat!
/\_/\
( o.o )
> ^ <
]])
assert_eq(t,
{[[- Do not wrap the cat!]],
[[ /\_/\]],
[[ ( o.o )]],
[[ > ^ <]]})
-- Variant that has the dash on the RPM-Changelog line.
t = rcd([[Do not wrap the cat
Resolves: RHEL-108475
RPM-Changelog: - Do not wrap the cat!
/\_/\
( o.o )
> ^ <
]])
assert_eq(t,
{[[- Do not wrap the cat!]],
[[ /\_/\]],
[[ ( o.o )]],
[[ > ^ <]]})
end
@ -1770,9 +1859,8 @@ local function process_commits(changelog, changelog_after_commit)
assert_commit(commit,
target_cl and #target_cl > 0,
'first commit skips changelog and has an entry')
for i=1,#cl_entries do
target_cl[#target_cl + 1] = '- ' .. cl_entries[i]
end
table.move(cl_entries, 1, #cl_entries,
#target_cl + 1, target_cl)
end
end
end