@ -84,13 +84,16 @@ def add_footer_change_id(message, change_id):
after_keys = [ ' Bug ' , ' Issue ' , ' Test ' , ' Feature ' ] )
after_keys = [ ' Bug ' , ' Issue ' , ' Test ' , ' Feature ' ] )
def add_footer ( message , key , value , after_keys = None ):
def add_footer ( message , key , value , after_keys = None , before_keys = None ):
""" Returns a message with given footer appended.
""" Returns a message with given footer appended.
If after_keys is None ( default ) , appends footer last .
If after_keys and before_keys are both None ( default ) , appends footer last .
Otherwise , after_keys must be iterable of footer keys , then the new footer
If after_keys is provided and matches footers already present , inserts footer
would be inserted at the topmost position such there would be no footer lines
as * early * as possible while still appearing after all provided keys , even
after it with key matching one of after_keys .
if doing so conflicts with before_keys .
If before_keys is provided , inserts footer as late as possible while still
appearing before all provided keys .
For example , given
For example , given
message = ' Header. \n \n Added: 2016 \n Bug: 123 \n Verified-By: CQ '
message = ' Header. \n \n Added: 2016 \n Bug: 123 \n Verified-By: CQ '
after_keys = [ ' Bug ' , ' Issue ' ]
after_keys = [ ' Bug ' , ' Issue ' ]
@ -99,22 +102,28 @@ def add_footer(message, key, value, after_keys=None):
assert key == normalize_name ( key ) , ' Use normalized key '
assert key == normalize_name ( key ) , ' Use normalized key '
new_footer = ' %s : %s ' % ( key , value )
new_footer = ' %s : %s ' % ( key , value )
top_lines , footer_lines , parsed _footers = split_footers ( message )
top_lines , footer_lines , _ = split_footers ( message )
if not footer_lines :
if not footer_lines :
if not top_lines or top_lines [ - 1 ] != ' ' :
if not top_lines or top_lines [ - 1 ] != ' ' :
top_lines . append ( ' ' )
top_lines . append ( ' ' )
footer_lines = [ new_footer ]
footer_lines = [ new_footer ]
elif not after_keys :
footer_lines . append ( new_footer )
else :
else :
after_keys = set ( map ( normalize_name , after_keys ) )
after_keys = set ( map ( normalize_name , after_keys or [ ] ) )
# Iterate from last to first footer till we find the footer keys above.
after_indices = [
for i , ( key , _ ) in reversed ( list ( enumerate ( parsed_footers ) ) ) :
footer_lines . index ( x ) for x in footer_lines for k in after_keys
if normalize_name ( key ) in after_keys :
if normalize_name ( parse_footer ( x ) [ 0 ] ) == k ]
footer_lines . insert ( i + 1 , new_footer )
before_keys = set ( map ( normalize_name , before_keys or [ ] ) )
break
before_indices = [
footer_lines . index ( x ) for x in footer_lines for k in before_keys
if normalize_name ( parse_footer ( x ) [ 0 ] ) == k ]
if after_indices :
# after_keys takes precedence, even if there's a conflict.
insert_idx = max ( after_indices ) + 1
elif before_indices :
insert_idx = min ( before_indices )
else :
else :
footer_lines . insert ( 0 , new_footer )
insert_idx = len ( footer_lines )
footer_lines . insert ( insert_idx , new_footer )
return ' \n ' . join ( top_lines + footer_lines )
return ' \n ' . join ( top_lines + footer_lines )