patman: Add a 'keep_change_id' setting

A Change-Id can be useful for traceability purposes, and some projects
may wish to have them preserved.  This change makes it configurable
via a new 'keep_change_id' setting.

Signed-off-by: Maxim Cournoyer <maxim.cournoyer@gmail.com>
Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Maxim Cournoyer 2023-10-12 23:06:24 -04:00 committed by Simon Glass
parent 07fe79c93c
commit a13af89e10
5 changed files with 45 additions and 13 deletions

View file

@ -103,6 +103,8 @@ send.add_argument('--no-signoff', action='store_false', dest='add_signoff',
default=True, help="Don't add Signed-off-by to patches") default=True, help="Don't add Signed-off-by to patches")
send.add_argument('--smtp-server', type=str, send.add_argument('--smtp-server', type=str,
help="Specify the SMTP server to 'git send-email'") help="Specify the SMTP server to 'git send-email'")
send.add_argument('--keep-change-id', action='store_true',
help='Preserve Change-Id tags in patches to send.')
send.add_argument('patchfiles', nargs='*') send.add_argument('patchfiles', nargs='*')

View file

@ -16,11 +16,14 @@ from patman import gitutil
from patman import patchstream from patman import patchstream
from u_boot_pylib import terminal from u_boot_pylib import terminal
def setup(): def setup():
"""Do required setup before doing anything""" """Do required setup before doing anything"""
gitutil.setup() gitutil.setup()
def prepare_patches(col, branch, count, start, end, ignore_binary, signoff):
def prepare_patches(col, branch, count, start, end, ignore_binary, signoff,
keep_change_id=False):
"""Figure out what patches to generate, then generate them """Figure out what patches to generate, then generate them
The patch files are written to the current directory, e.g. 0001_xxx.patch The patch files are written to the current directory, e.g. 0001_xxx.patch
@ -35,6 +38,7 @@ def prepare_patches(col, branch, count, start, end, ignore_binary, signoff):
end (int): End patch to use (0=last one in series, 1=one before that, end (int): End patch to use (0=last one in series, 1=one before that,
etc.) etc.)
ignore_binary (bool): Don't generate patches for binary files ignore_binary (bool): Don't generate patches for binary files
keep_change_id (bool): Preserve the Change-Id tag.
Returns: Returns:
Tuple: Tuple:
@ -59,11 +63,12 @@ def prepare_patches(col, branch, count, start, end, ignore_binary, signoff):
branch, start, to_do, ignore_binary, series, signoff) branch, start, to_do, ignore_binary, series, signoff)
# Fix up the patch files to our liking, and insert the cover letter # Fix up the patch files to our liking, and insert the cover letter
patchstream.fix_patches(series, patch_files) patchstream.fix_patches(series, patch_files, keep_change_id)
if cover_fname and series.get('cover'): if cover_fname and series.get('cover'):
patchstream.insert_cover_letter(cover_fname, series, to_do) patchstream.insert_cover_letter(cover_fname, series, to_do)
return series, cover_fname, patch_files return series, cover_fname, patch_files
def check_patches(series, patch_files, run_checkpatch, verbose, use_tree): def check_patches(series, patch_files, run_checkpatch, verbose, use_tree):
"""Run some checks on a set of patches """Run some checks on a set of patches
@ -166,7 +171,8 @@ def send(args):
col = terminal.Color() col = terminal.Color()
series, cover_fname, patch_files = prepare_patches( series, cover_fname, patch_files = prepare_patches(
col, args.branch, args.count, args.start, args.end, col, args.branch, args.count, args.start, args.end,
args.ignore_binary, args.add_signoff) args.ignore_binary, args.add_signoff,
keep_change_id=args.keep_change_id)
ok = check_patches(series, patch_files, args.check_patch, ok = check_patches(series, patch_files, args.check_patch,
args.verbose, args.check_patch_use_tree) args.verbose, args.check_patch_use_tree)

View file

