Compare commits
No commits in common. "main" and "production" have entirely different histories.
main
...
production
9 changed files with 76 additions and 2777 deletions
|
@ -134,10 +134,7 @@ class TestProcess:
|
|||
@patch("toddlers.utils.pagure.set_pagure")
|
||||
@patch("toddlers.utils.fedora_account.set_fasjson")
|
||||
@patch("toddlers.utils.bugzilla_system.set_bz")
|
||||
@patch("toddlers.utils.anitya.set_anitya")
|
||||
def test_process_exception(
|
||||
self, mock_anitya, mock_bugzilla, mock_fasjson, mock_pagure, toddler
|
||||
):
|
||||
def test_process_exception(self, mock_bugzilla, mock_fasjson, mock_pagure, toddler):
|
||||
"""
|
||||
Assert that message toddler will be initialized correctly, if message passes
|
||||
initial processing.
|
||||
|
@ -183,16 +180,12 @@ class TestProcess:
|
|||
)
|
||||
mock_fasjson.assert_called_with(config)
|
||||
mock_bugzilla.assert_called_with(config)
|
||||
mock_anitya.assert_called_with(config)
|
||||
mock_pagure_io.add_comment_to_issue.assert_called_once()
|
||||
|
||||
@patch("toddlers.utils.anitya.set_anitya")
|
||||
@patch("toddlers.utils.pagure.set_pagure")
|
||||
@patch("toddlers.utils.fedora_account.set_fasjson")
|
||||
@patch("toddlers.utils.bugzilla_system.set_bz")
|
||||
def test_process(
|
||||
self, mock_bugzilla, mock_fasjson, mock_pagure, mock_anitya, toddler
|
||||
):
|
||||
def test_process(self, mock_bugzilla, mock_fasjson, mock_pagure, toddler):
|
||||
"""
|
||||
Assert that message toddler will be initialized correctly, if message passes
|
||||
initial processing.
|
||||
|
@ -234,15 +227,11 @@ class TestProcess:
|
|||
)
|
||||
mock_fasjson.assert_called_with(config)
|
||||
mock_bugzilla.assert_called_with(config)
|
||||
mock_anitya.assert_called_with(config)
|
||||
|
||||
@patch("toddlers.utils.anitya.set_anitya")
|
||||
@patch("toddlers.utils.pagure.set_pagure")
|
||||
@patch("toddlers.utils.fedora_account.set_fasjson")
|
||||
@patch("toddlers.utils.bugzilla_system.set_bz")
|
||||
def test_process_comment(
|
||||
self, mock_bugzilla, mock_fasjson, mock_pagure, mock_anitya, toddler
|
||||
):
|
||||
def test_process_comment(self, mock_bugzilla, mock_fasjson, mock_pagure, toddler):
|
||||
"""
|
||||
Assert that toddler will handle comments correctly.
|
||||
"""
|
||||
|
@ -802,7 +791,6 @@ class TestProcessNewRepo:
|
|||
self.toddler = scm_request_processor.SCMRequestProcessor()
|
||||
self.toddler.pagure_io = Mock()
|
||||
self.toddler.dist_git = Mock()
|
||||
self.toddler.anitya = Mock()
|
||||
self.toddler.ping_comment = "{maintainers}"
|
||||
|
||||
def test_process_new_repo_missing_required_key(self):
|
||||
|
@ -812,77 +800,12 @@ class TestProcessNewRepo:
|
|||
issue = {
|
||||
"id": 100,
|
||||
}
|
||||
json = {
|
||||
"repo": "+a",
|
||||
"branch": "rawhide",
|
||||
"namespace": "rpms",
|
||||
"bug_id": "123",
|
||||
"action": "new_repo",
|
||||
"sls": {"rawhide": "2050-06-01"},
|
||||
"monitor": "monitoring",
|
||||
}
|
||||
self.toddler.process_new_repo(issue, json)
|
||||
self.toddler.process_new_repo(issue, {})
|
||||
|
||||
self.toddler.pagure_io.close_issue.assert_called_with(
|
||||
100,
|
||||
namespace=scm_request_processor.PROJECT_NAMESPACE,
|
||||
message="Invalid body, missing required field: upstreamurl",
|
||||
reason="Invalid",
|
||||
)
|
||||
|
||||
def test_process_new_repo_missing_required_key_for_monitor(self):
|
||||
"""
|
||||
Assert that ticket will be closed if required key for monitor
|
||||
is missing in request.
|
||||
"""
|
||||
issue = {
|
||||
"id": 100,
|
||||
}
|
||||
json = {
|
||||
"repo": "+a",
|
||||
"branch": "rawhide",
|
||||
"namespace": "rpms",
|
||||
"bug_id": "123",
|
||||
"action": "new_repo",
|
||||
"sls": {"rawhide": "2050-06-01"},
|
||||
"monitor": "monitoring",
|
||||
"upstreamurl": "",
|
||||
"backend": "GitLab",
|
||||
}
|
||||
self.toddler.process_new_repo(issue, json)
|
||||
|
||||
self.toddler.pagure_io.close_issue.assert_called_with(
|
||||
100,
|
||||
namespace=scm_request_processor.PROJECT_NAMESPACE,
|
||||
message="Invalid body, missing required field: project_name",
|
||||
reason="Invalid",
|
||||
)
|
||||
|
||||
def test_process_new_repo_monitor_accepts_different_options(self):
|
||||
"""
|
||||
Assert that ticket will be closed if required key for monitor
|
||||
is missing in request.
|
||||
"""
|
||||
issue = {
|
||||
"id": 100,
|
||||
}
|
||||
json = {
|
||||
"repo": "+a",
|
||||
"branch": "rawhide",
|
||||
"namespace": "rpms",
|
||||
"bug_id": "123",
|
||||
"action": "new_repo",
|
||||
"sls": {"rawhide": "2050-06-01"},
|
||||
"monitor": "monitoring11",
|
||||
"upstreamurl": "",
|
||||
"backend": "GitLab",
|
||||
}
|
||||
self.toddler.process_new_repo(issue, json)
|
||||
|
||||
self.toddler.pagure_io.close_issue.assert_called_with(
|
||||
100,
|
||||
namespace=scm_request_processor.PROJECT_NAMESPACE,
|
||||
message="Invalid body, missing required field: project_name",
|
||||
message="Invalid body, missing required field: repo",
|
||||
reason="Invalid",
|
||||
)
|
||||
|
||||
|
@ -899,8 +822,40 @@ class TestProcessNewRepo:
|
|||
"bug_id": "123",
|
||||
"action": "new_repo",
|
||||
"sls": {"rawhide": "2050-06-01"},
|
||||
"monitor": "no-monitoring",
|
||||
"upstreamurl": "",
|
||||
"monitor": "monitor",
|
||||
}
|
||||
|
||||
self.toddler.process_new_repo(issue, json)
|
||||
|
||||
error = (
|
||||
"The repository name is invalid. It must be at least two "
|
||||
"characters long with only letters, numbers, hyphens, "
|
||||
"underscores, plus signs, and/or periods. Please note that "
|
||||
"the project cannot start with a period or a plus sign. "
|
||||
"Repository name can't be longer than 64 characters."
|
||||
)
|
||||
|
||||
self.toddler.pagure_io.close_issue.assert_called_with(
|
||||
100,
|
||||
namespace=scm_request_processor.PROJECT_NAMESPACE,
|
||||
message=error,
|
||||
reason="Invalid",
|
||||
)
|
||||
|
||||
def test_process_new_repo_long_repo_name(self):
|
||||
"""
|
||||
Assert that ticket will be closed if provided repository name is invalid.
|
||||
"""
|
||||
issue = {"id": 100, "user": {"name": "zlopez"}}
|
||||
|
||||
json = {
|
||||
"repo": "".join("a" for _ in range(65)),
|
||||
"branch": "rawhide",
|
||||
"namespace": "rpms",
|
||||
"bug_id": "123",
|
||||
"action": "new_repo",
|
||||
"sls": {"rawhide": "2050-06-01"},
|
||||
"monitor": "monitor",
|
||||
}
|
||||
|
||||
self.toddler.process_new_repo(issue, json)
|
||||
|
@ -933,8 +888,7 @@ class TestProcessNewRepo:
|
|||
"bug_id": "",
|
||||
"action": "new_repo",
|
||||
"sls": {"rawhide": "2050-06-01"},
|
||||
"monitor": "no-monitoring",
|
||||
"upstreamurl": "",
|
||||
"monitor": "monitor",
|
||||
}
|
||||
|
||||
self.toddler.dist_git.get_project.return_value = None
|
||||
|
@ -963,8 +917,7 @@ class TestProcessNewRepo:
|
|||
"bug_id": "123",
|
||||
"action": "new_repo",
|
||||
"sls": {"rawhide": "2050-06-01"},
|
||||
"monitor": "no-monitoring",
|
||||
"upstreamurl": "",
|
||||
"monitor": "monitor",
|
||||
}
|
||||
|
||||
self.toddler.dist_git.get_project.return_value = None
|
||||
|
@ -998,8 +951,7 @@ class TestProcessNewRepo:
|
|||
bug_id = "123"
|
||||
action = "new_repo"
|
||||
sls = {"rawhide": "2050-06-01"}
|
||||
monitor = "no-monitoring"
|
||||
upstreamurl = ""
|
||||
monitor = "monitor"
|
||||
exception = False
|
||||
json = {
|
||||
"repo": repo,
|
||||
|
@ -1009,7 +961,6 @@ class TestProcessNewRepo:
|
|||
"action": action,
|
||||
"sls": sls,
|
||||
"monitor": monitor,
|
||||
"upstreamurl": upstreamurl,
|
||||
"exception": exception,
|
||||
}
|
||||
|
||||
|
@ -1039,8 +990,7 @@ class TestProcessNewRepo:
|
|||
bug_id = "123"
|
||||
action = "new_repo"
|
||||
sls = {"rawhide": "2050-06-01"}
|
||||
monitor = "no-monitoring"
|
||||
upstreamurl = ""
|
||||
monitor = "monitor"
|
||||
exception = False
|
||||
json = {
|
||||
"repo": repo,
|
||||
|
@ -1050,7 +1000,6 @@ class TestProcessNewRepo:
|
|||
"action": action,
|
||||
"sls": sls,
|
||||
"monitor": monitor,
|
||||
"upstreamurl": upstreamurl,
|
||||
"exception": exception,
|
||||
}
|
||||
|
||||
|
@ -1071,10 +1020,7 @@ class TestProcessNewRepo:
|
|||
comment=message,
|
||||
)
|
||||
|
||||
@patch(
|
||||
"toddlers.plugins.scm_request_processor.SCMRequestProcessor.validate_review_bug"
|
||||
)
|
||||
def test_process_new_repo_master_branch(self, mock_validate_review_bug):
|
||||
def test_process_new_repo_master_branch(self):
|
||||
"""
|
||||
Assert that ticket will be closed when branch is set to master branch.
|
||||
Master branch is no longer allowed.
|
||||
|
@ -1087,8 +1033,7 @@ class TestProcessNewRepo:
|
|||
bug_id = "123"
|
||||
action = "new_repo"
|
||||
sls = {"rawhide": "2050-06-01"}
|
||||
monitor = "no-monitoring"
|
||||
upstreamurl = ""
|
||||
monitor = "monitor"
|
||||
exception = False
|
||||
json = {
|
||||
"repo": repo,
|
||||
|
@ -1098,7 +1043,6 @@ class TestProcessNewRepo:
|
|||
"action": action,
|
||||
"sls": sls,
|
||||
"monitor": monitor,
|
||||
"upstreamurl": upstreamurl,
|
||||
"exception": exception,
|
||||
}
|
||||
self.toddler.dist_git.get_project.return_value = None
|
||||
|
@ -1124,8 +1068,7 @@ class TestProcessNewRepo:
|
|||
bug_id = "123"
|
||||
action = "new_repo"
|
||||
sls = {"rawhide": "2050-06-01"}
|
||||
monitor = "no-monitoring"
|
||||
upstreamurl = ""
|
||||
monitor = "monitor"
|
||||
exception = False
|
||||
json = {
|
||||
"repo": repo,
|
||||
|
@ -1135,7 +1078,6 @@ class TestProcessNewRepo:
|
|||
"action": action,
|
||||
"sls": sls,
|
||||
"monitor": monitor,
|
||||
"upstreamurl": upstreamurl,
|
||||
"exception": exception,
|
||||
}
|
||||
self.toddler.process_new_repo(issue, json)
|
||||
|
@ -1178,12 +1120,11 @@ class TestProcessNewRepo:
|
|||
}
|
||||
|
||||
repo = "repo"
|
||||
bug_id = "11"
|
||||
bug_id = ""
|
||||
action = "new_repo"
|
||||
sls = {branch: "2050-06-01"}
|
||||
monitor = "no-monitoring"
|
||||
upstreamurl = ""
|
||||
exception = False
|
||||
monitor = "monitor"
|
||||
exception = True
|
||||
json = {
|
||||
"repo": repo,
|
||||
"branch": branch,
|
||||
|
@ -1192,7 +1133,6 @@ class TestProcessNewRepo:
|
|||
"action": action,
|
||||
"sls": sls,
|
||||
"monitor": monitor,
|
||||
"upstreamurl": upstreamurl,
|
||||
"exception": exception,
|
||||
}
|
||||
dist_git_url = "https://src.fp.o"
|
||||
|
@ -1201,11 +1141,8 @@ class TestProcessNewRepo:
|
|||
self.toddler.pagure_io.get_project_contributors.return_value = {
|
||||
"users": {"admin": [user], "commit": [], "ticket": []}
|
||||
}
|
||||
self.toddler.validation_comment = "valid"
|
||||
self.toddler.validate_review_bug = Mock()
|
||||
|
||||
# Method to test
|
||||
with patch("toddlers.plugins.scm_request_processor.bugzilla_system"):
|
||||
self.toddler.process_new_repo(issue, json)
|
||||
|
||||
# asserts
|
||||
|
@ -1239,8 +1176,7 @@ class TestProcessNewRepo:
|
|||
bug_id = ""
|
||||
action = "new_repo"
|
||||
sls = {branch: "2050-06-01"}
|
||||
monitor = "no-monitoring"
|
||||
upstreamurl = ""
|
||||
monitor = "monitor"
|
||||
exception = True
|
||||
json = {
|
||||
"repo": repo,
|
||||
|
@ -1250,7 +1186,6 @@ class TestProcessNewRepo:
|
|||
"action": action,
|
||||
"sls": sls,
|
||||
"monitor": monitor,
|
||||
"upstreamurl": upstreamurl,
|
||||
"exception": exception,
|
||||
}
|
||||
dist_git_url = "https://src.fp.o"
|
||||
|
@ -1268,10 +1203,9 @@ class TestProcessNewRepo:
|
|||
|
||||
@patch("toddlers.plugins.scm_request_processor.bugzilla_system")
|
||||
@patch(
|
||||
"toddlers.plugins.scm_request_processor.SCMRequestProcessor._validate_new_repo_request",
|
||||
return_value=True,
|
||||
"toddlers.plugins.scm_request_processor.SCMRequestProcessor.validate_review_bug"
|
||||
)
|
||||
def test_process_new_repo_project_exists(self, mock_validate_request, mock_bz):
|
||||
def test_process_new_repo_project_exists(self, mock_validate_review_bug, mock_bz):
|
||||
"""
|
||||
Assert that ticket will be processed correctly when repo already
|
||||
exists in dist git.
|
||||
|
@ -1284,7 +1218,7 @@ class TestProcessNewRepo:
|
|||
bug_id = "123"
|
||||
action = "new_repo"
|
||||
sls = {"rawhide": "2050-06-01"}
|
||||
monitor = "no-monitoring"
|
||||
monitor = "monitor"
|
||||
exception = False
|
||||
json = {
|
||||
"repo": repo,
|
||||
|
@ -1295,7 +1229,6 @@ class TestProcessNewRepo:
|
|||
"sls": sls,
|
||||
"monitor": monitor,
|
||||
"exception": exception,
|
||||
"upstreamurl": "",
|
||||
}
|
||||
|
||||
dist_git_url = "https://src.fp.o"
|
||||
|
@ -1337,7 +1270,7 @@ class TestProcessNewRepo:
|
|||
bug_id = "123"
|
||||
action = "new_repo"
|
||||
sls = {branch: "2050-06-01"}
|
||||
monitor = "no-monitoring"
|
||||
monitor = "monitor"
|
||||
exception = False
|
||||
json = {
|
||||
"repo": repo,
|
||||
|
@ -1348,7 +1281,6 @@ class TestProcessNewRepo:
|
|||
"sls": sls,
|
||||
"monitor": monitor,
|
||||
"exception": exception,
|
||||
"upstreamurl": "",
|
||||
}
|
||||
self.toddler.branch_slas = {"rawhide": {"rawhide": "2050-06-01"}}
|
||||
|
||||
|
@ -1390,314 +1322,6 @@ class TestProcessNewRepo:
|
|||
)
|
||||
mock_bz.change_bug_status.assert_called_with(bug_id, "RELEASE_PENDING", message)
|
||||
|
||||
@patch(
|
||||
"toddlers.plugins.scm_request_processor.SCMRequestProcessor._validate_new_repo_request",
|
||||
return_value=True,
|
||||
)
|
||||
def test_process_new_repo_monitoring_project_created_successfully_package_exist(
|
||||
self,
|
||||
mock_validate_request,
|
||||
):
|
||||
"""
|
||||
Assert that ticket will be processed with correct Monitoring message
|
||||
when project and package exists.
|
||||
"""
|
||||
# Preparation
|
||||
user = "zlopez"
|
||||
issue = {
|
||||
"id": 100,
|
||||
"user": {"name": user},
|
||||
}
|
||||
|
||||
repo = "repo"
|
||||
branch = "main"
|
||||
namespace = "tests"
|
||||
bug_id = ""
|
||||
action = "new_repo"
|
||||
sls = {branch: "2050-06-01"}
|
||||
monitor = "monitoring"
|
||||
upstreamurl = ""
|
||||
backend = "custom"
|
||||
distibution = "Fedora"
|
||||
project_name = "test_project"
|
||||
exception = False
|
||||
json = {
|
||||
"repo": repo,
|
||||
"branch": branch,
|
||||
"namespace": namespace,
|
||||
"bug_id": bug_id,
|
||||
"action": action,
|
||||
"sls": sls,
|
||||
"monitor": monitor,
|
||||
"upstreamurl": upstreamurl,
|
||||
"backend": backend,
|
||||
"distribution": distibution,
|
||||
"project_name": project_name,
|
||||
"exception": exception,
|
||||
}
|
||||
dist_git_url = "https://src.fp.o"
|
||||
self.toddler.dist_git._pagure_url = dist_git_url
|
||||
self.toddler.dist_git.get_project.return_value = {"access_users": {"owner": []}}
|
||||
anitya_project_url = "https://release-monitoring.org/project/123"
|
||||
self.toddler.anitya.does_project_exists_in_anitya = Mock(
|
||||
return_value=anitya_project_url
|
||||
)
|
||||
self.toddler.anitya.does_package_exists_in_anitya = Mock(return_value=True)
|
||||
project_msg = (
|
||||
"Anitya project is accessible by this link \n`{0}`\n "
|
||||
"you can modify it manually.".format(anitya_project_url)
|
||||
)
|
||||
|
||||
self.toddler.process_new_repo(issue, json)
|
||||
|
||||
self.toddler.dist_git.set_monitoring_status.assert_called_with(
|
||||
namespace, repo, monitor
|
||||
)
|
||||
monitoring_msg = "\nMonitoring:\n{0}\n".format(project_msg)
|
||||
|
||||
message = "The Pagure repository was created at {0}/{1}/{2}{3}".format(
|
||||
dist_git_url, namespace, repo, monitoring_msg
|
||||
)
|
||||
|
||||
self.toddler.pagure_io.close_issue.assert_called_with(
|
||||
100,
|
||||
namespace=scm_request_processor.PROJECT_NAMESPACE,
|
||||
message=message,
|
||||
reason="Processed",
|
||||
)
|
||||
|
||||
@patch(
|
||||
"toddlers.plugins.scm_request_processor.SCMRequestProcessor._validate_new_repo_request",
|
||||
return_value=True,
|
||||
)
|
||||
def test_process_new_repo_monitoring_project_was_not_created(
|
||||
self,
|
||||
mock_validate_request,
|
||||
):
|
||||
"""
|
||||
Assert that ticket will be processed with correct Monitoring message
|
||||
when project and package exists.
|
||||
"""
|
||||
# Preparation
|
||||
user = "zlopez"
|
||||
issue = {
|
||||
"id": 100,
|
||||
"user": {"name": user},
|
||||
}
|
||||
|
||||
repo = "repo"
|
||||
branch = "main"
|
||||
namespace = "tests"
|
||||
bug_id = ""
|
||||
action = "new_repo"
|
||||
sls = {branch: "2050-06-01"}
|
||||
monitor = "monitoring"
|
||||
upstreamurl = ""
|
||||
backend = "custom"
|
||||
distibution = "Fedora"
|
||||
project_name = "test_project"
|
||||
exception = False
|
||||
json = {
|
||||
"repo": repo,
|
||||
"branch": branch,
|
||||
"namespace": namespace,
|
||||
"bug_id": bug_id,
|
||||
"action": action,
|
||||
"sls": sls,
|
||||
"monitor": monitor,
|
||||
"upstreamurl": upstreamurl,
|
||||
"backend": backend,
|
||||
"distribution": distibution,
|
||||
"project_name": project_name,
|
||||
"exception": exception,
|
||||
}
|
||||
dist_git_url = "https://src.fp.o"
|
||||
self.toddler.dist_git._pagure_url = dist_git_url
|
||||
self.toddler.dist_git.get_project.return_value = {"access_users": {"owner": []}}
|
||||
self.toddler.anitya.does_project_exists_in_anitya = Mock(return_value=None)
|
||||
self.toddler.anitya.create_project_in_anitya = Mock(return_value=None)
|
||||
project_msg = (
|
||||
"Wasn't able to create project in Anitya. "
|
||||
"You can create it manually on: `https://release-monitoring.org`"
|
||||
)
|
||||
|
||||
self.toddler.process_new_repo(issue, json)
|
||||
|
||||
self.toddler.dist_git.set_monitoring_status.assert_called_with(
|
||||
namespace, repo, monitor
|
||||
)
|
||||
monitoring_msg = "\nMonitoring:\n{0}\n".format(project_msg)
|
||||
|
||||
message = "The Pagure repository was created at {0}/{1}/{2}{3}".format(
|
||||
dist_git_url, namespace, repo, monitoring_msg
|
||||
)
|
||||
|
||||
self.toddler.pagure_io.close_issue.assert_called_with(
|
||||
100,
|
||||
namespace=scm_request_processor.PROJECT_NAMESPACE,
|
||||
message=message,
|
||||
reason="Processed",
|
||||
)
|
||||
|
||||
@patch(
|
||||
"toddlers.plugins.scm_request_processor.SCMRequestProcessor._validate_new_repo_request",
|
||||
return_value=True,
|
||||
)
|
||||
def test_process_new_repo_monitoring_creating_package(
|
||||
self,
|
||||
mock_validate_request,
|
||||
):
|
||||
"""
|
||||
Assert that ticket will be processed with correct Monitoring message
|
||||
when project and package exists.
|
||||
"""
|
||||
# Preparation
|
||||
user = "zlopez"
|
||||
issue = {
|
||||
"id": 100,
|
||||
"user": {"name": user},
|
||||
}
|
||||
|
||||
repo = "repo"
|
||||
branch = "main"
|
||||
namespace = "tests"
|
||||
bug_id = ""
|
||||
action = "new_repo"
|
||||
sls = {branch: "2050-06-01"}
|
||||
monitor = "monitoring"
|
||||
upstreamurl = ""
|
||||
backend = "custom"
|
||||
distibution = "Fedora"
|
||||
project_name = "test_project"
|
||||
exception = False
|
||||
json = {
|
||||
"repo": repo,
|
||||
"branch": branch,
|
||||
"namespace": namespace,
|
||||
"bug_id": bug_id,
|
||||
"action": action,
|
||||
"sls": sls,
|
||||
"monitor": monitor,
|
||||
"upstreamurl": upstreamurl,
|
||||
"backend": backend,
|
||||
"distribution": distibution,
|
||||
"project_name": project_name,
|
||||
"exception": exception,
|
||||
}
|
||||
dist_git_url = "https://src.fp.o"
|
||||
self.toddler.dist_git._pagure_url = dist_git_url
|
||||
self.toddler.dist_git.get_project.return_value = {"access_users": {"owner": []}}
|
||||
anitya_project_url = "https://release-monitoring.org/project/123"
|
||||
self.toddler.anitya.does_project_exists_in_anitya = Mock(
|
||||
return_value=anitya_project_url
|
||||
)
|
||||
self.toddler.anitya.does_package_exists_in_anitya = Mock(return_value=False)
|
||||
self.toddler.anitya.create_package_in_anitya = Mock(return_value="Success")
|
||||
project_msg = (
|
||||
"Anitya project is accessible by this link \n`{0}`\n "
|
||||
"you can modify it manually.".format(anitya_project_url)
|
||||
)
|
||||
package_msg = "Package was created in Anitya"
|
||||
|
||||
self.toddler.process_new_repo(issue, json)
|
||||
|
||||
self.toddler.dist_git.set_monitoring_status.assert_called_with(
|
||||
namespace, repo, monitor
|
||||
)
|
||||
monitoring_msg = "\nMonitoring:\n{0}\n{1}".format(project_msg, package_msg)
|
||||
|
||||
message = "The Pagure repository was created at {0}/{1}/{2}{3}".format(
|
||||
dist_git_url, namespace, repo, monitoring_msg
|
||||
)
|
||||
|
||||
self.toddler.pagure_io.close_issue.assert_called_with(
|
||||
100,
|
||||
namespace=scm_request_processor.PROJECT_NAMESPACE,
|
||||
message=message,
|
||||
reason="Processed",
|
||||
)
|
||||
|
||||
@patch(
|
||||
"toddlers.plugins.scm_request_processor.SCMRequestProcessor._validate_new_repo_request",
|
||||
return_value=True,
|
||||
)
|
||||
def test_process_new_repo_monitoring_creating_package_fails(
|
||||
self,
|
||||
mock_validate_request,
|
||||
):
|
||||
"""
|
||||
Assert that ticket will be processed with correct Monitoring message
|
||||
when project and package exists.
|
||||
"""
|
||||
# Preparation
|
||||
user = "zlopez"
|
||||
issue = {
|
||||
"id": 100,
|
||||
"user": {"name": user},
|
||||
}
|
||||
|
||||
repo = "repo"
|
||||
branch = "main"
|
||||
namespace = "tests"
|
||||
bug_id = ""
|
||||
action = "new_repo"
|
||||
sls = {branch: "2050-06-01"}
|
||||
monitor = "monitoring"
|
||||
upstreamurl = ""
|
||||
backend = "custom"
|
||||
distibution = "Fedora"
|
||||
project_name = "test_project"
|
||||
exception = False
|
||||
json = {
|
||||
"repo": repo,
|
||||
"branch": branch,
|
||||
"namespace": namespace,
|
||||
"bug_id": bug_id,
|
||||
"action": action,
|
||||
"sls": sls,
|
||||
"monitor": monitor,
|
||||
"upstreamurl": upstreamurl,
|
||||
"backend": backend,
|
||||
"distribution": distibution,
|
||||
"project_name": project_name,
|
||||
"exception": exception,
|
||||
}
|
||||
dist_git_url = "https://src.fp.o"
|
||||
self.toddler.dist_git._pagure_url = dist_git_url
|
||||
self.toddler.dist_git.get_project.return_value = {"access_users": {"owner": []}}
|
||||
anitya_project_url = "https://release-monitoring.org/project/123"
|
||||
self.toddler.anitya.does_project_exists_in_anitya = Mock(
|
||||
return_value=anitya_project_url
|
||||
)
|
||||
self.toddler.anitya.does_package_exists_in_anitya = Mock(return_value=False)
|
||||
response_msg = "Unauthorized, access token is incorrect."
|
||||
self.toddler.anitya.create_package_in_anitya = Mock(return_value=response_msg)
|
||||
project_msg = (
|
||||
"Anitya project is accessible by this link \n`{0}`\n "
|
||||
"you can modify it manually.".format(anitya_project_url)
|
||||
)
|
||||
package_msg = "Package wasn't created in Anitya, reason: `{0}`.".format(
|
||||
response_msg
|
||||
)
|
||||
|
||||
self.toddler.process_new_repo(issue, json)
|
||||
|
||||
self.toddler.dist_git.set_monitoring_status.assert_called_with(
|
||||
namespace, repo, monitor
|
||||
)
|
||||
monitoring_msg = "\nMonitoring:\n{0}\n{1}".format(project_msg, package_msg)
|
||||
|
||||
message = "The Pagure repository was created at {0}/{1}/{2}{3}".format(
|
||||
dist_git_url, namespace, repo, monitoring_msg
|
||||
)
|
||||
|
||||
self.toddler.pagure_io.close_issue.assert_called_with(
|
||||
100,
|
||||
namespace=scm_request_processor.PROJECT_NAMESPACE,
|
||||
message=message,
|
||||
reason="Processed",
|
||||
)
|
||||
|
||||
@patch("toddlers.plugins.scm_request_processor.bugzilla_system")
|
||||
@patch(
|
||||
"toddlers.plugins.scm_request_processor.SCMRequestProcessor.validate_review_bug"
|
||||
|
@ -1717,8 +1341,7 @@ class TestProcessNewRepo:
|
|||
bug_id = "123"
|
||||
action = "new_repo"
|
||||
sls = {branch: "2050-06-01"}
|
||||
monitor = "no-monitoring"
|
||||
upstreamurl = ""
|
||||
monitor = "monitor"
|
||||
exception = False
|
||||
json = {
|
||||
"repo": repo,
|
||||
|
@ -1728,7 +1351,6 @@ class TestProcessNewRepo:
|
|||
"action": action,
|
||||
"sls": sls,
|
||||
"monitor": monitor,
|
||||
"upstreamurl": upstreamurl,
|
||||
"exception": exception,
|
||||
}
|
||||
self.toddler.branch_slas = {"rawhide": {"rawhide": "2050-06-01"}}
|
||||
|
@ -1789,8 +1411,7 @@ class TestProcessNewRepo:
|
|||
bug_id = "123"
|
||||
action = "new_repo"
|
||||
sls = {branch: "2050-06-01"}
|
||||
monitor = "no-monitoring"
|
||||
upstreamurl = ""
|
||||
monitor = "monitor"
|
||||
exception = False
|
||||
json = {
|
||||
"repo": repo,
|
||||
|
@ -1800,7 +1421,6 @@ class TestProcessNewRepo:
|
|||
"action": action,
|
||||
"sls": sls,
|
||||
"monitor": monitor,
|
||||
"upstreamurl": upstreamurl,
|
||||
"exception": exception,
|
||||
}
|
||||
|
||||
|
@ -1853,7 +1473,7 @@ class TestProcessNewRepo:
|
|||
bug_id = "123"
|
||||
action = "new_repo"
|
||||
sls = {branch: "2050-06-01"}
|
||||
monitor = "no-monitoring"
|
||||
monitor = "monitor"
|
||||
exception = False
|
||||
json = {
|
||||
"repo": repo,
|
||||
|
@ -1863,7 +1483,6 @@ class TestProcessNewRepo:
|
|||
"action": action,
|
||||
"sls": sls,
|
||||
"monitor": monitor,
|
||||
"upstreamurl": "",
|
||||
"exception": exception,
|
||||
}
|
||||
|
||||
|
@ -1923,7 +1542,7 @@ class TestProcessNewRepo:
|
|||
bug_id = "123"
|
||||
action = "new_repo"
|
||||
sls = {branch: "2050-06-01"}
|
||||
monitor = "no-monitoring"
|
||||
monitor = "monitor"
|
||||
exception = False
|
||||
json = {
|
||||
"repo": repo,
|
||||
|
@ -1933,7 +1552,6 @@ class TestProcessNewRepo:
|
|||
"action": action,
|
||||
"sls": sls,
|
||||
"monitor": monitor,
|
||||
"upstreamurl": "",
|
||||
"exception": exception,
|
||||
}
|
||||
|
||||
|
@ -2009,7 +1627,7 @@ class TestProcessNewRepo:
|
|||
bug_id = "123"
|
||||
action = "new_repo"
|
||||
sls = {branch: "2050-06-01"}
|
||||
monitor = "no-monitoring"
|
||||
monitor = "monitor"
|
||||
exception = False
|
||||
json = {
|
||||
"repo": repo,
|
||||
|
@ -2019,7 +1637,6 @@ class TestProcessNewRepo:
|
|||
"action": action,
|
||||
"sls": sls,
|
||||
"monitor": monitor,
|
||||
"upstreamurl": "",
|
||||
"exception": exception,
|
||||
}
|
||||
|
||||
|
@ -2086,7 +1703,7 @@ class TestProcessNewRepo:
|
|||
bug_id = "123"
|
||||
action = "new_repo"
|
||||
sls = {branch: "2050-06-01"}
|
||||
monitor = "no-monitoring"
|
||||
monitor = "monitor"
|
||||
exception = False
|
||||
json = {
|
||||
"repo": repo,
|
||||
|
@ -2096,7 +1713,6 @@ class TestProcessNewRepo:
|
|||
"action": action,
|
||||
"sls": sls,
|
||||
"monitor": monitor,
|
||||
"upstreamurl": "",
|
||||
"exception": exception,
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,410 +0,0 @@
|
|||
"""
|
||||
Unit tests for `toddlers.utils.anitya`.
|
||||
"""
|
||||
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
|
||||
import toddlers.utils.anitya as anitya
|
||||
|
||||
|
||||
class TestAnityaSetAnitya:
|
||||
"""
|
||||
Test class for `toddlers.anitya.set_anitya` function.
|
||||
"""
|
||||
|
||||
def test_set_anitya(self):
|
||||
"""
|
||||
Test initialization of anitya module.
|
||||
"""
|
||||
config = {
|
||||
"anitya_endpoint": "https://release-monitoring.org",
|
||||
"anitya_access_token": "TOKEN",
|
||||
}
|
||||
anitya_obj = anitya.set_anitya(config)
|
||||
|
||||
assert anitya_obj._anitya_endpoint == config.get("anitya_endpoint")
|
||||
assert anitya_obj._anitya_token == config.get("anitya_access_token")
|
||||
assert anitya_obj._requests_session
|
||||
|
||||
def test_set_anitya_no_anitya_url(self):
|
||||
"""
|
||||
Test initialization of anitya module without required config value.
|
||||
"""
|
||||
with pytest.raises(
|
||||
ValueError, match=r"No anitya endpoint found in config file"
|
||||
):
|
||||
anitya.set_anitya({})
|
||||
|
||||
def test_set_anitya_no_anitya_api_key(self):
|
||||
"""
|
||||
Test initialization of anitya module without required config value.
|
||||
"""
|
||||
with pytest.raises(
|
||||
ValueError, match=r"No anitya access token found in config file"
|
||||
):
|
||||
config = {"anitya_endpoint": "https://anitya.io"}
|
||||
anitya.set_anitya(config)
|
||||
|
||||
|
||||
class TestAnityaDoesProjectExistInAnitya:
|
||||
"""
|
||||
Test class for
|
||||
`toddlers.anitya.Anitya.does_project_exists_in_anitya` method.
|
||||
"""
|
||||
|
||||
def setup_method(self):
|
||||
"""
|
||||
Setup method for test class.
|
||||
"""
|
||||
config = {
|
||||
"anitya_endpoint": "https://release-monitoring.org",
|
||||
"anitya_access_token": "TOKEN",
|
||||
}
|
||||
self.anitya_obj = anitya.set_anitya(config)
|
||||
self.anitya_obj._requests_session = Mock()
|
||||
self.anitya_obj.remove_trailing_slashes_from_url = Mock(
|
||||
return_value="https://release-monitoring.org/api/v2/projects/"
|
||||
)
|
||||
|
||||
def test_does_project_exists_in_anitya(self):
|
||||
"""
|
||||
Assert that method will return correct response about project exists in anitya.
|
||||
"""
|
||||
endpoint = "https://release-monitoring.org/api/v2/projects/"
|
||||
project_name = "amedvede_project"
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
"items": [
|
||||
{
|
||||
"id": 123,
|
||||
"name": project_name,
|
||||
}
|
||||
],
|
||||
"total_items": 1,
|
||||
}
|
||||
params = {"name": project_name}
|
||||
self.anitya_obj._requests_session.get.return_value = mock_response
|
||||
|
||||
result = self.anitya_obj.does_project_exists_in_anitya(project_name)
|
||||
|
||||
assert result == "https://release-monitoring.org/project/123"
|
||||
self.anitya_obj._requests_session.get.assert_called_once_with(
|
||||
endpoint, params=params
|
||||
)
|
||||
|
||||
def test_does_project_exists_in_anitya_project_not_found(self):
|
||||
"""
|
||||
Assert that method will return correct response about project does not exist in anitya.
|
||||
"""
|
||||
endpoint = "https://release-monitoring.org/api/v2/projects/"
|
||||
project_name = "amedvede_project"
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 404
|
||||
params = {"name": project_name}
|
||||
self.anitya_obj._requests_session.get.return_value = mock_response
|
||||
|
||||
result = self.anitya_obj.does_project_exists_in_anitya(project_name)
|
||||
|
||||
assert result is None
|
||||
self.anitya_obj._requests_session.get.assert_called_once_with(
|
||||
endpoint, params=params
|
||||
)
|
||||
|
||||
def test_does_project_exists_in_anitya_empty_items(self):
|
||||
"""Assert that method will return correct response about project not found in anitya."""
|
||||
endpoint = "https://release-monitoring.org/api/v2/projects/"
|
||||
project_name = "amedvede_project"
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {"items": [], "total_items": 0}
|
||||
params = {"name": project_name}
|
||||
self.anitya_obj._requests_session.get.return_value = mock_response
|
||||
|
||||
result = self.anitya_obj.does_project_exists_in_anitya(project_name)
|
||||
|
||||
assert result is None
|
||||
self.anitya_obj._requests_session.get.assert_called_once_with(
|
||||
endpoint, params=params
|
||||
)
|
||||
|
||||
def test_does_project_exists_in_anitya_wrong_structure(self):
|
||||
"""
|
||||
Assert that method will return correct response about project has wrong structure in anitya.
|
||||
"""
|
||||
endpoint = "https://release-monitoring.org/api/v2/projects/"
|
||||
project_name = "amedvede_project"
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
"items": [
|
||||
{
|
||||
"wrong": "structure",
|
||||
}
|
||||
],
|
||||
"total_items": 1,
|
||||
}
|
||||
params = {"name": project_name}
|
||||
self.anitya_obj._requests_session.get.return_value = mock_response
|
||||
|
||||
result = self.anitya_obj.does_project_exists_in_anitya(project_name)
|
||||
|
||||
assert result is None
|
||||
self.anitya_obj._requests_session.get.assert_called_once_with(
|
||||
endpoint, params=params
|
||||
)
|
||||
|
||||
|
||||
class TestAnityaDoesPackageExistInAnitya:
|
||||
"""
|
||||
Test class for `toddlers.anitya.Anitya.does_package_exists_in_anitya` method.
|
||||
"""
|
||||
|
||||
def setup_method(self):
|
||||
"""
|
||||
Setup method for test class.
|
||||
"""
|
||||
config = {
|
||||
"anitya_endpoint": "https://release-monitoring.org",
|
||||
"anitya_access_token": "TOKEN",
|
||||
}
|
||||
self.anitya_obj = anitya.set_anitya(config)
|
||||
self.anitya_obj._requests_session = Mock()
|
||||
self.anitya_obj.remove_trailing_slashes_from_url = Mock(
|
||||
return_value="https://release-monitoring.org/api/v2/packages/"
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"project_name, expected_project_name, expected_result",
|
||||
[
|
||||
("nice_project", "nice_project", True),
|
||||
("nice_project", "bad_project", False),
|
||||
],
|
||||
)
|
||||
def test_does_package_exists_in_anitya(
|
||||
self, project_name, expected_project_name, expected_result
|
||||
):
|
||||
"""
|
||||
Assert that method will return correct response about package exists in anitya
|
||||
and his project name is same with expected.
|
||||
"""
|
||||
endpoint = "https://release-monitoring.org/api/v2/packages/"
|
||||
package_name = "amedvede_package"
|
||||
distribution = "Fedora"
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {
|
||||
"items": [
|
||||
{
|
||||
"name": package_name,
|
||||
"project": project_name,
|
||||
}
|
||||
],
|
||||
"total_items": 1,
|
||||
}
|
||||
params = {
|
||||
"name": package_name,
|
||||
"distribution": distribution,
|
||||
}
|
||||
self.anitya_obj._requests_session.get.return_value = mock_response
|
||||
|
||||
result = self.anitya_obj.does_package_exists_in_anitya(
|
||||
package_name, distribution, expected_project_name
|
||||
)
|
||||
|
||||
assert result is expected_result # package and project name the same
|
||||
self.anitya_obj._requests_session.get.assert_called_once_with(
|
||||
endpoint, params=params
|
||||
)
|
||||
|
||||
def test_does_package_exists_in_anitya_not_found(self):
|
||||
"""
|
||||
Assert that method will return correct response when package does not exist in anitya.
|
||||
"""
|
||||
endpoint = "https://release-monitoring.org/api/v2/packages/"
|
||||
package_name = "amedvede_package"
|
||||
project_name = "different name"
|
||||
distribution = "Fedora"
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 202
|
||||
params = {
|
||||
"name": package_name,
|
||||
"distribution": distribution,
|
||||
}
|
||||
self.anitya_obj._requests_session.get.return_value = mock_response
|
||||
|
||||
result = self.anitya_obj.does_package_exists_in_anitya(
|
||||
package_name, distribution, project_name
|
||||
)
|
||||
|
||||
assert result is False # package and project name are different
|
||||
self.anitya_obj._requests_session.get.assert_called_once_with(
|
||||
endpoint, params=params
|
||||
)
|
||||
|
||||
def test_does_package_exists_in_anitya_found_zero_items(self):
|
||||
"""
|
||||
Assert that method will return correct response when response code is correct,
|
||||
but response does not contain items.
|
||||
"""
|
||||
endpoint = "https://release-monitoring.org/api/v2/packages/"
|
||||
package_name = "amedvede_package"
|
||||
project_name = "different name"
|
||||
distribution = "Fedora"
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 200
|
||||
mock_response.json.return_value = {"items": [], "total_items": 0}
|
||||
params = {
|
||||
"name": package_name,
|
||||
"distribution": distribution,
|
||||
}
|
||||
self.anitya_obj._requests_session.get.return_value = mock_response
|
||||
|
||||
result = self.anitya_obj.does_package_exists_in_anitya(
|
||||
package_name, distribution, project_name
|
||||
)
|
||||
|
||||
assert result is False # package and project name are different
|
||||
self.anitya_obj._requests_session.get.assert_called_once_with(
|
||||
endpoint, params=params
|
||||
)
|
||||
|
||||
|
||||
class TestAnityaCreateProjectInAnitya:
|
||||
"""
|
||||
Test class for `toddlers.anitya.Anitya.create_project_in_anitya` method.
|
||||
"""
|
||||
|
||||
def setup_method(self):
|
||||
"""
|
||||
Setup method for test class.
|
||||
"""
|
||||
config = {
|
||||
"anitya_endpoint": "https://release-monitoring.org",
|
||||
"anitya_access_token": "TOKEN",
|
||||
}
|
||||
self.anitya_obj = anitya.set_anitya(config)
|
||||
self.anitya_obj._requests_session = Mock()
|
||||
self.anitya_obj.remove_trailing_slashes_from_url = Mock(
|
||||
return_value="https://release-monitoring.org/api/v2/projects/"
|
||||
)
|
||||
|
||||
def test_create_project_in_anitya_successful_creation(self):
|
||||
"""
|
||||
Assert that method will return correct response when project is created.
|
||||
"""
|
||||
endpoint = "https://release-monitoring.org/api/v2/projects/"
|
||||
project_name = "project"
|
||||
homepage = "https://project.com"
|
||||
backend = "GitHub"
|
||||
test_data = {
|
||||
"name": project_name,
|
||||
"homepage": homepage,
|
||||
"backend": backend,
|
||||
}
|
||||
response_json = {"id": 123}
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 201
|
||||
mock_response.json.return_value = response_json
|
||||
self.anitya_obj._requests_session.post.return_value = mock_response
|
||||
|
||||
result = self.anitya_obj.create_project_in_anitya(
|
||||
project_name, homepage, backend
|
||||
)
|
||||
|
||||
assert result == "https://release-monitoring.org/project/123"
|
||||
self.anitya_obj._requests_session.post.assert_called_once_with(
|
||||
url=endpoint,
|
||||
data=test_data,
|
||||
headers={"Authorization": "token TOKEN"},
|
||||
)
|
||||
|
||||
def test_create_project_in_anitya_fail(self):
|
||||
"""
|
||||
Assert that method will return correct response when project is not created.
|
||||
"""
|
||||
endpoint = "https://release-monitoring.org/api/v2/projects/"
|
||||
project_name = "project"
|
||||
homepage = "https://project.com"
|
||||
backend = "GitHub"
|
||||
test_data = {
|
||||
"name": project_name,
|
||||
"homepage": homepage,
|
||||
"backend": backend,
|
||||
}
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = 400
|
||||
self.anitya_obj._requests_session.post.return_value = mock_response
|
||||
|
||||
result = self.anitya_obj.create_project_in_anitya(
|
||||
project_name, homepage, backend
|
||||
)
|
||||
|
||||
assert result is None
|
||||
self.anitya_obj._requests_session.post.assert_called_once_with(
|
||||
url=endpoint,
|
||||
data=test_data,
|
||||
headers={"Authorization": "token TOKEN"},
|
||||
)
|
||||
|
||||
|
||||
class TestAnityaCreatePackageInAnitya:
|
||||
"""
|
||||
Test class for `toddlers.anitya.Anitya.create_package_in_anitya` method.
|
||||
"""
|
||||
|
||||
def setup_method(self):
|
||||
"""
|
||||
Setup method for test class.
|
||||
"""
|
||||
config = {
|
||||
"anitya_endpoint": "https://release-monitoring.org",
|
||||
"anitya_access_token": "TOKEN",
|
||||
}
|
||||
self.anitya_obj = anitya.set_anitya(config)
|
||||
self.anitya_obj._requests_session = Mock()
|
||||
self.anitya_obj.remove_trailing_slashes_from_url = Mock(
|
||||
return_value="https://release-monitoring.org/api/v2/packages/"
|
||||
)
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"response_code, expected_result",
|
||||
[
|
||||
(201, "Success"),
|
||||
(400, "Bad Request, some necessary arguments were not provided."),
|
||||
(401, "Unauthorized, access token is incorrect."),
|
||||
(409, "Conflict, package already exists."),
|
||||
(404, None),
|
||||
],
|
||||
)
|
||||
def test_create_package_in_anitya(self, response_code, expected_result):
|
||||
"""
|
||||
Assert that method will return correct response when package is created.
|
||||
"""
|
||||
endpoint = "https://release-monitoring.org/api/v2/packages/"
|
||||
package_name = "test_package"
|
||||
project_name = "test_project"
|
||||
distribution = "Fedora"
|
||||
project_ecosystem = "https://project.com"
|
||||
test_data = {
|
||||
"package_name": package_name,
|
||||
"project_name": project_name,
|
||||
"distribution": distribution,
|
||||
"project_ecosystem": project_ecosystem,
|
||||
}
|
||||
mock_response = Mock()
|
||||
mock_response.status_code = response_code
|
||||
self.anitya_obj._requests_session.post.return_value = mock_response
|
||||
|
||||
result = self.anitya_obj.create_package_in_anitya(
|
||||
package_name, project_name, distribution, project_ecosystem
|
||||
)
|
||||
|
||||
assert result == expected_result
|
||||
self.anitya_obj._requests_session.post.assert_called_once_with(
|
||||
url=endpoint,
|
||||
data=test_data,
|
||||
headers={"Authorization": "token TOKEN"},
|
||||
)
|
|
@ -2,7 +2,7 @@
|
|||
Unit tests for `toddlers.utils.git`.
|
||||
"""
|
||||
|
||||
from unittest.mock import MagicMock, Mock, patch
|
||||
from unittest.mock import call, MagicMock, Mock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
|
@ -290,28 +290,24 @@ class TestGitRepoRevertLastCommit:
|
|||
Assert that revert last commit process correctly.
|
||||
"""
|
||||
mock_origin = MagicMock()
|
||||
mock_origin.url = "https://example.com"
|
||||
self.repo.repo.remote.return_value = mock_origin
|
||||
mock_git_cmd = MagicMock()
|
||||
self.repo.repo.git = mock_git_cmd
|
||||
|
||||
self.repo.revert_last_commit("Revert message", "bot", "token", "feature_branch")
|
||||
self.repo.revert_last_commit("Revert message", "feature_branch")
|
||||
self.repo.repo.git.checkout.assert_called_once_with("feature_branch")
|
||||
self.repo.repo.git.revert.assert_called_once_with("HEAD", no_edit=True)
|
||||
self.repo.repo.git.commit.assert_called_once_with(
|
||||
"--amend", "-m", "Revert message"
|
||||
)
|
||||
|
||||
mock_git_cmd.push.assert_called_once_with(
|
||||
"-u", "https://bot:token@example.com", "feature_branch"
|
||||
self.repo.repo.git.execute.assert_has_calls(
|
||||
[
|
||||
call(["git", "revert", "--no-edit", "HEAD"]),
|
||||
call(["git", "commit", "--amend", "-m", "Revert message"]),
|
||||
]
|
||||
)
|
||||
mock_origin.push.assert_called_once()
|
||||
|
||||
def test_revert_last_commit_revert_exception(self):
|
||||
mock_origin = MagicMock()
|
||||
self.repo.repo.remote.return_value = mock_origin
|
||||
self.repo.repo.git.revert.side_effect = Exception("Revert error")
|
||||
self.repo.repo.git.execute.side_effect = Exception("Revert error")
|
||||
|
||||
self.repo.revert_last_commit("Revert message", "bot", "token", "feature_branch")
|
||||
self.repo.revert_last_commit("Revert message", "feature_branch")
|
||||
mock_origin.push.assert_not_called()
|
||||
|
||||
|
||||
|
|
|
@ -253,9 +253,6 @@ monitor_choices = ['no-monitoring', 'monitoring', 'monitoring-with-scratch']
|
|||
ping_comment = "This request wants to skip bugzilla validation! {maintainers} could you check if this is correct? If yes, please respond to this ticket with 'valid' comment"
|
||||
# This is a OIDC token that allows pagure_user to push changes to dist git
|
||||
oidc_distgit_token = "OIDC token used to push git changes using pagure_user"
|
||||
# Anitya access token and endpoint for managing project in release-monitoring
|
||||
anitya_access_token = "API token for Anitya"
|
||||
anitya_endpoint = "https://release-monitoring.org"
|
||||
|
||||
|
||||
# Pagure mapping to bugzilla
|
||||
|
|
|
@ -24,14 +24,7 @@ import tomllib
|
|||
|
||||
from toddlers.base import ToddlerBase
|
||||
from toddlers.exceptions import ValidationError
|
||||
from toddlers.utils import (
|
||||
anitya,
|
||||
bugzilla_system,
|
||||
fedora_account,
|
||||
git,
|
||||
pagure,
|
||||
requests,
|
||||
)
|
||||
from toddlers.utils import bugzilla_system, fedora_account, git, pagure, requests
|
||||
|
||||
# Regex for branch name validation
|
||||
STREAM_NAME_REGEX = r"^[a-zA-Z0-9.\-_+]+$"
|
||||
|
@ -107,9 +100,6 @@ class SCMRequestProcessor(ToddlerBase):
|
|||
# for toddler
|
||||
pagure_user: str = ""
|
||||
|
||||
# Anitya object to work with Anitya
|
||||
anitya: anitya.Anitya
|
||||
|
||||
def accepts_topic(self, topic: str) -> bool:
|
||||
"""Returns a boolean whether this toddler is interested in messages
|
||||
from this specific topic.
|
||||
|
@ -197,9 +187,6 @@ class SCMRequestProcessor(ToddlerBase):
|
|||
_log.info("Setting up connection to Bugzilla")
|
||||
bugzilla_system.set_bz(config)
|
||||
|
||||
_log.info("Setting up connection to Anitya")
|
||||
self.anitya = anitya.set_anitya(config)
|
||||
|
||||
try:
|
||||
if message.topic.endswith("pagure.issue.comment.added"):
|
||||
self.process_comment(issue)
|
||||
|
@ -463,12 +450,6 @@ class SCMRequestProcessor(ToddlerBase):
|
|||
"namespace",
|
||||
"sls",
|
||||
"monitor",
|
||||
"upstreamurl",
|
||||
]
|
||||
required_keys_for_monitor = [
|
||||
"backend",
|
||||
"project_name",
|
||||
"distribution",
|
||||
]
|
||||
for key in required_keys:
|
||||
if key not in issue_body_json.keys():
|
||||
|
@ -480,18 +461,6 @@ class SCMRequestProcessor(ToddlerBase):
|
|||
)
|
||||
return
|
||||
|
||||
monitor = issue_body_json.get("monitor", "").strip()
|
||||
if monitor != "no-monitoring":
|
||||
for key in required_keys_for_monitor:
|
||||
if key not in issue_body_json.keys():
|
||||
self.pagure_io.close_issue(
|
||||
issue["id"],
|
||||
namespace=PROJECT_NAMESPACE,
|
||||
message="Invalid body, missing required field: {}".format(key),
|
||||
reason="Invalid",
|
||||
)
|
||||
return
|
||||
|
||||
# Validate the request first
|
||||
if self._validate_new_repo_request(issue, issue_body_json):
|
||||
_log.info("Ticket passed all validations. Creating repository.")
|
||||
|
@ -667,7 +636,6 @@ class SCMRequestProcessor(ToddlerBase):
|
|||
branch_name = issue_body_json.get("branch", "").strip()
|
||||
description = issue_body_json.get("description", "").strip()
|
||||
upstreamurl = issue_body_json.get("upstreamurl", "").strip()
|
||||
monitor = issue_body_json.get("monitor", "").strip()
|
||||
|
||||
if namespace in ["rpms", "container"]:
|
||||
default_branch = "rawhide"
|
||||
|
@ -768,50 +736,6 @@ class SCMRequestProcessor(ToddlerBase):
|
|||
'You may commit to the branch "{1}" in about '
|
||||
"10 minutes.".format(dist_git_url, branch_name)
|
||||
)
|
||||
|
||||
if monitor != "no-monitoring":
|
||||
_log.info("- Checking if project {0} exists in Anitya".format(repo))
|
||||
backend = issue_body_json["backend"].strip()
|
||||
distribution = issue_body_json["distribution"].strip()
|
||||
project_name = issue_body_json["project_name"].strip()
|
||||
|
||||
monitoring_message = ""
|
||||
project_msg = ""
|
||||
package_msg = ""
|
||||
anitya_project_url = self.anitya.does_project_exists_in_anitya(project_name)
|
||||
if anitya_project_url is None:
|
||||
anitya_project_url = self.anitya.create_project_in_anitya(
|
||||
repo, upstreamurl, backend
|
||||
)
|
||||
if anitya_project_url is None:
|
||||
project_msg = (
|
||||
"Wasn't able to create project in Anitya. "
|
||||
"You can create it manually on: `https://release-monitoring.org`"
|
||||
)
|
||||
else:
|
||||
project_msg = (
|
||||
"Anitya project is accessible by this link \n`{0}`\n "
|
||||
"you can modify it manually."
|
||||
).format(anitya_project_url)
|
||||
package_exists = self.anitya.does_package_exists_in_anitya(
|
||||
repo, project_name, distribution
|
||||
)
|
||||
if not package_exists:
|
||||
response_msg = self.anitya.create_package_in_anitya(
|
||||
repo, project_name, distribution, upstreamurl
|
||||
)
|
||||
if response_msg != "Success":
|
||||
package_msg = (
|
||||
"Package wasn't created in Anitya, reason: `{0}`.".format(
|
||||
response_msg
|
||||
)
|
||||
)
|
||||
else:
|
||||
package_msg = "Package was created in Anitya"
|
||||
|
||||
monitoring_message = project_msg + "\n" + package_msg
|
||||
new_repo_comment = new_repo_comment + "\nMonitoring:\n" + monitoring_message
|
||||
|
||||
self.pagure_io.close_issue(
|
||||
issue["id"],
|
||||
namespace=PROJECT_NAMESPACE,
|
||||
|
|
|
@ -1,581 +0,0 @@
|
|||
"""
|
||||
This is a script to automate unretirement of package automatically, when ticket is created.
|
||||
|
||||
Authors: Anton Medvedev <amedvede@redhat.com>
|
||||
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
import sys
|
||||
import tempfile
|
||||
import traceback
|
||||
from typing import Optional
|
||||
|
||||
import arrow
|
||||
from fedora_messaging.api import Message
|
||||
from git import GitCommandError
|
||||
import koji
|
||||
from pagure_messages.issue_schema import IssueNewV1
|
||||
import tomllib
|
||||
|
||||
from toddlers.base import ToddlerBase
|
||||
from toddlers.exceptions import ValidationError
|
||||
from toddlers.utils import bodhi, bugzilla_system, git, pagure, requests
|
||||
|
||||
|
||||
# Where to look for unretire request tickets
|
||||
PROJECT_NAMESPACE = "releng/fedora-scm-requests"
|
||||
# Keyword that will be searched for in the issue title
|
||||
UNRETIRE_KEYWORD = "unretire"
|
||||
# RPM package prefix, that will be searched in the issue title
|
||||
RPM_PREFIX = "rpms/"
|
||||
# Forbidden keywords for commit message
|
||||
FORBIDDEN_KEYWORDS_FOR_COMMIT_MESSAGE = ["legal", "license"]
|
||||
# Time difference limit not getting Bugzilla url
|
||||
TIME_DIFFERENCE_LIMIT = 56 # 8 weeks in days
|
||||
# Package retirement process url
|
||||
PACKAGE_RETIREMENT_PROCESS_URL = (
|
||||
"https://docs.fedoraproject.org/en-US/package-maintainers"
|
||||
"/Package_Retirement_Process/#claiming"
|
||||
)
|
||||
# Fedora review bugzilla flag
|
||||
FEDORA_REVIEW_FLAG_NAME = "fedora-review"
|
||||
# Koji hub url
|
||||
KOJIHUB_URL = "https://koji.fedoraproject.org/kojihub"
|
||||
|
||||
_log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class UnretirePackages(ToddlerBase):
|
||||
"""
|
||||
Listen for new tickets in https://pagure.io/releng/fedora-scm-requests/issues
|
||||
and process then, either by unretiring a package or rejecting the ticket
|
||||
"""
|
||||
|
||||
name: str = "unretire_packages"
|
||||
|
||||
amqp_topics: list = ["io.pagure.*.pagure.issue.new"]
|
||||
|
||||
# Path to temporary dir
|
||||
temp_dir: str = ""
|
||||
|
||||
# Requests session
|
||||
requests_session: requests.requests.Session
|
||||
|
||||
# Dist-git base url
|
||||
dist_git_base: Optional[str] = ""
|
||||
|
||||
# Pagure object connected to pagure.io
|
||||
pagure_io: pagure.Pagure
|
||||
|
||||
# Pagure user that will be creating the comments on pagure
|
||||
# for toddler
|
||||
pagure_user: str = ""
|
||||
|
||||
# Git repo object
|
||||
git_repo: git.GitRepo
|
||||
|
||||
# Koji session object
|
||||
koji_session: koji.ClientSession
|
||||
|
||||
# Bodhi object
|
||||
bodhi: bodhi.Bodhi
|
||||
|
||||
# OIDC distgit token
|
||||
oidc_distgit_token: str
|
||||
|
||||
def accepts_topic(self, topic: str) -> bool:
|
||||
"""
|
||||
Returns a boolean whether this toddler is interested in messages
|
||||
from this specific topic.
|
||||
|
||||
:arg topic: Topic to check
|
||||
|
||||
:returns: True if topic is accepted, False otherwise
|
||||
"""
|
||||
if topic.startswith("io.pagure."):
|
||||
if topic.endswith("pagure.issue.new"):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def process(
|
||||
self,
|
||||
config: dict,
|
||||
message: Message,
|
||||
) -> None:
|
||||
"""
|
||||
Process a given message.
|
||||
|
||||
:arg config: Toddlers configuration
|
||||
:arg message: Message to process
|
||||
"""
|
||||
_log.debug(
|
||||
"Processing message:\n{0}".format(json.dumps(message.body, indent=2))
|
||||
)
|
||||
project_name = message.body["project"]["fullname"]
|
||||
|
||||
if project_name != PROJECT_NAMESPACE:
|
||||
_log.info(
|
||||
"The message doesn't belong to project {0}. Skipping message.".format(
|
||||
PROJECT_NAMESPACE
|
||||
)
|
||||
)
|
||||
return
|
||||
|
||||
issue = message.body["issue"]
|
||||
|
||||
if issue["status"] != "Open":
|
||||
_log.info(
|
||||
"The issue {0} is not open. Skipping message.".format(issue["id"])
|
||||
)
|
||||
return
|
||||
|
||||
issue_title = issue["title"]
|
||||
words_in_issue_title = issue_title.split()
|
||||
if UNRETIRE_KEYWORD != words_in_issue_title[0].lower():
|
||||
_log.info(
|
||||
"The issue doesn't contain keyword '{0}' in the title '{1}'"
|
||||
"".format(UNRETIRE_KEYWORD, issue_title)
|
||||
)
|
||||
return
|
||||
|
||||
_log.debug("Getting temp_folder name from config.")
|
||||
self.temp_dir = config.get("temp_folder", "")
|
||||
|
||||
_log.debug("Creating a request session.")
|
||||
self.requests_session = requests.make_session()
|
||||
|
||||
_log.debug("Getting dist-git url from config.")
|
||||
self.dist_git_base = config.get("dist_git_url")
|
||||
|
||||
_log.debug("Setting up connection to Pagure")
|
||||
self.pagure_io = pagure.set_pagure(config)
|
||||
self.pagure_user = config.get("pagure_user", "")
|
||||
|
||||
_log.debug("Setting up connection to Bugzilla")
|
||||
bugzilla_system.set_bz(config)
|
||||
|
||||
_log.debug("Setting up session with Koji")
|
||||
self.koji_session = koji.ClientSession(KOJIHUB_URL)
|
||||
|
||||
_log.debug("Setting up bodhi session")
|
||||
self.bodhi = bodhi.set_bodhi(config)
|
||||
|
||||
_log.debug("Getting OIDC distgit token from config.")
|
||||
self.oidc_distgit_token = config.get("oidc_distgit_token", "")
|
||||
|
||||
try:
|
||||
self.process_ticket(issue)
|
||||
except BaseException:
|
||||
self.pagure_io.add_comment_to_issue(
|
||||
issue["id"],
|
||||
namespace=PROJECT_NAMESPACE,
|
||||
comment=(
|
||||
"Error happened during processing:\n" "```\n" "{0}\n" "```\n"
|
||||
).format(traceback.format_exc()),
|
||||
)
|
||||
|
||||
def process_ticket(self, issue: dict) -> None:
|
||||
"""
|
||||
Process a single ticket
|
||||
|
||||
:arg issue: A dictionary containing the issue
|
||||
"""
|
||||
_log.info("Handling pagure releng ticket '{0}'".format(issue["full_url"]))
|
||||
try:
|
||||
# If a ValueError is raised, that means it isn't valid JSON
|
||||
issue_body = json.loads(issue["content"].strip("`").strip("\n"))
|
||||
except ValueError:
|
||||
_log.info("Invalid JSON in ticket. Closing '{0}'".format(issue["full_url"]))
|
||||
self.pagure_io.close_issue(
|
||||
issue["id"],
|
||||
namespace=PROJECT_NAMESPACE,
|
||||
message="Invalid JSON provided",
|
||||
reason="Invalid",
|
||||
)
|
||||
return
|
||||
|
||||
package_name = issue_body["name"]
|
||||
package_ns = issue_body["type"]
|
||||
maintainer_fas = issue_body["maintainer"]
|
||||
|
||||
package_ns = self._ns_convertor(package_ns)
|
||||
|
||||
package_url = "{0}/{1}/{2}.git".format(
|
||||
self.dist_git_base, package_ns, package_name
|
||||
)
|
||||
|
||||
_log.debug("Verifying that package repository actually exist.")
|
||||
if not self._does_url_exist(package_url):
|
||||
msg = "Package repository doesnt exist. Try to repeat request."
|
||||
_log.info(msg)
|
||||
self.pagure_io.close_issue(
|
||||
issue["id"],
|
||||
namespace=PROJECT_NAMESPACE,
|
||||
message=msg,
|
||||
reason="Invalid",
|
||||
)
|
||||
return
|
||||
|
||||
_log.debug("Creating temporary directory")
|
||||
with tempfile.TemporaryDirectory(dir=self.temp_dir) as tmp_dir:
|
||||
_log.info("Cloning repo into dir with name '{0}'".format(self.temp_dir))
|
||||
try:
|
||||
self.git_repo = git.clone_repo(package_url, tmp_dir)
|
||||
except GitCommandError:
|
||||
message = "Something went wrong during cloning git repository."
|
||||
_log.info(message)
|
||||
self.pagure_io.close_issue(
|
||||
issue["id"],
|
||||
namespace=PROJECT_NAMESPACE,
|
||||
message=message,
|
||||
reason="Invalid",
|
||||
)
|
||||
return
|
||||
|
||||
branches = issue_body["branches"]
|
||||
|
||||
_log.debug("Getting active branches")
|
||||
active_branches = self.bodhi.get_active_branches()
|
||||
|
||||
filtered_branches = [
|
||||
branch for branch in branches if branch in active_branches
|
||||
]
|
||||
|
||||
final_list_of_branches = []
|
||||
deadpackage_file_path = "dead.package"
|
||||
_log.debug("Verifying that branches are actually exists.")
|
||||
_log.debug(
|
||||
"Verifying that branches are actually retired (have a `dead.package` file)."
|
||||
)
|
||||
for branch in filtered_branches:
|
||||
if self.git_repo.does_branch_exist(branch):
|
||||
if self.git_repo.does_branch_contains_file(
|
||||
branch, deadpackage_file_path
|
||||
):
|
||||
final_list_of_branches.append(branch)
|
||||
|
||||
_log.debug("Verifying if package is ready for unretirement.")
|
||||
if not self._is_package_ready_for_unretirement(
|
||||
issue_id=issue["id"],
|
||||
branches=final_list_of_branches,
|
||||
review_bugzilla=issue_body["review_bugzilla"],
|
||||
):
|
||||
return
|
||||
|
||||
_log.debug("Reverting retire commit")
|
||||
revert_commit_message = "Unretirement request: {0}".format(
|
||||
issue["full_url"]
|
||||
)
|
||||
for branch in final_list_of_branches:
|
||||
self.git_repo.revert_last_commit(
|
||||
message=revert_commit_message,
|
||||
user=self.pagure_user,
|
||||
token=self.oidc_distgit_token,
|
||||
branch=branch,
|
||||
)
|
||||
|
||||
_log.debug("Unblocking tags on Koji.")
|
||||
if self._check_tags_to_unblock(final_list_of_branches, package_name):
|
||||
_log.debug("Unblocking tags in koji.")
|
||||
for tag in final_list_of_branches:
|
||||
try:
|
||||
self.koji_session.packageListUnblock(
|
||||
taginfo=tag, pkginfo=package_name
|
||||
)
|
||||
except koji.GenericError:
|
||||
msg = "Not able to unblock `{0}` tag on koji.".format(tag)
|
||||
self.pagure_io.close_issue(
|
||||
issue_id=issue["id"],
|
||||
namespace=PROJECT_NAMESPACE,
|
||||
message=msg,
|
||||
reason="Invalid",
|
||||
)
|
||||
return
|
||||
|
||||
_log.debug("Verifying package is not orphan.")
|
||||
if self.pagure_io.is_project_orphaned(
|
||||
namespace=package_ns, repo=package_name
|
||||
):
|
||||
if maintainer_fas == "":
|
||||
msg = "Package is ophaned, but maintainer fas is not provided."
|
||||
self.pagure_io.close_issue(
|
||||
issue_id=issue["id"],
|
||||
namespace=PROJECT_NAMESPACE,
|
||||
message=msg,
|
||||
reason="Invalid",
|
||||
)
|
||||
return
|
||||
self.pagure_io.assign_maintainer_to_project(
|
||||
namespace=package_ns,
|
||||
repo=package_name,
|
||||
maintainer_fas=maintainer_fas,
|
||||
)
|
||||
|
||||
_log.info(
|
||||
"Package {0} is assigned to {1}".format(
|
||||
f"{package_ns}/{package_name}", maintainer_fas
|
||||
)
|
||||
)
|
||||
return
|
||||
|
||||
def _is_package_ready_for_unretirement(
|
||||
self, issue_id: int, branches: list, review_bugzilla: str
|
||||
) -> bool:
|
||||
"""
|
||||
Verify that package is ready for unretirement.
|
||||
|
||||
:arg issue_id: An int value of issue ID.
|
||||
:arg branches: A list containing branches that need to be unretired.
|
||||
:arg review_bugzilla: A str contain url on bugzilla review.
|
||||
|
||||
:returns: Bool value whether the package was verified.
|
||||
"""
|
||||
try:
|
||||
_log.debug("Verifying the reason of retirement.")
|
||||
self._verify_package_not_retired_for_reason(branches=branches)
|
||||
_log.debug("Verifying the date of retirement.")
|
||||
self._verify_bugzilla_ticket(
|
||||
review_bugzilla=review_bugzilla, branches=branches
|
||||
)
|
||||
except ValidationError as error:
|
||||
self.pagure_io.close_issue(
|
||||
issue_id=issue_id,
|
||||
namespace=PROJECT_NAMESPACE,
|
||||
message=str(error),
|
||||
reason="Invalid",
|
||||
)
|
||||
return False
|
||||
return True
|
||||
|
||||
def _verify_package_not_retired_for_reason(self, branches: list):
|
||||
"""
|
||||
Verify that commit message does not contain forbidden keywords.
|
||||
|
||||
Raises:
|
||||
`toddler.exceptions.ValidationError`: When retirement reason wasn't verified
|
||||
"""
|
||||
_log.debug("Verifying that issue message doesn't contain forbidden keywords")
|
||||
|
||||
for branch in branches:
|
||||
last_commit_message = self.git_repo.get_last_commit_message(branch)
|
||||
if any(
|
||||
re.search(forbidden_keyword, str(last_commit_message).lower())
|
||||
for forbidden_keyword in FORBIDDEN_KEYWORDS_FOR_COMMIT_MESSAGE
|
||||
):
|
||||
raise ValidationError(
|
||||
"Package was retired for a reason: legal or license issue."
|
||||
)
|
||||
|
||||
def _verify_bugzilla_ticket(self, review_bugzilla, branches):
|
||||
"""
|
||||
Verify if last commit was made more than 8 weeks ago, need to request a bugzilla ticket.
|
||||
"""
|
||||
_log.debug("Verifying that retire commit was made less than 8 weeks ago.")
|
||||
|
||||
is_need_to_verify_bz = False
|
||||
|
||||
for branch in branches:
|
||||
last_commit_date = self.git_repo.get_last_commit_date(branch)
|
||||
if last_commit_date is None:
|
||||
raise ValidationError("Couldn't get a date of the retire commit.")
|
||||
else:
|
||||
last_commit_date = arrow.get(last_commit_date)
|
||||
|
||||
current_time = arrow.utcnow()
|
||||
|
||||
time_diff_in_days = (current_time - last_commit_date).days
|
||||
|
||||
if time_diff_in_days > TIME_DIFFERENCE_LIMIT:
|
||||
is_need_to_verify_bz = True
|
||||
|
||||
if not is_need_to_verify_bz:
|
||||
return
|
||||
|
||||
if review_bugzilla == "":
|
||||
raise ValidationError(
|
||||
"Bugzilla url is missing, please add it and recreate the ticket."
|
||||
)
|
||||
|
||||
bug_id = review_bugzilla
|
||||
|
||||
_log.debug("Getting the bug object from bugzilla.")
|
||||
try:
|
||||
bug = bugzilla_system.get_bug(bug_id)
|
||||
except Exception as error:
|
||||
raise ValidationError(
|
||||
"The Bugzilla bug could not be verified. The following "
|
||||
"error was encountered: {0}".format(str(error))
|
||||
)
|
||||
|
||||
if bug is None:
|
||||
raise ValidationError(
|
||||
"Bugzilla can't get the bug by bug id, fix bugzilla url."
|
||||
)
|
||||
|
||||
if bug.product != "Fedora":
|
||||
raise ValidationError(
|
||||
"The bugzilla bug is for '{0}', "
|
||||
"but request should be for 'Fedora'.".format(bug.product)
|
||||
)
|
||||
|
||||
try:
|
||||
_log.info("Getting {0} flag from bug".format(FEDORA_REVIEW_FLAG_NAME))
|
||||
fedora_review_flag = bug.get_flags(FEDORA_REVIEW_FLAG_NAME)
|
||||
fedora_review_flag_status = fedora_review_flag[0]["status"]
|
||||
|
||||
if fedora_review_flag_status != "+":
|
||||
raise ValidationError(
|
||||
"Flag fedora-review has wrong status, need to be +"
|
||||
)
|
||||
except TypeError:
|
||||
raise ValidationError(
|
||||
"Tag fedora-review is missing on bugzilla, get it and recreate the ticket."
|
||||
)
|
||||
|
||||
def _check_tags_to_unblock(self, tags_to_unblock: list, repo: str) -> bool:
|
||||
"""
|
||||
Check if at least one of the tags requested to be unblocked are really blocked.
|
||||
|
||||
:arg tags_to_unblock: List of branch names
|
||||
:arg repo: Name of package
|
||||
|
||||
:returns: Bool value whether program need to unblock tags
|
||||
"""
|
||||
_log.debug("Verifying that tags are blocked on koji.")
|
||||
try:
|
||||
package_tags = self.koji_session.listTags(package=repo)
|
||||
if not package_tags:
|
||||
raise ValidationError("Package doesn't have tags on koji.")
|
||||
tags_that_suppose_to_be_blocked = []
|
||||
|
||||
for tag in package_tags:
|
||||
prefix = "dist-"
|
||||
if tag["name"].startswith(prefix):
|
||||
tag_name = tag["name"][len(prefix) :] # noqa: E203
|
||||
if tag_name in tags_to_unblock:
|
||||
tags_that_suppose_to_be_blocked.append(tag)
|
||||
|
||||
if len(tags_that_suppose_to_be_blocked) == 0:
|
||||
raise ValidationError(
|
||||
"Request to unblock tags that don't exist on koji."
|
||||
)
|
||||
return any([tag["locked"] for tag in tags_that_suppose_to_be_blocked])
|
||||
except koji.GenericError:
|
||||
raise ValidationError("Package doesn't exist on koji.")
|
||||
|
||||
def _does_url_exist(self, url: str) -> bool:
|
||||
"""
|
||||
Check whether url exist.
|
||||
|
||||
:arg url: Url that might exist
|
||||
|
||||
:returns: True if url exist, otherwise False
|
||||
"""
|
||||
try:
|
||||
response = self.requests_session.get(url)
|
||||
except ConnectionError:
|
||||
return False
|
||||
return response.status_code == 200
|
||||
|
||||
@staticmethod
|
||||
def _ns_convertor(namespace):
|
||||
ns_mapping = {
|
||||
"rpm": "rpms",
|
||||
"test": "tests",
|
||||
"flatpak": "flatpaks",
|
||||
"module": "modules",
|
||||
}
|
||||
namespace = ns_mapping[namespace] if namespace in ns_mapping else namespace
|
||||
return namespace
|
||||
|
||||
|
||||
def _get_arguments(args):
|
||||
"""Load and parse the CLI arguments.
|
||||
|
||||
:arg args: Script arguments
|
||||
|
||||
:returns: Parsed arguments
|
||||
"""
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Processor for Unretire packages, handling tickets from '{}'".format(
|
||||
PROJECT_NAMESPACE
|
||||
)
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"ticket",
|
||||
type=int,
|
||||
help="Number of ticket to process",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--config",
|
||||
help="Configuration file",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--debug",
|
||||
action="store_const",
|
||||
dest="log_level",
|
||||
const=logging.DEBUG,
|
||||
default=logging.INFO,
|
||||
help="Enable debugging output",
|
||||
)
|
||||
return parser.parse_args(args)
|
||||
|
||||
|
||||
def _setup_logging(log_level: int) -> None:
|
||||
"""
|
||||
Set up the logging level.
|
||||
|
||||
:arg log_level: Log level to set
|
||||
"""
|
||||
handlers = []
|
||||
|
||||
_log.setLevel(log_level)
|
||||
# We want all messages logged at level INFO or lower to be printed to stdout
|
||||
info_handler = logging.StreamHandler(stream=sys.stdout)
|
||||
handlers.append(info_handler)
|
||||
|
||||
if log_level == logging.INFO:
|
||||
# In normal operation, don't decorate messages
|
||||
for handler in handlers:
|
||||
handler.setFormatter(logging.Formatter("%(message)s"))
|
||||
|
||||
logging.basicConfig(level=log_level, handlers=handlers)
|
||||
|
||||
|
||||
def main(args):
|
||||
"""Main function"""
|
||||
args = _get_arguments(args)
|
||||
_setup_logging(log_level=args.log_level)
|
||||
_log.info("hello i'm starting work")
|
||||
|
||||
config = tomllib.load(args.config)
|
||||
|
||||
ticket = args.ticket
|
||||
|
||||
pagure_io = pagure.set_pagure(config)
|
||||
issue = pagure_io.get_issue(ticket, PROJECT_NAMESPACE)
|
||||
|
||||
# Convert issue to message
|
||||
body = {"project": {"fullname": PROJECT_NAMESPACE}, "issue": issue}
|
||||
message = IssueNewV1(body=body)
|
||||
_log.debug("Message prepared: {}".format(message.body))
|
||||
|
||||
UnretirePackages().process(
|
||||
config=config,
|
||||
message=message,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__": # pragma: no cover
|
||||
try:
|
||||
main(sys.argv[1:])
|
||||
except KeyboardInterrupt:
|
||||
pass
|
|
@ -1,212 +0,0 @@
|
|||
"""
|
||||
This module is a wrapper for Anitya. It uses Anitya API to communicate and configure
|
||||
release monitoring instance.
|
||||
To work with it, you need to set it up by calling `set_anitya`.
|
||||
|
||||
Examples:
|
||||
from utils import anitya
|
||||
|
||||
anitya_config = {
|
||||
"anitya_endpoint": "https://release-monitoring.org/",
|
||||
"anitya_access_token": "secret TOKEN",
|
||||
}
|
||||
|
||||
anitya_obj = anitya.set_anitya(config)
|
||||
anitya_obj.create_project_in_anitya("<name>", "<homepage>", "<backend>")
|
||||
"""
|
||||
|
||||
import logging
|
||||
from typing import Optional
|
||||
|
||||
from toddlers.utils import requests
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def set_anitya(config):
|
||||
"""
|
||||
Set the connection to the Anitya API.
|
||||
|
||||
Params:
|
||||
config: Configuration dictionary.
|
||||
"""
|
||||
return Anitya(config)
|
||||
|
||||
|
||||
class Anitya(object):
|
||||
"""
|
||||
Object that works with Anitya.
|
||||
"""
|
||||
|
||||
# URL to Anitya
|
||||
_anitya_endpoint: str = ""
|
||||
# API TOKEN to Anitya
|
||||
_anitya_access_token: Optional[str] = None
|
||||
# Request Session object used for communication
|
||||
_requests_session: requests.requests.Session
|
||||
|
||||
def __init__(self, config):
|
||||
"""
|
||||
Initialize the Anitya class.
|
||||
|
||||
Params:
|
||||
config (dict): A configuration with anitya_endpoint and anitya_access_token keys.
|
||||
|
||||
Raises:
|
||||
ValueError: If no pagure_api_key is provided.
|
||||
"""
|
||||
self._anitya_endpoint = config.get("anitya_endpoint", "").removesuffix("/")
|
||||
if not self._anitya_endpoint:
|
||||
raise ValueError("No anitya endpoint found in config file")
|
||||
|
||||
self._anitya_token = config.get("anitya_access_token", "")
|
||||
if not self._anitya_token:
|
||||
raise ValueError("No anitya access token found in config file")
|
||||
|
||||
self._requests_session = requests.make_session(timeout=300)
|
||||
|
||||
def does_project_exists_in_anitya(self, project_name: str) -> Optional[str]:
|
||||
"""
|
||||
Check if project exists in Anitya.
|
||||
|
||||
Params:
|
||||
project_name (str): The name of the project.
|
||||
|
||||
Returns:
|
||||
Optional[str]: project URL if it exists in Anitya, otherwise None.
|
||||
"""
|
||||
projects_params = {
|
||||
"name": project_name,
|
||||
}
|
||||
endpoint = self._anitya_endpoint + "/api/v2/projects/"
|
||||
projects_response = self._requests_session.get(endpoint, params=projects_params)
|
||||
if projects_response.status_code != 200:
|
||||
log.debug("Project '{0}' not found in Anitya.".format(project_name))
|
||||
return None
|
||||
|
||||
response_json = projects_response.json()
|
||||
item_count = response_json["total_items"]
|
||||
if item_count == 0:
|
||||
log.debug("Project '{0}' not found in Anitya.".format(project_name))
|
||||
return None
|
||||
|
||||
try:
|
||||
project_id = response_json["items"][0]["id"]
|
||||
project_url = "{0}/project/{1}".format(self._anitya_endpoint, project_id)
|
||||
return project_url
|
||||
except (KeyError, IndexError):
|
||||
return None
|
||||
|
||||
def does_package_exists_in_anitya(
|
||||
self, package_name: str, distribution: str, project_name: str
|
||||
) -> bool:
|
||||
"""
|
||||
Check if package exists in Anitya.
|
||||
|
||||
Params:
|
||||
package_name (str): The name of the package.
|
||||
distribution (str): The name of the distribution.
|
||||
project_name (str): The name of the project.
|
||||
|
||||
Returns:
|
||||
False if package don't exist
|
||||
False if package exist but his project is different from provided project name
|
||||
True if package exist and his project is correct
|
||||
"""
|
||||
endpoint = self._anitya_endpoint + "/api/v2/packages/"
|
||||
packages_params = {
|
||||
"name": package_name,
|
||||
"distribution": distribution,
|
||||
}
|
||||
packages_response = self._requests_session.get(endpoint, params=packages_params)
|
||||
if packages_response.status_code != 200:
|
||||
log.info("Package '{0}' not found in Anitya.".format(package_name))
|
||||
return False # Not able to find package
|
||||
response_json = packages_response.json()
|
||||
item_count = response_json["total_items"]
|
||||
if item_count < 1:
|
||||
log.info("Package '{0}' not found in Anitya.".format(package_name))
|
||||
return False
|
||||
package_json = response_json["items"][0]
|
||||
package_project_name = package_json["project"]
|
||||
if package_project_name != project_name:
|
||||
return False # Expected and actual project name are different
|
||||
else:
|
||||
return True # Expected and actual project name are the same
|
||||
|
||||
def create_project_in_anitya(
|
||||
self,
|
||||
name: str,
|
||||
homepage: str,
|
||||
backend: str,
|
||||
) -> Optional[str]:
|
||||
"""
|
||||
Create a new project in Anitya.
|
||||
|
||||
Params:
|
||||
name (str): The name of the project.
|
||||
homepage (str): The homepage of the project.
|
||||
backend (str): The name of the backend.
|
||||
|
||||
Returns:
|
||||
The project URL if successful, otherwise None.
|
||||
"""
|
||||
headers = {"Authorization": "token " + self._anitya_token}
|
||||
endpoint = self._anitya_endpoint + "/api/v2/projects/"
|
||||
payload = {
|
||||
"name": name,
|
||||
"homepage": homepage,
|
||||
"backend": backend,
|
||||
}
|
||||
log.info("Creating project '{0}' in Anitya.".format(name))
|
||||
response = self._requests_session.post(
|
||||
url=endpoint, data=payload, headers=headers
|
||||
)
|
||||
if response.status_code == 201:
|
||||
project_json = response.json()
|
||||
project_id = project_json["id"]
|
||||
project_url = "{0}/project/{1}".format(self._anitya_endpoint, project_id)
|
||||
return project_url
|
||||
else:
|
||||
return None
|
||||
|
||||
def create_package_in_anitya(
|
||||
self,
|
||||
package_name: str,
|
||||
project_name: str,
|
||||
distribution: str,
|
||||
project_ecosystem: str,
|
||||
) -> Optional[str]:
|
||||
"""
|
||||
Create a new package in Anitya.
|
||||
|
||||
Params:
|
||||
package_name (str): The name of the package.
|
||||
project_name (str): The name of the project.
|
||||
distribution (str): The name of the distribution.
|
||||
project_ecosystem (str): The name of the ecosystem.
|
||||
|
||||
Returns:
|
||||
Return message if status code is known, otherwise None.
|
||||
"""
|
||||
headers = {"Authorization": "token " + self._anitya_token}
|
||||
endpoint = self._anitya_endpoint + "/api/v2/packages/"
|
||||
payload = {
|
||||
"package_name": package_name,
|
||||
"project_name": project_name,
|
||||
"distribution": distribution,
|
||||
"project_ecosystem": project_ecosystem,
|
||||
}
|
||||
log.info("Creating package '{0}' in Anitya.".format(package_name))
|
||||
response = self._requests_session.post(
|
||||
url=endpoint, data=payload, headers=headers
|
||||
)
|
||||
if response.status_code == 400:
|
||||
return "Bad Request, some necessary arguments were not provided."
|
||||
elif response.status_code == 401:
|
||||
return "Unauthorized, access token is incorrect."
|
||||
elif response.status_code == 409:
|
||||
return "Conflict, package already exists."
|
||||
elif response.status_code == 201:
|
||||
return "Success"
|
||||
return None
|
|
@ -136,9 +136,7 @@ class GitRepo:
|
|||
except Exception: # Raised when branch name is not correct
|
||||
return None
|
||||
|
||||
def revert_last_commit(
|
||||
self, message: str, user: str, token: str, branch: str = "rawhide"
|
||||
) -> None:
|
||||
def revert_last_commit(self, message: str, branch: str = "rawhide") -> None:
|
||||
"""
|
||||
Revert last commit with message on requested branch.
|
||||
|
||||
|
@ -151,16 +149,10 @@ class GitRepo:
|
|||
self.repo.git.checkout(branch)
|
||||
|
||||
# reverting last commit and changing the commit message
|
||||
self.repo.git.revert("HEAD", no_edit=True)
|
||||
self.repo.git.commit("--amend", "-m", message)
|
||||
|
||||
self.repo.git.execute(["git", "revert", "--no-edit", "HEAD"])
|
||||
self.repo.git.execute(["git", "commit", "--amend", "-m", message])
|
||||
origin = self.repo.remote("origin")
|
||||
git_cmd = self.repo.git
|
||||
|
||||
push_url = origin.url.replace(
|
||||
"https://", "https://{0}:{1}@".format(user, token)
|
||||
)
|
||||
git_cmd.push("-u", push_url, branch)
|
||||
origin.push()
|
||||
except Exception as error:
|
||||
print(error, "\nSomething happened during reverting the last commit")
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue