#332 Creating project and package for Anitya if they not exists, when new repo requested
Merged 9 days ago by zlopez. Opened 3 months ago by amedvede.
fedora-infra/ amedvede/toddlers releng_10110  into  main

@@ -134,7 +134,10 @@ 

      @patch("toddlers.utils.pagure.set_pagure")

      @patch("toddlers.utils.fedora_account.set_fasjson")

      @patch("toddlers.utils.bugzilla_system.set_bz")

-     def test_process_exception(self, mock_bugzilla, mock_fasjson, mock_pagure, toddler):

+     @patch("toddlers.utils.anitya.set_anitya")

+     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

          initial processing.
@@ -180,12 +183,16 @@ 

          )

          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, toddler):

+     def test_process(

+         self, mock_bugzilla, mock_fasjson, mock_pagure, mock_anitya, toddler

+     ):

          """

          Assert that message toddler will be initialized correctly, if message passes

          initial processing.
@@ -227,11 +234,15 @@ 

          )

          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, toddler):

+     def test_process_comment(

+         self, mock_bugzilla, mock_fasjson, mock_pagure, mock_anitya, toddler

+     ):

          """

          Assert that toddler will handle comments correctly.

          """
@@ -791,6 +802,7 @@ 

          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):
@@ -800,21 +812,32 @@ 

          issue = {

              "id": 100,

          }

-         self.toddler.process_new_repo(issue, {})

+         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.pagure_io.close_issue.assert_called_with(

              100,

              namespace=scm_request_processor.PROJECT_NAMESPACE,

-             message="Invalid body, missing required field: repo",

+             message="Invalid body, missing required field: upstreamurl",

              reason="Invalid",

          )

  

-     def test_process_new_repo_invalid_repo_name(self):

+     def test_process_new_repo_missing_required_key_for_monitor(self):

          """

-         Assert that ticket will be closed if provided repository name is invalid.

+         Assert that ticket will be closed if required key for monitor

+         is missing in request.

          """

-         issue = {"id": 100, "user": {"name": "zlopez"}}

- 

+         issue = {

+             "id": 100,

+         }

          json = {

              "repo": "+a",

              "branch": "rawhide",
@@ -822,40 +845,62 @@ 

              "bug_id": "123",

              "action": "new_repo",

              "sls": {"rawhide": "2050-06-01"},

-             "monitor": "monitor",

+             "monitor": "monitoring",

+             "upstreamurl": "",

+             "backend": "GitLab",

          }

- 

          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="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=error,

+             message="Invalid body, missing required field: project_name",

              reason="Invalid",

          )

  

-     def test_process_new_repo_long_repo_name(self):

+     def test_process_new_repo_invalid_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)),

+             "repo": "+a",

              "branch": "rawhide",

              "namespace": "rpms",

              "bug_id": "123",

              "action": "new_repo",

              "sls": {"rawhide": "2050-06-01"},

-             "monitor": "monitor",

+             "monitor": "no-monitoring",

+             "upstreamurl": "",

          }

  

          self.toddler.process_new_repo(issue, json)
@@ -888,7 +933,8 @@ 

              "bug_id": "",

              "action": "new_repo",

              "sls": {"rawhide": "2050-06-01"},

-             "monitor": "monitor",

+             "monitor": "no-monitoring",

+             "upstreamurl": "",

          }

  

          self.toddler.dist_git.get_project.return_value = None
@@ -917,7 +963,8 @@ 

              "bug_id": "123",

              "action": "new_repo",

              "sls": {"rawhide": "2050-06-01"},

-             "monitor": "monitor",

+             "monitor": "no-monitoring",

+             "upstreamurl": "",

          }

  

          self.toddler.dist_git.get_project.return_value = None
@@ -951,7 +998,8 @@ 

          bug_id = "123"

          action = "new_repo"

          sls = {"rawhide": "2050-06-01"}

-         monitor = "monitor"

+         monitor = "no-monitoring"

+         upstreamurl = ""

          exception = False

          json = {

              "repo": repo,
@@ -961,6 +1009,7 @@ 

              "action": action,

              "sls": sls,

              "monitor": monitor,

+             "upstreamurl": upstreamurl,

              "exception": exception,

          }

  
@@ -990,7 +1039,8 @@ 

          bug_id = "123"

          action = "new_repo"

          sls = {"rawhide": "2050-06-01"}

-         monitor = "monitor"

+         monitor = "no-monitoring"

+         upstreamurl = ""

          exception = False

          json = {

              "repo": repo,
@@ -1000,6 +1050,7 @@ 

              "action": action,

              "sls": sls,

              "monitor": monitor,

+             "upstreamurl": upstreamurl,

              "exception": exception,

          }

  
@@ -1020,7 +1071,10 @@ 

              comment=message,

          )

  

-     def test_process_new_repo_master_branch(self):

+     @patch(

+         "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.

          Master branch is no longer allowed.
@@ -1033,7 +1087,8 @@ 

          bug_id = "123"

          action = "new_repo"

          sls = {"rawhide": "2050-06-01"}

-         monitor = "monitor"

+         monitor = "no-monitoring"

+         upstreamurl = ""

          exception = False

          json = {

              "repo": repo,
@@ -1043,6 +1098,7 @@ 

              "action": action,

              "sls": sls,

              "monitor": monitor,

+             "upstreamurl": upstreamurl,

              "exception": exception,

          }

          self.toddler.dist_git.get_project.return_value = None
@@ -1068,7 +1124,8 @@ 

          bug_id = "123"

          action = "new_repo"

          sls = {"rawhide": "2050-06-01"}

-         monitor = "monitor"

+         monitor = "no-monitoring"

+         upstreamurl = ""

          exception = False

          json = {

              "repo": repo,
@@ -1078,6 +1135,7 @@ 

              "action": action,

              "sls": sls,

              "monitor": monitor,

+             "upstreamurl": upstreamurl,

              "exception": exception,

          }

          self.toddler.process_new_repo(issue, json)
@@ -1120,11 +1178,12 @@ 

          }

  

          repo = "repo"

-         bug_id = ""

+         bug_id = "11"

          action = "new_repo"

          sls = {branch: "2050-06-01"}

-         monitor = "monitor"

-         exception = True

+         monitor = "no-monitoring"

+         upstreamurl = ""

+         exception = False

          json = {

              "repo": repo,

              "branch": branch,
@@ -1133,6 +1192,7 @@ 

              "action": action,

              "sls": sls,

              "monitor": monitor,

+             "upstreamurl": upstreamurl,

              "exception": exception,

          }

          dist_git_url = "https://src.fp.o"
@@ -1141,9 +1201,12 @@ 

          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

-         self.toddler.process_new_repo(issue, json)

+         with patch("toddlers.plugins.scm_request_processor.bugzilla_system"):

+             self.toddler.process_new_repo(issue, json)

  

          # asserts

          self.toddler.pagure_io.add_comment_to_issue.assert_called_with(
@@ -1176,7 +1239,8 @@ 

          bug_id = ""

          action = "new_repo"

          sls = {branch: "2050-06-01"}

-         monitor = "monitor"

+         monitor = "no-monitoring"

+         upstreamurl = ""

          exception = True

          json = {

              "repo": repo,
@@ -1186,6 +1250,7 @@ 

              "action": action,

              "sls": sls,

              "monitor": monitor,

+             "upstreamurl": upstreamurl,

              "exception": exception,

          }

          dist_git_url = "https://src.fp.o"
@@ -1203,9 +1268,10 @@ 

  

      @patch("toddlers.plugins.scm_request_processor.bugzilla_system")

      @patch(

-         "toddlers.plugins.scm_request_processor.SCMRequestProcessor.validate_review_bug"

+         "toddlers.plugins.scm_request_processor.SCMRequestProcessor._validate_new_repo_request",

+         return_value=True,

      )

-     def test_process_new_repo_project_exists(self, mock_validate_review_bug, mock_bz):

+     def test_process_new_repo_project_exists(self, mock_validate_request, mock_bz):

          """

          Assert that ticket will be processed correctly when repo already

          exists in dist git.
@@ -1218,7 +1284,7 @@ 

          bug_id = "123"

          action = "new_repo"

          sls = {"rawhide": "2050-06-01"}

-         monitor = "monitor"

+         monitor = "no-monitoring"

          exception = False

          json = {

              "repo": repo,
@@ -1229,6 +1295,7 @@ 

              "sls": sls,

              "monitor": monitor,

              "exception": exception,

+             "upstreamurl": "",

          }

  

          dist_git_url = "https://src.fp.o"