@ -68,6 +68,7 @@ STATE_PATCH_SUBJECT = 1 # In patch subject (first line of log for a commit)
STATE_PATCH_HEADER = 2 # In patch header (after the subject) STATE_PATCH_HEADER = 2 # In patch header (after the subject)
STATE_DIFFS = 3 # In the diff part (past --- line) STATE_DIFFS = 3 # In the diff part (past --- line)
class PatchStream: class PatchStream:
"""Class for detecting/injecting tags in a patch or series of patches """Class for detecting/injecting tags in a patch or series of patches
@ -76,7 +77,7 @@ class PatchStream:
unwanted tags or inject additional ones. These correspond to the two unwanted tags or inject additional ones. These correspond to the two
phases of processing. phases of processing.
""" """
def __init__(self, series, is_log=False): def __init__(self, series, is_log=False, keep_change_id=False):
self.skip_blank = False # True to skip a single blank line self.skip_blank = False # True to skip a single blank line
self.found_test = False # Found a TEST= line self.found_test = False # Found a TEST= line
self.lines_after_test = 0 # Number of lines found after TEST= self.lines_after_test = 0 # Number of lines found after TEST=
@ -86,6 +87,7 @@ class PatchStream:
self.section = [] # The current section...END section self.section = [] # The current section...END section
self.series = series # Info about the patch series self.series = series # Info about the patch series
self.is_log = is_log # True if indent like git log self.is_log = is_log # True if indent like git log
self.keep_change_id = keep_change_id # True to keep Change-Id tags
self.in_change = None # Name of the change list we are in self.in_change = None # Name of the change list we are in
self.change_version = 0 # Non-zero if we are in a change list self.change_version = 0 # Non-zero if we are in a change list
self.change_lines = [] # Lines of the current change self.change_lines = [] # Lines of the current change
@ -452,6 +454,8 @@ class PatchStream:
# Detect Change-Id tags # Detect Change-Id tags
elif change_id_match: elif change_id_match:
if self.keep_change_id:
out = [line]
value = change_id_match.group(1) value = change_id_match.group(1)
if self.is_log: if self.is_log:
if self.commit.change_id: if self.commit.change_id:
@ -763,7 +767,7 @@ def get_metadata_for_test(text):
pst.finalise() pst.finalise()
return series return series
def fix_patch(backup_dir, fname, series, cmt): def fix_patch(backup_dir, fname, series, cmt, keep_change_id=False):
"""Fix up a patch file, by adding/removing as required. """Fix up a patch file, by adding/removing as required.
We remove our tags from the patch file, insert changes lists, etc. We remove our tags from the patch file, insert changes lists, etc.
@ -776,6 +780,7 @@ def fix_patch(backup_dir, fname, series, cmt):
fname (str): Filename to patch file to process fname (str): Filename to patch file to process
series (Series): Series information about this patch set series (Series): Series information about this patch set
cmt (Commit): Commit object for this patch file cmt (Commit): Commit object for this patch file
keep_change_id (bool): Keep the Change-Id tag.
Return: Return:
list: A list of errors, each str, or [] if all ok. list: A list of errors, each str, or [] if all ok.
@ -783,7 +788,7 @@ def fix_patch(backup_dir, fname, series, cmt):
handle, tmpname = tempfile.mkstemp() handle, tmpname = tempfile.mkstemp()
outfd = os.fdopen(handle, 'w', encoding='utf-8') outfd = os.fdopen(handle, 'w', encoding='utf-8')
infd = open(fname, 'r', encoding='utf-8') infd = open(fname, 'r', encoding='utf-8')
pst = PatchStream(series) pst = PatchStream(series, keep_change_id=keep_change_id)
pst.commit = cmt pst.commit = cmt
pst.process_stream(infd, outfd) pst.process_stream(infd, outfd)
infd.close() infd.close()
@ -795,7 +800,7 @@ def fix_patch(backup_dir, fname, series, cmt):
shutil.move(tmpname, fname) shutil.move(tmpname, fname)
return cmt.warn return cmt.warn
def fix_patches(series, fnames): def fix_patches(series, fnames, keep_change_id=False):
"""Fix up a list of patches identified by filenames """Fix up a list of patches identified by filenames
The patch files are processed in place, and overwritten. The patch files are processed in place, and overwritten.
@ -803,6 +808,7 @@ def fix_patches(series, fnames):
Args: Args:
series (Series): The Series object series (Series): The Series object
fnames (:type: list of str): List of patch files to process fnames (:type: list of str): List of patch files to process
keep_change_id (bool): Keep the Change-Id tag.
""" """
# Current workflow creates patches, so we shouldn't need a backup # Current workflow creates patches, so we shouldn't need a backup
backup_dir = None #tempfile.mkdtemp('clean-patch') backup_dir = None #tempfile.mkdtemp('clean-patch')
@ -811,7 +817,8 @@ def fix_patches(series, fnames):
cmt = series.commits[count] cmt = series.commits[count]
cmt.patch = fname cmt.patch = fname
cmt.count = count cmt.count = count
result = fix_patch(backup_dir, fname, series, cmt) result = fix_patch(backup_dir, fname, series, cmt,
keep_change_id=keep_change_id)
if result: if result:
print('%d warning%s for %s:' % print('%d warning%s for %s:' %
(len(result), 's' if len(result) > 1 else '', fname)) (len(result), 's' if len(result) > 1 else '', fname))

View file

@ -371,11 +371,12 @@ Series-process-log: sort, uniq
Separate each tag with a comma. Separate each tag with a comma.
Change-Id: Change-Id:
This tag is stripped out but is used to generate the Message-Id This tag is used to generate the Message-Id of the emails that
of the emails that will be sent. When you keep the Change-Id the will be sent. When you keep the Change-Id the same you are
same you are asserting that this is a slightly different version asserting that this is a slightly different version (but logically
(but logically the same patch) as other patches that have been the same patch) as other patches that have been sent out with the
sent out with the same Change-Id. same Change-Id. The Change-Id tag line is removed from outgoing
patches, unless the `keep_change_id` settings is set to `True`.
Various other tags are silently removed, like these Chrome OS and Various other tags are silently removed, like these Chrome OS and
Gerrit tags:: Gerrit tags::

View file

@ -209,6 +209,22 @@ Signed-off-by: Simon Glass <sjg@chromium.org>
rc = os.system('diff -u %s %s' % (inname, expname)) rc = os.system('diff -u %s %s' % (inname, expname))
self.assertEqual(rc, 0) self.assertEqual(rc, 0)
os.remove(inname)
# Test whether the keep_change_id settings works.
inhandle, inname = tempfile.mkstemp()
infd = os.fdopen(inhandle, 'w', encoding='utf-8')
infd.write(data)
infd.close()
patchstream.fix_patch(None, inname, series.Series(), com,
keep_change_id=True)
with open(inname, 'r') as f:
content = f.read()
self.assertIn(
'Change-Id: I80fe1d0c0b7dd10aa58ce5bb1d9290b6664d5413',
content)
os.remove(inname) os.remove(inname)
os.remove(expname) os.remove(expname)