Skip to content

Commit 792b311

Browse files
committed
backporting accepts list of tools
for standalone, you now need to pass UPSTREAM_PATCHES and not UPSTREAM_FIX Signed-off-by: Tomas Tomecek <[email protected]> Assisted-by: Cursor(Claude)
1 parent 237bab6 commit 792b311

File tree

4 files changed

+36
-28
lines changed

4 files changed

+36
-28
lines changed

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ run-rebase-agent-standalone: run-rebase-agent-c10s-standalone
5959
run-backport-agent-c9s-standalone:
6060
$(COMPOSE_AGENTS) run --rm \
6161
-e PACKAGE=$(PACKAGE) \
62-
-e UPSTREAM_FIX=$(UPSTREAM_FIX) \
62+
-e UPSTREAM_PATCHES=$(UPSTREAM_PATCHES) \
6363
-e JIRA_ISSUE=$(JIRA_ISSUE) \
6464
-e BRANCH=$(BRANCH) \
6565
-e DRY_RUN=$(DRY_RUN) \
@@ -70,7 +70,7 @@ run-backport-agent-c9s-standalone:
7070
run-backport-agent-c10s-standalone:
7171
$(COMPOSE_AGENTS) run --rm \
7272
-e PACKAGE=$(PACKAGE) \
73-
-e UPSTREAM_FIX=$(UPSTREAM_FIX) \
73+
-e UPSTREAM_PATCHES=$(UPSTREAM_PATCHES) \
7474
-e JIRA_ISSUE=$(JIRA_ISSUE) \
7575
-e BRANCH=$(BRANCH) \
7676
-e DRY_RUN=$(DRY_RUN) \

README-agents.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ make trigger-pipeline JIRA_ISSUE=RHEL-12345
7171
# Test specific agents standalone
7272
make JIRA_ISSUE=RHEL-12345 run-triage-agent-standalone
7373
make PACKAGE=httpd VERSION=2.4.62 JIRA_ISSUE=RHEL-12345 BRANCH=c10s run-rebase-agent-standalone
74-
make PACKAGE=httpd UPSTREAM_FIX=https://github.com/... JIRA_ISSUE=RHEL-12345 BRANCH=c10s run-backport-agent-standalone
74+
make PACKAGE=httpd UPSTREAM_PATCHES=https://github.com/... JIRA_ISSUE=RHEL-12345 BRANCH=c10s run-backport-agent-standalone
7575

7676
# Or with dry-run
7777
DRY_RUN=true make JIRA_ISSUE=RHEL-12345 run-triage-agent-standalone

agents/backport_agent.py

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def get_instructions() -> str:
8686
return """
8787
You are an expert on backporting upstream patches to packages in RHEL ecosystem.
8888
89-
To backport upstream fix <UPSTREAM_FIX> to package <PACKAGE> in dist-git branch <DIST_GIT_BRANCH>, do the following:
89+
To backport upstream patches <UPSTREAM_PATCHES> to package <PACKAGE> in dist-git branch <DIST_GIT_BRANCH>, do the following:
9090
9191
CRITICAL: Do NOT modify, delete, or touch any existing patches in the dist-git repository.
9292
Only add new patches for the current backport. Existing patches are there for a reason
@@ -97,7 +97,7 @@ def get_instructions() -> str:
9797
end the process with `success=True` and `status="Backport already applied"`.
9898
9999
2. Use the `git_prepare_package_sources` tool to prepare package sources in directory <UNPACKED_SOURCES>
100-
for application of the upstream fix.
100+
for application of the upstream patch.
101101
102102
3. Determine which backport approach to use:
103103
@@ -108,7 +108,7 @@ def get_instructions() -> str:
108108
- <UPSTREAM_REPO>: A temporary upstream repository clone (created in step 3c with -upstream suffix)
109109
110110
When to use this workflow:
111-
- <UPSTREAM_FIX> is a commit or pull request URL
111+
- <UPSTREAM_PATCHES> is a list of commit or pull request URLs
112112
- This includes URLs with .patch suffix (e.g., https://github.com/.../commit/abc123.patch)
113113
- If URL extraction fails, fall back to approach B
114114
@@ -218,7 +218,9 @@ def get_instructions() -> str:
218218
219219
B. GIT AM WORKFLOW (Fallback approach):
220220
221-
Note: For this workflow, use the pre-downloaded patch file at {{local_clone}}/{{jira_issue}}.patch
221+
Note: For this workflow, use the pre-downloaded patch files at {{local_clone}}.
222+
Their name is {{jira_issue}}-N.patch where N is the index starting from 0.
223+
For example, the first patch is at {{local_clone}}/{{jira_issue}}-0.patch
222224
223225
3a. Backport the patch:
224226
- Use the `git_patch_apply` tool with the patch file: {{local_clone}}/{{jira_issue}}.patch
@@ -228,7 +230,7 @@ def get_instructions() -> str:
228230
3b. Once there are no more conflicts, use the `git_patch_create` tool with the patch file path
229231
{{local_clone}}/{{jira_issue}}.patch to update the patch file.
230232
231-
4. Update the spec file. Add a new `Patch` tag pointing to the <UPSTREAM_FIX> patch file.
233+
4. Update the spec file. Add a new `Patch` tag for every patch in <UPSTREAM_PATCHES>.
232234
Add the new `Patch` tag after all existing `Patch` tags and, if `Patch` tags are numbered,
233235
make sure it has the highest number. Make sure the patch is applied in the "%prep" section
234236
and the `-p` argument is correct.
@@ -267,7 +269,7 @@ def get_prompt() -> str:
267269
{{dist_git_branch}} dist-git branch has been checked out. You are working on Jira issue {{jira_issue}}
268270
{{#cve_id}}(a.k.a. {{.}}){{/cve_id}}.
269271
{{^build_error}}
270-
Backport upstream fix {{upstream_fix}}.
272+
Backport upstream patches {{upstream_patches}}.
271273
Unpacked upstream sources are in {{unpacked_sources}}.
272274
{{/build_error}}
273275
{{#build_error}}
@@ -287,7 +289,7 @@ def get_fix_build_error_prompt() -> str:
287289
{{dist_git_branch}} dist-git branch has been checked out. You are working on Jira issue {{jira_issue}}
288290
{{#cve_id}}(a.k.a. {{.}}){{/cve_id}}.
289291
290-
The backport of {{upstream_fix}} was initially successful using the cherry-pick workflow,
292+
The backport of {{upstream_patches}} was initially successful using the cherry-pick workflow,
291293
but the build failed with the following error:
292294
293295
{{build_error}}
@@ -490,7 +492,7 @@ async def main() -> None:
490492
local_tool_options = {"working_directory": None}
491493

492494
class State(PackageUpdateState):
493-
upstream_fix: str
495+
upstream_patches: list[str]
494496
cve_id: str | None
495497
unpacked_sources: Path | None = Field(default=None)
496498
backport_log: list[str] = Field(default=[])
@@ -500,7 +502,7 @@ class State(PackageUpdateState):
500502
incremental_fix_attempts: int = Field(default=0) # Track how many times we tried incremental fix
501503

502504
async def run_workflow(
503-
package, dist_git_branch, upstream_fix, jira_issue, cve_id, redis_conn=None
505+
package, dist_git_branch, upstream_patches, jira_issue, cve_id, redis_conn=None
504506
):
505507
local_tool_options["working_directory"] = None
506508

@@ -543,11 +545,14 @@ async def fork_and_prepare_dist_git(state):
543545
state.unpacked_sources = get_unpacked_sources(state.local_clone, state.package)
544546
timeout = aiohttp.ClientTimeout(total=30)
545547
async with aiohttp.ClientSession(timeout=timeout) as session:
546-
async with session.get(state.upstream_fix) as response:
547-
if response.status < 400:
548-
(state.local_clone / f"{state.jira_issue}.patch").write_text(await response.text())
549-
else:
550-
raise ValueError(f"Failed to fetch upstream fix: {response.status}")
548+
for idx, upstream_patch in enumerate(state.upstream_patches):
549+
# should we guess the patch name with log agent?
550+
patch_name = f"{state.jira_issue}-{idx}.patch"
551+
async with session.get(upstream_patch) as response:
552+
if response.status < 400:
553+
(state.local_clone / patch_name).write_text(await response.text())
554+
else:
555+
raise ValueError(f"Failed to fetch upstream patch: {response.status}")
551556
return "run_backport_agent"
552557

553558
async def run_backport_agent(state):
@@ -561,7 +566,7 @@ async def run_backport_agent(state):
561566
dist_git_branch=state.dist_git_branch,
562567
jira_issue=state.jira_issue,
563568
cve_id=state.cve_id,
564-
upstream_fix=state.upstream_fix,
569+
upstream_patches=state.upstream_patches,
565570
build_error=state.build_error,
566571
),
567572
),
@@ -622,7 +627,7 @@ async def fix_build_error(state):
622627
dist_git_branch=state.dist_git_branch,
623628
jira_issue=state.jira_issue,
624629
cve_id=state.cve_id,
625-
upstream_fix=state.upstream_fix,
630+
upstream_patches=state.upstream_patches,
626631
build_error=state.build_error,
627632
),
628633
),
@@ -772,21 +777,22 @@ async def run_log_agent(state):
772777
log_output=log_output,
773778
operation_type="backport",
774779
package=state.package,
775-
details=state.upstream_fix,
780+
details=state.upstream_patches,
776781
)
777782
state.log_result = log_output
778783

779784
return "stage_changes"
780785

781786
async def commit_push_and_open_mr(state):
782787
try:
788+
formatted_patches = "\n".join(f" - {p}" for p in state.upstream_patches)
783789
state.merge_request_url = await tasks.commit_push_and_open_mr(
784790
local_clone=state.local_clone,
785791
commit_message=(
786792
f"{state.log_result.title}\n\n"
787793
f"{state.log_result.description}\n\n"
788794
+ (f"CVE: {state.cve_id}\n" if state.cve_id else "")
789-
+ f"Upstream fix: {state.upstream_fix}\n"
795+
+ "Upstream patches:\n" + formatted_patches + "\n"
790796
+ f"Resolves: {state.jira_issue}\n\n"
791797
f"This commit was backported {I_AM_JOTNAR}\n\n"
792798
"Assisted-by: Jotnar\n"
@@ -799,7 +805,7 @@ async def commit_push_and_open_mr(state):
799805
f"This merge request was created {I_AM_JOTNAR}\n"
800806
f"{CAREFULLY_REVIEW_CHANGES}\n\n"
801807
f"{state.log_result.description}\n\n"
802-
f"Upstream patch: {state.upstream_fix}\n\n"
808+
+ "Upstream patches:\n" + formatted_patches + "\n"
803809
f"Resolves: {state.jira_issue}\n\n"
804810
f"Backporting steps:\n\n{state.backport_log[-1]}"
805811
),
@@ -847,7 +853,7 @@ async def comment_in_jira(state):
847853
State(
848854
package=package,
849855
dist_git_branch=dist_git_branch,
850-
upstream_fix=upstream_fix,
856+
upstream_patches=upstream_patches,
851857
jira_issue=jira_issue,
852858
cve_id=cve_id,
853859
),
@@ -857,14 +863,15 @@ async def comment_in_jira(state):
857863
if (
858864
(package := os.getenv("PACKAGE", None))
859865
and (branch := os.getenv("BRANCH", None))
860-
and (upstream_fix := os.getenv("UPSTREAM_FIX", None))
866+
and (upstream_patches_raw := os.getenv("UPSTREAM_PATCHES", None))
861867
and (jira_issue := os.getenv("JIRA_ISSUE", None))
862868
):
869+
upstream_patches = upstream_patches_raw.split(",")
863870
logger.info("Running in direct mode with environment variables")
864871
state = await run_workflow(
865872
package=package,
866873
dist_git_branch=branch,
867-
upstream_fix=upstream_fix,
874+
upstream_patches=upstream_patches,
868875
jira_issue=jira_issue,
869876
cve_id=os.getenv("CVE_ID", None),
870877
redis_conn=None,
@@ -926,7 +933,7 @@ async def retry(task, error):
926933
state = await run_workflow(
927934
package=backport_data.package,
928935
dist_git_branch=dist_git_branch,
929-
upstream_fix=backport_data.patch_url,
936+
upstream_patches=backport_data.patch_urls,
930937
jira_issue=backport_data.jira_issue,
931938
cve_id=backport_data.cve_id,
932939
redis_conn=redis,

common/models.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,8 @@ class BackportInputSchema(BaseModel):
9595
dist_git_branch: str = Field(description="Git branch in dist-git to be updated")
9696
jira_issue: str = Field(description="Jira issue to reference as resolved")
9797
cve_id: str | None = Field(default=None, description="CVE ID if the jira issue is a CVE")
98-
upstream_fix: str = Field(description="URL to the upstream fix (commit URL or patch URL)")
98+
upstream_patches: list[str] = Field(
99+
description="List of URLs to upstream patches that were validated using the PatchValidator tool")
99100
build_error: str | None = Field(description="Error encountered during package build")
100101

101102

@@ -273,4 +274,4 @@ class CachedMRMetadata(BaseModel):
273274
operation_type: str = Field(description="Type of operation (backport or rebase)")
274275
title: str = Field(description="Merge request title")
275276
package: str = Field(description="Package name")
276-
details: str = Field(description="Operation-specific identifier (upstream_fix URL for backport, version for rebase)")
277+
details: list[str] = Field(description="Operation-specific identifier (list of upstream patch URLs for backport, version for rebase)")

0 commit comments

Comments
 (0)