Skip to content

Commit 56b02d7

Browse files
committed
Automatically create missing Z-Stream branches
Signed-off-by: Nikola Forró <[email protected]>
1 parent 284aa53 commit 56b02d7

File tree

7 files changed

+92
-4
lines changed

7 files changed

+92
-4
lines changed

Containerfile.mcp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,8 @@ WORKDIR $HOME
4040

4141
ENV PYTHONPATH=$HOME:$PYTHONPATH
4242

43+
RUN mkdir ~/.ssh \
44+
&& chmod 0700 ~/.ssh \
45+
&& ssh-keyscan pkgs.devel.redhat.com >> ~/.ssh/known_hosts
46+
4347
CMD ["/bin/bash"]

agents/constants.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
from enum import Enum
22
from string import Template
33

4-
BREWHUB_URL = "https://brewhub.engineering.redhat.com/brewhub"
5-
64
BRANCH_PREFIX = "automated-package-update"
75

86
AGENT_WARNING = (

agents/tasks.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@ async def fork_and_prepare_dist_git(
3131
fork_url = await run_tool("fork_repository", repository=repository, available_tools=available_tools)
3232
local_clone = working_dir / package
3333
shutil.rmtree(local_clone, ignore_errors=True)
34+
if not is_cs_branch(dist_git_branch):
35+
await run_tool(
36+
"create_zstream_branch",
37+
package=package,
38+
branch=dist_git_branch,
39+
available_tools=available_tools,
40+
)
3441
await run_tool(
3542
"clone_repository",
3643
repository=repository,

agents/tools/specfile.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
from beeai_framework.emitter import Emitter
1414
from beeai_framework.tools import StringToolOutput, Tool, ToolError, ToolRunOptions
1515

16+
from common.constants import BREWHUB_URL
1617
from common.validators import NonEmptyString
17-
from constants import BREWHUB_URL
1818
from utils import get_absolute_path
1919

2020

common/constants.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
from enum import Enum
22

3+
BREWHUB_URL = "https://brewhub.engineering.redhat.com/brewhub"
4+
5+
36
class RedisQueues(Enum):
47
"""Constants for Redis queue names used by Jotnar agents"""
58
TRIAGE_QUEUE = "triage_queue"

mcp_server/distgit_tools.py

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import asyncio
2+
import os
3+
import tempfile
4+
import time
5+
from typing import Annotated
6+
7+
import git
8+
import koji
9+
from fastmcp.exceptions import ToolError
10+
from pydantic import Field
11+
12+
from common.constants import BREWHUB_URL
13+
from common.utils import init_kerberos_ticket, KerberosError
14+
15+
SYNC_TIMEOUT = 1 * 60 * 60 # seconds
16+
17+
18+
async def create_zstream_branch(
19+
package: Annotated[str, Field(description="Package name")],
20+
branch: Annotated[str, Field(description="Name of the branch to create")]
21+
) -> str:
22+
"""
23+
Creates a new Z-Stream branch for the specified package in internal dist-git.
24+
"""
25+
try:
26+
principal = await init_kerberos_ticket()
27+
except KerberosError as e:
28+
raise ToolError(f"Failed to initialize Kerberos ticket: {e}") from e
29+
username = principal.split("@", maxsplit=1)[0]
30+
try:
31+
with tempfile.TemporaryDirectory() as path:
32+
repo = await asyncio.to_thread(
33+
git.Repo.clone_from,
34+
f"ssh://{username}@pkgs.devel.redhat.com/rpms/{package}",
35+
path,
36+
)
37+
if branch in [ref.name.split("/")[-1] for ref in repo.remotes.origin.refs]:
38+
return f"Z-Stream branch {branch} already exists, no need to create it"
39+
# find the correct base for our new branch:
40+
# - get candidate tag corresponding to the branch
41+
# - get the latest build the candidate tag inherited (from Y-Stream or previous Z-Stream)
42+
# - get the ref the inherited build originated from
43+
# - use that as a base for the new branch
44+
# this allows us to create Z-Stream branches even if a higher Z-Stream branch already exists
45+
session = koji.ClientSession(BREWHUB_URL)
46+
candidate_tag = f"{branch}-candidate"
47+
builds = await asyncio.to_thread(
48+
session.listTagged,
49+
package=package,
50+
tag=candidate_tag,
51+
latest=True,
52+
inherit=True,
53+
strict=True,
54+
)
55+
if not builds:
56+
raise RuntimeError(f"There are no builds of {package} in {candidate_tag}")
57+
[build] = builds
58+
metadata = await asyncio.to_thread(session.getBuild, build["build_id"], strict=True)
59+
ref = metadata["source"].split("#")[-1]
60+
await asyncio.to_thread(repo.remotes.origin.push, f"{ref}:refs/heads/{branch}")
61+
# wait until the new branch is synced to GitLab
62+
token = os.environ["GITLAB_TOKEN"]
63+
start_time = time.monotonic()
64+
while time.monotonic() - start_time < SYNC_TIMEOUT:
65+
if await asyncio.to_thread(
66+
repo.git.ls_remote,
67+
f"https://oauth2:{token}@gitlab.com/redhat/rhel/rpms/{package}",
68+
branch,
69+
branches=True,
70+
):
71+
return f"Succesfully created Z-Stream branch {branch}"
72+
await asyncio.sleep(30)
73+
raise RuntimeError(f"The {branch} branch wasn't synced to GitLab after {SYNC_TIMEOUT} seconds")
74+
except Exception as e:
75+
raise ToolError(f"Failed to create Z-Stream branch: {e}") from e

mcp_server/gateway.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from fastmcp import FastMCP
66

77
import copr_tools
8+
import distgit_tools
89
import gitlab_tools
910
import jira_tools
1011
import lookaside_tools
@@ -14,7 +15,7 @@
1415
name="MCP Gateway",
1516
tools=[
1617
coroutine
17-
for module in [copr_tools, gitlab_tools, jira_tools, lookaside_tools]
18+
for module in [copr_tools, distgit_tools, gitlab_tools, jira_tools, lookaside_tools]
1819
for name, coroutine in inspect.getmembers(module, inspect.iscoroutinefunction)
1920
if coroutine.__module__ == module.__name__
2021
and not name.startswith("_")

0 commit comments

Comments
 (0)