@@ -1270,7 +1337,7 @@ 

          bug_id = "123"

          action = "new_repo"

          sls = {branch: "2050-06-01"}

-         monitor = "monitor"

+         monitor = "no-monitoring"

          exception = False

          json = {

              "repo": repo,
@@ -1281,6 +1348,7 @@ 

              "sls": sls,

              "monitor": monitor,

              "exception": exception,

+             "upstreamurl": "",

          }

          self.toddler.branch_slas = {"rawhide": {"rawhide": "2050-06-01"}}

  
@@ -1322,6 +1390,314 @@ 

          )

          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"
@@ -1341,7 +1717,8 @@ 

          bug_id = "123"

          action = "new_repo"

          sls = {branch: "2050-06-01"}

-         monitor = "monitor"

+         monitor = "no-monitoring"

+         upstreamurl = ""

          exception = False

          json = {

              "repo": repo,
@@ -1351,6 +1728,7 @@ 

              "action": action,

              "sls": sls,

              "monitor": monitor,

+             "upstreamurl": upstreamurl,

              "exception": exception,

          }

          self.toddler.branch_slas = {"rawhide": {"rawhide": "2050-06-01"}}
@@ -1411,7 +1789,8 @@ 

          bug_id = "123"

          action = "new_repo"

          sls = {branch: "2050-06-01"}

-         monitor = "monitor"

+         monitor = "no-monitoring"

+         upstreamurl = ""

          exception = False

          json = {

              "repo": repo,
@@ -1421,6 +1800,7 @@ 

              "action": action,

              "sls": sls,

              "monitor": monitor,

+             "upstreamurl": upstreamurl,

              "exception": exception,

          }

  
@@ -1473,7 +1853,7 @@ 

          bug_id = "123"

          action = "new_repo"

          sls = {branch: "2050-06-01"}

-         monitor = "monitor"

+         monitor = "no-monitoring"

          exception = False

          json = {

              "repo": repo,
@@ -1483,6 +1863,7 @@ 

              "action": action,

              "sls": sls,

              "monitor": monitor,

+             "upstreamurl": "",

              "exception": exception,

          }

  
@@ -1542,7 +1923,7 @@ 

          bug_id = "123"

          action = "new_repo"

          sls = {branch: "2050-06-01"}

-         monitor = "monitor"

+         monitor = "no-monitoring"

          exception = False

          json = {

              "repo": repo,
@@ -1552,6 +1933,7 @@ 

              "action": action,

              "sls": sls,

              "monitor": monitor,

+             "upstreamurl": "",

              "exception": exception,

          }

  
@@ -1627,7 +2009,7 @@ 

          bug_id = "123"

          action = "new_repo"

          sls = {branch: "2050-06-01"}

-         monitor = "monitor"

+         monitor = "no-monitoring"

          exception = False

          json = {

              "repo": repo,
@@ -1637,6 +2019,7 @@ 

              "action": action,

              "sls": sls,

              "monitor": monitor,

+             "upstreamurl": "",

              "exception": exception,

          }

  
@@ -1703,7 +2086,7 @@ 

          bug_id = "123"

          action = "new_repo"

          sls = {branch: "2050-06-01"}

-         monitor = "monitor"

+         monitor = "no-monitoring"

          exception = False

          json = {

              "repo": repo,
@@ -1713,6 +2096,7 @@ 

              "action": action,

              "sls": sls,

              "monitor": monitor,

+             "upstreamurl": "",

              "exception": exception,

          }

  

@@ -0,0 +1,410 @@ 

+ """

+ 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"},

+         )

file modified
+3
@@ -253,6 +253,9 @@ 

  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,7 +24,14 @@ 

  

  from toddlers.base import ToddlerBase

  from toddlers.exceptions import ValidationError

- from toddlers.utils import bugzilla_system, fedora_account, git, pagure, requests

+ from toddlers.utils import (

+     anitya,

+     bugzilla_system,

+     fedora_account,

+     git,

+     pagure,

+     requests,

+ )

  

  # Regex for branch name validation

  STREAM_NAME_REGEX = r"^[a-zA-Z0-9.\-_+]+$"
@@ -100,6 +107,9 @@ 

      # 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.
@@ -187,6 +197,9 @@ 

          _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)
@@ -450,6 +463,12 @@ 

              "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():
@@ -461,6 +480,18 @@ 

                  )

                  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.")
@@ -636,6 +667,7 @@ 

          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"
@@ -736,6 +768,50 @@ 

                  '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,

@@ -0,0 +1,212 @@ 

+ """

