koji_block_retired: Do not block on stable branches
Signed-off-by: Lenka Segura <lsegura@redhat.com>
This commit is contained in:
parent
901d77f0b5
commit
dba8da1dc6
4 changed files with 315 additions and 8 deletions
|
@ -208,6 +208,49 @@ class TestProcessBlockRetired:
|
|||
== "Cannot block package example-repo on frozen branch main, bailing."
|
||||
)
|
||||
|
||||
@patch("toddlers.plugins.koji_block_retired.bodhi.set_bodhi")
|
||||
@patch("toddlers.plugins.koji_block_retired.pagure.set_pagure")
|
||||
@patch("toddlers.plugins.koji_block_retired.KojiBlockRetired._create_session")
|
||||
@patch("toddlers.plugins.koji_block_retired.KojiBlockRetired.get_tag_from_target")
|
||||
def test_dead_package_added_to_stable_branch(
|
||||
self,
|
||||
mock_get_tag_from_target,
|
||||
mock_session,
|
||||
mock_pagure,
|
||||
mock_set_bodhi,
|
||||
config,
|
||||
caplog,
|
||||
):
|
||||
"""
|
||||
Assert that that main branch will be changed to rawhide tag
|
||||
"""
|
||||
mock_get_tag_from_target.return_value = "f41"
|
||||
caplog.set_level(logging.INFO)
|
||||
mock_dist_git = MagicMock()
|
||||
mock_dist_git.has_dead_package_on_branch.return_value = True
|
||||
mock_pagure.return_value = mock_dist_git
|
||||
|
||||
mock_bodhi = MagicMock()
|
||||
mock_bodhi.is_branch_frozen.return_value = False
|
||||
mock_bodhi.is_branch_stable.return_value = True
|
||||
mock_set_bodhi.return_value = mock_bodhi
|
||||
|
||||
message = MagicMock()
|
||||
message.body = {
|
||||
"commit": {
|
||||
"stats": {"files": {"dead.package": {"additions": 1, "deletions": 0}}},
|
||||
"branch": "f41",
|
||||
"repo": "example-repo",
|
||||
"namespace": "example_ns",
|
||||
"date": "2024-09-16T12:12:46+01:00",
|
||||
}
|
||||
}
|
||||
message.topic = "git.receive"
|
||||
self.toddler_cls.process(config, message)
|
||||
self.toddler_cls.koji_session.packageListBlock.assert_not_called()
|
||||
self.toddler_cls.koji_session.listPackages.assert_not_called()
|
||||
assert caplog.records[-1].message == "Cannot block on stable branches: f41"
|
||||
|
||||
@patch("toddlers.plugins.koji_block_retired.bodhi.set_bodhi")
|
||||
@patch("toddlers.plugins.koji_block_retired.pagure.set_pagure")
|
||||
@patch("toddlers.plugins.koji_block_retired.KojiBlockRetired._create_session")
|
||||
|
@ -232,6 +275,7 @@ class TestProcessBlockRetired:
|
|||
|
||||
mock_bodhi = MagicMock()
|
||||
mock_bodhi.is_branch_frozen.return_value = False
|
||||
mock_bodhi.is_branch_stable.return_value = False
|
||||
mock_set_bodhi.return_value = mock_bodhi
|
||||
|
||||
message = MagicMock()
|
||||
|
@ -270,6 +314,7 @@ class TestProcessBlockRetired:
|
|||
|
||||
mock_bodhi = MagicMock()
|
||||
mock_bodhi.is_branch_frozen.return_value = False
|
||||
mock_bodhi.is_branch_stable.return_value = False
|
||||
mock_set_bodhi.return_value = mock_bodhi
|
||||
|
||||
caplog.set_level(logging.INFO)
|
||||
|
@ -306,6 +351,7 @@ class TestProcessBlockRetired:
|
|||
|
||||
mock_bodhi = MagicMock()
|
||||
mock_bodhi.is_branch_frozen.return_value = False
|
||||
mock_bodhi.is_branch_stable.return_value = False
|
||||
mock_set_bodhi.return_value = mock_bodhi
|
||||
|
||||
message = MagicMock()
|
||||
|
@ -348,6 +394,7 @@ class TestProcessBlockRetired:
|
|||
|
||||
mock_bodhi = MagicMock()
|
||||
mock_bodhi.is_branch_frozen.return_value = False
|
||||
mock_bodhi.is_branch_stable.return_value = False
|
||||
mock_set_bodhi.return_value = mock_bodhi
|
||||
|
||||
message = MagicMock()
|
||||
|
@ -431,6 +478,7 @@ class TestProcessBlockRetired:
|
|||
|
||||
mock_bodhi = MagicMock()
|
||||
mock_bodhi.is_branch_frozen.return_value = False
|
||||
mock_bodhi.is_branch_stable.return_value = False
|
||||
mock_set_bodhi.return_value = mock_bodhi
|
||||
|
||||
caplog.set_level(logging.INFO)
|
||||
|
@ -1044,14 +1092,12 @@ class TestProcessBlockRetired:
|
|||
)
|
||||
|
||||
@patch("requests.get")
|
||||
@patch("toddlers.plugins.koji_block_retired.KojiBlockRetired.get_tag_from_target")
|
||||
@patch("toddlers.plugins.koji_block_retired.bodhi.set_bodhi")
|
||||
@patch("toddlers.plugins.koji_block_retired.KojiBlockRetired._create_session")
|
||||
def test_playtime_call_frozen_branch(
|
||||
self,
|
||||
mock_create_session,
|
||||
mock_set_bodhi,
|
||||
mock_rawhide,
|
||||
mock_req,
|
||||
config,
|
||||
caplog,
|
||||
|
@ -1068,20 +1114,16 @@ class TestProcessBlockRetired:
|
|||
mock_response = MagicMock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
"rawhide": [
|
||||
"f41": [
|
||||
"fedora_pkg",
|
||||
]
|
||||
}
|
||||
|
||||
def req(*args, **kwargs):
|
||||
if (
|
||||
args[0]
|
||||
== "https://src.fedoraproject.org/lookaside/retired_in_rawhide.json"
|
||||
):
|
||||
if args[0] == "https://src.fedoraproject.org/lookaside/retired_in_f41.json":
|
||||
return mock_response
|
||||
|
||||
mock_req.side_effect = req
|
||||
mock_rawhide.return_value = "f42"
|
||||
self.toddler_cls.process(config, message)
|
||||
self.toddler_cls.koji_session.listPackages.assert_not_called()
|
||||
self.toddler_cls.koji_session.packageListBlock.assert_not_called()
|
||||
|
@ -1091,6 +1133,54 @@ class TestProcessBlockRetired:
|
|||
)
|
||||
assert caplog.records[-2].message == "Branch rawhide is frozen, ignoring."
|
||||
|
||||
@patch("requests.get")
|
||||
@patch(
|
||||
"toddlers.plugins.koji_block_retired.KojiBlockRetired.adjust_releases_for_lookaside"
|
||||
)
|
||||
@patch("toddlers.plugins.koji_block_retired.bodhi.set_bodhi")
|
||||
@patch("toddlers.plugins.koji_block_retired.KojiBlockRetired._create_session")
|
||||
def test_playtime_call_stable_branch(
|
||||
self,
|
||||
mock_create_session,
|
||||
mock_set_bodhi,
|
||||
mock_adjusted,
|
||||
mock_req,
|
||||
config,
|
||||
caplog,
|
||||
):
|
||||
mock_bodhi = MagicMock()
|
||||
mock_bodhi.get_active_branches.return_value = [
|
||||
"f41",
|
||||
]
|
||||
mock_bodhi.is_branch_frozen.return_value = False
|
||||
mock_bodhi.is_branch_stable.return_value = True
|
||||
mock_set_bodhi.return_value = mock_bodhi
|
||||
caplog.set_level(logging.INFO)
|
||||
message = MagicMock()
|
||||
message.topic = "toddlers.trigger.koji_block_retired"
|
||||
mock_response = MagicMock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
"f41": [
|
||||
"fedora_pkg",
|
||||
]
|
||||
}
|
||||
|
||||
def req(*args, **kwargs):
|
||||
if args[0] == "https://src.fedoraproject.org/lookaside/retired_in_f41.json":
|
||||
return mock_response
|
||||
|
||||
mock_req.side_effect = req
|
||||
mock_adjusted.return_value = ["f41"]
|
||||
self.toddler_cls.process(config, message)
|
||||
self.toddler_cls.koji_session.listPackages.assert_not_called()
|
||||
self.toddler_cls.koji_session.packageListBlock.assert_not_called()
|
||||
assert (
|
||||
caplog.records[-1].message
|
||||
== "All packages that should be blocked in this run: {}"
|
||||
)
|
||||
assert caplog.records[-2].message == "Cannot block on stable branches: f41"
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"releases",
|
||||
[
|
||||
|
|
|
@ -202,3 +202,121 @@ class TestBodhiGetFrozenBranches:
|
|||
result = self.bodhi.is_branch_frozen("f41")
|
||||
|
||||
assert result is False
|
||||
|
||||
|
||||
class TestBodhiGetBranchInfo:
|
||||
"""
|
||||
Test class for `toddlers.utils.bodhi.Bodhi.get_frozen_branches` method.
|
||||
"""
|
||||
|
||||
def setup_method(self):
|
||||
"""
|
||||
Setup method for the test class.
|
||||
"""
|
||||
config = {
|
||||
"bodhi_url": "https://bodhi.fedoraproject.org",
|
||||
}
|
||||
self.bodhi = bodhi.set_bodhi(config)
|
||||
self.bodhi._requests_session = Mock()
|
||||
|
||||
def test_get_branch_info(self):
|
||||
"""
|
||||
Assert that branch info isretrieved correctly from Bodhi.
|
||||
"""
|
||||
response_mock = Mock()
|
||||
response_mock.status_code = 200
|
||||
info = {"name": "F42", "long_name": "Fedora 42", "version": "42", "eol": None}
|
||||
data = {
|
||||
"releases": [
|
||||
{"name": "F42", "long_name": "Fedora 42", "version": "42", "eol": None}
|
||||
],
|
||||
"page": 1,
|
||||
"pages": 1,
|
||||
"rows_per_page": 20,
|
||||
"total": 1,
|
||||
}
|
||||
|
||||
response_mock.json.return_value = data
|
||||
|
||||
self.bodhi._requests_session.get.return_value = response_mock
|
||||
|
||||
result = self.bodhi.get_branch_info("f42")
|
||||
|
||||
self.bodhi._requests_session.get.assert_called_once()
|
||||
|
||||
assert result == info
|
||||
|
||||
def test_get_branch_info_malformed_data(self):
|
||||
"""
|
||||
Assert that retrieving malformed json from bodhi is handled correctly.
|
||||
"""
|
||||
response_mock = Mock()
|
||||
response_mock.status_code = 200
|
||||
data = {}
|
||||
response_mock.json.return_value = data
|
||||
|
||||
self.bodhi._requests_session.get.return_value = response_mock
|
||||
|
||||
expected_error = "Expected key not found in bodhi response."
|
||||
|
||||
with pytest.raises(BodhiError, match=expected_error):
|
||||
self.bodhi.get_branch_info("f41")
|
||||
|
||||
self.bodhi._requests_session.get.assert_called_once()
|
||||
|
||||
def test_get_branch_info_not_ok(self):
|
||||
"""
|
||||
Assert that failing to retrieve branch info from bodhi is handled correctly.
|
||||
"""
|
||||
response_mock = Mock()
|
||||
response_mock.status_code = 500
|
||||
response_mock.headers = {"content-type": "application/json"}
|
||||
|
||||
self.bodhi._requests_session.get.return_value = response_mock
|
||||
|
||||
expected_error = "Couldn't retrieve branch info."
|
||||
|
||||
with pytest.raises(BodhiError, match=expected_error):
|
||||
self.bodhi.get_branch_info("f41")
|
||||
|
||||
self.bodhi._requests_session.get.assert_called_once()
|
||||
|
||||
def test_is_branch_stable_no_eol(self):
|
||||
get_stable_mock = Mock()
|
||||
get_stable_mock.return_value = {
|
||||
"name": "F42",
|
||||
"long_name": "Fedora 42",
|
||||
"version": "42",
|
||||
"eol": None,
|
||||
}
|
||||
|
||||
self.bodhi.get_branch_info = get_stable_mock
|
||||
|
||||
result = self.bodhi.is_branch_stable("f42")
|
||||
|
||||
assert result is False
|
||||
|
||||
def test_is_branch_stable_eol(self):
|
||||
get_stable_mock = Mock()
|
||||
get_stable_mock.return_value = {
|
||||
"name": "F41",
|
||||
"long_name": "Fedora 41",
|
||||
"version": "41",
|
||||
"eol": "2025-11-11",
|
||||
}
|
||||
|
||||
self.bodhi.get_branch_info = get_stable_mock
|
||||
|
||||
result = self.bodhi.is_branch_stable("f41")
|
||||
|
||||
assert result is True
|
||||
|
||||
def test_is_branch_stable_returns_nothing(self):
|
||||
get_stable_mock = Mock()
|
||||
get_stable_mock.return_value = {}
|
||||
|
||||
self.bodhi.get_branch_info = get_stable_mock
|
||||
|
||||
result = self.bodhi.is_branch_stable("f41")
|
||||
|
||||
assert result is True
|
||||
|
|
|
@ -96,9 +96,15 @@ class KojiBlockRetired(ToddlerBase):
|
|||
adjusted = self.adjust_releases_for_lookaside(active_releases)
|
||||
needs_blocking = defaultdict(list)
|
||||
for active_release in adjusted:
|
||||
# Do not block on frozen branches
|
||||
if self.bodhi.is_branch_frozen(active_release):
|
||||
_log.info(f"Branch {active_release} is frozen, ignoring.")
|
||||
continue
|
||||
# Do not block on fedora stable branches (have EOL)
|
||||
if re.match(r"^f", active_release):
|
||||
if self.bodhi.is_branch_stable(active_release):
|
||||
_log.info(f"Cannot block on stable branches: {active_release}")
|
||||
continue
|
||||
retired_url = f"{config['lookaside_url']}/retired_in_{active_release}.json"
|
||||
response = requests.get(retired_url)
|
||||
if not response.ok:
|
||||
|
@ -228,6 +234,15 @@ class KojiBlockRetired(ToddlerBase):
|
|||
)
|
||||
return
|
||||
|
||||
# Retirements are allowed on rawhide, branched and EPEL
|
||||
# and so is koji blocking.
|
||||
# Exclude stable fedora branches from blocking.
|
||||
# Stable branches are defined as those that have set EOL date.
|
||||
if re.match(r"^f", branch):
|
||||
if self.bodhi.is_branch_stable(branch):
|
||||
_log.info(f"Cannot block on stable branches: {branch}")
|
||||
return
|
||||
|
||||
if self.koji_session is None:
|
||||
self._create_session() # pragma: no cover
|
||||
|
||||
|
|
|
@ -197,3 +197,87 @@ class Bodhi:
|
|||
if branch in frozen:
|
||||
return True
|
||||
return False
|
||||
|
||||
def get_branch_info(self, branch) -> dict:
|
||||
"""
|
||||
Get info about a particular branch from bodhi.
|
||||
Params:
|
||||
branch: string
|
||||
|
||||
Returns:
|
||||
Dict containing branch info.
|
||||
|
||||
Raises:
|
||||
toddlers.utils.exceptions.BodhiError when the issue couldn't be retrieved.
|
||||
"""
|
||||
api_url = f"{0}/list_releases/?name={branch}".format(self._bodhi_url)
|
||||
log.debug("Retrieving branch info from bodhi.")
|
||||
response = self._requests_session.get(api_url)
|
||||
|
||||
info = {}
|
||||
|
||||
if response.status_code == 200:
|
||||
response_json = response.json()
|
||||
try:
|
||||
if response_json["releases"]:
|
||||
(info,) = response_json["releases"]
|
||||
return info
|
||||
|
||||
except KeyError:
|
||||
raise BodhiError(
|
||||
(
|
||||
"Expected key not found in bodhi response. "
|
||||
"Expected data: [<branch_name>]\n\n"
|
||||
"Request to '{0}':\n\n"
|
||||
"Response:\n"
|
||||
"{1}\n\n"
|
||||
"Status code: {2}"
|
||||
).format(
|
||||
api_url,
|
||||
response_json,
|
||||
response.status_code,
|
||||
)
|
||||
)
|
||||
|
||||
log.error(
|
||||
"Error when retrieving branch info. " "Got status_code '%s'.",
|
||||
response.status_code,
|
||||
)
|
||||
|
||||
response_json = None
|
||||
if response.headers.get("content-type") == "application/json":
|
||||
response_json = response.json()
|
||||
log.error("Received response: %s", response.json())
|
||||
|
||||
raise BodhiError(
|
||||
(
|
||||
"Couldn't retrieve branch info.\n\n"
|
||||
"Request to '{0}':\n\n"
|
||||
"Response:\n"
|
||||
"{1}\n\n"
|
||||
"Status code: {2}"
|
||||
).format(
|
||||
api_url,
|
||||
response_json,
|
||||
response.status_code,
|
||||
)
|
||||
)
|
||||
|
||||
def is_branch_stable(self, branch) -> bool:
|
||||
"""Check whether the given branch is already stable => has end-of-life set.
|
||||
Params:
|
||||
branch: string
|
||||
|
||||
Returns:
|
||||
bool
|
||||
"""
|
||||
branch_info = self.get_branch_info(branch)
|
||||
try:
|
||||
if branch_info["eol"]:
|
||||
return True
|
||||
return False
|
||||
except KeyError:
|
||||
log.info(
|
||||
"Did not get relevant data from Bodhi to decide if the branch is stable"
|
||||
)
|
||||
return True
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue