Skip to content

Commit b643ea5

Browse files
authored
Merge pull request #91 from nforro/fixes
Several fixes
2 parents ec42a8b + 0355a01 commit b643ea5

File tree

9 files changed

+97
-95
lines changed

9 files changed

+97
-95
lines changed

beeai/agents/backport_agent.py

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
import asyncio
22
import logging
33
import os
4-
from shutil import rmtree
54
import subprocess
65
import sys
76
import traceback
8-
97
from pathlib import Path
108

119
from pydantic import BaseModel, Field
@@ -50,7 +48,6 @@ class InputSchema(BaseModel):
5048
class OutputSchema(BaseModel):
5149
success: bool = Field(description="Whether the backport was successfully completed")
5250
status: str = Field(description="Backport status")
53-
mr_url: str | None = Field(description="URL to the opened merge request")
5451
error: str | None = Field(description="Specific details about an error")
5552

5653

@@ -78,7 +75,6 @@ async def main() -> None:
7875
logging.basicConfig(level=logging.INFO)
7976

8077
setup_observability(os.environ["COLLECTOR_ENDPOINT"])
81-
cve_id = os.getenv("CVE_ID", "")
8278

8379
async with mcp_tools(os.environ["MCP_GATEWAY_URL"]) as gateway_tools:
8480
backport_agent = RequirementAgent(
@@ -117,6 +113,8 @@ async def main() -> None:
117113
],
118114
)
119115

116+
dry_run = os.getenv("DRY_RUN", "False").lower() == "true"
117+
120118
class State(BaseModel):
121119
jira_issue: str
122120
package: str
@@ -173,7 +171,7 @@ async def run_backport_agent(state):
173171
if state.backport_result.success:
174172
return "commit_push_and_open_mr"
175173
else:
176-
return Workflow.END
174+
return "comment_in_jira"
177175

178176
async def commit_push_and_open_mr(state):
179177
state.merge_request_url = await tasks.commit_push_and_open_mr(
@@ -186,13 +184,29 @@ async def commit_push_and_open_mr(state):
186184
mr_title="{COMMIT_PREFIX} backport {state.jira_issue}",
187185
mr_description="TODO",
188186
available_tools=gateway_tools,
189-
commit_only=os.getenv("DRY_RUN", "False").lower() == "true",
187+
commit_only=dry_run,
188+
)
189+
return "comment_in_jira"
190+
191+
async def comment_in_jira(state):
192+
if dry_run:
193+
return Workflow.END
194+
await tasks.comment_in_jira(
195+
jira_issue=state.jira_issue,
196+
agent_type="Backport",
197+
comment_text=(
198+
state.merge_request_url
199+
if state.backport_result.success
200+
else f"Agent failed to perform a backport: {state.backport_result.error}"
201+
),
202+
available_tools=gateway_tools,
190203
)
191204
return Workflow.END
192205

193206
workflow.add_step("fork_and_prepare_dist_git", fork_and_prepare_dist_git)
194207
workflow.add_step("run_backport_agent", run_backport_agent)
195208
workflow.add_step("commit_push_and_open_mr", commit_push_and_open_mr)
209+
workflow.add_step("comment_in_jira", comment_in_jira)
196210

197211
async def run_workflow(package, dist_git_branch, upstream_fix, jira_issue, cve_id):
198212
response = await workflow.run(
@@ -280,31 +294,17 @@ async def retry(task, error):
280294
f"Backport processing completed for {backport_data.jira_issue}, " f"success: {state.backport_result.success}"
281295
)
282296

283-
agent_type = "Backport"
284-
if state.backport_result.success:
285-
logger.info(f"Updating JIRA {backport_data.jira_issue} with {state.backport_result.mr_url} ")
286-
287-
await post_private_jira_comment(gateway_tools, backport_data.jira_issue, agent_type, state.backport_result.mr_url)
288-
else:
289-
logger.info(f"Agent failed to perform a backport for {backport_data.jira_issue}.")
290-
await post_private_jira_comment(gateway_tools, backport_data.jira_issue, agent_type,
291-
"Agent failed to perform a backport: {state.backport_result.error}")
292-
293-
294-
295297
except Exception as e:
296298
error = "".join(traceback.format_exception(e))
297299
logger.error(f"Exception during backport processing for {backport_data.jira_issue}: {error}")
298300
await retry(task, ErrorData(details=error, jira_issue=backport_data.jira_issue).model_dump_json())
299-
rmtree(local_clone)
300301
else:
301-
rmtree(local_clone)
302-
if state.backport_data.success:
302+
if state.backport_result.success:
303303
logger.info(f"Backport successful for {backport_data.jira_issue}, " f"adding to completed list")
304-
await redis.lpush("completed_backport_list", output.model_dump_json())
304+
await redis.lpush("completed_backport_list", state.backport_result.model_dump_json())
305305
else:
306-
logger.warning(f"Backport failed for {backport_data.jira_issue}: {state.backport_data.error}")
307-
await retry(task, state.backport_data.error)
306+
logger.warning(f"Backport failed for {backport_data.jira_issue}: {state.backport_result.error}")
307+
await retry(task, state.backport_result.error)
308308