+ 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

Build failed. More information on how to proceed and troubleshoot errors available at https://fedoraproject.org/wiki/Zuul-based-ci
https://fedora.softwarefactory-project.io/zuul/buildset/d5f4f4080c724fbdbcc67b095ccc2d50

1 new commit added

  • feat: sending link on anitya project in issue
2 months ago

Merge Failed.

This change or one of its cross-repo dependencies was unable to be automatically merged with the current state of its repository. Please rebase the change and upload a new patchset.
Warning:
Error merging pagure.io/fedora-infra/toddlers for 332,98eda6f

1 new commit added

  • feat: tests are changes to be suitable
2 months ago

Merge Failed.

This change or one of its cross-repo dependencies was unable to be automatically merged with the current state of its repository. Please rebase the change and upload a new patchset.
Warning:
Error merging pagure.io/fedora-infra/toddlers for 332,119bbab

1 new commit added

  • test: added test that covers monitoring features
2 months ago

Merge Failed.

This change or one of its cross-repo dependencies was unable to be automatically merged with the current state of its repository. Please rebase the change and upload a new patchset.
Warning:
Error merging pagure.io/fedora-infra/toddlers for 332,e1ec045

1 new commit added

  • test: scm_request_processor 100% coverage
2 months ago

Merge Failed.

This change or one of its cross-repo dependencies was unable to be automatically merged with the current state of its repository. Please rebase the change and upload a new patchset.
Warning:
Error merging pagure.io/fedora-infra/toddlers for 332,7a41c6d

1 new commit added

  • test: small change in code and tests
2 months ago

Merge Failed.

This change or one of its cross-repo dependencies was unable to be automatically merged with the current state of its repository. Please rebase the change and upload a new patchset.
Warning:
Error merging pagure.io/fedora-infra/toddlers for 332,3eb6a52

3 new commits added

  • flake8 ref
  • mypy ref
  • black ref
2 months ago

Merge Failed.

This change or one of its cross-repo dependencies was unable to be automatically merged with the current state of its repository. Please rebase the change and upload a new patchset.
Warning:
Error merging pagure.io/fedora-infra/toddlers for 332,ed804d4

rebased onto 7a458db

a month ago

Merge Failed.

This change or one of its cross-repo dependencies was unable to be automatically merged with the current state of its repository. Please rebase the change and upload a new patchset.
Warning:
Error merging pagure.io/fedora-infra/toddlers for 332,5c4392a

rebased onto 7a458db

a month ago

Build failed. More information on how to proceed and troubleshoot errors available at https://fedoraproject.org/wiki/Zuul-based-ci
https://fedora.softwarefactory-project.io/zuul/buildset/5767376851a94476a307c74bf87a24f4

1 new commit added

  • resolving merge conflicts
a month ago

rebased onto 7a458db

a month ago

I would move this to utils and create a new python module for Anitya.

I would move this to utils and create a new python module for Anitya.

I would move this to utils and create a new python module for Anitya.

I would move this to utils and create a new python module for Anitya.

It would be better to check if the monitoring is present and not set to no-monitoring. There are more than two options for monitoring now.

It would be better to check if the monitoring is present and not set to no-monitoring. There are more than two options for monitoring now.

You can create it manually on https://release-monitoring.org/

3 new commits added

  • ref: black and flake8 fixes
  • feat: creating new anitya util and moving anitya functionality there
  • fix tests
a month ago

rebased onto b0156c9

a month ago

rebased onto b0156c9

a month ago

This test is not testing what it should test. Also I'm not sure why it is looking like something newly added, when it was there before your changes.

This looks completely different than what is in scm_request_processor test file right now. Why?

This test shouldn't be even here. It was moved to TestProcessComment class.

This test is no longer even in the scm_request_processor test module.

Double /, that should actually fail

The name of this method is really confusing. I understand that is testing if the package exists and the name of project is the same, but it's not really clear. Even from the description.

Same as above, it's hard to tell what this method is testing. And I assume this could be done by parametrization in pytest as the only difference is result and name of project.

You probably want to replace about with when. It will probably make more sense and not only in this method.

I don't see anywhere in the method anything about testing items count. So the name of the method is not descriptive.

