From 6419249ae5717f6945a299e09a5f845f40ba4604 Mon Sep 17 00:00:00 2001
From: Dominik Wombacher <dominik@wombacher.cc>
Date: Jun 06 2024 11:38:23 +0000
Subject: [PATCH 1/3] refactor(ci): Make pagure CI hook / plugin system generic


Move Jenkins related code into plugin file.
Adjust logic to load and trigger CI to be generic.
Allows new plugins and CI types other than Jenkins.

---

diff --git a/pagure/api/__init__.py b/pagure/api/__init__.py
index 25f0417..764f9a4 100644
--- a/pagure/api/__init__.py
+++ b/pagure/api/__init__.py
@@ -344,9 +344,6 @@ from pagure.api import plugins  # noqa: E402, I202
 from pagure.api import project  # noqa: E402, I202
 from pagure.api import user  # noqa: E402, I202
 
-if pagure_config.get("PAGURE_CI_SERVICES", False):
-    from pagure.api.ci import jenkins  # noqa: E402, F401
-
 
 @API.route("/version/")
 @API.route("/version")
@@ -630,12 +627,8 @@ def api():
 
     if pagure_config.get("PAGURE_CI_SERVICES", False):
         ci_methods = []
-        if "jenkins" in pagure_config["PAGURE_CI_SERVICES"]:
-            if "jenkins" not in locals():
-                # We run into this situation in the tests
-                from pagure.api.ci import jenkins  # noqa: E402, F811
-            ci_methods.append(jenkins.jenkins_ci_notification)
-
+        for ci in pagure_config["PAGURE_CI_SERVICES"]:
+            ci_methods.append(f"{ci}.ci_notification")
         if ci_methods:
             sections.append(
                 build_docs_section(
diff --git a/pagure/api/ci/__init__.py b/pagure/api/ci/__init__.py
index ccbb2cb..3fcbf78 100644
--- a/pagure/api/ci/__init__.py
+++ b/pagure/api/ci/__init__.py
@@ -7,3 +7,12 @@
    Pierre-Yves Chibon <pingou@pingoured.fr>
 
 """
+
+from pagure.config import config as pagure_config
+
+BUILD_STATS = {
+    "SUCCESS": ("Build #%s successful", pagure_config["FLAG_SUCCESS"], 100),
+    "FAILURE": ("Build #%s failed", pagure_config["FLAG_FAILURE"], 0),
+    "ABORTED": ("Build #%s aborted", "error", 0),
+    "BUILDING": ("Build #%s in progress", pagure_config["FLAG_PENDING"], 0),
+}
diff --git a/pagure/api/ci/jenkins.py b/pagure/api/ci/jenkins.py
index 7c23dc6..900a6fe 100644
--- a/pagure/api/ci/jenkins.py
+++ b/pagure/api/ci/jenkins.py
@@ -18,14 +18,15 @@ from kitchen.text.converters import to_bytes
 
 import pagure
 import pagure.exceptions
-import pagure.lib.lib_ci as lib_ci
+import pagure.lib.query
+from pagure.config import config as pagure_config
 import pagure.lib.plugins
 import pagure.lib.query
 from pagure.api import API, APIERROR, api_method
+from pagure.api.ci import BUILD_STATS
 
 _log = logging.getLogger(__name__)
 
-
 @API.route(
     "/ci/jenkins/<repo>/<pagure_ci_token>/build-finished", methods=["POST"]
 )
@@ -43,7 +44,7 @@ _log = logging.getLogger(__name__)
     methods=["POST"],
 )
 @api_method
-def jenkins_ci_notification(
+def ci_notification(
     repo, pagure_ci_token, username=None, namespace=None
 ):
     """
@@ -96,7 +97,7 @@ def jenkins_ci_notification(
         raise pagure.exceptions.APIError(400, error_code=APIERROR.EINVALIDREQ)
 
     try:
-        lib_ci.process_jenkins_build(flask.g.session, project, build_id)
+        process_build(flask.g.session, project, build_id)
     except pagure.exceptions.NoCorrespondingPR as err:
         raise pagure.exceptions.APIError(
             400, error_code=APIERROR.ENOCODE, error=str(err)
@@ -109,3 +110,148 @@ def jenkins_ci_notification(
 
     _log.info("Successfully proccessed jenkins notification")
     return ("", 204)
+
+def process_build(session, project, build_id, iteration=0):
+    """Gets the build info from jenkins and flags that particular
+    pull-request.
+    """
+    import jenkins
+
+    # This import is needed as pagure.lib relies on Project.ci_hook to be
+    # defined and accessible and this happens in pagure.hooks.pagure_ci
+    from pagure.hooks import pagure_ci  # noqa: E402,F401
+
+    # Jenkins Base URL
+    _log.info("Querying jenkins at: %s", project.ci_hook.ci_url)
+    jenk = jenkins.Jenkins(
+        project.ci_hook.ci_url,
+        username=project.ci_hook.ci_username or None,
+        password=project.ci_hook.ci_password or None,
+    )
+    jenkins_name = project.ci_hook.ci_job
+    _log.info(
+        "Querying jenkins for project: %s, build: %s", jenkins_name, build_id
+    )
+    try:
+        build_info = jenk.get_build_info(jenkins_name, build_id)
+    except jenkins.NotFoundException:
+        _log.debug("Could not find build %s at: %s", build_id, jenkins_name)
+        raise pagure.exceptions.PagureException(
+            "Could not find build %s at: %s" % (build_id, jenkins_name)
+        )
+
+    if build_info.get("building") is True:
+        if iteration < 5:
+            _log.info("Build is still going, let's wait a sec and try again")
+            time.sleep(1)
+            return process_build(
+                session, project, build_id, iteration=iteration + 1
+            )
+        _log.info(
+            "We've been waiting for 5 seconds and the build is still "
+            "not finished, so let's keep going."
+        )
+
+    result = build_info.get("result")
+    if not result and build_info.get("building") is True:
+        result = "BUILDING"
+
+    _log.info("Result from jenkins: %s", result)
+    url = build_info["url"]
+    _log.info("URL from jenkins: %s", url)
+
+    pr_id = None
+    for action in build_info["actions"]:
+        for cause in action.get("causes", []):
+            try:
+                pr_id = int(cause["note"])
+            except (KeyError, ValueError):
+                continue
+
+    if not pr_id:
+        raise pagure.exceptions.NoCorrespondingPR("No corresponding PR found")
+
+    if not result or result not in BUILD_STATS:
+        raise pagure.exceptions.PagureException(
+            "Unknown build status: %s" % result
+        )
+
+    request = pagure.lib.query.search_pull_requests(
+        session, project_id=project.id, requestid=pr_id
+    )
+
+    if not request:
+        raise pagure.exceptions.PagureException("Request not found")
+
+    comment, state, percent = BUILD_STATS[result]
+    comment = comment % build_id
+    # Adding build ID to the CI type
+    username = "%s" % project.ci_hook.ci_type
+    if request.commit_stop:
+        comment += " (commit: %s)" % (request.commit_stop[:8])
+
+    uid = None
+    for flag in request.flags:
+        if (
+            flag.status == pagure_config["FLAG_PENDING"]
+            and flag.username == username
+        ):
+            uid = flag.uid
+            break
+
+    _log.info("Flag's UID: %s", uid)
+    pagure.lib.query.add_pull_request_flag(
+        session,
+        request=request,
+        username=username,
+        percent=percent,
+        comment=comment,
+        url=url,
+        status=state,
+        uid=uid,
+        user=project.user.username,
+        token=None,
+    )
+    session.commit()
+
+
+def trigger_build(
+    project_path,
+    url,
+    job,
+    token,
+    branch,
+    branch_to,
+    cause,
+    ci_username=None,
+    ci_password=None,
+):
+    """Trigger a build on a jenkins instance."""
+    try:
+        import jenkins
+    except ImportError:
+        _log.error("Pagure-CI: Failed to load the jenkins module, bailing")
+        return
+
+    _log.info("Jenkins CI")
+
+    repo = "%s/%s" % (pagure_config["GIT_URL_GIT"].rstrip("/"), project_path)
+
+    data = {
+        "cause": cause,
+        "REPO": repo,
+        "BRANCH": branch,
+        "BRANCH_TO": branch_to,
+    }
+
+    server = jenkins.Jenkins(
+        url, username=ci_username or None, password=ci_password or None
+    )
+    _log.info(
+        "Pagure-CI: Triggering at: %s for: %s - data: %s", url, job, data
+    )
+    try:
+        server.build_job(name=job, parameters=data, token=token)
+        _log.info("Pagure-CI: Build triggered")
+    except Exception as err:
+        _log.info("Pagure-CI:An error occured: %s", err)
diff --git a/pagure/hooks/pagure_ci.py b/pagure/hooks/pagure_ci.py
index 4cce6dd..d2418c4 100644
--- a/pagure/hooks/pagure_ci.py
+++ b/pagure/hooks/pagure_ci.py
@@ -77,7 +77,7 @@ tmpl = """
 {% if repo | hasattr('ci_hook') and repo.ci_hook and
     repo.ci_hook.pagure_ci_token %}
 
-The token to be used by jenkins to trigger the build is:
+The token to be used by the CI to trigger the build is:
 <pre>
 {{ repo.ci_hook.pagure_ci_token}}
 </pre>
diff --git a/pagure/lib/lib_ci.py b/pagure/lib/lib_ci.py
deleted file mode 100644
index fac71d6..0000000
--- a/pagure/lib/lib_ci.py
+++ /dev/null
@@ -1,176 +0,0 @@
-# -*- coding: utf-8 -*-
-
-"""
- (c) 2016 - Copyright Red Hat Inc
-
- Authors:
-   Lubomír Sedlář <lubomir.sedlar@gmail.com>
-   Farhaan Bukhsh <farhaan.bukhsh@gmail.com>
-   Pierre-Yves Chibon <pingou@pingoured.fr>
-
-"""
-
-from __future__ import absolute_import, unicode_literals
-
-# pylint: disable=too-many-locals
-import logging
-import time
-
-import pagure.exceptions
-import pagure.lib.query
-from pagure.config import config as pagure_config
-
-_log = logging.getLogger(__name__)
-
-BUILD_STATS = {
-    "SUCCESS": ("Build #%s successful", pagure_config["FLAG_SUCCESS"], 100),
-    "FAILURE": ("Build #%s failed", pagure_config["FLAG_FAILURE"], 0),
-    "ABORTED": ("Build #%s aborted", "error", 0),
-    "BUILDING": ("Build #%s in progress", pagure_config["FLAG_PENDING"], 0),
-}
-
-
-def process_jenkins_build(session, project, build_id, iteration=0):
-    """Gets the build info from jenkins and flags that particular
-    pull-request.
-    """
-    import jenkins
-
-    # This import is needed as pagure.lib relies on Project.ci_hook to be
-    # defined and accessible and this happens in pagure.hooks.pagure_ci
-    from pagure.hooks import pagure_ci  # noqa: E402,F401
-
-    # Jenkins Base URL
-    _log.info("Querying jenkins at: %s", project.ci_hook.ci_url)
-    jenk = jenkins.Jenkins(
-        project.ci_hook.ci_url,
-        username=project.ci_hook.ci_username or None,
-        password=project.ci_hook.ci_password or None,
-    )
-    jenkins_name = project.ci_hook.ci_job
-    _log.info(
-        "Querying jenkins for project: %s, build: %s", jenkins_name, build_id
-    )
-    try:
-        build_info = jenk.get_build_info(jenkins_name, build_id)
-    except jenkins.NotFoundException:
-        _log.debug("Could not find build %s at: %s", build_id, jenkins_name)
-        raise pagure.exceptions.PagureException(
-            "Could not find build %s at: %s" % (build_id, jenkins_name)
-        )
-
-    if build_info.get("building") is True:
-        if iteration < 5:
-            _log.info("Build is still going, let's wait a sec and try again")
-            time.sleep(1)
-            return process_jenkins_build(
-                session, project, build_id, iteration=iteration + 1
-            )
-        _log.info(
-            "We've been waiting for 5 seconds and the build is still "
-            "not finished, so let's keep going."
-        )
-
-    result = build_info.get("result")
-    if not result and build_info.get("building") is True:
-        result = "BUILDING"
-
-    _log.info("Result from jenkins: %s", result)
-    url = build_info["url"]
-    _log.info("URL from jenkins: %s", url)
-
-    pr_id = None
-    for action in build_info["actions"]:
-        for cause in action.get("causes", []):
-            try:
-                pr_id = int(cause["note"])
-            except (KeyError, ValueError):
-                continue
-
-    if not pr_id:
-        raise pagure.exceptions.NoCorrespondingPR("No corresponding PR found")
-
-    if not result or result not in BUILD_STATS:
-        raise pagure.exceptions.PagureException(
-            "Unknown build status: %s" % result
-        )
-
-    request = pagure.lib.query.search_pull_requests(
-        session, project_id=project.id, requestid=pr_id
-    )
-
-    if not request:
-        raise pagure.exceptions.PagureException("Request not found")
-
-    comment, state, percent = BUILD_STATS[result]
-    comment = comment % build_id
-    # Adding build ID to the CI type
-    username = "%s" % project.ci_hook.ci_type
-    if request.commit_stop:
-        comment += " (commit: %s)" % (request.commit_stop[:8])
-
-    uid = None
-    for flag in request.flags:
-        if (
-            flag.status == pagure_config["FLAG_PENDING"]
-            and flag.username == username
-        ):
-            uid = flag.uid
-            break
-
-    _log.info("Flag's UID: %s", uid)
-    pagure.lib.query.add_pull_request_flag(
-        session,
-        request=request,
-        username=username,
-        percent=percent,
-        comment=comment,
-        url=url,
-        status=state,
-        uid=uid,
-        user=project.user.username,
-        token=None,
-    )
-    session.commit()
-
-
-def trigger_jenkins_build(
-    project_path,
-    url,
-    job,
-    token,
-    branch,
-    branch_to,
-    cause,
-    ci_username=None,
-    ci_password=None,
-):
-    """Trigger a build on a jenkins instance."""
-    try:
-        import jenkins
-    except ImportError:
-        _log.error("Pagure-CI: Failed to load the jenkins module, bailing")
-        return
-
-    _log.info("Jenkins CI")
-
-    repo = "%s/%s" % (pagure_config["GIT_URL_GIT"].rstrip("/"), project_path)
-
-    data = {
-        "cause": cause,
-        "REPO": repo,
-        "BRANCH": branch,
-        "BRANCH_TO": branch_to,
-    }
-
-    server = jenkins.Jenkins(
-        url, username=ci_username or None, password=ci_password or None
-    )
-    _log.info(
-        "Pagure-CI: Triggering at: %s for: %s - data: %s", url, job, data
-    )
-    try:
-        server.build_job(name=job, parameters=data, token=token)
-        _log.info("Pagure-CI: Build triggered")
-    except Exception as err:
-        _log.info("Pagure-CI:An error occured: %s", err)
diff --git a/pagure/lib/tasks_services.py b/pagure/lib/tasks_services.py
index d4d628e..41d5379 100644
--- a/pagure/lib/tasks_services.py
+++ b/pagure/lib/tasks_services.py
@@ -13,8 +13,8 @@ from __future__ import absolute_import, unicode_literals
 import datetime
 import hashlib
 import hmac
+import importlib
 import json
-import os
 import os.path
 import time
 import uuid
@@ -29,7 +29,6 @@ from sqlalchemy.exc import SQLAlchemyError
 
 import pagure.lib.query
 from pagure.config import config as pagure_config
-from pagure.lib.lib_ci import trigger_jenkins_build
 from pagure.lib.tasks_utils import pagure_task
 from pagure.mail_logging import format_callstack
 from pagure.utils import set_up_logging, split_project_fullname
@@ -474,25 +473,23 @@ def trigger_ci_build(
         branch,
     )
 
-    if ci_type == "jenkins":
-
-        jenk_project = project
+    try:
+        ci_project = project
         if project.is_fork:
-            jenk_project = project.parent
-
-        trigger_jenkins_build(
-            project_path=project.path,
-            url=jenk_project.ci_hook.ci_url,
-            job=jenk_project.ci_hook.ci_job,
-            token=jenk_project.ci_hook.pagure_ci_token,
-            branch=branch,
-            branch_to=branch_to,
-            cause=cause,
-            ci_username=jenk_project.ci_hook.ci_username,
-            ci_password=jenk_project.ci_hook.ci_password,
-        )
-
-    else:
-        _log.warning("Pagure-CI:Un-supported CI type")
+            ci_project = project.parent
+        ci = importlib.import_module(f"pagure.api.ci.{ci_type}")
+        ci.trigger_build(
+                project_path=project.path,
+                url=ci_project.ci_hook.ci_url,
+                job=ci_project.ci_hook.ci_job,
+                token=ci_project.ci_hook.pagure_ci_token,
+                branch=branch,
+                branch_to=branch_to,
+                cause=cause,
+                ci_username=ci_project.ci_hook.ci_username,
+                ci_password=ci_project.ci_hook.ci_password,
+            )
+    except Exception as e:
+        _log.error(f"Pagure-CI: Un-supported CI type {ci_type}. Error while loading CI plugin: {e}")
 
     _log.info("Pagure-CI: Ready for another")
diff --git a/pagure/ui/oidc_login.py b/pagure/ui/oidc_login.py
index 30bdd77..07dd70a 100644
--- a/pagure/ui/oidc_login.py
+++ b/pagure/ui/oidc_login.py
@@ -33,7 +33,7 @@ _log = logging.getLogger(__name__)
 def fas_user_from_oidc():
     if "oidc_cached_userdata" in flask.session:
         flask.g.fas_user = munch.Munch(**flask.session["oidc_cached_userdata"])
-        # Edge case, avoid 'KeyError' after pagure update if a cached session is used
+        # Edge case, avoid 'KeyError' after pagure update with cached sessions
         flask.g.fas_user.can_create = flask.g.fas_user.get("can_create", False)
     elif oidc.user_loggedin and "oidc_logintime" in flask.session:
         email_key, fulln_key, usern_key, ssh_key, groups_key = [

From 3b2719e30c9b0c2199f52acc038df558b4b04692 Mon Sep 17 00:00:00 2001
From: Dominik Wombacher <dominik@wombacher.cc>
Date: Jun 06 2024 11:38:23 +0000
Subject: [PATCH 2/3] refactor: Address black and flake8 findings.


---

diff --git a/pagure/api/ci/jenkins.py b/pagure/api/ci/jenkins.py
index 900a6fe..81780f4 100644
--- a/pagure/api/ci/jenkins.py
+++ b/pagure/api/ci/jenkins.py
@@ -25,8 +25,11 @@ import pagure.lib.query
 from pagure.api import API, APIERROR, api_method
 from pagure.api.ci import BUILD_STATS
 
+import time
+
 _log = logging.getLogger(__name__)
 
+
 @API.route(
     "/ci/jenkins/<repo>/<pagure_ci_token>/build-finished", methods=["POST"]
 )
@@ -44,9 +47,7 @@ _log = logging.getLogger(__name__)
     methods=["POST"],
 )
 @api_method
-def ci_notification(
-    repo, pagure_ci_token, username=None, namespace=None
-):
+def ci_notification(repo, pagure_ci_token, username=None, namespace=None):
     """
     Jenkins Build Notification
     --------------------------
@@ -111,6 +112,7 @@ def ci_notification(
     _log.info("Successfully proccessed jenkins notification")
     return ("", 204)
 
+
 def process_build(session, project, build_id, iteration=0):
     """Gets the build info from jenkins and flags that particular
     pull-request.
diff --git a/pagure/lib/tasks_services.py b/pagure/lib/tasks_services.py
index 41d5379..1bef240 100644
--- a/pagure/lib/tasks_services.py
+++ b/pagure/lib/tasks_services.py
@@ -479,17 +479,20 @@ def trigger_ci_build(
             ci_project = project.parent
         ci = importlib.import_module(f"pagure.api.ci.{ci_type}")
         ci.trigger_build(
-                project_path=project.path,
-                url=ci_project.ci_hook.ci_url,
-                job=ci_project.ci_hook.ci_job,
-                token=ci_project.ci_hook.pagure_ci_token,
-                branch=branch,
-                branch_to=branch_to,
-                cause=cause,
-                ci_username=ci_project.ci_hook.ci_username,
-                ci_password=ci_project.ci_hook.ci_password,
-            )
+            project_path=project.path,
+            url=ci_project.ci_hook.ci_url,
+            job=ci_project.ci_hook.ci_job,
+            token=ci_project.ci_hook.pagure_ci_token,
+            branch=branch,
+            branch_to=branch_to,
+            cause=cause,
+            ci_username=ci_project.ci_hook.ci_username,
+            ci_password=ci_project.ci_hook.ci_password,
+        )
     except Exception as e:
-        _log.error(f"Pagure-CI: Un-supported CI type {ci_type}. Error while loading CI plugin: {e}")
+        _log.error(
+            f"Pagure-CI: Un-supported CI type {ci_type}. "
+            f"Error while loading CI plugin: {e}"
+        )
 
     _log.info("Pagure-CI: Ready for another")

From a51c69642196f6c9b80c5e8ea34442baf90bd464 Mon Sep 17 00:00:00 2001
From: Dominik Wombacher <dominik@wombacher.cc>
Date: Jun 06 2024 11:38:23 +0000
Subject: [PATCH 3/3] tests: Fix AttributeError after refactoring 'lib/task_services'


---

diff --git a/pagure/api/__init__.py b/pagure/api/__init__.py
index 764f9a4..819bce9 100644
--- a/pagure/api/__init__.py
+++ b/pagure/api/__init__.py
@@ -19,6 +19,7 @@ from __future__ import absolute_import, unicode_literals
 import codecs
 import enum
 import functools
+import importlib
 import logging
 import os
 
@@ -627,8 +628,16 @@ def api():
 
     if pagure_config.get("PAGURE_CI_SERVICES", False):
         ci_methods = []
-        for ci in pagure_config["PAGURE_CI_SERVICES"]:
-            ci_methods.append(f"{ci}.ci_notification")
+        for ci_type in pagure_config["PAGURE_CI_SERVICES"]:
+            if ci_type not in locals():
+                # Necessary to pass the tests and avoid:
+                # AttributeError: 'str' object has no attribute '__name__'
+                # 'build_docs_section' expects type function down the line.
+                ci = importlib.import_module(
+                    f"pagure.api.ci.{ci_type}"
+                )  # noqa: E402, F811
+                ci_notification = getattr(ci, f"{ci_type}_ci_notification")
+            ci_methods.append(ci_notification)
         if ci_methods:
             sections.append(
                 build_docs_section(
diff --git a/pagure/api/ci/jenkins.py b/pagure/api/ci/jenkins.py
index 81780f4..0e8ff27 100644
--- a/pagure/api/ci/jenkins.py
+++ b/pagure/api/ci/jenkins.py
@@ -47,7 +47,11 @@ _log = logging.getLogger(__name__)
     methods=["POST"],
 )
 @api_method
-def ci_notification(repo, pagure_ci_token, username=None, namespace=None):
+# <ci_type>_ci_notification
+# convention required to ensure unique names in API namespace
+def jenkins_ci_notification(
+    repo, pagure_ci_token, username=None, namespace=None
+):
     """
     Jenkins Build Notification
     --------------------------
@@ -98,7 +102,7 @@ def ci_notification(repo, pagure_ci_token, username=None, namespace=None):
         raise pagure.exceptions.APIError(400, error_code=APIERROR.EINVALIDREQ)
 
     try:
-        process_build(flask.g.session, project, build_id)
+        _process_build(flask.g.session, project, build_id)
     except pagure.exceptions.NoCorrespondingPR as err:
         raise pagure.exceptions.APIError(
             400, error_code=APIERROR.ENOCODE, error=str(err)
@@ -113,7 +117,7 @@ def ci_notification(repo, pagure_ci_token, username=None, namespace=None):
     return ("", 204)
 
 
-def process_build(session, project, build_id, iteration=0):
+def _process_build(session, project, build_id, iteration=0):
     """Gets the build info from jenkins and flags that particular
     pull-request.
     """
@@ -146,7 +150,7 @@ def process_build(session, project, build_id, iteration=0):
         if iteration < 5:
             _log.info("Build is still going, let's wait a sec and try again")
             time.sleep(1)
-            return process_build(
+            return _process_build(
                 session, project, build_id, iteration=iteration + 1
             )
         _log.info(
diff --git a/tests/test_pagure_flask_ui_plugins_pagure_ci.py b/tests/test_pagure_flask_ui_plugins_pagure_ci.py
index 412e1db..3d41f3e 100644
--- a/tests/test_pagure_flask_ui_plugins_pagure_ci.py
+++ b/tests/test_pagure_flask_ui_plugins_pagure_ci.py
@@ -369,7 +369,7 @@ class PagureFlaskPluginPagureCItests(tests.SimplePagureTest):
                 output_text,
             )
 
-    @mock.patch("pagure.lib.tasks_services.trigger_jenkins_build")
+    @mock.patch("pagure.api.ci.jenkins.trigger_build")
     def test_plugin_pagure_ci_namespaced_auth(self, trigger_jenk):
         """Test the pagure ci plugin on/off endpoint."""
 
diff --git a/tests/test_pagure_lib_task_services.py b/tests/test_pagure_lib_task_services.py
index 7142fc2..d510f58 100644
--- a/tests/test_pagure_lib_task_services.py
+++ b/tests/test_pagure_lib_task_services.py
@@ -125,7 +125,7 @@ class PagureLibTaskServicestests(tests.Modeltests):
             "/path/to/git", ANY, "master", ["hash1", "hash2"]
         )
 
-    @patch("pagure.lib.tasks_services.trigger_jenkins_build")
+    @patch("pagure.api.ci.jenkins.trigger_build")
     def test_trigger_ci_build_invalid_project(self, trigger_jenk):
         """Test the trigger_ci_build method."""
         output = pagure.lib.tasks_services.trigger_ci_build(
@@ -138,7 +138,7 @@ class PagureLibTaskServicestests(tests.Modeltests):
         self.assertIsNone(output)
         trigger_jenk.assert_not_called()
 
-    @patch("pagure.lib.tasks_services.trigger_jenkins_build")
+    @patch("pagure.api.ci.jenkins.trigger_build")
     def test_trigger_ci_build_not_configured_project(self, trigger_jenk):
         """Test the trigger_ci_build method."""
         self.assertRaises(
@@ -152,7 +152,7 @@ class PagureLibTaskServicestests(tests.Modeltests):
         )
         trigger_jenk.assert_not_called()
 
-    @patch("pagure.lib.tasks_services.trigger_jenkins_build")
+    @patch("pagure.api.ci.jenkins.trigger_build")
     def test_trigger_ci_build_not_configured_project_fork(self, trigger_jenk):
         """Test the trigger_ci_build method."""
         self.assertRaises(
@@ -595,7 +595,7 @@ class PagureLibTaskServicesJenkinsCItests(tests.Modeltests):
         self.session.add(item)
         self.session.commit()
 
-    @patch("pagure.lib.tasks_services.trigger_jenkins_build")
+    @patch("pagure.api.ci.jenkins.trigger_build")
     def test_trigger_ci_build_invalid_ci(self, trigger_jenk):
         """Test the trigger_ci_build method."""
         output = pagure.lib.tasks_services.trigger_ci_build(
@@ -608,7 +608,7 @@ class PagureLibTaskServicesJenkinsCItests(tests.Modeltests):
         self.assertIsNone(output)
         trigger_jenk.assert_not_called()
 
-    @patch("pagure.lib.tasks_services.trigger_jenkins_build")
+    @patch("pagure.api.ci.jenkins.trigger_build")
     def test_trigger_ci_build_invalid_ci_fork(self, trigger_jenk):
         """Test the trigger_ci_build method."""
         output = pagure.lib.tasks_services.trigger_ci_build(
@@ -621,7 +621,7 @@ class PagureLibTaskServicesJenkinsCItests(tests.Modeltests):
         self.assertIsNone(output)
         trigger_jenk.assert_not_called()
 
-    @patch("pagure.lib.tasks_services.trigger_jenkins_build")
+    @patch("pagure.api.ci.jenkins.trigger_build")
     def test_trigger_ci_build_valid_project(self, trigger_jenk):
         """Test the trigger_ci_build method."""
         output = pagure.lib.tasks_services.trigger_ci_build(
@@ -644,7 +644,7 @@ class PagureLibTaskServicesJenkinsCItests(tests.Modeltests):
             branch_to="master",
         )
 
-    @patch("pagure.lib.tasks_services.trigger_jenkins_build")
+    @patch("pagure.api.ci.jenkins.trigger_build")
     def test_trigger_ci_build_valid_project_fork(self, trigger_jenk):
         """Test the trigger_ci_build method."""
         output = pagure.lib.tasks_services.trigger_ci_build(
@@ -714,7 +714,7 @@ class PagureLibTaskServicesJenkinsCIAuthtests(tests.Modeltests):
         self.session.add(item)
         self.session.commit()
 
-    @patch("pagure.lib.tasks_services.trigger_jenkins_build")
+    @patch("pagure.api.ci.jenkins.trigger_build")
     def test_trigger_ci_build_invalid_ci(self, trigger_jenk):
         """Test the trigger_ci_build method."""
         output = pagure.lib.tasks_services.trigger_ci_build(
@@ -727,7 +727,7 @@ class PagureLibTaskServicesJenkinsCIAuthtests(tests.Modeltests):
         self.assertIsNone(output)
         trigger_jenk.assert_not_called()
 
-    @patch("pagure.lib.tasks_services.trigger_jenkins_build")
+    @patch("pagure.api.ci.jenkins.trigger_build")
     def test_trigger_ci_build_invalid_ci_fork(self, trigger_jenk):
         """Test the trigger_ci_build method."""
         output = pagure.lib.tasks_services.trigger_ci_build(
@@ -740,7 +740,7 @@ class PagureLibTaskServicesJenkinsCIAuthtests(tests.Modeltests):
         self.assertIsNone(output)
         trigger_jenk.assert_not_called()
 
-    @patch("pagure.lib.tasks_services.trigger_jenkins_build")
+    @patch("pagure.api.ci.jenkins.trigger_build")
     def test_trigger_ci_build_valid_project(self, trigger_jenk):
         """Test the trigger_ci_build method."""
         output = pagure.lib.tasks_services.trigger_ci_build(
@@ -763,7 +763,7 @@ class PagureLibTaskServicesJenkinsCIAuthtests(tests.Modeltests):
             branch_to="master",
         )
 
-    @patch("pagure.lib.tasks_services.trigger_jenkins_build")
+    @patch("pagure.api.ci.jenkins.trigger_build")
     def test_trigger_ci_build_valid_project_fork(self, trigger_jenk):
         """Test the trigger_ci_build method."""
         output = pagure.lib.tasks_services.trigger_ci_build(

