11import argparse
22import logging
33import os
4+ import re
45import subprocess
56
67import git
78
89from ciq_helpers import (
910 CIQ_cherry_pick_commit_standardization ,
1011 CIQ_commit_exists_in_current_branch ,
12+ CIQ_find_fixes_in_mainline_current_branch ,
1113 CIQ_fixes_references ,
14+ CIQ_get_full_hash ,
1215 CIQ_original_commit_author_to_tag_string ,
16+ CIQ_run_git ,
1317)
1418
1519MERGE_MSG = git .Repo (os .getcwd ()).git_dir + "/MERGE_MSG"
20+ MERGE_MSG_BAK = f"{ MERGE_MSG } .bak"
1621
1722
1823def check_fixes (sha ):
@@ -31,6 +36,100 @@ def check_fixes(sha):
3136 raise RuntimeError (f"The commit you want to cherry pick references a Fixes: { fix } but this is not here" )
3237
3338
39+ def manage_commit_message (full_sha , ciq_tags , jira_ticket ):
40+ """
41+ It standardize the commit message by including the ciq_tags, original
42+ author and the original commit full sha.
43+
44+ Original message location: MERGE_MSG
45+ Makes a copy of the original message in MERGE_MSG_BAK
46+
47+ The new standardized commit message is written to MERGE_MSG
48+ """
49+
50+ subprocess .run (["cp" , MERGE_MSG , MERGE_MSG_BAK ], check = True )
51+
52+ # Make sure it's a deep copy because ciq_tags may be used for other cherry-picks
53+ new_tags = [tag for tag in ciq_tags ]
54+
55+ author = CIQ_original_commit_author_to_tag_string (repo_path = os .getcwd (), sha = full_sha )
56+ if author is None :
57+ raise RuntimeError (f"Could not find author of commit { full_sha } " )
58+
59+ new_tags .append (author )
60+ with open (MERGE_MSG , "r" ) as file :
61+ original_msg = file .readlines ()
62+
63+ new_msg = CIQ_cherry_pick_commit_standardization (original_msg , full_sha , jira = jira_ticket , tags = ciq_tags )
64+
65+ print (f"Cherry Pick New Message for { full_sha } " )
66+ print (f"\n Original Message located here: { MERGE_MSG_BAK } " )
67+
68+ with open (MERGE_MSG , "w" ) as file :
69+ file .writelines (new_msg )
70+
71+
72+ def cherry_pick (sha , ciq_tags , jira_ticket ):
73+ """
74+ Cherry picks a commit and it adds the ciq standardized format
75+ In case of error (cherry pick conflict):
76+ - MERGE_MSG.bak contains the original commit message
77+ - MERGE_MSG contains the standardized commit message
78+ - Conflict has to be solved manualy
79+
80+ In case of success:
81+ - the commit is cherry picked
82+ - MERGE_MSG.bak is deleted
83+ - You can still see MERGE_MSG for the original message
84+ """
85+
86+ # Expand the provided SHA1 to the full SHA1 in case it's either abbreviated or an expression
87+ full_sha = CIQ_get_full_hash (repo = os .getcwd (), short_hash = sha )
88+
89+ check_fixes (sha = full_sha )
90+
91+ # Commit message is in MERGE_MSG
92+ git_res = subprocess .run (["git" , "cherry-pick" , "-nsx" , full_sha ])
93+ manage_commit_message (full_sha = full_sha , ciq_tags = ciq_tags , jira_ticket = jira_ticket )
94+
95+ if git_res .returncode != 0 :
96+ error_str = (
97+ f"[FAILED] git cherry-pick -nsx { full_sha } \n "
98+ "Manually resolve conflict and include `upstream-diff` tag in commit message\n "
99+ f"Subprocess Call: { git_res } "
100+ )
101+ raise RuntimeError (error_str )
102+
103+ CIQ_run_git (repo_path = os .getcwd (), args = ["commit" , "-F" , MERGE_MSG ])
104+
105+
106+ def cherry_pick_fixes (sha , ciq_tags , jira_ticket , upstream_ref ):
107+ """
108+ It checks upstream_ref for commits that have this reference:
109+ Fixes: <sha>. If any, these will also be cherry picked with the ciq
110+ tag = cve-bf. If the tag was cve-pre, it stays the same.
111+ """
112+ fixes_in_mainline = CIQ_find_fixes_in_mainline_current_branch (os .getcwd (), upstream_ref , sha )
113+
114+ # Replace cve with cve-bf
115+ # Leave cve-pre and cve-bf as they are
116+ bf_ciq_tags = [re .sub (r"^cve " , "cve-bf " , s ) for s in ciq_tags ]
117+ for full_hash , display_str in fixes_in_mainline :
118+ print (f"Extra cherry picking { display_str } " )
119+ full_cherry_pick (sha = full_hash , ciq_tags = bf_ciq_tags , jira_ticket = jira_ticket , upstream_ref = upstream_ref )
120+
121+
122+ def full_cherry_pick (sha , ciq_tags , jira_ticket , upstream_ref ):
123+ """
124+ It cherry picks a commit from upstream-ref along with its Fixes: references.
125+ """
126+ # Cherry pick the commit
127+ cherry_pick (sha = sha , ciq_tags = ciq_tags , jira_ticket = jira_ticket )
128+
129+ # Cherry pick the fixed-by dependencies
130+ cherry_pick_fixes (sha = sha , ciq_tags = ciq_tags , jira_ticket = jira_ticket , upstream_ref = upstream_ref )
131+
132+
34133if __name__ == "__main__" :
35134 print ("CIQ custom cherry picker" )
36135 parser = argparse .ArgumentParser (formatter_class = argparse .RawTextHelpFormatter )
@@ -44,59 +143,22 @@ def check_fixes(sha):
44143 " cve-pre CVE-1974-0001 - A pre-condition or dependency needed for the CVE\n "
45144 "Multiple tags are separated with a comma. ex: cve CVE-1974-0001, cve CVE-1974-0002\n " ,
46145 )
146+ parser .add_argument (
147+ "--upstream-ref" ,
148+ default = "origin/kernel-mainline" ,
149+ help = "Reference to upstream mainline branch (default: origin/kernel-mainline)" ,
150+ )
151+
47152 args = parser .parse_args ()
48153
49154 logging .basicConfig (level = logging .INFO )
50155
51- # Expand the provided SHA1 to the full SHA1 in case it's either abbreviated or an expression
52- git_sha_res = subprocess .run (["git" , "show" , "--pretty=%H" , "-s" , args .sha ], stdout = subprocess .PIPE )
53- if git_sha_res .returncode != 0 :
54- print (f"[FAILED] git show --pretty=%H -s { args .sha } " )
55- print ("Subprocess Call:" )
56- print (git_sha_res )
57- print ("" )
58- else :
59- args .sha = git_sha_res .stdout .decode ("utf-8" ).strip ()
60-
61156 tags = []
62157 if args .ciq_tag is not None :
63158 tags = args .ciq_tag .split ("," )
64159
65160 try :
66- check_fixes ( args .sha )
161+ full_cherry_pick ( sha = args .sha , ciq_tags = tags , jira_ticket = args . ticket , upstream_ref = args . upstream_ref )
67162 except Exception as e :
68163 print (e )
69164 exit (1 )
70-
71- author = CIQ_original_commit_author_to_tag_string (repo_path = os .getcwd (), sha = args .sha )
72- if author is None :
73- exit (1 )
74-
75- git_res = subprocess .run (["git" , "cherry-pick" , "-nsx" , args .sha ])
76- if git_res .returncode != 0 :
77- print (f"[FAILED] git cherry-pick -nsx { args .sha } " )
78- print (" Manually resolve conflict and include `upstream-diff` tag in commit message" )
79- print ("Subprocess Call:" )
80- print (git_res )
81- print ("" )
82-
83- print (os .getcwd ())
84- subprocess .run (["cp" , MERGE_MSG , f"{ MERGE_MSG } .bak" ])
85-
86- tags .append (author )
87-
88- with open (MERGE_MSG , "r" ) as file :
89- original_msg = file .readlines ()
90-
91- new_msg = CIQ_cherry_pick_commit_standardization (original_msg , args .sha , jira = args .ticket , tags = tags )
92-
93- print (f"Cherry Pick New Message for { args .sha } " )
94- for line in new_msg :
95- print (line .strip ("\n " ))
96- print (f"\n Original Message located here: { MERGE_MSG } .bak" )
97-
98- with open (MERGE_MSG , "w" ) as file :
99- file .writelines (new_msg )
100-
101- if git_res .returncode == 0 :
102- subprocess .run (["git" , "commit" , "-F" , MERGE_MSG ])
0 commit comments