Double / in URL, that should not happen.

This could be probably parametrized as the only difference with the two previous methods is the result and mocked status_code.

We should probably upgrade monitor_choices as there are more of them now. Are you using this configuration value for anything?

This should be done the same as https://pagure.io/fedora-infra/toddlers/pull-request/332#_4__73. Otherwise the whole toddler will crash when the value is not in JSON body.

.format(anitya_project_url) this should be after (, otherwise it will only affect string before it. I'm surprised this didn't crashed as the string before doesn't have any variable to fill.

I'm not sure why they are two =? One should be enough.

This shouldn't be hardcoded as the anitya instance URL is provided in config.

There is no return specified in method definition.

You should remove trailing / from the endpoint. This explains the strange URLs in the tests cases.

No return defined in method header.

I don't think we care about that, if the package mapping already exists. This could just return True or False. Or URL to project or None would be better.

No return definition in method header.

The description of the method says that it is returning project ID and here is the project URL.

No return definition in method header.

The ecosystem shouldn't be a required argument for creating package.

Review should be now done, but I'm not sure what you did when rebasing this code. There are methods in scm_request_processor test module that are not in main and are not related to your code changes.

Also keep the commits when doing changes, it's easier to review.

The ecosystem shouldn't be a required argument for creating package.

Should be, this util sends a request, but in the code for the ecosystem parameter upstream URL is used. This parameter is mandatory.

We should probably upgrade monitor_choices as there are more of them now. Are you using this configuration value for anything?

It was in repo before my changes, I'm not using it, can be removed probably

We should probably upgrade monitor_choices as there are more of them now. Are you using this configuration value for anything?

It was in repo before my changes, I'm not using it, can be removed probably

In that case leave it there.

The ecosystem shouldn't be a required argument for creating package.

Should be, this util sends a request, but in the code for the ecosystem parameter upstream URL is used. This parameter is mandatory.

You are right, it's even in the docs. I just don't understand why creating a package mapping needs to know in which ecosystem project is. It was there even before I took over the project, so it could be some reasoning I'm not aware of.

7 new commits added

  • removing monitoring_choices from tests since it was removed from code
  • fixing scm_request_processor tests
  • fix mistakes in scm_request_processor
  • fix anitya tests
  • removed monitoring_choices field from config and checks from code, since it useless
  • improve anitya util
  • removing useless tests for scm_request_processor
a month ago

Build failed. More information on how to proceed and troubleshoot errors available at https://fedoraproject.org/wiki/Zuul-based-ci
https://fedora.softwarefactory-project.io/zuul/buildset/7172e23a0bc44787a0180a36172ad87f

You shouldn't remove the tests in cee0b79. It rather seems that you did something wrong when rebasing your branch, so I would rather see you fixing it doing rebase on latest master.

You need to check the trailing / in code and potentially remove it. You need to validate every input that could be provided by user, you can't expect they will not make mistake. So just removing it here is not enough.

Keep 3b3a8a7 in place. You shouldn't remove it as part of this PR.

What is the difference between this and the test_does_package_exists_in_anitya_found_zero_items? Both of them have same description

Keep 3b3a8a7 in place. You shouldn't remove it as part of this PR.

Same for e5ae4e7

They are improvements on the PR, but it still needs some work

You shouldn't remove the tests in cee0b79. It rather seems that you did something wrong when rebasing your branch, so I would rather see you fixing it doing rebase on latest master.

I did a rebase, but when I was resolving the merge conflict, I mostly added changes from both versions, because of it, a duplicate of those tests was created there

You need to check the trailing / in code and potentially remove it. You need to validate every input that could be provided by user, you can't expect they will not make mistake. So just removing it here is not enough.

The initial idea was to have trailing //, to reduce the risk of potential errors, since // in endpoint is the same thing as /. I removed it there to keep / in front of tail for endpoints so, endpoint sysnax will have the same look as in documentation e.g. /api/something.

You need to check the trailing / in code and potentially remove it. You need to validate every input that could be provided by user, you can't expect they will not make mistake. So just removing it here is not enough.

The initial idea was to have trailing //, to reduce the risk of potential errors, since // in endpoint is the same thing as /. I removed it there to keep / in front of tail for endpoints so, endpoint sysnax will have the same look as in documentation e.g. /api/something.

But that still doesn't solve the issue when somebody will add the trailing space to url and you will end up with URLs with // which sometimes works sometimes don't. You should always check if the user input is correct before using it.

Keep 3b3a8a7 in place. You shouldn't remove it as part of this PR.

Same for e5ae4e7

So I need to keep changes in this PR, but remove this code in next one? What if I just make two commits in final version of this PR, one with changes and one with removing of not used code

You need to check the trailing / in code and potentially remove it. You need to validate every input that could be provided by user, you can't expect they will not make mistake. So just removing it here is not enough.

The initial idea was to have trailing //, to reduce the risk of potential errors, since // in endpoint is the same thing as /. I removed it there to keep / in front of tail for endpoints so, endpoint sysnax will have the same look as in documentation e.g. /api/something.

But that still doesn't solve the issue when somebody will add the trailing space to url and you will end up with URLs with // which sometimes works sometimes don't. You should always check if the user input is correct before using it.

I agree with you. But there is no user input, all those URLs are created based on the config and anitya project id, which is obtained from API

Keep 3b3a8a7 in place. You shouldn't remove it as part of this PR.

Same for e5ae4e7

So I need to keep changes in this PR, but remove this code in next one? What if I just make two commits in final version of this PR, one with changes and one with removing of not used code

No, you shouldn't even touch this in this PR as it not even related to the work you do.

You need to check the trailing / in code and potentially remove it. You need to validate every input that could be provided by user, you can't expect they will not make mistake. So just removing it here is not enough.

The initial idea was to have trailing //, to reduce the risk of potential errors, since // in endpoint is the same thing as /. I removed it there to keep / in front of tail for endpoints so, endpoint sysnax will have the same look as in documentation e.g. /api/something.

But that still doesn't solve the issue when somebody will add the trailing space to url and you will end up with URLs with // which sometimes works sometimes don't. You should always check if the user input is correct before using it.

I agree with you. But there is no user input, all those URLs are created based on the config and anitya project id, which is obtained from API

Config is user input.

1 new commit added

  • changing test method describtion so it is crear what it's doing
a month ago

Build failed. More information on how to proceed and troubleshoot errors available at https://fedoraproject.org/wiki/Zuul-based-ci
https://fedora.softwarefactory-project.io/zuul/buildset/95ec1257ef7a4acfa033bf77f0133225

7 new commits added

  • changing test method describtion so it is crear what it's doing
  • fixing scm_request_processor tests
  • fix mistakes in scm_request_processor
  • fix anitya tests
  • improve anitya util
  • removing useless tests for scm_request_processor
  • feat: creating project and package for Anitya if they not exists, when new repo requested
a month ago

Build failed. More information on how to proceed and troubleshoot errors available at https://fedoraproject.org/wiki/Zuul-based-ci
https://fedora.softwarefactory-project.io/zuul/buildset/3145359b28c24649a540639f4b2e11e1

1 new commit added

  • added method that tests endpoints on trailing slashes and removes them
a month ago

1 new commit added

  • ref: format changes
a month ago

monitor_choices changes removed from commits and check on trailed slashes in endpoint is added

You don't need a whole new method, just doing removesuffix('/') should be enough. See https://docs.python.org/3/library/stdtypes.html#str.removesuffix

You don't need a whole new method, just doing removesuffix('/') should be enough. See https://docs.python.org/3/library/stdtypes.html#str.removesuffix

yeah, but this will just remove suffix. What if the input has trailing slashes in the middle of it

You don't need a whole new method, just doing removesuffix('/') should be enough. See https://docs.python.org/3/library/stdtypes.html#str.removesuffix

yeah, but this will just remove suffix. What if the input has trailing slashes in the middle of it

Then it's not a valid URL and it's a configuration mistake made by the user. But if we have just the trailing '/' (trailing means that it's at the end) it's still a valid URL, we just expect it without the / at the end.

1 new commit added

  • simplify removing trailed slashes
22 days ago

Build failed. More information on how to proceed and troubleshoot errors available at https://fedoraproject.org/wiki/Zuul-based-ci
https://fedora.softwarefactory-project.io/zuul/buildset/dcaea424c25949858bde9edc3d7d7794

rebased onto c314de8

17 days ago

1 new commit added

  • ref: format changes
17 days ago

updated, must be ready

It looks good now, let me merge it.

It looks good now, let me merge it.

Pull-Request has been merged by zlopez

9 days ago