309309

310310
if __name__ == "__main__":

beeai/agents/rebase_agent.py

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ class InputSchema(BaseModel):
4444
class OutputSchema(BaseModel):
4545
success: bool = Field(description="Whether the rebase was successfully completed")
4646
status: str = Field(description="Rebase status")
47-
mr_url: str | None = Field(description="URL to the opened merge request")
4847
error: str | None = Field(description="Specific details about an error")
4948

5049

@@ -132,6 +131,8 @@ async def main() -> None:
132131
],
133132
)
134133

134+
dry_run = os.getenv("DRY_RUN", "False").lower() == "true"
135+
135136
class State(BaseModel):
136137
jira_issue: str
137138
package: str
@@ -178,7 +179,7 @@ async def run_rebase_agent(state):
178179
if state.rebase_result.success:
179180
return "commit_push_and_open_mr"
180181
else:
181-
return Workflow.END
182+
return "comment_in_jira"
182183

183184
async def commit_push_and_open_mr(state):
184185
state.merge_request_url = await tasks.commit_push_and_open_mr(
@@ -191,13 +192,29 @@ async def commit_push_and_open_mr(state):
191192
mr_title=f"{COMMIT_PREFIX} Update to version {state.version}",
192193
mr_description="TODO",
193194
available_tools=gateway_tools,
194-
commit_only=os.getenv("DRY_RUN", "False").lower() == "true",
195+
commit_only=dry_run,
196+
)
197+
return "comment_in_jira"
198+
199+
async def comment_in_jira(state):
200+
if dry_run:
201+
return Workflow.END
202+
await tasks.comment_in_jira(
203+
jira_issue=state.jira_issue,
204+
agent_type="Rebase",
205+
comment_text=(
206+
state.merge_request_url
207+
if state.rebase_result.success
208+
else f"Agent failed to perform a rebase: {state.rebase_result.error}"
209+
),
210+
available_tools=gateway_tools,
195211
)
196212
return Workflow.END
197213

198214
workflow.add_step("fork_and_prepare_dist_git", fork_and_prepare_dist_git)
199215
workflow.add_step("run_rebase_agent", run_rebase_agent)
200216
workflow.add_step("commit_push_and_open_mr", commit_push_and_open_mr)
217+
workflow.add_step("comment_in_jira", comment_in_jira)
201218

202219
async def run_workflow(package, dist_git_branch, version, jira_issue):
203220
response = await workflow.run(
@@ -282,15 +299,6 @@ async def retry(task, error):
282299
f"Rebase processing completed for {rebase_data.jira_issue}, " f"success: {state.rebase_result.success}"
283300
)
284301

285-
agent_type = "Rebase"
286-
if state.rebase_result.success:
287-
logger.info(f"Updating JIRA {rebase_data.jira_issue} with {state.rebase_result.mr_url} ")
288-
await post_private_jira_comment(gateway_tools, rebase_data.jira_issue, agent_type, state.rebase_result.mr_url)
289-
else:
290-
logger.info(f"Agent failed to perform a rebase for {rebase_data.jira_issue}.")
291-
await post_private_jira_comment(gateway_tools, rebase_data.jira_issue, agent_type,
292-
"Agent failed to perform a rebase: {state.rebase_result.error}")
293-
294302
except Exception as e:
295303
error = "".join(traceback.format_exception(e))
296304
logger.error(f"Exception during rebase processing for {rebase_data.jira_issue}: {error}")

beeai/agents/tasks.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
from beeai_framework.tools import Tool
99

10-
from constants import BRANCH_PREFIX
10+
from constants import BRANCH_PREFIX, JIRA_COMMENT_TEMPLATE
1111
from utils import check_subprocess, run_tool
1212

1313

@@ -73,3 +73,18 @@ async def commit_push_and_open_mr(
7373
source=update_branch,
7474
available_tools=available_tools,
7575
)
76+
77+
78+
async def comment_in_jira(
79+
jira_issue: str,
80+
agent_type: str,
81+
comment_text: str,
82+
available_tools: list[Tool],
83+
) -> None:
84+
await run_tool(
85+
"add_jira_comment",
86+
issue_key=jira_issue,
87+
comment=JIRA_COMMENT_TEMPLATE.substitute(AGENT_TYPE=agent_type, JIRA_COMMENT=comment_text),
88+
private=True,
89+
available_tools=available_tools,
90+
)

beeai/agents/triage_agent.py

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,12 @@
2323
from beeai_framework.tools.think import ThinkTool
2424
from beeai_framework.workflows import Workflow
2525

26+
import tasks
2627
from observability import setup_observability
2728
from tools.commands import RunShellCommandTool
2829
from tools.patch_validator import PatchValidatorTool
2930
from tools.version_mapper import VersionMapperTool
30-
from utils import fix_await, get_agent_execution_config, mcp_tools, redis_client, post_private_jira_comment, run_tool
31+
from utils import fix_await, get_agent_execution_config, mcp_tools, redis_client, run_tool
3132

3233
logger = logging.getLogger(__name__)
3334

@@ -329,6 +330,8 @@ async def main() -> None:
329330
]
330331
)
331332

333+
dry_run = os.getenv("DRY_RUN", "False").lower() == "true"
334+
332335
class State(BaseModel):
333336
jira_issue: str
334337
cve_eligibility_result: dict | None = Field(default=None)
@@ -360,7 +363,7 @@ async def check_cve_eligibility(state):
360363
jira_issue=state.jira_issue
361364
)
362365
)
363-
return Workflow.END
366+
return "comment_in_jira"
364367

365368
reason = state.cve_eligibility_result.get('reason', 'Eligible')
366369
logger.info(f"Issue {state.jira_issue} is eligible for triage: {reason}")
@@ -379,6 +382,8 @@ async def run_triage_analysis(state):
379382

380383
if state.triage_result.resolution in [Resolution.REBASE, Resolution.BACKPORT]:
381384
return "determine_target_branch"
385+
elif state.triage_result.resolution in [Resolution.CLARIFICATION_NEEDED, Resolution.NO_ACTION]:
386+
return "comment_in_jira"
382387
else:
383388
return Workflow.END
384389

@@ -398,9 +403,25 @@ async def determine_target_branch_step(state):
398403

399404
return Workflow.END
400405

406+
async def comment_in_jira(state):
407+
if dry_run:
408+
return Workflow.END
409+
await tasks.comment_in_jira(
410+
jira_issue=state.jira_issue,
411+
agent_type="Triage",
412+
comment_text=(
413+
state.triage_result.data.additional_info_needed
414+
if state.triage_result.resolution == Resolution.CLARIFICATION_NEEDED
415+
else state.triage_result.data.reasoning
416+
),
417+
available_tools=gateway_tools,
418+
)
419+
return Workflow.END
420+
401421
workflow.add_step("check_cve_eligibility", check_cve_eligibility)
402422
workflow.add_step("run_triage_analysis", run_triage_analysis)
403423
workflow.add_step("determine_target_branch", determine_target_branch_step)
424+
workflow.add_step("comment_in_jira", comment_in_jira)
404425

405426
async def run_workflow(jira_issue):
406427
response = await workflow.run(State(jira_issue=jira_issue))
@@ -465,12 +486,6 @@ async def retry(task, error):
465486
if state.target_branch:
466487
logger.info(f"Target branch: {state.target_branch}")
467488

468-
agent_type = "Triage"
469-
if output.resolution.value == "clarification-needed":
470-
await post_private_jira_comment(gateway_tools, input.issue, agent_type, output.data.additional_info_needed)
471-
elif output.resolution.value == "no-action":
472-
await post_private_jira_comment(gateway_tools, input.issue, agent_type, output.data.reasoning)
473-
474489
except Exception as e:
475490
error = "".join(traceback.format_exception(e))
476491
logger.error(f"Exception during triage processing for {input.issue}: {error}")

beeai/agents/utils.py

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
from beeai_framework.tools import Tool
1919
from beeai_framework.tools.mcp import MCPTool
2020

21-
from constants import JIRA_COMMENT_TEMPLATE
2221

2322
def get_agent_execution_config() -> AgentExecutionConfig:
2423
return AgentExecutionConfig(
@@ -127,25 +126,3 @@ async def mcp_tools(
127126
if filter:
128127
tools = [t for t in tools if filter(t.name)]
129128
yield tools
130-
131-
async def post_private_jira_comment(gateway_tools: list, issue_key: str, agent_type: str, comment: str):
132-
"""Finds the Jira comment tool and posts a comment to the specified issue."""
133-
134-
logger = logging.getLogger(__name__)
135-
136-
dry_run = os.getenv("DRY_RUN", "False").lower() == "true"
137-
138-
if not dry_run:
139-
try:
140-
comment_tool = next(t for t in gateway_tools if t.name == "add_private_jira_comment")
141-
await comment_tool.run(
142-
input={
143-
"issue_key": issue_key,
144-
"comment": JIRA_COMMENT_TEMPLATE.substitute({"AGENT_TYPE": agent_type,
145-
"JIRA_COMMENT": comment}),
146-
}
147-
).middleware(GlobalTrajectoryMiddleware(pretty=True))
148-
except StopIteration:
149-
logger.error("Jira comment tool not found in gateway tools.")
150-
except Exception as e:
151-
logger.error(f"Failed to post Jira comment for issue {issue_key}: {e}")

beeai/compose.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ services:
4747
- .secrets/mcp-gateway.env
4848
volumes:
4949
- ./mcp_server:/home/mcp/mcp_server:ro,z
50-
- .secrets/keytab:/home/mcp/keytab:ro,z
50+
- .secrets/keytab:/home/mcp/keytab:ro,z,U
5151
- git-repos:/git-repos
5252
- .secrets/rhel-config.json:/home/mcp/rhel-config.json:ro,z,U
5353
command: ["python", "mcp_server/gateway.py"]

beeai/mcp_server/gateway.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@
2121

2222

2323
if __name__ == "__main__":
24-
mcp.run(transport="sse", host="0.0.0.0", port=os.getenv("SSE_PORT"))
24+
mcp.run(transport="sse", host="0.0.0.0", port=int(os.getenv("SSE_PORT", "8000")))

beeai/mcp_server/jira_tools.py

Lines changed: 5 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -142,36 +142,18 @@ def set_jira_fields(
142142
def add_jira_comment(
143143
issue_key: Annotated[str, Field(description="Jira issue key (e.g. RHEL-12345)")],
144144
comment: Annotated[str, Field(description="Comment text to add")],
145+
private: Annotated[bool, Field(description="Whether the comment should be hidden from public")] = False,
145146
) -> str:
146147
"""
147148
Adds a comment to the specified Jira issue.
148149
"""
149150
try:
150151
response = requests.post(
151152
urljoin(os.getenv("JIRA_URL"), f"rest/api/2/issue/{issue_key}/comment"),
152-
json={"body": comment},
153-
headers=_get_jira_headers(os.getenv("JIRA_TOKEN")),
154-
)
155-
response.raise_for_status()
156-
except requests.RequestException as e:
157-
return f"Failed to add the specified comment: {e}"
158-
return f"Successfully added the specified comment to {issue_key}"
159-
160-
def add_private_jira_comment(
161-
issue_key: Annotated[str, Field(description="Jira issue key (e.g. RHEL-12345)")],
162-
comment: Annotated[str, Field(description="Comment text to add")],
163-
) -> str:
164-
"""
165-
Adds a private comment to the specified Jira issue.
166-
"""
167-
168-
if os.getenv("DRY_RUN", "False").lower() == "true":
169-
return "Dry run, not adding private comment"
170-
171-
try:
172-
response = requests.post(
173-
urljoin(os.getenv("JIRA_URL"), f"rest/api/2/issue/{issue_key}/comment"),
174-
json={"body": comment, "visibility": {"type":"group", "value":"Red Hat Employee"}},
153+
json={
154+
"body": comment,
155+
**({"visibility": {"type": "group", "value": "Red Hat Employee"}} if private else {}),
156+
},
175157
headers=_get_jira_headers(os.getenv("JIRA_TOKEN")),
176158
)
177159
response.raise_for_status()

0 commit comments

Comments
 (0)