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 ])
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+ 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 = 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,57 +143,21 @@ 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 )
47- args = parser .parse_args ()
48146
49- # Expand the provided SHA1 to the full SHA1 in case it's either abbreviated or an expression
50- git_sha_res = subprocess .run (["git" , "show" , "--pretty=%H" , "-s" , args .sha ], stdout = subprocess .PIPE )
51- if git_sha_res .returncode != 0 :
52- print (f"[FAILED] git show --pretty=%H -s { args .sha } " )
53- print ("Subprocess Call:" )
54- print (git_sha_res )
55- print ("" )
56- else :
57- args .sha = git_sha_res .stdout .decode ("utf-8" ).strip ()
147+ parser .add_argument (
148+ "--upstream-ref" ,
149+ default = "origin/kernel-mainline" ,
150+ help = "Reference to upstream mainline branch (default: origin/kernel-mainline)" ,
151+ )
152+
153+ args = parser .parse_args ()
58154
59155 tags = []
60156 if args .ciq_tag is not None :
61157 tags = args .ciq_tag .split ("," )
62158
63159 try :
64- check_fixes ( args .sha )
160+ full_cherry_pick ( sha = args .sha , ciq_tags = tags , jira_ticket = args . ticket , upstream_ref = args . upstream_ref )
65161 except Exception as e :
66162 print (e )
67163 exit (1 )
68-
69- author = CIQ_original_commit_author_to_tag_string (repo_path = os .getcwd (), sha = args .sha )
70- if author is None :
71- exit (1 )
72-
73- git_res = subprocess .run (["git" , "cherry-pick" , "-nsx" , args .sha ])
74- if git_res .returncode != 0 :
75- print (f"[FAILED] git cherry-pick -nsx { args .sha } " )
76- print (" Manually resolve conflict and include `upstream-diff` tag in commit message" )
77- print ("Subprocess Call:" )
78- print (git_res )
79- print ("" )
80-
81- print (os .getcwd ())
82- subprocess .run (["cp" , MERGE_MSG , f"{ MERGE_MSG } .bak" ])
83-
84- tags .append (author )
85-
86- with open (MERGE_MSG , "r" ) as file :
87- original_msg = file .readlines ()
88-
89- new_msg = CIQ_cherry_pick_commit_standardization (original_msg , args .sha , jira = args .ticket , tags = tags )
90-
91- print (f"Cherry Pick New Message for { args .sha } " )
92- for line in new_msg :
93- print (line .strip ("\n " ))
94- print (f"\n Original Message located here: { MERGE_MSG } .bak" )
95-
96- with open (MERGE_MSG , "w" ) as file :
97- file .writelines (new_msg )
98-
99- if git_res .returncode == 0 :
100- subprocess .run (["git" , "commit" , "-F" , MERGE_MSG ])
0 commit comments