Skip to content

Commit 0904b1c

Browse files
committed
ciq-cherry-pick.py: Automatically cherry pick cve-bf commits
It now automatically cherry picks the Fixes: dependencies. To accomodate this, CIQ_find_mainline_fixes was moved to ciq_helpers. And an extra argument for upstream-ref was introduced, the default being origin/kernel-mainline, as the dependencies are looked up there. To simplify things and keep main cleaner, separate functions were used. If one of the commits (the original and its dependencies) cannot be applied, the return code will be 1. This is useful when ciq-cherry-pick.py is called from other script. This also removed redundant prints. Signed-off-by: Roxana Nicolescu <rnicolescu@ciq.com>
1 parent b40b17b commit 0904b1c

File tree

2 files changed

+108
-45
lines changed

2 files changed

+108
-45
lines changed

check_kernel_commits.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from ciq_helpers import (
1212
CIQ_commit_exists_in_branch,
1313
CIQ_extract_fixes_references_from_commit_body_lines,
14+
CIQ_find_fixes_in_mainline,
1415
CIQ_get_commit_body,
1516
CIQ_hash_exists_in_ref,
1617
CIQ_run_git,
@@ -238,7 +239,7 @@ def main():
238239
)
239240
out_lines.append("") # blank line
240241
continue
241-
fixes = find_fixes_in_mainline(args.repo, args.pr_branch, upstream_ref, uhash)
242+
fixes = CIQ_find_fixes_in_mainline(args.repo, args.pr_branch, upstream_ref, uhash)
242243
if fixes:
243244
any_findings = True
244245

ciq-cherry-pick.py

Lines changed: 106 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
11
import argparse
22
import logging
33
import os
4+
import re
45
import subprocess
56

67
import git
78

89
from 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

1519
MERGE_MSG = git.Repo(os.getcwd()).git_dir + "/MERGE_MSG"
20+
MERGE_MSG_BAK = f"{MERGE_MSG}.bak"
1621

1722

1823
def 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+
34133
if __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

Comments
 (0)