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.pagure.set_pagure")
|
||||||
@patch("toddlers.utils.fedora_account.set_fasjson")
|
@patch("toddlers.utils.fedora_account.set_fasjson")
|
||||||
@patch("toddlers.utils.bugzilla_system.set_bz")
|
@patch("toddlers.utils.bugzilla_system.set_bz")
|
||||||
@patch("toddlers.utils.anitya.set_anitya")
|
def test_process_exception(self, mock_bugzilla, mock_fasjson, mock_pagure, toddler):
|
||||||
def test_process_exception(
|
|
||||||
self, mock_anitya, mock_bugzilla, mock_fasjson, mock_pagure, toddler
|
|
||||||
):
|
|
||||||
"""
|
"""
|
||||||
Assert that message toddler will be initialized correctly, if message passes
|
Assert that message toddler will be initialized correctly, if message passes
|
||||||
initial processing.
|
initial processing.
|
||||||
|
@ -183,16 +180,12 @@ class TestProcess:
|
||||||
)
|
)
|
||||||
mock_fasjson.assert_called_with(config)
|
mock_fasjson.assert_called_with(config)
|
||||||
mock_bugzilla.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()
|
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.pagure.set_pagure")
|
||||||
@patch("toddlers.utils.fedora_account.set_fasjson")
|
@patch("toddlers.utils.fedora_account.set_fasjson")
|
||||||
@patch("toddlers.utils.bugzilla_system.set_bz")
|
@patch("toddlers.utils.bugzilla_system.set_bz")
|
||||||
def test_process(
|
def test_process(self, mock_bugzilla, mock_fasjson, mock_pagure, toddler):
|
||||||
self, mock_bugzilla, mock_fasjson, mock_pagure, mock_anitya, toddler
|
|
||||||
):
|
|
||||||
"""
|
"""
|
||||||
Assert that message toddler will be initialized correctly, if message passes
|
Assert that message toddler will be initialized correctly, if message passes
|
||||||
initial processing.
|
initial processing.
|
||||||
|
@ -234,15 +227,11 @@ class TestProcess:
|
||||||
)
|
)
|
||||||
mock_fasjson.assert_called_with(config)
|
mock_fasjson.assert_called_with(config)
|
||||||
mock_bugzilla.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.pagure.set_pagure")
|
||||||
@patch("toddlers.utils.fedora_account.set_fasjson")
|
@patch("toddlers.utils.fedora_account.set_fasjson")
|
||||||
@patch("toddlers.utils.bugzilla_system.set_bz")
|
@patch("toddlers.utils.bugzilla_system.set_bz")
|
||||||
def test_process_comment(
|
def test_process_comment(self, mock_bugzilla, mock_fasjson, mock_pagure, toddler):
|
||||||
self, mock_bugzilla, mock_fasjson, mock_pagure, mock_anitya, toddler
|
|
||||||
):
|
|
||||||
"""
|
"""
|
||||||
Assert that toddler will handle comments correctly.
|
Assert that toddler will handle comments correctly.
|
||||||
"""
|
"""
|
||||||
|
@ -802,7 +791,6 @@ class TestProcessNewRepo:
|
||||||
self.toddler = scm_request_processor.SCMRequestProcessor()
|
self.toddler = scm_request_processor.SCMRequestProcessor()
|
||||||
self.toddler.pagure_io = Mock()
|
self.toddler.pagure_io = Mock()
|
||||||
self.toddler.dist_git = Mock()
|
self.toddler.dist_git = Mock()
|
||||||
self.toddler.anitya = Mock()
|
|
||||||
self.toddler.ping_comment = "{maintainers}"
|
self.toddler.ping_comment = "{maintainers}"
|
||||||
|
|
||||||
def test_process_new_repo_missing_required_key(self):
|
def test_process_new_repo_missing_required_key(self):
|
||||||
|
@ -812,77 +800,12 @@ class TestProcessNewRepo:
|
||||||
issue = {
|
issue = {
|
||||||
"id": 100,
|
"id": 100,
|
||||||
}
|
}
|
||||||
json = {
|
self.toddler.process_new_repo(issue, {})
|
||||||
"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.pagure_io.close_issue.assert_called_with(
|
self.toddler.pagure_io.close_issue.assert_called_with(
|
||||||
100,
|
100,
|
||||||
namespace=scm_request_processor.PROJECT_NAMESPACE,
|
namespace=scm_request_processor.PROJECT_NAMESPACE,
|
||||||
message="Invalid body, missing required field: upstreamurl",
|
message="Invalid body, missing required field: repo",
|
||||||
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",
|
|
||||||
reason="Invalid",
|
reason="Invalid",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -899,8 +822,40 @@ class TestProcessNewRepo:
|
||||||
"bug_id": "123",
|
"bug_id": "123",
|
||||||
"action": "new_repo",
|
"action": "new_repo",
|
||||||
"sls": {"rawhide": "2050-06-01"},
|
"sls": {"rawhide": "2050-06-01"},
|
||||||
"monitor": "no-monitoring",
|
"monitor": "monitor",
|
||||||
"upstreamurl": "",
|
}
|
||||||
|
|
||||||
|
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)
|
self.toddler.process_new_repo(issue, json)
|
||||||
|
@ -933,8 +888,7 @@ class TestProcessNewRepo:
|
||||||
"bug_id": "",
|
"bug_id": "",
|
||||||
"action": "new_repo",
|
"action": "new_repo",
|
||||||
"sls": {"rawhide": "2050-06-01"},
|
"sls": {"rawhide": "2050-06-01"},
|
||||||
"monitor": "no-monitoring",
|
"monitor": "monitor",
|
||||||
"upstreamurl": "",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.toddler.dist_git.get_project.return_value = None
|
self.toddler.dist_git.get_project.return_value = None
|
||||||
|
@ -963,8 +917,7 @@ class TestProcessNewRepo:
|
||||||
"bug_id": "123",
|
"bug_id": "123",
|
||||||
"action": "new_repo",
|
"action": "new_repo",
|
||||||
"sls": {"rawhide": "2050-06-01"},
|
"sls": {"rawhide": "2050-06-01"},
|
||||||
"monitor": "no-monitoring",
|
"monitor": "monitor",
|
||||||
"upstreamurl": "",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.toddler.dist_git.get_project.return_value = None
|
self.toddler.dist_git.get_project.return_value = None
|
||||||
|
@ -998,8 +951,7 @@ class TestProcessNewRepo:
|
||||||
bug_id = "123"
|
bug_id = "123"
|
||||||
action = "new_repo"
|
action = "new_repo"
|
||||||
sls = {"rawhide": "2050-06-01"}
|
sls = {"rawhide": "2050-06-01"}
|
||||||
monitor = "no-monitoring"
|
monitor = "monitor"
|
||||||
upstreamurl = ""
|
|
||||||
exception = False
|
exception = False
|
||||||
json = {
|
json = {
|
||||||
"repo": repo,
|
"repo": repo,
|
||||||
|
@ -1009,7 +961,6 @@ class TestProcessNewRepo:
|
||||||
"action": action,
|
"action": action,
|
||||||
"sls": sls,
|
"sls": sls,
|
||||||
"monitor": monitor,
|
"monitor": monitor,
|
||||||
"upstreamurl": upstreamurl,
|
|
||||||
"exception": exception,
|
"exception": exception,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1039,8 +990,7 @@ class TestProcessNewRepo:
|
||||||
bug_id = "123"
|
bug_id = "123"
|
||||||
action = "new_repo"
|
action = "new_repo"
|
||||||
sls = {"rawhide": "2050-06-01"}
|
sls = {"rawhide": "2050-06-01"}
|
||||||
monitor = "no-monitoring"
|
monitor = "monitor"
|
||||||
upstreamurl = ""
|
|
||||||
exception = False
|
exception = False
|
||||||
json = {
|
json = {
|
||||||
"repo": repo,
|
"repo": repo,
|
||||||
|
@ -1050,7 +1000,6 @@ class TestProcessNewRepo:
|
||||||
"action": action,
|
"action": action,
|
||||||
"sls": sls,
|
"sls": sls,
|
||||||
"monitor": monitor,
|
"monitor": monitor,
|
||||||
"upstreamurl": upstreamurl,
|
|
||||||
"exception": exception,
|
"exception": exception,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1071,10 +1020,7 @@ class TestProcessNewRepo:
|
||||||
comment=message,
|
comment=message,
|
||||||
)
|
)
|
||||||
|
|
||||||
@patch(
|
def test_process_new_repo_master_branch(self):
|
||||||
"toddlers.plugins.scm_request_processor.SCMRequestProcessor.validate_review_bug"
|
|
||||||
)
|
|
||||||
def test_process_new_repo_master_branch(self, mock_validate_review_bug):
|
|
||||||
"""
|
"""
|
||||||
Assert that ticket will be closed when branch is set to master branch.
|
Assert that ticket will be closed when branch is set to master branch.
|
||||||
Master branch is no longer allowed.
|
Master branch is no longer allowed.
|
||||||
|
@ -1087,8 +1033,7 @@ class TestProcessNewRepo:
|
||||||
bug_id = "123"
|
bug_id = "123"
|
||||||
action = "new_repo"
|
action = "new_repo"
|
||||||
sls = {"rawhide": "2050-06-01"}
|
sls = {"rawhide": "2050-06-01"}
|
||||||
monitor = "no-monitoring"
|
monitor = "monitor"
|
||||||
upstreamurl = ""
|
|
||||||
exception = False
|
exception = False
|
||||||
json = {
|
json = {
|
||||||
"repo": repo,
|
"repo": repo,
|
||||||
|
@ -1098,7 +1043,6 @@ class TestProcessNewRepo:
|
||||||
"action": action,
|
"action": action,
|
||||||
"sls": sls,
|
"sls": sls,
|
||||||
"monitor": monitor,
|
"monitor": monitor,
|
||||||
"upstreamurl": upstreamurl,
|
|
||||||
"exception": exception,
|
"exception": exception,
|
||||||
}
|
}
|
||||||
self.toddler.dist_git.get_project.return_value = None
|
self.toddler.dist_git.get_project.return_value = None
|
||||||
|
@ -1124,8 +1068,7 @@ class TestProcessNewRepo:
|
||||||
bug_id = "123"
|
bug_id = "123"
|
||||||
action = "new_repo"
|
action = "new_repo"
|
||||||
sls = {"rawhide": "2050-06-01"}
|
sls = {"rawhide": "2050-06-01"}
|
||||||
monitor = "no-monitoring"
|
monitor = "monitor"
|
||||||
upstreamurl = ""
|
|
||||||
exception = False
|
exception = False
|
||||||
json = {
|
json = {
|
||||||
"repo": repo,
|
"repo": repo,
|
||||||
|
@ -1135,7 +1078,6 @@ class TestProcessNewRepo:
|
||||||
"action": action,
|
"action": action,
|
||||||
"sls": sls,
|
"sls": sls,
|
||||||
"monitor": monitor,
|
"monitor": monitor,
|
||||||
"upstreamurl": upstreamurl,
|
|
||||||
"exception": exception,
|
"exception": exception,
|
||||||
}
|
}
|
||||||
self.toddler.process_new_repo(issue, json)
|
self.toddler.process_new_repo(issue, json)
|
||||||
|
@ -1178,12 +1120,11 @@ class TestProcessNewRepo:
|
||||||
}
|
}
|
||||||
|
|
||||||
repo = "repo"
|
repo = "repo"
|
||||||
bug_id = "11"
|
bug_id = ""
|
||||||
action = "new_repo"
|
action = "new_repo"
|
||||||
sls = {branch: "2050-06-01"}
|
sls = {branch: "2050-06-01"}
|
||||||
monitor = "no-monitoring"
|
monitor = "monitor"
|
||||||
upstreamurl = ""
|
exception = True
|
||||||
exception = False
|
|
||||||
json = {
|
json = {
|
||||||
"repo": repo,
|
"repo": repo,
|
||||||
"branch": branch,
|
"branch": branch,
|
||||||
|
@ -1192,7 +1133,6 @@ class TestProcessNewRepo:
|
||||||
"action": action,
|
"action": action,
|
||||||
"sls": sls,
|
"sls": sls,
|
||||||
"monitor": monitor,
|
"monitor": monitor,
|
||||||
"upstreamurl": upstreamurl,
|
|
||||||
"exception": exception,
|
"exception": exception,
|
||||||
}
|
}
|
||||||
dist_git_url = "https://src.fp.o"
|
dist_git_url = "https://src.fp.o"
|
||||||
|
@ -1201,12 +1141,9 @@ class TestProcessNewRepo:
|
||||||
self.toddler.pagure_io.get_project_contributors.return_value = {
|
self.toddler.pagure_io.get_project_contributors.return_value = {
|
||||||
"users": {"admin": [user], "commit": [], "ticket": []}
|
"users": {"admin": [user], "commit": [], "ticket": []}
|
||||||
}
|
}
|
||||||
self.toddler.validation_comment = "valid"
|
|
||||||
self.toddler.validate_review_bug = Mock()
|
|
||||||
|
|
||||||
# Method to test
|
# Method to test
|
||||||
with patch("toddlers.plugins.scm_request_processor.bugzilla_system"):
|
self.toddler.process_new_repo(issue, json)
|
||||||
self.toddler.process_new_repo(issue, json)
|
|
||||||
|
|
||||||
# asserts
|
# asserts
|
||||||
self.toddler.pagure_io.add_comment_to_issue.assert_called_with(
|
self.toddler.pagure_io.add_comment_to_issue.assert_called_with(
|
||||||
|
@ -1239,8 +1176,7 @@ class TestProcessNewRepo:
|
||||||
bug_id = ""
|
bug_id = ""
|
||||||
action = "new_repo"
|
action = "new_repo"
|
||||||
sls = {branch: "2050-06-01"}
|
sls = {branch: "2050-06-01"}
|
||||||
monitor = "no-monitoring"
|
monitor = "monitor"
|
||||||
upstreamurl = ""
|
|
||||||
exception = True
|
exception = True
|
||||||
json = {
|
json = {
|
||||||
"repo": repo,
|
"repo": repo,
|
||||||
|
@ -1250,7 +1186,6 @@ class TestProcessNewRepo:
|
||||||
"action": action,
|
"action": action,
|
||||||
"sls": sls,
|
"sls": sls,
|
||||||
"monitor": monitor,
|
"monitor": monitor,
|
||||||
"upstreamurl": upstreamurl,
|
|
||||||
"exception": exception,
|
"exception": exception,
|
||||||
}
|
}
|
||||||
dist_git_url = "https://src.fp.o"
|
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.bugzilla_system")
|
||||||
@patch(
|
@patch(
|
||||||
"toddlers.plugins.scm_request_processor.SCMRequestProcessor._validate_new_repo_request",
|
"toddlers.plugins.scm_request_processor.SCMRequestProcessor.validate_review_bug"
|
||||||
return_value=True,
|
|
||||||
)
|
)
|
||||||
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
|
Assert that ticket will be processed correctly when repo already
|
||||||
exists in dist git.
|
exists in dist git.
|
||||||
|
@ -1284,7 +1218,7 @@ class TestProcessNewRepo:
|
||||||
bug_id = "123"
|
bug_id = "123"
|
||||||
action = "new_repo"
|
action = "new_repo"
|
||||||
sls = {"rawhide": "2050-06-01"}
|
sls = {"rawhide": "2050-06-01"}
|
||||||
monitor = "no-monitoring"
|
monitor = "monitor"
|
||||||
exception = False
|
exception = False
|
||||||
json = {
|
json = {
|
||||||
"repo": repo,
|
"repo": repo,
|
||||||
|
@ -1295,7 +1229,6 @@ class TestProcessNewRepo:
|
||||||
"sls": sls,
|
"sls": sls,
|
||||||
"monitor": monitor,
|
"monitor": monitor,
|
||||||
"exception": exception,
|
"exception": exception,
|
||||||
"upstreamurl": "",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
dist_git_url = "https://src.fp.o"
|
dist_git_url = "https://src.fp.o"
|
||||||
|
@ -1337,7 +1270,7 @@ class TestProcessNewRepo:
|
||||||
bug_id = "123"
|
bug_id = "123"
|
||||||
action = "new_repo"
|
action = "new_repo"
|
||||||
sls = {branch: "2050-06-01"}
|
sls = {branch: "2050-06-01"}
|
||||||
monitor = "no-monitoring"
|
monitor = "monitor"
|
||||||
exception = False
|
exception = False
|
||||||
json = {
|
json = {
|
||||||
"repo": repo,
|
"repo": repo,
|
||||||
|
@ -1348,7 +1281,6 @@ class TestProcessNewRepo:
|
||||||
"sls": sls,
|
"sls": sls,
|
||||||
"monitor": monitor,
|
"monitor": monitor,
|
||||||
"exception": exception,
|
"exception": exception,
|
||||||
"upstreamurl": "",
|
|
||||||
}
|
}
|
||||||
self.toddler.branch_slas = {"rawhide": {"rawhide": "2050-06-01"}}
|
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)
|
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.bugzilla_system")
|
||||||
@patch(
|
@patch(
|
||||||
"toddlers.plugins.scm_request_processor.SCMRequestProcessor.validate_review_bug"
|
"toddlers.plugins.scm_request_processor.SCMRequestProcessor.validate_review_bug"
|
||||||
|
@ -1717,8 +1341,7 @@ class TestProcessNewRepo:
|
||||||
bug_id = "123"
|
bug_id = "123"
|
||||||
action = "new_repo"
|
action = "new_repo"
|
||||||
sls = {branch: "2050-06-01"}
|
sls = {branch: "2050-06-01"}
|
||||||
monitor = "no-monitoring"
|
monitor = "monitor"
|
||||||
upstreamurl = ""
|
|
||||||
exception = False
|
exception = False
|
||||||
json = {
|
json = {
|
||||||
"repo": repo,
|
"repo": repo,
|
||||||
|
@ -1728,7 +1351,6 @@ class TestProcessNewRepo:
|
||||||
"action": action,
|
"action": action,
|
||||||
"sls": sls,
|
"sls": sls,
|
||||||
"monitor": monitor,
|
"monitor": monitor,
|
||||||
"upstreamurl": upstreamurl,
|
|
||||||
"exception": exception,
|
"exception": exception,
|
||||||
}
|
}
|
||||||
self.toddler.branch_slas = {"rawhide": {"rawhide": "2050-06-01"}}
|
self.toddler.branch_slas = {"rawhide": {"rawhide": "2050-06-01"}}
|
||||||
|
@ -1789,8 +1411,7 @@ class TestProcessNewRepo:
|
||||||
bug_id = "123"
|
bug_id = "123"
|
||||||
action = "new_repo"
|
action = "new_repo"
|
||||||
sls = {branch: "2050-06-01"}
|
sls = {branch: "2050-06-01"}
|
||||||
monitor = "no-monitoring"
|
monitor = "monitor"
|
||||||
upstreamurl = ""
|
|
||||||
exception = False
|
exception = False
|
||||||
json = {
|
json = {
|
||||||
"repo": repo,
|
"repo": repo,
|
||||||
|
@ -1800,7 +1421,6 @@ class TestProcessNewRepo:
|
||||||
"action": action,
|
"action": action,
|
||||||
"sls": sls,
|
"sls": sls,
|
||||||
"monitor": monitor,
|
"monitor": monitor,
|
||||||
"upstreamurl": upstreamurl,
|
|
||||||
"exception": exception,
|
"exception": exception,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1853,7 +1473,7 @@ class TestProcessNewRepo:
|
||||||
bug_id = "123"
|
bug_id = "123"
|
||||||
action = "new_repo"
|
action = "new_repo"
|
||||||
sls = {branch: "2050-06-01"}
|
sls = {branch: "2050-06-01"}
|
||||||
monitor = "no-monitoring"
|
monitor = "monitor"
|
||||||
exception = False
|
exception = False
|
||||||
json = {
|
json = {
|
||||||
"repo": repo,
|
"repo": repo,
|
||||||
|
@ -1863,7 +1483,6 @@ class TestProcessNewRepo:
|
||||||
"action": action,
|
"action": action,
|
||||||
"sls": sls,
|
"sls": sls,
|
||||||
"monitor": monitor,
|
"monitor": monitor,
|
||||||
"upstreamurl": "",
|
|
||||||
"exception": exception,
|
"exception": exception,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1923,7 +1542,7 @@ class TestProcessNewRepo:
|
||||||
bug_id = "123"
|
bug_id = "123"
|
||||||
action = "new_repo"
|
action = "new_repo"
|
||||||
sls = {branch: "2050-06-01"}
|
sls = {branch: "2050-06-01"}
|
||||||
monitor = "no-monitoring"
|
monitor = "monitor"
|
||||||
exception = False
|
exception = False
|
||||||
json = {
|
json = {
|
||||||
"repo": repo,
|
"repo": repo,
|
||||||
|
@ -1933,7 +1552,6 @@ class TestProcessNewRepo:
|
||||||
"action": action,
|
"action": action,
|
||||||
"sls": sls,
|
"sls": sls,
|
||||||
"monitor": monitor,
|
"monitor": monitor,
|
||||||
"upstreamurl": "",
|
|
||||||
"exception": exception,
|
"exception": exception,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2009,7 +1627,7 @@ class TestProcessNewRepo:
|
||||||
bug_id = "123"
|
bug_id = "123"
|
||||||
action = "new_repo"
|
action = "new_repo"
|
||||||
sls = {branch: "2050-06-01"}
|
sls = {branch: "2050-06-01"}
|
||||||
monitor = "no-monitoring"
|
monitor = "monitor"
|
||||||
exception = False
|
exception = False
|
||||||
json = {
|
json = {
|
||||||
"repo": repo,
|
"repo": repo,
|
||||||
|
@ -2019,7 +1637,6 @@ class TestProcessNewRepo:
|
||||||
"action": action,
|
"action": action,
|
||||||
"sls": sls,
|
"sls": sls,
|
||||||
"monitor": monitor,
|
"monitor": monitor,
|
||||||
"upstreamurl": "",
|
|
||||||
"exception": exception,
|
"exception": exception,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2086,7 +1703,7 @@ class TestProcessNewRepo:
|
||||||
bug_id = "123"
|
bug_id = "123"
|
||||||
action = "new_repo"
|
action = "new_repo"
|
||||||
sls = {branch: "2050-06-01"}
|
sls = {branch: "2050-06-01"}
|
||||||
monitor = "no-monitoring"
|
monitor = "monitor"
|
||||||
exception = False
|
exception = False
|
||||||
json = {
|
json = {
|
||||||
"repo": repo,
|
"repo": repo,
|
||||||
|
@ -2096,7 +1713,6 @@ class TestProcessNewRepo:
|
||||||
"action": action,
|
"action": action,
|
||||||
"sls": sls,
|
"sls": sls,
|
||||||
"monitor": monitor,
|
"monitor": monitor,
|
||||||
"upstreamurl": "",
|
|
||||||
"exception": exception,
|
"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`.
|
Unit tests for `toddlers.utils.git`.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from unittest.mock import MagicMock, Mock, patch
|
from unittest.mock import call, MagicMock, Mock, patch
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -290,28 +290,24 @@ class TestGitRepoRevertLastCommit:
|
||||||
Assert that revert last commit process correctly.
|
Assert that revert last commit process correctly.
|
||||||
"""
|
"""
|
||||||
mock_origin = MagicMock()
|
mock_origin = MagicMock()
|
||||||
mock_origin.url = "https://example.com"
|
|
||||||
self.repo.repo.remote.return_value = mock_origin
|
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.checkout.assert_called_once_with("feature_branch")
|
||||||
self.repo.repo.git.revert.assert_called_once_with("HEAD", no_edit=True)
|
self.repo.repo.git.execute.assert_has_calls(
|
||||||
self.repo.repo.git.commit.assert_called_once_with(
|
[
|
||||||
"--amend", "-m", "Revert message"
|
call(["git", "revert", "--no-edit", "HEAD"]),
|
||||||
)
|
call(["git", "commit", "--amend", "-m", "Revert message"]),
|
||||||
|
]
|
||||||
mock_git_cmd.push.assert_called_once_with(
|
|
||||||
"-u", "https://bot:token@example.com", "feature_branch"
|
|
||||||
)
|
)
|
||||||
|
mock_origin.push.assert_called_once()
|
||||||
|
|
||||||
def test_revert_last_commit_revert_exception(self):
|
def test_revert_last_commit_revert_exception(self):
|
||||||
mock_origin = MagicMock()
|
mock_origin = MagicMock()
|
||||||
self.repo.repo.remote.return_value = mock_origin
|
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()
|
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"
|
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
|
# 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"
|
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
|
# Pagure mapping to bugzilla
|
||||||
|
|
|
@ -24,14 +24,7 @@ import tomllib
|
||||||
|
|
||||||
from toddlers.base import ToddlerBase
|
from toddlers.base import ToddlerBase
|
||||||
from toddlers.exceptions import ValidationError
|
from toddlers.exceptions import ValidationError
|
||||||
from toddlers.utils import (
|
from toddlers.utils import bugzilla_system, fedora_account, git, pagure, requests
|
||||||
anitya,
|
|
||||||
bugzilla_system,
|
|
||||||
fedora_account,
|
|
||||||
git,
|
|
||||||
pagure,
|
|
||||||
requests,
|
|
||||||
)
|
|
||||||
|
|
||||||
# Regex for branch name validation
|
# Regex for branch name validation
|
||||||
STREAM_NAME_REGEX = r"^[a-zA-Z0-9.\-_+]+$"
|
STREAM_NAME_REGEX = r"^[a-zA-Z0-9.\-_+]+$"
|
||||||
|
@ -107,9 +100,6 @@ class SCMRequestProcessor(ToddlerBase):
|
||||||
# for toddler
|
# for toddler
|
||||||
pagure_user: str = ""
|
pagure_user: str = ""
|
||||||
|
|
||||||
# Anitya object to work with Anitya
|
|
||||||
anitya: anitya.Anitya
|
|
||||||
|
|
||||||
def accepts_topic(self, topic: str) -> bool:
|
def accepts_topic(self, topic: str) -> bool:
|
||||||
"""Returns a boolean whether this toddler is interested in messages
|
"""Returns a boolean whether this toddler is interested in messages
|
||||||
from this specific topic.
|
from this specific topic.
|
||||||
|
@ -197,9 +187,6 @@ class SCMRequestProcessor(ToddlerBase):
|
||||||
_log.info("Setting up connection to Bugzilla")
|
_log.info("Setting up connection to Bugzilla")
|
||||||
bugzilla_system.set_bz(config)
|
bugzilla_system.set_bz(config)
|
||||||
|
|
||||||
_log.info("Setting up connection to Anitya")
|
|
||||||
self.anitya = anitya.set_anitya(config)
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if message.topic.endswith("pagure.issue.comment.added"):
|
if message.topic.endswith("pagure.issue.comment.added"):
|
||||||
self.process_comment(issue)
|
self.process_comment(issue)
|
||||||
|
@ -463,12 +450,6 @@ class SCMRequestProcessor(ToddlerBase):
|
||||||
"namespace",
|
"namespace",
|
||||||
"sls",
|
"sls",
|
||||||
"monitor",
|
"monitor",
|
||||||
"upstreamurl",
|
|
||||||
]
|
|
||||||
required_keys_for_monitor = [
|
|
||||||
"backend",
|
|
||||||
"project_name",
|
|
||||||
"distribution",
|
|
||||||
]
|
]
|
||||||
for key in required_keys:
|
for key in required_keys:
|
||||||
if key not in issue_body_json.keys():
|
if key not in issue_body_json.keys():
|
||||||
|
@ -480,18 +461,6 @@ class SCMRequestProcessor(ToddlerBase):
|
||||||
)
|
)
|
||||||
return
|
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
|
# Validate the request first
|
||||||
if self._validate_new_repo_request(issue, issue_body_json):
|
if self._validate_new_repo_request(issue, issue_body_json):
|
||||||
_log.info("Ticket passed all validations. Creating repository.")
|
_log.info("Ticket passed all validations. Creating repository.")
|
||||||
|
@ -667,7 +636,6 @@ class SCMRequestProcessor(ToddlerBase):
|
||||||
branch_name = issue_body_json.get("branch", "").strip()
|
branch_name = issue_body_json.get("branch", "").strip()
|
||||||
description = issue_body_json.get("description", "").strip()
|
description = issue_body_json.get("description", "").strip()
|
||||||
upstreamurl = issue_body_json.get("upstreamurl", "").strip()
|
upstreamurl = issue_body_json.get("upstreamurl", "").strip()
|
||||||
monitor = issue_body_json.get("monitor", "").strip()
|
|
||||||
|
|
||||||
if namespace in ["rpms", "container"]:
|
if namespace in ["rpms", "container"]:
|
||||||
default_branch = "rawhide"
|
default_branch = "rawhide"
|
||||||
|
@ -768,50 +736,6 @@ class SCMRequestProcessor(ToddlerBase):
|
||||||
'You may commit to the branch "{1}" in about '
|
'You may commit to the branch "{1}" in about '
|
||||||
"10 minutes.".format(dist_git_url, branch_name)
|
"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(
|
self.pagure_io.close_issue(
|
||||||
issue["id"],
|
issue["id"],
|
||||||
namespace=PROJECT_NAMESPACE,
|
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
|
except Exception: # Raised when branch name is not correct
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def revert_last_commit(
|
def revert_last_commit(self, message: str, branch: str = "rawhide") -> None:
|
||||||
self, message: str, user: str, token: str, branch: str = "rawhide"
|
|
||||||
) -> None:
|
|
||||||
"""
|
"""
|
||||||
Revert last commit with message on requested branch.
|
Revert last commit with message on requested branch.
|
||||||
|
|
||||||
|
@ -151,16 +149,10 @@ class GitRepo:
|
||||||
self.repo.git.checkout(branch)
|
self.repo.git.checkout(branch)
|
||||||
|
|
||||||
# reverting last commit and changing the commit message
|
# reverting last commit and changing the commit message
|
||||||
self.repo.git.revert("HEAD", no_edit=True)
|
self.repo.git.execute(["git", "revert", "--no-edit", "HEAD"])
|
||||||
self.repo.git.commit("--amend", "-m", message)
|
self.repo.git.execute(["git", "commit", "--amend", "-m", message])
|
||||||
|
|
||||||
origin = self.repo.remote("origin")
|
origin = self.repo.remote("origin")
|
||||||
git_cmd = self.repo.git
|
origin.push()
|
||||||
|
|
||||||
push_url = origin.url.replace(
|
|
||||||
"https://", "https://{0}:{1}@".format(user, token)
|
|
||||||
)
|
|
||||||
git_cmd.push("-u", push_url, branch)
|
|
||||||
except Exception as error:
|
except Exception as error:
|
||||||
print(error, "\nSomething happened during reverting the last commit")
|
print(error, "\nSomething happened during reverting the last commit")
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue