Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion ymir/agents/tests/unit/test_triage_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
TriageEligibility,
TriageOutputSchema,
)
from ymir.common.version_utils import is_modular, parse_module_stream
from ymir.common.version_utils import extract_downstream_package, is_modular, parse_module_stream


@pytest.mark.parametrize(
Expand Down Expand Up @@ -316,6 +316,15 @@ def test_map_version_to_module_branch_invalid_version():
assert branch is None


def test_map_version_to_module_branch_extracts_package_from_raw_field():
"""customfield_10669 stores module:stream/package; mapping needs the package."""
raw = "postgresql:16/postgis"
summary = "postgresql:16/postgis: PostGIS: vuln"
assert _map_version_to_module_branch("rhel-9.8", summary, raw) is None
package = extract_downstream_package(raw)
assert _map_version_to_module_branch("rhel-9.8", summary, package) == "stream-postgresql-16-rhel-9.8.0"


# --- Modular target branch + namespace selection ---


Expand Down
11 changes: 9 additions & 2 deletions ymir/agents/triage_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
)
from ymir.common.version_utils import (
construct_internal_branch_name,
extract_downstream_package,
is_modular,
is_older_zstream,
normalize_fix_version,
Expand Down Expand Up @@ -410,7 +411,10 @@ class TriageState(BaseModel):
)
downstream_component: str | None = Field(
default=None,
description="Jira Downstream Component Name (customfield_10669), used for modular detection.",
description=(
"Package name from Jira Downstream Component Name (customfield_10669). "
"Modular values are reduced from 'module:stream/package' to the package."
),
)
jira_summary: str | None = Field(
default=None,
Expand Down Expand Up @@ -645,7 +649,10 @@ async def run_triage_analysis(state):

input_data = InputSchema(issue=state.jira_issue)
state.jira_summary = jira_details.get("fields", {}).get("summary")
state.downstream_component = jira_details.get("fields", {}).get(DOWNSTREAM_COMPONENT_CUSTOM_FIELD)
raw_component = jira_details.get("fields", {}).get(DOWNSTREAM_COMPONENT_CUSTOM_FIELD)
# Modular issues store "module:stream/package" (e.g. "postgresql:16/postgis");
# extract the package so is_modular() / parse_module_stream() match the summary.
state.downstream_component = extract_downstream_package(raw_component)
response = await triage_agent.run(
await render_prompt(
input_data,
Expand Down
32 changes: 32 additions & 0 deletions ymir/common/tests/unit/test_version_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
from flexmock import flexmock

from ymir.common.version_utils import (
extract_downstream_package,
get_maintenance_rhel_branch,
is_modular,
is_older_zstream,
parse_branch_name,
parse_module_stream,
Expand Down Expand Up @@ -199,3 +201,33 @@ async def mock_load_rhel_config():
)
def test_parse_module_stream(summary, component, expected):
assert parse_module_stream(summary, component) == expected


@pytest.mark.parametrize(
"raw, expected",
[
("postgresql:16/postgis", "postgis"),
("nodejs:18/nodejs", "nodejs"),
("perl:5.32/perl-IO-Socket-SSL", "perl-IO-Socket-SSL"),
("libtiff", "libtiff"),
("regular-component", "regular-component"),
(None, None),
("", None),
],
)
def test_extract_downstream_package(raw, expected):
assert extract_downstream_package(raw) == expected


def test_is_modular_requires_package_not_full_modular_string():
summary = "postgresql:16/postgis: PostGIS: vuln"
raw = "postgresql:16/postgis"
assert is_modular(summary, raw) is False
assert is_modular(summary, extract_downstream_package(raw)) is True


def test_parse_module_stream_requires_package_not_full_modular_string():
summary = "postgresql:16/postgis: PostGIS: vuln"
raw = "postgresql:16/postgis"
assert parse_module_stream(summary, raw) is None
assert parse_module_stream(summary, extract_downstream_package(raw)) == ("postgresql", "16")
12 changes: 12 additions & 0 deletions ymir/common/version_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,18 @@ async def is_older_zstream(
MODULAR_SUMMARY_PREFIX = r"^(?:\S+\s+)*([\w.+-]+):([^/\s]+)/"


def extract_downstream_package(raw: str | None) -> str | None:
"""Return the package name from Jira Downstream Component Name (customfield_10669).

Modular issues store ``module:stream/package`` (e.g. ``postgresql:16/postgis``);
non-modular issues store just the package name. ``is_modular`` and
``parse_module_stream`` match the summary against the package part only.
"""
if not raw:
return None
return raw.rsplit("/", 1)[-1]


def is_modular(summary: str | None, component: str | None) -> bool:
if not summary or not component:
return False
Expand Down
Loading