88import textwrap
99from typing import Optional
1010
11-
12- def run_git ( repo , args ):
13- """Run a git command in the given repository and return its output as a string."""
14- result = subprocess . run ([ "git" , "-C" , repo ] + args , text = True , capture_output = True , check = False )
15- if result . returncode != 0 :
16- raise RuntimeError ( f"Git command failed: { ' ' . join ( args ) } \n { result . stderr } " )
17- return result . stdout
11+ from ciq_helpers import (
12+ CIQ_commit_exists_in_branch ,
13+ CIQ_extract_fixes_references_from_commit_body_lines ,
14+ CIQ_get_commit_body ,
15+ CIQ_hash_exists_in_ref ,
16+ CIQ_run_git ,
17+ )
1818
1919
2020def ref_exists (repo , ref ):
2121 """Return True if the given ref exists in the repository, False otherwise."""
2222 try :
23- run_git (repo , ["rev-parse" , "--verify" , "--quiet" , ref ])
23+ CIQ_run_git (repo , ["rev-parse" , "--verify" , "--quiet" , ref ])
2424 return True
2525 except RuntimeError :
2626 return False
2727
2828
2929def get_pr_commits (repo , pr_branch , base_branch ):
3030 """Get a list of commit SHAs that are in the PR branch but not in the base branch."""
31- output = run_git (repo , ["rev-list" , f"{ base_branch } ..{ pr_branch } " ])
31+ output = CIQ_run_git (repo , ["rev-list" , f"{ base_branch } ..{ pr_branch } " ])
3232 return output .strip ().splitlines ()
3333
3434
35- def get_commit_message (repo , sha ):
36- """Get the commit message for a given commit SHA."""
37- return run_git (repo , ["log" , "-n" , "1" , "--format=%B" , sha ])
38-
39-
4035def get_short_hash_and_subject (repo , sha ):
4136 """Get the abbreviated commit hash and subject for a given commit SHA."""
42- output = run_git (repo , ["log" , "-n" , "1" , "--format=%h%x00%s" , sha ]).strip ()
37+ output = CIQ_run_git (repo , ["log" , "-n" , "1" , "--format=%h%x00%s" , sha ]).strip ()
4338 short_hash , subject = output .split ("\x00 " , 1 )
4439 return short_hash , subject
4540
@@ -48,61 +43,56 @@ def hash_exists_in_mainline(repo, upstream_ref, hash_):
4843 """
4944 Return True if hash_ is reachable from upstream_ref (i.e., is an ancestor of it).
5045 """
51- try :
52- run_git (repo , ["merge-base" , "--is-ancestor" , hash_ , upstream_ref ])
53- return True
54- except RuntimeError :
55- return False
46+
47+ return CIQ_hash_exists_in_ref (repo , upstream_ref , hash_ )
5648
5749
5850def find_fixes_in_mainline (repo , pr_branch , upstream_ref , hash_ ):
5951 """
60- Return unique commits in upstream_ref that have Fixes: <N chars of hash_> in their message, case-insensitive.
52+ Return unique commits in upstream_ref that have Fixes: <N chars of hash_> in their message, case-insensitive,
53+ if they have not been commited in the pr_branch.
6154 Start from 12 chars and work down to 6, but do not include duplicates if already found at a longer length.
6255 Returns a list of tuples: (full_hash, display_string)
6356 """
6457 results = []
58+
59+ # Prepare hash prefixes from 12 down to 6
60+ hash_prefixes = [hash_ [:index ] for index in range (12 , 5 , - 1 )]
61+
6562 # Get all commits with 'Fixes:' in the message
66- output = run_git (repo , ["log" , upstream_ref , "--grep" , "Fixes:" , "-i" , "--format=%H %h %s (%an)%x0a%B%x00" ]).strip ()
63+ output = CIQ_run_git (
64+ repo ,
65+ [
66+ "log" ,
67+ upstream_ref ,
68+ "--grep" ,
69+ "Fixes:" ,
70+ "-i" ,
71+ "--format=%H %h %s (%an)%x0a%B%x00" ,
72+ ],
73+ ).strip ()
6774 if not output :
6875 return []
76+
6977 # Each commit is separated by a NUL character and a newline
7078 commits = output .split ("\x00 \x0a " )
71- # Prepare hash prefixes from 12 down to 6
72- hash_prefixes = [hash_ [:index ] for index in range (12 , 5 , - 1 )]
7379 for commit in commits :
7480 if not commit .strip ():
7581 continue
76- # The first line is the summary, the rest is the body
82+
7783 lines = commit .splitlines ()
78- if not lines :
79- continue
84+ # The first line is the summary, the rest is the body
8085 header = lines [0 ]
81- full_hash = header .split ()[0 ]
82- # Search for Fixes: lines in the commit message
83- for line in lines [1 :]:
84- m = re .match (r"^\s*Fixes:\s*([0-9a-fA-F]{6,40})" , line , re .IGNORECASE )
85- if m :
86- for prefix in hash_prefixes :
87- if m .group (1 ).lower ().startswith (prefix .lower ()):
88- if not commit_exists_in_branch (repo , pr_branch , full_hash ):
89- results .append ((full_hash , " " .join (header .split ()[1 :])))
90- break
91- else :
92- continue
93- return results
86+ full_hash , display_string = (lambda h : (h [0 ], " " .join (h [1 :])))(header .split ())
87+ fixes = CIQ_extract_fixes_references_from_commit_body_lines (lines = lines [1 :])
88+ for fix in fixes :
89+ for prefix in hash_prefixes :
90+ if fix .lower ().startswith (prefix .lower ()):
91+ if not CIQ_commit_exists_in_branch (repo , pr_branch , full_hash ):
92+ results .append ((full_hash , display_string ))
93+ break
9494
95-
96- def commit_exists_in_branch (repo , pr_branch , upstream_hash_ ):
97- """
98- Return True if upstream_hash_ has been backported and it exists in the
99- pr branch
100- """
101- output = run_git (repo , ["log" , pr_branch , "--grep" , "commit " + upstream_hash_ ])
102- if not output :
103- return False
104-
105- return True
95+ return results
10696
10797
10898def wrap_paragraph (text , width = 80 , initial_indent = "" , subsequent_indent = "" ):
@@ -176,7 +166,7 @@ def main():
176166 if os .path .exists (vulns_repo ):
177167 # Repository exists, update it with git pull
178168 try :
179- run_git (vulns_repo , ["pull" ])
169+ CIQ_run_git (vulns_repo , ["pull" ])
180170 except RuntimeError as e :
181171 print (f"WARNING: Failed to update vulns repo: { e } " )
182172 print ("Continuing with existing repository..." )
@@ -222,7 +212,7 @@ def main():
222212 for sha in reversed (pr_commits ): # oldest first
223213 short_hash , subject = get_short_hash_and_subject (args .repo , sha )
224214 pr_commit_desc = f"{ short_hash } ({ subject } )"
225- msg = get_commit_message (args .repo , sha )
215+ msg = CIQ_get_commit_body (args .repo , sha )
226216 upstream_hashes = re .findall (r"^commit\s+([0-9a-fA-F]{40})" , msg , re .MULTILINE )
227217 for uhash in upstream_hashes :
228218 short_uhash = uhash [:12 ]
0 commit comments